9 Replies
      Latest reply: Nov 13, 2016 9:26 PM by vickyzhang209 RSS
      vickyzhang209 Level 1 Level 1 (0 points)

        Now I want to implement a download manager which can support to download an assert of a hls link. There are some issues:

        1.As https://forums.developer.apple.com/message/42352#42352,    there is a resume rate limiter. So,  it seems we can't create and resume one segment at a time. For this, I do some tests that I create all tasks but just resume the first task at begin, then I resume the next task in "didcompletewitherror":

        - (void)beginDownloadWithUrlArray:(NSArray *)downloadURLArray{
        
            for (NSString *urlStr in downloadURLArray) {
                NSURL *downloadURL = [NSURL URLWithString:urlStr];
                NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL];
                NSURLSessionTask *task = [self.session downloadTaskWithRequest:request];
                [self.taskArray addObject:task];
            }
        
            [self runNextTask];
        }
        
        - (void)runNextTask{
            if (self.taskIndex < self.taskArray.count) {
        
                self.currentDownloadTask = self.taskArray[self.taskIndex];
                [self.currentDownloadTask resume];
                NSLog(@"nextrequest--%@",self.currentDownloadTask);
            }else{
                self.currentDownloadTask = nil;
            }
        
            self.taskIndex ++ ;
        }
        
        - (void)URLSession:(NSURLSession *)session
                      task:(NSURLSessionTask *)task
        didCompleteWithError:(NSError *)error {
            NSLog(@"didCompleteWithError");
            if (error) {
                NSLog(@"error -- %@",error);
                if ([error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData]) {
                    self.resumeData = [error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData];
                    NSURLSessionTask *task = [[[self class] sharedManager] downloadTaskWithResumeData:self.resumeData];
                    [task resume];
                }
            }else{
                [self runNextTask];
            }
        }
        

        I can see it can continue downloading all tasks without delay. But it is strange that I can see didCompleteWithError is called  when all tasks are finished. So I wonder whether  "[self runNextTask]" in "didCompleteWithError" is called? But if I remove "[self runNextTask]" from "didCompleteWithError", it just can download the first task. Can someone explain what is the mechanism of this? Thanks. Also we capture the pcap packet to analyze and find that the tasks are not called in order.

         

        2. As apple provides an AVAssetDownloadURLSession for downloading an asset and find that it can download the segment in order and have no delay. What is the mechanism of this. Thanks.

        • Re: How to use nsurlsession to download an asset of a hls link at background
          eskimo Apple Staff Apple Staff (6,005 points)

          So,  it seems we can't create and resume one segment at a time.

          Correct.

          For this, I do some tests that I create all tasks but just resume the first task at begin, then I resume the next task in "didcompletewitherror":

          Splitting the creation and resuming of the tasks won’t help.  The limiting factor here is NSURLSession’s resuming (or relaunching) of your process, not of the tasks themselves.

          If you’re seeing odd behaviours here, be aware that the debugger has a big impact on background task execution, so make sure you follow the guidelines outlined Testing Background Session Code.

          Also we capture the pcap packet to analyze and find that the tasks are not called in order.

          This is expected; NSURLSession background sessions do not specify the order in which tasks are run.


          As apple provides an AVAssetDownloadURLSession for downloading an asset and find that it can download the segment in order and have no delay. What is the mechanism of this.

          I’m not sure what you’re asking here.  Are you asking how to use AVAssetDownloadURLSession?  Or how AVAssetDownloadURLSession works?

          If it’s the latter, that won’t help you because AVAssetDownloadURLSession is part of the system and thus has access to facilities that you don’t have access to.

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"

            • Re: How to use nsurlsession to download an asset of a hls link at background
              vickyzhang209 Level 1 Level 1 (0 points)

              Hi eskimo

                  Thank you very much. For second question, I just want to ask how AVAssetDownloadURLSession works and you already answered it. I have one more question, for it needs to create all tasks at begin, is there a limitation on the number of task? i.e. does it work if I create hundreds or thousands of tasks at a time?Thanks again.

                • Re: How to use nsurlsession to download an asset of a hls link at background
                  eskimo Apple Staff Apple Staff (6,005 points)

                  … is there a limitation on the number of task? i.e. does it work if I create hundreds or thousands of tasks at a time?

                  There is no hard limit.  In my experience you won’t have problems with a few hundred tasks.  Back when NSURLSession was first introduced (iOS 7) I heard reports from developers describing weird problems when the task count got up into the thousands.  I’ve not tracked that issue since then, so I don’t know how things currently stand.

                  My general advice on this front is covered by the  Moving to Fewer, Larger Transfers pinned post.

                  Share and Enjoy

                  Quinn “The Eskimo!”
                  Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                  let myEmail = "eskimo" + "1" + "@apple.com"

                    • Re: How to use nsurlsession to download an asset of a hls link at background
                      vickyzhang209 Level 1 Level 1 (0 points)

                      Thanks for your reply

                      • Re: How to use nsurlsession to download an asset of a hls link at background
                        vickyzhang209 Level 1 Level 1 (0 points)

                        Since create all tasks and resume them at a time, the tasks are not called in order. Does it have any solution to make the tasks to be processed in order? i.e. download task1, task1 finish then download task2, task2 finish then downlod task3 and so on. Thanks.

                          • Re: How to use nsurlsession to download an asset of a hls link at background
                            eskimo Apple Staff Apple Staff (6,005 points)

                            Since create all tasks and resume them at a time, the tasks are not called in order.

                            Right.  That’s expected behaviour.

                            Does it have any solution to make the tasks to be processed in order?

                            No, alas.

                            If you'd like to see such support added in the future, I encourage you to file an enhancement request describing your requirements.  While we may have seen similar requests before, a fresh bug report will allow you to express your needs in your own terms, and allow iOS engineering to gauge the level of demand.

                            Please post your bug number, just for the record.

                            Share and Enjoy

                            Quinn “The Eskimo!”
                            Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                            let myEmail = "eskimo" + "1" + "@apple.com"

                              • Re: How to use nsurlsession to download an asset of a hls link at background
                                vickyzhang209 Level 1 Level 1 (0 points)

                                Thanks. I already file an enhancement request and the bug number is  29194026. Also as we test, the delegate function is awaked till all takes are finished at background . And there is a 30 seconds limitation for handling the remaining work(such as remove the downloaded files from system storage to app sandbox) of all tasks. Is it expected result? If we can't finish the remaining work of all tasks within 30 seconds, then what should we do? Let me describe the situation more clearly:

                                1. create 500 download tasks at foreground

                                2. switch to backgroud

                                3. when all tasks is finished, the delegate function of each task(such as didfinishdownloadingtourl) is called and we can do some needed work in the delegate function.

                                4. For there is a 30 seconds limitation, assume we can just finish the needed work for 400 tasks, then 100 tasks are left.

                                5. Does it have any chance to do the needed work of the left 100 tasks?

                                Thanks again.

                                  • Re: How to use nsurlsession to download an asset of a hls link at background
                                    eskimo Apple Staff Apple Staff (6,005 points)

                                    In step 3 you should start a UIApplication background task to get the maximum amount of background execution time to process the results of these tasks.  As you say, that time is currently capped to around 30 seconds.  If that’s not enough, the best you can do is defer the work until your app gets background execution time for other reasons.

                                    What I’d do in your situation is:

                                    1. Implement -URLSession:downloadTask:didFinishDownloadingToURL: so that it runs very quickly, moving the file to a ‘to be processed’ directory.

                                    2. Similarly, implement -URLSession:task:didCompleteWithError: so that it runs very quickly.

                                    3. When you get -URLSessionDidFinishEventsForBackgroundURLSession:, do three things:

                                    4. Start a background process to process all the files in your ‘to be processed’ directory.  When you’re done with a file, move it to a different directory.

                                    5. Use a UIApplication background to keep your process from being suspended.

                                    6. Call the completion handler that you got via -application:handleEventsForBackgroundURLSession:completionHandler: so that the system knows you’re done with the background session work.

                                    7. In the code that processes these files in the background, do three things:

                                    8. Monitor the backgroundTimeRemaining property of UIApplication so that can stop your background work orderly when you start running out of time.

                                    9. If the expiry handler associated with your UIApplication background task gets called, urgently stop your background work.

                                    10. In both case, once you’ve stopped your background work, end the background task.

                                    The next time your app gets execution time (either in the background, or because your user has brought the app to the front), you can continue processing any files left over in the ‘to be processed’ directory.

                                    Share and Enjoy

                                    Quinn “The Eskimo!”
                                    Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                                    let myEmail = "eskimo" + "1" + "@apple.com"