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?
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
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...