Audio系統(tǒng)和上層接口
在Android中,Audio系統(tǒng)自上而下由Java的Audio類、Audio本地框架類、AudioFlinger和Audio的硬件抽象層幾個部分組成。 è 7.2.1 Audio系統(tǒng)的各個層次Audio系統(tǒng)的各層次情況如下所示。 Audio本地框架類是libmedia.so的一個部分,這些Audio接口對上層提供接口,由下層的本地代碼去實現(xiàn)。 AudioFlinger繼承l(wèi)ibmeida中的接口,提供實現(xiàn)庫libaudiofilnger.so。這部分內(nèi)容沒有自己的對外頭文件,上層調(diào)用的只是libmedia本部分的接口,但實際調(diào)用的內(nèi)容是libaudioflinger.so。 Audio使用JNI和Java對上層提供接口,JNI部分通過調(diào)用libmedia庫提供的接口來實現(xiàn)。 Audio的硬件抽象層提供到硬件的接口,供AudioFlinger調(diào)用。Audio的硬件抽象層實際上是各個平臺開發(fā)過程中需要主要關(guān)注和獨立完成的部分。 提示:Android的Audio系統(tǒng)不涉及編解碼環(huán)節(jié),只是負(fù)責(zé)上層系統(tǒng)和底層Audio硬件的交互,一般以PCM作為輸入/輸出格式。 在Android的Audio系統(tǒng)中,無論上層還是下層,都使用一個管理類和輸出輸入兩個類來表示整個Audio系統(tǒng),輸出輸入兩個類負(fù)責(zé)數(shù)據(jù)通道。在各個層次之間具有對應(yīng)關(guān)系,如表7-1所示所示。 表7-1 Android各個層次的對應(yīng)關(guān)系
è 7.2.2 media庫中的Audio框架部分Android的Audio系統(tǒng)的核心框架在media庫中提供,對上面主要實現(xiàn)AudioSystem、AudioTrack和AudioRecorder三個類。 提供了IAudioFlinger類接口,在這個類中,可以獲得IAudioTrack和IAudioRecorder兩個接口,分別用于聲音的播放和錄制。AudioTrack和AudioRecorder分別通過調(diào)用IAudioTrack和IAudioRecorder來實現(xiàn)。 Audio系統(tǒng)的頭文件在frameworks/base/include/media/目錄中,主要的頭文件如下:
IaudioFlinger.h、IAudioTrack.h和IAudioRecorder.h這三個接口通過下層的繼承來實現(xiàn)(即AudioFlinger)。AudioFlinger.h、AudioTrack.h和AudioRecorder.h是對上層提供的接口,它們既供本地程序調(diào)用(例如聲音的播放器、錄制器等),也可以通過JNI向Java層提供接口。 meida庫中Audio部分的結(jié)構(gòu)如圖7-2所示。 圖7-2 meida庫中Audio部分的結(jié)構(gòu) 從功能上看,AudioSystem負(fù)責(zé)的是Audio系統(tǒng)的綜合管理功能,而AudioTrack和AudioRecorder分別負(fù)責(zé)音頻數(shù)據(jù)的輸出和輸入,即播放和錄制。 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數(shù)據(jù)輸出類型 // …… 省略部分內(nèi)容 }; enum audio_format { // Audio數(shù)據(jù)格式 FORMAT_DEFAULT = 0, PCM_16_BIT, PCM_8_BIT, INVALID_FORMAT }; enum audio_mode { // Audio模式 // …… 省略部分內(nèi)容 }; 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, }; // …… 省略部分內(nèi)容 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); // …… 省略部分內(nèi)容 }; 在Audio系統(tǒng)的幾個枚舉值中,audio_routes是由單獨的位來表示的,而不是由順序的枚舉值表示,因此這個值在使用過程中可以使用“或”的方式。例如,表示聲音可以既從耳機(EARPIECE)輸出,也從揚聲器(SPEAKER)輸出,這樣是否能實現(xiàn),由下層提供支持。在這個類中,set/get等接口控制的也是相關(guān)的內(nèi)容,例如Audio聲音的大小、Audio的模式、路徑等。 AudioTrack是Audio輸出環(huán)節(jié)的類,其中最重要的接口是write(),主要的函數(shù)如下所示。 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, // 音頻的通道數(shù) int frameCount = 0, // 音頻的幀數(shù) 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); // …… 省略部分內(nèi)容 } AudioRecord是Audio輸入環(huán)節(jié)的類,其中最重要的接口為read(),主要的函數(shù)如下所示。 class AudioRecord { public: AudioRecord(int streamType, uint32_t sampleRate = 0, // 音頻的采樣律 int format = 0, // 音頻的格式(例如8位或者16位的PCM) int channelCount = 0, // 音頻的通道數(shù) int frameCount = 0, // 音頻的幀數(shù) 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); // …… 省略部分內(nèi)容 } AudioTrack和AudioRecord的read/write函數(shù)的參數(shù)都是內(nèi)存的指針及其大小,內(nèi)存中的內(nèi)容一般表示的是Audio的原始數(shù)據(jù)(PCM數(shù)據(jù))。這兩個類還涉及Auido數(shù)據(jù)格式、通道數(shù)、幀數(shù)目等參數(shù),可以在建立時指定,也可以在建立之后使用set()函數(shù)進行設(shè)置。 在libmedia庫中提供的只是一個Audio系統(tǒng)框架,AudioSystem、AudioTrack和AudioRecord分別調(diào)用下層的IAudioFlinger、IAudioTrack和IAudioRecord來實現(xiàn)。另外的一個接口是IAudioFlingerClient,它作為向IAudioFlinger中注冊的監(jiān)聽器,相當(dāng)于使用回調(diào)函數(shù)獲取IAudioFlinger運行時信息。 è 7.2.3 AudioFlinger本地代碼AudioFlinger是Audio系統(tǒng)的中間層,在系統(tǒng)中起到服務(wù)作用,它主要作為libmedia提供的Audio部分接口的實現(xiàn),其代碼路徑為: frameworks/base/libs/audioflinger AudioFlinger的核心文件是AudioFlinger.h和AudioFlinger.cpp,提供了類AudioFlinger,這個類是一個IAudioFlinger的實現(xiàn),其主要接口如下所示: class AudioFlinger : public BnAudioFlinger, public IBinder::DeathRecipient { public: // …… 省略部分內(nèi)容 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); // …… 省略部分內(nèi)容 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()創(chuàng)建音頻的輸出設(shè)備IAudioTrack,openRecord()創(chuàng)建音頻的輸入設(shè)備IAudioRecord。另外包含的就是一個get/set接口,用于控制。 AudioFlinger構(gòu)造函數(shù)片段如下所示: 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); } // …… 省略部分內(nèi)容 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在初始化之后,首先獲得放音設(shè)備,然后為混音器(Mixer)建立線程,接著建立放音設(shè)備線程,在線程中獲得放音設(shè)備。 在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, // 靜態(tài)地創(chuàng)建函數(shù) int32_t sampleRate, int quality=DEFAULT); virtual ~AudioResampler(); virtual void init() = 0; virtual void setSampleRate(int32_t inSampleRate); // 設(shè)置重采樣率 virtual void setVolume(int16_t left, int16_t right); // 設(shè)置音量 virtual void resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider) = 0; }; 這個音頻重取樣工具包含3種質(zhì)量:低等質(zhì)量(LOW_QUALITY)將使用線性差值算法實現(xiàn);中等質(zhì)量(MED_QUALITY)將使用立方差值算法實現(xiàn);高等質(zhì)量(HIGH_ QUALITY)將使用FIR(有限階濾波器)實現(xiàn)。AudioResampler中的AudioResamplerOrder1是線性實現(xiàn),AudioResamplerCubic.*文件提供立方實現(xiàn)方式,AudioResamplerSinc.*提供FIR實現(xiàn)。 AudioMixer.h和AudioMixer.cpp中實現(xiàn)的是一個Audio系統(tǒng)混音器,它被AudioFlinger調(diào)用,一般用于在聲音輸出之前的處理,提供多通道處理、聲音縮放、重取樣。AudioMixer調(diào)用了AudioResampler。 提示: AudioFlinger本身的實現(xiàn)通過調(diào)用下層的Audio硬件抽象層的接口來實現(xiàn)具體的功能,各個接口之間具有對應(yīng)關(guān)系。 è 7.2.4 Audio系統(tǒng)的JNI代碼Android的Audio部分通過JNI向Java層提供接口,在Java層可以通過JNI接口完成Audio系統(tǒng)的大部分操作。 Audio JNI部分的代碼路徑為:frameworks/base/core/jni。 其中,主要實現(xiàn)的3個文件為:android_media_AudioSystem.cpp、android_media_Audio Track.cpp和android_media_AudioRecord.cpp,它們分別對應(yīng)了Android Java框架中的3個類的支持:
在Android的Java層中,可以對Audio系統(tǒng)進行控制和數(shù)據(jù)流操作,對于控制操作,和底層的處理基本一致;但是對于數(shù)據(jù)流操作,由于Java不支持指針,因此接口被封裝成了另外的形式。 例如,對于音頻輸出,android_media_AudioTrack.cpp提供的是寫字節(jié)和寫短整型的接口類型。 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); // …… 省略部分內(nèi)容 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; } } // …… 省略部分內(nèi)容 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接口,它們一般是通過調(diào)用AudioTrack的write()函數(shù)來完成的,只是在Java的數(shù)據(jù)類型和C++的指針中做了一步 轉(zhuǎn)換。 è 7.2.5 Audio系統(tǒng)的Java代碼Android的Audio系統(tǒng)的相關(guān)類在android.media 包中,Java部分的代碼路徑為: frameworks/base/media/java/android/media Audio系統(tǒng)主要實現(xiàn)了以下幾個類:android.media.AudioSystem、android.media. Audio Track、android.media.AudioRecorder、android.media.AudioFormat。前面的3個類和本地代碼是對應(yīng)的,AudioFormat提供了一些Audio相關(guān)類型的枚舉值。 注意:在Audio系統(tǒng)的Java代碼中,雖然可以通過AudioTrack和AudioRecorder的write()和read()接口,在Java層對Audio的數(shù)據(jù)流進行操作。但是,更多的時候并不需要這樣做,而是在本地代碼中直接調(diào)用接口進行數(shù)據(jù)流的輸入/輸出,而Java層只進行控制類操作,不處理數(shù)據(jù)流。 |
|