一 概述
安卓内核采用的是Linux内核,所以安卓也沿用了Linux内核内置的音频子系统。
Linux内核的音频子系统全称是Advanced Linux Sound Architecture,简称ALSA。
ALSA官网为https://www.alsa-project.org/wiki/Main_Page,在官网上有一些编程手册以及API介绍,也可以直接到Linux内核源码的 Documentation/sound 目录下去查阅编程信息
ALSA的版本是随同Linux内核版本一起发布,可以在https://www.kernel.org/获取到最新的Linux内核和ALSA的源码。
二 ALSA在安卓架构中的位置
在安卓系统中,hal层往上的结构图可以在官网找到
关于HAL到Linux Kernel,谷歌的图简略了一些
对于Linux Kernel来说,HAL就是应用层,从应用层访问ALSA,详细的结构应该是如下图所示
在这张结构图中,HAL和Kernel之间还隔了一个Tiny Alsa,这是一个谷歌写的开源的库,用来替换Linux系统中的ALSA库,通过这个库,HAL可以利用几个简单的API来写入音频数据。
三 ALSA代码结构简介
在Linux内核中各种子系统都会有一个Core,由这个Core来拿主设备号,音频子系统也不例外,Alsa Core会注册Alsa主设备,设备号是116。
为了适应移动平台,有了ASOC(ALSA System on Chip),在这个架构下,音频驱动程序可以分为三种,分别是
- Machine :用于描述一台设备的驱动,将Platform和Codec联系起来,在这个驱动里面注册声卡
- Platform:音频平台驱动,描述了CPU上的信息
- Codec:codec驱动,描述了各种外接的编解码器的信息
举例:
一款名为S5PV4418的处理器芯片,芯片上有个I2S接口,这个I2S接口的驱动程序就是Platform驱动,因为这个驱动可以适用在所有搭载了这颗CPU的板子上
一款名为ES8316的功放芯片,负责控制这颗芯片进行工作的驱动,就是Codec驱动,Codec驱动可以适用在所有使用ES8316作为codec的板子上
最后是Machine驱动,Machine驱动描述了Platform和Codec之间的连接信息,每一块板子,就会有自己的Machine驱动。
ALSA这么设计是为了解决之前ALSA中代码CPU和Codec代码过于耦合, 提高代码的复用性,减少重复工作。
四 代码位置
Alsa : kernel/sound/
TinyAlsa: 安卓源码/external/tinyalsa
五 设备节点与调试节点
Linux的用户层与内核驱动交互,基本都是通过设备的文件节点来的。
对于声卡,用户层通过以下的节点来交互。
/dev/snd/
- control:控制节点,可以通过这个节点来控制声卡内部的通路
- pcmC0D0c :capture的设备节点,其中C0表示声卡0,D表示该声卡上的0号设备,c表示Capture
- pcmC0D0p :playback的设备节点,p表示playback
除了这里的设备节点,还有调试节点:
/proc/asound/
- card0:声卡0,如果声卡注册失败,就不会有这个节点,可以进入这个节点,查看声卡上有哪些设备
- cards:cat这个节点可以知道当前系统所有注册的声卡
- pcm:获取当前设备的pcm信息
除了这个proc下的节点,如果在编译内核时enable了DEBUG_FS,还会有下面这个节点
/d/asoc/
- codecs:cat这个节点可以查看当前注册的codec
- dais:这个节点可以查看当前注册的dai
- platforms:这个节点可以查看当前注册的platform
- 还有一个声卡节点,会根据声卡名字变化,我这里是nanopi2-audio