全部博文(153)
分类: LINUX
2010-11-12 10:00:55
第7章 Android的Audio系统
本章介绍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等一系列接口,如下所示:
- class AudioSystem
- {
- public:
- enum stream_type { // Audio 流的类型
- SYSTEM = 1,
- RING = 2,
- MUSIC = 3,
- ALARM = 4,
- NOTIFICATION = 5,
- BLUETOOTH_SCO = 6,
- ENFORCED_AUDIBLE = 7,
- NUM_STREAM_TYPES
- };
- enum audio_output_type { // Audio数据输出类型
- // …… 省略部分内容 };
- enum audio_format { // Audio数据格式
- FORMAT_DEFAULT = 0,
- PCM_16_BIT,
- PCM_8_BIT,
- INVALID_FORMAT
- };
- enum audio_mode { // Audio模式
- // …… 省略部分内容 };
- enum audio_routes { // Audio 路径类型
- ROUTE_EARPIECE = (1 << 0),
- ROUTE_SPEAKER = (1 << 1),
- ROUTE_BLUETOOTH_SCO = (1 << 2),
- ROUTE_HEADSET = (1 << 3),
- ROUTE_BLUETOOTH_A2DP = (1 << 4),
- ROUTE_ALL = -1UL,
- };
- // …… 省略部分内容
- static status_t setMasterVolume(float value);
- static status_t setMasterMute(bool mute);
- static status_t getMasterVolume(float* volume);
- static status_t getMasterMute(bool* mute);
- static status_t setStreamVolume(int stream, float value);
- static status_t setStreamMute(int stream, bool mute);
- static status_t getStreamVolume(int stream, float* volume);
- static status_t getStreamMute(int stream, bool* mute);
- static status_t setMode(int mode);
- static status_t getMode(int* mode);
- static status_t setRouting(int mode,
uint32_t routes, uint32_t mask);- static status_t getRouting(int mode, uint32_t* routes);
- // …… 省略部分内容
- };
在Audio系统的几个枚举值中,audio_routes是由单独的位来表示的,而不是由顺序的枚举值表示,因此这个值在使用过程中可以使用" 或"的方式。例如,表示声音可以既从耳机(EARPIECE)输出,也从扬声器(SPEAKER)输出,这样是否能实现,由下层提供支持。在这个类 中,set/get等接口控制的也是相关的内容,例如Audio声音的大小、Audio的模式、路径等。
AudioTrack是Audio输出环节的类,其中最重要的接口是write(),主要的函数如下所示。
- class AudioTrack
- {
- typedef void (*callback_t)(int event,
void* user, void *info);- AudioTrack( int streamType,
- uint32_t sampleRate = 0, // 音频的采样律
- int format = 0, //
音频的格式(例如8位或者16位的PCM)- int channelCount = 0, // 音频的通道数
- int frameCount = 0, // 音频的帧数
- uint32_t flags = 0,
- callback_t cbf = 0,
- void* user = 0,
- int notificationFrames = 0);
- void start();
- void stop();
- void flush();
- void pause();
- void mute(bool);
- ssize_t write(const void* buffer, size_t size);
- // …… 省略部分内容
- }
AudioRecord是Audio输入环节的类,其中最重要的接口为read(),主要的函数如下所示。
- class AudioRecord
- {
- public:
- AudioRecord(int streamType,
- uint32_t sampleRate = 0, // 音频的采样律
- int format = 0, //
音频的格式(例如8位或者16位的PCM)- int channelCount = 0, // 音频的通道数
- int frameCount = 0, // 音频的帧数
- uint32_t flags = 0,
- callback_t cbf = 0,
- void* user = 0,
- int notificationFrames = 0);
- status_t start();
- status_t stop();
- ssize_t read(void* buffer, size_t size);
- // …… 省略部分内容
- }
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的实现,其主要接口如下所示:
- class AudioFlinger : public BnAudioFlinger,
public IBinder::DeathRecipient- {
- public:
// …… 省略部分内容- virtual sp
createTrack( // 获得音频输出接口(Track)- pid_t pid,
- int streamType,
- uint32_t sampleRate,
- int format,
- int channelCount,
- int frameCount,
- uint32_t flags,
- const sp
& sharedBuffer, - status_t *status);
- // …… 省略部分内容
- virtual status_t setMasterVolume(float value);
- virtual status_t setMasterMute(bool muted);
- virtual status_t setStreamVolume(int stream, float value);
- virtual status_t setStreamMute(int stream, bool muted);
- virtual status_t setRouting(int mode,
uint32_t routes, uint32_t mask);- virtual uint32_t getRouting(int mode) const;
- virtual status_t setMode(int mode);
- virtual int getMode() const;
- virtual sp
openRecord( // 获得音频输出接口(Record)- pid_t pid,
- int streamType,
- uint32_t sampleRate,
- int format,
- int channelCount,
- int frameCount,
- uint32_t flags,
- status_t *status);
AudioFlinger主要提供createTrack()创建音频的输出设备IAudioTrack,openRecord()创建音频的输入 设备IAudioRecord。另外包含的就是一个get/set接口,用于控制。
AudioFlinger构造函数片段如下所示:
- AudioFlinger::AudioFlinger()
- {
- mHardwareStatus = AUDIO_HW_IDLE;
- mAudioHardware = AudioHardwareInterface::create();
- mHardwareStatus = AUDIO_HW_INIT;
- if (mAudioHardware->initCheck() == NO_ERROR) {
- mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
- status_t status;
- AudioStreamOut *hwOutput =
- mAudioHardware->openOutputStream
(AudioSystem::PCM_16_BIT, 0, 0, &status);- mHardwareStatus = AUDIO_HW_IDLE;
- if (hwOutput) {
- mHardwareMixerThread =
- new MixerThread(this, hwOutput,
AudioSystem::AUDIO_OUTPUT_HARDWARE);- } else {
- LOGE("Failed to initialize hardware
output stream, status: %d", status);- }
- // …… 省略部分内容
- mAudioRecordThread = new
AudioRecordThread(mAudioHardware, this);- if (mAudioRecordThread != 0) {
- mAudioRecordThread->run("
AudioRecordThread", PRIORITY_URGENT_AUDIO);- }
- } else {
- LOGE("Couldn't even initialize the stubbed audio hardware!");
- }
- }
从工作的角度看,AudioFlinger在初始化之后,首先获得放音设备,然后为混音器(Mixer)建立线程,接着建立放音设备线程,在线程中 获得放音设备。
在AudioFlinger的AudioResampler.h中定义了一个音频重取样器工具类,如下所示:
- class AudioResampler {
- public:
- enum src_quality {
- DEFAULT=0,
- LOW_QUALITY=1, // 线性差值算法
- MED_QUALITY=2, // 立方差值算法
- HIGH_QUALITY=3 // fixed multi-tap FIR算法
- };
- static AudioResampler* create(int bitDepth,
int inChannelCount, // 静态地创建函数- int32_t sampleRate, int quality=DEFAULT);
- virtual ~AudioResampler();
- virtual void init() = 0;
- virtual void setSampleRate(int32_t inSampleRate);
// 设置重采样率- virtual void setVolume(int16_t left, int16_t right);
// 设置音量- virtual void resample(int32_t* out, size_t outFrameCount,
- AudioBufferProvider* provider) = 0;
- };
这个音频重取样工具包含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不支持指针,因此接口被封装成了另外的形式。
例如,对于音频输出,android_media_AudioTrack.cpp提供的是写字节和写短整型的接口类型。
- static jint android_media_AudioTrack_native_
write(JNIEnv *env, jobject thiz,
jbyteArray javaAudioData,
jint offsetInBytes, jint sizeInBytes,
jint javaAudioFormat) {- jbyte* cAudioData = NULL;
- AudioTrack *lpTrack = NULL;
- lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields. Native TrackInJavaObj);
- // …… 省略部分内容
- ssize_t written = 0;
- if (lpTrack->sharedBuffer() == 0) {
- //进行写操作
- written = lpTrack->write(cAudioData +
offsetInBytes, sizeInBytes);- } else {
- if (javaAudioFormat == javaAudioTrackFields.PCM16) {
- memcpy(lpTrack->sharedBuffer()->pointer(),
- cAudioData+offsetInBytes, sizeInBytes);
- written = sizeInBytes;
- } else if (javaAudioFormat == javaAudioTrackFields.PCM8) {
- int count = sizeInBytes;
- int16_t *dst = (int16_t *)lpTrack->sharedBuffer()->pointer();
- const int8_t *src = (const int8_t *)
(cAudioData + offsetInBytes);- while(count--) {
- *dst++ = (int16_t)(*src++^0x80) << 8;
- }
- written = sizeInBytes;
- }
- }
- // …… 省略部分内容
- env->ReleasePrimitiveArrayCritical(javaAudioData, cAudioData, 0);
- return (int)written;
- }
所定义的JNI接口native_write_byte和native_write_short如下所示:
- {"native_write_byte", "([BIII]I", (void *)
android_media_AudioTrack_native_write),- {"native_write_short", "([SIII]I", (void *)
android_media_AudioTrack_native_ write_short),
向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. Audio Track、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的主要定义如下所示:
- class AudioStreamOut {
- public:
- virtual ~AudioStreamOut() = 0;
- virtual status_t setVolume(float volume) = 0;
- virtual ssize_t write(const void* buffer, size_t bytes) = 0;
- //...... 省略部分内容
- };
- class AudioStreamIn {
- public:
- virtual ~AudioStreamIn() = 0;
- virtual status_t setGain(float gain) = 0;
- virtual ssize_t read(void* buffer, ssize_t bytes) = 0;
- //...... 省略部分内容
- };
AudioStreamOut和AudioStreamIn分别对应了音频的输出环节和输入环节,其中负责数据流的接口分别是wirte()和 read(),参数是一块内存的指针和长度;另外还有一些设置和获取接口。
Audio的硬件抽象层主体AudioHardwareInterface类的定义如下所示:
- class AudioHardwareInterface
- {
- public:
- virtual status_t initCheck() = 0;
- virtual status_t setVoiceVolume(float volume) = 0;
- virtual status_t setMasterVolume(float volume) = 0;
- virtual status_t setRouting(int mode, uint32_t routes) = 0;
- virtual status_t getRouting(int mode, uint32_t* routes) = 0;
- virtual status_t setMode(int mode) = 0;
- virtual status_t getMode(int* mode) = 0;
- //...... 省略部分内容
- virtual AudioStreamOut* openOutputStream( // 打开输出流
- int format=0,
- int channelCount=0,
- uint32_t sampleRate=0,
- status_t *status=0) = 0;
- virtual AudioStreamIn* openInputStream( // 打开输入流
- int format,
- int channelCount,
- uint32_t sampleRate,
- status_t *status,
- AudioSystem::
audio_in_acoustics acoustics) = 0;- static AudioHardwareInterface* create();
- };
在这个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硬件抽象层实现(1)
在AudioFlinger中可以通过编译宏的方式选择使用哪一个Audio硬件抽象层。这些Audio硬件抽象层既可以作为参考设计,也可以在没 有实际的Audio硬件抽象层(甚至没有Audio设备)时使用,以保证系统的正常运行。
在AudioFlinger的编译文件Android.mk中,具有如下的定义:
- ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
- LOCAL_STATIC_LIBRARIES += libaudiointerface
- else
- LOCAL_SHARED_LIBRARIES += libaudio
- endif
- LOCAL_MODULE:= libaudioflinger
- include $(BUILD_SHARED_LIBRARY)
定义的含义为:当宏BOARD_USES_GENERIC_AUDIO为true时,连接libaudiointer face.a静态库;当BOARD_USES_GENERIC_AUDIO为false时,连接libaudiointerface.so动态库。在正常 的情况下,一般是使用后者,即在另外的地方实现libaudiointerface.so动态库,由AudioFlinger的库 libaudioflinger.so来连接使用。
libaudiointerface.a也在这个Android.mk中生成:
- include $(CLEAR_VARS)
- LOCAL_SRC_FILES:= \
- AudioHardwareGeneric.cpp \
- AudioHardwareStub.cpp \
- AudioDumpInterface.cpp \
- AudioHardwareInterface.cpp
- LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- libmedia \
- libhardware_legacy
- ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
- LOCAL_CFLAGS += -DGENERIC_AUDIO
- endif
- LOCAL_MODULE:= libaudiointerface
- include $(BUILD_STATIC_LIBRARY)
以上内容通过编译4个源文件,生成了libaudiointerface.a静态库。其中AudioHard wareInterface.cpp负责实现基础类和管理,而AudioHardwareGeneric.cpp、AudioHard wareStub.cpp和AudioDumpInterface.cpp三个文件各自代表一种Auido硬件抽象层的实现。
AudioHardwareGeneric.cpp:实现基于特定驱动的通用Audio硬件抽象层;
AudioHardwareStub.cpp:实现Audio硬件抽象层的一个桩;
AudioDumpInterface.cpp:实现输出到文件的Audio硬件抽象层。
在AudioHardwareInterface.cpp中,实现了Audio硬件抽象层的创建函数 AudioHardwareInterface::create(),内容如下所示:
- AudioHardwareInterface* AudioHardwareInterface::create()
- {
- AudioHardwareInterface* hw = 0;
- char value[PROPERTY_VALUE_MAX];
- #ifdef GENERIC_AUDIO
- hw = new AudioHardwareGeneric();
// 使用通用的Audio硬件抽象层- #else
- if (property_get("ro.kernel.qemu", value, 0)) {
- LOGD("Running in emulation - using generic audio driver");
- hw = new AudioHardwareGeneric();
- }
- else {
- LOGV("Creating Vendor Specific AudioHardware");
- hw = createAudioHardware();
// 使用实际的Audio硬件抽象层- }
- #endif
- if (hw->initCheck() != NO_ERROR) {
- LOGW("Using stubbed audio hardware.
No sound will be produced.");- delete hw;
- hw = new AudioHardwareStub();
// 使用实际的Audio硬件抽象层的桩实现- }
- #ifdef DUMP_FLINGER_OUT
- hw = new AudioDumpInterface(hw);
// 使用实际的Audio的Dump接口实现- #endif
- return hw;
- }
根据GENERIC_AUDIO、DUMP_FLINGER_OUT等宏选择创建几个不同的Audio硬件抽象层,最后返回的接口均为 AudioHardwareInterface类型的指针。
1.用桩实现的Audio硬件抽象层
AudioHardwareStub.h和AudioHardwareStub.cpp是一个Android硬件抽象层的桩实现方式。这个实现不操 作实际的硬件和文件,它所进行的是空操作,在系统没有实际的Audio设备时使用这个实现,来保证系统的正常工作。如果使用这个硬件抽象层,实际上 Audio系统的输入和输出都将为空。
AudioHardwareStub.h定义了AudioStreamOutStub 和AudioStreamInStub类的情况 如下所示:
- class AudioStreamOutStub : public AudioStreamOut {
- public:
- virtual status_t set(int format, int
channelCount, uint32_t sampleRate);- virtual uint32_t sampleRate() const { return 44100; }
- virtual size_t bufferSize() const { return 4096; }
- virtual int channelCount() const { return 2; }
- virtual int format() const { return
AudioSystem::PCM_16_BIT; }- virtual uint32_t latency() const { return 0; }
- virtual status_t setVolume(float volume) { return NO_ERROR; }
- virtual ssize_t write(const void* buffer, size_t bytes);
- virtual status_t standby();
- virtual status_t dump(int fd, const Vector
& args); - };
- class AudioStreamInStub : public AudioStreamIn {
- public:
- virtual status_t set(int format, int
channelCount, uint32_t sampleRate, AudioSystem::
audio_in_acoustics acoustics);- virtual uint32_t sampleRate() const { return 8000; }
- virtual size_t bufferSize() const { return 320; }
- virtual int channelCount() const { return 1; }
- virtual int format() const { return
AudioSystem::PCM_16_BIT; }- virtual status_t setGain(float gain) { return NO_ERROR; }
- virtual ssize_t read(void* buffer, ssize_t bytes);
- virtual status_t dump(int fd, const Vector
& args); - virtual status_t standby() { return NO_ERROR; }
- };
上面实际上使用了最简单模式,只是用固定的参数(缓冲区大小、采样率、通道数),以及将一些函数直接无错误返回。
使用AudioHardwareStub类来继承AudioHardwareBase,事实上也就是继承 AudioHardwareInterface。
- class AudioHardwareStub : public AudioHardwareBase
- {
- public:
- AudioHardwareStub();
- virtual ~AudioHardwareStub();
- virtual status_t initCheck();
- virtual status_t setVoiceVolume(float volume);
- virtual status_t setMasterVolume(float volume);
- virtual status_t setMicMute(bool state)
{ mMicMute = state; return NO_ERROR; }- virtual status_t getMicMute(bool* state)
{ *state = mMicMute ; return NO_ERROR; }- virtual status_t setParameter(const
char* key, const char* value)- { return NO_ERROR; }
- virtual AudioStreamOut* openOutputStream( //打开输出流
- int format=0,
- int channelCount=0,
- uint32_t sampleRate=0,
- status_t *status=0);
- virtual AudioStreamIn* openInputStream( //打开输入流
- int format,
- int channelCount,
- uint32_t sampleRate,
- status_t *status,
- AudioSystem::audio_in_acoustics acoustics);
- // …… 省略部分内容
- };
7.3.2 AudioFlinger中自带Audio硬件抽象层实现(2)
在实现过程中,为了保证声音可以输入和输出,这个桩实现的主要内容是实现AudioStreamOutStub和 AudioStreamInStub类的读/写函数。实现如下所示:
由此可见,使用这个接口进行音频的输入和输出时,和真实的设备没有关系,输出和输入都使用延时来完成。对于输出的情况,不会有声音播出,但是返回值 表示全部内容已经输出完成;对于输入的情况,将返回全部为0的数据。
此外,这种实现支持默认的参数,如果用set()函数设置的参数与默认参数不一致,还会返回错误。
2.Android通用的Audio硬件抽象层
AudioHardwareGeneric.h和AudioHardwareGeneric.cpp是Android通用的一个Audio硬件抽象 层。与前面的桩实现不同,这是一个真正能够使用的Audio硬件抽象层,但是它需要Android的一种特殊的声音驱动程序的支持。
与前面类似,AudioStreamOutGeneric、AudioStreamInGeneric和AudioHardwareGeneric 这3个类分别继承Audio硬件抽象层的3个接口。
在AudioHardwareGeneric.cpp的实现中,使用的驱动程序是/dev/eac,这是一个非标准程序,定义设备的路径如下所示:
对于Linux操作系统,这个驱动程序在文件系统中的节点主设备号为10,次设备号自动生成。
提示:eac是Linux中的一个misc驱动程序,作为Android的通用音频驱动,写设备表示放音,读设备表示录音。
在AudioHardwareGeneric的构造函数中,打开这个驱动程序的设备节点。
这个音频设备是一个比较简单的驱动程序,没有很多设置接口,只是用写设备表示录音,读设备表示放音。放音和录音支持的都是16位的PCM。
虽然AudioHardwareGeneric是一个可以真正工作的Audio硬件抽象层,但是这种实现方式非常简单,不支持各种设置,参数也只能 使用默认的。而且,这种驱动程序需要在Linux核心加入eac驱动程序的支持。
3.提供Dump功能的Audio硬件抽象层
AudioDumpInterface.h和AudioDumpInterface.cpp是一个提供了Dump功能的Audio硬件抽象层,它所 起到的作用就是将输出的Audio数据写入到文件中。
AudioDumpInterface本身支持Audio的输出功能,不支持输入功能。AudioDumpInterface.h中的类定义如下:
只实现了AudioStreamOut,没有实现AudioStreamIn,因此这个Audio硬件抽象层只支持输出功能,不支持输入功能。
输出文件的名称被定义为:
在AudioDumpInterface.cpp的AudioStreamOut所实现的写函数中,写入的对象就是这个文件。
如果文件是打开的,则使用追加方式写入。因此使用这个Audio硬件抽象层时,播放的内容(PCM)将全部被写入文件。而且这个类支持各种格式的输 出,这取决于调用者的设置。
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硬件抽象层也是可以处理这种情况的。chinaunix网友2010-11-12 17:25:54
很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com