iOS 开启 voiceChat 后 TTS 回声仍触发麦克风检测怎么办?
结论
.voiceChat 将 AVAudioSession 设为通话模式,但仅凭这段配置,无法确认录音链路已启用有效的回声消除,也无法判断当前输出路由和 TTS 播放方式是否受回声处理覆盖。应先确认音频引擎、输入输出路由和语音处理状态,再调整打断逻辑。不要仅根据麦克风音量或能量变化停止 TTS。
检查语音处理是否启用
如果应用使用 AVAudioEngine,可以在启动引擎前检查并启用输入节点的语音处理。AVAudioSession 配置和节点语音处理属于不同层面:前者设置会话类别与模式,后者为音频引擎的 I/O 节点启用语音处理。
let audioSession = AVAudioSession.sharedInstance()
try audioSession.setCategory(
.playAndRecord,
mode: .voiceChat,
options: [.duckOthers, .allowBluetooth]
)
try audioSession.setActive(true)
let engine = AVAudioEngine()
let inputNode = engine.inputNode
try inputNode.setVoiceProcessingEnabled(true)
engine.prepare()
try engine.start()
这段示例适用于使用 AVAudioEngine 的情况。如果项目通过其他方式采集麦克风或播放 TTS,这段代码未必能控制相应链路。需要确认实际使用的音频 API 和会话路由。若启用语音处理失败,应记录错误,并检查当前设备和路由是否支持所需配置。
排查音频路由
先用 iPhone 内置扬声器和麦克风复现问题,再单独测试蓝牙设备。.allowBluetoothA2DP 允许选择 A2DP 路由,但这本身不代表回声消除已启用。通话场景下,实际的输入输出端点和设备支持情况也会影响结果。可以暂时移除该选项进行对比,并记录 AVAudioSession 当前的输入、输出端口和路由变化。
还要确认 TTS 是否通过与麦克风采集相同的音频处理路径播放。如果录音由一个音频引擎处理,而 TTS 走另一条独立播放路径,就不能仅凭 .voiceChat 判断回声一定会被消除。具体行为取决于应用的播放和采集实现。
调整打断检测
即使启用了语音处理,打断判定也应留有容错空间:
- 不要仅因输入音量升高就判断用户开口。可以结合持续时间、语音活动检测(VAD)或 STT 结果判断。
- TTS 播放时记录输入信号,分别比较无人说话和用户说话时的检测结果,再调整门限和持续时间。
- 如果 TTS 回声仍会触发 VAD,可以在播放期间提高打断门限,或要求连续多个检测窗口都满足条件。确认检测到用户语音后,再停止 TTS 并启动 STT。
- 如果产品允许,可以先实现半双工流程:TTS 播放时暂停语音识别,播放结束后再恢复。需要支持打断时,再逐步加入经过验证的 barge-in 检测。
调整后,分别测试内置扬声器、耳机和实际使用的蓝牙路由。仅凭题目提供的配置和现象,无法确定根因是语音处理未启用、路由不匹配,还是打断检测过于敏感。还需要结合音频 API、运行时路由和输入检测日志进一步定位。
备注:内容仅供参考。
