在语音交互设备中,一个很常见的问题是:设备正在通过扬声器播放声音时,麦克风也会把这部分声音重新采集进去,形成回声。如果不处理,服务端会收到混杂了扬声器回放声的人声,影响语音识别、实时对话和打断体验。
RYMCU BigSmart 已经在设备端实现 AEC,也就是 Acoustic Echo Cancellation,声学回声消除。设备可以在本地利用参考通道消除扬声器回声,再将处理后的干净音频推送到服务端。
硬件与配置
BigSmart 使用 ES7210 进行多通道音频采集,ES8311 负责音频播放输出。麦克风侧并不是简单地只采集一路人声,而是将主麦和参考通道一起送入 ESP-SR AFE,让 AFE 在本地完成回声消除、降噪和语音检测。
完整音频链路
flowchart TD
SPK["扬声器输出<br/>ES8311 DAC"] -->|声学耦合 + 电气回送| REF["MIC3<br/>参考通道"]
MIC1["MIC1"] --> SEL["动态选主麦<br/>MIC1 / MIC2"]
MIC2["MIC2"] --> SEL
SEL --> ADC["ES7210 四通道 ADC<br/>4ch TDM 采集"]
REF --> ADC
ADC --> READ["CustomAudioCodec::Read()<br/>4ch TDM -> 2ch"]
READ --> MAIN["主麦通道<br/>M"]
READ --> REF2["参考通道<br/>R"]
MAIN --> AFE["AfeAudioProcessor<br/>ESP-SR AFE<br/>输入格式:MR"]
REF2 --> AFE
AFE --> AEC["AEC<br/>AEC_MODE_VOIP_HIGH_PERF<br/>消除扬声器回声"]
AEC --> NS["NS<br/>降噪"]
NS --> VAD["VAD<br/>语音检测"]
VAD --> OPUS["Opus 编码"]
OPUS --> WS["WebSocket"]
WS --> SERVER["服务端<br/>Rodak"]这里的关键点是参考通道。AEC 并不是只靠算法“猜”哪些声音是回声,而是需要知道设备自己正在播放什么声音。BigSmart 将 MIC3 作为参考输入,AFE 可以根据主麦信号和参考信号之间的关系,尽量消除扬声器回放进入麦克风后的回声成分。
CustomAudioCodec::Read() 会从 ES7210 的四通道 TDM 输入中整理出 AFE 所需的双通道数据:一路主麦,一路参考。随后 AfeAudioProcessor 使用 ESP-SR AFE 进行设备端音频处理。
Realtime 模式下的行为
当系统工作在设备端 AEC 模式时:
aec_mode_ == kAecOnDeviceSidelistening_mode_会设置为kListeningModeRealtime- 进入
Speaking状态时,不停止VoiceProcessing - AFE 会持续运行,持续使用参考通道做 AEC
- 设备持续推送经过 AEC 处理后的干净音频到服务端
这意味着设备在播放声音的同时,仍然可以继续监听用户语音。对于实时对话、语音打断、连续问答等场景,这一点非常重要。
为什么选择设备端 AEC
将 AEC 放在设备端有几个直接优势:
- 服务端收到的音频更干净,语音识别压力更小
- 扬声器播放时仍可保持实时监听
- 减少回声对 VAD、唤醒和语音识别的干扰
- 更适合低延迟、强交互的 AI 对话设备
- 对网络传输更友好,避免把明显无效的回声数据上传到服务端
对于 BigSmart 这类带扬声器、麦克风阵列和触屏交互的 AI 设备来说,设备端 AEC 是实现自然语音体验的基础能力之一。
总结
RYMCU BigSmart 的设备端 AEC 链路已经打通:硬件上使用 ES7210 四通道 ADC + ES8311 DAC,MIC1/MIC2 负责主麦采集,MIC3 作为参考通道;软件上通过 ESP-SR AFE 的 AEC_MODE_VOIP_HIGH_PERF 模式完成 AEC、NS 和 VAD 处理。
在 Realtime 模式下,即使设备正在说话,AFE 也会持续运行,并将消除回声后的音频实时发送到服务端。这为更自然的语音打断、更稳定的实时对话和更好的 AI 助手体验打下了基础。