Android音频系统之音频基础

第1章  音频系统

转载请注明:LXS, http://blog.csdn.net/uiop78uiop78/article/details/8787779


对于一部嵌入式设备来说,除了若干基础功能外(比如手机通话、短信),最重要的可能就是多媒体了——那么一个最简单的问题,什么是多媒体呢?

这个术语对应的英文单词是“Multi-Media”,直译过来就是多媒体。名称就很好地解释了它的含义,我们引用Wikipedia上对其的详细定义:

Multimedia is media and content that uses a combination of differentcontent forms. This contrasts with media that use only rudimentary computerdisplays such as text-only or traditional forms of printed or hand-producedmaterial. Multimedia includes a combination of text, audio, still images,animation, video, or interactivity content forms.

换句话说,多媒体是各种形式的媒体(比如文本、音频、视频、图片、动画等等)的组合。可以说,它是一款产品能否在众多“同质化”严重的市场上脱颖而出的关键。另外,由于不同的产品在音频处理、视频解码等芯片方面或多或少都存在差异,原生态的Android系统不可能覆盖市面上的所有硬件方案,所以这部分功能的移植与二次开发就成了设备研发中的重头戏——当然,Android系统在设计之初就充分考虑到了这点,它提供了一整套灵活的多媒体解决方案,以应对厂商的定制化需求。

对于应用开发人员来说,最熟悉最常用的就是MediaPlayer和MediaRecorder,而深藏在这两个类之间的实现细节却鲜有人知。这也是Android的一大优点——高度封装,让各类开发人员可以把精力放在自己“需要做的事情上”,各司其职,细化分工,从而极大的提高了产品的开发效率。

不过,这种封装也同时带来了一些代价。比如系统异常庞大,各种类定义、C++库、Java封装等等让人目不暇接,这给我们剖析多媒体系统带来了不少障碍。为此,我们特别选取其中的音频实现(其中大部分又以音频回放为主),通过有重点、深入的分析音频系统的实现,来为大家学习Android多媒体系统打开一个缺口。

本章的内容编排是由下而上的,即从最底层的基础知识、框架实现讲起,再逐步扩展延伸到上层应用

·        音频的基础知识

理解音频的一些基础知识,对于我们分析整个音频系统是大有裨益的。它可以让我们从实现的层面去思考,音频系统的目的是什么,然后才是怎么样去完成这个目的

·        AudioFlinger、AudioPolicyService和AudioTrack/AudioRecorder

抛开MediaPlayer、MediaRecorder这些与应用开发直接关联的部分,整个音频系统的核心就是由这三者构建而成的。其中前两个都是System Service,驻留在mediaserver进程中,不断地处理AudioTrack/AudioRecorder的请求。音频的回放和录制从大的流程上看都是相似的,所以我们侧重于对AudioTrack的分析

·        音频的数据流

数据流处理是音频系统管理的一大重点和难点,至少有如下几点是需要充分考虑的:

Ø 如何决定音频流的路径

通常一台设备会有多种音频设备,而且同一时间内系统也很可能会播放多种音频,我们需要将这些音频流与对应的设备建立关联,并做好全局管理

Ø 如何保证音频流以有效的速度传输到音频设备

显然,数据太快或者太慢都会是缺陷

Ø 跨进程的数据传递

举个例子,从Apk应用程序创建一个MediaPlayer,到音频真正从设备中回放出来,这个过程涉及到多个进程间的通信,如何在这些进程间做好数据传递,也是我们所关心的

·        音频系统的上层建筑

在理解了音频系统的实现核心后,我们再从上层应用的角度来思考,相信会有不一样的收获

 

1.1 音频基础

1.1.1 声波

从物理学的角度来说,声波是机械波的一种。

机械波(MechanicalWave)是由机械振荡产生的,它的传播需要介质的支持。它有如下特点:

l 介质本身并不会随着机械波不断地前进

比如我们抖动一条绳子产生的绳波,绳子上的某个点只是在一定范围内做上下运动,没有因为波的传递而脱离绳子。因而机械波是能量的传递,而不是质量的传递

l 在不同的介质中,传播速度是不一样的

 

那么,作为机械波的一种,声音有哪些重要属性呢?

l 响度(Loudness)

响度就是人类可以感知到的各种声音的大小,也就是音量。响度与声波的振幅有直接关系——理论上振幅越大,响度也就越大

l 音调(Pitch)

我们常说某人唱高音很好,或者低音很棒,这就是音调。音调与声音的频率有关系——当声音的频率越大时,人耳所感知到的音调就越高,否则就越低

l 音色(Quality)

同一种乐器,使用不同的材质来制作,所表现出来的音色效果是不一样的,这是由物体本身的结构特性所决定的——它直接影响了声音的音色属性。同样的道理,不同的演唱者因为他们的发声部位有差异,所以才造就了更种嗓音特色的音乐才子

 

声音的这几个属性,是所有音频效果处理的基础。任何对音频的调整都将反应到这些属性上,在我们分析源码时可以结合起来思考。

1.1.2 音频的录制、存储与回放

上面的多媒体定义还从侧面反映出一个结论,即Multi-Media并不是专门为计算机而生的——只不过后者的出现极大地推动了它的发展。那么和传统的多媒体相比,计算机领域的多媒体系统,会有哪些区别呢?

一个很显然的问题是,我们如何将各种媒体源数字化呢?比如,早期的音频信息是存储在录音带中的,以模拟信号的形式存储。而到了计算机时代,这些音频数据必须通过一定的处理手段才可能存储到设备中,这是我们在数字化时代会遇到的一个常见问题。下面这个图很好地描述了音频从录制到播放的一系列操作流程:


Android音频系统之音频基础_第1张图片

图 13‑1 音频的录制、存储和回放

引用自http://en.wikipedia.org/wiki/File:A-D-A_Flow.svg

 

录制过程

·        首先,音频采集设备(比如Microphone)捕获声音信息,初始数据是模拟信号

·        模拟信号通过模-数转换器(ADC)处理成计算机能接受的二进制数据

·        上一步得到的数据根据需求进行必要的渲染处理,比如音效调整、过滤等等

·        处理后的音频数据理论上已经可以存储到计算机设备中了,比如硬盘、USB设备等等。不过由于这时的音频数据体积相对庞大,不利于保存和传输,通常还会对其进行压缩处理。比如我们常见的mp3音乐,实际上就是对原始数据采用相应的压缩算法后得到的。压缩过程根据采样率、位深等因素的不同,最终得到的音频文件可能会有一定程度的失真

另外,音视频的编解码既可以由纯软件完成,也同样可以借助于专门的硬件芯片来完成

 

回放过程

回放过程总体上是录制过程的逆向操作。

l 从存储设备中取出相关文件,并根据录制过程采用的编码方式进行相应的解码

l 音频系统为这一播放实例选定最终匹配的音频回放设备

l 解码后的数据经过音频系统设计的路径传输

l 音频数据信号通过数模转换器(DAC)变换成模拟信号

l 模拟信号经过回放设备,还原出原始声音

 

本章着重讲解的是音频“回放过程”。

1.1.3 音频采样

前面我们说过,数字音频系统需要将声波波形信号通过ADC转换成计算机支持的二进制,进而保存成音频文件,这一过程叫做音频采样(Audio Sampling)。音频采样是众多数字信号处理的一种,它们的基本原理都是类似的(比如视频的采样和音频采样本质上也没有太大区别)。

可想而知,采样(Sampling)的核心是把连续的模拟信号转换成离散的数字信号。它涉及到如下几点:

l 样本(Sample)

这是我们进行采样的初始资料,比如一段连续的声音波形

l 采样器(Sampler)

采样器是将样本转换成终态信号的关键。它可以是一个子系统,也可以指一个操作过程,甚至是一个算法,取决于不同的信号处理场景。理想的采样器要求尽可能不产生信号失真

l 量化(Quantization)

采样后的值还需要通过量化,也就是将连续值近似为某个范围内有限多个离散值的处理过程。因为原始数据是模拟的连续信号,而数字信号则是离散的,它的表达范围是有限的,所以量化是必不可少的一个步骤

l 编码(Coding)

计算机的世界里,所有数值都是用二进制表示的,因而我们还需要把量化值进行二进制编码。这一步通常与量化同时进行

 

整个流程如下图所示:

Android音频系统之音频基础_第2张图片

 图 13‑2  PCM流程

 

PCM(Pulse-code modulation)俗称脉冲编码调制,是将模拟信号数字化的一种经典方式,得到了非常广泛的应用。比如数字音频在计算机、DVD以及数字电话等系统中的标准格式采用的就是PCM。它的基本原理就是我们上面的几个流程,即对原始模拟信号进行抽样、量化和编码,从而产生PCM流。另外,我们可以调整PCM的以下属性来达到不同的采样需求:

l 采样速率(Sampling Rate)

在将连续信号转化成离散信号时,就涉及到采样周期的选择。如果采样周期太长,虽然文件大小得到控制,但采样后得到的信息很可能无法准确表达原始信息;反之,如果采样的频率过快,则最终产生的数据量会大幅增加,这两种情况都是我们不愿意看到的,因而需要根据实际情况来选择合适的采样速率。

由于人耳所能辨识的声音范围是20-20KHZ,所以人们一般都选用44.1KHZ(CD)、48KHZ或者96KHZ来做为采样速率

l 采样深度(Bit Depth)

我们知道量化(Quantization)是将连续值近似为某个范围内有限多个离散值的处理过程。那么这个范围的宽度以及可用离散值的数量会直接影响到音频采样的准确性,这就是采样深度的意义

Android音频系统之音频基础_第3张图片

图 13‑3 采用4-bit深度的PCM,引自Wikipedia

 

比如上图是一个采用4位深度进行量化得到的PCM。因为4bit最多只能表达16个数值(0-15),所以图中最终量化后的数值依次为7、9、11、12、13、14、15等等。这样的结果显然是相对粗糙的,存在一定程度的失真。当位深越大,所能表达的数值范围越广,上图中纵坐标的划分也就越细致,从而使得量化的值越接近原始数据。

1.1.4 Nyquist–Shannon采样定律

由Harry Nyquist和Claude Shannon总结出来的采样规律,为我们选择合适的采样频率提供了理论依据。这个规律又被称为“Nyquist sampling theorem”或者“The sampling theorem”,中文通常译为“奈奎斯特采样理论”。它的中心思想是:

“当对被采样的模拟信号进行还原时,其最高频率只有采样频率的一半”。

换句话说,如果我们要完整重构原始的模拟信号,则采样频率就必须是它的两倍以上。比如人的声音范围是20-20kHZ,那么选择的采样频率就应该在40kHZ左右,数值太小则声音将产生失真现象,而数值太大也无法明显提升人耳所能感知的音质。

1.1.5 声道和立体声

我们在日常生活中会经常听到单声道、双声道这些专业词语,那么它们代表什么意思呢?

一个声道(AudioChannel),简单来讲就代表了一种独立的音频信号,所以双声道理论上就是两种独立音频信号的混合。具体而言,如果我们在录制声音时在不同空间位置放置两套采集设备(或者一套设备多个采集头),就可以录制两个声道的音频数据了。后期对采集到的声音进行回放时,通过与录制时相同数量的外放扬声器来分别播放各声道的音频,就可以尽可能还原出录制现场的真实声音了。

声道的数量发展经历了几个重要阶段,分别是:

l Monaural (单声道)

早期的音频录制是单声道的,它只记录一种音源,所以在处理上相对简单。播放时理论上也只要一个扬声器就可以了——即便有多个扬声器,它们的信号源也是一样的,起不到很好的效果

l Stereophonic(立体声)

之所以称为立体声,是因为人们可以感受到声音所产生的空间感。大自然中的声音就是立体的,比如办公室里键盘敲击声,马路上汽车鸣笛,人们的说话声等等。那么这些声音为什么会产生立体感呢?

我们知道,当音源发声后(比如你右前方有人在讲话),音频信号将分别先后到达人类的双耳。在这个场景中,是先传递到右耳然后左耳,并且右边的声音比左边稍强。这种细微的差别通过大脑处理后,我们就可以判断出声源的方位了。

这个原理现在被应用到了多种场合。在音乐会的录制现场,如果我们只使用单声道采集,那么后期回放时所有的音乐器材都会从一个点出来;反之,如果能把现场各方位的声音单独记录下来,并在播放时模拟当时的场景,那么就可以营造出音乐会的逼真氛围。

为了加深大家的理解,我们特别从某双声道音频文件中提取出它的波形:

Android音频系统之音频基础_第4张图片

图 13‑4 双声道音频文件

 

顺便以这个图为例子再说一下音频的采样频率。我们把上图进行放大,如下所示:

Android音频系统之音频基础_第5张图片

图 13‑5 采样频率实例

 

图上共有三个采样点,时间间隔是从4:26.790863到4:26.790908左右,也就是说在大约0.000045秒的时间里采集了两个点,因而采样频率就是:

1/(0.000045/2)=44kHZ,这和此音频文件所标记的采样率是一致的

l 4.1 Surround Sound(4.1环绕立体声)

随着技术的发展和人们认知的提高,单纯的双声道已不能满足需求了,于是更多的声道数逐渐成为主流,其中被广泛采用的就有四声道环绕立体声。

其中的“4”代表了四个音源,位置分别是前左(Front-Left)、前右(Front-Right)、后左(Rear-Left)、后右(Rear-Right)。而小数点后面的1,则代表了一个低音喇叭(Subwoofer),专门用于加强低频信号效果

l 5.1 Surround Sound(5.1环绕立体声)

相信大家都听过杜比数字技术,这是众多5.1环绕声中的典型代表。另外还有比如DTS、SDDS等都属于5.1技术。5.1相对于4.1多了一个声道,位置排列分别是前左、前右、中置(Center Channel)和两个Surround Channel,外加一个低音喇叭。

根据ITU(InternationalTelecommunication Union)的建议,5.1环绕技术各扬声器位置图如下所示:

Android音频系统之音频基础_第6张图片

 

图 13‑6  ITU发布的5.1环绕技术推荐方位图

 

即:

l 各扬声器和听者距离是一致的,因而组成一个圆形

l 角度分布:前左和前右分别是+22.5/-22.5度(看电影时),以及+30/-30度(听音乐时);中置总是为0度;后面的两个环绕器分别为+110/-110度

1.1.6 Weber–Fechner law

估计知道这个定律的人比较少,它是音频系统中计算声音大小的一个重要依据。从严格意义上讲,它并不只适用于声音感知,而是人体各种感观(听觉、视觉、触觉)与刺激物理量之间的一条综合规律。其中心思想用公式表达就是:

△I/I=C

其中△I表示差别阈值,I是原先的刺激量,而C则是常量。换句话说,就是能引起感观变化的刺激差别量与原先的刺激量比值是固定的。这样子说可能比较抽象,我们举个例子来说。

场合1. 去商店买一瓶水,原本2块钱的东西卖到了5块钱

场合2. 买一辆奔驰车,原先价格是一百万,现在涨了3块钱

这两种场景下,前后的价格虽然都是相差3元,但对我们造成的主观感受是有很大不同的。显然在第一种情况下,我们会觉得很贵而可能选择不买;而后者则对我们基本不会产生任何影响。这是因为引起感观变化的刺激量并不单单取决于前后变化量的绝对差值,同时也与原来的刺激量有很大关系。对于特定的场合,上述公式中的C值是固定的。比如有的人觉得2块钱的东西卖3元就是贵了,有的人则能接受2块钱的东西卖4块,对于不同的人C值是会有差异的。

这就是德国心理物理学家ErnstHeinrich Weber发现的规律,后来的学生GustavFechner把这一发现系统地用公式表达出来,就是上述公式所表达的韦伯定律。

后来,Fechner在此基础上又做了改进。他提出刺激量和感知是呈对数关系的,即当刺激强度以几何级数增长时,感知强度则以算术级数增加。这就是Weber–Fechner law,如下公式所示:

SC log R

那么这对音频系统有什么指导意义呢?

我们知道,系统音量是可调的,比如分为0-20个等级。这些等级又分别对应不同的输出电平值,那么我们如何确定每一个等级下应该设置的具体电平值呢?你可能会想到平均分配。没错,这的确是一种方法,只不过按照这样的算法所输出的音频效果在用户听来并不是最佳的,因为声音的变化不连续。

一个更好的方案就是遵循Weber–Fechnerlaw,而采用对数的方法。在Android系统中,这一部分计算具体的实现代码在audiosystem.cpp文件中,大家有兴趣的话可以自行阅读了解下。

1.1.7 音频的几种文件格式

前面小节我们分析了音频采样的基本过程,它将连续的声音波形转换成为若干范围内的离散数值,从而将音频数据用二进制的形式在计算机系统中表示。不过音频的处理并没有结束,我们通常还需要对上述过程产生的数据进行格式转化,然后才最终存储到设备中。

要特别注意文件格式(FileFormat)和文件编码器(Codec)的区别。编码器负责将原始数据进行一定的前期处理,比如压缩算法以减小体积,然后才以某种特定的文件格式进行保存。Codec和File Format不一定是一对一的关系,比如常见的AVI就支持多种音频和视频编码方式。本小节所讲述的以文件格式为主。

我们把数字音频格式分为以下几种:

l  不压缩的格式(UnCompressed Audio Format)

比如前面所提到的PCM数据,就是采样后得到的未经压缩的数据。PCM数据在Windows和Mac系统上通常分别以wav和aiff后缀进行存储。可想而知,这样的文件大小是比较可观的

l 无损压缩格式(Lossless Compressed Audio Format)

这种压缩的前提是不破坏音频信息,也就是说后期可以完整还原出原始数据。同时它在一定程度上可以减小文件体积。比如FLAC、APE(Monkey’sAudio)、WV(WavPack)、m4a(Apple Lossless)等等

l 有损压缩格式(Lossy Compressed Audio Format)

无损压缩技术能减小的文件体积相对有限,因而在满足一定音质要求的情况下,我们还可以进行有损压缩。其中最为人熟知的当然是mp3格式,另外还有iTunes上使用的AAC,这些格式通常可以指定压缩的比率——比率越大,文件体积越小,但效果也越差

 

至于采用哪一种格式,通常要视具体的使用场景而定。

你可能感兴趣的:(android,frameworks)