在Android中,Audio系統(tǒng)自上而下由Java的Audio類、Audio本地框架類、AudioFlinger和Audio的硬件抽象層幾個部分組成。
Audio系統(tǒng)的各層次情況如下所示。
在Android的Audio系統(tǒng)中,無論上層還是下層,都使用一個管理類和輸出輸入兩個類來表示整個Audio系統(tǒng),輸出輸入兩個類負責(zé)數(shù)據(jù)通道。在各個層次之間具有對應(yīng)關(guān)系,如表7-1所示所示。
表7-1 Android各個層次的對應(yīng)關(guān)系
Audio管理環(huán)節(jié) | Audio輸出 | Audio輸入 | |
Java層 | android.media.AudioSystem | android.media.AudioTrack | android.media.AudioRecorder |
本地框架層 | AudioSystem | AudioTrack | AudioRecorder |
AudioFlinger | IAudioFlinger | IAudioTrack | IAudioRecorder |
硬件抽象層 | AudioHardwareInterface | AudioStreamOut | AudioStreamIn |
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/目錄中,主要的頭文件如下:
n
n
n
n
n
n
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負責(zé)的是Audio系統(tǒng)的綜合管理功能,而AudioTrack和AudioRecorder分別負責(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運行時信息。
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。
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個類的支持:
n
n
n
在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)換。
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)類型的枚舉值。