主要内容来之参考文档,对一些描述做了些修正.
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详解