1. ALSA音频子系统概述
ALSA(Advanced Linux Sound Architecture)是 Linux 内核中用于替代旧式 OSS(Open Sound System)的音频子系统。它提供了从底层硬件驱动到上层用户空间 API 的完整音频处理栈,是嵌入式 Linux 音频开发的核心基础设施。
1.1 ALSA 整体架构
ALSA 采用分层设计,从上到下依次为:用户空间应用程序、ALSA 库(libasound)、ALSA 内核核心层、硬件驱动层。每一层都封装了特定的职责,并通过标准接口进行交互。
架构要点: ALSA 的分层设计使得应用程序无需关心底层硬件细节,驱动开发者只需实现内核层的 ops 回调,即可完成音频设备适配。
1.2 用户空间与内核空间接口
ALSA 的用户空间与内核空间通过 字符设备文件 和 ioctl 系统调用 进行通信。设备文件通常位于 /dev/snd/ 目录下,包括 pcmC0D0p(播放)、pcmC0D0c(录音)等。
| 接口类型 | 设备文件示例 | 说明 |
|---|---|---|
| PCM 播放 | /dev/snd/pcmC0D0p |
Card 0, Device 0, Playback |
| PCM 录音 | /dev/snd/pcmC0D0c |
Card 0, Device 0, Capture |
| Control 接口 | /dev/snd/controlC0 |
音量控制、混音器、路由 |
| Timer 接口 | /dev/snd/timer |
音频定时器 |
| MIDI 接口 | /dev/snd/midiC0D0 |
MIDI 输入/输出 |
用户空间通过 open() 打开设备文件,然后使用 ioctl() 传递 SNDRV_PCM_IOCTL_* 命令字来配置采样率、声道数、数据格式、缓冲区大小等参数。内核中的 ALSA 核心层解析这些命令,并调用底层驱动的回调函数。
性能提示: 在嵌入式系统中,频繁的 ioctl 调用会增加上下文切换开销。建议在初始化阶段一次性配置好 PCM 参数,运行时尽量减少控制命令的发送频率。
1.3 PCM 设备模型
PCM(Pulse Code Modulation)是 ALSA 中最核心的音频数据流模型。一个 PCM 设备代表一个数字音频输入或输出通道,它管理着音频数据的缓冲区、DMA 传输、中断触发和指针更新。
1.3.1 PCM 设备的核心组件
- snd_pcm 结构体: 内核中表示 PCM 设备的核心对象,包含硬件参数、运行时状态、ops 回调函数指针。
- snd_pcm_substream: 每个 PCM 设备可以包含多个 substream,用于支持多路并发播放/录音。
- snd_pcm_hardware: 描述硬件能力,如支持的采样率范围、缓冲区大小限制、DMA 对齐要求。
- snd_pcm_ops: 驱动开发者需要实现的回调函数集合,包括
open、close、hw_params、prepare、trigger、pointer等。 - DMA 缓冲区: 用于在内存和音频硬件之间传输音频数据的环形缓冲区。
1.3.2 PCM 操作流程
- open: 创建 substream 实例,分配运行时数据结构。
- hw_params: 设置硬件参数(采样率、格式、声道数、缓冲区大小)。
- sw_params: 设置软件参数(中断触发阈值、起始阈值、静音阈值)。
- prepare: 重置 DMA 指针,清空缓冲区,准备硬件传输。
- trigger (START): 启动 DMA 传输,音频数据开始流动。
- 中断处理: 每次 period 完成时触发中断,更新 appl_ptr,唤醒等待队列。
- trigger (STOP): 停止 DMA 传输。
- close: 释放资源,关闭设备。
常见陷阱: 在嵌入式平台上,
hw_params 阶段分配的 DMA 缓冲区必须满足硬件对齐要求(如 32 字节对齐)。如果缓冲区地址或大小不对齐,可能导致 DMA 传输失败或数据错位。
1.3.3 关键数据结构关系
| 数据结构 | 所属层次 | 主要字段 | 作用 |
|---|---|---|---|
snd_card |
核心层 | number, driver, devices | 声卡实例,管理所有设备 |
snd_pcm |
核心层 | card, streams, ops | PCM 设备,包含 playback/capture 流 |
snd_pcm_substream |
核心层 | runtime, number, stream | 单个音频流实例 |
snd_pcm_runtime |
核心层 | hw/sw_params, status, dma_area | 运行时状态和缓冲区管理 |
snd_dma_buffer |
驱动层 | area, addr, bytes, type | DMA 缓冲区描述 |