2

I am creating a function to download M3u8 files in iOS. I can download the M3u8 but I want the ability to restore a pending download if the app is paused or quit. Below is the main documentation I used but I can't get the restore function to work as intended.

https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/MediaPlaybackGuide/Contents/Resources/en.lproj/HTTPLiveStreaming/HTTPLiveStreaming.html#//apple_ref/doc/uid/TP40016757-CH11-SW3

Below is what I use to download the M3U8:

private var config: URLSessionConfiguration!

var downloadSession: AVAssetDownloadURLSession!
var downloadTask: AVAssetDownloadTask!

var mediaSelectionMap = [AVAssetDownloadTask : AVMediaSelection]()
let downloadIdentifier = "mySession"

func assetDownload(url: URL) {
    print("Download started...")

    //Create new background session configuration
    let configuration = URLSessionConfiguration.background(withIdentifier: downloadIdentifier)

    //Create a new AVAssetDownloadURLSession with background config, delegate and queue
    let downloadSession = AVAssetDownloadURLSession(configuration: configuration, assetDownloadDelegate: self, delegateQueue: OperationQueue.main)

    downloadSession.getAllTasks { (taskArray) in
        //Task array always nil when segment should be found
        if taskArray.count > 0 {
            print("Check if to resume previous download")
            self.restorePendingDownloads()
        } else {
            let asset = AVURLAsset(url: url)
            print("New Movie downloading")
            //Create new AVAssetDownloadTask for the desired asset
            self.downloadTask = downloadSession.makeAssetDownloadTask(asset: asset, assetTitle: "VideoSample", assetArtworkData: nil, options: [AVAssetDownloadTaskMinimumRequiredMediaBitrateKey: NSNumber(value: 0)])

            //Start task and begin download
            self.downloadTask?.resume()
        }
    }
}

Below is the restore pending function:

 func restorePendingDownloads() {
    print("restore pending download...")
    // Create session configuration with ORIGINAL download identifier
    config = URLSessionConfiguration.background(withIdentifier: downloadIdentifier)

    // Create a new AVAssetDownloadURLSession
    downloadSession = AVAssetDownloadURLSession(configuration: config,
                                                assetDownloadDelegate: self,
                                                delegateQueue: OperationQueue.main)

    // Grab all the pending tasks associated with the downloadSession
    downloadSession.getAllTasks { tasksArray in
        print("getting all tasks.. \(tasksArray.count)") //returns 0
        // For each task, restore the state in the app
        for task in tasksArray {
            guard let downloadTask = task as? AVAssetDownloadTask else { break }
            // Restore asset, progress indicators, state, etc...
            let asset = downloadTask.urlAsset
            print("asset:\(asset)")
            //NEVER CALLED BECAUSE EMPTY
        }
    }
}

Someone recommended using the function below but this just reset the download to the beginning.

func restorePendingDownload(url: URL){
    let urlAsset = AVURLAsset(url: url)
    downloadTask = downloadSession.makeAssetDownloadTask(asset: urlAsset, assetTitle: "master", assetArtworkData: nil, options: nil)
    downloadTask.resume()
}

UPDATE

I found a solution for the pause resume function but not on how to resume when the app is quit.

I added this function which stores the destinationURL when paused and can be used in the restore pending function.

func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didFinishDownloadingTo location: URL) {
    // Do not move the asset from the download location
    UserDefaults.standard.set(location.relativePath, forKey: "assetPath")
    destinationURL = location 
}

in donwload asset function, I changed the following line from:

  self.downloadTask = downloadSession.makeAssetDownloadTask(asset: asset, assetTitle: "VideoSample", assetArtworkData: nil, options: [AVAssetDownloadTaskMinimumRequiredMediaBitrateKey: NSNumber(value: 0)])

to:

 self.downloadTask = downloadSession.makeAssetDownloadTask(asset: asset, assetTitle: "VideoSample", assetArtworkData: nil, options: nil)

I think to set the minimum requirement was causing the issue.

Any help or direction in how to restore the pending download when quitting the application would be amazing. Thanks

STerrier
  • 3,755
  • 1
  • 16
  • 41
  • Try calling restorePendingDownloads from appDelegate using this function func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) { } – Kathir Mar 13 '20 at 13:07

1 Answers1

0

From HLSCatalog example I tried adding [AVAssetDownloadTaskMinimumRequiredMediaBitrateKey: 265_000] to options when creating AVAssetDownloadTask.

In AppDelegate I call restorePending() and getAllTasks returns number of pending tasks. In next step I still get errors, which I'm still resolving, but tasks are not empty.

I hope it helps you.

Arijan
  • 297
  • 3
  • 6