【转】Audio系统综述

7.1  Audio系统综述   

Audio系统在Android中负责音频方面的数据流传输和控制功能,也负责音频设备的管理。这个部分作为Android的Audio系统的输入/输出层次,一般负责播放PCM声音输出和从外部获取PCM声音,以及管理声音设备和设置。

Audio系统主要分成如下几个层次:

1.�(1)media库提供的Audio系统本地部分接口;

2.�(2)AudioFlinger作为Audio系统的中间层;

3.�(3)Audio的硬件抽象层提供底层支持;

4.�(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��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/目录中,主要的头文件如下:

n  AudioSystem.h:media库的Audio部分对上层的总管接口;

n  IAudioFlinger.h:需要下层实现的总管接口;

n  AudioTrack.h:放音部分对上接口;

n  IAudioTrack.h:放音部分需要下层实现的接口;

n  AudioRecorder.h:录音部分对上接口;

n  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<IAudioTrack> createTrack(           // 获得音频输出接口(Track)

                                pid_t pid,

                                int streamType,

                                uint32_t sampleRate,

                                int format,

                                int channelCount,

                                int frameCount,

                                uint32_t flags,

                                const sp<IMemory>& 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<IAudioRecord> 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个类的支持:

n  android.media.AudioSystem:负责Audio系统的总体控制;

n  android.media.AudioTrack:负责Audio系统的输出环节;

n  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.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硬件抽象层实现

在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硬件抽象层的实现。

n  AudioHardwareGeneric.cpp:实现基于特定驱动的通用Audio硬件抽象层;

n  AudioHardwareStub.cpp:实现Audio硬件抽象层的一个桩;

n  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<String16>& 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<String16>& 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);

// …… 省略部分内容

};

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

ssize_t AudioStreamOutStub::write(const void* buffer, size_t bytes)

{

    usleep(bytes * 1000000 / sizeof(int16_t) / channelCount() / sampleRate());

    return bytes;

}

ssize_t AudioStreamInStub::read(void* buffer, ssize_t bytes)

{

    usleep(bytes * 1000000 / sizeof(int16_t) / channelCount() / sampleRate());

    memset(buffer, 0, bytes);

    return bytes;

}

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

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

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

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

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

class AudioStreamOutGeneric : public AudioStreamOut {

    // ...... 通用Audio输出类的接口

};

class AudioStreamInGeneric : public AudioStreamIn {

    // ...... 通用Audio输入类的接口

};

class AudioHardwareGeneric : public AudioHardwareBase

{

    // ...... 通用Audio控制类的接口

};

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

static char const * const kAudioDeviceName = "/dev/eac";

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

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

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

AudioHardwareGeneric::AudioHardwareGeneric()

    : mOutput(0), mInput(0),  mFd(-1), mMicMute(false)

{

    mFd = ::open(kAudioDeviceName, O_RDWR);  //打开通用音频设备的节点

}

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

ssize_t AudioStreamOutGeneric::write(const void* buffer, size_t bytes)

{

    Mutex::Autolock _l(mLock);

    return ssize_t(::write(mFd, buffer, bytes)); //写入硬件设备

}

ssize_t AudioStreamInGeneric::read(void* buffer, ssize_t bytes)

{

    AutoMutex lock(mLock);

    if (mFd < 0) {

        return NO_INIT;

    }

    return ::read(mFd, buffer, bytes);              // 读取硬件设备

}

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

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

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

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

class AudioStreamOutDump : public AudioStreamOut {

public:

                        AudioStreamOutDump( AudioStreamOut* FinalStream);

                        ~AudioStreamOutDump();

                        virtual ssize_t     write(const void* buffer, size_t bytes);

    virtual uint32_t    sampleRate() const { return mFinalStream->sampleRate(); }

    virtual size_t      bufferSize() const { return mFinalStream->bufferSize(); }

    virtual int         channelCount() const { return mFinalStream->channelCount(); }

    virtual int         format() const { return mFinalStream->format(); }

    virtual uint32_t    latency() const { return mFinalStream->latency(); }

    virtual status_t    setVolume(float volume)

                            { return mFinalStream->setVolume(volume); }

    virtual status_t    standby();

    // …… 省略部分内容

};

class AudioDumpInterface : public AudioHardwareBase

{

    virtual AudioStreamOut* openOutputStream(

                                int format=0,

                                int channelCount=0,

                                uint32_t sampleRate=0,

                                status_t *status=0);

    // …… 省略部分内容

}

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

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

#define FLINGER_DUMP_NAME "/data/FlingerOut.pcm"

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

ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes)

{

    ssize_t ret;

    ret = mFinalStream->write(buffer, bytes);

    if(!mOutFile && gFirst) {

        gFirst = false;

        mOutFile = fopen(FLINGER_DUMP_NAME, "r");

        if(mOutFile) {

            fclose(mOutFile);

            mOutFile = fopen(FLINGER_DUMP_NAME, "ab");      // 打开输出文件

        }

    }

    if (mOutFile) {

        fwrite(buffer, bytes, 1, mOutFile);            // 写文件输出内容

    }

    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硬件抽象层也是可以处理这种情况的。

 

 原文地址 http://www.360doc.com/showWeb/0/0/45289725.aspx

               http://www.360doc.com/content/11/0428/11/3779243_112887503.shtml

               

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值