<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                AudioPolicyService和AudioFlinger都駐留于一個進程,之前在MixerThread來歷一節中,曾簡單介紹過APS的創建,現在需要仔細觀察其中的內容。 1. 創建 AudioPolicyService AudioPolicyService的代碼如下所示: **AudioPolicyService.cpp** ~~~ AudioPolicyService::AudioPolicyService() :BnAudioPolicyService() , //mpPolicyManager是Audio系統中的另一種HAL對象,它的類型是AudioPolicyInterface mpPolicyManager(NULL) { char value[PROPERTY_VALUE_MAX]; //TonePlayback用于播放Tone音,Tone包括按鍵音等 mTonePlaybackThread = new AudioCommandThread(String8("")); //用于處理控制命令,例如路由切換、音量調節等 mAudioCommandThread = newAudioCommandThread(String8("ApmCommandThread")); #if (defined GENERIC_AUDIO) || (definedAUDIO_POLICY_TEST) //注意AudioPolicyManagerBase的構造函數,把this傳進去了。 mpPolicyManager = new AudioPolicyManagerBase(this); #else ... //使用硬件廠商實現的AudioPolicyInterface mpPolicyManager= createAudioPolicyManager(this); #endif //根據系統屬性來判斷照相機拍照時是否強制發聲。為了防止偷拍,強制按快門的時候必須發出聲音。 property_get("ro.camera.sound.forced",value, "0"); mpPolicyManager->setSystemProperty("ro.camera.sound.forced",value); } ~~~ 和AudioFlinger中的AudioHardwareInterface一樣,在APS中可以見到另外一個HAL層對象AudioPolicyInterface,為什么在APS中也會存在HAL對象呢? 如前所述,APS主要是用來控制Audio系統的,由于各個硬件廠商的控制策略不可能完全一致,所以Android把這些內容抽象成一個HAL對象。下面來看這個AudioPolicyInterface。 2. 對AudioPolicyInterface的分析 AudioPolicyInterface比AudioHardwareInterface簡單直接。這里,只需看幾個重點函數即可,代碼如下所示: **AudioPolicyInterface.h** ~~~ class AudioPolicyInterface { public: ...... //設置設備的連接狀態,這些設備有耳機、藍牙等 virtualstatus_t setDeviceConnectionState( AudioSystem::audio_devicesdevice, AudioSystem::device_connection_state state, const char *device_address) = 0; //設置系統Phone狀態,這些狀態包括通話狀態、來電狀態等 virtual void setPhoneState(int state) = 0; //設置force_use的config策略,例如通話中強制使用揚聲器 virtualvoid setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) = 0; /* audio_io_handle_t是int類型。這個函數的目的是根據傳入的參數類型 找到合適的輸出句柄。這個句柄,在目前的Audio系統代表AF中的某個工作線程。 還記得創建AudioTrack的時候傳入的那個output值嗎?它就是通過這個函數得來的。 關于這個問題,馬上會分析到 */ virtualaudio_io_handle_t getOutput( AudioSystem::stream_typestream, uint32_t samplingRate = 0, uint32_t format = AudioSystem::FORMAT_DEFAULT, uint32_t channels = 0, AudioSystem::output_flagsflags = AudioSystem::OUTPUT_FLAG_INDIRECT)= 0; //在下面這兩個函數后會介紹。它們的第二個參數表示使用的音頻流類型, virtualstatus_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) = 0; virtual status_t stopOutput(audio_io_handle_toutput, AudioSystem::stream_type stream) = 0; ...... //音量控制:設置不同音頻流的音量級別范圍,例如MUSIC有15個級別的音量 virtual void initStreamVolume(AudioSystem::stream_type stream, intindexMin, intindexMax) = 0; //設置某個音頻流類型的音量級,例如覺得music聲音太小時,可以調用這個函數提高音量級 virtualstatus_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index) = 0; } ~~~ 從上面的分析中可知,AudioPolicyInterface主要提供了一些設備切換管理和音量控制的接口。每個廠商都有各自的實現方式。目前,Audio系統提供了一個通用的實現類AudioPolicyManagerBase,以前這個類是放在hardware目錄下的,現在是放到framework目錄中了。圖7-12展示了AP和HAL類之間的關系: :-: ![](http://img.blog.csdn.net/20150802160810409?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖7-12 AudioPolicy和AudioPolicyInterface的關系 其中: - AudioPolicyService有一個AudioPolicyInterface類型的對象。 - AudioPolicyManagerBase有一個AudioPolicyClientInterace的對象。 AudioPolicyInterface中的一些函數后面會分析到,這些函數中有很多參數都是以AudioSystem::xxx方式出現的,那么 AudioSystem又是什么呢? 3. AudioSystem的介紹 AudioSystem是一個Native類,這個類在Java層有對應的Java類,其中定義了一些重要的類型,比如音頻流流程、音頻設備等,這些都在AudioSystem.h中。下面來看其中的一些定義。 (1)stream type(音頻流類型) 音頻流類型,我們已在AudioTrack中見識過了,其完整定義如下: ~~~ enum stream_type { DEFAULT =-1,//默認 VOICE_CALL = 0,//通話聲 SYSTEM = 1,//系統聲,例如開關機提示 RING = 2,//來電鈴聲 MUSIC = 3,//媒體播放聲 ALARM = 4,//鬧鐘等的警告聲 NOTIFICATION = 5,//短信等的提示聲 BLUETOOTH_SCO = 6,//藍牙SCO ENFORCED_AUDIBLE = 7,//強制發聲,照相機的快門聲就屬于這個類型 DTMF = 8,//DTMF,撥號盤的按鍵聲 TTS = 9,//文本轉語音,Text to Speech NUM_STREAM_TYPES }; ~~~ 音頻流類型有什么用呢?為什么要做這種區分呢?它主要與兩項內容有關: - 設備選擇:例如,之前在創建AudioTrack時,傳入的音頻流類型是MUSIC,當插上耳機時,這種類型的聲音只會從耳機中出來,但如果音頻流類型是RING,則會從耳機和揚聲器中同時出來。 - 音量控制:不同流類型音量級的個數不同,例如,MUSIC類型有15個級別可供用戶調節,而有些類型只有7個級別的音量。 (2)audio mode(聲音模式) audio mode和電話的狀態有直接關系。先看它的定義: ~~~ enum audio_mode { MODE_INVALID = -2, MODE_CURRENT = -1, MODE_NORMAL = 0, //正常,既不打電話,也沒有來電 MODE_RINGTONE,//有來電 MODE_IN_CALL,//通話狀態 NUM_MODES }; ~~~ 為什么Audio需要特別強調Phone的狀態呢?這必須和智能手機的硬件架構聯系上。先看智能手機的硬件架構,如圖7-13所示: :-: ![](http://img.blog.csdn.net/20150802160722654?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖7-13 智能手機的硬件架構圖 從圖7-13中看出了什么? - 系統有一個音頻DSP,聲音的輸入輸出都要經過它(不考慮藍牙的情況)。但它處理完的數字信號,需通過D/A(數/模)轉換后輸出到最終的設備上,這些設備包括揚聲器、聽筒、耳機等。 >[info] **注意**:所謂的設備切換,是指諸如揚聲器切換到聽筒的情況,而前面常提到的音頻輸出設備,應該指的是DSP。 - 系統有兩個核心處理器,一個是應用處理的核心,叫AP(Application Processor),可把它當做臺式機上的CPU,在這上面可以運行操作系統。另一個和手機通信相關,一般叫BP(Baseband Processor 基帶處理器),可把它當做臺式機上的“貓”。 - 從圖7-13中可看出,AP和BP都能向音頻DSP發送數據,它們在硬件上通路上互不干擾。于是就出現了一個問題,即如果兩個P同時往DSP發送數據,而互相之間沒有協調,就可能出現通話聲和音樂聲混雜的情況。誰還會用這樣的手機?所以打電話時,將由AP上的Phone程序主動設置Audio系統的mode,在這種mode下,Audio系統會做一些處理,例如把music音量調小等。 - 注意圖中的藍牙了嗎?它沒有像AP那樣直接和音頻DSP的相連,所以音頻數據需要單獨發給藍牙設備。如果某種聲音要同時從藍牙和揚聲器發出,亦即一份數據要往兩個地方發送,便滿足了AudioFlinger中DuplicatingThread出現的現實要求。 注意:藍牙設備實際上會建立兩條數據通路:SCO和A2DP。A2DP和高質量立體聲有關,且必須由AudioFlinger向它發送數據。所以“音頻數據需要單獨發送給藍牙設備”,這個設備實際上是指藍牙的A2DP設備。藍牙技術很復雜,有興趣的讀者可以自行研究。 (3)force use和config(強制使用及配置) 大家知道,手機通話時可以選擇揚聲器輸出,這就是強制使用的案例。Audio系統對此有很好的支持。它涉及到兩個方面: - 強制使用何種設備,例如使用揚聲器、聽筒、耳機等。它由forced_config控制,代碼如下所示: ~~~ enum forced_config { FORCE_NONE, FORCE_SPEAKER, //強制使用揚聲器 FORCE_HEADPHONES, FORCE_BT_SCO, FORCE_BT_A2DP, FORCE_WIRED_ACCESSORY, FORCE_BT_CAR_DOCK, FORCE_BT_DESK_DOCK, NUM_FORCE_CONFIG, FORCE_DEFAULT = FORCE_NONE } ~~~ - 在什么情況下需要強制使用,是通話的強制使用,還是聽音樂的強制使用?這須由force_use控制,代碼如下所示: ~~~ enumforce_use { FOR_COMMUNICATION,//通話情況,注意前綴,是FOR_XXX FOR_MEDIA,//聽音樂等媒體相關的情況 FOR_RECORD, FOR_DOCK, NUM_FORCE_USE } ~~~ 所以,AudioPolicyInterface的setForceUse函數,就是設置在什么情況下強制使用什么設備: ~~~ virtual void setForceUse(AudioSystem::force_useusage,//什么情況 AudioSystem::forced_configconfig //什么設備 )= 0; ~~~ (4)輸出設備的定義 前面曾反復提到輸出設備。這些設備在軟件中是怎么表示的呢?Audio定義了很多輸出設備,來看其中幾個: ~~~ enum audio_devices { //output devices DEVICE_OUT_EARPIECE = 0x1, //聽筒 DEVICE_OUT_SPEAKER = 0x2, //揚聲器 DEVICE_OUT_WIRED_HEADSET = 0x4, //耳機 DEVICE_OUT_WIRED_HEADPHONE = 0x8, //另外一種耳機 DEVICE_OUT_BLUETOOTH_SCO = 0x10, //藍牙相關,SCO用于通話的語音傳輸 DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20, DEVICE_OUT_BLUETOOTH_SCO_CARKIT= 0x40, DEVICE_OUT_BLUETOOTH_A2DP = 0x80, //藍牙相關,A2DP用于立體聲傳輸 DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100, DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200, DEVICE_OUT_AUX_DIGITAL = 0x400, DEVICE_OUT_DEFAULT= 0x8000, ...... } ~~~ 至此,AudioSystem中常用的定義都已見過了,現在要回到APS的創建上了。對這個例子,將使用Generic的設備,所以會直接創建AudioPolicyManagerBase對象,這個對象實現了AudioPolicyInterface的所有功能。一起來看。 說明:實際上很多硬件廠商實現的AudioPolicyInterface,基本上是直接使用這個AudioPolicyManagerBase。 4. AudioPolicyManagerBase的分析 AudioPolicyManagerBase類在AudioPolicyManagerBase.cpp中實現,先來看它的構造函數: **AudioPolicyManagerBase.cpp** ~~~ AudioPolicyManagerBase::AudioPolicyManagerBase( AudioPolicyClientInterface*clientInterface) :mPhoneState(AudioSystem::MODE_NORMAL),mRingerMode(0), mMusicStopTime(0),mLimitRingtoneVolume(false) { //APS實現了AudioPolicyClientInterface接口 mpClientInterface= clientInterface;//這個clientInterface就是APS對象 //清空強制使用配置 for(int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) { mForceUse[i] = AudioSystem::FORCE_NONE; } //輸出設備有聽筒和揚聲器 mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE | AudioSystem::DEVICE_OUT_SPEAKER; //輸入設備是內置的麥克(學名叫傳聲器) mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC; #ifdef WITH_A2DP //和藍牙立體聲有關。 mA2dpOutput = 0; mDuplicatedOutput = 0; mA2dpDeviceAddress = String8(""); #endif mScoDeviceAddress = String8(""); //SCO主要用于通話 /* ①創建一個AudioOutputDescriptor對象,這個對象用來記錄并維護與 輸出設備(相當于硬件的音頻DSP)相關的信息,例如使用該設備的流個數、各個流的音量、 該設備所支持的采樣率、采樣精度等。其中,有一個成員mDevice用來表示目前使用的輸出設備, 例如耳機、聽筒、揚聲器等 */ AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(); outputDesc->mDevice= (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER; /* ②還記得MixerThread的來歷嗎?openOutput導致AF創建了一個工作線程。 該函數返回的是一個工作線程索引號 */ mHardwareOutput =mpClientInterface->openOutput(&outputDesc->mDevice, &outputDesc->mSamplingRate, &outputDesc->mFormat, &outputDesc->mChannels, &outputDesc->mLatency, outputDesc->mFlags); ...... //AMB維護了一個與設備相關的key/value集合,下面將對應信息加到該集合中。 addOutput(mHardwareOutput,outputDesc); //③設置輸出設備,就是設置DSP的數據流到底從什么設備出去,這里設置的是從揚聲器出去 setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER,true); } //④更新不同策略使用的設備 updateDeviceForStrategy(); } ~~~ 關于AMB這個小小的構造函數,有幾個重要點需要介紹: (1)AudioOutputDescriptor和openOutput AudioOutputDescriptor對象,是AMB用來控制和管理音頻輸出設備的,從硬件上看,它代表的是DSP設備。關于這一點已在注釋中做出說明,這里就不再贅述。 另一個重要點是openOutput函數。該函數的實現由APS來完成。之前曾分析過,它最終會在AF中創建一個混音線程(不考慮DirectOutput的情況),該函數返回的是該線程在AF中的索引號,亦即 ~~~ mHardwareOutput =mpClientInterface->openOutput(......) ~~~ mHardwareOutput表示的是AF中一個混音線程的索引號。這里涉及到一個非常重要的設計問題:AudioFlinger到底會創建多少個MixerThread?有兩種設計方案: - 一種是一個MixerThread對應一個Track。如果這樣,AMB僅使用一個mHardwareOutput恐怕還不夠用。 - 另一種是用一個MixerThread支持32路的Track數據,多路數據通過AudioMixer混音對象在軟件層面進行混音。 這里用的是第二種,當初設計時為何不用一個MixerThread支持一路Track,然后把混音的工作交給硬件來完成呢?我覺得,原因之一是如采用一個線程一個Track的方式,就非常難于管理和控制,另一個原因是多線程比較浪費資源。 如采用第二種方法(也就是現有的方案),就極大簡化了AMB的工作量。圖7-14展示了AMB和AF及MixerThread之間的關系: :-: ![](http://img.blog.csdn.net/20150802160748160?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖7-14 AF、AMB及MixerThread之間的關系 圖7-14表明: - AMB中除了mHardwareOutput外,還有一個mA2dpOutput,它對應的MixerThread,專往代表藍牙A2DP設備的AudioStreamOut上發送數據。關于這個問題,在后面分析DuplicatingThread時可以見到。 * * * * * **注意**:使用mA2dpOutput需要藍牙設備連接上才會有意義。 * * * * * - 除了藍牙外,系統中一般也就只有圖7-14右邊這么一個MixerThread了,所以AMB通過mHardwareOutput就能控制整個系統的聲音,這真是一勞永逸。 * * * * * **說明**:關于這一點,現在通過setOutputDevice來分析。 * * * * * (2)setOutputDevice 現在要分析的調用是setOutputDevice,目的是為DSP選擇一個合適的輸出設備。注意它的第一個參數是傳入的mHardwareOutput,它最終會找到代表DSP的AudioStreamOut對象,第二個參數是一個設備號。 **AudioPolicyManagerBase.cpp** ~~~ void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_toutput, uint32_tdevice, bool force, int delayMs) { AudioOutputDescriptor*outputDesc = mOutputs.valueFor(output); //判斷是否是Duplicate輸出,和藍牙A2DP有關,后面再做分析 if(outputDesc->isDuplicated()) { setOutputDevice(outputDesc->mOutput1->mId, device, force,delayMs); setOutputDevice(outputDesc->mOutput2->mId, device, force,delayMs); return; } // 初始設置的輸出設備為聽筒和揚聲器 uint32_tprevDevice = (uint32_t)outputDesc->device(); if ((device == 0 || device == prevDevice)&& !force) { return; } //現在設置新的輸出設備為揚聲器,注意這是軟件層面上的設置 outputDesc->mDevice = device; ...... /* 還需要硬件也做相應設置,主要是告訴DSP把它的輸出切換到某個設備上,根據之前的分析, 這個請求要發送到AF中的MixerThread上,因為只有它擁有代表輸出設備的AudioStreamOut 對象 */ AudioParameter param = AudioParameter(); param.addInt(String8(AudioParameter::keyRouting),(int)device); /* 上面的配置參數將投遞到APS的消息隊列,而APS中創建的AudioCommandThread 會取出這個配置參數,再投遞給AF中對應的MixerThread,最終由MixerThread處理。 這個流程,將在耳機插拔事件處理中進行分析 */ mpClientInterface->setParameters(mHardwareOutput, param.toString(),delayMs); ...... } ~~~ setOutputDevice要實現的目的已很明確,只是實現的過程比較繁瑣而已。其間沒有太多復雜之處,讀者可自行研究,以加深對Audio系統的了解。 (3)Audio Strategy 現調用的函數是updateDeviceForStrategy,這里會引出一個strategy的概念。先看updataDeviceForStrategy函數: **AudioPolicyManagerBase.cpp** ~~~ voidAudioPolicyManagerBase::updateDeviceForStrategy() { for(int i = 0; i < NUM_STRATEGIES; i++) { mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i,false); } } ~~~ 關于getDeviceForStrategy,在耳機插拔事件中再做分析,現在先看routing_stratgy的定義,代碼如下所示: **getDeviceForStrategy.h::routing_strategy** ~~~ //routing_strategy:路由策略 enum routing_strategy { STRATEGY_MEDIA, STRATEGY_PHONE, STRATEGY_SONIFICATION, STRATEGY_DTMF, NUM_STRATEGIES } ~~~ 它是在AudioPolicyManagerBase.h中定義的,一般的應用程序不會使用這個頭文件。這個routing_strategy有什么用處呢?從名字上看,似乎和路由的選擇有關系,但AudioSystem定義的是stream type,這兩者之間會有什么關系嗎?有,而且還很緊密。這個關系通過AMB的getStrategy就可以看出來。它會從指定的流類型得到對應的路由策略,代碼如下所示: **AudioPolicyManagerBase.cpp** ~~~ AudioPolicyManagerBase::getStrategy(AudioSystem::stream_typestream) { switch(stream) { caseAudioSystem::VOICE_CALL: caseAudioSystem::BLUETOOTH_SCO: return STRATEGY_PHONE; //PHONE路由策略 caseAudioSystem::RING: caseAudioSystem::NOTIFICATION: caseAudioSystem::ALARM: caseAudioSystem::ENFORCED_AUDIBLE: return STRATEGY_SONIFICATION; //SONIFICATION路由策略 caseAudioSystem::DTMF: return STRATEGY_DTMF; //DTMF路由策略 default: LOGE("unknown stream type"); caseAudioSystem::SYSTEM: caseAudioSystem::TTS: caseAudioSystem::MUSIC: return STRATEGY_MEDIA;//media 路由策略 } } ~~~ 從這個函數中可看出,AudioSystem使用的流類型并不是和路由直接相關的,AMB或AudioPolicy內部,是使用routing_strategy來控制路由策略的。 5. 小結 這一節涉及到不少新東西,但本人覺得,最重要的還是圖7-13和圖7-14。其中: - 圖7-13展示了智能手機的硬件架構,通過和Audio相關的架構設計,我們能理解Audio系統設計的緣由。 - 圖7-14展示了APS和AF內部聯系的紐帶,后續APS的控制無非就是找到對應的MixerThread,給它發送控制消息,最終由MixerThread將控制信息傳給對應的代表音頻輸出設備的HAL對象。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看