iosavassetdownloadtaskavassetresourceloaderdelegate

How can I use AVAssetDownloadTask to download a FairPlay-encrypted AVURLAsset instance that has not yet been streamed?


I'm trying to use AVAssetDownloadTask to download and play FairPlay-encrypted audio content offline. I kept getting an error like this in urlSession:task:didCompleteWithError::

Error Domain=AVFoundationErrorDomain Code=-11863 "Operation Stopped" UserInfo={NSLocalizedFailureReason=This content is no longer available., NSLocalizedDescription=Operation Stopped}

My flow was:

All of this worked, and was done in the same way as in Apple's HLSCatalog sample code. But downloading would still give me the above error, even though plugging the same playlist and key URLs into the sample code would download fine.

What I finally figured out was that AVAssetDownloadTask will only download an AVURLAsset instance that has already been streamed and given its decryption keys (via the AVAssetResourceLoaderDelegate) and that is not associated with a player. I can't just make a new AVURLAsset using the same URL as what is already playing and download it. So it seems that in order to download arbitrary FairPlay content, I have to:

But this seems horrible. It can't be true.

So, my question: How do I download a FairPlay-encrypted AVURLAsset without having streamed that specific instance of it before?


Solution

  • Turns out you set preloadsEligibleContentKeys to true on the asset's resource loader. Then you can download:

    AVURLAsset *asset = [AVURLAsset assetWithURL:self.currDownload.url];
    [asset.resourceLoader setDelegate:self queue:dispatch_get_main_queue()];
    asset.resourceLoader.preloadsEligibleContentKeys = YES;
    AVAssetDownloadTask *task = [self.downloadSession assetDownloadTaskWithURLAsset:asset assetTitle:self.currDownload.title assetArtworkData:nil options:@{AVAssetDownloadTaskMinimumRequiredMediaBitrateKey: @(265000)}];
    task.taskDescription = self.currDownload.title;
    [task resume];