iOS端WebRTC通话应用音频输入源切换失效问题求助
iOS WebRTC音频输入源切换解决方案
针对WebRTC M105在iOS 16环境下调用setPreferredInput无报错但输入源未切换的问题,核心原因是WebRTC对音频会话的接管逻辑,需调整初始化和路由变更处理流程,具体实现如下:
1. 修正音频会话初始化逻辑
WebRTC的RTCAudioSession会自行管理会话激活状态,避免提前手动激活导致后续设备切换失效:
func setupRTCAudioSession() { let rtcAudioSession = RTCAudioSession.sharedInstance() rtcAudioSession.lockForConfiguration() defer { rtcAudioSession.unlockForConfiguration() } do { try rtcAudioSession.setCategory(AVAudioSession.Category.playAndRecord.rawValue) try rtcAudioSession.setMode(AVAudioSession.Mode.voiceChat.rawValue) // 移除手动激活代码,由WebRTC在需要时自动激活 } catch { print("Audio session setup failed: \(error.localizedDescription)") } }
2. 正确处理路由变更通知
仅在设备连接/断开的时机处理切换,设置首选输入后需重新激活音频会话,触发WebRTC识别新设备:
@objc func handleAudioRouteChange(_ notification: Notification) { guard let userInfo = notification.userInfo, let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt, let reason = AVAudioSession.RouteChangeReason(rawValue: reasonValue) else { return } // 仅在设备接入/移除时执行切换 guard reason == .newDeviceAvailable || reason == .oldDeviceUnavailable else { return } let rtcAudioSession = RTCAudioSession.sharedInstance() rtcAudioSession.lockForConfiguration() defer { rtcAudioSession.unlockForConfiguration() } // 切换到AirPods(蓝牙HFP设备) if let bluetoothInput = rtcAudioSession.availableInputs?.first(where: { $0.portType == .bluetoothHFP }) { do { try rtcAudioSession.setPreferredInput(bluetoothInput) // 重新激活会话让WebRTC生效 refreshRTCAudioSession() } catch { print("Failed to set Bluetooth input: \(error.localizedDescription)") } } else { // 切换回内置麦克风 if let builtInInput = rtcAudioSession.availableInputs?.first(where: { $0.portType == .builtInMic }) { do { try rtcAudioSession.setPreferredInput(builtInInput) refreshRTCAudioSession() } catch { print("Failed to set built-in mic: \(error.localizedDescription)") } } } } // 辅助方法:重新激活音频会话 private func refreshRTCAudioSession() { let rtcAudioSession = RTCAudioSession.sharedInstance() rtcAudioSession.lockForConfiguration() rtcAudioSession.setActive(false) rtcAudioSession.unlockForConfiguration() // 延迟0.1秒重新激活,避免会话状态冲突 DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { rtcAudioSession.lockForConfiguration() do { try rtcAudioSession.setActive(true) } catch { print("Failed to reactivate audio session: \(error.localizedDescription)") } rtcAudioSession.unlockForConfiguration() } }
3. 注册与移除通知观察者
确保在合适生命周期内注册通知,避免内存泄漏:
// 注册通知(如在viewDidLoad或初始化方法中) NotificationCenter.default.addObserver( self, selector: #selector(handleAudioRouteChange(_:)), name: AVAudioSession.routeChangeNotification, object: nil ) // 移除通知(如在deinit中) deinit { NotificationCenter.default.removeObserver( self, name: AVAudioSession.routeChangeNotification, object: nil ) }
关键说明
- WebRTC接管音频会话后,手动提前激活会覆盖设备切换配置,需交由WebRTC管理激活时机。
- 设置
preferredInput后必须重新激活会话,触发WebRTC重新获取当前输入设备的音频流。 - 仅在路由变更的有效时机(设备接入/移除)处理切换,避免无效操作干扰会话状态。
内容的提问来源于stack exchange,提问作者lidium
相关产品推荐
相关产品推荐

