I have been working on a simple AVPlayer
to play encrypted HLS
media.
I am using the AVAssetResourceLoaderDelegate
to handle the key retrieving process so the encrypted media can be played with a valid key.
The program works perfectly on simulator, but it doesn't work at all on device.
Here are the codes:
- (void) playUrlByAVPlayer:(NSString *) videoUrl
{
NSURL *streamURL = [NSURL URLWithString:videoUrl];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:streamURL options:nil];
[asset.resourceLoader setDelegate:self queue:dispatch_get_main_queue()];
self.playerItem = [AVPlayerItem playerItemWithAsset:asset];
self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
[self.playerLayer setFrame:self.view.frame];
[self.view.layer addSublayer:self.playerLayer];
[self.player play];
}
After some debugging, I realized that the delegate method shouldWaitForLoadingOfRequestedResource
was never called on device.
I have read other relevant questions:
AVAssetResourceLoaderDelegate not being called
AVAssetResourceLoaderDelegate - Only requests first two bytes?
and I tried enclosing all codes within a dispatch_async
, dispatch_get_main_queue
block but there's no luck on solving mine.
Currently my codes above are not enclosed by any dispatch queue blocks.
Any thoughts on the problem?
If you take a look on Apple example code where they show bipbop.m3u8 HLS playback you will see that they are using masks for real http requests: "http:/host/bipbop.m3u8" => "custom_scheme:/host/bipbop.m3u8" Same trick should be made with playlist subresources.
Otherwise avplayer ignores AVAssetResourceLoaderDelegate and load data directly.
You need to implement some kind of mapping:
NSString* videoUrl = @"fake_scheme://host/video.m3u8";
NSURL *streamURL = [NSURL URLWithString:videoUrl];
As I mentioned in the other thread as well, AVAssetResourceLoaderDelegate works only when we use a "Non Standard/Non Reserved" url scheme. HTTP, HTTPS etc are considered reserved URL schemes and iOS will not make a delegate call if the URL has one of those schemes. What I ended up doing was using my_own_http for the http urls and my_own_https for the https urls. It works well after I made that change. As you know this makes your playlist unusable on other deices.
In your delegate shouldWaitForLoadingOfRequestedResource
change the URL scheme back to http:
NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:loadingRequest.request.URL resolvingAgainstBaseURL:NO];
urlComponents.scheme = @"http";
NSMutableURLRequest *mutableLoadingRequest = [loadingRequest.request mutableCopy];
[mutableLoadingRequest setURL:urlComponents.URL];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With