Linux音频系统比较复杂,各层间有很多交叉,可能是最无序的子系统。
ALSA 是 Advanced Linux Sound Architecture 的缩写,即高级Linux声音架构,在 Linux 操作系统上提供了对音频和 MIDI(Musical InstrumentDigital Interface,音乐设备数字化接口)的支持。在Linux2.6 版本内核以后,ALSA 已经成为默认的声音子系统,用来替换 2.4 版本内核中的OSS(Open Sound System,开放声音系统)。
ALSA 是一个完全开放源码的音频驱动程序集,是由志愿者维护的开源项目,而 OSS 则是由公司提供的商业产品。ALSA 系统包括驱动包alsa-driver(集成在内核源码),开发包 alsa-libs,开发包插件 alsalibplugins,设置管理工具包 alsa-utils,其他声音相关处理小程序包alsa-tools,特殊音频固件支持包 alsa-firmware。
ASoC 是Alsa System on Chip的缩写,用于实现那些集成声音控制器的CPU,它的设计目标如下:
解耦codec,codec的驱动不依赖具体的平台;
简单易用的I2S/PCM配置接口,让soc和codec的配置相匹配;
动态的电源管理DAPM,实现对用户空间透明的电源管理,各个widget按需供电,实现功耗最小化;
消除pop音,控制各个widget上下电的顺序消除pop音;
添加平台相关的控制,如earphone, speaker。
在嵌入式开发中,SoC一般都会集成音频相关的控制器,所以嵌入式开发中基本上就是使用ASoC架构,后面也是以ASoC 架构来分析。
为了解决复用性问题, 内核才引入了ASoC架构,在底层ASoC抽象了如下三个模块:Platform、Codec 和 Machine。
指某款soc平台的音频模块,该模块负责DMA的控制和I2S的控制, 由CPU厂商负责编写此部分代码。platform又可细分为二个部分:
cpu dai:在嵌入式系统里面通常指soc的i2s,pcm总线控制器,负责把音频数据从I2S tx FIFO搬运到codec(playback,capture则相反)。cpu_dai通过 snd_soc_register_dai()来注册。注:DAI是Digital Audio Interface的简称,分为cpu_dai和codec_dai,这两者通过i2s/pcm总线连接;AIF是Audio Interface母的简称,嵌入式系统中一般是I2S和PCM接口。
PCM dma:负责把dma buffer中的音频数据搬运到i2s tx fifo。值得留意的是:某些情形下是不需要dma操作的,比如modem和codec直连,因为modem本身已经把数据送到fifo了,这时只需要启动codec_dai接收数据即可;该情形下,machine驱动dai_link中需要设定.platform_name = “snd_soc_dummy”,这是虚拟dma驱动,实现见sound/soc/soc-utils.c。音频dma驱动通过 snd_soc_register_platform()来注册,故也常用platform来指代音频dma驱动(这里的platform需要与soc platfrom区分开)。
该模块负责AFIx的控制和DAC部分的控制(也可以说是芯片自身的功能的控制), 由Codec厂商负责编写此部分代码。codec部分主要就是codec dai。
对于回放来说,userspace送过来的音频数据是经过采样量化的数字信号,在codec经过DAC转换成模拟信号然后输出到外放或耳机,这样你就可以听到声音了,codec字面意思是编解码器,但芯片(codec)里面的功能部件很多,常见的有AIF,DAC,ADC,Mixer,PGA,line-in,line-out,有些高端的codec芯片还有EQ,DSP,SRC,DRC,AGC,Echo-Canceller,Noise-Suppression等部件。
用于描述一块电路板, 它指明此块电路板上用的是哪个Platform和哪个Codec, 由电路板商负责编写此部分代码。
通过配置dai_link把cpu_dai,codec_dai,modem_dai各个音频接口给链结成一条条音频链路,然后注册snd_soc_card.和上面两个不一样,platform和codec驱动一般是可以重用的,而machine有它特定的硬件特性,几乎是不可重用的。所谓的硬件特性指:Soc Platform与Codec的差异;DAIs之间的链结方式;通过某个GPIO打开Amplifier;通过某个GPIO检测耳机插拔;使用某个时钟如MCLK/External-OSC作为i2s,CODEC的时钟源等等。
以播放为例, 流程如下:
DMA : 负责把用户空间的音频数据从系统内存搬移至I2S的FIFO.
I2S : 负责以某个采样频率、采样深度、通道数发送音频数据, 也叫dai (Digital Audio Interface).
AFIx : 负责以某个采样频率、采样深度、通道数接收音频数据, 也称作dai.
DAC : 并把数据通过DAC转换后送给耳机等播放.
controlC0 :用于声卡的控制,例如通道选择,混音,麦克风的控制等
midiC0D0: 用于播放midi音频,C0D0代表的是声卡0中的设备0
pcmC0D0c: 用于录音的pcm设备,c表示capture
pcmC0D0p: 用于播放的pcm设备,p表示playback
seq : 音序器
timer : 定时器
cards : 可显示系统中存在多少个声卡
card0 : 代表某个声卡
devices : 可显示系统中存在多少个逻辑设备
PCM中间层(pcm.c)主要完成一些公共性的事情, 这些事情一般与具体的硬件无关(例如存储音频数据时, 肯定需要一个Buffer, 这个Buffer很显然用环形缓冲区描述比较好, 怎么管理这个环形缓冲区的读写指针?
另外, 用户空间设置的音频参数要检查其合法性. 还有, 用户空间可能启停音频播放/录制, 这意味着我们最好实现一个状态机, 来管理用户空间的切换操作. 等等). 对于与具体硬件相关的操作,PCM中间层会pass给底层驱动去处理(这就意味着PCM中间层要定义interface, 让底层驱动去实现这些interface);
底层驱动(具体的platform或codec)则处理与具体硬件相关的事情, 例如I2S控制器的配置, Codec芯片的配置, 时钟的初始化等等。