问题
I’m using AVPlayer
to implement a custom video player in an iOS application. To play video from the network I allocate a player:
[[AVPlayer alloc] initWithURL:_URL];
Create an asset:
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:self.URL
options:@{AVURLAssetPreferPreciseDurationAndTimingKey : @(YES)}];
load the playable
key asynchronously:
NSArray *keys = @[@"playable"];
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
for (NSString *key in keys) {
NSError *error;
AVKeyValueStatus status = [asset statusOfValueForKey:key error:&error];
if (status == AVKeyValueStatusFailed) {
NSLog(@"Failed to load asset key %@ error %@", key, [error localizedDescription]);
[self fail];
return;
}
}
if (asset.isPlayable) {
[self.player replaceCurrentItemWithPlayerItem:self.playerItem];
}
else {
[self fail];
}
});
}];
The problem is that when the device has no internet connection or high packet loss, the completionHandler
is never called (even after waiting for minutes) and so I have no idea when to show a message to the user that loading the video failed.
My questions are:
- Am I missing something / is there a better way to handle this?
- Should I roll my own timeout logic or should I just never
loadValuesAsynchronouslyForKeys:
whenReachability
believes that the network isn't reachable. - What are the best practices regarding
AVPlayer
and network failures?
回答1:
You should be observing (KVO) features of the AVPlayerItem that reveal how the buffer is doing, such as playbackBufferEmpty
etc.
回答2:
I've integrated AVAsset before, but haven't run into this specific issue. Nonetheless, here's what I would do:
- Set a timer or delayed block dispatch for the length of the timeout you'd like to enforce.
- Check the value of the "playable" key with
statusOfValueForKey:error:
. - If the status is not
AVKeyValueStatusLoaded
or error is not nil, call[asset cancelLoading]
and display an error message to the user or whatever cleanup you might need to do.
回答3:
It turns out that this may have been related to the way I was testing. Using the Network Link conditioner didn't trigger the block, but when I actually blocked the host using Charles Proxy, everything worked as intended. I'm trying to go with my original code for now, and will add in some of Dan's ideas if it proves to be problematic still during real world testing
来源:https://stackoverflow.com/questions/23701057/how-does-avplayer-avplayeritem-inform-my-application-about-unreachable-network