iPod Controls in Lockscreen for own App - iphone

How can I use the Lock Screen iPod Controls for my own App?
I tried MPNowPlayingInfoCenter, but if I set the information it won't be displayed anywhere; Not on the lock-screen and not in airplay on AppleTV.
I use the AVPlayer to play my audio files.

Take a look at the Remote Control of Multimedia documentation.
Here’s how to listen for remote control events in a UIViewController subclass. First, make your controller participate in the responder chain, otherwise the events will be forwarded to the app delegate:
- (BOOL)canBecomeFirstResponder
{
return YES;
}
Where appropriate, tell the application to start receiving events and make your controller the first responder:
// maybe not the best place but it works as an example
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
Then respond to them:
- (void) remoteControlReceivedWithEvent: (UIEvent *) receivedEvent {
if (receivedEvent.type == UIEventTypeRemoteControl) {
switch (receivedEvent.subtype) {
case UIEventSubtypeRemoteControlTogglePlayPause:
[self playOrStop: nil];
break;
case UIEventSubtypeRemoteControlPreviousTrack:
[self previousTrack: nil];
break;
case UIEventSubtypeRemoteControlNextTrack:
[self nextTrack: nil];
break;
default:
break;
}
}
}

Related

iOS MPMoviePlayerController playing audio in background

I have MPMoviePlayerController that should play video's audio in background and should be controlled by the multitasking play/pause controls.
After updating .plist file with Required background modes and calling the following:
- (void)startBackgroundStreaming
{
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
NSError *activationError = nil;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:&activationError];
[audioSession setActive:YES error:&activationError];
}
The app icon appears in the multitasking play/pause bar, but these buttons don't respond.
Thanks!
The missing piece of the puzzle is handling the remote control events you are receiving. You do this by implementing the -(void)remoteControlReceivedWithEvent:(UIEvent *)event method in your application delegate. In its simplest form it would look like:
-(void)remoteControlReceivedWithEvent:(UIEvent *)event{
if (event.type == UIEventTypeRemoteControl){
switch (event.subtype) {
case UIEventSubtypeRemoteControlTogglePlayPause:
// Toggle play pause
break;
default:
break;
}
}
}
However this method is called on the application delegate, but you can always post a notification with the event as the object so that the view controller that owns the movie player controller can get the event, like so:
-(void)remoteControlReceivedWithEvent:(UIEvent *)event{
[[NSNotificationCenter defaultCenter] postNotificationName:#"RemoteControlEventReceived" object:event];
}
Then grab the event object in the listener method you assign to the notification.
-(void)remoteControlEventNotification:(NSNotification *)note{
UIEvent *event = note.object;
if (event.type == UIEventTypeRemoteControl){
switch (event.subtype) {
case UIEventSubtypeRemoteControlTogglePlayPause:
if (_moviePlayerController.playbackState == MPMoviePlaybackStatePlaying){
[_moviePlayerController pause];
} else {
[_moviePlayerController play];
}
break;
// You get the idea.
default:
break;
}
}
}

remoteControlReceivedWithEvent Never called

I'm trying to allow a remote or earbuds to play and pause audio when the app is in background or the screen is locked. So In viewDidLoad I have:
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
I then have:
- (void) remoteControlReceivedWithEvent: (UIEvent *) receivedEvent {
if (receivedEvent.type == UIEventTypeRemoteControl) {
switch (receivedEvent.subtype) {
case UIEventSubtypeRemoteControlTogglePlayPause:
[self playOrStop];
break;
case UIEventSubtypeRemoteControlPreviousTrack:
break;
case UIEventSubtypeRemoteControlNextTrack:
break;
default:
break;
}
}
}
But, it never gets called. Running in background is turned on, the AVSession is set in AppDelegate. I'm at a loss.
You probably also need to add:
- (BOOL)canBecomeFirstResponder {
return YES;
}
Any subclass of UIResponder needs to implement this, or it won't accept first responder status.
Try putting
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
in viewWillAppear:(BOOL)animated instead of viewDidLoad.

remoteControlReceivedWithEvent not Called in appDelegate

I'm having problem to control the iPhone controls with my avplayer.
if I put the function
- (void)remoteControlReceivedWithEvent:(UIEvent *)event
in the view controller that responsible for playing the function called but only if I i'm going to background in the current view controller.
if i'm going to background from other view controller the function never called.
that's why i want to put it in the app delegate.
I tried Becomefirstresponse and to put the function in every view controller but it did help.
also I call
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
in the
-(void)applicationWillResignActive:(UIApplication *)application
thanks
I have used below code to iPhone Control -
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
Used to get register for listening the remote control.
Once done remove it -
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
make the App canBecomeFirstResponder-
- (BOOL)canBecomeFirstResponder {
return YES;
}
Used delegate method to handle iPhone control, like play and pause while doble tap on the home button
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
//if it is a remote control event handle it correctly
if (event.type == UIEventTypeRemoteControl) {
if (event.subtype == UIEventSubtypeRemoteControlPlay) {
[audioPlayer play];
NSLog(#"play");
} else if (event.subtype == UIEventSubtypeRemoteControlPause) {
[audioPlayer stop];
NSLog(#"pause");
} else if (event.subtype == UIEventSubtypeRemoteControlTogglePlayPause) {
NSLog(#"toggle");
}
}
}
In my case i am able to handle play and pause.Please let know if any thing wrong.
You can move the function up the responder chain, to UIApplication subclass. This way, it will always be there to catch the event.
This kind of event is ignored in common UI and controller classes, so it travels up to the bottom of responder chain, where your app delegate and the the application itself reside.
As noted here, UIApplication's delegate is not part of responder chain (I was wrong here). UIApplication is there, so is root UIWidow, all the views in chain and corresponding UIViewControllers.
Hint: becomeFirstResponder must be called from within viewDidAppear, not viewWillAppear...
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self becomeFirstResponder];
}

I have an iPad app that plays audio in background but app icon is not appear with ipod controls

My problem is - when audio is playing in background in my iPad then "my app icon" is not coming. I am using iPodMusicPlayer. For playing audio in background I have write these code..
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
- (void)viewWillDisappear:(BOOL)animated
{
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
[super viewWillDisappear:animated];
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
// The iPod controls will send these events when the app is in the background
- (void) remoteControlReceivedWithEvent: (UIEvent *) receivedEvent {
if (receivedEvent.type == UIEventTypeRemoteControl) {
switch (receivedEvent.subtype) {
case UIEventSubtypeRemoteControlTogglePlayPause:
[self performSelector:#selector(playPause:)];
break;
case UIEventSubtypeRemoteControlPreviousTrack:
//[self previousSong:nil];
//[self performSelector:#selector(previousSong:)];
break;
case UIEventSubtypeRemoteControlNextTrack:
//[self performSelector:#selector(nextSong:)];
break;
default:
break;
}
}
}
and info.plist I have also set "required background mode"
You will also have to add UIBackgroundModes to your Info.plist and set its value to audio.
Please check the iOS App Programming Guide, specifically the App States and Multitasking section for detailed info on how to execute tasks in background.
[UPDATE]
Also add these two lines to application:didFinishLaunchingWithOptions: in your AppDelegate.m:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
And this code when you start playing your audio:
UIBackgroundTaskIdentifier newTaskId = UIBackgroundTaskInvalid;
[_player play];
newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
This should do it. Tested in the simulator, as well as on a device.

MPMoviePlayerViewController running in background and using Remote Controls

I'm currently running on iOS 4.3.5 and trying to get my MPMoviePlayerViewController to continue playing after entering background.
I implemented everything as it is described on
http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
and
http://developer.apple.com/library/ios/#documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/RemoteControl/RemoteControl.html
I have also set the UIBackgroundMode to audio.
My custom MPMoviePlayerViewController class is called like this from a TabBarApplication:
NSURL *streamUrl = [NSURL URLWithString:STREAM_URL];
self.playerViewController = [[CustomMoviePlayerViewController alloc] initWithContentURL:streamUrl];
// Register for the playback finished notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(myMovieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.playerViewController.moviePlayer];
// Present
[self presentMoviePlayerViewControllerAnimated:self.playerViewController];
// Play the movie!
self.playerViewController.moviePlayer.movieSourceType = MPMovieSourceTypeStreaming;
[self.playerViewController.moviePlayer prepareToPlay];
[self.playerViewController.moviePlayer play];
Inside my CustomMovePlayerController looks like the following:
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
-(void)viewWillAppear:(BOOL)animated {
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
-(void)viewWillDisappear:(BOOL)animated {
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
[super viewWillDisappear:animated];
}
-(BOOL)canBecomeFirstResponder {
return YES;
}
-(void)remoteControlReceivedWithEvent:(UIEvent *)event {
[super remoteControlReceivedWithEvent:event];
NSLog(#"remoteControlReceived");
NSLog(#"%d", [[AVAudioSession sharedInstance] isActive]);
if (event.type == UIEventTypeRemoteControl) {
switch (event.subtype) {
case UIEventSubtypeRemoteControlPlay:
[self.moviePlayer play];
break;
case UIEventSubtypeRemoteControlPause:
[self.moviePlayer pause];
break;
default:
break;
}
}
}
The main problem with my MPMoviePlayerViewController is, that it doesn't respond to the remoteControlReceivedWithEvent message, why is that? Am I subclassing the wrong thing? Does my Tabbar based app prevent me from doing that?
Last but not Least - applicationDidFinishLaunchingWithOptions contains following:
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
[audioSession setActive:YES error:nil];
I just can't figure out what's missing... all help is greatly appreciated!
I think I can answer both questions :)
The background issue:
What file format are you trying to play? My app has been using a MPMoviePlayerViewController for background audio for a while, but recently had reports that it wasn't playing in the background anymore.
Turns out it was AAC files; they're podcasts with chapters and cover art per chapter... iOS 5 added improved support for them, but it must make the MPMoviePlayerViewController think it's playing video. Background video was turned off around iOS 4.3, from what I can find.
Try it with a plain MP3 file, that still works for me. I'm about to log the AAC problem as a bug with Apple.
The remote control issue:
Both the lock screen and notification bar remote control buttons send the UIEventSubtypeRemoteControlTogglePlayPause event, not play and pause separately. So I handle events like this:
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
switch (event.subtype) {
case UIEventSubtypeRemoteControlTogglePlayPause:
if (controller.playbackState == MPMusicPlaybackStatePlaying) {
[controller pause];
} else {
[controller play];
}
break;
//etc
}