音频会话相关问题 CallKit

Moh*_*sim 5 ios avaudiosession callkit ios11

在一个应用程序上工作,我在其中集成了用于 VoIP 呼叫的 Linphone。我正在使用 CallKit 进行来电,以便为我的应用程序提供原生触摸。

在 iOS 11 之前一切正常。问题似乎与音频会话的创建有关。第一次它工作正常,但在随后的运行中它无法在耳机中发出声音。确切的问题是与音频会话相关的不一致意味着我无法使用麦克风来捕捉声音,而另一端的用户无法听到我的声音。

我注意到它在创建 AVSession 的共享实例并设置类别类型后触发 AVAudioSessionRouteChangeNotification 并且在 AVAudioSessionRouteChangeReasonCategoryChange 的情况下切换案例。当我打印类别类型时 - 它给出了名为 AVAudioSessionCategoryPlayAndRecord 的正确选择的类别。

让您知道,如果我在用于 AVAudioSessionRouteChangeReasonCategoryChange 通知的方法中的 switch-case 中放置断点并打印命名的类别,那么它工作正常。可能在那时它有足够的时间来创建音频会话并通过麦克风捕捉声音。

使用下面的代码来设置 Audio Session,如 SpeakerBox 示例中给出的 -

- (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;
}
Run Code Online (Sandbox Code Playgroud)

下面是在 AVAudioSessionRouteChangeNotification 通知上触发的方法-

- (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);
    }
Run Code Online (Sandbox Code Playgroud)