We write app that records audio in background. We use AVAudioSession with AVAudioSessionCategoryPlayAndRecord category and AVAudioSessionCategoryOptionAllowBluetooth option:
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayAndRecord withOptions: AVAudioSessionCategoryOptionMixWithOthers | AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionAllowBluetooth error:&error];
We noticed the strange issue - when iPhone connected to Multimedia Car Bluetooth system and our app runs, there are shown phone call from device to itself (the call continues during all device connection to bluetooth system). When we close app - the call is ended, when we open app again - call begins and etc.
This issue reproduces on all Multimedia Bluetooth systems. How can we fix it? Thanks
Think you need to add AVAudioSessionCategoryOptionAllowBluetoothA2DP instead of the old HFP profile. The call is used to make older bluetooth devices to work.
With iOS 10, Apple added the option AVAudioSessionCategoryOptionAllowBluetoothA2DP. They also changed the meaning of AudioSessionCategoryOptionAllowBluetooth to only allow output using the HFP Bluetooth profile, which is where you get the low quality audio output.
If you use this new option in place of the AudioSessionCategoryOptionAllowBluetooth option in your code snippet, it will allow high quality output but disallow low quality audio output.
Here's the online documentation for the options, but unfortunately there's no description for the new iOS 10 options online. You can see more detail in the in-code documentation in AVAudioSession.h
https://developer.apple.com/reference/avfoundation/avaudiosessioncategoryoptions?language=objc
Info from: Keep bluetooth sound when initializing AVAudioSession
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
I'm trying to combine media playback with VoIP feature (via Twilio) for iOS 9 and 8.While an audio stream plays in the background, I connect or disconnect a Voice Conference session which results in a volume jump from value X to value Y. This jump can be heard, as well as observed by a [AVAudioSession sharedInstance].outputVolume value change.I would like to prevent this jump and keep the volume at a constant level, unless the user manually decides to change it.Further investigation showed that while AVAudioSession's category is set to AVAudioSessionCategoryPlayAndRecord, switching between modes[[AVAudioSession sharedInstance] setMode:AVAudioSessionModeDefault error:&error]and[[AVAudioSession sharedInstance] setMode:AVAudioSessionModeVoiceChat error:&error]causes the app to operate in two completely separate volume scales, respectively.i.e there a volume for Mode "Default" and a completely unrelated volume for Mode "Voice Chat".AVAudioSession's documentation seems to omit any mention of volume in relation to mode/category switches and I can't find anything relevant on the interwebs...
Appreciate any help.
When setting your play and record category, pass AVAudioSessionCategoryOptionDefaultToSpeaker as an option:
[[AVAudioSession sharedInstance] AVAudioSessionCategoryPlayAndRecord withOptions: AVAudioSessionCategoryOptionDefaultToSpeaker error:&error];
This overrides the default play-and-record behaviour of switching from the speaker to the much quieter receiver. The reason for this being that play-and-record was designed for telephony, where you'd be holding the phone to year ear & presumably wouldn't want to have your hearing damaged by loud sounds.
Megan from Twilio here.
I'm not most familiar with the iOS SDK but you should be able to control connection audio from TCDevice parameters incomingSoundEnabled, outgoingSoundEnabled, and disconnectSoundEnabled as documented here.
Otherwise, I would suggest looking at the sharedInstance properties of AVAudioSession that the Twilio SDK calls upon as demonstrated in this post:
setCategory:error:
setActive:error:
overrideOutputAudioPort:error:
Please let me know if this helps.
I am making an app in which i always want to take input from the device (iOS) BuiltInMic even if the headphones are plugged in. I have done a lot of research on it and came out with some solutions but they are not working.
I need to use this method to get the preferred input from a device :-
setPreferredInput:error:
More description can be found on this link :-
https://developer.apple.com/library/ios/qa/qa1799/_index.html
I got stuck in the method parameters to be passed
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setPreferredInput:(AVAudioSessionPortDescription *)inPort error:&myAudioError];
i.e the inPort to be pass. I need to set it to AVAudioSessionPortBuiltInMic but i am not able to do it.
Any help would be appreciated.
From Api Documents
- (BOOL)overrideOutputAudioPort:(AVAudioSessionPortOverride)portOverride
error:(NSError **)outError
Calling this method with the AVAudioSessionPortOverrideSpeaker option and the audio session’s category AVAudioSessionCategoryPlayAndRecord causes audio to use the built-in speaker and microphone regardless of other settings. This change remains in effect only until the current route changes or you call this method again with the AVAudioSessionPortOverrideNone option.
I have 2 different makes of guitar adapters that connect to my iphone using the lightning connector
When adapter 1 is plugged in, the device becomes a usb audio mic and it plays the sound through my iPhone's speakers as the adapter does not contain a headphone socket
When adapter 2 is plugged in, the device becomes a usb audio mic but plays the sound through the headphone socket on the adapter.
I'm trying to write an app that work with adapter 2, but rather than output the sound to the adapter's headphone socket, I want to route it through the iPhone's speakers.
The code below should work, but what i'm finding is that calling AVAudioSessionPortOverride with the AVAudioSessionPortOverrideSpeaker option and the audio session’s category is AVAudioSessionCategoryPlayAndRecord causes audio to use the built-in speaker and microphone regardless of other settings, basically ignoring setPreferredInput
I can't quite understand how adapter 1 manages to take input from usb audio and output to speaker but my app can't because of the restrictions above. Anyone know of a solution?
AVAudioSession* session = [AVAudioSession sharedInstance];
//Set the audioSession category. Needs to be Record or PlayAndRecord to use audioRouteOverride:
[session setCategory:AVAudioSessionCategoryPlayAndRecord
withOptions:AVAudioSessionCategoryOptionMixWithOthers
error:nil];
//set the audioSession override
[session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker
error:nil];
//activate the audio session
[session setActive:YES error:nil];
//set input to usb
for (AVAudioSessionPortDescription *destPort in session.availableInputs){
if ([destPort.portType isEqualToString:AVAudioSessionPortUSBAudio]) {
[setPreferredInput:(AVAudioSessionPortDescription *)inPort
error:(nil)outError
session setPreferredInput:destPort error:nil];
}
}
I think you can only achieve input via USB device and output through the speakers when the USB device has no audio output component.
I can't find any documentation that says exactly this, but my reasoning is as follows:
Mixing and matching audio devices is done via the generalised version of AVAudioSessionCategoryPlayAndRecord, the so called multi-route category (AVAudioSessionCategoryMultiRoute) and its documentation in AVAudioSession.h says that
Input is limited to the last-in input port.
AVAudioSessionPortBuiltInSpeaker is only allowed to be used when there are no other eligible outputs connected
Point 1 is not a problem, but point 2 disallows your adapter 2 scenario.
NB This would allow adapter 1 & 2 to both work with USB input and line-out or headphones. Would that be of any use to you?
This is a bit of a long shot, but have you tried..
[session setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error:nil]
..instead of overrideOutputAudioPort:?
With the iOS7 the AudioSession Category AVAudioSessionCategoryPlayAndRecord asks for Microphone permission. However, that permission doesn't feel right if I only need to support bluetooth for external audio. There are some people that are in the same situation as I am right now, but I can't find an answer for this.
In iOS6 I was using this code to route the sound to bluetooth devices:
[[AVAudioSession sharedInstance] setDelegate:self];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord
error:&sessionError];
AudioSessionSetActive (true);
UInt32 audioCategory = kAudioSessionCategory_MediaPlayback;
AudioSessionSetProperty (kAudioSessionProperty_AudioCategory,
sizeof (audioCategory), &audioCategory);
Is there any way to support a bluetooth device without using a audio session category that asks the user permission to use the microphone?
PS: I have noticed that google does the same with maps and youtube. Is it possible that we can't get around this issue on iOS7?
The "Allow app to use Microphone" prompt has been put in place to give the user more confidence in what the application is interfacing with. There will be no way to get around this.
You can however respond on the event of the user denying access. This might help:
How to detect microphone input permission refused in iOS 7