Mimi实时字幕背后的PCM管线:有界队列、流式重采样与本地回声取消原理详解
Mimi实时字幕背后的PCM管线:有界队列、流式重采样与本地回声取消原理详解
Mimi 是一款实时翻译字幕工具,可以把电脑系统声音或麦克风声音转成即时双语字幕。要让字幕"实时",底层的 PCM 音频管线必须足够快、足够稳:音频采集回调不能阻塞、积压要可预测、回声要在本地消除。本文带你读懂 Mimi 实时字幕背后的 PCM 管线设计,包括有界队列、流式重采样和回声取消三大核心机制。
一、为什么 PCM 管线对实时字幕如此关键
实时字幕的链路大致是:系统声音/麦克风 → 原生采集回调 → 格式归一化 → 有界队列 → 上传识别/翻译 → 字幕渲染。
其中最容易出问题的就是采集到上传这一段。PCM(脉冲编码调制)是音频的原始波形数据,原生回调有三个"先天麻烦":
- 回调包大小不固定:Windows WASAPI 可能一次给几十毫秒,也可能攒了 250ms 才回调一次;
- 采样率不一致:声卡常用 44.1kHz/48kHz,而识别服务要求 16kHz 或 24kHz;
- 双源回声:系统声音从扬声器播放后又被麦克风拾取,会让识别结果里混入"自己的回声"。
Mimi 用三层机制分别解决这三个问题。
二、有界队列:不阻塞回调,用"最新丢弃"换稳定性
所有音频先进入一条有界队列(bounded queue)再异步上传,核心实现在 send_pipeline.rs。
关键设计有三点:
- 固定容量,永不等待。队列容量为 20 个音频包,采集回调只做非阻塞的
try_send,绝不await——一旦网络发送变慢,积压立刻被"背压"信号感知,而不是无限堆积导致延迟雪崩。 - 溢出即降级,而非崩溃。当队列满时,本代入口永久关闭并报出一次
Backpressure错误,UI 会给出提示,而不是让音频悄悄丢帧。 - 每个包自带"在途"守卫。每个
PendingAudio包携带一个 PendingPcmGuard,包被丢弃、发送完成或任务被取消时,守卫随 RAII 析构自动释放计数——停止会话时能精确知道还有多少 PCM 没处理完,避免资源泄漏。
三、流式重采样:1024 帧一块,余量留在下次回调
采样率转换由 streaming_resampler.rs 完成,它是一个有状态的流式重采样器:
- 交错帧补齐:原生回调给的是"多声道交错"数据,可能切在半帧中间。
push_interleaved会把不完整的帧留在 pending 缓冲,下次回调接着拼,同时按声道数做下混(downmix)到单声道; - 1024 帧小块处理:重采样按 1024 帧为一块 调用
rubato的 FFT 重采样器,块与块之间的残差同样缓存在pending_mono中,保证跨回调的相位连续性; - 同采样率零开销直通:输入与目标采样率相同时直接跳过重采样,只编码 PCM16 输出。
这套"每次回调都可能有剩余、下次接着算"的模式,正是流式(streaming)与整段重采样的本质区别——它不要求拿到完整录音,只要求状态不丢。
四、本地回声取消:双源输入时的 500ms 自适应滤波器
当同时开启系统声音和麦克风时,Mimi 会用系统声音作为"播放参考",在本地做声学回声取消(AEC),源码在 echo_cancellation.rs:
- 线性自适应滤波:基于 SpeexDSP 的自适应回声滤波器,500ms 滤波长度 覆盖实测的播放延迟与房间反射尾音,支持 16kHz / 24kHz 单声道 PCM16;
- 刻意不开非线性处理:不启用 Speex 的非线性预处理,避免"系统声音一响,你的说话声就被门限掉"的误杀;
- 10ms 精确分帧:任意回调大小会被重组为精确的 10ms 帧再进入滤波器,双源缓冲各自限制在 500ms 以内,麦克风处理缓冲含抖动窗口共 700ms;
- 系统声音原样直发:参考副本不经过滤波器、不等待任何处理,直接进独立发送队列,只有麦克风支路被扣除回声;
- 时间线对齐而非逐帧硬配:两个来源的启动时间可能相差数秒,Mimi 按单调时间线对齐,麦克风帧延迟约 350ms 处理、参考超前 100ms 选取,确保滤波器输入在时序上"因果"。
设计动机与取舍详见开发计划文档:2026-10-03-microphone-echo-cancellation.md。
五、整条管线走一遍:数据如何流动
把三个机制串起来,Mimi 的 PCM 管线是:
系统声音 ──► 重采样(1024帧块) ──► 原样直发队列(容量20) ──► 识别/翻译服务
│
▼ (作为播放参考)
麦克风 ──► 重采样 ──► 10ms分帧 ──► SpeexDSP AEC ──► 独立发送队列 ──► 识别/翻译服务
│ ▲
└── 任意包大小缓冲 ──┘ 溢出即背压,绝不阻塞回调
一句话总结设计哲学:所有环节都有界,溢出时快速失败而非悄悄拖延。正因为队列容量、缓冲时长、滤波器长度都是显式的毫秒级常量,Mimi 的实时字幕延迟才可预测、可测试、可回归——这也是 docs/development/ 下大量管线验收记录存在的原因。
想动手看看这套管线,建议从这三个文件入手:


