Switching audio output between Receiver and Speaker in iOS7 and above? - ios

I have an audio player which has an option of switching the Audio Output from Speaker to Receiver/Earpiece (irrespective of whether headset is connected) when proximity sensor notifies 1. The following is my code for doing so.
- (void) switchAudioOutput:(NSString*)output{
AVAudioSession* audioSession = [AVAudioSession sharedInstance];
BOOL success;
NSError* error;
if([output isEqualToString:keAudioOutputReciever]){
//Force current audio out through reciever
//set the audioSession override
success = [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideNone
error:&error];
if (!success)
NSLog(#"AVAudioSession error overrideOutputAudioPort:%#",error);
//activate the audio session
success = [audioSession setActive:YES error:&error];
if (!success)
NSLog(#"AVAudioSession error activating: %#",error);
else
NSLog(#"AVAudioSession active with override: AVAudioSessionPortOverrideNone");
}else if([output isEqualToString:keAudioOutputSpeaker]){
//set the audioSession override
success = [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker
error:&error];
if (!success)
NSLog(#"AVAudioSession error overrideOutputAudioPort:%#",error);
//activate the audio session
success = [audioSession setActive:YES error:&error];
if (!success)
NSLog(#"AVAudioSession error activating: %#",error);
else
NSLog(#"AVAudioSession active with override: AVAudioSessionPortOverrideSpeaker");
}
}
This was based on the answer Toggle Button route audio to speaker and receiver and enter link description here. I noticed that this only forces the Audio to Speaker alone but does not ensure that the route goes to receiver alone. Moreover while shifting to speaker I get the following error:
AVAudioSession error overrideOutputAudioPort:Error Domain=NSOSStatusErrorDomain Code=-50 "The operation couldn’t be completed. (OSStatus error -50.)"

I figured out the answer by avoiding overrides for Receiver
- (void) setAudioSession:(NSString*)audioOutput{
NSError* error;
if([audioOutput isEqualToString:audioOutputSpeaker.lowercaseString]){
//set the audioSession override
if(![self setCategory:AVAudioSessionCategoryPlayAndRecord
withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker|AVAudioSessionCategoryOptionAllowBluetooth
error:&error])
NSLog(#"AVAudioSession error AVAudioSessionCategoryPlayAndRecord:%#",error);
//activate the audio session
if (![self setActive:YES error:&error])
NSLog(#"AVAudioSession error activating: %#",error);
else
NSLog(#"AVAudioSession active with override: AVAudioSessionPortOverrideNone");
}else if ([audioOutput isEqualToString:audioOutputReciever.lowercaseString]){
//Force current audio out through reciever
//set the audioSession override
if(![self setCategory:AVAudioSessionCategoryPlayAndRecord
withOptions:AVAudioSessionCategoryOptionAllowBluetooth
error:&error])
NSLog(#"AVAudioSession error AVAudioSessionCategoryPlayAndRecord:%#",error);
if (![self overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:&error])
NSLog(#"AVAudioSession error overrideOutputAudioPort to Reciever:%#",error);
//activate the audio session
if (![self setActive:YES error:&error])
NSLog(#"AVAudioSession error activating: %#",error);
else
NSLog(#"AVAudioSession active with override: AVAudioSessionPortOverrideNone");
}
}

I was struggling with this too and was trying to set the mode parameter so something potentially appropriate, e.g.
try AVAudioSession.sharedInstance().setCategory(.playAndRecord,
mode: .voicePrompt,
options: .defaultToSpeaker)
And that would just throw me an error:
Error Domain=NSOSStatusErrorDomain Code=2003329396 "(null)"
The audio was routing to the receiver rather than speaker with just the category parameter and with the mode, but when I randomly decided to try without the mode parameter but with the options parameter it worked fine!
So give this code a try if you struggle:
try AVAudioSession.sharedInstance().setCategory(.playAndRecord,
options: .defaultToSpeaker)

Related

iOS: AVAudioSession sample rate is not changing when playing a sound from speaker

When setting the preferred sample rate to 16000 it is working fine. However, when I want to play the sound from the speaker and print the sample rate I find it 48000.
I tried to set the sample rate again after playing from the speaker, but it is not working.
NSError *err = nil;
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:NO error:&err];
BOOL successfullySatSampleRate = [session setPreferredSampleRate:SAMPLING_FREQUENCY error:&err];
if(err != nil)
{
NSLog(#"Error in setting up audio: %#", err);
}
if(!successfullySatSampleRate)
{
NSLog(#"Error in setting up sample rate");
}
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error: nil];
[session setActive:YES error:&err];
NSLog(#"initialize Session preferredSampleRate = %f, hardware sampleRate = %f",[session preferredSampleRate],[session sampleRate]);
What should I do to keep the sample rate 16000?

BlueTooth audio capturing using airpod microphone

How to set audio session category so that external Bluetooth airpod device can record audio using airpod microphone and works flowless with other bluetooth device as well. Here is my code.
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
/*
optimum to minimize delay, must put a software resampler to deal with 8khz
*/
NSError *error;
[audioSession setPreferredSampleRate:8000.0 error:&error];
if([[UIDevice currentDevice] systemVersion].floatValue>=10.0)
{
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord
withOptions:AVAudioSessionCategoryOptionAllowBluetoothA2DP
error:&error];
}
else
{
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord
withOptions:AVAudioSessionCategoryOptionAllowBluetooth
error:&error];
}

How to fix audio distortion issue in iPhone 6s/iPhone 6s

I'm developing a live streaming app. I have an issue with audio distortion on both the iPhone 6s and 6s Plus. I know that Apple has changed the audio hardware sample rate (to 48000Hz).
I have tried following code, but still audio gets distorted:
-(void) setupAudioSpeaker
{
NSError * audioSessionError = nil;
[[AVAudioSession sharedInstance] setCategory:
AVAudioSessionCategoryPlayback error: &audioSessionError];
if (audioSessionError) {
DLog(#"AVAudioSession Error %ld, %#",
(long)audioSessionError.code,
audioSessionError.localizedDescription);
}
NSTimeInterval bufferDuration =0.01;
[[AVAudioSession sharedInstance]
setPreferredIOBufferDuration:bufferDuration
error:&audioSessionError];
if (audioSessionError) {
DLog(#"Error %ld, %#", (long)audioSessionError.code,
audioSessionError.localizedDescription);
}
double sampleRate = 48000.0;
[[AVAudioSession sharedInstance] setPreferredSampleRate:sampleRate
error:&audioSessionError];
if (audioSessionError) {
DLog(#"AVAudioSession Error %ld, %#",
(long)audioSessionError.code,
audioSessionError.localizedDescription);
}
[[AVAudioSession sharedInstance] setActive:YES
error:&audioSessionError];
if (audioSessionError) {
DLog(#"AVAudioSession Error %ld, %#", (long)audioSessionError.code,
audioSessionError.localizedDescription);
}
sampleRate = [AVAudioSession sharedInstance].sampleRate;
bufferDuration = [AVAudioSession sharedInstance].IOBufferDuration;
DLog(#"Sampe Rate:%0.0fHZ I/O Buffer Duration:%f", sampleRate,
bufferDuration);
}

AVAudioSession manipulate sound output

I'm using AVSoundSession to configure sound, and AVAudioPlayer to play different sounds.
I searched a lot and couldn't find anything. How can I manipulate output sources?
I need a method in my SoundManager where I could switch output between phone speaker and loudspeaker.
success = [session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker
error:&error];
Using this I can route sound to loudspeaker, but there is no method to move it to phone speaker. Can anybody help me with it?
So, I found solution for manipulating with sound output.
You could initialize sound settings with AVAudioSession
Something like this:
session = [AVAudioSession sharedInstance];
BOOL success;
NSError* error;
success = [session setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
if (!success) NSLog(#"AVAudioSession error setting category:%#",error);
success = [session setMode:AVAudioSessionModeVoiceChat error:&error];
if (!success) NSLog(#"AVAudioSession error setting mode:%#",error);
success = [session overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:&error];
[session setPreferredOutputNumberOfChannels:0 error:nil];
if (!success) NSLog(#"AVAudioSession error overrideOutputAudioPort:%#",error);
success = [session setActive:YES error:&error];
if (!success) NSLog(#"AVAudioSession error activating: %#",error);
else NSLog(#"audioSession active");
With
[session overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:&error];
You set don't override output port. And your app playing with default speaker. As I understand for mode AVAudioSessionModeVoiceChat used phone speaker. It's directly what I need for my SIP caller app.
Then you can override output port with
[session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error];
I do it so:
- (void) loudSpeakerOn:(BOOL)isLoudSpeaker{
[session setActive:NO error:nil];
BOOL success;
NSError* error;
success = [session overrideOutputAudioPort:isLoudSpeaker?AVAudioSessionPortOverrideSpeaker:AVAudioSessionPortOverrideNone error:&error];
if (!success) NSLog(#"AVAudioSession error setting category:%#",error);
[session setActive:YES error:nil];
}

iOS How to play alert sound in speaker when recording

I want to manually trigger to play some alert sound during recording audio, and I want the alert sound be recorded. So I want the alert play loudly in speaker instead of Receiver during recording audio.
I use AVAudioRecorder to record audio and use AVAudioPlayer to play the alert sound.
Code for recorder
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *sessionError;
[session setCategory:AVAudioSessionCategoryRecord error:&sessionError];
if(session == nil)
NSLog(#"Error creating session: %#", [sessionError description]);
else
[session setActive:YES error:nil];
recorder = [[AVAudioRecorder alloc] initWithURL:_recordedFile settings:recordSettings error:nil];
[recorder prepareToRecord];
[recorder record];
Code for player
AVAudioSession *session = [AVAudioSession sharedInstance];
// session.outputDataSources
NSError *sessionError;
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:&sessionError];
// use the louder speaker
UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryDefaultToSpeaker,
sizeof (audioRouteOverride),&audioRouteOverride);
if(session == nil)
NSLog(#"Error creating session: %#", [sessionError description]);
else
[session setActive:YES error:nil];
NSError *error;
player = [[AVAudioPlayer alloc] initWithContentsOfURL:self.filePath error:&error];
player.delegate =self;
player.volume = 1.0;
player.numberOfLoops = 0;
self.timeDuration = player.duration;
If I stop the recording, and manually trigger the play alert, it plays in speaker.
But during recording, when I manually trigger the play alert, nothing happens.
Is there anything wrong here? Or Is it possible to play sound in speaker when recording?
Just change category as below thats all
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:&err];

Resources