主要内容来之参考文档,对一些描述做了些修正.
ALSA 的基本架构可以用上图表示,组成部分主要有:
ALSA 应用调用 ALSA 库提供的 API 来实现自己的需求。ALSA 库不同,代码实现差别也很大,这里不会做过多介绍。我们只是以 tinyalsa 为例,介绍一下声音播放的简单流程。
struct pcm_config config;
struct pcm *pcm;
char *buffer;
int size;
int num_read;
/* 设置音频的配置,通道、采样率、采样周期、编码格式等等 */
config.channels = xxx;
config.rate = xxx;
config.period_size = xxx;
config.period_count = xxx;
config.format = xxx;
/* 打开 PCM 设备 */
pcm = pcm_open(card, device, PCM_OUT, &config);
/* 根据音频配置计算需要的 buffer */
size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));
buffer = malloc(size);
/* 读取数据,写入到 PCM 设备中 */
do {
num_read = fread(buffer, 1, size, file);
if (num_read > 0)
pcm_write(pcm, buffer, num_read));
} while (num_read > 0);
/* 释放 buffer,关闭设备 */
free(buffer);
pcm_close(pcm);
}
应用一般通过 ALSA Library 与内核空间交互,尽管各种 Library 在实现上差别很大,但最终都是通过 Kernel ALSA Layer 提供系统调用完成调用。
ALSA Layer 是 ALSA 架构的核心层,在内核空间实现。它为用户空间提供逻辑设备接口,如PCM、Control、Mixer等等。同时为驱动提供接口来驱动硬件设备,如总线接口、DMA、Codec等等。
该层的主要数据结构包括,
- snd_card 表示一个声卡实例, 包含多个声卡设备 - snd_device 表示一个声卡设备部件 - snd_pcm 表示一个PCM设备, 声卡设备的一种, 用于播放和录音 - snd_control 表示Control设备, 声卡设备的一种, 用于控制声卡 - snd_pcm_str 表示PCM流, 分为playback和capture - snd_pcm_substream PCM子流, 用于音频的播放或录制 - snd_pcm_ops PCM流操作集
各数据结构的关系如下,
核心驱动的一般实现步骤如下,
为了简化 SoC 芯片上 ALSA 驱动的开发,在核心层的基础上构建了 ASoC(ALSA System on Chip) 层。ASoC 层主要由如下三部分组成:
ASoC Layer 主要负责驱动音频硬件设备,对外表现为一个整体的 Machine。Platform 控制 SoC 芯片中数字音频传输。Codec 控制音频编解码器,可能为内置或外置,通常使用 I2C 进行控制。
ASoC 支持三种主流的数字音频接口(Digital Audio Interfaces):AC97、I2S 和 PCM。注意这里的 PCM 表示只有硬件接口协议,与上面所说的软件 PCM 接口不同。
AC97: 通常用于PC声卡, 为5线接口, 每个AC97帧为21uS长, 被分为13个时隙
I2S是HiFi、STB和便携式设备中常用的4线DAI
PCM是另一种4线接口, 与I2S非常相似, 可以支持更灵活的协议
Codec驱动用于配置编解码器、FM、MODEM、BT 或外部 DSP, 以提供 playback 和 capture。每个Codec驱动必须提供如下功能:
Linux ALSA详解