I have an app that streams audio protected by FairPlay DRM. It originally shipped using AVAssetResourceLoaderDelegate
to deliver FairPlay keys, but now I'm updating it to use AVContentKeySession
for iOS 11.2 and later. Side note: if you're trying to do this and are frustrated at the lack of documentation, there's sample code at the "FairPlay Streaming Server SDK (4.2.0)" link here.
Each of my audio products is broken into many tracks. When I open an audio product, I queue up more than one track, via AVQueuePlayer
. Each of those tracks generates a request for a FairPlay key. In the case when there is no persistent key already downloaded, each of those requests goes to the key server, downloads a key, generates a persistent key, and saves it. Each track has the same key, so they all end up with the same persistent key data, and each one overwrites the last one to finish.
Because the cost of my key servers is dependent on the number of key requests I make, I'd like to have only the first request actually hit the key server, and subsequent requests use the persistent key. But the method used to get the SPC data to pass up to the key server, makeStreamingContentKeyRequestDataForApp
, uses an async completion block. The equivalent method on AVAssetResourceLoadingRequest
is synchronous.
My question: is it safe to force this call to be synchronous using a semaphore? Like this:
-(void)handleOnlineRequest:(AVContentKeyRequest *)req
NSData *appCert = [self _getAppCertData];
NSData *assetId = [self _kidFromRequest:req];
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
[req makeStreamingContentKeyRequestDataForApp:appCert
contentIdentifier:assetId
options:nil
completion:^
NSData *contentKeyRequestData, NSError *error)
{
//request key data and respond to request
dispatch_semaphore_signal(sema);
}];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
dispatch_release(semaphore);
The effect is especially pronounced when downloading audio that has not been streamed before. Download speeds for audio using AVAssetDownloadTask are very slow, so I initiate many at once, and each one generates a key request.