KunSpace
返回博客

如何获取 Mic + Ref 数据做语音唤醒 / 降噪

2026年7月21日
6 次阅读

读完了?别空手走啊 😏

白嫖可以,但点个赞显得有教养

写评论

有想法?直接在这说,不用跑留言板

这篇写什么?

语音唤醒 / 回声消除(AEC)/ 降噪 时,算法通常同时需要两类声音:

  1. Mic:麦克风采到的「人声 + 环境声 + 扬声器回声」
  2. Ref(Reference):正在播放出去的参考信号(扬声器在播什么)

很多板子上,上层 不是直接读物理麦设备,而是从一个叫 loopback 的虚拟采集口,一次读出「Mic + Ref」的多通道混合数据。

一句话:

PDM 物理麦 → 驱动合成 → alsaPORT-loopback(Mic + Ref 多通道)
→ 开 PCM(16k / 16bit / mic_ch+ref_ch)→ 按帧读 → 拆通道
→ Ref downmixer → AEC / 降噪 / 唤醒 → 2ch 降噪语音 + 唤醒回调

相关延伸:麦克风阵列音频检查方法与标准Google 远场与 HAL 多通道 AECLoopback 抗混叠实测多路语音唤醒验证喇叭失真 THD。本文讲算法侧如何从 loopback 拿到 Mic + Ref


数据流示意

Mic + Ref 数据流:PDM 物理麦与播放 Ref 汇入 loopback,再拆通道做唤醒/降噪Mic + Ref 数据流:PDM 物理麦与播放 Ref 汇入 loopback,再拆通道做唤醒/降噪

要点: alsaPORT-pdm-builtinmic 是物理麦克风来源;上层算法侧认的采集节点是 alsaPORT-loopback


1. 数据来源

项目 说明
采集节点 alsaPORT-loopback(全名常见为 LOOPBACK-A-dummy-alsaPORT-loopback
数据内容 loopback 里是 Mic 原始声音 + 播放参考信号(Ref) 的多通道混合数据
物理麦 alsaPORT-pdm-builtinmic(PDM 内置麦)——由驱动合成进 loopback,上层一般不直接读它

为什么要 Ref?
扬声器在播音乐 / TTS 时,Mic 会录到回声。AEC / 降噪要用 Ref 知道「现在正在播什么」,才能把回声从 Mic 里减掉,唤醒也更稳。


2. 采集参数(按产品需求定)

常见语音链路参数:

参数 取值 说明
采样率 16 kHz 唤醒 / 通话类算法常用
位宽 16 bit PCM 有符号 16-bit
通道数 mic_ch + ref_ch 例:4mic + 6ref → 10 通道

通道数不是随便开:必须和 loopback 实际布局、算法期望一致,否则拆通道会错位。


3. 通道布局(框架约定)

loopback 约定:

前面 = Mic 通道:mic0 … micN-1
后面 = Ref 通道:ref0 … ref5(固定 6 路 Ref 很常见)

举例

4 麦 + 6 Ref(共 10 通道):

[ mic0  mic1  mic2  mic3 | ref0  ref1  ref2  ref3  ref4  ref5 ]
  ←—————— Mic 4 路 ————→   ←—————————— Ref 6 路 ——————————→

2 麦 + 6 Ref(共 8 通道):

[ mic0  mic1 | ref0  ref1  ref2  ref3  ref4  ref5 ]
  ←— Mic 2 —→   ←—————————— Ref 6 路 ——————————→

拆分时:mic_ch 路是麦,后 ref_ch 路是参考。搞反了,AEC 会完全失效。


4. 用 tinycap 抓 Mic / Ref 数据

调试时可用 tinycap 把 loopback 录成 wav,再用 Audacity 等工具看通道是否对得上。

# 2mic(按你板子上的 card/device 改 -D / -d)
tinycap /sdcard/test_2mic.wav -D 0 -d 3 -c 2 -r 16000

# 4mic
tinycap /sdcard/test_4mic.wav -D 0 -d 3 -c 4 -r 16000

# 10ch(4mic + 6ref)
tinycap /sdcard/test_10ch.wav -d 6 -c 10 -r 16000 -p 480

说明:

  • -c:通道数,要和「你想抓的布局」一致(只抓 mic 或抓完整 mic+ref)
  • -r 16000:16 kHz
  • -D / -d:card / device,/proc/asound/pcm 里 loopback 实际编号为准(不同机型可能不是 0/3 或 device 6)
  • -p:period 大小,按驱动 / 框架习惯(例:480)

录完后建议核对:说话时前几路能量大;播放音乐时后几路 Ref 有能量。


5. 处理过程(运行时链路)

步骤 1:定位 ALSA 设备

/proc/asound/pcm,用设备名 alsaPORT-loopback 匹配出对应的 card / device

不要写死编号——换机型、换内核配置后 card 号常会变,用名字匹配更稳。

步骤 2:打开 PCM

用上一步的 card/device 打开 loopback,配置例如:

  • 采样率:16 kHz
  • 位宽:16 bit
  • 通道:mic_ch + ref_ch(如 4+6=10)

步骤 3:获取一帧数据

循环读取 PCM buffer。当前架构常见约定:

  • 每次处理固定 256 帧
  • 在 16 kHz 下:256 / 16000 ≈ 16 ms

读取长度、算法帧长、回调节奏都围绕这个帧长对齐,避免缓冲积压或欠载。

步骤 4:通道拆分

按布局约定,把一帧交错 PCM 拆成:

  • mic[mic_ch][256](或等价缓冲)
  • ref[ref_ch][256]

步骤 5:Ref downmixer

loopback 往往 固定给 6 路 Ref,但算法可能只要 2 / 4 / 5 路。
这时做 downmixer:对部分 Ref 做求和 / 平均(或按产品表映射),得到算法需要的 Ref 路数。

ref0..ref5(6 路)──downmixer──▶ ref'(2/4/5 路)──▶ AEC / 降噪

步骤 6:算法处理

Mic + Ref 做:

  • AEC(回声消除)
  • 降噪
  • 唤醒检测

步骤 7:输出结果

输出 用途
2 通道降噪语音 交给上层语音链路(识别 / 通话等)
唤醒事件回调 检测到唤醒词时通知上层

责任怎么分(小结)

环节 谁负责 常见坑
物理麦 PDM + 驱动 上层去读 builtinmic,读不到完整 Ref
Mic+Ref 合成 loopback 驱动 通道数 / 布局和文档不一致
打开设备 按名字找 card/device 写死 -D0 -d3 换机失败
拆通道 应用 / 中间件 Mic、Ref 前后搞反
Ref 路数 downmixer 算法要 2 路却硬塞 6 路
帧长 PCM 读 + 算法 和 256@16k(约 16ms)不对齐导致卡顿

一句话记住

唤醒 / 降噪要的不是「随便一个麦」,而是 loopback 里按约定排好的 Mic + Ref;拆对通道、对齐帧长、必要时把 6 路 Ref downmix 成算法要的路数,后面的 AEC / 唤醒才站得住。

评论

还没有评论,来做第一个吧

有想法?直接在这说,不用跑留言板