Android音频系统

1 音频基础

1.1 声波

从物理学的角度来说,声波是机械波的一种,是由空气振荡产生的。

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

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

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

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

作为机械波的一种,声波有以下重要属性:

a 响度(Loudness)

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

b 音调(Pitch)

某人唱高音很好,或者低音很棒,所谓的高音低音就是音调的高低。音调与声波的频率有关,频率越高,音调越高。

c 音色(Quality)

同一种乐器,使用不同的材质来制作,所表现出来的音色效果是不一样的,这是由物体本身的结构特性所决定的——它直接影响了声波的音色属性。同理,每个人的喉咙不一样,音色也就不一样了。

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

图 1.2 音频的录制、存储和回放

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

录制过程:

a 音频采集设备(如Microphone)捕获声波,处理成模拟信号,通过电压传递到模数转换器(ADC)。

b 模数转换器将模拟信号转换成数字信号。

c 数字处理器对数字信号进行效果、过滤、转换等渲染处理,得到二进制数据。

d  渲染处理后的音频数据理论上已经可以存储到计算机设备中了,比如硬盘、USB设备等。由于原始音频数据相对庞大,不利于保存和传输,通常还需要压缩处理。比如mp3格式的音频文件,是对原始数据采用相应的压缩算法后得到的。压缩后的音频文件可能会有一定程度的失真。

e 将音频数据编码后存储到计算机设备中。

回放过程:

a 从存储设备中取出相关音频文件。

b 数字处理器根据录制过程采用的编码方式进行相应的解码。

c 将数字信号传递到数模转换器(DAC)。

b 数模转换器将数字信号转换成模拟信号。

e 通过电压将模拟信号传递到音频回放设备(如扬声器Speaker),经过处理,产生声波。

1.3 音频文件格式

不压缩格式:

直接以PCM(Pulse-code modulation)脉冲编码调制的数据保存的音频文件是未压缩的,文件是比较大的,格式有wav,aiff

无损压缩格式:

无损压缩不破坏音频信息,可还原出原始数据,不失真,比不压缩的文件小。格式有flac,ape,wv,m4a等。

有损压缩格式:

有损压缩的文件比较小,但是会破坏音频信息,会失真,压缩的越小,播放出来的效果会越差。格式有mp3,aac等。

2 音频框架

2.1 OSS (Open Sound System)

早期Linux版本采用的是OSS框架,它也是Unix及类Unix系统中广泛使用的一种音频体系OSS既可以指OSS接口本身,也可以用来表示接口的实现。由于涉及到知识产权问题,OSS后期的支持与改善不是很好,这也是Linux内核最终放弃OSS的一个原因。另外,OSS在某些方面遭到质疑,比如对新音频特性的支持不足,缺乏对最新内核特性的支持等等。当然,OSS做为Unix下统一音频处理操作的早期实现,本身算是比较成功的。它符合“一切都是文件”的设计理念,而且做为一种体系框架,其更多地只是规定了应用程序与操作系统音频驱动间的交互,各个系统可以根据实际的需求进行定制开发。

2.2 ALSA (Advanced Linux Sound Architecture)

ALSA是Linux社区为了取代OSS而提出的一种框架,是一个源代码完全开放的系统(遵循GNU GPL和GNU LGPL)。ALSA在Kernel 2.5版本中被正式引入后,OSS就逐步被排除在内核之外。当然,OSS本身还是在不断维护的,只是不再为Kernel所采用而已。

ALSA相对于OSS提供了更多,也更为复杂的API接口,因而开发难度相对来讲加大了一些。为此,ALSA专门提供了一个供开发者使用的工具库,以便于使用ALSA的API。

ALSA有以下特性:

a 高效支持大多数类型的audio interface(不论是消费型或者是专业型的多声道声卡)。

b 高度模块化的声音驱动。

c 采用了SMP(Symmetrical Multi-Processing,对称多处理)及线程安全(thread-safe)设计 。

d 在用户空间提供了alsa-lib来简化应用程序的编写。

2.3 TinyAlsa

TinyAlsa是ALSA的缩减版本,在Android系统的其它地方也可以看到类似的做法——既想用开源项目,又嫌工程太大太繁琐,那就只能瘦身了,于是很多Tiny-XXX就出现了。

在早期版本中,Android系统的音频架构主要是基于ALSA的,其上层实现可以看做是ALSA的一种“应用”。后来可能是由于ALSA所存在的一些不足,Android后期版本开始不再依赖于ALSA提供的用户空间层的实现,因此在它的库文件夹中已经找不到alsa相关的lib了,而取代它的是tinyalsa相关的库文件。

2.4 Android音频框架

图 2.4 Android音频系统框架

引用自https://blog.csdn.net/xuesen_lin/article/details/8796492

Application应用层

Music,Recorder,Call,Game等涉及音频播放或录制的应用。

Application Framework应用框架层

MediaPlayer和MediaRecorder是开发音频相关产品时使用最广泛的两个类。Android也提供了另两个相似功能的类,即AudioTrack和AudioRecorder,MediaPlayerService内部的实现就是通过它们来完成的。此外,Android还为管理控制音频系统提供了AudioManager、AudioService及AudioSystem类。

Libraries本地库层

framework层的很多类,实际上只是应用程序使用Android库文件的“中介”而已。因为上层应用采用java语言编写,需要java接口的支持,这就是framework层存在的意义之一。而作为“中介”,并不会真正去实现具体的功能,或者只实现其中的一部分功能,而把主要重心放在库中来完成。比如上面的AudioTrack、AudioRecorder、MediaPlayer和MediaRecorder等在库中都能找到相对应的类。这一部分代码集中放置在frameworks/av/media/libmedia中,多数是C++语言编写的。

音频系统的“核心中控”是AudioFlinger和AudioPolicyService,其代码放置在frameworks/av/services/audioflinger,生成的最主要的库叫做libaudioflinger。

音频体系中另一个重要的系统服务是MediaPlayerService,位置在frameworks/av/media/libmediaplayerservice。

AudioPolicyService和AudioFlinger等在libaudioflinger库中,AudioTrack、AudioRecorder等在libmedia库中。

库并不代表一个进程,进程则依赖于库来运行。虽然有的类是在同一个库中实现的,但并不代表它们会在同一个进程中被调用。AudioFlinger和AudioPolicyService驻留于名为mediaserver的系统进程中,AudioTrack/AudioRecorder和MediaPlayer/MediaRecorder实际上只是应用进程的一部分,通过binder来与其它系统进程通信。

HAL硬件抽象层

Hardware Abstraction Layer,硬件抽象层是位于操作系统内核与硬件电路之间的接口层,其目的在于将硬件抽象化。从设计上来看,AudioFlinger直接访问HAL。这说明了两个问题,一方面AudioFlinger并不直接调用底层的驱动程序;另一方面,AudioFlinger上层(包括和它同一层的MediaPlayerService)的模块只需要与它进行交互就可以实现音频相关的功能了。可认为AudioFlinger是Android音频系统中真正的“隔离板”,无论下层如何变化,上层的实现都可以保持兼容。

音频方面的硬件抽象层主要分为两部分,即AudioFlinger和AudioPolicyService。实际上后者并不是一个真实的设备,只是采用虚拟设备的方式来让厂商可以方便地定制出自己的策略。

HAL的任务是将AudioFlinger/AudioPolicyService真正地与硬件设备关联起来,但又必须提供灵活的结构来应对变化——特别是对于Android这个更新相当频繁的系统。比如以前Android系统中的Audio系统依赖于ALSA,但后期就变为了TinyAlsa。这样的转变不应该对上层造成破坏,因而Audio HAL提供了统一的接口来定义它与AudioFlinger/AudioPolicyService之间的通信方式,这就是audio_hw_device、audio_stream_in及audio_stream_out等存在的目的,这些Struct数据类型内部大多只是函数指针的定义,是一些“壳”。当AudioFlinger/AudioPolicyService初始化时,它们会去寻找系统中最匹配的实现(这些实现驻留在以audio.primary.*,audio.a2dp.*为名的各种库中)来填充这些“壳”。

根据产品的不同,音频设备存在很大差异,在Android的音频架构中,这些问题是由HAL的audio.primary等库来解决的,而不需要大规模地修改上层实现。换句话说,厂商在定制时的重点就是如何提供这部分库的高效实现了。

参考:

https://blog.csdn.net/xuesen_lin/article/details/8787779

https://blog.csdn.net/xuesen_lin/article/details/8796492

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值