Android_P_Audio_系统(1) — Auido 系统简介

1 音频基础

1.1 声音的三要素

1. 音量(Volume)

也叫做响度(Loudness),人耳对声音强弱的主观感觉就是响度,响度和声波振动的幅度有关。一般说来,声波振动幅度越大则响度也越大。当我们用较大的力量敲鼓时,鼓膜振动的幅度大,发出的声音响;轻轻敲鼓时,鼓膜振动的幅度小,发出的声音弱。

2. 音调(Pitch)

人耳对声音高低的感觉称为音调(也叫音频),音调主要与声波的频率有关。声波的频率高,则音调也高。当我们分别敲击一个小鼓和一个大鼓时,会感觉它们所发出的声音不同。小鼓被敲击后振动频率快,发出的声音比较清脆,即音调较高;而大鼓被敲击后振动频率较慢,发出的声音比较低沉,即音调较低。

一般音调:儿童 > 女生 > 男生

人耳听觉音频范围是 20Hz-20000Hz (若音频压缩时不在这个范围内的数据就可以砍掉)。

3. 音色(Quality)

同一种乐器,使用不同的材质来制作,所表现出来的音色效果是不一样的,这是由物体本身的结构特性所决定的。

音色与声波的振动波形有关,或者说与声音的频谱结构有关。

1.2 音频的量化与编码

日常生活中我们听到的声波波形信号都是时间连续的,我们称这种信号为模拟信号,模拟信号需要量化成数字信号(离散、不连续的)以后才能被我们的计算机识别。音频的量化过程可以简单分为以下 5 个步骤:

Android_P_Audio_系统(1) — Auido 系统简介_第1张图片

1) 模拟信号

现实生活中的声音表现为连续的、平滑的波形,其横坐标为时间轴,纵坐标表示声音的强弱。

2) 采样

按照一定的时间间隔在连续的波上进行采样取值,如下图所示取了 10 个样。

3) 量化

将采样得到的值进行量化处理,也就是给纵坐标定一个刻度,记录下每个采样的纵坐标的值。

4) 编码

将每个量化后的样本值转换成二进制编码,可以看到模拟信号经过采样、量化、编码后形成的二进制序列就是数字音频信号。

5) 数字信号

将所有样本二进制编码连起来存储在计算机上就形成了数字信号。

1.3 量化基本概念

1. 采样位数

每个采样点能够表示的数据范围,用多少个 bit 表示。采样位数通常有 8 bits 或 16 bits 两种,采样位数越大,所能记录声音的变化度就越细腻,相应的数据量就越大。8 位字长量化(低品质)和 16 位字长量化(高品质),16 bit 是最常见的采样精度。

采样位数也被叫做采样精度、量化级、量化数据位数等。

2. 采样率

单位时间内对模拟信号的采样次数,也就是采样频率,采样频率越高,声音的还原就越真实越自然,当然数据量就越大。

我们日常生活中常见的采样率:

  • 5kHz:仅能满足人们讲话的声音质量
  • 8KHz:电话所用采样率, 对于人的说话已经足够
  • 22.05KHz:达到 FM 广播的声音品质(适用于语音和中等品质的音乐)
  • 44.1KHz:最常见的采样率标准,理论上的 CD 音质界限,可以达到很好的听觉效果
  • 48KHz:比 CD 音质更加精确一些

对于高于 48KHz 的采样频率人耳已无法辨别出来了,所以在电脑上没有多少使用价值。

3. 声道数

为了播放声音时能够还原真实的声场,在录制声音时在前后左右几个不同的方位同时获取声音,每个方位的声音就是一个声道。声道数是声音录制时的音源数量或回放时相应的扬声器数量,有单声道、双声道、多声道。

4. 码率

也叫比特率,指每秒传送的数据量,单位为 bps(Bit Per Second),码率代表了压缩质量,码率越高,每秒传送的数据就越多,音质就越好。

公式:
    码率 = 采样率 * 采样位数 * 声道数

例如:
    CD 音质,采样率 44.1KHz,采样位数 16 bit,立体声(双声道)
    码率 = 44.1 * 1000 * 16 * 2 = 1411200 bps = 176400 Bps

根据上面的码率,录制一分钟需要 176400 Bps * 60秒 / 1024 / 1024 = 10.09MB

5. PCM

PCM(Pulse Code Modulation),即脉冲编码调制,对声音进行采样、量化过程,未经过任何编码和压缩处理。

PCM 数据是最原始的音频数据完全无损,所以 PCM 数据虽然音质优秀但体积庞大,为了解决这个问题先后诞生了一系列的音频格式,这些音频格式运用不同的方法对音频数据进行压缩,通常分为无损压缩(ALAC、APE、FLAC)和有损压缩(MP3、AAC、OGG、WMA)两种。

5. 音频帧

音频数据是流式的,本身没有明确的一帧帧的概念,在实际的应用中,为了音频算法处理/传输的方便,一般约定俗成取 2.5ms~60ms 为单位的数据量为一帧音频。这个时间被称之为 “采样时间”,其长度没有特别的标准,它是根据编解码器和具体应用的需求来决定的。

例如最常见的音频格式 MP3 的数据通常由两部分组成,一部分为 “ID3” 用来存储歌名、演唱者、专辑、音轨数
等信息,另一部分为音频数据。音频数据部分以帧(frame)为单位存储,每个音频都有自己的帧头,如下图所示就是一个 MP3 文件帧结构图。

Android_P_Audio_系统(1) — Auido 系统简介_第2张图片

MP3 中的每一帧都有自己的帧头,其中存储了采样率等解码必须的信息,所以每一个帧都可以独立于文件存在和播放,这个特性加上高压缩比使得 MP3 文件成为了音频流播放的主流格式。帧头之后存储着音频数据,这些音频数据是若干个 PCM 数据帧经过压缩算法压缩得到的。

1.4 音频编解码器

常见的音频编解码器包括 OPUS、AAC、Vorbis、Speex、iLBC、AMR、G.711 等。目前泛娱乐化直播系统采用 rtmp 协议,支持 AAC 和 Speex。
性能上来看,OPUS > AAC > Vorbis,其它的逐渐被淘汰。

2 Android Audio 系统框架

Android_P_Audio_系统(1) — Auido 系统简介_第3张图片
Android_P_Audio_系统(1) — Auido 系统简介_第4张图片

2.1 Application

常见的音频相关软件有:音乐播放器、视频播放器、电话、录音软件等等

2.2 Framework

1) framework Java 部分

这部分接口直接提供给 Application 层定制开发 Audio 相关功能,相关代码主要在:

PATH:frameworks/base/media/java/android/media

可供使用的 API 有

  • AudioTrack & AudioRecorder:提供声音播放和录制接口
  • MediaPlayer & MediaRecorder:提供声音播放和录制接口,接口更加通用
  • AudioManager、AudioService & AudioSystem:提供声音控制、通道选择、音效设置等功能

AudioRcorder 和 MediaRecorder 主要用于完成音视频数据的采集,而 AudioTrack 和 MediaPlayer 则负责音频数据的输出。

MediaPlayer 能够播放多种格式的声音文件,比如 MP3、AAC、WAV 等,MediaPlayer 的实现包含了 AudioTrack,而 AudioTrack 因为不创建解码器,仅能播放无须解码的 PCM 流(wav 格式)。

2) framework Native 部分
  1. 客户端:
    包含 Java API 接口 AudioTrack、AudioRecord、MediaPlayer、MediaRecord、AudioSystem 对应的 native 实现。在 Android 9.0 代码中,为了显式的区分客户端和服务端, 这部分实现从 libmedia 中分离出来,编译成一个单独的库 libaudioclient.so,代码路径:

PATH: frameworks/av/media/libaudioclient

  1. 服务端:
    包含 Audio 系统中最核心的 AudioFlinger & AudioPolicyService 实现代码,其中 AudioFlinger 是 Audio 系统的工作引擎,管理着系统中的输入输出音频流,并承担音频数据的混音以及读写 Audio 硬件等工作。而 AudioPolicyService 是 Audio 系统的策略控制中心,掌管系统中声音设备的选择和切换、音量控制等功能。两个功能分别被编译成 libaudioflinger 和 libaudiopolicyservice 库,运行在 AudioServer 系统进程中,通过 binder 跨进程向客户端提供服务。代码路径:

PATH: frameworks/av/services/audioflinger(audiopolicy)

2.3 Audio HAL

从整体设计上看,硬件抽象层是 AudioFlinger 直接访问的对象,厂商会在这一层添加自己的实现,桥接硬件驱动和上层框架。

Android Audio 上层设计框架中与硬件抽象层直接交互的只有 AudioFlinger 和 AudioPolicyService。实际上后者并不是一个真实的设备,只是采用虚拟设备的方式让厂商可以方便地定制自己的策略。抽象层的任务就是提供统一的接口来定义它与 AudioFlinger/AudioPolicyService 之间的通信方式,不论 Audio 系统依赖 ALSA-lib 还是 tinyalsa,都不应该对上层框架造成破坏。下面来介绍 Android Audio Hal 的统一接口设计。

在 Android Audio 系统设计中,无论是上层还是下层都是用一个管理类和输入输出两个类来表示 Audio 系统,输入输出两个类负责数据通道,在各个层级间对应关系:

Audio 管理类 Audio 输入 Audio 输出
Java android.media.AudioSystem android.media.AudioRecord android.media.AudioTrack
native AudioSystem AudioRecord AudioTrack
AudioFlinger IAudioFlinger IAudioRecord IAudioTrack
硬件抽象层 AudioHardwareInterface AudioStreamOut AudioStreamIn

在 Android libhardware_legacy 中定义的音频相关的参考硬件抽象层数据结构:

音频设备描述符:

struct legacy_audio_device {
    struct audio_hw_device device;
    struct AudioHardwareInterface *hwif;
};

音频输入描述符

struct legacy_stream_in {
    struct audio_stream_in stream;
    AudioStreamIn *legacy_in;
};

音频输出描述符:

struct legacy_stream_out {
    struct audio_stream_out stream;
    AudioStreamOut *legacy_out;
};

audio_hw_device 和 AudioHardwareInterface、audio_stream_out 和 AudioStreamOut、audio_stream_in 和 AudioStreamIn 定义的接口基本一致,这是为了兼容 Android 先后版本,下面的分析以 AudioHardwareInterface、AudioStreamIn、AudioStreamOut 作为硬件抽象层音频管理和输入输出结构体定义。

Android_P_Audio_系统(1) — Auido 系统简介_第5张图片

AudioHardwareInterface 负责实现基础类和管理,而 AudioHardwareGeneric.cpp、AudioHardwareStub.cpp、AudioDumpInterface.cpp 和 A2dpAudioInterface.cpp 各自代表一种 Auido 硬件抽象层的实现。

  1. AudioHardwareGeneric:实现基于特定驱动的通用 Audio 硬件抽象层,这是一个真正能够使用的 Audio 硬件抽象层,但是它需要 Android 的一种特殊的声音驱动程序的支持。
  2. AudioHardwareStub:实现 Audio 硬件抽象层的一个桩,这个实现不操作实际的硬件和文件,它所进行的是空操作。
  3. AudioDumpInterface: 实现输出到文件的 Audio 硬件抽象层,支持 Audio 的输出功能,不支持输入功能.
  4. A2dpAudioInterface:实现蓝牙音频的 Audio 硬件抽象层。

2.4 驱动

一般情况下用的 ALSA 音频架构

你可能感兴趣的:(audio)