Chinaunix首页 | 论坛 | 博客
  • 博客访问: 489343
  • 博文数量: 153
  • 博客积分: 3010
  • 博客等级: 中校
  • 技术积分: 1724
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-08 11:55
文章分类

全部博文(153)

文章存档

2011年(1)

2010年(55)

2009年(88)

2008年(9)

我的朋友

分类: 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等一系列接口,如下所示:

  1. class AudioSystem  
  2. {  
  3. public:  
  4.     enum stream_type {                      // Audio 流的类型  
  5.         SYSTEM          = 1,  
  6.         RING            = 2,  
  7.         MUSIC           = 3,  
  8.         ALARM           = 4,  
  9.         NOTIFICATION    = 5,  
  10.         BLUETOOTH_SCO   = 6,  
  11.         ENFORCED_AUDIBLE = 7,  
  12.         NUM_STREAM_TYPES  
  13.     };  
  14.     enum audio_output_type {            // Audio数据输出类型  
  15.         // …… 省略部分内容   };  
  16.     enum audio_format {                 // Audio数据格式  
  17.         FORMAT_DEFAULT = 0,  
  18.         PCM_16_BIT,  
  19.         PCM_8_BIT,  
  20.         INVALID_FORMAT  
  21.     };  
  22.     enum audio_mode {                       // Audio模式  
  23.         // …… 省略部分内容   };  
  24.     enum audio_routes {                 // Audio 路径类型  
  25.         ROUTE_EARPIECE         = (1 << 0),  
  26.         ROUTE_SPEAKER          = (1 << 1),  
  27.         ROUTE_BLUETOOTH_SCO  = (1 << 2),  
  28.         ROUTE_HEADSET           = (1 << 3),  
  29.         ROUTE_BLUETOOTH_A2DP  = (1 << 4),  
  30.         ROUTE_ALL                 = -1UL,  
  31.     };  
  32.     // …… 省略部分内容  
  33.     static status_t setMasterVolume(float value);  
  34.     static status_t setMasterMute(bool mute);  
  35.     static status_t getMasterVolume(float* volume);  
  36.     static status_t getMasterMute(bool* mute);  
  37.     static status_t setStreamVolume(int stream, float value);  
  38.     static status_t setStreamMute(int stream, bool mute);  
  39.     static status_t getStreamVolume(int stream, float* volume);  
  40.     static status_t getStreamMute(int stream, bool* mute);  
  41.     static status_t setMode(int mode);  
  42.     static status_t getMode(int* mode);  
  43.     static status_t setRouting(int mode,
    uint32_t routes, uint32_t mask);  
  44.     static status_t getRouting(int mode, uint32_t* routes);  
  45.     // …… 省略部分内容  
  46. }; 

在Audio系统的几个枚举值中,audio_routes是由单独的位来表示的,而不是由顺序的枚举值表示,因此这个值在使用过程中可以使用" 或"的方式。例如,表示声音可以既从耳机(EARPIECE)输出,也从扬声器(SPEAKER)输出,这样是否能实现,由下层提供支持。在这个类 中,set/get等接口控制的也是相关的内容,例如Audio声音的大小、Audio的模式、路径等。

AudioTrack是Audio输出环节的类,其中最重要的接口是write(),主要的函数如下所示。

  1. class AudioTrack  
  2. {  
  3.     typedef void (*callback_t)(int event, 
    void* user, void *info);  
  4.     AudioTrack( int streamType,  
  5.                 uint32_t sampleRate  = 0,       // 音频的采样律  
  6.                 int format           = 0,       //
    音频的格式(例如8位或者16位的PCM)
     
  7.                 int channelCount     = 0,       // 音频的通道数  
  8.                 int frameCount       = 0,       // 音频的帧数  
  9.                 uint32_t flags       = 0,  
  10.                 callback_t cbf       = 0,  
  11.                 void* user           = 0,  
  12.                 int notificationFrames = 0);  
  13.     void        start();  
  14.     void        stop();  
  15.     void        flush();  
  16.     void        pause();  
  17.     void        mute(bool);  
  18.     ssize_t     write(const void* buffer, size_t size);  
  19. // …… 省略部分内容  

AudioRecord是Audio输入环节的类,其中最重要的接口为read(),主要的函数如下所示。

  1. class AudioRecord  
  2. {  
  3. public:  
  4.     AudioRecord(int streamType,  
  5.                 uint32_t sampleRate  = 0,       // 音频的采样律  
  6.                 int format           = 0,       // 
    音频的格式(例如8位或者16位的PCM)
     
  7.                 int channelCount     = 0,       // 音频的通道数  
  8.                 int frameCount       = 0,       // 音频的帧数  
  9.                 uint32_t flags      = 0,  
  10.                 callback_t cbf = 0,  
  11.                 void* user = 0,  
  12.                 int notificationFrames = 0);  
  13.     status_t    start();  
  14.     status_t    stop();  
  15.     ssize_t     read(void* buffer, size_t size);  
  16. // …… 省略部分内容  

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部分接口的实现,其代码路 径为:

  1. frameworks/base/libs/audioflinger 

AudioFlinger的核心文件是AudioFlinger.h和AudioFlinger.cpp,提供了类AudioFlinger,这个 类是一个IAudioFlinger的实现,其主要接口如下所示:

  1. class AudioFlinger : public BnAudioFlinger, 
    public IBinder::DeathRecipient  
  2. {  
  3. public:  
  4.                                              
    // …… 省略部分内容  
  5.     virtual sp createTrack(       
    // 获得音频输出接口(Track)  
  6.                                 pid_t pid,  
  7.                                 int streamType,  
  8.                                 uint32_t sampleRate,  
  9.                                 int format,  
  10.                                 int channelCount,  
  11.                                 int frameCount,  
  12.                                 uint32_t flags,  
  13.                                 const sp& sharedBuffer,  
  14.                                 status_t *status);  
  15.     // …… 省略部分内容  
  16.     virtual     status_t    setMasterVolume(float value);  
  17.     virtual     status_t    setMasterMute(bool muted);  
  18.     virtual     status_t    setStreamVolume(int stream, float value);  
  19.     virtual     status_t    setStreamMute(int stream, bool muted);  
  20.     virtual     status_t    setRouting(int mode, 
    uint32_t routes, uint32_t mask);  
  21.     virtual     uint32_t    getRouting(int mode) const;  
  22.     virtual     status_t    setMode(int mode);  
  23.     virtual     int         getMode() const;  
  24.     virtual sp openRecord(         
    // 获得音频输出接口(Record)  
  25.                                 pid_t pid,  
  26.                                 int streamType,  
  27.                                 uint32_t sampleRate,  
  28.                                 int format,  
  29.                                 int channelCount,  
  30.                                 int frameCount,  
  31.                                 uint32_t flags,  
  32.                                 status_t *status); 

AudioFlinger主要提供createTrack()创建音频的输出设备IAudioTrack,openRecord()创建音频的输入 设备IAudioRecord。另外包含的就是一个get/set接口,用于控制。

AudioFlinger构造函数片段如下所示:

  1. AudioFlinger::AudioFlinger()  
  2. {  
  3.     mHardwareStatus = AUDIO_HW_IDLE;  
  4.     mAudioHardware = AudioHardwareInterface::create();  
  5.     mHardwareStatus = AUDIO_HW_INIT;  
  6.     if (mAudioHardware->initCheck() == NO_ERROR) {  
  7.         mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;  
  8.         status_t status;  
  9.         AudioStreamOut *hwOutput =  
  10.             mAudioHardware->openOutputStream
    (AudioSystem::PCM_16_BIT, 
    00, &status);  
  11.         mHardwareStatus = AUDIO_HW_IDLE;  
  12.         if (hwOutput) {  
  13.             mHardwareMixerThread =  
  14.             new MixerThread(this, hwOutput, 
    AudioSystem::AUDIO_OUTPUT_HARDWARE);  
  15.         } else {  
  16.             LOGE("Failed to initialize hardware 
    output stream, status: %d"
    , status);  
  17.         }  
  18.     // …… 省略部分内容  
  19.         mAudioRecordThread = new 
    AudioRecordThread(mAudioHardware, 
    this);  
  20.         if (mAudioRecordThread != 0) {  
  21.             mAudioRecordThread->run("
    AudioRecordThread"
    , PRIORITY_URGENT_AUDIO);  
  22.         }  
  23.      } else {  
  24.         LOGE("Couldn't even initialize the stubbed audio hardware!");  
  25.     }  

从工作的角度看,AudioFlinger在初始化之后,首先获得放音设备,然后为混音器(Mixer)建立线程,接着建立放音设备线程,在线程中 获得放音设备。

在AudioFlinger的AudioResampler.h中定义了一个音频重取样器工具类,如下所示:

  1. class AudioResampler {  
  2. public:  
  3.     enum src_quality {  
  4.         DEFAULT=0,  
  5.         LOW_QUALITY=1,              // 线性差值算法  
  6.         MED_QUALITY=2,              // 立方差值算法  
  7.         HIGH_QUALITY=3              // fixed multi-tap FIR算法  
  8.     };  
  9.     static AudioResampler* create(int bitDepth,
    int inChannelCount, // 静态地创建函数  
  10.             int32_t sampleRate, int quality=DEFAULT);  
  11.     virtual ~AudioResampler();  
  12.     virtual void init() = 0;  
  13.     virtual void setSampleRate(int32_t inSampleRate);
    // 设置重采样率  
  14.     virtual void setVolume(int16_t left, int16_t right); 
    // 设置音量  
  15.     virtual void resample(int32_t* out, size_t outFrameCount,  
  16.                        AudioBufferProvider* provider) = 0;  
  17. }; 

这个音频重取样工具包含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提供的是写字节和写短整型的接口类型。

  1. static jint android_media_AudioTrack_native_
    write(JNIEnv *env,  jobject thiz,  
  2.                                              
    jbyteArray javaAudioData,  
  3.                                              
    jint offsetInBytes, jint sizeInBytes,  
  4.                                             
    jint javaAudioFormat) {  
  5.     jbyte* cAudioData = NULL;  
  6.     AudioTrack *lpTrack = NULL;  
  7.     lpTrack = (AudioTrack *)env->GetIntField(  
  8.                  thiz, javaAudioTrackFields. Native TrackInJavaObj);  
  9.     // …… 省略部分内容  
  10.     ssize_t written = 0;  
  11.     if (lpTrack->sharedBuffer() == 0) {  
  12.     //进行写操作  
  13.         written = lpTrack->write(cAudioData +
    offsetInBytes, sizeInBytes);  
  14.     } else {  
  15.         if (javaAudioFormat == javaAudioTrackFields.PCM16) {  
  16.             memcpy(lpTrack->sharedBuffer()->pointer(),  
  17.                     cAudioData+offsetInBytes, sizeInBytes);  
  18.             written = sizeInBytes;  
  19.         } else if (javaAudioFormat == javaAudioTrackFields.PCM8) {  
  20.             int count = sizeInBytes;  
  21.             int16_t *dst = (int16_t *)lpTrack->sharedBuffer()->pointer();  
  22.             const int8_t *src = (const int8_t *)
    (cAudioData + offsetInBytes);              
  23.             while(count--) {  
  24.                 *dst++ = (int16_t)(*src++^0x80) << 8;  
  25.             }  
  26.             written = sizeInBytes;  
  27.         }  
  28.     }  
  29.     // …… 省略部分内容  
  30.     env->ReleasePrimitiveArrayCritical(javaAudioData, cAudioData, 0);  
  31.     return (int)written;  

所定义的JNI接口native_write_byte和native_write_short如下所示:

  1. {"native_write_byte",    "([BIII]I", (void *)
    android_media_AudioTrack_native_write),  
  2. {"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的主要定义如下所示:

  1. class AudioStreamOut {  
  2. public:  
  3.     virtual             ~AudioStreamOut() = 0;  
  4.     virtual status_t    setVolume(float volume) = 0;  
  5.     virtual ssize_t     write(const void* buffer, size_t bytes) = 0;  
  6.     //......  省略部分内容  
  7. };  
  8. class AudioStreamIn {  
  9. public:  
  10.     virtual             ~AudioStreamIn() = 0;  
  11.     virtual status_t    setGain(float gain) = 0;  
  12.     virtual ssize_t     read(void* buffer, ssize_t bytes) = 0;  
  13.     //......  省略部分内容  
  14. }; 

AudioStreamOut和AudioStreamIn分别对应了音频的输出环节和输入环节,其中负责数据流的接口分别是wirte()和 read(),参数是一块内存的指针和长度;另外还有一些设置和获取接口。

Audio的硬件抽象层主体AudioHardwareInterface类的定义如下所示:

  1. class AudioHardwareInterface  
  2. {  
  3. public:  
  4.     virtual status_t    initCheck() = 0;  
  5.     virtual status_t    setVoiceVolume(float volume) = 0;  
  6.     virtual status_t    setMasterVolume(float volume) = 0;  
  7.     virtual status_t    setRouting(int mode, uint32_t routes) = 0;  
  8.     virtual status_t    getRouting(int mode, uint32_t* routes) = 0;  
  9.     virtual status_t    setMode(int mode) = 0;  
  10.     virtual status_t    getMode(int* mode) = 0;  
  11.     //......  省略部分内容  
  12.     virtual AudioStreamOut* openOutputStream(       // 打开输出流  
  13.                                 int format=0,  
  14.                                 int channelCount=0,  
  15.                                 uint32_t sampleRate=0,  
  16.                                 status_t *status=0) = 0;  
  17.     virtual AudioStreamIn* openInputStream(         // 打开输入流  
  18.                                 int format,  
  19.                                 int channelCount,  
  20.                                 uint32_t sampleRate,  
  21.                                 status_t *status,  
  22.                                 AudioSystem::
    audio_in_acoustics acoustics) = 
    0;  
  23.     static AudioHardwareInterface* create();  
  24. }; 

在这个AudioHardwareInterface接口中,使用openOutputStream()和openInputStream()函数 分别获取AudioStreamOut和AudioStreamIn两个类,它们作为音频输入/输出设备来  使用。

此外,AudioHardwareInterface.h定义了C语言的接口来获取一个AudioHardware Interface类型的指针。

  1. 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中,具有如下的定义:

  1. ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)  
  2.   LOCAL_STATIC_LIBRARIES += libaudiointerface  
  3. else 
  4.   LOCAL_SHARED_LIBRARIES += libaudio  
  5. endif  
  6. LOCAL_MODULE:= libaudioflinger  
  7. 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中生成:

  1. include $(CLEAR_VARS)  
  2. LOCAL_SRC_FILES:= \  
  3.     AudioHardwareGeneric.cpp \  
  4.     AudioHardwareStub.cpp \  
  5.     AudioDumpInterface.cpp \  
  6.     AudioHardwareInterface.cpp  
  7. LOCAL_SHARED_LIBRARIES := \  
  8.     libcutils \  
  9.     libutils \  
  10.     libmedia \  
  11.     libhardware_legacy  
  12. ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)  
  13.   LOCAL_CFLAGS += -DGENERIC_AUDIO  
  14. endif  
  15. LOCAL_MODULE:= libaudiointerface  
  16. 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(),内容如下所示:

  1. AudioHardwareInterface* AudioHardwareInterface::create()  
  2. {  
  3.     AudioHardwareInterface* hw = 0;  
  4.     char value[PROPERTY_VALUE_MAX];  
  5. #ifdef GENERIC_AUDIO  
  6.     hw = new AudioHardwareGeneric();           
    // 使用通用的Audio硬件抽象层  
  7. #else 
  8.     if (property_get("ro.kernel.qemu", value, 0)) {  
  9.         LOGD("Running in emulation - using generic audio driver");  
  10.         hw = new AudioHardwareGeneric();  
  11.     }  
  12.     else {  
  13.         LOGV("Creating Vendor Specific AudioHardware");  
  14.         hw = createAudioHardware();            
    // 使用实际的Audio硬件抽象层  
  15.     }  
  16. #endif  
  17.     if (hw->initCheck() != NO_ERROR) {  
  18.         LOGW("Using stubbed audio hardware. 
    No sound will be produced."
    );  
  19.         delete hw;  
  20.         hw = new AudioHardwareStub();          
    // 使用实际的Audio硬件抽象层的桩实现  
  21.     }  
  22. #ifdef DUMP_FLINGER_OUT  
  23.     hw = new AudioDumpInterface(hw);           
    // 使用实际的Audio的Dump接口实现  
  24. #endif  
  25.     return hw;  

根据GENERIC_AUDIO、DUMP_FLINGER_OUT等宏选择创建几个不同的Audio硬件抽象层,最后返回的接口均为 AudioHardwareInterface类型的指针。

1.用桩实现的Audio硬件抽象层

AudioHardwareStub.h和AudioHardwareStub.cpp是一个Android硬件抽象层的桩实现方式。这个实现不操 作实际的硬件和文件,它所进行的是空操作,在系统没有实际的Audio设备时使用这个实现,来保证系统的正常工作。如果使用这个硬件抽象层,实际上 Audio系统的输入和输出都将为空。

AudioHardwareStub.h定义了AudioStreamOutStub 和AudioStreamInStub类的情况  如下所示:

  1. class AudioStreamOutStub : public AudioStreamOut {  
  2. public:  
  3.     virtual status_t    set(int format, int 
    channelCount, uint32_t sampleRate);  
  4.     virtual uint32_t    sampleRate() const { return 44100; }  
  5.     virtual size_t      bufferSize() const { return 4096; }  
  6.     virtual int         channelCount() const { return 2; }  
  7.     virtual int         format() const { return
     AudioSystem::PCM_16_BIT; }  
  8.     virtual uint32_t    latency() const { return 0; }  
  9.     virtual status_t    setVolume(float volume) { return NO_ERROR; }  
  10.     virtual ssize_t     write(const void* buffer, size_t bytes);  
  11.     virtual status_t    standby();  
  12.     virtual status_t    dump(int fd, const Vector& args);  
  13. };  
  14. class AudioStreamInStub : public AudioStreamIn {  
  15. public:  
  16.     virtual status_t set(int format, int
     channelCount, uint32_t sampleRate, AudioSystem::   
    audio_in_acoustics acoustics);  
  17.     virtual uint32_t    sampleRate() const { return 8000; }  
  18.     virtual size_t      bufferSize() const { return 320; }  
  19.     virtual int         channelCount() const { return 1; }  
  20.     virtual int         format() const { return
     AudioSystem::PCM_16_BIT; }  
  21.     virtual status_t    setGain(float gain) { return NO_ERROR; }  
  22.     virtual ssize_t     read(void* buffer, ssize_t bytes);  
  23.     virtual status_t    dump(int fd, const Vector& args);  
  24.     virtual status_t    standby() { return NO_ERROR; }  
  25. }; 

上面实际上使用了最简单模式,只是用固定的参数(缓冲区大小、采样率、通道数),以及将一些函数直接无错误返回。

使用AudioHardwareStub类来继承AudioHardwareBase,事实上也就是继承 AudioHardwareInterface。

  1. class AudioHardwareStub : public  AudioHardwareBase  
  2. {  
  3. public:  
  4.                         AudioHardwareStub();  
  5.     virtual             ~AudioHardwareStub();  
  6.     virtual status_t    initCheck();  
  7.     virtual status_t    setVoiceVolume(float volume);  
  8.     virtual status_t    setMasterVolume(float volume);  
  9.     virtual status_t    setMicMute(bool state)
    { mMicMute = state;  
    return  NO_ERROR; }  
  10.     virtual status_t    getMicMute(bool* state)
    { *state = mMicMute ; 
    return NO_ERROR; }  
  11.     virtual status_t    setParameter(const 
    char* key, const char* value)  
  12.             { return NO_ERROR; }  
  13.     virtual AudioStreamOut* openOutputStream(       //打开输出流  
  14.                                 int format=0,  
  15.                                 int channelCount=0,  
  16.                                 uint32_t sampleRate=0,  
  17.                                 status_t *status=0);  
  18.  
  19.     virtual AudioStreamIn* openInputStream(     //打开输入流  
  20.                                 int format,  
  21.                                 int channelCount,  
  22.                                 uint32_t sampleRate,  
  23.                                 status_t *status,  
  24.                                 AudioSystem::audio_in_acoustics acoustics);  
  25. // …… 省略部分内容  
  26. };

7.3.2  AudioFlinger中自带Audio硬件抽象层实现(2)

在实现过程中,为了保证声音可以输入和输出,这个桩实现的主要内容是实现AudioStreamOutStub和 AudioStreamInStub类的读/写函数。实现如下所示:

  1. ssize_t AudioStreamOutStub::write(const void* buffer, size_t bytes)  
  2. {  
  3.     usleep(bytes * 1000000 / sizeof(int16_t) /
    channelCount() / sampleRate());  
  4.     return bytes;  
  5. }  
  6. ssize_t AudioStreamInStub::read(void* buffer, ssize_t bytes)  
  7. {  
  8.     usleep(bytes * 1000000 / sizeof(int16_t) / 
    channelCount() / sampleRate());  
  9.     memset(buffer, 0, bytes);  
  10.     return bytes;  

由此可见,使用这个接口进行音频的输入和输出时,和真实的设备没有关系,输出和输入都使用延时来完成。对于输出的情况,不会有声音播出,但是返回值 表示全部内容已经输出完成;对于输入的情况,将返回全部为0的数据。

此外,这种实现支持默认的参数,如果用set()函数设置的参数与默认参数不一致,还会返回错误。

2.Android通用的Audio硬件抽象层

AudioHardwareGeneric.h和AudioHardwareGeneric.cpp是Android通用的一个Audio硬件抽象 层。与前面的桩实现不同,这是一个真正能够使用的Audio硬件抽象层,但是它需要Android的一种特殊的声音驱动程序的支持。

与前面类似,AudioStreamOutGeneric、AudioStreamInGeneric和AudioHardwareGeneric 这3个类分别继承Audio硬件抽象层的3个接口。

  1. class AudioStreamOutGeneric : public AudioStreamOut {  
  2.     // ...... 通用Audio输出类的接口  
  3. };  
  4. class AudioStreamInGeneric : public AudioStreamIn {  
  5.     // ...... 通用Audio输入类的接口  
  6. };  
  7. class AudioHardwareGeneric : public AudioHardwareBase  
  8. {  
  9.     // ...... 通用Audio控制类的接口  
  10. }; 

在AudioHardwareGeneric.cpp的实现中,使用的驱动程序是/dev/eac,这是一个非标准程序,定义设备的路径如下所示:

  1. static char const * const kAudioDeviceName = "/dev/eac"

对于Linux操作系统,这个驱动程序在文件系统中的节点主设备号为10,次设备号自动生成。

提示:eac是Linux中的一个misc驱动程序,作为Android的通用音频驱动,写设备表示放音,读设备表示录音。

在AudioHardwareGeneric的构造函数中,打开这个驱动程序的设备节点。

  1. AudioHardwareGeneric::AudioHardwareGeneric()  
  2.     : mOutput(0), mInput(0),  mFd(-1), mMicMute(false)  
  3. {  
  4.     mFd = ::open(kAudioDeviceName, O_RDWR); //打开通用音频设备的节点  

这个音频设备是一个比较简单的驱动程序,没有很多设置接口,只是用写设备表示录音,读设备表示放音。放音和录音支持的都是16位的PCM。

  1. ssize_t AudioStreamOutGeneric::write(const void* buffer, size_t bytes)  
  2. {  
  3.     Mutex::Autolock _l(mLock);  
  4.     return ssize_t(::write(mFd, buffer, bytes));    //写入硬件设备  
  5. }  
  6. ssize_t AudioStreamInGeneric::read(void* buffer, ssize_t bytes)  
  7. {  
  8.     AutoMutex lock(mLock);  
  9.     if (mFd < 0) {  
  10.         return NO_INIT;  
  11.     }  
  12.     return ::read(mFd, buffer, bytes);              // 读取硬件设备  

虽然AudioHardwareGeneric是一个可以真正工作的Audio硬件抽象层,但是这种实现方式非常简单,不支持各种设置,参数也只能 使用默认的。而且,这种驱动程序需要在Linux核心加入eac驱动程序的支持。

3.提供Dump功能的Audio硬件抽象层

AudioDumpInterface.h和AudioDumpInterface.cpp是一个提供了Dump功能的Audio硬件抽象层,它所 起到的作用就是将输出的Audio数据写入到文件中。

AudioDumpInterface本身支持Audio的输出功能,不支持输入功能。AudioDumpInterface.h中的类定义如下:

  1. class AudioStreamOutDump : public AudioStreamOut {  
  2. public:  
  3.                         AudioStreamOutDump
    ( AudioStreamOut* FinalStream);  
  4.                         ~AudioStreamOutDump();  
  5.                         virtual ssize_t     write
    (
    const void* buffer, size_t bytes);  
  6.     virtual uint32_t    sampleRate() const { return 
    mFinalStream->sampleRate(); }  
  7.     virtual size_t      bufferSize() const { return 
    mFinalStream->bufferSize(); }  
  8.     virtual int         channelCount() const { return
     mFinalStream->channelCount(); }  
  9.     virtual int         format() const { return
     mFinalStream->format(); }  
  10.     virtual uint32_t    latency() const { return
     mFinalStream->latency(); }  
  11.     virtual status_t    setVolume(float volume)  
  12.                             { return 
    mFinalStream->setVolume(volume); }  
  13.     virtual status_t    standby();  
  14.     // …… 省略部分内容  
  15. };  
  16. class AudioDumpInterface : public AudioHardwareBase  
  17. {  
  18.     virtual AudioStreamOut* openOutputStream(  
  19.                                 int format=0,  
  20.                                 int channelCount=0,  
  21.                                 uint32_t sampleRate=0,  
  22.                                 status_t *status=0);  
  23.     // …… 省略部分内容  

只实现了AudioStreamOut,没有实现AudioStreamIn,因此这个Audio硬件抽象层只支持输出功能,不支持输入功能。

输出文件的名称被定义为:

  1. #define FLINGER_DUMP_NAME "/data/FlingerOut.pcm" 

在AudioDumpInterface.cpp的AudioStreamOut所实现的写函数中,写入的对象就是这个文件。

  1. ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes)  
  2. {  
  3.     ssize_t ret;  
  4.     ret = mFinalStream->write(buffer, bytes);  
  5.     if(!mOutFile && gFirst) {  
  6.         gFirst = false;  
  7.         mOutFile = fopen(FLINGER_DUMP_NAME, "r");  
  8.         if(mOutFile) {  
  9.             fclose(mOutFile);  
  10.             mOutFile = fopen(FLINGER_DUMP_NAME, "ab");
    // 打开输出文件  
  11.         }  
  12.     }  
  13.     if (mOutFile) {  
  14.         fwrite(buffer, bytes, 1, mOutFile);  
    // 写文件输出内容  
  15.     }  
  16.     return ret;  

如果文件是打开的,则使用追加方式写入。因此使用这个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硬件抽象层也是可以处理这种情况的。

====================================================







阅读(6061) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-11-12 17:25:54

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com