Work with kiosks AVPlayer

I am trying to catch the moment when AVPlayer cannot continue playing if there are no media available (network too slow, signal loss, etc.). As described in the documentation and various examples, I use 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 start playback and turn off WiFi after that. Unfortunately, neither " playbackBufferEmpty " nor " AVPlayerItemPlaybackStalledNotification " comes. At the time of stopping playback, I get only one AVPlayerItemTimeJumpedNotification and that's it. However, when I received these notifications, it was at least 2 times. But I can’t understand how to get them every time the playback stops. Am I doing something wrong?

+6
source share
2 answers

First, try disconnecting the Internet from your router, and you will receive a BufferEmpty playback notification. To manage network switching, you need to perform Reachability

+2
source

There are two cases where a player may be stuck: he never starts or ends with buffered data. To handle both cases, I use the following:

When creating an 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 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. } } } 

Remember to remove the watchers when you are done:

 [_player.currentItem removeObserver:self forKeyPath:@"status"]; [_player removeObserver:self forKeyPath:@"rate"]; 

See my answer here to see how I handle a locked video: AVPlayer stops playing and does not resume again

0
source

All Articles