7

I want to implement the following things,

  1. App is running a music or video (using MPMoviePlayerController) in background.
  2. User double clicks the home button and go to the first screen showing playback controls (fast rewind, play or pause, fast forward buttons)
  3. User click fast rewind or fast forward button. Then app play previous or next music or video.

For the 3rd step, I should know which button is clicked. (As I naturally know, the currently playing item is paused, stopped.. using MPMoviePlayerPlaybackStateDidChangeNotification notification).

Which notification should I register? Or are there any other approaches?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
alones
  • 2,848
  • 2
  • 27
  • 30

2 Answers2

6

I got the answer by myself.

That is using UIApplication's beginReceivingRemoteControlEvents.

In an appropriate place (like viewWillAppear:) put the following code

[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];

And the view controller should implement the following method returning YES

- (BOOL)canBecomeFirstResponder {
    return YES; 
}

And then you can receive remote controller event in the following method.

- (void)remoteControlReceivedWithEvent:(UIEvent *)event {

    if( event.type == UIEventTypeRemoteControl ) {
        NSLog(@"sub type: %d", event.subtype);
    }
}

And event.subtype is as below,

typedef enum {
    // available in iPhone OS 3.0
    UIEventSubtypeNone                              = 0,

    // for UIEventTypeMotion, available in iPhone OS 3.0
    UIEventSubtypeMotionShake                       = 1,

    // for UIEventTypeRemoteControl, available in iPhone OS 4.0
    UIEventSubtypeRemoteControlPlay                 = 100,
    UIEventSubtypeRemoteControlPause                = 101,
    UIEventSubtypeRemoteControlStop                 = 102,
    UIEventSubtypeRemoteControlTogglePlayPause      = 103,
    UIEventSubtypeRemoteControlNextTrack            = 104,
    UIEventSubtypeRemoteControlPreviousTrack        = 105,
    UIEventSubtypeRemoteControlBeginSeekingBackward = 106,
    UIEventSubtypeRemoteControlEndSeekingBackward   = 107,
    UIEventSubtypeRemoteControlBeginSeekingForward  = 108,
    UIEventSubtypeRemoteControlEndSeekingForward    = 109,
} UIEventSubtype;
alones
  • 2,848
  • 2
  • 27
  • 30
  • 1
    This doesn't seem to work in the simulator running an iPhone 4.1 device? Is this the case or am I doing something wrong? – Johan Carlsson Nov 20 '10 at 15:04
  • I seem to have exactly same setup, but just can't get any events. – JOM Dec 22 '10 at 21:08
  • 1
    Plz check if you did becomeFirstResponder. And check if other classes call becomeFirstResponder after the class which will receive events called becomeFirstResponder. – alones Jan 22 '11 at 02:32
  • There seems to be mixed experiences whether capturing the remote control events works or not. Alones, could you provide a standalone sample for your solution, please? – DrMickeyLauer May 12 '11 at 12:03
  • I got this to respond to button clicks via the iPhone headphone controls, but not the on-screen buttons. Has anyone had any luck capturing the on-screen next/prev buttons? – amrox Oct 18 '11 at 16:54
  • @amrox I hope you've solved this problem by now, but I figured out how to do this and I'm posting my answer below. – Neeku Dec 04 '13 at 08:10
  • this doesn't seem to work on an iPhone 6 with iOS 8.1, isFirstResponder is true, but no events are received. – taber Nov 02 '14 at 16:26
  • @alones This doesn't work for iOS 8.1! I have tried and can't a way to make it work. – valbu17 Feb 03 '15 at 19:54
  • @taber have you found a solution or workaround to this? – valbu17 Feb 03 '15 at 19:55
  • @NorthBlast: no, gave up and used AVFoundation instead – taber Feb 04 '15 at 05:47
  • This doesn't seem to fire. – eNeF Jun 02 '15 at 10:11
1

This might be a very late answer, but as I notice, there aren't many Q/As about audio playing and remote controls, so I hope my answer helps the others who have the same problem:

I'm using AVAudioPlayer at the moment, but the remote controlling method which is - (void)remoteControlReceivedWithEvent:(UIEvent *)event must not be involved with the type of the player you're using.

To get the forward and rewind buttons on lock screen work, follow this:

In your view controller's viewDidLoad method add the following code:

//Make sure the system follows our playback status - to support the playback when the app enters the background mode.
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];

Then add these methods: viewDidAppear:: (if not implemented already)

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    //Once the view has loaded then we can register to begin recieving controls and we can become the first responder
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    [self becomeFirstResponder];
}

viewWillDisappear: (if not implemented already)

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];

    //End recieving events
    [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
    [self resignFirstResponder];
}

And:

//Make sure we can recieve remote control events
- (BOOL)canBecomeFirstResponder {
    return YES;
}

- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
    //if it is a remote control event handle it correctly
    if (event.type == UIEventTypeRemoteControl)
    {
        if (event.subtype == UIEventSubtypeRemoteControlPlay)
        {
            [self playAudio];
        }
        else if (event.subtype == UIEventSubtypeRemoteControlPause)
        {
            [self pauseAudio];
        }
        else if (event.subtype == UIEventSubtypeRemoteControlTogglePlayPause)
        {
            [self togglePlayPause];
        }

        else if (event.subtype == UIEventSubtypeRemoteControlBeginSeekingBackward)
        {
            [self rewindTheAudio]; //You must implement 15" rewinding in this method.
        }
        else if (event.subtype == UIEventSubtypeRemoteControlBeginSeekingForward)
        {
            [self fastForwardTheAudio]; //You must implement 15" fastforwarding in this method.
        }

    }
}

This is working fine in my app, however if you want to be able to receive remote control events in all view controllers, then you should set it in the AppDelegate.

NOTE! This code is working fine at the moment, but I see two more subtypes called UIEventSubtypeRemoteControlEndSeekingBackward and UIEventSubtypeRemoteControlEndSeekingBackward. I'm not sure if they have to be implemented or not, if someone knows about it, let us know.

Neeku
  • 3,646
  • 8
  • 33
  • 43
  • Have you tested in iOS 8? because seems not to be working @Neeku – valbu17 Feb 03 '15 at 19:44
  • @NorthBlast no, I was on this over a year ago, but will need to update and test it on iOS 8 soon... – Neeku Feb 03 '15 at 23:08
  • @NorthBlast By the way, you may think it's not working, but you actually need to long tap (tap & hold for a while) to make it rewind. It's not as great as Apple's own Podcast app, but with limited access to the library, this is satisfying enough. – Neeku Feb 06 '15 at 11:36