7.2 音频子系统结构
↘7.2.1 总体结构
Android音频系统包括驱动程序层、硬件抽象层、Audio Flinger、本地框架库、Java框架类和Java应用层对Audio系统的调用。
Audio系统的结构如图7-1所示。
图7-1 Android的Audio音频系统结构
自下而上,Android的Audio系统分成以下几个部分。
(1)驱动程序
Linux的音频系统可以使用OSS、ALSA等标准的架构或者其他自定义驱动,各种驱动实现的内容类似,提供对Audio设备的控制通道和数据通道。
(2)硬件抽象层
Audio硬件抽象层接口是C++形式的,需要实现者继承并完成功能,其代码路径为hardware/libhardware_legacy/include/hardware/,包括以下的文件。
·AudioHardwareInterface.h:Audio主要的硬件抽象层接口。
·AudioPolicyInterface.h:Audio策略层的接口。
(3)本地框架层:Audio Flinger和Audio框架部分
·frameworks/base/include/media/:Audio框架部分头文件。
·frameworks/base/media/libmedia/:Audio框架部分源代码。
Audio本地框架是media库的一部分,本部分内容被编译成库libmedia.so。定义Audio部分的接口,这些内容实际上也作为Audio系统对本地层的接口。
·frameworks/base/services/audioflinger/:Audio Flinger的实现。
Audio Flinger实际上是对Audio框架部分的实现,作为Audio系统的本地服务部分使用,被编译成库libaudioflinger.so。
(4)JNI部分:Audio本地层接口的直接封装
·frameworks/base/core/jni/:和Audio相关的几个文件。
框架层的JNI库libandroid_runtime.so,Audio的JNI是其中的一部分。
(5)Audio的Java部分
·frameworks/base/media/java/android/media/:和Audio相关的几个类。
android.media包中具有和Audio相关的部分,主要包含Audio系统中的几个类和更上层的AudioManager。
提示:Android 4.x的音频系统开始使用硬件模块作为硬件抽象层,与上述结构不同。
↘7.2.2 Audio的本地框架层
1.media库中的Audio框架部分
Android的Audio系统的核心框架在media库的一部分。其中的头文件分成两个部分,一个部分是提供给上层调用的接口,另一个部分是需要由下层实现的接口。
提供给上层调用的接口包括以下几个类。
·AudioSystem.h:音频管理的AudioSystem类,其中也包括类型的定义。
·AudioTrack.h:放音类AudioTrack,包括控制函数和数据函数write()。
·AudioRecord.h:录音类AudioRecord,包括控制函数和数据函数read()。
·AudioEffect.h:音频效果类AudioEffect,包括查询和设置函数。
这些接口既提供给JNI封装给Java层,也给本地的其他部分调用。实际上是Audio系统对本地提供的功能,相当于本地API。AudioTrack和AudioRecord两个类功能对应,方向相反,用于音频数据流传输的类。音频播放器和音频录制器利用这些接口完成本地功能的调用。
需要由下层实现的接口也就是音频系统基于Binder IPC的接口,包括以下几个部分。
·IAudioFlinger.h:需要下层实现的音频总管接口。
·IAudioTrack.h:需要下层实现的放音部分。
·IAudioRecorder.h:需要下层实现的录音部分。
·IAudioPolicyService.h:需要下层实现的音频策略服务。
这些接口的实现者就是Audio部分的服务AudioFlingerClient。
AudioSystem类中包含了音频部分一系列的枚举类型,这些类型在Audio系统的各个层次中均被使用。主要的一些内容如表7-2所示。
表7-2 AudioSystem中定义的类型及其取值
2.AudioFlinger动态库
AudioFlinger是音频部分服务的实现,它实现了media库中Audio层的几个通过Binder IPC定义的接口,并且调用Audio和Audio策略的硬件抽象层来实现。AudioFlinger运行于mediaserver守护进程中,在执行的过程中将建立几个线程负责各个部分的处理。
AudioFlinger中几个核心的实现部分包括以下的几个文件。
·AudioFlinger.*:主要的文件实现上层IAudioFlinger接口。
·AudioPolicyService.*:IAudioPolicyService的实现。
·AudioMixer.*:音频混合工具的实现。
·AudioResampler.*:音频重取样的实现(线性、正弦Sinc、三次Cubic)。
·AudioPolicyManagerBase.h:音频策略基类的定义。
AudioFlinger主要的逻辑就是音频混合的处理,这里使用了AudioMixer作为实现。AudioFlinger完成初始化之后,将为放音、录音和混音等建立各自的线程,在线程循环中进行处理。
AudioFlinger另外一个职责是对硬件抽象层的调用,其Android.mk中具有如下定义:
ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true) LOCAL_STATIC_LIBRARIES += libaudiointerface libaudiopolicybase LOCAL_CFLAGS += -DGENERIC_AUDIO else LOCAL_SHARED_LIBRARIES += libaudio libaudiopolicy Endif LOCAL_MODULE:= libaudioflinger
当生成AudioFlinger库时,如果配置宏BOARD_USES_GENERIC_AUDIO为true,链接libaudiointerface.a和libaudiopolicybase.a静态库,它们是音频和音频策略硬件抽象层的默认实现;如果为false,链接libaudiointerface.so和libaudiopolicy.so动态库,它们是音频和音频策略硬件抽象层的真正实现。
↘7.2.3 Audio系统的JNI和Java层
1.JNI部分
Android的Audio部分通过JNI向Java层提供接口,在Java层可以通过JNI接口完成Audio系统的大部分操作。
Audio部分的几个JNI文件如下。
·android_media_AudioSystem.cpp:总体控制,主要调用本地的AudioSystem。
·android_media_AudioTrack.cpp:输出环节,主要调用本地的AudioTrack。
·android_media_AudioRecord.cpp:输入环节,主要调用本地的AudioRecord。
它们实现了对Java框架层中的android.media包中AudioSystem、AudioTrack和AudioRecord三个类的本地支持。在Java层,可以对Audio系统进行控制和数据流操作,对于控制操作,和底层的处理基本一致;对于数据流操作,由于Java不支持指针,因此接口被封装成了另外的形式。
例如,对于音频输出,android_media_AudioTrack.cpp提供的是写字节和写短整型的接口类型,它们都调用writeToTrack()函数实现,如下所示:
jint writeToTrack(AudioTrack* pTrack, jint audioFormat, jbyte* data, jint offsetInBytes, jint sizeInBytes) { ssize_t written = 0; if (pTrack->sharedBuffer() == 0) { written = pTrack->write(data + offsetInBytes, sizeInBytes); // 写操作 } else { if (audioFormat == javaAudioTrackFields.PCMl6) { if ((size_t)sizeInBytes > pTrack->sharedBuffer()->size()) { sizeInBytes = pTrack->sharedBuffer()->size(); // 获取数据的大小 } memcpy(pTrack->sharedBuffer()->pointer(), // 内存复制 data + offsetInBytes, sizeInBytes); written = sizeInBytes; } else if (audioFormat == javaAudioTrackFields.PCM8) { // PCM8格式处理 if (((size_t)sizeInBytes)*2 > pTrack->sharedBuffer()->size()) { sizeInBytes = pTrack->sharedBuffer()->size() / 2; //准备扩展成l6位 } int count = sizeInBytes; intl6_t *dst = (intl6_t *)pTrack->sharedBuffer()->pointer(); const int8_t *src = (const int8_t *)(data + offsetInBytes); while(count--) { *dst++ = (intl6_t)(*src++^0x80) << 8; }// 复制 written = sizeInBytes; // 记录写的数目 } } return written; // 返回写的数目 }
由此可见,JNI中利用本地的指针方式,得到数据后拼凑成Java的数据,由此实现音频数据流的传输。显然,Java层传输音频数据的效率是比较低的。因此,虽然Java层也有数据流的操作接口,但是通常不在Java层次进行数据流操作。
提示:AudioTrack和AudioRecord类只供特殊需要取得音频数据的应用程序使用,媒体播放和录制等程序的音频数据都只从本地层传递,不会传入Java层。
2.Java部分
android.media中的几个类提供了Audio部分的实现,主要包括以下几个类。
·AudioFormat:Audio格式的常量定义,主要为通道类型。
·AudioSystem:Audio系统类,全类被@hide标识,不属于API。
·AudioTrack:用于放音的数据流操作。
·AudioRecord:用于录音的数据流操作。
·AudioManager:Audio的控制核心。
AudioManager是Java层音频系统的控制核心,使用android.content包中的Context类的getSystemService()方法,以AUDIO_SERVICE("audio")为参数调用可以获得一个AudioManager的实例。
AudioManager中的几个主要常量为音频流(Stream Type),具有STREAM_SYSTEM(系统音频流)、STREAM_RING(铃声流)、STREAM_MUSIC(音乐流)、STREAM_ALARM(警报流)、STREAM_NOTIFICATION(通知)等几种类型。
AudioManager的主要的几个方法如下所示:
public void adjustVolume(int direction, int flags) // 调节音量 public void setMode(int mode) // 设置音频模式 public void setRingerMode(int ringerMode) // 调节铃声音量 public void setStreamMute(int streamType, boolean state) // 设置音频流为静音 public void setStreamSolo(int streamType, boolean state) // 设置音频流为单声道
AudioTrack和AudioRecord分别用于放音和录音的数据流处理,可以根据音频流类型、采样率、通道等参数建立实例。AudioTrack的核心方法是write(),AudioRecord的核心方法是read()。通过这两个类可以在Java层对音频系统进行原始数据流的读/写操作。