Woking on an app in which I integrated Linphone for VoIP calls. I am using CallKit for incoming calls to give native touch to my app.
All the thing works fine before iOS 11. Issue seems with the creation of Audio session. Very first time It works fine but in subsequent runs It fails to give voice in earphone. The exact issue is that there is an inconsistency related to audio session means I am not able to use mic to catch voice and the user on other end not able to listen my voice.
I notices that It fires AVAudioSessionRouteChangeNotification after creating shared instance of AVSession and setting category type and switch-case goes in the case of AVAudioSessionRouteChangeReasonCategoryChange. When I print category type- It gives right selected category named AVAudioSessionCategoryPlayAndRecord.
Let you know that If I put break point in switch-case in the method used for AVAudioSessionRouteChangeReasonCategoryChange notification and prints category named then It works fine. May be at that point It got enough time to create Audio Session and catch the voice through mic.
Using below code for setting up Audio Session as given in SpeakerBox example-
- (void)setupAudioSession
{
try {
// Configure the audio session
AVAudioSession *sessionInstance = [AVAudioSession sharedInstance];
// we are going to play and record so we pick that category
NSError *error = nil;
[sessionInstance setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
XThrowIfError((OSStatus)error.code, "couldn't set session's audio category");
// set the mode to voice chat
[sessionInstance setMode:AVAudioSessionModeVoiceChat error:&error];
XThrowIfError((OSStatus)error.code, "couldn't set session's audio mode");
// set the buffer duration to 5 ms
NSTimeInterval bufferDuration = .005;
[sessionInstance setPreferredIOBufferDuration:bufferDuration error:&error];
XThrowIfError((OSStatus)error.code, "couldn't set session's I/O buffer duration");
// set the session's sample rate
[sessionInstance setPreferredSampleRate:44100 error:&error];
XThrowIfError((OSStatus)error.code, "couldn't set session's preferred sample rate");
// add interruption handler
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleInterruption:)
name:AVAudioSessionInterruptionNotification
object:sessionInstance];
// we don't do anything special in the route change notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleRouteChange:)
name:AVAudioSessionRouteChangeNotification
object:sessionInstance];
// if media services are reset, we need to rebuild our audio chain
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(handleMediaServerReset:)
name: AVAudioSessionMediaServicesWereResetNotification
object: sessionInstance];
}
catch (CAXException &e) {
NSLog(@"Error returned from setupAudioSession: %d: %s", (int)e.mError, e.mOperation);
}
catch (...) {
NSLog(@"Unknown error returned from setupAudioSession");
}
return;
}
Below is the method fired on AVAudioSessionRouteChangeNotification notification-
- (void)handleRouteChange:(NSNotification *)notification
{
UInt8 reasonValue = [[notification.userInfo valueForKey:AVAudioSessionRouteChangeReasonKey] intValue];
AVAudioSessionRouteDescription *routeDescription = [notification.userInfo valueForKey:AVAudioSessionRouteChangePreviousRouteKey];
NSLog(@"Route change:");
switch (reasonValue) {
case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
NSLog(@" NewDeviceAvailable");
break;
case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
NSLog(@" OldDeviceUnavailable");
break;
case AVAudioSessionRouteChangeReasonCategoryChange:
NSLog(@" CategoryChange");
NSLog(@" New Category: %@", [[AVAudioSession sharedInstance] category]);
[self setupAudioSession];
break;
case AVAudioSessionRouteChangeReasonOverride:
NSLog(@" Override");
break;
case AVAudioSessionRouteChangeReasonWakeFromSleep:
NSLog(@" WakeFromSleep");
break;
case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory:
NSLog(@" NoSuitableRouteForCategory");
break;
default:
NSLog(@" ReasonUnknown");
}
NSLog(@"Previous route:\n");
NSLog(@"%@", routeDescription);
}