小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Android源碼分析:AudioPolicy

 ScorpioRen360 2013-08-15

在創(chuàng)建一個AudioPolicyService對象時,主要是:

1. 創(chuàng)建兩個AudioCommand線程,一個線程用于Tone的播放,另一個用于聲音的音量及其它參數(shù)設(shè)置;

2.創(chuàng)建音頻策略管理器(AudioPolicyManager)。Android Frameworks為音頻策略管理器定義了統(tǒng)一的接口--AudioPolicyInterface,并提供一個缺省的音頻管理器--AudioPolicyManagerBase,它為運行在模擬器上Android所使用,也可以使用宏激活該通用管理器。不同的硬件廠商,可以編寫一個繼承AudioPolicyInterface的子類,針對自己的硬件平臺,實現(xiàn)自己的音頻策略管理。

在音頻策略服務(AudioPolicyService)中,會根據(jù)一定的條件去判斷創(chuàng)建何種音頻策略管理器:

AudioPolicyService::AudioPolicyService()
: BnAudioPolicyService() , mpPolicyManager(NULL)
{
char value[PROPERTY_VALUE_MAX];
// start tone playback thread
mTonePlaybackThread = new AudioCommandThread(String8(“”));
// start audio commands thread
mAudioCommandThread = new AudioCommandThread(String8(“ApmCommandThread”));

#if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST)
mpPolicyManager = new AudioPolicyManagerBase(this);//
通用類型
LOGV(“build for GENERIC_AUDIO – using generic audio policy”);
#else
// if running in emulation – use the emulator driver
if (property_get(“ro.kernel.qemu”, value, 0)) {
LOGV(“Running in emulation – using generic audio policy”);
mpPolicyManager = new AudioPolicyManagerBase(this);//Android
模擬器上,注意將this指針傳遞了過去,實際上AudioPolicyService也繼承了AudioPolicyClientInterface的緣故,因此可以把它看作該接口的指針。在音頻策略管理器AudioPolicyManagerBase中會通過AudioPolicyClientInterface指針去調(diào)用AudioFlinger
}
else {
LOGV(“Using hardware specific audio policy”);
mpPolicyManager = createAudioPolicyManager(this);//
由硬件平臺廠商實現(xiàn)該創(chuàng)建函數(shù),然后返回自己的AudioPolicyManager。亦即,硬件平臺廠商應實現(xiàn)一個自己的AudioPolicyInterface子類,然后在該創(chuàng)建函數(shù)中返回該子類的對象
}
#endif

// load properties
property_get(“ro.camera.sound.forced”, value, “0″);
mpPolicyManager->setSystemProperty(“ro.camera.sound.forced”, value);
}

下圖反映了幾個類之間的關(guān)系:AudioPolicyService繼承自BnAudioPolicyService,所以它提供了IAudioPolicyService接口的真正實現(xiàn),可以通過該接口跨進程調(diào)用到它。AudioPolicyService也繼承了AudioPolicyClientInterface,所以它實現(xiàn)了該抽象類的接口,其實現(xiàn)是通過AudioSystem調(diào)用到AudioFlinger(下圖AudioPolicyServiceAudioFlinger的虛線所示)。如上面代碼所示,在創(chuàng)建AudioPolicyService時,會創(chuàng)建一個音頻策略管理器,如Android默認的管理器AudioPolicyManagerBase,也可能創(chuàng)建的是硬件平臺廠家提供的音頻管理器,這些管理器實現(xiàn)了AudioPolicyInterface接口。在創(chuàng)建音頻管理器時,將this指針傳遞給了它,意味著音頻管理器可以通過AudioPolicyClientInterface接口指針(圖中策略管理器到AudioPolicyClientInterface的虛線)來使用AudioPolicyService,進而使用AudioFlinger。

 

 

 

音頻策略管理器(Audio Policy Manager

音頻策略管理器用于管理聲音的輸入輸出路由,它決定各種類型的聲音(即流類型)優(yōu)先送往系統(tǒng)中的哪種輸出設(shè)備,或優(yōu)先采用哪種輸入設(shè)備進行聲音的采樣。如手機連有藍牙耳機或耳機(HeadPhone)時,將優(yōu)先使用它們作為輸入輸出設(shè)備。在Android中,有一個通用實現(xiàn):類AudioPolicyManagerBase。硬件平臺廠家往往需要實現(xiàn)自己的音頻策略管理器,所有的重新實現(xiàn)必繼承抽象類AudioPolicyInterface,該繼承類定義了統(tǒng)一的接口函數(shù)。繼承自該抽象類的通用實現(xiàn)AudioPolicyManagerBase位于文件frameworks/base/services/audioflinger/AudioPolicyManagerBase.cpp中。

在進行播放時,需使用策略管理器的getOutput函數(shù)去獲得一個音頻輸入輸出句柄audio_io_handle_t。這個句柄用來標識策略管理器中使用的一個數(shù)據(jù)結(jié)構(gòu):音頻輸出描述符AudioOutputDescriptor。一個描述符對應著一次音頻輸出,由輸出句柄標識。音頻輸出描述符包含了某音頻輸出對應的輸出設(shè)備、音量、格式、聲道、采樣率等信息。在策略管理器中,也維護著句柄和描述符的映射表:

KeyedVector<audio_io_handle_t, AudioOutputDescriptor *> mOutputs;

音頻輸入輸出句柄audio_io_handle_t,實際上是一個整型數(shù),是在AduioFlinger打開輸出(openOutput)時遞增分配一個整型id號,用于標示新創(chuàng)建的播放線程(DirectOutputThreadMixerThread)。這個id號和新創(chuàng)建的線程作為數(shù)據(jù)對添加到向量表mPlaybackThreads中。AudioFlinger中維護的播放線程向量表如下,由句柄這個id號標識:

DefaultKeyedVector< int, sp<PlaybackThread> > mPlaybackThreads;

因此,在策略管理中,可以由句柄得到對應的音頻輸出描述符,進而可以得到對應的音頻相關(guān)信息和輸出設(shè)備。在AudioFlinger中,可以由句柄得到對應的播放線程(該線程用于將音頻數(shù)據(jù)送往HAL音頻硬件)。

Android中,將聲音區(qū)分為不同的流類型。不同的流類型往往使用不同的輸入輸出設(shè)備進行輸出,這就是音頻策略。流類型由AudioSystem統(tǒng)一定義,但音頻策略由平臺實現(xiàn)者定義。因不同的平臺廠商往往有自己的輸入輸出設(shè)備,音頻的輸入輸出與這些設(shè)備有很大的相關(guān)性。因此,音頻策略由平臺廠商定義。在通用的實現(xiàn)AudioPolicyManagerBase中,定義有4種音頻策略類型:

enum routing_strategy {
STRATEGY_MEDIA, //
媒體類型
STRATEGY_PHONE, //
電話類型
STRATEGY_SONIFICATION, //
通知類型
STRATEGY_DTMF, //DTMF
類型
NUM_STRATEGIES
};

根據(jù)流類型(Stream Type),應該可以得到對應的音頻輸入輸出策略,這是由成員函數(shù)getStrategyForStreamAudioPolicyInterface中定義的接口之一)來實現(xiàn)。在通用實現(xiàn)AudioPolicyManagerBase中,由成員函數(shù)getStrategy真正去完成該功能。該函數(shù)實現(xiàn)的對應關(guān)系如下表:

Stream類型Strategy類型
AudioSystem::VOICE_CALLAudioPolicyManagerBase
::STRATEGY_PHONE
AudioSystem::BLUETOOTH_SCO
AudioSystem::RINGAudioPolicyManagerBase
::STRATEGY_SONIFICATION
AudioSystem::NOTIFICATION
AudioSystem::ALARM
AudioSystem::ENFORCED_AUDIBLE
AudioSystem::DTMFAudioPolicyManagerBase
::STRATEGY_DTMF
AudioSystem::SYSTEMAudioPolicyManagerBase
::STRATEGY_MEDIA
AudioSystem::TTS
AudioSystem::MUSIC

第一欄是流的類型,第二欄是音頻策略。從表中可以看出,某些流可以使用相同的音頻策略進行輸出或輸入。

通過流確定了策略之后,就可以確定輸入輸出設(shè)備。在通常情況下,一種策略又決定著聲音何種輸入輸出設(shè)備。 這由函數(shù)AudioPolicyManagerBase::getDeviceForStrategy來實現(xiàn):

  1. 若在調(diào)用時第二個實參為true,則表示直接從cache(見數(shù)組mDeviceForStrategy,在強制指定輸入輸出設(shè)備和某些設(shè)備連接上后會更新該數(shù)組)中獲取策略對應何種輸入或輸出設(shè)備;否則:
  2. 按照一定的優(yōu)先級順序,檢查有哪些可用的輸入輸出設(shè)備,然后選擇一個用來輸入輸出。下表概略地反映了由策略到選擇的設(shè)備的映射關(guān)系:
音頻策略選擇的輸入輸出設(shè)備
STRATEGY_DTMF非通話狀態(tài)則進入STRATEGY_MEDIA,通話狀態(tài)則進入STRATEGY_PHONE
STRATEGY_PHONEAudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSETAudioSystem::FORCE_BT_SCO

AudioSystem::DEVICE_OUT_WIRED_HEADPHONE

AudioSystem::DEVICE_OUT_WIRED_HEADSET

AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP

AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES

AudioSystem::DEVICE_OUT_EARPIECE

AudioSystem::FORCE_SPEAKER

STRATEGY_SONIFICATIONAudioSystem::DEVICE_OUT_SPEAKER(非通話狀態(tài)),通話狀態(tài)則進入STRATEGY_PHONE
STRATEGY_MEDIAAudioSystem::DEVICE_OUT_AUX_DIGITALAudioSystem::DEVICE_OUT_WIRED_HEADPHONE

AudioSystem::DEVICE_OUT_WIRED_HEADSET

AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP

AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES

AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER

AudioSystem::DEVICE_OUT_SPEAKER

 

有時,我們不希望策略管理器選定的設(shè)備,而希望自己選擇輸入輸出設(shè)備,在SDKAPI中,提供了兩個函數(shù)來為通話狀態(tài)強制選擇揚聲器和藍牙設(shè)備,這兩個函數(shù)API是:android.media.AudioManagersetSpeakerphoneOnsetBluetoothScoOn。它們?yōu)橥ㄔ挔顟B(tài)(AudioSystem.FOR_COMMUNICATION)強制指定語音輸入和輸出設(shè)備。這兩個API函數(shù)調(diào)用順序如下:android.media.AudioManager->android.media.AudioService->android.media.AudioSystem->JNI(文件android_media_AudioSystem.cpp)->AudioSystem-> AudioPolicyService->AudioPolicyManagerBase::setForceUse

通過上述調(diào)用后,函數(shù)setForceUse將記錄強制使用的設(shè)備,以優(yōu)先使用。下表第一欄是四種場景類型,第二欄是可以強制使用的語音輸入輸出設(shè)備:

場景類型(AudioSystem::force_use強制的輸入輸出設(shè)備類型取值
AudioSystem::FOR_COMMUNICATION(通話,包括通常的語音電話和VoIPAudioSystem::FORCE_SPEAKERAudioSystem::FORCE_BT_SCO,AudioSystem::FORCE_NONE
AudioSystem::FOR_MEDIA(多媒體播放)AudioSystem::FORCE_HEADPHONES AudioSystem::FORCE_BT_A2DP,

AudioSystem::FORCE_WIRED_ACCESSORY

AudioSystem::FORCE_NONE

AudioSystem::FOR_RECORD(錄音)AudioSystem::FORCE_BT_SCO,AudioSystem::FORCE_WIRED_ACCESSORY

AudioSystem::FORCE_NONE

AudioSystem::FOR_DOCK()AudioSystem::FORCE_NONE,AudioSystem::FORCE_BT_CAR_DOCK,

AudioSystem::FORCE_BT_DESK_DOCK,

AudioSystem::FORCE_WIRED_ACCESSORY

更多的強制選擇,可以修改setForceUse的對應檢查后,然后依據(jù)自己的代碼所在的層次,參照對setForceUse的調(diào)用層次,調(diào)用適當?shù)暮瘮?shù)。

 

對于各種輸入輸出設(shè)備是否可用,如藍牙耳機或線控耳機是否連接上,則是在Java層的android.media.AudioSystem中進行檢測處理。當這些外設(shè)連接狀態(tài)發(fā)生變化時,對應的模塊會廣播發(fā)送Intent,而android.media.AudioSystem中的AudioServiceBroadcastReceiver會接收到這些Intent,從而判斷出設(shè)備狀態(tài)變化,通過如下調(diào)用順序來修可用IO設(shè)備列表:android.media.AudioSystem->JNI層 -> AudioSystem-> AudioPolicyService -> AudioPolicyManagerBasesetDeviceConnectionState。

 

創(chuàng)建AudioPolicyManagerBase時,會在其構(gòu)造函數(shù)里

 

mpClientInterface = clientInterface;//指向AudioPolicyService的指針

for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {
mForceUse[i] = AudioSystem::FORCE_NONE;//
初始狀態(tài)無強制輸出
}

// devices available by default are speaker, ear piece and microphone
mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE |
AudioSystem::DEVICE_OUT_SPEAKER;//
初始默認的可用輸出設(shè)備
mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC;//
初始默認的輸入設(shè)備

#ifdef WITH_A2DP//一般情況下A2DP是打開的
mA2dpOutput = 0;
mDuplicatedOutput = 0;
mA2dpDeviceAddress = String8(“”);
#endif
mScoDeviceAddress = String8(“”);

// open hardware output
AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;
mHardwareOutput = //
打開一個默認到speaker的輸出
mpClientInterface->openOutput(&outputDesc->mDevice,
&outputDesc->mSamplingRate,
&outputDesc->mFormat,
&outputDesc->mChannels,
&outputDesc->mLatency,
outputDesc->mFlags);

if (mHardwareOutput == 0) {//失敗
LOGE(“Failed to initialize hardware output stream, samplingRate: %d, format %d, channels %d”,
outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannels);
} else {//
成功
addOutput(mHardwareOutput, outputDesc);//
添加句柄和描述到表中
setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER, true);//
為其指定輸出設(shè)備
//TODO: configure audio effect output stage here
}
updateDeviceForStrategy();//
更新數(shù)組(cache)中的輸出設(shè)備

從上面的代碼看出,在創(chuàng)建音頻管理器的初始時刻,就會打開一個默認的輸出,這個輸出句柄賦值給mHardwareOutput,并添加到對應的列表中。

 

可以使用函數(shù)setOutputDevice為輸出句柄(output)指定輸出設(shè)備:

void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t device, bool force, int delayMs)

它首先檢查是復制輸出,是否是A2DP輸出,然后調(diào)用mpClientInterface(實際調(diào)用到AudioFlinger)的setParameters來設(shè)置輸出設(shè)備。還要將輸出設(shè)備信息,更新到句柄output對應的輸出描述符中。

 

獲取音頻IO句柄

audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type stream,

uint32_t samplingRate,

uint32_t format,

uint32_t channels,

AudioSystem::output_flags flags)

該函數(shù)根據(jù)steam類型得到strategy,再進而得到輸出設(shè)備,然后創(chuàng)建一個輸出描述符AudioOutputDescriptor,儲存相關(guān)信息,最后將句柄和描述符添加到策略管理器維護的映射表中。注意:句柄的獲取實際調(diào)用的是mpClientInterfaceopenOutput(實際調(diào)用到AudioFlingeropenOutput去準備播放線程進行播放輸出)。

 

開始輸出

status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output,

AudioSystem::stream_type stream,

int session)

主要是調(diào)用setOutputDeviceouput句柄指定輸出設(shè)備,最后為其設(shè)定流對應的音量

 

主要是調(diào)用setOutputDeviceouput句柄恢復為默認的輸出設(shè)備

status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output,

AudioSystem::stream_type stream,

int session)

將輸出

獲得輸入句柄

audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource,

uint32_t samplingRate,

uint32_t format,

uint32_t channels,

AudioSystem::audio_in_acoustics acoustics,

AudioSystem::audio_input_clients *inputClientId)

 

開始輸入

status_t AudioPolicyManagerBase::startInput(audio_io_handle_t input)

通過輸入句柄得到對應的輸入描述符,然后通過mpClientInterface(實際調(diào)用到AudioFlinger)的setParametersAudioParameter::keyRoutinginputDesc->mDevice,AudioParameter::keyInputSource,inputDesc->mInputSource

 

停止輸入

status_t AudioPolicyManagerBase::stopInput(audio_io_handle_t input)

類似于輸入,通過setParametersAudioParameter::keyRouting對應的值修改為0

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多