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:
- Create an
AVURLAsset
using a URL likehttps://my.cdn.com/playlist.m3u8
- Set its resource loader's delegate
- Give it to a player in the form of an
AVPlayerItem
- Using the methods in
AVAssetResourceLoaderDelegate
, look for a URL beginning the schemeskd
, download the CKC, get the persist-able form, and hand it back to the resource loader request
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:
- Make an
AVURLAsset
- Make an
AVPlayer
and set its volume to 0 - Give it the asset and play it
- Wait until it requests its keys from the resource loader and starts playing
- Give it to a download task and deassociate it with the player
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?
Turns out you set
preloadsEligibleContentKeys
to true on the asset's resource loader. Then you can download: