本章介绍Android的音频系统内容,主要是音频的输入/输出环节,不涉及编解码的内容(音频系统从驱动程序、本地框架到Java框架都具有内容)。本章介绍Audio系统各个层次的内容、Audio硬件抽象层的实现。
在学习本章的过程中,读者应重点关注以下内容:
Audio系统结构(知识性内容)
在Java中调用Audio系统的方式(知识性内容)
Audio系统本地代码的接口(开发要点)
Audio硬件抽象层的实现(开发要点)
7.1 Audio系统综述
Audio系统在Android中负责音频方面的数据流传输和控制功能,也负责音频设备的管理。这个部分作为Android的Audio系统的输入/输出层次,一般负责播放PCM声音输出和从外部获取PCM声音,以及管理声音设备和设置。
Audio系统主要分成如下几个层次:
(1)media库提供的Audio系统本地部分接口;
(2)AudioFlinger作为Audio系统的中间层;
(3)Audio的硬件抽象层提供底层支持;
(4)Audio接口通过JNI和Java框架提供给上层。
Audio系统的各个层次接口主要提供了两方面功能:放音(Track)和录音(Recorder)。
Android的Audio系统结构如图7-1所示。
图7-1 Android的Audio系统结构
Android系统的代码分布情况如下所示:
(1)Audio的Java部分
代码路径:frameworks/base/media/java/android/media
与Audio相关的Java包是android.media,主要包含AudioManager和Audio系统的几个类。
(2)Audio的JNI部分
代码路径:frameworks/base/core/jni
生成库libandroid_runtime.so,Audio的JNI是其中的一个部分。
(3)Audio的框架部分
头文件路径:frameworks/base/include/media/
源代码路径:frameworks/base/media/libmedia/
Audio本地框架是media库的一部分,本部分内容被编译成库libmedia.so,提供Audio部分的接口(包括基于Binder的IPC机制)。
(4)Audio Flinger
代码路径:frameworks/base/libs/audioflinger
这部分内容被编译成库libaudioflinger.so,它是Audio系统的本地服务部分。
(5)Audio的硬件抽象层接口
头文件路径:hardware/libhardware_legacy/include/hardware/
Audio硬件抽象层的实现在各个系统中可能是不同的,需要使用代码去继承相应的类并实现它们,作为Android系统本地框架层和驱动程序接口。
7.2 Audio系统和上层接口
在Android中,Audio系统自上而下由Java的Audio类、Audio本地框架类、AudioFlinger和Audio的硬件抽象层几个部分组成。
7.2.1 Audio系统的各个层次
Audio系统的各层次情况如下所示。
Audio本地框架类是libmedia.so的一个部分,这些Audio接口对上层提供接口,由下层的本地代码去实现。
AudioFlinger继承libmeida中的接口,提供实现库libaudiofilnger.so。这部分内容没有自己的对外头文件,上层调用的只是libmedia本部分的接口,但实际调用的内容是libaudioflinger.so。
Audio使用JNI和Java对上层提供接口,JNI部分通过调用libmedia库提供的接口来实现。
Audio的硬件抽象层提供到硬件的接口,供AudioFlinger调用。Audio的硬件抽象层实际上是各个平台开发过程中需要主要关注和独立完成的部分。
提示:Android的Audio系统不涉及编解码环节,只是负责上层系统和底层Audio硬件的交互,一般以PCM作为输入/输出格式。
在Android的Audio系统中,无论上层还是下层,都使用一个管理类和输出输入两个类来表示整个Audio系统,输出输入两个类负责数据通道。在各个层次之间具有对应关系,如表7-1所示所示。
表7-1 Android各个层次的对应关系
|
Audio管理环节 |
Audio输出 |
Audio输入 |
Java层 |
android.media.AudioSystem |
android.media.AudioTrack |
android.media.AudioRecorder |
本地框架层 |
AudioSystem |
AudioTrack |
AudioRecorder |
AudioFlinger |
IAudioFlinger |
IAudioTrack |
IAudioRecorder |
硬件抽象层 |
AudioHardwareInterface |
AudioStreamOut |
AudioStreamIn |
7.2.2 media库中的Audio框架部分
Android的Audio系统的核心框架在media库中提供,对上面主要实现AudioSystem、AudioTrack和AudioRecorder三个类。
提供了IAudioFlinger类接口,在这个类中,可以获得IAudioTrack和IAudioRecorder两个接口,分别用于声音的播放和录制。AudioTrack和AudioRecorder分别通过调用IAudioTrack和IAudioRecorder来实现。
Audio系统的头文件在frameworks/base/include/media/目录中,主要的头文件如下:
AudioSystem.h:media库的Audio部分对上层的总管接口;
IAudioFlinger.h:需要下层实现的总管接口;
AudioTrack.h:放音部分对上接口;
IAudioTrack.h:放音部分需要下层实现的接口;
AudioRecorder.h:录音部分对上接口;
IAudioRecorder.h:录音部分需要下层实现的接口。
IAudioFlinger.h、IAudioTrack.h和IAudioRecorder.h这三个接口通过下层的继承来实现(即 AudioFlinger)。AudioFlinger.h、AudioTrack.h和AudioRecorder.h是对上层提供的接口,它们既供本地程序调用(例如声音的播放器、录制器等),也可以通过JNI向Java层提供接口。
meida库中Audio部分的结构如图7-2所示。
图7-2 meida库中Audio部分的结构
从功能上看,AudioSystem负责的是Audio系统的综合管理功能,而AudioTrack和AudioRecorder分别负责音频数据的输出和输入,即播放和录制。
AudioSystem.h中主要定义了一些枚举值和set/get等一系列接口
在Audio系统的几个枚举值中,audio_routes是由单独的位来表示的,而不是由顺序的枚举值表示,因此这个值在使用过程中可以使用" 或"的方式。例如,表示声音可以既从耳机(EARPIECE)输出,也从扬声器(SPEAKER)输出,这样是否能实现,由下层提供支持。在这个类中,set/get等接口控制的也是相关的内容,例如Audio声音的大小、Audio的模式、路径等。
AudioTrack是Audio输出环节的类,其中最重要的接口是write()
AudioRecord是Audio输入环节的类,其中最重要的接口为read()
AudioTrack和AudioRecord的read/write函数的参数都是内存的指针及其大小,内存中的内容一般表示的是Audio的原始数据(PCM数据)。这两个类还涉及Auido数据格式、通道数、帧数目等参数,可以在建立时指定,也可以在建立之后使用set()函数进行设置。
在libmedia库中提供的只是一个Audio系统框架,AudioSystem、 AudioTrack和AudioRecord分别调用下层的IAudioFlinger、IAudioTrack和IAudioRecord来实现。另外的一个接口是IAudioFlingerClient,它作为向IAudioFlinger中注册的监听器,相当于使用回调函数获取 IAudioFlinger运行时信息。
7.2.3 AudioFlinger本地代码
AudioFlinger是Audio系统的中间层,在系统中起到服务作用,它主要作为libmedia提供的Audio部分接口的实现,其代码路径为:frameworks/base/libs/audioflinger
AudioFlinger的核心文件是AudioFlinger.h和AudioFlinger.cpp,提供了类AudioFlinger,这个类是一个IAudioFlinger的实现
AudioFlinger主要提供createTrack()创建音频的输出设备IAudioTrack,openRecord()创建音频的输入设备IAudioRecord。另外包含的就是一个get/set接口,用于控制。
从工作的角度看,AudioFlinger在初始化之后,首先获得放音设备,然后为混音器(Mixer)建立线程,接着建立放音设备线程,在线程中获得放音设备。
在AudioFlinger的AudioResampler.h中定义了一个音频重取样器工具类,这个音频重取样工具包含3种质量:低等质量(LOW_QUALITY)将使用线性差值算法实现;中等质量(MED_QUALITY)将使用立方差值算法实现;高等质量(HIGH_ QUALITY)将使用FIR(有限阶滤波器)实现。AudioResampler中的AudioResamplerOrder1是线性实现,AudioResamplerCubic.*文件提供立方实现方式,AudioResamplerSinc.*提供FIR实现。
AudioMixer.h和AudioMixer.cpp中实现的是一个Audio系统混音器,它被AudioFlinger调用,一般用于在声音输出之前的处理,提供多通道处理、声音缩放、重取样。AudioMixer调用了AudioResampler。
提示: AudioFlinger本身的实现通过调用下层的Audio硬件抽象层的接口来实现具体的功能,各个接口之间具有对应关系。
7.2.4 Audio系统的JNI代码
Android的Audio部分通过JNI向Java层提供接口,在Java层可以通过JNI接口完成Audio系统的大部分操作。Audio JNI部分的代码路径为:frameworks/base/core/jni。
其中,主要实现的3个文件为:android_media_AudioSystem.cpp、android_media_Audio Track.cpp和android_media_AudioRecord.cpp,它们分别对应了Android Java框架中的3个类的支持:
android.media.AudioSystem:负责Audio系统的总体控制;
android.media.AudioTrack:负责Audio系统的输出环节;
android.media.AudioRecorder:负责Audio系统的输入环节。
在Android的Java层中,可以对Audio系统进行控制和数据流操作,对于控制操作,和底层的处理基本一致;但是对于数据流操作,由于Java不支持指针,因此接口被封装成了另外的形式。
向Java提供native_write_byte和native_write_short接口,它们一般是通过调用AudioTrack的write()函数来完成的,只是在Java的数据类型和C++的指针中做了一步转换。
7.2.5 Audio系统的Java代码
Android的Audio系统的相关类在android.media 包中,Java部分的代码路径为:
frameworks/base/media/java/android/media
Audio系统主要实现了以下几个类:android.media.AudioSystem、android.media. AudioTrack、android.media.AudioRecorder、android.media.AudioFormat。前面的3个类和本地代码是对应的,AudioFormat提供了一些Audio相关类型的枚举值。
注意:在Audio系统的Java代码中,虽然可以通过AudioTrack和AudioRecorder的write()和read()接口,在 Java层对Audio的数据流进行操作。但是,更多的时候并不需要这样做,而是在本地代码中直接调用接口进行数据流的输入/输出,而Java层只进行控制类操作,不处理数据流。
7.3 Audio的硬件抽象层
7.3.1 Audio硬件抽象层的接口定义
Audio的硬件抽象层是AudioFlinger和Audio硬件的接口,在各个系统的移植过程中可以有不同的实现方式。Audio硬件抽象层的接口路径为:
hardware/libhardware_legacy/include/hardware/
其中主要的文件为:AudioHardwareBase.h和AudioHardwareInterface.h。
Android中的Audio硬件抽象层可以基于Linux标准的ALSA或OSS音频驱动实现,也可以基于私有的Audio驱动接口来实现。
在AudioHardwareInterface.h中定义了类:AudioStreamOut、AudioStreamIn和AudioHardwareInterface。AudioStreamOut和AudioStreamIn分别对应了音频的输出环节和输入环节,其中负责数据流的接口分别是wirte()和read(),参数是一块内存的指针和长度;另外还有一些设置和获取接口。在这个AudioHardwareInterface接口中,使用openOutputStream()和openInputStream()函数分别获取AudioStreamOut和AudioStreamIn两个类,它们作为音频输入/输出设备来使用。此外,AudioHardwareInterface.h定义了C语言的接口来获取一个AudioHardware Interface类型的指针。
extern "C" AudioHardwareInterface* createAudioHardware(void);
如果实现一个Android的硬件抽象层,则需要实现AudioHardwareInterface、AudioStream Out和AudioStreamIn三个类,将代码编译成动态库libauido.so。AudioFlinger会连接这个动态库,并调用其中的 createAudioHardware()函数来获取接口。
在AudioHardwareBase.h中定义了类:AudioHardwareBase,它继承了Audio HardwareInterface,显然继承这个接口也可以实现Audio的硬件抽象层。
提示:Android系统的Audio硬件抽象层可以通过继承类AudioHardwareInterface来实现,其中分为控制部分和输入/输出处理部分。
7.3.2 AudioFlinger中自带Audio硬件抽象层实现
在AudioFlinger中可以通过编译宏的方式选择使用哪一个Audio硬件抽象层。这些Audio硬件抽象层既可以作为参考设计,也可以在没有实际的Audio硬件抽象层(甚至没有Audio设备)时使用,以保证系统的正常运行。AudioDumpInterface.h和AudioDumpInterface.cpp是一个提供了Dump功能的Audio硬件抽象层,它所起到的作用就是将输出的Audio数据写入到文件中。AudioDumpInterface并不是为了实际的应用使用的,而是为了调试使用的类。当进行音频播放器调试时,有时无法确认是解码器的问题还是Audio输出单元的问题,这时就可以用这个类来替换实际的Audio硬件抽象层,将解码器输出的Audio的PCM数据写入文件中,由此可以判断解码器的输出是否正确。
提示:使用AudioDumpInterface音频硬件抽象层,可以通过/data/FlingerOut.pcm文件找到PCM的输出数据。
7.3.3 Audio硬件抽象层的真正实现
实现一个真正的Audio硬件抽象层,需要完成的工作和实现以上的硬件抽象层类似。
例如:可以基于Linux标准的音频驱动:OSS(Open Sound System)或者ALSA(Advanced Linux Sound Architecture)驱动程序来实现。
对于OSS驱动程序,实现方式和前面的AudioHardwareGeneric类似,数据流的读/写操作通过对/dev/dsp设备的读/写来完成;区别在于OSS支持了更多的ioctl来进行设置,还涉及通过/dev/mixer设备进行控制,并支持更多不同的参数。
对于ALSA驱动程序,实现方式一般不是直接调用驱动程序的设备节点,而是先实现用户空间的alsa-lib,然后Audio硬件抽象层通过调用alsa-lib来实现。
在实现Audio硬件抽象层时,对于系统中有多个Audio设备的情况,可由硬件抽象层自行处理setRouting()函数设定,例如,可以选择支持多个设备的同时输出,或者有优先级输出。对于这种情况,数据流一般来自AudioStreamOut::write()函数,可由硬件抽象层确定输出方法。对于某种特殊的情况,也有可能采用硬件直接连接的方式,此时数据流可能并不来自上面的write(),这样就没有数据通道,只有控制接口。 Audio硬件抽象层也是可以处理这种情况的。
here: http://forest606.blog.163.com/blog/static/134450089201002824922585/