跳到主要内容

图 3 - 音频数据流图

PCM 怎么从麦克风走到云端、Opus 怎么从云端走到喇叭?整个音频链路的全貌。

如果上方图无法显示,点这里看 PNG 版本

上行链(用户说话)

麦克风 → input_pcm_queue → AFE → encode_pcm_queue → Opus Encoder → send_opus_queue → Protocol

每一站的作用:

站点作用
I²S 麦克风硬件采集 16 kHz 16-bit PCM
input_pcm_queue麦克风快、AFE 慢,用队列解耦
AFE 前端AEC(消回声)+ VAD(检测人声)+ NS(降噪)
encode_pcm_queueAFE 输出再排队,让 Opus 编码独立线程消费
Opus Encoder60ms 帧、16 kbps 压缩,输出二进制 Opus
send_opus_queue网络发包独立,背压时不阻塞前面
Protocol.SendAudioWebSocket 帧或 UDP+AES 包

下行链(云端说话)

Protocol → decode_opus_queue → Opus Decoder → Opus Resampler → output_pcm_queue → 喇叭
站点作用
Protocol.OnIncomingAudio网络收到云端 Opus 包
decode_opus_queue让 OpusCodecTask 独立消费
Opus Decoder解码出 24 kHz PCM(TTS 默认采样率)
Opus Resampler把 24 kHz 适配到喇叭实际采样率
output_pcm_queue让 AudioOutputTask 取出来播
I²S 喇叭硬件输出

5 个队列的核心价值

为什么这么多队列?两个原因:

  1. 解耦速度:麦克风采样率固定,但网络速度波动;硬件采集硬性 16 kHz,编码任务可能因为系统忙慢一点——用队列吸收抖动。
  2. 任务隔离:3 个 FreeRTOS 任务(input / output / codec)通过队列通信,零锁,无死锁风险。

AEC 反馈环

注意图最下面:喇叭播放的 PCM 会反馈给 AFE 作为参考信号。这是 AEC 的核心——通过对比"喇叭在播什么"和"麦克风听到什么",可以减掉对方的回声,避免设备自己说话被自己当成用户输入。

一句话讲清

"麦克风原始声音先过 AFE 清洗(消回声去噪),再压成 Opus 发上云;云端回的 Opus 解出来重采样后塞给喇叭。中间 5 个队列把不同速度的环节解耦,让所有任务都能各跑各的不互相卡。"

关联章节

  • /04-audio 整章