4. PCM 设备命名规则:hw 与 plughw 的区别

在 ALSA 用户空间编程中,正确理解 PCM 设备的命名规则是音频开发的第一步。ALSA 提供了两套设备访问接口:hw 和 plughw,它们分别对应直接硬件访问和带自动转换的访问方式。本章将详细解析设备名称格式、查看设备列表的方法,以及 hw 与 plughw 的核心差异。

4.1 设备名称格式:hw:card,device

ALSA 使用统一的设备标识符格式来定位 PCM 设备,基本语法为:

hw:<card_id>,<device_id>
  • card_id:声卡编号(从 0 开始),或声卡名称(如 "Generic")。
  • device_id:该声卡上的设备编号(从 0 开始)。

常见示例:

设备标识符 含义
hw:0,0 第一张声卡上的第一个 PCM 设备(通常为默认播放设备)
hw:0,1 第一张声卡上的第二个 PCM 设备(如 HDMI 输出)
hw:1,0 第二张声卡上的第一个 PCM 设备(如 USB 声卡)
hw:Generic,0 使用声卡名称 "Generic" 的第一个设备
提示: 在嵌入式开发中,hw:0,0 是最常用的设备标识符。如果系统只有一块声卡,通常就是它。但要注意,某些 SoC 内部音频编解码器可能映射到 hw:0,0,而外部 Codec 可能映射到 hw:0,1 或 hw:1,0。

4.2 hw 与 plughw 的核心区别

hw 设备提供对硬件的直接访问,不进行任何格式转换;plughw 设备则在用户空间和硬件之间插入一个软件转换层。两者的对比如下:

特性 hw plughw
访问方式 直接操作硬件寄存器 通过插件层间接访问
格式支持 仅支持硬件原生格式 自动转换采样率、位深、通道数
性能 零开销,低延迟 有转换开销,延迟略高
适用场景 已知硬件参数,追求极致性能 开发调试、跨平台兼容、格式不匹配时
错误处理 参数不匹配直接返回错误 自动尝试转换,失败才报错
重要: 在嵌入式产品中,生产环境应优先使用 hw 设备,因为 plughw 的软件转换层会引入额外的 CPU 占用和延迟,可能影响实时音频性能。仅在开发调试阶段或需要兼容不同音频格式时使用 plughw。

4.3 设备访问流程对比

下图展示了 hw 与 plughw 在 ALSA 架构中的位置差异:

hw 与 plughw 设备访问架构对比 用户空间应用程序 hw 设备(直接硬件访问) 硬件寄存器 / DMA 零转换开销 要求参数完全匹配硬件 用户空间应用程序 plughw 设备(插件层) 软件转换层 采样率 / 位深 / 通道转换 硬件寄存器 / DMA 有转换开销 自动适配硬件不支持的格式

4.4 使用 aplay -l 和 arecord -l 查看设备列表

在开发过程中,最常用的工具是 aplay(播放)和 arecord(录音),它们可以列出系统中所有可用的 PCM 设备。

4.4.1 查看播放设备:aplay -l

$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: Generic [HD-Audio Generic], device 0: ALC1220 Analog [ALC1220 Analog]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: Generic [HD-Audio Generic], device 1: ALC1220 Digital [ALC1220 Digital]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: USB [USB Audio], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

输出解读:

  • card 0:第一张声卡,名称为 "Generic"(HD-Audio Generic)。
  • device 0:该声卡上的第一个设备,模拟输出(ALC1220 Analog)。
  • device 1:该声卡上的第二个设备,数字输出(ALC1220 Digital)。
  • card 1:第二张声卡,USB 音频设备。
  • Subdevices:子设备数量,表示该设备支持多少个独立音频流。

4.4.2 查看录音设备:arecord -l

$ arecord -l
**** List of CAPTURE Hardware Devices ****
card 0: Generic [HD-Audio Generic], device 0: ALC1220 Analog [ALC1220 Analog]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: USB [USB Audio], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
关键点: 同一张声卡上的同一个设备编号,可能同时支持播放和录音(如 ALC1220 Analog 在 aplay -l 和 arecord -l 中都出现)。但有些设备只支持单向(如 HDMI 输出通常只出现在 aplay -l 中)。

4.5 设备名称的完整格式

除了 hw:card,device 和 plughw:card,device,ALSA 还支持更丰富的设备名称格式:

格式 示例 说明
hw:card,device hw:0,0 直接硬件访问,无转换
plughw:card,device plughw:0,0 带自动格式转换的硬件访问
default default 系统默认 PCM 设备(通常映射到 plughw:0,0)
sysdefault sysdefault 系统默认硬件设备(类似 hw:0,0)
dmix dmix:CARD=0,DEV=0 软件混音设备,允许多个进程同时播放

4.6 嵌入式开发中的实际选择策略

在嵌入式 Linux 音频开发中,选择 hw 还是 plughw 需要根据具体场景权衡:

  1. 原型验证阶段:优先使用 plughw:0,0 或 default,避免因格式不匹配导致开发中断。
  2. 性能调优阶段:切换到 hw:0,0,并确保应用程序设置的参数与硬件完全一致。
  3. 多进程场景:考虑使用 dmix 设备实现软件混音,避免独占硬件。
  4. 调试技巧:使用 aplay -D plughw:0,0 test.wav 和 aplay -D hw:0,0 test.wav 对比测试,观察是否出现错误。
实战建议: 在嵌入式设备上,先用 aplay -l 确认设备存在,然后用 aplay -D hw:0,0 test.wav 测试播放。如果报错 "Parameter not available",说明格式不匹配,此时改用 plughw:0,0 可快速验证硬件是否正常工作。

4.7 设备名称与子设备

某些硬件支持多个子设备(subdevice),允许同时打开多个音频流。设备名称可以进一步指定子设备编号:

hw:card,device,subdevice

例如:hw:0,0,0 表示第一张声卡、第一个设备、第一个子设备。大多数嵌入式 Codec 只支持 1 个子设备,因此通常省略子设备编号。

子设备的使用场景:

  • 多通道音频接口(如 8 通道 ADC,每个通道映射为一个子设备)。
  • 支持多个独立音频流的专业声卡。
  • 嵌入式 SoC 内部多个 I2S 接口共享同一个 PCM 设备。

4.8 本章小结

  • hw 设备:直接、高效、零开销,但要求参数完全匹配硬件。
  • plughw 设备:灵活、兼容、自动转换,但有性能开销。
  • 设备名称格式:hw:card,device 或 plughw:card,device,card 和 device 从 0 开始。
  • 查看设备列表:aplay -l 查看播放设备,arecord -l 查看录音设备。
  • 生产环境:优先使用 hw 设备,仅在需要兼容性时使用 plughw。