While playing a video, I'm seeing rate change notifications from AVPlayer
that don't seem to be connected to app activity.
When my app receives a UIApplicationDidEnterBackgroundNotification
notification, I tell the AVPlayer
to pause
. The logic is that it should come back to the foreground at the same place the user left. If I do not call pause
when going to the background, the problem doesn't appear.
The sequence of events sent to the player is pause
, seekToTime:
, play
. Generally, this works fine but, after the app has been sent to the background and then returned to the foreground, each play
invocation results in two rate changes from the AVPlayer
. The first is to 1 and the second, immediately following, is to 0. This pattern continues for each call to -[AVPlayer play]
as long as that player instance is in use.
I'm able to put a breakpoint on -[AVPlayer pause]
and I do not see it being hit when the rate changes to 0. If I comment out the seekToTime:
call, the problem goes away. If I use seekToTime:completionHandler:
, I also get the same problem although my block's finished
parameter is YES
.
Apart from "how do I fix this", I'm interested in any details about how to detect the reason for rate changes in AVPlayer
that aren't connected to play
/pause
. (Putting a breakpoint on -[AVPlayer setRate:]
never seems to trigger.)
(One workaround that almost works is to save the player position when entering the background, let it play, and fix the position when returning to the foreground. This also requires some manipulation of audio levels, which is probably doable, but another problem is that not all background notifications indicate that the view has been obscured (e.g. double-tap home button). This leads to cases where my workaround shows a distracting moving image when the app is interrupted but still visible.)
Suggestions?
(A last bit of extra information: In all the cases I've tried, I eventually get to a state where the AVPlayer is changing the rate from 1 to 0 moments after I invoke 'play' if I've returned from the background and then performed a seek. There are things I can do to make it less frequent but none that eliminate it except getting rid of the AVPlayer and creating a new instance. This results is very long delays but is better than a complete malfunction...I guess.
I have some evidence that the seek distance affects the result, which suggests that the error might be in the underlying buffering mechanism. Without knowing what causes the rate change (other than play/pause) I don't see a way to investigate further.)
You are probably getting an AVPlayerItemPlaybackStalledNotification
.
Try this:
[[NSNotificationCenter defaultCenter]
addObserverForName:AVPlayerItemPlaybackStalledNotification
object:cell.avPlayerItem
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
DDLogVerbose(@"%@", @"AVPlayerItemPlaybackStalledNotification");
}];
However, Apple docs say Playback will continue once a sufficient amount of media has subsequently been delivered.
(https://developer.apple.com/library/iOS/documentation/AVFoundation/Reference/AVPlayerItem_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40009532-CH1-SW83)
This is not happening for me or you.
I am still tracking the reason down.
EDIT:
This was the problem for me. When AVPlayerItem.likelyToKeepUp
was YES then it wouldn't happen.
Not sure why it wasn't resuming.
EDIT:
From the Apple docs there is a situation where playback will not resume:
This property communicates a prediction of playability. Factors considered in this prediction include I/O throughput and media decode performance. It is possible for playbackLikelyToKeepUp to indicate NO while the property playbackBufferFull indicates YES. In this event the playback buffer has reached capacity but there isn't the statistical data to support a prediction that playback is likely to keep up in the future.
It is up to you to decide whether to continue media playback.
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