Resuming iPod Playback after calling AVAudioSession setActive:NO - objective-c

What's the best way to resume playback of the ipod or other audio sessions after your app has completed using its session?
NOTE I've already tried calling...
[_session setActive:NO
withFlags:AVAudioSessionSetActiveFlags_NotifyOthersOnDeactivation
error:outError];
I'm building an iOS VoIP app which uses AVAudioSessionCategoryPlayAndRecord as its category and kAudioSessionMode_VoiceChat as its mode. To simplify handling of audio session management, I've got a singleton which listens for notifications on application state and other important events. However, the above code does not seem to cause the music to resume on the iPod app.
Finally, we've also noticed that the music controls that are shown on the bottom of the screen when the home button is double tapped act as if our application is the one playing audio. Yet we've already set it to be inactive.
Would love to understand more about what's going on here if anyone has any clue.

I seems to me that you are unable to notify the iOS that you no longer require an audio session. Are you sure that the call to "setActive" doesn't fail? Or maybe somewhere else in the code you reactivate your session.
Other than that, the Music application should be able to re-gain it's audio as soon as the system realizes you are not using it. This can be accomplished by third-party applications using the AVAudioSessionInterruptionNotification notification. For debugging you might try adding yourself as observer and see if your callback gets called. So, if you successfully deactivate your session, other applications should be able to do the rest.

Related

NSWorkspaceDidActivateApplicationNotification called before application is ready to use (launched)

I'm using both NSWorkspaceDidActivateApplicationNotification and NSWorkspaceDidLaunchApplicationNotification notifications to know which app the user is interacting with.
The problem is that, if an application is just opened and still launching, I first receive a activate notification, and soon afterwards a launch notification.
Is there any way to know within the activate method that the app is still launching and not yet ready for use? (Still bouncing in the dock)
I see that the ichat sample project by apple does not use the above approach and instead only listens to launch notifications. It then uses kAXApplicationActivatedNotification to add an AXObserver to the app. Is this the preferred way? (And also NSRunningApplications to add an observer to all already loaded apps).
I wanted to keep using just plain simple NSNotifications because I think it may be less memory intensive. (No need to keep an observer around for each and every app loaded).
check the NSRunningApplication object passed in the userinfo of the NSWorkspaceDidActivateApplicationNotification
NSRunningApplication *app = [note.userInfo objectForKey:NSWorkspaceApplicationKey];
if(app.isFinishedLaunching)
NSLog(#"up");

Cancel Local Notification When app goes to Suspended state.(removed from background)

I am using Local notification in my application.it is working fine in foreground and background.
Now, What i need,if i remove my app from background then i want to cancel all notification
before that.
so , there are not any method are calling in appdelegate when i am going to remove my app from background, obviously it is going to Suspended state so no method is going to called.
so is there any other way to do this ?
Thanks in advance...
Considering your app is not one of the supported background execution modes, like audio, VoIP, or navigation,
Your app will generally never see willTerminate, because the system generally only terminates your app once it's already suspended (in the background). Once your app is suspended, it gets no further chance to act, so there's no callback for that.
The didEnterBackground delegate message or notification should be considered your last chance to clean things up or save state before possible termination.
Here and here are good overview of the application lifecycle notifications & delegate messages on iOS 4.0 and later.

iOS app lifecycle regarding CLLocationManager startMonitoringForRegion

In iOS one can purportedly use the CLLocationManager's startMonitoringForRegion: method to register a delegate to respond to the device moving into a specific geographic region, even when the app isn't launched. From the CLLocationManager Class Reference:
In iOS, the regions you register with the location manager persist between launches of your application. If a region crossing occurs while your iOS app is not running, the system automatically wakes it up (or relaunches it) in the background so that it can process the event. When relaunched, all of the regions you configured previously are made available in the monitoredRegions property of any location manager objects you create.
I assume if the app is relaunched, iOS doesn't actually bring it to the foreground. I couldn't find any good samples illustrating where startMonitoringForRegion fits into an overall application, so my questions are:
Does one have to register the delegate for startMonitoringForRegion from somewhere specific? I'm guessing it can't be plonked in a view controller if we're launching the app without bringing it into the foreground. Can someone give an example with some context around it?
If we decide we do want to bring the app into the foreground as a result of entering the region, how would we do so?
When is startMonitoringForRegion registered with the OS and when is it unregistered? Does the user have to have launched the app at least once (even if it's since been killed) for the initial registration to take place? What about if the user powers off the device? Will our handler be registered the next time the device is powered on, or will the user have to launch the app at least once again?
Does one have to register the delegate for startMonitoringForRegion from somewhere specific? I'm guessing it can't be plonked in a view controller if we're launching the app without bringing it into the foreground.
False. A view controller object still does exists if it's allocated-initialized, even if its contents are not presented.
If we decide we do want to bring the app into the foreground as a result of entering the region, how would we do so?
Not possible using public APIs (I'm not sure whether an app in the background can use - [UIApplication openURL:] with its own URL scheme to bring itself into the background, but I doubt it); however you may be able to use the SpringBoardServices framework to launch your app:
SBSLaunchApplicationWithIdentifier(CFSTR("com.mycompany.theBestiPhoneAppEver"), false);
When is startMonitoringForRegion registered with the OS and when is it unregistered? Does the user have to have launched the app at least once (even if it's since been killed) for the initial registration to take place?
If the user never runs your application, code inside will never be run, so it won't get registered.
What about if the user powers off the device? Will our handler be registered the next time the device is powered on, or will the user have to launch the app at least once again?
Now that's a good question. I don't know it off the top of my head, nor did I find an answer in the documentation (probably you haven't found that either), so I'd say you just better try it yourself to be sure.

Initiate Download while iOS Device is Locked or App is in Background

I'm playing music using an instance of AVAudioPlayer. Once one song finishes, the next song in the "playlist" is downloaded using NSURLConnection.
Where I'm stuck: I want to be able to download the next audio file in the playlist AND begin playback in the background while the phone is locked, or while the user is using another app. How do I do this?
I have stumbled across this post: Play music in the background using AVAudioplayer which suggests using [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];, but this only seems to allow audio to play in the background, not initiate a download.
Surely this is possible, as Pandora, Spotify, and others can do it...help!
You should request the system to let you run in the background while you are downloading the audiofile. You can do so by using UIApplication's beginBackgroundTaskWithExpirationHandler: method. Once you download the file, you can get the AVAudioPlayer to play your file.
You should have a read of the Apple documentation for multitasking.
http://developer.apple.com/library/ios/#DOCUMENTATION/iPhone/Conceptual/iPhoneOSProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html#//apple_ref/doc/uid/TP40007072-CH4-SW3
You need to add a UIBackgroundModes key to your info.plist for audio. This stops your app from being suspended and then all the normal callbacks will still run.

Receive remote control events without audio

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.
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:
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.
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.
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.
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'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];