RK3588 录音音量太小怎么办?——从 PDM 数字麦克风原理到 softvol 软件增益实战

RK3588 录音音量太小怎么办?——从 PDM 数字麦克风原理到 softvol 软件增益实战

环境:RK3588 开发板 / Linux 6.1 BSP / Buildroot(alsa-lib 1.2.11、alsa-utils 1.2.12)
关键词:PDM 数字麦克风、dBFS、ALSA、softvol、arecord、amixer

0. 现象

在 RK3588 板子上用板载 PDM 数字麦克风录音,录出来的 wav 文件音量特别小:正常距离说话,回放时要把音量开得很大才听得清。而同一块板子用 aplay 放音时,喇叭又能非常响。

"放音能很大声、录音却很小"——这不是巧合,也不是板子坏了,而是两条完全不同的通路。这篇博客完整记录我把它查清楚并解决的全过程。

(PDM 数字麦克风:输出"脉冲密度调制"数字信号的 MEMS 麦克风,只用"时钟 + 数据"两根线就能把声音直接送给 SoC,板载麦克风方案里很常见。)

1. 第一步:找"录音音量"这个旋钮

第一反应:有没有一个像 Windows"麦克风加强"那样的录音增益开关?Linux 下这套音频系统叫 ALSA,对应的命令是 amixer:

arecord -l                # 先看板子上有哪些录音设备、各是哪个 card
amixer -c 1 scontrols     # -c 1:打开"card 1"(PDM 麦克风所在声卡)的全部控件

输出只有 7 个控件:

'Receive PATH0 Source Select'   'Receive PATH1 Source Select'
'Receive PATH2 Source Select'   'Receive PATH3 Source Select'
'HPF Cutoff'    'HPFL Switch'    'HPFR Switch'

全是信号路由选择和高通滤波器开关,没有任何一个叫 Gain / Volume / PGA / Mic Boost 的控件。

也就是说:ALSA 层面根本没有暴露"录音增益"这个东西。要么驱动没实现,要么硬件真没有。

2. 求证:硬件真的"没有旋钮"(三层证据)

为确认不是配置问题,我从"板子 → 芯片 → 代码"三个层面交叉验证。

2.1 原理图/网表:麦克风是"直连"的

把 PDM 麦克风座子(CN4)的 4 根线从网表里找出来:

座子引脚 连到哪里
1 VCCA3V3_MIC(3.3V 电源,经一颗磁珠 L47 滤波)
2 GND
3 PDM1_CLK1_M0(SoC 输出的 PDM 时钟)
4 PDM1_SDI1_M0(麦克风输出的 PDM 数据)

就是"电源 + 地 + 时钟 + 数据"四根线直连 SoC,中间没有任何放大器、电位器之类的可编程器件。

2.2 寄存器:PDM 控制器里没有"增益"这个位

RK3588 的 PDM 控制器驱动头文件把全部寄存器列得清清楚楚(sound/soc/rockchip/rockchip_pdm.h):系统配置、控制寄存器、时钟控制、HPF 控制、FIFO 控制、DMA 控制、中断、数据、版本……

没有哪怕一个 bit 和增益 / 音量 / 衰减有关。

2.3 驱动:注册给 ALSA 的控件里也没有

rockchip_pdm.c 里注册的全部 mixer 控件,就是第 1 节 scontrols 列出的那 7 个;另外两个"启动延迟 / 滤波延迟"是 PCM 接口参数,不是音量类控件。在驱动里搜 gain / volume / pga / attenu,结果为零。

2.4 旁证:厂商补丁里的"土办法"

Rockchip 的 alsa-lib 补丁里有个有意思的东西:add_gain()(0003-add-gain-for-audio-input.patch),通过环境变量 ALSA_LIB_ADD_GAIN 指定一个"左移位数",把录音采样值整体左移(相当于乘一个整数倍)来放大。但它的判断条件是"跳过最后两个声道",双声道录音时一个声道都轮不到,等于白搭。

这个补丁的存在本身也从侧面说明:连芯片原厂都清楚 PDM 通路没有正经的硬件增益,只能在软件侧想办法。

小结:PDM 数字麦克风的输出电平,由麦克风芯片本身出厂决定。既然"源头"摇不动,唯一的出路就是——在软件侧对录到的数据做放大。

3. 数字麦克风到底有多小声?——顺便搞懂 dB

(已懂 dB/dBFS 的读者可以跳到第 4 节。)

3.1 dB 是"比值"的另一种写法

分贝(dB)不是一种单位,而是两个量比值的对数写法:+6 dB ≈ 幅度大 1 倍(更准确是 ×2,工程上常说 6 dB 翻倍),+20 dB = ×10,-20 dB = ×0.1。

关键:dB 永远要问"相对谁"。

  • dB SPL:声压级,衡量物理声音的强弱。0 dB SPL = 人的听阈(20 µPa);正常说话约 60 dB SPL,大嗓门喊叫约 85~90 dB SPL。
  • dBFS:数字音频"相对满刻度"(Full Scale)。0 dBFS 是数字波形能表示的最大值(顶格),所有正常录音信号都低于它,所以 dBFS 几乎总是负数——越接近 0 越大,负得越多越小。

3.2 麦克风的"-26 dBFS"是什么意思

数字麦克风数据手册里的灵敏度一般长这样:

Sensitivity: -26 dBFS @ 94 dB SPL

意思是:用 94 dB SPL 的标准测试声(1 帕斯卡声压,音频行业的标准测试条件)去"吹"它,它输出的数字信号位于满刻度以下 26 dB(-26 dBFS,换算成线性幅度约为满刻度的 5%)。

于是可以算一笔账:

  • 近距离大声说话,声压约 85 dB SPL:比 94 dB SPL 低 9 dB → 麦克风输出约 -26 - 9 = -35 dBFS;
  • -35 dBFS 换算成线性:10^(-35/20) ≈ 1.8%——16-bit 音频满刻度是 ±32767,这就是个幅度五百多的信号;
  • 想让麦克风输出"顶格"(0 dBFS)?需要约 94 + 26 = 120 dB SPL——那是喷气机起飞附近的声压级,正常人不会这么对着麦克风喊。

所以"录出来的文件天生就小"是设计使然:麦克风留了整整 26 dB 的动态余量,防止你一激动喊一声就削波失真。不是你的板子有问题。

注:有的麦克风模块资料会把灵敏度标注成"增益 26dB"。这个说法容易误导——它描述的仍然是"相对满刻度差 26 dB"的固定灵敏度,而不是说麦克风里装了一个可以调大调小的 26 dB 放大器。

4. 解决方案:ALSA softvol 软件增益

4.1 30 秒看懂 ALSA

ALSA(Advanced Linux Sound Architecture)是 Linux 的音频子系统,从下到上分三层:

  1. 内核层:声卡驱动(第 2 节看的 rockchip_pdm.c 就在这层),向用户空间提供 PCM 播放/录音节点;
  2. 库层:alsa-lib(即 libasound)。它的精华是插件体系——plughw、dmix、softvol 等等,可以把"硬件 + 各种软件处理"串联成一个设备,对上层透明;
  3. 工具层:aplay / arecord / amixer 等命令行工具。

平时 arecord -D hw:1,0 里的 hw:1,0 是"直达硬件"的设备名。而 -D 后面跟的名字不一定是内核设备:alsa-lib 会先在配置文件(/etc/asound.conf 或 ~/.asoundrc)里找同名定义。我们可以自定义一个名字,把它包装成"硬件 + 软件增益"的组合——这就是后面的 micboost。

4.2 /etc/asound.conf:给录音和放音各包一层增益

配置文件内容(板端 /etc/asound.conf):

# 放音:hw:0,0 + 软件增益,控件名 BoostPlayback
pcm.boost {
    type softvol
    slave.pcm "hw:0,0"
    control { name "BoostPlayback"; card 0 }
    min_dB -20.0      # 增益卷尺下端:-20 dB(衰减)
    max_dB 30.0       # 增益卷尺上端:+30 dB(约 31.6 倍)
    resolution 100    # 100 个刻度
}

# 录音:hw:1,0 + 软件增益,控件名 BoostCapture
pcm.micboost {
    type softvol
    slave.pcm "hw:1,0"
    control { name "BoostCapture"; card 1 }
    min_dB -20.0
    max_dB 30.0
    resolution 100
}

几行配置解释:

  • type softvol:软件音量插件——数据流经过它时,逐采样乘一个由控件控制的系数;
  • slave.pcm:它背后真正干活的硬件;
  • control { name ...; card ... }:让 softvol 在指定声卡上注册同名控件,之后就能用 amixer 调它;
  • min_dB / max_dB / resolution:这条"增益卷尺"的范围与刻度数。

之后:

  • 放音 aplay -D boost xxx.wav = 原来的 hw:0,0 + 可调增益;
  • 录音 arecord -D micboost ... = 原来的 hw:1,0 + 可调增益。

这就是"以前录调用 -D hw:1,0、现在用 -D micboost"的区别:同一个硬件,外面包了一层软件增益。

4.3 三个真心会踩的坑

  1. min_dB 必须写负数。我一开始写了 min_dB 0.0,直接被拒绝,报错:
    min_dB must be a negative value——这是 alsa-lib 源码 pcm_softvol.c 里写死的校验。写 -20.0 即可。
  2. 报 Unknown PCM boost 就是配置文件没生效。asound.conf 要放 /etc/asound.conf(全局)或 ~/.asoundrc(当前用户)。
  3. 控件是"动态出生"的:BoostPlayback / BoostCapture 这些控件不是驱动固件的一部分,而是 softvol 插件第一次以该 PCM 打开设备时注册到声卡上的(重启后需要重新打开一次才会再出现)。所以正确顺序是:
    先跑一次 aplay -D boost / arecord -D micboost(控件出生)→ amixer -c X scontrols 能看到它 → 再 sset 设置值。

4.4 这条"卷尺"怎么读(很重要)

100 格对应 -20 dB ~ +30 dB,刻度按 dB 均匀:每 1% ≈ 0.5 dB。

百分比 增益 线性倍数 说明
0% -20 dB ×0.1 衰减(不是静音)
20% -10 dB ×0.32
40% 0 dB ×1.0 原声:不放大也不衰减
50% +5 dB ×1.78
60% +10 dB ×3.16
80% +20 dB ×10
100% +30 dB ×31.6 最大

两个反直觉的点:

  • 40% 才是"原声",不是 50%(因为卷尺是 -20 ~ +30 dB,中点偏到了 +5 dB);
  • 控件刚出生时,默认值就是 0 dB 那一格(约 40%)。也就是说:你不去设置它,它等于不存在——录出来的文件还是原来那么小。这正是"必须显式设置"的原因。

5. 实战:正确的录音姿势

5.1 一条失败的命令:为什么录不了

我一开始很自然地写了:

arecord -D micboost -f S16_LE -d 5 /tmp/voice2.wav     # ← 录不了

报错关键词:Channels count non available(声道数不可用)。

原因:PDM 硬件最少要 2 个声道。驱动里写死了 channels_min = 2, channels_max = 8(rockchip_pdm.c:763);而 arecord 不写 -c 时默认按单声道打开(实测默认 1 声道、8000 Hz)。"1 声道的请求"撞上"最少 2 声道的硬件",参数协商直接失败。

顺便排除其他嫌疑:格式 S16_LE 和 8000~192000 Hz 的采样率都在 PDM 支持范围内(rockchip_pdm.c:753-757),所以卡住的就是声道数这一项。

5.2 完整流程

# 1) 第一次录音:让 BoostCapture 控件"出生"(此时是默认 0dB,声音小属正常)
arecord -D micboost -f S16_LE -r 16000 -c 2 -d 5 /tmp/voice2.wav

# 2) 确认控件出现了
amixer -c 1 scontrols | grep BoostCapture

# 3) 设置录音增益:+30 dB
#    录音侧原始信号很小,建议先拉满;
#    若大声说话时出现破音/发"呲"(削波),再降回 60%(约 +10 dB)
amixer -c 1 sset 'BoostCapture' 100%

# 4) 正式录音(与步骤 1 同一条命令)
arecord -D micboost -f S16_LE -r 16000 -c 2 -d 5 /tmp/voice2.wav

对比步骤 1 和步骤 4 的文件,音量提升非常明显(100% 即 +30 dB ≈ 31.6 倍)。

参数速查:

参数 含义 注意
-D micboost 设备名 来自 /etc/asound.conf,= hw:1,0 + 软件增益
-f S16_LE 16-bit 小端格式 PDM 支持
-r 16000 采样率 16 kHz 语音场景够用;不写默认 8000
-c 2 2 声道 必写,PDM 硬件要求 ≥ 2
-d 5 录 5 秒

5.3 顺带:放音侧

放音侧的 boost 同理:

amixer -c 0 sset 'BoostPlayback' 100%    # 100% = +30 dB,实测声音非常足
# 觉得太响?降到 60%(约 +10 dB)
amixer -c 0 sset 'BoostPlayback' 60%

注意两个控件的分工是独立的:

  • BoostCapture(card 1):决定录进文件里的数字有多大;
  • BoostPlayback(card 0):决定喇叭放出来听到的有多大。

6. 还差最后一步:重启后会失效

softvol 控件是动态注册的,重启后就没影了——直到你再用 boost / micboost 打开一次设备,它才会重新出生(并且回到默认 0 dB)。

如果希望开机就自动设好,可以在启动脚本(如 /etc/init.d/S99audio)末尾追加:

# 先各"空跑"一次,让 softvol 控件出生
arecord -D micboost -f S16_LE -r 16000 -c 2 -d 1 /dev/null 2>/dev/null
aplay  -D boost -t raw -f S16_LE -r 8000 -c 2 -d 1 /dev/zero 2>/dev/null

# 再设置目标增益
amixer -c 1 sset 'BoostCapture'  100% >/dev/null
amixer -c 0 sset 'BoostPlayback'  60% >/dev/null

代价是开机多花约 2 秒(两次 1 秒的"空跑")。

7. 常见坑速查

现象 / 报错 原因 解决
Channels count non available arecord 没写 -c 2(PDM 最少 2 声道) 加 -c 2
Unknown PCM boost asound.conf 没被加载 放到 /etc/asound.conf 或 ~/.asoundrc
min_dB must be a negative value min_dB 写了 0 或正数 写负值,如 -20.0
amixer 找不到 Boost* 控件 控件还没出生 先跑一次 aplay / arecord 打开设备
重启后增益失效 softvol 控件是动态注册的 启动脚本里"先空跑、再设置"
把 50% 当成"原声" 卷尺是 -20 ~ +30 dB,原声在 40% 记住 40% = 0 dB
hw:1.0 报错 hw 设备名的语法是逗号不是点 写 hw:1,0

8. 总结

  1. RK3588 + PDM 数字麦录音小,不是配置错误:麦克风灵敏度固定(-26 dBFS 级别),SoC 与驱动都没有任何硬件增益可调——这是从网表、寄存器、驱动源码三层验证过的。
  2. 解法是 ALSA 的 softvol 软件增益:在 /etc/asound.conf 里把 hw:1,0 包成 micboost。
  3. 录音命令三要素:-D micboost + -c 2 + 先让控件出生、再 amixer -c 1 sset 'BoostCapture' 100%。
  4. 软件增益的代价是底噪也会被一起放大——先解决"能不能听清",再按需要在 60% ~ 100% 之间找平衡。
posted @ 2026-10-10 09:06  风间澈1998  阅读(6)  评论(0)    收藏  举报