CallKit结合TokBox使用时扬声器自动激活且无法关闭问题求助
I’ve run into this exact audio routing headache with TokBox and CallKit before—super frustrating when the speaker sticks on even after tapping to disable it. Let’s break down the fixes that worked for me, aligned with how apps like WhatsApp and Messenger handle this flow:
1. Take Control of Audio Session in CallKit’s Activation Callback
CallKit takes over the audio session when a call is answered, and TokBox’s default settings can clash with this. You need to explicitly set the audio route to the earpiece right after CallKit activates the session.
Add this to your CXProviderDelegate implementation:
- (void)provider:(CXProvider *)provider didActivateAudioSession:(AVAudioSession *)audioSession { // Link TokBox to the CallKit-managed audio session first [[OTDefaultAudioDevice sharedInstance] setAudioSession:audioSession]; // Force route audio to earpiece (system default) instead of speaker NSError *routeError; [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:&routeError]; if (routeError) { NSLog(@"Failed to adjust audio route: %@", routeError.localizedDescription); } }
AVAudioSessionPortOverrideNone tells the system to use the default audio route (earpiece for calls) instead of forcing speaker output.
2. Delay TokBox Audio Initialization Until After Call Acceptance
Don’t initialize TokBox’s audio device or start your OTSession until the user has actually answered the call. If you set up TokBox before CallKit activates the audio session, it might grab control and lock the speaker on.
Wait until the didActivateAudioSession callback fires, then finish setting up your TokBox call flow—this ensures the audio session is properly managed by CallKit first.
3. Override Unexpected Route Changes
Sometimes system events (like a Bluetooth disconnect) can trigger unwanted route switches. Add a listener to catch these and correct the route back to the earpiece:
// Register the notification in your view controller/manager init [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAudioRouteShift:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]]; // Handle route changes - (void)handleAudioRouteShift:(NSNotification *)notification { NSDictionary *routeInfo = notification.userInfo; AVAudioSessionRouteChangeReason reason = [routeInfo[AVAudioSessionRouteChangeReasonKey] unsignedIntegerValue]; // If the route switched unexpectedly, force it back to earpiece if (reason == AVAudioSessionRouteChangeReasonCategoryChange || reason == AVAudioSessionRouteChangeReasonOverride) { AVAudioSession *activeSession = [AVAudioSession sharedInstance]; NSError *correctionError; [activeSession overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:&correctionError]; } }
4. Check TokBox’s Default Speaker Setting
Double-check if TokBox’s audio device is defaulting to speakerphone. Some SDK versions have useSpeakerphone enabled by default—disable it before starting your call:
// Call this before initiating/accepting the TokBox call [[OTDefaultAudioDevice sharedInstance] setUseSpeakerphone:NO];
Why This Works (Like WhatsApp/Messenger)
Apps like WhatsApp don’t let TokBox’s default audio settings override CallKit’s session management. They strictly enforce audio routing rules immediately after CallKit activates the session, ensuring the earpiece is used by default. The key is keeping the audio session under CallKit’s control and only letting TokBox interact with it after the session is properly configured.
内容的提问来源于stack exchange,提问作者Abhishek Mitra

