10

Here is some background information, otherwise skip ahead to the question in bold. I am building an app and I would like it to have access to the remote control/lock screen events. The tricky part is that this app does not play audio itself, it controls the audio of another device nearby. The communication between devices is not a problem when the app is in the foreground. As I just found out, an app does not assume control of the remote controls until it has played audio with a playback audio session, and was the last do so. This presents a problem because like I said, the app controls ANOTHER device's audio and has no need to play its own.

My first inclination is to have the app play a silent clip every time it is opened in order to assume control of the remote controls. The fact that I have to do this makes me wonder if I am even going to be allowed to do it by Apple or if there is another way to achieve this without fooling the system with fake audio clips.

QUESTION(S): Will Apple approve an app that plays a silent audio clip in order to assume control of the remote/lock screen controls for the purpose of controlling another device's audio? Is there any way of assuming control of the remote controls without an audio session?

P.S. I would prefer to have this functionality on iOS 4.0 and up.

P.P.S I have seen this similar question and it has gotten me brainstorming but the answer provided is not specific to what I need to know.

Community
  • 1
  • 1
Squatch
  • 1,027
  • 14
  • 27
  • Did you get a solution for this? Will Apple approve an app that plays a silent audio clip to control cast video on smart tvs / streaming boxes? Also any idea how Spotify, Sonos & Youtube are implemented? – Shiva Reddy Sep 17 '18 at 16:55

2 Answers2

25

NOTE: As of iOS 7.1, you should be using MPRemoteCommandCenter instead of the answer below.

You create various system-provided subclasses of MPRemoteCommand and assign them to properties of the [MPRemoteCommandCenter sharedCommandCenter].

I'm keeping the rest of this around for historical reference, but the following is not guaranteed to work on recent iOS versions. In fact, it just might not.


You definitely do need an audio player but not necessarily an explicit session to take control of the remote control events. (AVAudioSession is implicit to any app that plays audio.) I spent a decent amount of time playing with this to confirm this.

I've seen a lot of confusion on the internet about where to set up the removeControlEventRecievedWithEvent: method and various approaches to the responder chain. I know this method works on iOS 6 and iOS 7. Other methods have not. Don't waste your time handling remote control events in the app delegate (where they used to work) or in a view controller which may go away during the lifecycle of your app.

I made a demo project to show how to do this.

Here's a quick rundown of what has to happen:

  1. You need to create a subclass of UIApplication. When the documentation says UIResponder, it means UIApplication, since your application class is a subclass of UIResponder. In this subclass, you're going to implement the remoteControlReceivedWithEvent: and canBecomeFirstResponder methods. You want to return YES from canBecomeFirstResponder. In the remote control method, you'll probably want to notify your audio player that something's changed.

  2. You need to tell iOS to use your custom class to run the app, instead of the default UIApplication. To do so, open main.m and change this:

     return UIApplicationMain(argc, argv, nil, NSStringFromClass([RCAppDel`egate class]));
    

    to look like this:

    return UIApplicationMain(argc, argv, NSStringFromClass([RCApplication class]), NSStringFromClass([RCAppDelegate class]));
    

    In my case RCApplication is the name of my custom class. Use the name of your subclass instead. Don't forget to #import the appropriate header.

  3. OPTIONAL: You should configure an audio session. It's not required, but if you don't, audio won't play if the phone is muted. I do this in the demo app's delegate, but do so where appropriate.

  4. Play something. Until you do, the remote controls will ignore your app. I just took an AVPlayer and gave it the URL of a streaming site that I expect to be up. If you find that it fails, put your own URL in there and play with it to your heart's content.

This example has a little bit more code in there to log out remote events, but it's not all that complicated. I just define and pass around some string constants.

I bet that a silent looping MP3 file would help work towards your goal.

Moshe
  • 57,511
  • 78
  • 272
  • 425
  • Wow, thanks! I'll check out the demo when I get home. Now you say the methodology here works in iOS 6 & 7; do you know off the top of your head if it will go as far back as 5.1? – Squatch Oct 02 '13 at 14:08
  • I don't know for sure, but I think the breaking changes were between iOS 6 and 7, so I would imagine that it works on iOS 5. – Moshe Oct 02 '13 at 14:10
  • 1
    I just charged up my iPad running iOS 5 and tried to run the demo on it. At first it wouldn't work, but if you turn off autolayout and the iOS 6+ localization feature (and copy the unlocalized nib back in) it mostly works. I say mostly because something is wrong with the play/pause button. (I think it's just an event type I didn't account for correctly. Run it and you'll see what I mean.) – Moshe Oct 02 '13 at 18:56
  • You're a genius this was exactly what I was looking for! One more question - in order for my application to receive the remote control events, it must be the last application to have played any sort of audio. Is that correct? – Se Won Jang Oct 13 '13 at 15:35
  • Thank you very much! Above and beyond the call of duty. – Moritz Dec 06 '13 at 09:53
  • 1
    Tried a bunch of other solutions on here, this is the only one that actually got me the events, finally, thanks!!!! – Michael Apr 22 '14 at 03:59
  • Just in case it confuses anyone else, note that this does not work in the simulator, only on a real device. – Phil Mitchell Jan 28 '15 at 05:44
1

Moshe's solution worked great for me! However one issue I noticed is when you paused the audio, the media controls would go away and you won't be able to play it again without going back into the app. If you set the Media Info on the lock screen when you play the audio then this won't happen:

NSDictionary *mediaInfo = @{MPMediaItemPropertyTitle: @"My Title",
                                 MPMediaItemPropertyAlbumTitle: @"My Album Name",
                                 MPMediaItemPropertyPlaybackDuration: [NSNumber numberWithFloat:0.30f]};
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:mediaInfo];
Oren
  • 5,055
  • 3
  • 34
  • 52
  • Will Apple approve an app that plays a silent audio clip to control cast video on smart tvs / streaming boxes? Also any idea how Spotify, Sonos & Youtube are implemented? – Shiva Reddy Sep 19 '18 at 05:59