Detect when AVPlayer(ViewController) has stopped playing

For an streaming app I'm required to do a "heart beat" call to the server every 10 seconds otherwise the stream will be invalided.


I start the call by overriding the "play" function of the AVPlayer in a subclass. However I can't seem to find a way to detect when the user has pressed menu (or done on iOS) to stop the heart beats.


Looking at the rate doesn't work, because when the stream is paused, I still need to do the heart beat call.

Overriding the pause method also doesn't work because of the same reason.

The "AVPlayerItemDidPlayToEndTimeNotification" notification also does not work since it is a stream.

Replies

Hi renssies,


We do not currently offer a callback when the AVPlayerViewController is dismissed, which I believe is what you are asking about.


What you could do is associate a UITapGestureRecognizer with the view of the AVPlayerViewController, allowing the "menu" press type, and cancelling touches in view. Your selector callback will then be responsible for handling the pausing of playback and the dismissal of the AVPlayerViewController, but it would also allow you to perform any other cleanup required specific to your implementation.


I hope that helps point you on a good path forward.

TidBits: I wonder why a delegate method is not offered for the Done button touch event. It may be the only thing that's missing...


renssies: I was able to overcome this, but it may only work if AVPlayer is presented full screen I'd think:


1. Define a BOOL in the parent view and set it to YES when AVPlayerItemStatusReadyToPlay:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
                        change:(NSDictionary *)change context:(void *)context {

    if (object == self.moviePlayerVC.player && [keyPath isEqualToString:@"status"]) {

        // AVPlayer is ready to play
        if (self.moviePlayerVC.player.status == AVPlayerItemStatusReadyToPlay) {

            AVPlayerMovieIsPlaying = YES;


2. Whenever the parent subviews are being rendered, test if this method was called right after the AVPlayerViewController was either dismissed or switched to Picture in Picture mode (iOS 9):

- (void)viewWillLayoutSubviews {
    // if movie stopped playing and AVPlayer was just
    // dismissed or switched to PiP, revealing the parent views
    if (AVPlayerMovieIsPlaying) { // should be YES if AVPlayer is still up and has played for a while
        // now when the "Done" button is tapped in AVPlayerViewController,
        // the AVPlayer is not released yet, so you can't check "if (!self.moviePlayerVC)"...
        // but the video is now in Pause mode, reporting rate = 0
        // and self.view.window checks whether the parent view is shown from under AVPlayer view
        if (self.moviePlayerVC.player.rate == 0 && self.view.window) {
            [self moviePlayerDidStop]; // do whatever you want after the AVPlayer was dismissed
        }
    }
}


3. Do whatever you want after the AVPlayer was dismissed:

- (void)moviePlayerDidStop {
    AVPlayerMovieIsPlaying = NO;
    ........

I don't have an answer on that, but please do file an enhancement request with details on your use case at bugreporter.apple.com


I still believe that managing the exit of the AVPlayerViewController instance manually by utilizing the recommended gesture method above would be the most reilable way to know that the player view controller has been dismissed, since you'll be in charge of it's dismissal at that point.