我想通过 playerFailedToReachEnd 通知或通过 KVO 观察 player.status 强制 AVPlayer 抛出播放器错误,当在通过 AVAssetResourceLoader 加载资源请求的过程中请求完成加载错误时。
它不应该在 AVPlayer 上进行手动播放停止,以避免处理手动停止和 KVO/通知之间的竞争条件
避免发生错误时在 AVPlayer 上手动停止播放以避免竞争条件。
尝试返回回调“resourceLoader:shouldWaitForLoadingOfRequestedResource:”的部分以返回 NO 它不会使 AVPlayer 将状态更改为失败,也不会发送有关播放器失败的通知
@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
在调用 AVAssetResourceLoadingRequest.finishLoadingWithError() 时预期 AVPlayer 将发送失败通知或 KVO 状态更改
实际 AVPlayer 没有状态变化也没有失败通知