You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 03:10:35