Audio triggered by background location - ios

Target OS: iOS 6+
Devices: Phones only
I'm creating an fairly simple locative media app. The one technical difficulty I'm having is whether or not I can do what I want with background audio.
I receive GPS location updates successfully in the background but I would like to use these to trigger audio on region entry. The app does not play audio constantly in foreground, only on entry to these fences.
Does the 'playing silence' trick still work to keep the Audio Session and is this an app where Apple would tolerate its use? If so could anyone provide recently functional code for it?

If you set up your application to also enable background audio, in application:didFinishLaunching: like so:
[[AVAudioSession sharedInstance] setDelegate: self];
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
and add audio as a background mode in the app's plist file, your app will keep on running in the background and play sounds when it wishes (e.g. when a location change has happened). However, I think you have to close the application while playing sound.
However, there might be an issue with this, because background audio is meant for apps that actually keep running a track/stream in the background. I could see how Apple might reject your app for using their API in an unintended way. So this is the problem with the playing silence trick.
Also, another problem could be that if the user goes out of your app, then starts playing their music through Music or any other music app (Spotify, a radio app etc.) that has access to background audio, your application's audio permissions will be disabled (your app won't be able to play sound anymore through the audio framework, because another app has taken control of the background audio).
An option I would recommend: throw a local notification with your own sound when the user changes location:
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
localNotif.soundName = #"your-sound-file-name";

Related

Can AVAudioSession be activated in Background state without MixWithOthers?

So my app is running in the background because of CoreLocation that has requested AlwaysAuthorization. This prevents app to reach suspended state. It stays in background state and is receiving location events. After some location events I would like to activate AVAudioSession and play some sounds. How to activate session properly (in this background app) when I'm using other app in foreground right now and this app is playing audio track for example. Suppose I'm watching some video in Youtube app and my background app needs to play audio right now. I've problems in activating audio session in this case.
I can't use AudioToolbox playing engine in this case because those sounds needs to be played even when Ring/Silent switch is on.
I know I need to use AVAudioSessionCategoryPlayback category. I also don't want other apps to be played in the same time so I'm not using MixWithOthers or DuckOthers category options.
I have enabled UIBackgroundModes for audio playback in background.
How to activate such session when app is in background and other app currently is playing audio without any mixing options enabled. How to interrupt audio session in current foreground app so my background app can activate it for playback time. After playing is over my plan is to deactivate audio session in background and notify other apps that they can resume theirs playback.
Add these below 3 lines in the didFinishLaunchingWithOptions method of AppDelegate.m class and test the app again. Let me know if there is any problem regarding the same.
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
[UIApplication sharedApplication].idleTimerDisabled = YES;

Configuring AirPlay to play video on apple tv for AVPlayer while app goes in background

Referring to the document https://developer.apple.com/library/ios/qa/qa1668/_index.html ,
I have modified the info.plist to support playback for HLS stream while app is in background, and removed/restored AVPlayer when app goes to background/comes to foreground using Application delegate events(application: app didBecomeActive and application: app didEnterBackground) , am certain that code gets executed as I can see the logs. Yet when I navigate out of the app by pressing home key on actual device, Airplay stops. Also, I added a KVObserver on the rate property of AVPlayer, the rate is 1 while the app is minimized.
One thing that I noticed was for the same piece of code, on simulator, If I simulate home key press (cmd+shift+h) , the audio for the video is audible while I am outside the app, while it stops on actual device. Am I doing something wrong?
Had to put the methods :
[[AVAudioSession sharedInstance] setDelegate: self];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
in the app delegate, thought they were just for audio streaming, but for video as well are required for multitasking, this resolved the issue.

How can I avoid interrupting audio that is already playing when my app launches?

I have an app that needs to use AVAudioSessionCategoryPlayback in order to play sound while the device is locked or my app is in the background. (It's an alarm feature.) So I also need to set the "audio" key in my UIBackgroundModes list.
I have put the following code in my application:didFinishLaunchingWithOptions: method:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback
withOptions:AVAudioSessionCategoryOptionMixWithOthers
error:nil];
However, I don't want to interrupt any music that is already playing on the device. When my app is launched, it causes Spotify (for example) to stop playing music. I can switch to Spotify and press play, and when I switch back to my app, it continues playing.
But this is very annoying to the user - alarms are not the only thing my app does, and there are many reasons for them to launch it that don't involve setting alarms. I don't think the user would ever want my app to stop any other audio playing on the device.
Ideally I'd never interrupt already-playing audio. I could also live with stopping audio when an alarm is set (at which point I have to activate my audio session to ensure that I'm able to play it) but it seems like there is no way for me to avoid the audio stop at app launch.
Is there some way to start my app with the audio session disabled, or to start it with this option already applied?
It turns out that I was calling .prepareForPlayback() on an AVAudioPlayer in an init() method which was getting called long before my didFinishLaunchingWithOptions: fired.

AVAudioPlayer, using AmbientSound session, is not playing when app is in background

If this is in the apple doc then I've not been able to find it - hoping someone can help:
My app plays occasional short audio clips - I want the audio to mix in with audio playing from other apps in the background like the iPod app - but I also want it to carry on playing these audio clips when the app is running in background.
I have set "App plays audio" in the Required Background Modes settings in info.plist (the app is also using location services too so that is also set in there)
My app sets up an audio session on applicationDidFinishLaunching:
AudioSessionInitialize (NULL,NULL,NULL,NULL);
UInt32 sessionCategory = kAudioSessionCategory_AmbientSound;
AudioSessionSetProperty (kAudioSessionProperty_AudioCategory,sizeof (sessionCategory),&sessionCategory);
AudioSessionSetActive(true);
In my viewWillAppear: method in the view that is active I have:
[super viewWillAppear:animated];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
and the corresponding event handler and endReceivingRemoteControlEvents code in viewWillDisappear: as discussed in iOS 4: Remote controls for background audio
Finally I have an AVAudioPlayer, set up in the normal way, that plays a sound on certain events
bool successful = [avAudioPlayer play];
if(!successful)
NSLog(#"did not play");
When the app is in foreground the app works fine and plays the audio - but when the app goes into background and the app attempts to play a sound the return value from the [avAudioPlayer play] is NO and the sound does not play - when switched back to foreground the audio starts working again.
If when I set up the session I instead use
UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
Then the audio plays in foreground and background perfectly. But MediaPlayback is not the really the right mode for this app since I am only occasionally playing audio clips - AmbientSound is really the mode I should be using.
What am I missing? Is it just not possible to use kAudioSessionCategory_AmbientSound to play Audio in the background? If so I've not found anything in the documentation about that.
Had to submit a tech support request for this in the end.
According to Apple background playback is not supported by the AmbientSound category - you have to use MediaPlayback.
They claim this is in the documentation - I've looked again and I could not find it.
Ok so getting background sounds to mix into MediaPlayback is easy enough using kAudioSessionProperty_OverrideCategoryMixWithOthers - but I am now going to have to jump through some other hoops to replicate the other AmbientSound functionality (obeying the mute switch and not playing when locked). I really don't understand why AmbientSound is not supported playing in background - but there we go.

Continue playing audio from html5 player when in iOS background mode

We built our music-oriented app in html5 and javascript with Sencha touch. For distribution we wrapped it in xcode with UIwebView. Everything runs fine except one thing that does not work: audio playing in multitask mode.
I know the general idea: add the UIBackgroundModes in info.plist.
Done. Now we can play the audio even in background mode.
Until we reach the end of the song. To start the next song we have to bring the app to foreground again or we can hit the play or 'next song' button on the iPhone audio controller.
After some research I found a promising workaround at: " Entering background on iOS4 to play audio " where the workaround is to edit AVAudioSessionCategoryPlayback and work with the UIBackgroundTaskIdentifier.
The problem for me is (just like in any other fix I found so far) that those solutions always assume that the audio is played either with AVaudioPlayer or MPMusicPlayerController. But in my case I user neither, our audio is played by our html5 player wrapped in UIwebView.
Anyone has any advice on how to continue playing the audio in iOS multitask mode when the audio player is a html5/javascript player?
My app plays audio via an <audio> tag in html hosted in UIWebView, and it supports background playing.
As you suggest, you need to have the 'App plays audio' background mode defined in your plist.
Try adding this to your applicationDidFinishLaunching: handler:
NSError *setCategoryError = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: &setCategoryError];
Thanks, guys, but I ended up simply keeping the app busy in a loop when in background mode. This was enough to bridge the time when connecting to the next song on the playlist.
The code I used is similar to this one:
iPhone - Backgrounding to poll for events
You could try this, adding a function on the onend event.

Resources