物理链路篇
转自:https://me.csdn.net/zyuanyun
Linux ALSA 音频系统:物理链路篇
Linux ALSA 音频系统:物理链路篇
1. Overview
硬件平台及软件版本:
- Kernel - 3.4.5
- SoC - Samsung exynos
- CODEC - WM8994
- Machine - goni_wm8994
- Userspace - tinyalsa
Linux ALSA 音频系统架构大致如下:
+--------+ +--------+ +--------+|tinyplay| |tinycap | |tinymix |+--------+ +--------+ +--------+| ^ ^ V | V+--------------------------------+| ALSA Library API || (tinyalsa, alsa-lib) |+--------------------------------+user space ^
-------------------------------|---------------------kernel space V+--------------------------------+| ALSA CORE || +-------+ +-------+ +------+ || | PCM | |CONTROL| | MIDI |...|| +-------+ +-------+ +------+ |+--------------------------------+|+--------------------------------+| ASoC CORE |+--------------------------------+|+--------------------------------+| hardware driver || +-------+ +--------+ +-----+ || |Machine| |Platform| |Codec| || +-------+ +--------+ +-----+ |+--------------------------------+
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- Native ALSA Application:tinyplay/tinycap/tinymix,这些用户程序直接调用 alsa 用户库接口来实现放音、录音、控制
- ALSA Library API:alsa 用户库接口,常见有 tinyalsa、alsa-lib
- ALSA CORE:alsa 核心层,向上提供逻辑设备(PCM/CTL/MIDI/TIMER/…)系统调用,向下驱动硬件设备(Machine/I2S/DMA/CODEC)
- ASoC CORE:asoc 是建立在标准 alsa core 基础上,为了更好支持嵌入式系统和应用于移动设备的音频 codec 的一套软件体系
- Hardware Driver:音频硬件设备驱动,由三大部分组成,分别是 Machine、Platform、Codec
本主题不遵循自顶而下的原则,而先从硬件设备驱动说起,毕竟这些是看得见摸得着听得到的东西,容易对其有着直观的理解。
//
// 声明:本文由 http://blog.csdn.net/zyuanyun 原创,转载请注明出处,谢谢!
//
ALSA/ASoC 中硬件设备关系:
+------------------------------------------+
| Machine |
| +--------------+ +--------------+ |
| | Platform | | Codec | |
| | | I2S | | |
| | cpu_dai|<---->|codec_dai | |
| | | | | |
| +--------------+ +--------------+ |
+------------------------------------------+
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-
Platform:指某款 SoC 平台的音频模块,如 exynos、omap、qcom 等等。Platform 又可细分两部分:
- cpu dai:在嵌入式系统里面通常指 SoC 的 I2S、PCM 总线控制器,负责把音频数据从 I2S tx FIFO 搬运到 CODEC(这是回放的情形,录制则方向相反)。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 Platform 区分开)。
- cpu dai:在嵌入式系统里面通常指 SoC 的 I2S、PCM 总线控制器,负责把音频数据从 I2S tx FIFO 搬运到 CODEC(这是回放的情形,录制则方向相反)。cpu_dai 通过
-
Codec:对于回放来说,userspace 送过来的音频数据是经过采样量化的数字信号,在 codec 经过 DAC 转换成模拟信号然后输出到外放或耳机,这样我们就可以听到声音了。Codec 字面意思是编解码器,但芯片里面的功能部件很多,常见的有 AIF、DAC、ADC、Mixer、PGA、Line-in、Line-out,有些高端的 codec 芯片还有 EQ、DSP、SRC、DRC、AGC、Echo-Canceller、Noise-Suppression 等部件。
-
Machine:指某款机器,通过配置 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 的时钟源等等。
从上面的描述来看,对于回放的情形,PCM 数据流向大致是:
copy_from_user DMA I2S DAC^ ^ ^ ^
+---------+ | +----------+ | +-----------+ | +-----+ | +------+
|userspace+-------->DMA Buffer+------->I2S TX FIFO+------->CODEC+------->SPK/HP|
+---------+ +----------+ +-----------+ +-----+ +------+
- 1
- 2
- 3
- 4
- 5
几个音频物理链路的概念:
dai_link:machine 驱动中定义的音频数据链路,它指定链路用到的 codec、codec_dai、cpu_dai、platform。比如对于 goni_wm8994 平台的 media 链路:codec="wm8994-codec"、codec_dai="wm8994-aif1"、cpu_dai="samsung-i2s"、platform="samsung-audio"
,这四者就构成了一条音频数据链路用于多媒体声音的回放和录制。一个系统可能有多个音频数据链路,比如 media 和 voice,因此可以定义多个 dai_link 。如 WM8994 的典型设计,有三个 dai_link,分别是 AP<>AIF1
的 “HIFI”(多媒体声音链路),BP<>AIF2
的 “Voice”(通话语音链路),以及 BT<>AIF3
(蓝牙 SCO 语音链路)。
代码如下:
static struct snd_soc_dai_link goni_dai[] = {
{.name = "WM8994",.stream_name = "WM8994 HiFi",.cpu_dai_name = "samsung-i2s.0",.codec_dai_name = "wm8994-aif1",.platform_name = "samsung-audio",.codec_name = "wm8994-codec.0-001a",.init = goni_wm8994_init,.ops = &goni_hifi_ops,
}, {.name = "WM8994 Voice",.stream_name = "Voice",.cpu_dai_name = "goni-voice-dai",.codec_dai_name = "wm8994-aif2",.codec_name = "wm8994-codec.0-001a",.ops = &goni_voice_ops,
},
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
hw constraints:指平台本身的硬件限制,如所能支持的通道数/采样率/数据格式、DMA 支持的数据周期大小(period size)、周期次数(period count)等,通过 snd_pcm_hardware
结构体描述:
static const struct snd_pcm_hardware dma_hardware = {.info = SNDRV_PCM_INFO_INTERLEAVED |SNDRV_PCM_INFO_BLOCK_TRANSFER |SNDRV_PCM_INFO_MMAP |SNDRV_PCM_INFO_MMAP_VALID |SNDRV_PCM_INFO_PAUSE |SNDRV_PCM_INFO_RESUME,.formats = SNDRV_PCM_FMTBIT_S16_LE |SNDRV_PCM_FMTBIT_U16_LE |SNDRV_PCM_FMTBIT_U8 |SNDRV_PCM_FMTBIT_S8,.channels_min = 2,.channels_max = 2,.buffer_bytes_max = 128*1024,.period_bytes_min = PAGE_SIZE,.period_bytes_max = PAGE_SIZE*2,.periods_min = 2,.periods_max = 128,.fifo_size = 32,
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
hw params:用户层设置的硬件参数,如 channels、sample rate、pcm format、period size、period count;这些参数受 hw constraints 约束。
sw params:用户层设置的软件参数,如 start threshold、stop threshold、silence threshold。
2. ASoC
ASoC:ALSA System on Chip,是建立在标准 ALSA 驱动之上,为了更好支持嵌入式系统和应用于移动设备的音频 codec 的一套软件体系,它依赖于标准 ALSA 驱动框架。内核文档 Documentation/alsa/soc/overview.txt
中详细介绍了 ASoC 的设计初衷,这里不一一引用,简单陈述如下:
- 独立的 codec 驱动,标准的 ALSA 驱动框架里面 codec 驱动往往与 SoC/CPU 耦合过于紧密,不利于在多样化的平台/机器上移植复用
- 方便 codec 与 SoC 通过 PCM/I2S 总线建立链接
- 动态音频电源管理 DAPM,使得 codec 任何时候都工作在最低功耗状态,同时负责音频路由的创建
- POPs 和 click 音抑制弱化处理,在 ASoC 中通过正确的音频部件上下电次序来实现
- Machine 驱动的特定控制,比如耳机、麦克风的插拔检测,外放功放的开关
在概述中已经介绍了 ASoC 硬件设备驱动的三大构成:Codec、Platform 和 Machine,下面列举各驱动的功能构成:
ASoC Codec Driver:
- Codec DAI 和 PCM 的配置信息
- Codec 的控制接口,如 I2C/SPI
- Mixer 和其他音频控件
- Codec 的音频接口函数,见
snd_soc_dai_ops
结构体定义 - DAPM 描述信息
- DAPM 事件处理句柄
- DAC 数字静音控制
ASoC Platform Driver: 包括 dma 和 cpu_dai 两部分:
- dma 驱动实现音频 dma 操作,具体见
snd_pcm_ops
结构体定义 - cpu_dai 驱动实现音频数字接口控制器的描述和配置
ASoC Machine Driver:
- 作为链结 Platform 和 Codec 的载体,它必须配置 dai_link 为音频数据链路指定 Platform 和 Codec
- 处理机器特有的音频控件和音频事件,例如回放时打开外放功放
硬件设备驱动相关结构体:
- snd_soc_codec_driver:音频编解码芯片描述及操作函数,如控件/微件/音频路由的描述信息、时钟配置、IO 控制等
- snd_soc_dai_driver:音频数据接口描述及操作函数,根据 codec 端和 soc 端,分为 codec_dai 和 cpu_dai
- snd_soc_platform_driver:音频 dma 设备描述及操作函数
- snd_soc_dai_link:音频链路描述及板级操作函数
下面是 goni_wm8994 类图,从这个类图中,我们可以大致了解 goni_wm8994 整个音频驱动组成:
3. Codec
上一章提到 codec_drv 的几个组成部分,下面逐一介绍,基本是以内核文档 Documentation/sound/alsa/soc/codec.txt
中的内容为脉络来分析的。Codec 的作用,之前已有描述,本章主要罗列下 Codec driver 中重要的数据结构及注册流程。
我们先看看 Codec 的硬件框图,以 WM8994 为例:
其中有着各种功能部件,包括但不限于 :