Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AVAssetResourceLoaderDelegate methods not working on device

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?

like image 640
onsankawai Avatar asked Oct 30 '14 09:10

onsankawai


3 Answers

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];
like image 176
Chugaister Avatar answered Sep 28 '22 18:09

Chugaister


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.

like image 28
Dvyz Avatar answered Sep 28 '22 18:09

Dvyz


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];
like image 20
Alex Avatar answered Sep 28 '22 16:09

Alex