I'm trying to catch a moment when AVPlayer
is unable to continue playback in case no more media available (too slow network, signal loss, etc). As described in documentation and different examples I'm using KVO
to detect this:
item = [[AVPlayerItem alloc] initWithURL:audioURL];
player = [AVPlayer playerWithPlayerItem:item];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onItemNotification:) name:AVPlayerItemPlaybackStalledNotification object:item];
[item addObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];
[item addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];
...
- (void) onItemNotification:(NSNotification*)not
{
NSLog(@"Item notification: %@", not.name);
}
...
- (void) observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
{
NSLog(@"Observe keyPath %@", keyPath);
}
I'm starting a playback and turn WiFi
off after that. Unfortunately neither 'playbackBufferEmpty
' nor 'AVPlayerItemPlaybackStalledNotification
' comes. At the moment when playback stops I receive only one AVPlayerItemTimeJumpedNotification
and that's all.
However there were at least 2 times when I got these notifications. But I can't figure out how to get them every time when playback is stalled.
Am I doing something wrong?
How do I stop AVPlayer in Objective C? AVPlayer does not have a method named stop . You can pause or set rate to 0.0.
An object that models the timing and presentation state of an asset during playback.
VideoPlayer in SwiftUIimport AVKit import SwiftUI struct ContentView: View { var body: some View { VideoPlayer(player: AVPlayer(url: Bundle. main. url(forResource: "movie", withExtension: "mp4")!)) } }
First try to disconnect internet from your router and you will get playbackBufferEmpty notification. To handle network switching you will need to implemented Reachability
There are 2 cases where player can get stuck: it never starts or it runs out of buffered data. I use the following to handle both cases:
When you create a AVPlayer instance:
[_player addObserver:self forKeyPath:@"rate" options:0 context:nil];
[_player.currentItem addObserver:self forKeyPath:@"status" options:0 context:nil];
This is the handler:
-(void)observeValueForKeyPath:(NSString*)keyPath
ofObject:(id)object
change:(NSDictionary*)change
context:(void*)context {
if ([keyPath isEqualToString:@"status"]) {
if (_player.status == AVPlayerStatusFailed) {
//Failed to start.
//Description from the docs:
// Indicates that the player can no longer play AVPlayerItem instances because of an error. The error is described by
// the value of the player's error property.
}
} else if ([keyPath isEqualToString:@"rate"]) {
if (_player.rate == 0 && //playback rate is 0
CMTIME_COMPARE_INLINE(_player.currentItem.currentTime, >, kCMTimeZero) && //video has started
CMTIME_COMPARE_INLINE(_player.currentItem.currentTime, <, _player.currentItem.duration) && //video hasn't reached the end
_isPlaying) { //instance variable to track playback state
//Video stalled. Possible connection loss or connection is too slow.
}
}
}
Don't forget to remove observers when you are done:
[_player.currentItem removeObserver:self forKeyPath:@"status"];
[_player removeObserver:self forKeyPath:@"rate"];
See my answer here to see how I handle stalled video: AVPlayer stops playing and doesn't resume again
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