How to force AVPlayer to fail when AVAssetResourceLoadingRequest's finishLoadingWithError(err) is called

638 views Asked by At

I want to force AVPlayer to throw the player error, either through the playerFailedToReachEnd notification or observe player.status via KVO, when during the process of loading resource request via AVAssetResourceLoader that the request is finished loading with error.

It should not do the manual playback stop on AVPlayer to avoid dealing with the race condition between the manual stop and the KVO/notifications

Manual playback stop on AVPlayer when error occurred is refrained to avoid race condition.

Tried the part to return the callback 'resourceLoader:shouldWaitForLoadingOfRequestedResource:' to return NO it doesn't make AVPlayer change state to Failure nor does it send notification about player failure


@implementation AssetLoader <AVAssetResourceLoaderDelegate>

- (AVPlayerItem *)setupLoader {

    NSURL *playbackUrl = [NSURL URLWithString:@"example-url"];
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:playbackUrl options:nil];

    [asset.resourceLoader setDelegate:self queue:_sample_queue];
    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
    return playerItem;
}

- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest {

    if ([url.scheme isEqual:@"skd"] == NO) {
        QPLogError(@"Unexpected url scheme: %@", url.absoluteString);
        return NO;
    }

    LicenseAction *action = [[LicenseAction alloc] initWithLoadingRequest:loadingRequest];

    [action execute:^(NSData *ckcData, NSError *error) {
         if (error) {
             [loadingRequest finishLoadingWithError:error]; //This should prompt AVPlayer to fail 
         } else {
              [loadingRequest.dataRequest respondWithData:ckcData];
              [loadingRequest finishLoading];
         }

    }];
    return YES;
}

...

@end
@implementation Player {
   AVPlayer *_player;

}

- (void)prepare {
    [_player replaceCurrentItemWithPlayerItem:playerItem];

    NSKeyValueObservingOptions options = (NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld | NSKeyValueObservingOptionInitial);
    [_player addObserver:self forKeyPath:@"status" options:options context:&QPClearPlayerAVPlayerKVOContext];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemFailedToEnd:) name:AVPlayerItemFailedToPlayToEndTimeNotification object:_player.currentItem];

}

- (void)stopWithError {
   ...
   [self reportPlayerError];
}
...
- (void)playerItemFailedToEnd:(NSNotification *)notification {
   ...
   [self reportPlayerError];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if(object == _player && keyPath == @"status") {
        ...
        if (_player.status == AVPlayerStatusFailed) {
            [self reportPlayerError];
        }
    }
}

...

@end

Expected upon invoking AVAssetResourceLoadingRequest.finishLoadingWithError() that the AVPlayer would send a failed notification or KVO status changes

Actual AVPlayer doesn't have status change nor failed notification

0

There are 0 answers