Preventing no-audio AVPlayer from pausing background audio - ios

I understand that based on AVAudioSession category AVPlayer will pause background audio currently played by other app when starting its playback. I wonder if this is the expected behavior regardless of the type item/content being played?
I'm asking as in my case showing video with no sound. The video files contain no audio track. AVPlayer itself is also set to muted. It just a little weird to me that I still have to change to AVAudioSession category even though I do not produce audio. So I want to know if that is by design or if there is something that I miss. For example, could I set up AVPlayer with no audio session so that it knows not to worry about audio or something like that.

No. Just set the audio category to "Ambient" so that it doesn't step on any other audio:
AVAudioSession *session = [AVAudioSession sharedInstance];
if (session) {
NSError *setCategoryError = nil;
BOOL success = [session setCategory:AVAudioSessionCategoryAmbient error:&setCategoryError];
if (success) {
NSError *activationError = nil;
[session setActive:YES error:&activationError];
} else {
NSLog(#"Failed to set music category to ambient. May interrupt other audio.");
}
}

Related

Play MPMoviePlayerController audio stream in background

So I have this app where I play videos and when you exit the app I would like the user to continue to listen to the audio of the video. I use MPMoviePlayerController to play the video and it works in the app perfectly fine. I also setup AVAudioSession up before I play the video and I get no error.
NSError *audioSessionError;
NSError *activationError;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:&audioSessionError];
[audioSession setActive:YES error:&activationError];
I also set in plist background modes audio. But the video with the audio both stop playing when you close the app. I've also imported the AVFoundation framework.
Simply set Application does not run in background to NO in .plsit file
You need to make couple of changes in plist file.i.e.
1) Set Required background mode to App plays audio
2) set Application does not run in background to YES.
NSError *setCategoryErr = nil;
NSError *activationErr = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error:&setCategoryErr];
[[AVAudioSession sharedInstance] setActive:YES error:&activationErr];
Then, you need to write these much code in AppDelegate
Now, you can easily run audio while phone screen locks or goes in background.
This code worked for me, first you must to give your app permissions to keep playing music in the background (In your .plis), after that go to the wished class and implement this code, first the imports and the the method to play the music.
#import <MediaPlayer/MPNowPlayingInfoCenter.h>
#import <MediaPlayer/MPMediaItem.h>
#import <AVFoundation/AVFoundation.h>
---- o ----
-(void) playMusic{
[[AVAudioSession sharedInstance] setDelegate: self];
NSError *myErr;
// Initialize the AVAudioSession here.
if (![[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&myErr]) {
// Handle the error here.
NSLog(#"Audio Session error %#, %#", myErr, [myErr userInfo]);
}else{
// Since there were no errors initializing the session, we'll allow begin receiving remote control events
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
//initialize our audio player
audioPlayer = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:#"http://www.cocoanetics.com/files/Cocoanetics_031.mp3"]];
[audioPlayer setShouldAutoplay:NO];
[audioPlayer setControlStyle: MPMovieControlStyleEmbedded];
audioPlayer.view.hidden = YES;
[audioPlayer prepareToPlay];
[audioPlayer play];
}//end playmusic
You need to turn on Background Modes in capabilities.

AVAudioSession record while playing weird issue

For part of an app that I'm making I need to record audio from the user. I have chosen to use AVAudioRecorder to do this.
The problem is that when I start to record audio, all audio playing on the device is paused. I then looked in the Apple docs for AVAudioSession and set the recording options to be: AVAudioSessionCategoryOptionMixWithOthers.
The problem is that whenever I start recording, any audio playing on the device switches from the main external speaker to the small phone (call) speaker.
My goal is to record audio while still allowing all other audio from the device to be outputted through the main speaker.
How can I achieve this?
Here's my code currently:
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&error];
[audioSession setActive:YES error:&error];
recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
if(recorder != nil){
[recorder prepareToRecord];
recorder.meteringEnabled = YES;
[recorder record];
levelTimer = [NSTimer scheduledTimerWithTimeInterval:0.03 target:self selector:#selector(levelTimerCallback:) userInfo:nil repeats:YES];
}else{
NSLog(#"Error: %#",[error description]);
}//end if
Thanks!
Maybe you can try using AVAudioSessionCategoryOptionDefaultToSpeaker. According to the AVAudioSession reference:
When using this option and no other audio route (such as a headset) is available, session audio will play through the device’s built-in speaker. When not using this option, and no other audio output is available or selected, audio will play through the receiver (a speaker intended to be held to the ear).

iOS - Unable to play a sound in background

I'm currently trying to implement a system like the alarm one to alert the phone when an event occurred (in my case a bluetooth event). I want this alert to occur even if the phone is in silent and in background.
I create a local notification but i can't get sound played if the phone is in silent mode (which seems to be normal since we put the phone in silent).
So i tried to manage the sound by myself and i'm struggling with playing sound in background. So far i implement the "App plays audio or streams audio/video using AirPlay" key in my plist and i'm using this code.
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error = nil;
BOOL result = [audioSession setActive:YES error:&error];
if ( ! result && error) {
NSLog(#"Error For AudioSession Activation: %#", error);
}
error = nil;
result = [audioSession setCategory:AVAudioSessionCategoryPlayback error:&error];
if ( ! result && error) {
NSLog(#"Error For AudioSession Category: %#", error);
}
if (player == nil) {
NSString *path = [[NSBundle mainBundle] pathForResource:#"bell" ofType:#"wav"];
NSURL *url = [NSURL fileURLWithPath:path];
NSError *err = nil;
player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&err];
if(err)
{
NSLog(#"Error Player == %#", err);
}
else {
NSLog(#"Play ready");
}
}
[player prepareToPlay];
[player setVolume:1.0];
if([player play])
{
NSLog(#"YAY sound");
}
else {
NSLog(#"Error sound");
}
The sound works great in foreground, even in silent mode, but i got no sound at all in background. Any ideas ?
Thanks
EDIT:
Finally i got it working with the above code. The only missing point is that i was trying to play the sound in somewhat appeared to be a different thread, when i play it right in my bluetooth event and not my function call it's working.
An app that plays audio continuously (even while the app is running in the background) can register as a background audio app by including the UIBackgroundModes key (with the value audio) in its Info.plist file. Apps that include this key must play audible content to the user while in the background.
Apple reference "Playing Background Audio"
Ensuring That Audio Continues When the Screen Locks
Found here
I'm not sure if your problem is that you have not configure correctly the audio session output. I had similar problem while playing .wav in my app. I only listened them with earphones. This method helped me:
- (void) configureAVAudioSession {
//get your app's audioSession singleton object
AVAudioSession *session = [AVAudioSession sharedInstance];
//error handling
BOOL success;
NSError* error;
//set the audioSession category.
//Needs to be Record or PlayAndRecord to use audioRouteOverride:
success = [session setCategory:AVAudioSessionCategoryPlayAndRecord
error:&error];
if (!success) NSLog(#"AVAudioSession error setting category:%#",error);
//set the audioSession override
success = [session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker
error:&error];
if (!success) NSLog(#"AVAudioSession error overrideOutputAudioPort:%#",error);
//activate the audio session
success = [session setActive:YES error:&error];
if (!success) NSLog(#"AVAudioSession error activating: %#",error);
else NSLog(#"audioSession active"); }
Try it out!
You need to make couple of changes in plist file.
for enabling sound when the app enter's Background.
1) Set Required background mode to App plays audio
2) set Application does not run in background to YES.
NSError *setCategoryErr = nil;
NSError *activationErr = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error:&setCategoryErr];
[[AVAudioSession sharedInstance] setActive:YES error:&activationErr];
Then, you need to write these much code in AppDelegate
Now, you can easily run audio while phone screen locks or in background.
It works fine for me. :)
for more please refer to Playing Audio in background mode and Audio Session Programming Guide

How to use kAudioSessionProperty_OverrideCategoryMixWithOthers

I would like to make my virtual instrument app able to being used (via a MIDI keyboard) when the app is in the background. This works fine by setting UIBackgroundModes to "audio" and setting the AudioSessions's category to AVAudioSessionCategoryPlayback. Furthermore, to allow mixing with the Music player app, I set the property kAudioSessionProperty_OverrideCategoryMixWithOthers.
To save battery energy, it is recommended to let the user switch off the background operation if it is not needed. So there is a switch in my app to toggle between the category AVAudioSessionCategoryAmbient and the category AVAudioSessionCategoryPlayback (with kAudioSessionProperty_OverrideCategoryMixWithOthers). The code is like this (error handling omitted):
NSString *category = supportsBackgroundOperation ? AVAudioSessionCategoryPlayback : AVAudioSessionCategoryAmbient;
[session setCategory:category error:nil];
if (category == AVAudioSessionCategoryPlayback) {
UInt32 allowMixing = true;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(allowMixing), &allowMixing);
}
Now the problem: Suppose the Music application is playing in the background. The user is playing the virtual instrument in the foreground (via a MIDI keyboard) to accompany the Music player and decides to start yet another app, say a slide show to enjoy why playing the instrument. So he/she goes to the settings view of my app and activates background operation. Then the above code is executed. Boom, the Music application gets silent. As I understand it, the kAudioSessionProperty_OverrideCategoryMixWithOthers property can only be set after setting the category, but when I set the category to AVAudioSessionCategoryPlayback, the Music player is silenced by the system before I have a chance to set kAudioSessionProperty_OverrideCategoryMixWithOthers.
Is this was happens? Can there anything be done? I tried to deactivate/activate the session before/after changing the category, but that lead to other trouble.
Markus
Since iOS 6.0 you can use
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];
Swift 5:
try? AVAudioSession.sharedInstance().setCategory(.playback, options: .mixWithOthers)
You can achieve this. The principle is to deactivate your audio session first, setup all the properties of your audio session, and then active audio session. In this way, the music playbacked in other app will not be silenced.
// Initialize audio session
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
// Active your audio session
[audioSession setActive: NO error: nil];
// Set audio session category
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
// Modifying Playback Mixing Behavior, allow playing music in other apps
OSStatus propertySetError = 0;
UInt32 allowMixing = true;
propertySetError = AudioSessionSetProperty (
kAudioSessionProperty_OverrideCategoryMixWithOthers,
sizeof (allowMixing),
&allowMixing);
// Active your audio session
[audioSession setActive: YES error: nil];
This solution works for me. But from your description, You mentioned that you did try activate/deactivate the session before/after changing the category but lead to other problems. Did you do the deactivate/activate in the exact same way as above? If so, provide more information about other troubles and maybe I can help.
I have to disagree with M0rph3v5.
The only valid value for the withOptions parameter is AVAudioSessionInterruptionOptionShouldResume

Starting AVAudioPlayer when application is in background

I have an application with App plays audio and App provides Voice over IP services options configured in the .plist.
The application is receiving socket events (even in background) and regarding the events, plays sound. When the application is in foreground, all is ok. When the app is in background, the app is triggered, the play method of the player is called, but without sound.
I have tried many sample code from Internet but nothing is working. I have tried to start playing sound in foreground and then move my app in background and it's working.
What is the problem to start playing a sound when the app is in background?
Here's my code handling an event when my app is triggered in background:
NSError *error;
NSURL *audioFileLocationURL = [[NSBundle mainBundle] URLForResource:#"HeadspinLong" withExtension:#"caf"];
if (audioPlayer != nil) return;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileLocationURL error:&error];
audioPlayer.delegate=self;
if (error) {
NSLog(#"%#", [error localizedDescription]);
}
audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
[audioSession setActive: YES error: &error];
audioSession.delegate=self;
if (error) {
NSLog(#"");
}
Seems like an obvious question, but are you actually calling the play method on the audioPlayer object in your real-life application? Probably at the end of background event handler?
i.e. [audioPlayer play];
For my understanding it seems not possible to start playing a music when the app is in background... It is only possible to continue playing an existing played music in background

Resources