1. ALSA 音频架构概述
ALSA(Advanced Linux Sound Architecture)是 Linux 内核中负责音频设备管理的核心子系统。它向上提供统一的系统调用接口,向下抽象各类音频硬件,是用户空间应用程序与音频硬件之间的桥梁。理解 ALSA 在 Linux 内核中的位置、用户空间与内核空间的交互方式以及核心数据结构的关系,是掌握声卡注册与设备树配置的基础。
1.1 ALSA 在 Linux 内核中的位置
ALSA 位于 Linux 内核的 drivers/sound/ 目录下,属于字符设备驱动框架的一部分。它通过 VFS(虚拟文件系统)暴露设备节点,并依赖内核其他子系统完成 DMA 传输、中断处理、电源管理等任务。
关键路径: 用户空间 → 系统调用 → VFS → ALSA 核心层 → 硬件驱动层 → 音频控制器
ALSA 在内核中的层次关系如下表所示:
| 层次 | 组件 | 职责 |
|---|---|---|
| 用户空间 | 应用程序(aplay、arecord、PulseAudio、PipeWire) | 通过 ALSA lib 调用 ioctl、mmap、read/write |
| 系统调用层 | VFS + 字符设备接口 | 将文件操作映射到 ALSA 核心层的回调函数 |
| ALSA 核心层 | snd core、pcm、control、midi、timer | 管理声卡对象、PCM 流、控制接口、DMA 缓冲区 |
| 硬件抽象层 | soc-core、ac97、hdmi、i2s 控制器驱动 | 封装硬件寄存器操作,提供平台无关接口 |
| 硬件层 | 音频控制器(I2S、AC97、HDA)、Codec、DMA 引擎 | 物理音频信号的采集与播放 |
1.2 用户空间与内核空间接口
ALSA 在用户空间与内核空间之间定义了清晰的接口边界。用户空间通过 ALSA lib 库调用内核暴露的字符设备接口,内核则通过 file_operations 结构体注册回调函数处理请求。
1.2.1 设备节点
ALSA 在 /dev/snd/ 目录下创建以下设备节点:
- controlC0:控制接口,用于音量调节、混音器设置、枚举控件
- pcmC0D0p:PCM 播放设备(p = playback)
- pcmC0D0c:PCM 录音设备(c = capture)
- timer:定时器接口,用于音频时钟同步
- midiC0D0:MIDI 设备接口
1.2.2 核心接口调用流程
| 用户空间操作 | 系统调用 | 内核回调 | 说明 |
|---|---|---|---|
| snd_pcm_open() | open() | snd_pcm_playback_open() | 打开 PCM 设备,分配运行时结构 |
| snd_pcm_hw_params() | ioctl(SNDRV_PCM_IOCTL_HW_PARAMS) | snd_pcm_hw_params() | 设置采样率、格式、通道数、缓冲区大小 |
| snd_pcm_sw_params() | ioctl(SNDRV_PCM_IOCTL_SW_PARAMS) | snd_pcm_sw_params() | 设置触发阈值、中断周期等软件参数 |
| snd_pcm_prepare() | ioctl(SNDRV_PCM_IOCTL_PREPARE) | snd_pcm_prepare() | 准备 DMA 缓冲区,重置指针 |
| snd_pcm_writei() | write() / ioctl | snd_pcm_playback_trigger() | 启动 DMA 传输,将数据写入环形缓冲区 |
| snd_pcm_readi() | read() / ioctl | snd_pcm_capture_trigger() | 从环形缓冲区读取采集到的音频数据 |
提示: 内核空间与用户空间之间的数据传递主要通过 DMA 环形缓冲区 完成,避免每次读写都产生中断。用户空间通过 mmap 可以直接映射 DMA 缓冲区,实现零拷贝音频传输。
1.3 核心数据结构关系图
ALSA 内核驱动的核心数据结构围绕 struct snd_card 展开,它代表一个物理或逻辑声卡。理解这些结构体之间的关联是编写音频驱动的关键。
1.3.1 核心结构体一览
| 结构体 | 头文件 | 作用 |
|---|---|---|
struct snd_card |
include/sound/core.h | 声卡顶层对象,管理所有子设备 |
struct snd_pcm |
include/sound/pcm.h | PCM 设备,包含 playback 和 capture 子流 |
struct snd_pcm_substream |
include/sound/pcm.h | 单个 PCM 数据流,管理运行时参数和 DMA 缓冲区 |
struct snd_pcm_runtime |
include/sound/pcm.h | 运行时状态,记录 hw/sw 参数、DMA 地址、指针位置 |
struct snd_control |
include/sound/control.h | 控制接口,用于音量、混音器、开关等控件 |
struct snd_soc_card |
include/sound/soc.h | ASoC 框架中的声卡对象,关联平台、Codec、DAI 链路 |
struct snd_soc_dai |
include/sound/soc.h | 数字音频接口,描述 I2S、TDM、AC97 等总线配置 |
struct snd_soc_codec |
include/sound/soc.h | 音频编解码器驱动,负责 DAC/ADC 转换 |
1.3.2 结构体关系
核心结构体之间的包含与引用关系如下:
- snd_card 是根对象,通过
devices链表挂载 snd_pcm、snd_control 等子设备。 - snd_pcm 包含两个 snd_pcm_substream(playback 和 capture),每个 substream 拥有独立的 snd_pcm_runtime。
- snd_pcm_runtime 记录 snd_pcm_hw_params(硬件参数)和 snd_pcm_sw_params(软件参数),并指向 DMA 缓冲区描述符。
- 在 ASoC 框架中,snd_soc_card 通过 dai_link 数组连接 snd_soc_dai 和 snd_soc_codec,形成完整的音频路径。
注意: 在设备树配置中,
snd_soc_card 的实例化通常由 simple-card 或 audio-graph-card 驱动完成,开发者只需在设备树中描述 DAI 连接关系,无需手动编写结构体初始化代码。
1.4 本章小结
- ALSA 是 Linux 内核音频子系统的核心,位于 drivers/sound/,通过 VFS 字符设备接口与用户空间交互。
- 用户空间通过
/dev/snd/设备节点和 ALSA lib 库访问内核音频功能,核心操作包括 open、ioctl、mmap、read/write。 - 核心数据结构以 snd_card 为根,向下包含 snd_pcm、snd_pcm_substream、snd_pcm_runtime,以及 snd_control 控制接口。
- 在 ASoC 框架中,snd_soc_card 通过 DAI link 连接 Codec 和 CPU DAI,设备树配置直接描述这些连接关系。