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硬件抽象層也是可以處理這種情況的。