<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 功能強大 支持多語言、二開方便! 廣告
                按照前文所介紹的內容可知,AudioTrack在調用createTrack時,會傳入一個audio_handle_t,這個值表示AF中某個工作線程的索引號,而它又是從APS中得到的。那么,這中間又有哪些曲折的經歷呢? 先回顧一下AudioTrack的set函數。 1. 重回set 先來看相應的代碼,如下所示: **AudioTrack.cpp** ~~~ status_t AudioTrack::set(int streamType,uint32_tsampleRate,int format, int channels,intframeCount,uint32_t flags, callback_t cbf,void*user,int notificationFrames, constsp<IMemory>& sharedBuffer, bool threadCanCallJava) { ...... //得到AF中一個工作線程的索引號 audio_io_handle_toutput = AudioSystem::getOutput( (AudioSystem::stream_type)streamType, sampleRate,format, channels, (AudioSystem::output_flags)flags); ...... //創建Track,最終會調到AF的createTrack status_t status = createTrack(streamType,sampleRate, format, channelCount, frameCount,flags, sharedBuffer, output); ~~~ 再看AudioSystem是如何實現getOutput的,代碼如下所示: **AudioSystem.cpp** ~~~ audio_io_handle_tAudioSystem::getOutput(stream_type stream, uint32_tsamplingRate, uint32_tformat, uint32_tchannels, output_flagsflags) { audio_io_handle_t output = 0; ...... if(output == 0) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if(aps == 0) return 0; //調用AP的getOutput函數 output = aps->getOutput(stream, samplingRate, format, channels,flags); if((flags & AudioSystem::OUTPUT_FLAG_DIRECT) == 0) { Mutex::Autolock _l(gLock); //把這個stream和output的對應關系保存到map中 AudioSystem::gStreamOutputMap.add(stream, output); } } returnoutput; } ~~~ 這里調用了AP的getOutput,來看: **AudioPolicyService.cpp** ~~~ audio_io_handle_t AudioPolicyService::getOutput( AudioSystem::stream_typestream, uint32_t samplingRate, uint32_tformat,uint32_t channels, AudioSystem::output_flagsflags) { //和硬件廠商的實現相關,所以交給AudioPolicyInterface處理 //這里將由AudioPolicyManagerBase處理 Mutex::Autolock _l(mLock); returnmpPolicyManager->getOutput(stream, samplingRate, format, channels, flags); } ~~~ **AudioPolicyManagerBase.cpp** ~~~ audio_io_handle_tAudioPolicyManagerBase::getOutput( AudioSystem::stream_typestream, uint32_t samplingRate, uint32_t format,uint32_tchannels, AudioSystem::output_flagsflags) { audio_io_handle_t output = 0; uint32_tlatency = 0; //根據流類型得到對應的路由策略,這個我們已經見過了,MUSIC類型返回MUSIC策略 routing_strategystrategy = getStrategy((AudioSystem::stream_type)stream); //根據策略得到使用這個策略的輸出設備(指揚聲器之類的),以后再看這個函數 uint32_tdevice = getDeviceForStrategy(strategy); ...... //看這個設備是不是與藍牙的A2DP相關 uint32_ta2dpDevice = device & AudioSystem::DEVICE_OUT_ALL_A2DP; if(AudioSystem::popCount((AudioSystem::audio_devices)device) == 2) { #ifdef WITH_A2DP //對于有A2DP支持,a2dpUsedForSonification函數直接返回true if (a2dpUsedForSonification() &&a2dpDevice != 0) { //和DuplicatingThread相關,以后再看 output = mDuplicatedOutput; } else #endif { output = mHardwareOutput; //使用非藍牙的混音輸出線程 } } else{ #ifdef WITH_A2DP if(a2dpDevice != 0) { //使用藍牙的混音輸出線程 output = mA2dpOutput; }else #endif { output = mHardwareOutput; } } returnoutput; } ~~~ 終于明白了!原來,AudioSystem的getOutput就是想找到AF中的一個工作線程。為什么這個線程號會由AP返回呢?是因為Audio系統需要: - 根據流類型找到對應的路由策略。 - 根據該策略找到合適的輸出device(指揚聲器、聽筒之類的)。 - 根據device選擇AF中合適的工作線程,例如是藍牙的MixerThread,還是DSP的MixerThread,或者是DuplicatingThread。 - AT根據得到的工作線程索引號,最終將在對應的工作線程中創建一個Track。之后,AT的數據將由該線程負責處理。 下面用圖7-15來回顧一下上面AT、AF、AP之間的交互關系。 :-: ![](http://img.blog.csdn.net/20150802160955740?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖7-15 Audio三巨頭的交互關系 圖7-15充分展示了AT、AF和AP之間復雜微妙的關系。關系雖復雜,但目的卻單純。讀者在分析時一定要明確目的。下面從目的開始,反推該流程: - AT的目的是把數據發送給對應的設備,例如是藍牙、DSP等。 - 代表輸出設備的HAL對象由MixerThread線程持有,所以要找到對應的MixerThread。 - AP維護流類型和輸出設備(耳機、藍牙耳機、聽筒等)之間的關系,不同的輸出設備使用不同的混音線程。 - AT根據自己的流類型,向AudioSystem查詢,希望得到對應的混音線程號。 這樣,三者精妙配合,便達到了預期目的。 2. 重回start 現在要分析的就是start函數。AT的start雖沒有直接與AP交互,但在AF的start中卻和AP有著交互關系。其代碼如下所示: **AudioFlinger.cpp** ~~~ status_tAudioFlinger::PlaybackThread::Track::start() { status_t status = NO_ERROR; sp<ThreadBase> thread = mThread.promote(); ...... if(!isOutputTrack() && state != ACTIVE && state != RESUMING) { thread->mLock.unlock(); //調用AudioSystem的startOutput status = AudioSystem::startOutput(thread->id(), (AudioSystem::stream_type)mStreamType); thread->mLock.lock(); } PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); playbackThread->addTrack_l(this);//把這個Track加入到活躍Track數組中 returnstatus; } ~~~ 下面來看AudioSystem的startOutput,代碼如下所示: **AudioSystem.cpp** ~~~ status_tAudioSystem::startOutput(audio_io_handle_t output, AudioSystem::stream_typestream) { constsp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps== 0) return PERMISSION_DENIED; //調用AP的startOutput,最終由AMB完成實際功能 returnaps->startOutput(output, stream); } ~~~ **AudioPolicyManagerBase.cpp** ~~~ status_tAudioPolicyManagerBase::startOutput(audio_io_handle_t output, AudioSystem::stream_typestream) { //根據output找到對應的AudioOutputDescriptor ssize_t index = mOutputs.indexOfKey(output); AudioOutputDescriptor*outputDesc = mOutputs.valueAt(index); //找到對應流使用的路由策略 routing_strategy strategy =getStrategy((AudioSystem::stream_type)stream); //增加outputDesc中該流的使用計數,1表示增加1 outputDesc->changeRefCount(stream, 1); //getNewDevice將得到一個設備,setOutputDevice將使用這個設備進行路由切換。 //至于setOutputDevice,我們在分析耳機插入事件時再來講解 setOutputDevice(output, getNewDevice(output)); //設置音量,讀者可自行分析 checkAndSetVolume(stream,mStreams[stream].mIndexCur, output, outputDesc->device()); returnNO_ERROR; } ~~~ 再看getNewDevice,它和音頻流的使用計數有關系: **AudioPolicyManagerBase.cpp** ~~~ uint32_tAudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, bool fromCache) { uint32_t device = 0; AudioOutputDescriptor*outputDesc = mOutputs.valueFor(output); /* isUsedByStrategy判斷某個策略是否正在被使用,之前曾通過changeRefCount為 MUSIC流使用計數增加了1,所以使用MUSIC策略的個數至少為1,這表明,此設備正在使用該策略。 一旦得到當前outputDesc使用的策略,便可根據該策略找到對應的設備。 注意if和else的順序,它代表了系統優先使用的策略,以第一個判斷為例, 假設系統已經插上耳機,并且處于通話狀態時,而且強制使用了揚聲器,那么聲音都從揚聲器出。 這時,如果想聽音樂的話,則應首先使用STRATEGY_PHONE的對應設備,此時就是揚聲器。 所以音樂將從揚聲器出來,而不是耳機。上面僅是舉例,具體的情況還要綜合考慮Audio 系統中的其他信息。另外如果fromCache為true,將直接從內部保存的舊信息中得到設備, 關于這個問題,在后面的耳機插入事件處理中再做分析 */ if(mPhoneState == AudioSystem::MODE_IN_CALL || outputDesc->isUsedByStrategy(STRATEGY_PHONE)) { device = getDeviceForStrategy(STRATEGY_PHONE, fromCache); } elseif (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION)) { device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache); } elseif (outputDesc->isUsedByStrategy(STRATEGY_MEDIA)) { device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache); } elseif (outputDesc->isUsedByStrategy(STRATEGY_DTMF)) { device = getDeviceForStrategy(STRATEGY_DTMF, fromCache); } returndevice; } ~~~ 這里,有一個問題需要關注: * **為什么startOutput函數會和設備切換有關系呢?** 僅舉一個例子,幫助理解這一問題。AudioTrack創建時可設置音頻流類型,假設第一個AT創建時使用的是MUSIC類型,那么它將使用耳機出聲(假設耳機已經連接上)。這時第二個AT創建了,它使用的是RING類型,它對應的策略應是SONIFACATION,這個策略的優先級比MUSIC要高(因為getNewDevice的判斷語句首先會判斷isUsedByStrategy(STRATEGY_SONIFICATION)),所以這時需要把設備切換為耳機加揚聲器(假設這種類型的聲音需要從耳機和揚聲器同時輸出)。startOutput的最終結果,是這兩路的Track聲音都將從耳機和揚聲器中聽到。當第二路AT調用stop時,對應音頻流類型使用計數會減一,這會導致新的路由切換,并重新回到只有耳機的情況,這時第一路AT的聲音會恢復為只從耳機輸出。 >[warning] **提醒**:讀者可自行分析stop的處理方式,基本上是start的逆向處理過程。 3. 本節小結 這一節主要講解了AudioTrack和AP之間的交互,總結為以下兩點: - AT通過AP獲取AF中的工作線程索引號,這決定了數據傳輸的最終目標是誰,比如是音頻DSP或是藍牙。 - AT的start和stop會影響Audio系統的路由切換。 讀完這一節,讀者可能只會對與工作線程索引有關的內容印象較深刻,畢竟這個決定了數據傳輸的目的地。至于與路由切換有關的知識,可能就還不太了解了。下面,通過分析一個應用場景來啟發、加深對它的理解。
                  <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>

                              哎呀哎呀视频在线观看