2. ALSA驱动框架:声卡、设备、子设备与PCM/Control

ALSA(Advanced Linux Sound Architecture)驱动框架的核心在于将复杂的音频硬件抽象为层次化的软件对象。理解声卡(Card)、设备(Device)、子设备(Subdevice)以及PCM和Control设备的概念,是掌握ALSA驱动开发与调试的基础。本章将逐一拆解这些核心抽象层,并展示它们之间的组织关系。

2.1 核心概念:Card、Device、Subdevice

ALSA采用三级层次结构来管理音频硬件:

  • 声卡(Card):代表一个物理或逻辑的音频接口单元。通常对应一个硬件设备(如PCI声卡、USB音频设备、SoC内部音频控制器)。每个Card拥有唯一的编号(card index,如0、1、2)。
  • 设备(Device):Card内部的独立功能单元。一个Card可以包含多个Device,例如:一个用于播放的PCM设备(device 0)、一个用于录音的PCM设备(device 1)、一个MIDI设备(device 2)、一个Control设备(device 0)。Device在Card内通过device index区分。
  • 子设备(Subdevice):Device内部的进一步细分。用于支持多路独立音频流。例如,一个支持多通道独立播放的PCM设备,可以包含多个Subdevice,每个Subdevice对应一个独立的音频流通道。Subdevice通过subdevice index标识。
关键理解: 用户空间通过 hw:Card,Device,Subdevice 三元组来唯一标识一个音频端点。例如 hw:0,0,0 表示Card 0、Device 0、Subdevice 0。
类比: Card就像一台多功能的音频接口机架;Device是机架上的独立模块(如播放模块、录音模块、效果器模块);Subdevice则是模块上的独立通道(如播放模块上的通道1、通道2)。
ALSA Card-Device-Subdevice 层次结构 ALSA 三级层次结构:Card → Device → Subdevice 声卡 (Card) - 索引: 0 设备 (Device) 0: PCM播放 子设备 0 (主通道) 子设备 1 (辅助通道) 设备 (Device) 1: PCM录音 子设备 0 (麦克风) 子设备 1 (线路输入) 用户空间访问路径示例: hw:0,0,0 → Card 0, Device 0 (PCM播放), Subdevice 0 (主通道)

2.2 PCM设备:音频数据传输的核心

PCM(Pulse Code Modulation)设备是ALSA驱动中负责数字音频数据播放(Playback)和录音(Capture)的接口。它是音频流传输的核心通道。

2.2.1 PCM设备的主要特征

  • 方向性:一个PCM设备可以是只播放、只录音或全双工。
  • 硬件参数:包括采样率(Sample Rate)、位深(Sample Format)、通道数(Channels)、周期大小(Period Size)等。
  • DMA传输:PCM设备通常通过DMA(直接内存访问)在内存和音频硬件之间搬运数据,减少CPU负载。
  • 数据流管理:通过 snd_pcm_open()、snd_pcm_writei()、snd_pcm_readi()、snd_pcm_close() 等API进行控制。
常见误区: PCM设备并不直接对应物理的“扬声器”或“麦克风”。它代表的是与音频编解码器(Codec)或数字音频接口(DAI)之间的数字数据通道。物理换能器(扬声器/麦克风)通常由更底层的Codec驱动管理。
PCM 设备数据流 PCM 设备数据流:用户空间 ↔ 内核空间 ↔ 硬件 用户空间 应用程序 (aplay / arecord) 内核空间 ALSA PCM 驱动 (DMA 缓冲区管理) 硬件 音频控制器 (I2S / DMA 引擎) 播放数据 DMA 传输 DMA 传输 录音数据 PCM 设备通过环形 DMA 缓冲区实现低延迟、高吞吐的音频数据传输

2.3 Control设备:音频路径与参数的管理者

Control设备是ALSA驱动中用于配置和控制音频路径、音量、增益、开关、混音器、路由等非数据流参数的接口。它不传输音频数据,而是提供“旋钮”和“开关”。

2.3.1 Control设备的核心元素

  • Control Element:一个具体的控制项,例如“Master Playback Volume”、“Mic Capture Switch”、“Left Input Mixer”等。
  • 属性:每个Element包含名称(Name)、类型(Type,如Integer、Boolean、Enum)、访问权限(Read/Write)、数值范围(Min/Max)等。
  • 用户空间接口:通过 amixer 工具或 snd_ctl_open() / snd_ctl_elem_read() / snd_ctl_elem_write() 等API进行访问。
PCM vs Control 对比:
特性PCM 设备Control 设备
主要功能传输音频数据流配置音频参数与路由
数据类型连续的PCM采样数据离散的控制值(整数、布尔、枚举)
典型操作read / writeread / write element value
用户工具aplay, arecord, speaker-testamixer, alsamixer
驱动接口snd_pcm_opssnd_kcontrol_new
Control 设备与 PCM 设备在声卡中的角色 声卡内部:PCM 设备与 Control 设备的分工 声卡 (Card) PCM 设备 播放数据流 录音数据流 DMA 缓冲区管理 硬件参数设置 Control 设备 音量控制 (Master, PCM, Mic) 开关控制 (Mute, Loopback) 路由选择 (Input Source, Mixer) 枚举控制 (接口选择) 控制/查询 PCM 设备负责“搬运”音频数据,Control 设备负责“调节”音频属性,两者协同工作

2.4 设备节点与用户空间访问

在用户空间,ALSA设备通过 /dev/snd/ 目录下的设备文件暴露。理解这些文件与Card/Device/Subdevice的对应关系至关重要。

设备文件对应关系说明
/dev/snd/controlC0Card 0 的 Control 设备用于访问混音器、音量等控制元素
/dev/snd/pcmC0D0pCard 0, Device 0, PlaybackPCM播放设备
/dev/snd/pcmC0D0cCard 0, Device 0, CapturePCM录音设备
/dev/snd/pcmC0D1pCard 0, Device 1, Playback第二个PCM播放设备(如果存在)
/dev/snd/timer全局定时器用于音频同步和时间戳
命名规则: pcmC<Card>D<Device><方向>。方向中 p 表示播放(Playback),c 表示录音(Capture)。例如 pcmC0D0p 是Card 0的第一个播放设备。

2.5 驱动注册流程简述

在ALSA驱动中,创建Card、Device、Subdevice的典型流程如下:

  1. 创建Card:调用 snd_card_new() 分配并初始化一个 struct snd_card 实例。
  2. 创建PCM设备:调用 snd_pcm_new() 在Card上创建一个PCM设备,并设置其播放/录音子设备数量。
  3. 设置PCM操作集:填充 struct snd_pcm_ops 结构体,实现 open、close、hw_params、prepare、trigger、pointer 等回调函数。
  4. 创建Control元素:调用 snd_ctl_new1() 和 snd_ctl_add() 注册音量、开关等控制元素。
  5. 注册Card:调用 snd_card_register() 将Card注册到ALSA核心,此时会在 /dev/snd/ 下创建设备节点。
关键数据结构:
struct snd_card {
    int number;                     // Card 索引
    char id[32];                    // Card ID 字符串
    struct list_head devices;       // 设备链表
    // ... 其他成员
};

struct snd_pcm {
    struct snd_card *card;          // 所属 Card
    unsigned int device;            // Device 索引
    struct snd_pcm_str streams[2];  // 播放和录音流 (SNDRV_PCM_STREAM_PLAYBACK / CAPTURE)
};

struct snd_pcm_substream {
    struct snd_pcm *pcm;            // 所属 PCM 设备
    unsigned int number;            // Subdevice 索引
    struct snd_pcm_ops *ops;        // 操作函数集
    struct snd_dma_buffer dma_buffer; // DMA 缓冲区
};
ALSA 驱动注册流程 ALSA 驱动注册流程(简化) 1. snd_card_new() 创建声卡对象 2. snd_pcm_new() 创建PCM设备 3. 设置 ops 填充回调函数 4. 添加 Control 注册控制元素 5. 注册 snd_card_register() 注册完成后,用户空间可见的设备节点 /dev/snd/controlC0 → Control 设备 /dev/snd/pcmC0D0p → PCM 播放设备 (Subdevice 0) /dev/snd/pcmC0D0c → PCM 录音设备 (Subdevice 0) /dev/snd/pcmC0D1p → 第二个 PCM 播放设备 (如果存在) /dev/snd/timer → 全局定时器

2.6 本章小结

  • ALSA驱动采用 Card → Device → Subdevice 三级层次结构管理音频硬件。
  • PCM设备是音频数据流的核心通道,负责播放和录音的DMA传输。
  • Control设备是音频参数和路由的配置接口,提供音量、开关、混音器等控制元素。
  • 用户空间通过 /dev/snd/ 下的设备文件访问这些抽象对象,命名规则为 pcmC<Card>D<Device><方向>。
  • 驱动注册流程遵循 snd_card_new() → snd_pcm_new() → 设置ops → 添加Control → snd_card_register() 的步骤。