Responding to MPMoviePlayerController notifications during background media playback
Asked Answered
J

3

6

I have an app that streams video from the net and plays it using an MPMoviePlayerController object for playback on the device or via AirPlay.

The app supports background operation and has the 'audio' option listed within the required UIBackgroundModes key in its plist file.

When playing over AirPlay, the app can successfully be pushed to the background and the video continues to play properly. So far, so good.

According to the Apple documentation:

Including the audio key tells the system frameworks that they should continue playing and make the necessary callbacks to the app at appropriate intervals. If the app does not include this key, any audio being played by the app stops when the app moves to the background.

However, these callbacks are not being made.

The app uses two types of callback: those associated with notifications MPMoviePlayerController and AVPlayer send during playback together with timer based callbacks that monitor the playback position and performance stats for monitoring purposes.

Looking at Apple's notes, I would certainly expect to receive the first type of callback so that the app can respond to MPMoviePlayerPlaybackStateDidChangeNotification, MPMoviePlayerPlaybackDidFinishNotification and MPMoviePlayerLoadStateDidChangeNotification, but this doesn't happen.

Does anyone know if it is possible to receive these during background AirPlay playback and, if so, how was this achieved?

**Please note: the app works correctly when running in the foreground and receives the notifications fine. It is only when pushed to the background and playing over AirPlay that the notifications are not received.

Likewise, the video plays over AirPlay in the background properly. It is only the notifications which are not received**

Jagir answered 31/1, 2012 at 19:40 Comment(0)
J
0

For completeness, I ought to add that at present I believe there is no solution to this problem.

I've discussed it directly with Apple via tech support and there was no practical work-around available.

This functionality was needed to allow the app to record stats about the playback of the stream at regular intervals. While this is fine when the video is played on the device's screen and over AirPlay while the app is in the foreground, it isn't possible to do with the app in the background.

The solution I've gone with instead is to disable the idle timer during all types of playback and to re-enable afterwards using:

[UIApplication sharedApplication].idleTimerDisabled = YES;

and

[UIApplication sharedApplication].idleTimerDisabled = NO;

While this isn't a solution to the original question, it's a workaround for avoiding the issue in the first place.

Jagir answered 15/2, 2012 at 17:34 Comment(0)
H
4

I had this issue and have fixed it though it was a few months back. I could send you my entire class for movie playback if this doesn't work. Note it is using the navigation controller model.

NOTE: This is tested on iPad 2 not on the iPhone.

I show my VC like this:

 - (IBAction)playMovie:(id)sender {

    MovieVC* movController = [[MovieVC alloc] initWithID:2];
    movController.view.backgroundColor = [UIColor blackColor];
    AppDelegate *appDel = [[UIApplication sharedApplication] delegate];

    [appDel.navigationController pushViewController:movController animated:NO];
    [movController release];
}

Then in my MovieVC view controller class i set up the video playback like this:

- (void)initMoviePlayer {

    mMoviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:[self getMovieURL]];

    mMoviePlayer.allowsAirPlay = YES;   

    mMoviePlayer.view.frame = [self.view bounds];

    mMoviePlayer.view.backgroundColor = [UIColor clearColor];

    mMoviePlayer.shouldAutoplay = YES;

    mMoviePlayer.fullscreen = YES;

    mMoviePlayer.scalingMode = MPMovieScalingModeAspectFit;

    [[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(moviePreloadDidFinish:) 
                                             name:MPMoviePlayerLoadStateDidChangeNotification 
                                           object:mMoviePlayer];

    [[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(moviePlayBackDidFinish:) 
                                                  name:MPMoviePlayerPlaybackDidFinishNotification 
                                           object:nil];
}

This fixed it for me, if it doesn't fix comment and ill edit with the entire class file.

Hartfield answered 11/2, 2012 at 11:29 Comment(7)
Yes, this correctly gets the notifications when the app is in the foreground, but not when it has been pushed to the background with a multi-tasking app.Jagir
@virorum: ok at the risk of sounding foolish. When the app enters the background doesn't the video playback on apple TV stop ? Reason i ask is as far as i am aware notifications and threads would be stopped on an app in the background. Reason being is that a snapshot is stored, not a running application as you would get on a desktop machine. Meaning that even if an event is dispatched to your app it wont have any effect as your application isn't listening for notifications. You are supposed to unregister for notifications on entering background and then on entering foreground register again.Hartfield
No :) As I say in the question, the UIBackgroundModes is set correctly and the video continues to play properly. It is just the notifications which do not fire.Jagir
@Virorium Yeah after a re-check of the docs, if the app enters suspended mode after being put in the background then it will queue some (not all notifications). So upon bringing the app into the acitive/background state the app will then deliver them. So you can either check the state of the app when its gone into the background. But from what i read it would appear that there might not be support for those notifications in the background. Id recommend pinging apple on there forum to be honest.Hartfield
The odd thing is, when doing this just with music in a Spotify type app, you do get the notifications.Jagir
Out of interest was that app using airplay or MPMoviePlayerController? I know that MPMoviePlayerController has its very own way of handling this stuff over airplay as it was a big sale when airplay support was released by apple.Hartfield
let us continue this discussion in chatJagir
C
2

In one of my projects I did what you did, and it worked for me. Two differences in my project :

  • I am not streaming via airPlay (device playback only),
  • I am just playing audio files.

My step-by-step :

  • Add the audio option to UIBackgroundModes in the plist file,
  • Register to the NotificationCenter for MPMoviePlayerPlaybackDidFinishNotification and MPMoviePlayerPlaybackStateDidChangeNotification with the following code :

    [[NSNotificationCenter defaultCenter]
                    addObserver:self
                       selector:@selector(playbackStateChanged:)
                           name:MPMoviePlayerPlaybackStateDidChangeNotification
                         object:moviePlayer];
    
    [[NSNotificationCenter defaultCenter]
                    addObserver:self
                       selector:@selector(playbackEnded:)
                           name:MPMoviePlayerPlaybackDidFinishNotification
                         object:moviePlayer];
    

It works like a charm.

Carnage answered 9/2, 2012 at 13:53 Comment(4)
Yes, playing audio just through the device does work fine. Unfortunately, it's AirPlay and video that are needed I'm afraid.Jagir
@virorum If you remove airplay from the equation, do the callbacks do get called? If so, it sounds like an Apple bug. Otherwise maybe mmich will be kind enough to share his code ;)Behaviorism
The calls do get made when in the foreground. It is only when playing over AirPlay in the background that they don't. I think it may be an Apple thing though.Jagir
When playing not over airplay in the background do they get called? That's what I meant.Behaviorism
J
0

For completeness, I ought to add that at present I believe there is no solution to this problem.

I've discussed it directly with Apple via tech support and there was no practical work-around available.

This functionality was needed to allow the app to record stats about the playback of the stream at regular intervals. While this is fine when the video is played on the device's screen and over AirPlay while the app is in the foreground, it isn't possible to do with the app in the background.

The solution I've gone with instead is to disable the idle timer during all types of playback and to re-enable afterwards using:

[UIApplication sharedApplication].idleTimerDisabled = YES;

and

[UIApplication sharedApplication].idleTimerDisabled = NO;

While this isn't a solution to the original question, it's a workaround for avoiding the issue in the first place.

Jagir answered 15/2, 2012 at 17:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.