ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Linux 音频入门:一首歌是怎么从手机里播放出来的?从 PCM 到 ALSA(一)

Linux 音频入门:一首歌是怎么从手机里播放出来的?从 PCM 到 ALSA(一) 目录一、先别急着学 ALSA想一个问题二、先记住这一张图三、声音到底是什么四、那播放声音是不是反过来五、CPU 里的音频数据长什么样PCM六、PCM 有三个特别重要的参数七、什么是采样率八、什么是位宽九、什么是声道Frame十、一个真实一点的例子十一、好了终于可以聊 ALSA 了ALSA十二、ALSA 到底解决了什么问题十三、ALSA 不是一个命令十四、Linux 为什么会有 /dev/snd十五、aplay -l 到底在干什么十六、播放一首歌到底发生了什么十七、等等为什么又冒出来一个 DMA十八、Codec 又是什么十九、那 ASoC 又是从哪里冒出来的ASoC二十、现在重新看整条音频链路二十一、这一篇到底应该记住什么1. PCM 是什么2. PCM 最重要的参数有哪些3. ALSA 是什么4. aplay 是什么5. Codec 是什么6. ASoC 是什么二十二、把这些东西记成一句话二十三、下一篇讲什么系列说明这是《从零理解 Linux ALSA、ASoC 到 Qualcomm Audio》系列的第一篇。如果你之前没有接触过 ALSA、ASoC、Codec甚至看到aplay都不知道它是什么那么没关系。这一篇我们不看复杂源码只解决一个问题你点下“播放音乐”之后声音到底是怎么从 CPU 里一路跑到 Speaker 的一、先别急着学 ALSA想一个问题假设现在手机里有一首歌music.mp3你点击播放。几秒钟之后 音乐响了是不是感觉理所当然但如果站在程序员的角度这里面其实有很多问题MP3 文件怎么变成声音CPU 处理的到底是什么数据什么是 PCMALSA 在这里干什么声卡又是什么Codec 是什么东西Speaker 为什么能发出声音Android 的 AudioFlinger 又跑到哪里去了ASoC 和 ALSA 到底是什么关系后面这些问题我们都会慢慢解决。不过第一篇先别急着冲进源码。先把整个世界地图拿到手。二、先记住这一张图如果你暂时什么都不想看只记住下面这张图也行。播放声音大体可以理解成应用程序 ↓ 音频数据 ↓ ALSA ↓ Linux 音频驱动 ↓ 音频硬件 ↓ Codec ↓ Speaker ↓ 耳朵当然真实系统比这个复杂得多。特别是 Android 和高通平台还会在中间塞进去一大堆东西。比如App ↓ AudioTrack ↓ AudioFlinger ↓ Audio Policy ↓ Audio HAL ↓ Qualcomm Audio ↓ DSP ↓ ALSA / ASoC ↓ Codec ↓ Speaker看到这里如果你已经有点头疼非常正常。这也是为什么我们要从 ALSA 开始而不是第一篇直接去看 Qualcomm Audio 源码。三、声音到底是什么这个问题听起来有点哲学。我们程序员平时接触到的是0 1 0 1 0 1而声音其实是空气的振动。比如你说一句你好空气会跟着振动。麦克风负责把这种振动转换成电信号。问题来了CPU 不认识“空气振动”。CPU 更喜欢数字所以我们需要把模拟世界的声音转换成数字世界的数据。大概是这样空气振动 ↓ 麦克风 ↓ 模拟电信号 ↓ ADC ↓ 数字音频数据 ↓ CPU这里的ADC全称是Analog to Digital Converter也就是模数转换器。简单说把现实世界的声音翻译成 CPU 能看懂的数字。四、那播放声音是不是反过来没错。录音的时候声音 ↓ Mic ↓ ADC ↓ 数字音频 ↓ CPU播放的时候CPU ↓ 数字音频 ↓ DAC ↓ 模拟信号 ↓ Speaker ↓ 声音这里又出现一个东西DAC全称Digital to Analog Converter也就是数模转换器。所以可以非常粗暴地记ADC声音 → 数字 DAC数字 → 声音这两个概念以后学习 Codec 的时候会天天见。五、CPU 里的音频数据长什么样好了现在我们知道声音要变成数字。那么问题来了数字音频到底长什么样其实没有那么神秘。例如100 105 120 135 150 142 130 110 90 ...这些数字可以用来描述声音波形。当然真实数据远比这个复杂。但你可以先把它理解成声音波形 ↓ 不断采样 ↓ 得到一堆数字这些数字就是我们经常说的PCMPCM 全称Pulse Code Modulation中文一般叫脉冲编码调制。这里先不要把 PCM 想得太复杂。对于初学者可以先记住PCM 就是计算机里非常常见的一种原始数字音频数据。六、PCM 有三个特别重要的参数看到 PCM脑子里应该马上想到三个东西采样率 位宽 声道也就是Sample Rate Bit Width Channels这三个东西以后看日志、看 Audio HAL、看 ALSA 参数基本跑不掉。七、什么是采样率例如48000 Hz是什么意思意思是一秒钟采样 48000 次。可以想象我们拿着一个相机拍声音。当然这个相机有点奇怪它不是拍照片而是每秒拍 48000 次于是声音 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 采样 | | | | | | | | | | | | | | |采样率越高单位时间采集的数据点越多。常见的采样率包括8000 Hz 16000 Hz 44100 Hz 48000 Hz 96000 Hz在手机和嵌入式音频系统中48000 Hz是非常常见的一个采样率。以后你看高通 Audio 日志如果看到48000不要一脸懵。它很可能就是48 kHz八、什么是位宽假设我们采集到了一个采样点。这个采样点到底用多少个 bit 表示这就是Bit Width常见的有8 bit 16 bit 24 bit 32 bit例如16 bit表示一个采样点使用 16 bit 数据表示。也就是16 bit 2 Byte所以采样率决定一秒钟采多少次。而位宽决定每一次采样用多少数据表示。九、什么是声道再看第三个参数Channel也就是声道。例如1 Channel就是单声道Mono而2 Channels就是双声道Stereo双声道可以简单理解成Left Right 左声道 右声道所以一个双声道音频可能是Frame 0 Left Right Frame 1 Left Right Frame 2 Left Right这里又会出现一个后面非常重要的词Frame对于双声道来说一个 Left Sample 一个 Right Sample 一个 Frame这个概念先记住。后面学习 ALSA Buffer、Period 的时候会再次遇到。十、一个真实一点的例子假设我们现在有这么一个 PCM 音频Sample Rate 48000 Hz Bit Width 16 bit Channels 2那么每秒有48000 个 Frame因为是双声道所以每个 Frame 有Left 16 bit Right 16 bit一个 Frame16 16 32 bit 4 Byte所以每秒的数据量48000 × 4 192000 Byte也就是大约187.5 KiB/s这就是原始 PCM 数据。注意PCM 没有 MP3 那么“苗条”。MP3 会进行压缩而 PCM 基本就是老老实实把采样数据放在那里。所以MP3 ↓ 解码 PCM这一步在音频系统里非常重要。十一、好了终于可以聊 ALSA 了现在我们知道 CPU 里面有一堆 PCM 数据。但是问题来了CPU 怎么把这些数据交给声卡总不能让每个应用程序自己研究I2S DMA Codec 寄存器那程序员估计还没听到音乐头发先没了。所以 Linux 提供了一套统一的音频架构ALSAALSA 全称Advanced Linux Sound Architecture简单理解ALSA 是 Linux 用来管理和访问音频设备的一套音频架构。它负责把上层的软件和底层音频硬件连接起来。可以先粗略理解成应用程序 ↓ ALSA ↓ 音频设备当然真实情况要复杂很多。但作为第一步这样理解完全够用。十二、ALSA 到底解决了什么问题假设没有 ALSA。现在有三个声卡厂商厂商 A 厂商 B 厂商 C每个厂商的硬件接口都不一样。应用程序是不是要写if (A) 用 A 的接口; if (B) 用 B 的接口; if (C) 用 C 的接口;那简直就是灾难。ALSA 的作用之一就是提供一个相对统一的接口。于是应用程序可以通过 ALSA 访问音频设备而不用直接关心底层硬件的所有细节。可以理解成应用程序 ↓ ALSA API ↓ ┌────────┴────────┐ ↓ ↓ 声卡 A 声卡 B ↓ ↓ 硬件 A 硬件 B上面的应用程序“我想播放 PCM。”下面具体是什么 Codec“你们自己商量。”这就是软件抽象的价值。十三、ALSA 不是一个命令刚开始学 ALSA特别容易产生一个误解ALSA 是不是那个aplay命令不是。aplay只是 ALSA 相关工具之一。常见的还有aplay arecord amixer alsamixer例如aplay -l可以查看播放设备。arecord -l可以查看录音设备。amixer可以查看和控制一些音频 Mixer 参数。所以ALSA ├── Kernel 音频框架 ├── 用户空间 API ├── PCM ├── Control └── 各种工具而aplay只是其中一个工具。十四、Linux 为什么会有 /dev/snd如果你是在 Linux 开发板或者 Ubuntu 上折腾音频可以执行ls -l /dev/snd/可能看到controlC0 pcmC0D0c pcmC0D0p timer看到这些名字先别害怕。拆开看就简单多了。比如pcmC0D0p可以粗略理解成C0表示Card 0D0表示Device 0最后p表示Playback也就是播放。而pcmC0D0c最后的c表示Capture也就是录音。所以pcmC0D0p ↓ Card 0 Device 0 PlaybackpcmC0D0c ↓ Card 0 Device 0 Capture这时候你已经开始看懂 Linux 的声音设备节点了。十五、aplay -l 到底在干什么执行aplay -l你可能看到类似**** List of PLAYBACK Hardware Devices **** card 0: Device [xxx], device 0: ...这里至少先记住两个词card device可以先简单理解成Card 0 ├── Device 0 ├── Device 1 └── Device 2一张声卡上可以有多个音频设备。所以card ≠ device这个区别以后分析 ALSA 和 ASoC 时非常重要。十六、播放一首歌到底发生了什么现在把前面所有知识串起来。假设我们执行aplay test.wav表面上非常简单。但内部实际上干了不少事情。第一步打开 test.wav然后读取音频参数Sample Rate Channels Format比如48000 Hz 2 Channels 16 bit然后获取 PCM 数据接下来打开 ALSA PCM 设备然后设置Sample Rate Channels Format Buffer Size Period Size最后不断把 PCM 数据写进去。于是整个过程大概是test.wav ↓ aplay ↓ ALSA Library ↓ ALSA PCM ↓ Linux Kernel ↓ PCM Buffer ↓ DMA ↓ Audio Controller ↓ Codec ↓ DAC ↓ Speaker ↓ 这就是我们第一篇最重要的一张图。十七、等等为什么又冒出来一个 DMA这里先简单解释一下。CPU 如果每次播放一个采样点都亲自跑过去告诉硬件“兄弟给你一个数据。”然后“再给你一个。”再“还有一个。”CPU 会累死。所以一般会准备一块内存PCM Buffer然后让 DMA 帮忙搬数据。大概是CPU ↓ PCM Buffer ↓ DMA ↓ Audio Controller ↓ Codec ↓ SpeakerCPU 主要负责准备数据 配置硬件 管理状态DMA 负责搬数据这样大家各司其职。这个概念后面分析 ALSA PCM Buffer 时会详细讲。十八、Codec 又是什么现在问题来了我们不是已经有 ALSA 了吗为什么又冒出来一个 Codec因为 ALSA 是软件框架。Codec 通常是音频硬件。Codec 这个名字来自Coder Decoder不过现代音频芯片里的 Codec 通常不只是简单的“编码器/解码器”。它可能集成很多音频功能例如ADC DAC Mixer PGA Mic 输入 Headphone 输出 Speaker 输出所以可以粗略理解CPU ↓ 数字音频 ↓ Codec ↓ 模拟音频 ↓ Speaker而录音则反过来Mic ↓ Codec ↓ 数字音频 ↓ CPUCodec 是后面整个系列非常重要的一部分。十九、那 ASoC 又是从哪里冒出来的恭喜你。到这里我们终于可以稍微提一下下一篇的主角ASoCASoC 全称ALSA System on Chip主要用于 SoC 平台上的音频系统。为什么需要它因为手机、开发板这些设备上的音频硬件往往不是CPU → Speaker这么简单。可能是SoC │ ├── I2S ├── TDM ├── DMA └── DSP │ ↓ Codec │ ├── DAC ├── ADC ├── Mixer └── PGA这里面有 CPU DAI、Codec DAI、Machine Driver、DAPM 等各种东西。ASoC 就是用来把这些东西组织起来的。所以后面我们会看到ALSA ↓ ASoC ├── CPU DAI ├── Codec DAI ├── Machine Driver └── DAPM现在不用急着理解。先知道它是 ALSA 在 SoC 音频场景下的一套组织方式即可。下一篇再拆。二十、现在重新看整条音频链路到了这里我们可以把整个 Linux 播放链路画得稍微完整一点┌──────────────────────┐ │ Application │ └──────────┬───────────┘ ↓ ┌──────────────────────┐ │ ALSA Library │ └──────────┬───────────┘ ↓ ┌──────────────────────┐ │ ALSA PCM │ └──────────┬───────────┘ ↓ ┌──────────────────────┐ │ ALSA Kernel │ └──────────┬───────────┘ ↓ ┌──────────────────────┐ │ ASoC │ └──────────┬───────────┘ ↓ ┌──────────────────────┐ │ Codec Driver │ └──────────┬───────────┘ ↓ ┌──────────────────────┐ │ Codec │ └──────────┬───────────┘ ↓ ┌──────────────────────┐ │ DAC / AMP │ └──────────┬───────────┘ ↓ Speaker注意这是一张用于建立认知的简化图不代表所有平台的实际调用链都完全一样。尤其到了 Android 和 Qualcomm 平台中间还会增加很多组件。二十一、这一篇到底应该记住什么第一篇不要背代码。如果看完之后你能回答下面几个问题就已经达标了。1. PCM 是什么可以先记PCM 是数字音频数据的一种表示方式。2. PCM 最重要的参数有哪些Sample Rate Bit Width Channels也就是采样率 位宽 声道3. ALSA 是什么Linux 的音频架构用来统一管理和访问音频设备。4. aplay 是什么ALSA 相关的用户空间工具用来播放音频、查看播放设备等。5. Codec 是什么音频硬件中的重要组成部分负责 ADC、DAC、Mixer、PGA 等音频处理功能具体能力取决于芯片。6. ASoC 是什么Linux 面向 SoC 音频系统的 ALSA 架构负责把 CPU、Codec 等音频组件组织起来。二十二、把这些东西记成一句话如果现在让你用一句话解释 Linux 音频可以这样说应用程序产生或者消费 PCM 音频数据通过 ALSA 访问 Linux 音频设备再经过 ASoC、Codec 等软硬件组件最终把数字音频转换成我们能听到的声音。虽然这句话还是有点长。那就记这张图PCM ↓ ALSA ↓ ASoC ↓ Codec ↓ Speaker这五个词接下来会一个一个拆开。二十三、下一篇讲什么下一篇我们不继续讲理论。直接上机器。准备几个最常用的 ALSA 命令aplay -l aplay -L arecord -l arecord -L amixer然后搞清楚一个非常关键的问题hw:0,0到底是什么意思接着再写一个最简单的 ALSA PCM 播放程序真正跑一遍snd_pcm_open() snd_pcm_hw_params() snd_pcm_prepare() snd_pcm_writei() snd_pcm_close()到那个时候ALSA 就不再只是一个“听起来很厉害的名词”而是能真正跑起来的东西。而等 ALSA 用户空间这一层搞明白之后我们再进入ALSA Kernel ↓ ASoC ↓ CPU DAI ↓ Codec DAI ↓ DAPM ↓ 设备树最后再一路走到 AndroidAudioTrack ↓ AudioFlinger ↓ Audio Policy ↓ Audio HAL ↓ Qualcomm Audio ↓ ALSA / ASoC ↓ Codec这才是这个系列真正想带你走完的路线。
返回列表