Android板级支持与硬件相关子系统
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

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层对音频系统进行原始数据流的读/写操作。