This issue is that starting with iOS 5, apps are put to the background when the device goes to sleep (even if your app was the forground app!!!).
So the solution is to configure your app as one that can play audio in the background (works for video too).
First you must add this to your info.plist:
Here is a very simple view controller that works with AirPlay when your app is put to sleep:
BMTViewController.h:
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>
@interface BMTViewController : MPMoviePlayerViewController
{
}
@end
BMTViewController.m:
#import "BMTViewController.h"
@implementation BMTViewController
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[superviewDidLoad];
self.moviePlayer.allowsAirPlay = YES;
[[AVAudioSessionsharedInstance] setCategory:AVAudioSessionCategoryPlaybackerror:nil];
[[AVAudioSessionsharedInstance] setActive: YESerror: nil];
[self.moviePlayerprepareToPlay];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIApplicationsharedApplication] beginReceivingRemoteControlEvents];
[selfbecomeFirstResponder];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
//End recieving events
[[UIApplicationsharedApplication] endReceivingRemoteControlEvents];
[selfresignFirstResponder];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
returnYES;
}
//Make sure we can recieve remote control events
- (BOOL)canBecomeFirstResponder {
returnYES;
}
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
//if it is a remote control event handle it correctly
if (event.type == UIEventTypeRemoteControl) {
if (event.subtype == UIEventSubtypeRemoteControlPlay) {
[self.moviePlayer play];
} elseif (event.subtype == UIEventSubtypeRemoteControlPause) {
[self.moviePlayer pause];
} elseif (event.subtype == UIEventSubtypeRemoteControlTogglePlayPause) {
if(self.moviePlayer.playbackState == MPMoviePlaybackStatePlaying)
[self.moviePlayerplay];
else
[self.moviePlayerpause];
}
}
}
@end
Then just instantiate your view controller from your app delegate or however you like. Here's how I'm doing it in this demo app:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindowalloc] initWithFrame:[[UIScreenmainScreen] bounds]];
// Override point for customization after application launch.
NSURL* movieURL = [NSURLURLWithString:@"http://www.yourmovieurl"];
self.viewController = [[BMTViewControlleralloc] initWithContentURL:movieURL];
self.window.rootViewController = self.viewController;
[self.windowmakeKeyAndVisible];
returnYES;
}
Hope this helps everyone struggling with this issue. There is still one issue that many of you may encounter. NSTimers are suspended when the device goes to sleep, even though the movie is still playing in AirPlay. It isn't the end of the world, but I track progress of movie playback and report it back to a server periodically and I'm unable to accomplish this task with the NSTimers suspended.....sigh.
Craig