Offline Fairplay AVAssetDownloadTask got unknown error callback while downloading (only happened on iOS 10.2)

1.9k views Asked by At

We're building offline fairplay content for our client app; we implemented that feature by referencing to Apple sample download manager AssetPersistenceManager class in HLSCatalog demo app. There is one function, and two call back in AssetPersistenceManager class that I want to highlight here, it's

    /
    func downloadStream(for asset: Asset) {
        /
         For the initial download, we ask the URLSession for an AVAssetDownloadTask
         with a minimum bitrate corresponding with one of the lower bitrate variants
         in the asset.
         */
        guard let task = assetDownloadURLSession.makeAssetDownloadTask(asset: asset.urlAsset, assetTitle: asset.name, assetArtworkData: nil, options: [AVAssetDownloadTaskMinimumRequiredMediaBitrateKey: 265000]) else { return }

        /
        task.taskDescription = asset.name

        activeDownloadsMap[task] = asset

        task.resume()

        var userInfo = [String: Any]()
        userInfo[Asset.Keys.name] = asset.name
        userInfo[Asset.Keys.downloadState] = Asset.DownloadState.downloading.rawValue

        NotificationCenter.default.post(name: AssetDownloadStateChangedNotification, object: nil, userInfo:  userInfo)
    }

And callback when it's finished downloading the stream

func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didFinishDownloadingTo location: URL) {
    let userDefaults = UserDefaults.standard

    /
     This delegate callback should only be used to save the location URL
     somewhere in your application. Any additional work should be done in
     `URLSessionTaskDelegate.urlSession(_:task:didCompleteWithError:)`.
     */
    if let asset = activeDownloadsMap[assetDownloadTask] {

        userDefaults.set(location.relativePath, forKey: asset.name)
    }
}

The last is didCompleteWithError callback

func urlSession(_ session: URLSession, task: URLSessionTask,
didCompleteWithError error: Error?)

Everything seems works fine on iOS < 10.2, but after test on some device which running latest iOS 10.2, the app alway got callback to didFinishDownloadTo delegate while only 13-15% completed percent, after that the didCompleteWithError is called and we received below error

> "=======> completed percent 11.2888760669556" .
> "=======> completed percent 11.44566601233" 
> "=======> completed percent 11.7592459030787"
> "=======> completed percent 12.0728257938275" 
> "=======> completed percent 12.5431956299506" 
> "=======> completed percent 13.0135654660738" 
> "=======> completed percent 13.3271453568226" 
> "=======> completed percent 13.6407252475713" 
> "=======> completed percent 13.9543051383201" 
> "=======> completed percent 14.1110950836945" 
> "=======> completed percent 14.2678850290689" 
> "Error Domain=AVFoundationErrorDomain Code=-11800 \"The operation could not
> be completed\" UserInfo={NSLocalizedDescription=The operation could
> not be completed, NSLocalizedFailureReason=An unknown error occurred
> (-12667)}"

Checking with the proxy debugging app, it points out that app closes the connection before entire receive response.

Status
Complete
Failure
Client closed connection before receiving entire response
Response Code
206 Partial Content

Only iOS 10.2 has that error, the same stream tested on other OS below that version is still working fine. Trying to find some changelog for iOS 10.2 about this part but I found nothing? Do you guys have any advice?

1

There are 1 answers

4
untouchable On BEST ANSWER

We found out the answer ourself after a week stucking with it. It turned out to be bugs on iOS 10.0 - 10.1 instead of 10.2. The error occurs after 30s is related to DRM error, it happened on iOS 10.2, after AVAssetDownloadTask are resumed there is a callback from AVAssetResourceLoaderDelegate and you need to hit server key to fulfill the Fairplay DRM content key in

func resourceLoader(_ resourceLoader: AVAssetResourceLoader, 
shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool

Otherwise, download will be forced to stop and you will receive unknown error as mentioned above. Apple sample code HLSCatalog is just demo for non-DRM stream, and they didn't even mention about the content key fulfillment required in the demo.

We have followed their sample and seem iOS 10.0 - 10.1, AVFoundation didn't check the content key on processing download, that's the reason why when we first implementing our Download feature, we thought content key isn't needed when downloading, that lead us to a wasteful week on stucking in iOS 10.2...