I've read many posts and articles and am having no luck playing audio when iPhone is in silent. I'm using react-native-sound which uses AVAudioPlayer under the hood. The following calls succeed without any luck with sound coming through when in silent.
NSError *setCategoryError = nil;
BOOL success = [audioSession setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError];
if (!success) { /* handle the error condition */ }
NSError *activationError = nil;
success = [audioSession setActive:YES error:&activationError];
if (!success) { /* handle the error condition */ }
Any suggestions?
Resources:
https://developer.apple.com/library/content/qa/qa1668/_index.html
I am struggling with this as well. I don't think it is totally possible. I can have sound play in silent mode when the app is in foreground then continue playing while it is in the background, but I don't think iOS allows you to trigger a sound to play while the app is in the background and in silent mode. I am using local notifications to trigger the sound to play.
Some people have had luck setting 'Application does not run in background' to YES in the info.plist which keeps the app in the foreground when someone locks there phone with the app still in the foreground but I need the app to work if the phone is locked when the app is in the background.
Currently the only solutions I know of are to play a silent audio track then tell it to keep it active after playing (to not waste cpu/battery). See link here. Apple normally doesn't approve of this in app review. Or to use location updates.
Related
I am working on a VoIP app. For that I had set the category of AVAudioSession to AVAudioSessionCategoryPlayAndRecord.
All the app functionality was working fine till now.
Then we had a new requirement where within app when the voice call is going on, user can play one video embedded in WKWebView.
Now when user plays video from WKWebView, video plays successfully and the volume of video is also as expected. But when user stops/pauses the video then voice call gets disconnected.
So I came to know that WKWebView runs in different process than the app, so in order to make my app's audio mixable with WKWebview I have to set the AVAudioSession as mixwithOthers.
I have done that with the following code...
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *errorInSettingCategory;
BOOL success = [session setCategory:AVAudioSessionCategoryPlayAndRecord withOptions: AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionMixWithOthers | AVAudioSessionCategoryOptionAllowBluetooth error:&errorInSettingCategory];
Now after playing video form WKWebView I am able continue with my voice call.
But this approach introduced the new bug.
As now the AVAudioSession is mixable, volume of the video from WKWebView is quite low and app's audio (voice call audio) is quite dominant.
I have tried different setcategory options but with no luck.
I want to have volume of app's audio and volume of WKWebView's video at same level.
Thank you for any help.
Try setting the duckOthers property of your AVAudioSession to false:
https://developer.apple.com/documentation/avfoundation/avaudiosession/categoryoptions/1616618-duckothers
My app uses device's microphone and manages AVAudioSession.
I want to check if there is other app playing audio, if so, I want my app to stop using microphone & stop my audio session, this is what I tried (the following code is periodically triggered to check is there other app playing audio):
BOOL isPlayingWithOthers = [[AVAudioSession sharedInstance] isOtherAudioPlaying];
if (isPlayingWithOthers) {
[[AVAudioSession sharedInstance] setActive:NO error:error];
}
I run my app, then, I open "My music" app, and playing a music, the above code is executed but I get the following error:
Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session.
Why I get this error? How to solve it in my case? (My app is running on iOS7 and above)
I'm trying to figure how i can play audio using AVAudioPlayer to the phone's internal ear piece.
When headphones are connected the audio should play on those else it must play from internal ear piece (AVAudioPlayer should never play from Phone's Bottom Speaker).
Is there any way to achieve this? iOS 7+ answers are welcome!
It's interesting to see how many more answers there are regarding Android questions, iOS questions are much less answered.
This is the solution that i managed to find:
NSError *error;
// Initialize Audio Player
_player = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:_audioPath] error:&error];
// Set Audio Session to "Play and Record", UNFORTUNATELY this is the only way to play
// from the internal speaker. It asks the user to grant Recording permission to the app.
NSError *setCategoryError = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error: &setCategoryError];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
if (setCategoryError) {
CLS_LOG(#"Error routing audio: %#",setCategoryError);
[self.navigationController popViewControllerAnimated:YES];
}
[_player prepareToPlay];
// And now you can play from the internal speaker.
You can see that i had to use AVAudioSessionCategoryPlayAndRecord because it's the only category that routes the audio to the receiver (the small speaker you hold to your ear when on a phone call) see the audio session programming guide for reference.
Actually, there is a method named overrideOutputAudioPort:error: that looks promising but it can only be used AVAudioSessionCategoryPlayAndRecord to force the device to use the external speaker, and not vice versa.
So I successfully created an app, in this case it's a VOIP app using linphone sip library. I was doing some tests where I want a WAV file to always play, regardless of whether my app is in the foreground or background. I was able to successfully implement this test with the following code:
NSString * resourcePath = [NSString stringWithFormat:#"%#/myres/sounds/oldphone-mono.wav",[[NSBundle mainBundle] resourcePath]];
ringer = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:resourcePath] error:nil];
[ringer setNumberOfLoops:100];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
[ringer setVolume:1.0];
UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride), &audioRouteOverride);
[ringer play];
I think this is pretty straightforward code, because I copied it from another stack overflow answer. I also had to do something to my plist file to allow for audio background playing.
So the problem is that a function from some 3rd party software (in this case LinPhone SIP Library's Receive Incoming Call Function) that when fired will prevent my app from playing my sound file in background.
As an example, here's a test case:
start up my app and i hear the ringing wav file, that's good
i put the app in background mode and i still hear the ringing wav file, that's good
i bring the app back into focus, i still hear the ringing, that's good
i trigger the linphone receive call function, the ringing still continues because i'm in foreground, that's good
i put the app in background mode, the ringing stops, that's not good
So I suspect that linphone has done something to the avaudioplayer/avaudiosession, such that i can no longer play in background. So my question is, can anyone hazard a guess as to what linphone may have done to prevent my app from playing sound in the background, and how i might get around this issue?
ADDITIONAL NOTES
I even tried to instantiate a new avaudioplayer every second while the app was in the background. But it couldn't override whatever linphone has done to silence the playing of audio.
It appears that Linphone messed with the AVAudioSession Category Options. I had to reset the category option to AVAudioSessionCategoryOptionMixWithOthers in order to get around the problem like so:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];
I'm faced with very interesting problem and now I'm trying to understand how to sort it out. In fact, my application plays sound when it come into background. Everything is ok, but when I run application like youtube it make interuption for my audio session. I use audio session delegate methods to catch this moment. My question is that how to restore my audio session in background after I kill youtube?
I've tried this:
NSError *err = noErr;
[[AVAudioSession sharedInstance] setActive: YES error: &err];
if(err != noErr)
{
NSLog([err description]);
}
but it doesn't work.
Any suggestion?
Thank you.
Ok, as I understood, to make audio session mixed with other application I have to set special property like this:
UInt32 allowMixing = true;
AudioSessionSetProperty ( kAudioSessionProperty_OverrideCategoryMixWithOthers,
sizeof (allowMixing),
&allowMixing
);
And now I can see that my application plays audio in background even if I start youtube. The problem is that it plays audio simultaneously :(. I can hear my application's audio and youtube as well. There is not audio session interruption. Strange problem.