<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>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                圖7-5中說明的AT和AF交互的流程,對于分析AF來說非常重要。先來回顧一下圖7-5的流程: - AT調用createTrack,得到一個IAudioTrack對象。 - AT調用IAudioTrack對象的start,表示準備寫數據了。 - AT通過write寫數據,這個過程和audio_track_cblk_t有著密切關系。 - 最后AT調用IAudioTrack的stop或delete IAudioTrack結束工作。 至此,上面的每一步都很清楚了。根據Binder知識,AT調用的這些函數最終都會在AF端得到實現,所以可直接從AF端開始。 1. createTrack的分析 按照前面的流程步驟,第一個被調用的函數會是createTrack,請注意在用例中傳的參數。 **AudioFlinger.cpp** ~~~ sp<IAudioTrack> AudioFlinger::createTrack( pid_t pid,//AT的pid號 int streamType,//流類型,用例中是MUSIC類型 uint32_t sampleRate,//8000 采樣率 int format,//PCM_16類型 int channelCount,//2,雙聲道 int frameCount,//需要創建緩沖的大小,以幀為單位 uint32_t flags, const sp<IMemory>& sharedBuffer,//AT傳入的共享buffer,這里為空 int output,//這個值前面提到過,是AF中的工作線程索引號 status_t *status) { sp<PlaybackThread::Track> track; sp<TrackHandle> trackHandle; sp<Client> client; wp<Client>wclient; status_t lStatus; { Mutex::Autolock _l(mLock); //output代表索引號,這里根據索引號找到一個工作線程,它是一個PlaybackThread PlaybackThread *thread = checkPlaybackThread_l(output); //看看這個進程是否已經是AF的Client,AF根據進程pid來標識不同的Client wclient = mClients.valueFor(pid); if(wclient != NULL) { }else { //如果還沒有這個Client信息,則創建一個,并加入到mClients中去 client = new Client(this, pid); mClients.add(pid, client); } //在找到的工作線程對象中創建一個Track,注意它的類型是Track track = thread->createTrack_l(client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer, &lStatus); } /* TrackHandle是Track對象的Proxy,它支持Binder通信,而Track不支持Binder TrackHandle所接收的請求最終會由Track處理,這是典型的Proxy模式 */ trackHandle= new TrackHandle(track); returntrackHandle; } ~~~ 這個函數相當復雜,主要原因之一,是其中出現了幾個我們沒接觸過的類。我剛接觸這個函數的時候,大腦也曾因看到這些眼生的東西而“死機”!不過暫時先不用去理會它們,等了解了這個函數后,再回過頭來收拾它們。先進入checkPlaybackThread_l看看。 (1) 選擇工作線程 checkPlaybackThread_l的代碼如下所示: **AudioFlinger.cpp** ~~~ AudioFlinger::PlaybackThread * AudioFlinger::checkPlaybackThread_l(intoutput) const { PlaybackThread*thread = NULL; //根據output的值找到對應的thread if(mPlaybackThreads.indexOfKey(output) >= 0) { thread = (PlaybackThread *)mPlaybackThreads.valueFor(output).get(); } returnthread; } ~~~ 上面函數中傳入的output,就是之前在分析AT時提到的工作線程索引號。看到這里,是否感覺有點困惑?困惑的原因可能有二: - 目前的流程中尚沒有見到創建線程的地方,但在這里確實能找到一個線程。 - Output含義到底是什么?為什么會把它作為index來找線程呢? 關于這兩個問題,待會兒再做解釋。現在只需知道AudioFlinger會創建幾個工作線程,AT會找到對應的工作線程即可。 (2) createTrack_l的分析 找到工作線程后,會執行createTrack_l函數,請看這個函數的作用: **AudioFlinger.cpp** ~~~ // Android的很多代碼都采用了內部類的方式進行封裝,看習慣就好了 sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l( const sp<AudioFlinger::Client>& client,int streamType, uint32_tsampleRate,int format,int channelCount,int frameCount, const sp<IMemory>& sharedBuffer,//注意這個參數,從AT中傳入,為0 status_t *status) { sp<Track> track; status_t lStatus; { Mutex::Autolock _l(mLock); //創建Track對象 track= new Track(this, client, streamType, sampleRate, format, channelCount, frameCount,sharedBuffer); //將新創建的Track加入到內部數組mTracks中 mTracks.add(track); } lStatus= NO_ERROR; returntrack; } ~~~ 上面的函數調用傳入的sharedBuffer為空,那共享內存又是在哪里創建的呢?可以注意到Track構造函數關于sharedBuffer這個參數的類型是一個引用,莫非是構造函數創建的? (3) Track創建共享內存和TrackHandle 在createTrack_l中,會new出來一個Track,請看它的代碼: **AudioFlinger.cpp** ~~~ AudioFlinger::PlaybackThread::Track::Track(const wp<ThreadBase>& thread, const sp<Client>& client,int streamType,uint32_t sampleRate, int format,int channelCount,int frameCount, const sp<IMemory>& sharedBuffer) : TrackBase(thread, client, sampleRate, format, channelCount, frameCount,0, sharedBuffer),//sharedBuffer仍然為空 mMute(false), mSharedBuffer(sharedBuffer), mName(-1) { // mCblk!=NULL? 什么時候創建的呢?只能看基類TrackBase的構造函數了 if(mCblk != NULL) { mVolume[0] = 1.0f; mVolume[1] = 1.0f; mStreamType = streamType; mCblk->frameSize = AudioSystem::isLinearPCM(format) ? channelCount * sizeof(int16_t): sizeof(int8_t); } } ~~~ 對于這種重重繼承,我們只能步步深入分析,一定要找到共享內存創建的地方,繼續看代碼: **AudioFlinger.cpp** ~~~ AudioFlinger::ThreadBase::TrackBase::TrackBase( const wp<ThreadBase>& thread,const sp<Client>&client, uint32_t sampleRate,int format,int channelCount,int frameCount, uint32_t flags,const sp<IMemory>& sharedBuffer) : RefBase(), mThread(thread),mClient(client),mCblk(0), mFrameCount(0),mState(IDLE),mClientTid(-1),mFormat(format), mFlags(flags & ~SYSTEM_FLAGS_MASK) { size_tsize = sizeof(audio_track_cblk_t);//得到CB對象大小 //計算數據緩沖大小 size_tbufferSize = frameCount*channelCount*sizeof(int16_t); if(sharedBuffer == 0) { //還記得圖7-4嗎?共享內存最前面一部分是audio_track_cblk_t,后面才是數據空間 size+= bufferSize; } //根據size創建一塊共享內存。 mCblkMemory = client->heap()->allocate(size); /* pointer()返回共享內存的首地址, 并強制轉換void*類型為audio_track_cblk_t*類型。 其實把它強制轉換成任何類型都可以,但是這塊內存中會有CB對象嗎? */ mCblk= static_cast<audio_track_cblk_t *>(mCblkMemory->pointer()); //①下面這句代碼看起來很獨特。什么意思??? new(mCblk)audio_track_cblk_t(); mCblk->frameCount = frameCount; mCblk->sampleRate = sampleRate; mCblk->channels = (uint8_t)channelCount; if (sharedBuffer == 0) { //清空數據區 mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t)); // flowControlFlag初始值為1 mCblk->flowControlFlag = 1; } ...... } ~~~ 這里需要重點講解下面這句話的意思。 ~~~ new(mCblk) audio_track_cblk_t(); ~~~ 注意它的用法,new后面的括號里是內存,緊接其后的是一個類的構造函數。 * * * * * **重點說明**:這個語句就是C++語言中的placement new。其含義是在括號里指定的內存中創建一個對象。我們知道,普通的new只能在堆上創建對象,堆的地址由系統分配。這里采用placementnew將使得audio_track_cblk_t創建在共享內存上,它就自然而然地能被多個進程看見并使用了。關于placementnew較詳細的知識,還請讀者自己搜索一下。 * * * * * 通過上面的分析,可以知道: - Track創建了共享內存。 * CB對象通過placement new方法創建于這塊共享內存中。 AF的createTrack函數返回的是一個IAudioTrack類型的對象,可現在碰到的Track對象是IAudioTrack類型嗎?來看代碼: **AudioFlinger.cpp** ~~~ sp<IAudioTrack> AudioFlinger::createTrack(......) { sp<TrackHandle>trackHandle; ...... track= thread->createTrack_l(client, streamType, sampleRate, format,channelCount,frameCount, sharedBuffer, &lStatus); trackHandle= new TrackHandle(track); return trackHandle;//① 這個trackHandle對象竟然沒有在AF中保存! } ~~~ 原來,createTrack返回的是TrackHandle對象,它以Track為參數構造。這二者之間又是什么關系呢? Android在這里使用了Proxy模式,即TrackHandle是Track的代理,TrackHandle代理的內容是什么呢?分析TrackHandle的定義可以知道: - Track沒有基于Binder通信,它不能接收來自遠端進程的請求。 - TrackHandle能基于Binder通信,它可以接收來自遠端進程的請求,并且能調用Track對應的函數。這就是Proxy模式的意思。 * * * * * **討論**:Android為什么不直接讓Track從IBinder派生,直接支持Binder通信呢?關于這個問題,在看到后面的Track家族圖譜后,我們或許就明白了。 * * * * * 另外,注意代碼中的注釋①: - **trackHandle被new出來后直接返回,而AF中并沒有保存它,這豈不是成了令人聞之色變的野指針?** * * * * * 拓展思考:關于這個問題的答案,請讀者自己思考并回答。提示,可從Binder和RefBase入手。 * * * * * 分析完createTrack后,估計有些人會暈頭轉向的。確實,這個createTrack比較復雜。僅對象類型就層出不窮。到底它有多少種對象,它們之間又有怎樣的關系呢?下面就來解決這幾個問題。 2. 到底有多少種對象? 不妨把AudioFlinger中出現的對象總結一下,以了解它們的作用和相互之間的關系。 (1) AudioFlinger對象 作為Audio系統的核心引擎,首先要介紹AudioFlinger。它的繼承關系很簡單: ~~~ class AudioFlinger : public BnAudioFlinger,public IBinder::DeathRecipient ~~~ AudioFlinger的主要工作由其定義的許多內部類來完成,我們用圖7-7來表示。圖中大括號所指向的類為外部類,大括號所包含的為該外部類所定義的內部類。例如,DuplicatingThread、RecordThread和DirectOutputThread都包括在一個大括號中,這個大括號指向AudioFlinger,所以它們三個都是AudioFlinger的內部類,而AudioFlinger則是它們三個的外部類: :-: ![](http://img.blog.csdn.net/20150802160448011?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖7-7 AF中的所有類 看,AF夠復雜吧?要不是使用了VisualStudio的代碼段折疊功能,我畫這個圖,也會破費周折的。 (2) Client對象 Client是AudioFlinger對客戶端的封裝,凡是使用了AudioTrack和AudioRecord的進程,都被會當做是AF的Client,并且Client用它的進程pid作為標識。代碼如下所示: ~~~ class Client : public RefBase { public: Client(const sp<AudioFlinger>& audioFlinger, pid_t pid); virtual ~Client(); const sp<MemoryDealer>& heap() const; pid_t pid() const {return mPid; } sp<AudioFlinger> audioFlinger() { return mAudioFlinger; } private: Client(constClient&); Client&operator = (const Client&); sp<AudioFlinger> mAudioFlinger; sp<MemoryDealer> mMemoryDealer;//內存分配器 pid_t mPid; }; ~~~ Client對象比較簡單,因此就不做過多的分析了。 >[warning] **注意**:一個Client進程可以創建多個AudioTrack,這些AudioTrack都屬于一個Client。 (3) 工作線程介紹 AudioFlinger中有幾種不同類型的工作線程,它們之間的關系如圖7-8所示: :-: ![](http://img.blog.csdn.net/20150802160616685?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖7-8 AF中的工作線程家譜 下面來解釋圖7-8中各種類型工作線程的作用: - PlaybackThread:回放線程,用于音頻輸出。它有一個成員變量mOutput,為AudioStreamOutput*類型,這表明PlaybackThread直接和Audio音頻輸出設備建立了聯系。 - RecordThread:錄音線程,用于音頻輸入,它的關系比較單純。它有一個成員變量mInput為AudioStreamInput*類型,這表明RecordThread直接和Audio音頻輸入設備建立了聯系。 從PlaybackThread的派生關系上可看出,手機上的音頻回放應該比較復雜,否則也不會派生出三個子類了。其中: - MixerThread:混音線程,它將來自多個源的音頻數據混音后再輸出。 - DirectOutputThread:直接輸出線程,它會選擇一路音頻流后將數據直接輸出,由于沒有混音的操作,這樣可以減少很多延時。 - DuplicatingThread:多路輸出線程,它從MixerThread派生,意味著它也能夠混音。它最終會把混音后的數據寫到多個輸出中,也就是一份數據會有多個接收者。這就是Duplicate的含義。目前在藍牙A2DP設備輸出中使用。 另外從圖7-8中還可以看出: - PlaybackThread維護兩個Track數組,一個是mActiveTracks,表示當前活躍的Track,一個是mTracks,表示這個線程創建的所有Track。 - DuplicatingThread還維護了一個mOutputTracks,表示多路輸出的目的端。后面分析DuplicatingThread時再對此進行講解。 * * * * * **說明**:大部分常見音頻輸出使用的是MixerThread,后文會對此進行詳細分析。另外,在拓展內容中,也將深入分析DuplicatingThread的實現。 * * * * * (4) PlaybackThread和AudioStreamOutput 從圖7-8中,可以發現一個PlaybackThread有一個AudioStreamOutput類型的對象,這個對象提供了音頻數據輸出功能。可以用圖7-9來表示音頻數據的流動軌跡。該圖以PlaybackThread最常用的子類MixerThread作為代表。 :-: ![](http://img.blog.csdn.net/20150802160531691?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖7-9 音頻數據的流動軌跡 根據圖7-9,就能明白MixerThread的大致工作流程: - 接收來自AT的數據。 - 對這些數據進行混音。 - 把混音的結果寫到AudioStreamOut,這樣就完成了音頻數據的輸出。 (5) Track對象 前面所說的工作線程,其工作就是圍繞Track展開的,圖7-10展示了Track的家族: :-: ![](http://img.blog.csdn.net/20150802160545747?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖7-10 Track家族 * * * * * **注意**:這里把RecordTrack也統稱為Track。 * * * * * 從圖7-10中可看出,TrackHandle和RecordHandle是基于Binder通信的,它作為Proxy,用于接收請求并派發給對應的Track和RecordTrack。 * * * * * **說明**:從圖7-10也能看出,之所以不讓Track繼承Binder框架,是因為Track本身的繼承關系和所承擔的工作已經很復雜了,如再讓它摻合Binder,只會亂上添亂。 * * * * * Track類作為工作線程的內部類來實現,其中: - TrackBase定義于ThreadBase中。 - Track定義于PlaybackThread中,RecordTrack定義于RecordThread中。 - OutputTrack定義于DuplicatingThread中。 根據前面的介紹可知,音頻輸出數據最后由Playback線程來處理,用例所對應的Playback線程,實際上是一個MixerThread,那么它是如何工作的呢?一起來分析。 3. MixerThread分析 MixerThread是Audio系統中負擔最重的一個工作線程。先來了解一下它的來歷。 (1) MixerThread的來歷 前面,在checkplaybackThread_l中,有一個地方一直沒來得及解釋。回顧一下它的代碼: **AudioFlinger.cpp** ~~~ AudioFlinger::PlaybackThread * AudioFlinger::checkPlaybackThread_l(intoutput) const { PlaybackThread*thread = NULL; //根據output的值找到對應的thread if(mPlaybackThreads.indexOfKey(output) >= 0) { thread = (PlaybackThread *)mPlaybackThreads.valueFor(output).get(); } returnthread; } ~~~ 上面這個函數的意思很明確:就是根據output值找到對應的回放線程。 但在前面的流程分析中,并沒有見到創建線程的地方,那這個線程又是如何得來的?它又是何時、怎樣創建的呢? 答案在AudioPolicyService中。提前看看AudioPolicyService,分析一下,它為什么和這個線程有關系。 AudioPolicyService和AudioFlinger一樣,都駐留在MediaServer中,直接看它的構造函數: **AudioPolicyService.cpp** ~~~ AudioPolicyService::AudioPolicyService() :BnAudioPolicyService() , mpPolicyManager(NULL) { charvalue[PROPERTY_VALUE_MAX]; // Tone音播放線程 mTonePlaybackThread = new AudioCommandThread(String8("")); // 命令處理線程 mAudioCommandThread = newAudioCommandThread(String8("ApmCommandThread")); #if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST) //這里屬于Generic的情況,所以構造AudioPolicyManagerBase,注意構造函數的參數 mpPolicyManager = new AudioPolicyManagerBase(this); #else ...... //創建和硬件廠商相關的AudioPolicyManager #endif ...... } ~~~ 看AudioPolicyManagerBase的構造函數,注意傳給它的參數是this,即把AudioPolicyService對象傳進去了。 **AudioPolicyManagerBase.cpp** ~~~ AudioPolicyManagerBase::AudioPolicyManagerBase( AudioPolicyClientInterface*clientInterface) :mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0),mLimitRingtoneVolume(false) { mpClientInterface = clientInterface; // 先把不相關的內容去掉 ...... /* 返回來調用mpClientInterface的openOutput,實際就是AudioPolicyService。 注意openOutput函數是在AP的創建過程中調用的 */ mHardwareOutput =mpClientInterface->openOutput(&outputDesc->mDevice, &outputDesc->mSamplingRate, &outputDesc->mFormat, &outputDesc->mChannels, &outputDesc->mLatency, outputDesc->mFlags); ...... } ~~~ 真是山不轉水轉!咱們還得回到AudioPolicyService中去看看: **AudioPolicyService.cpp** ~~~ audio_io_handle_tAudioPolicyService::openOutput(uint32_t *pDevices, uint32_t*pSamplingRate, uint32_t*pFormat, uint32_t*pChannels, uint32_t*pLatencyMs, AudioSystem::output_flags flags) { sp<IAudioFlinger>af = AudioSystem::get_audio_flinger(); //下面會調用AudioFlinger的openOutput,這個時候AF已經啟動了 returnaf->openOutput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels, pLatencyMs,flags); } ~~~ 真是曲折啊,又得到AF去看看: **AudioFlinger.cpp** ~~~ int AudioFlinger::openOutput( uint32_t *pDevices,uint32_t*pSamplingRate,uint32_t *pFormat, uint32_t*pChannels,uint32_t *pLatencyMs,uint32_t flags) { ...... Mutex::Autolock _l(mLock); //創建Audio HAL的音頻輸出對象,和音頻輸出扯上了關系 AudioStreamOut *output = mAudioHardware->openOutputStream(*pDevices, (int *)&format, &channels, &samplingRate, &status); mHardwareStatus = AUDIO_HW_IDLE; if(output != 0) { if((flags & AudioSystem::OUTPUT_FLAG_DIRECT) || (format != AudioSystem::PCM_16_BIT) || (channels != AudioSystem::CHANNEL_OUT_STEREO)) { //如果標志為OUTPUT_FLAG_DIRECT,則創建DirectOutputThread thread = new DirectOutputThread(this, output, ++mNextThreadId); } else { //一般創建的都是MixerThread,注意代表AudioStreamOut對象的output也傳進去了 thread= new MixerThread(this, output, ++mNextThreadId); } //把新創建的線程加入線程組mPlaybackThreads中保存, mNextThreadId是它的索引號 mPlaybackThreads.add(mNextThreadId, thread); ...... return mNextThreadId;//返回該線程的索引號 } return0; } ~~~ 明白了嗎?是否感覺有點繞?可用一個簡單的示意圖來觀察三者的交互流程,如圖7-11所示: :-: ![](http://img.blog.csdn.net/20150802160718913?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖7-11 MixerThread的曲折來歷示意圖 圖7-11表明: - AF中的工作線程的創建,受到了AudioPolicyService的控制。從AudioPolicyService的角度出發,這也是應該的,因為APS控制著整個音頻系統,而AF只是管理音頻的輸入和輸出。 - 另外,注意這個線程是在AP的創建過程中產生的。也就是說,AP一旦創建完Audio系統,就已經準備好工作了。 關于AF和AP的恩恩怨怨,在后面APS的分析過程中再去探討。目前,讀者只需了解系統中第一個MixerThread的來歷即可。下面來分析這個來之不易的MixerThread。 (2) MixerThread的構造和線程啟動 **AudioFlinger.cpp** ~~~ AudioFlinger::MixerThread::MixerThread( constsp<AudioFlinger>& audioFlinger, AudioStreamOut*output, // AudioStreamOut為音頻輸出設備的HAL抽象 intid) : PlaybackThread(audioFlinger, output, id),mAudioMixer(0) { mType = PlaybackThread::MIXER; //混音器對象,這個對象比較復雜,它完成多路音頻數據的混合工作 mAudioMixer = new AudioMixer(mFrameCount, mSampleRate); } ~~~ 再來看MixerThread的基類PlaybackThread的構造函數: **AudioFlinger.cpp** ~~~ AudioFlinger::PlaybackThread::PlaybackThread(constsp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id) : ThreadBase(audioFlinger, id), mMixBuffer(0),mSuspended(0), mBytesWritten(0), mOutput(output), mLastWriteTime(0),mNumWrites(0), mNumDelayedWrites(0), mInWrite(false) { //獲取音頻輸出HAL對象的一些信息,包括硬件中音頻緩沖區的大小(以幀為單位) readOutputParameters(); mMasterVolume= mAudioFlinger->masterVolume(); mMasterMute= mAudioFlinger->masterMute(); //設置不同類型音頻流的音量及靜音情況 for(int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { mStreamTypes[stream].volume= mAudioFlinger->streamVolumeInternal(stream); mStreamTypes[stream].mute= mAudioFlinger->streamMute(stream); } //發送一個通知消息給監聽者,這部分內容較簡單,讀者可自行研究 sendConfigEvent(AudioSystem::OUTPUT_OPENED); } ~~~ 此時,線程對象已經創建完畢。根據對Thread的分析,應該調用它的run函數才能真正創建新線程。在首次創建sp時調用了run,這里利用了RefBase的onFirstRef函數。根據MixerThread的派生關系,該函數最終由父類PlaybackThread的onFirstRef實現: **AudioFlinger.cpp** ~~~ void AudioFlinger::PlaybackThread::onFirstRef() { constsize_t SIZE = 256; charbuffer[SIZE]; snprintf(buffer, SIZE, "Playback Thread %p", this); //下面的run就真正創建了線程并開始執行threadLoop run(buffer, ANDROID_PRIORITY_URGENT_AUDIO); } ~~~ 好,線程已經run起來了。繼續按流程分析,下一個輪到的調用函數是start。 4. start的分析 AT調用的是IAudioTrack的start函數,由于TrackHandle的代理作用,這個函數的實際處理會由Track對象來完成。 **AudioFlinger.cpp** ~~~ status_tAudioFlinger::PlaybackThread::Track::start() { status_t status = NO_ERROR; sp<ThreadBase>thread = mThread.promote(); //該Thread是用例中的MixerThread if(thread != 0) { Mutex::Autolock _l(thread->mLock); int state = mState; if (mState == PAUSED) { mState = TrackBase::RESUMING; } else { mState = TrackBase::ACTIVE;//設置Track的狀態 } PlaybackThread *playbackThread =(PlaybackThread *)thread.get(); //addTrack_l把這個track加入到mActiveTracks數組中 playbackThread->addTrack_l(this); returnstatus; } ~~~ 看看這個addTrack_l函數,代碼如下所示: **AudioFlinger.cpp** ~~~ status_tAudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track) { status_t status = ALREADY_EXISTS; //①mRetryCount:設置重試次數,kMaxTrackStartupRetries值為50 track->mRetryCount = kMaxTrackStartupRetries; if(mActiveTracks.indexOf(track) < 0) { //②mFillingUpStatus:緩沖狀態 track->mFillingUpStatus= Track::FS_FILLING; //原來是把調用start的這個track加入到活躍的Track數組中了 mActiveTracks.add(track); status = NO_ERROR; } //廣播一個事件,一定會觸發MixerThread線程,通知它有活躍數組加入,需要開工干活 mWaitWorkCV.broadcast(); return status; } ~~~ start函數把這個Track加入到活躍數組后,將觸發一個同步事件,這個事件會讓工作線程動起來。雖然這個函數很簡單,但有兩個關鍵點必須指出,這兩個關鍵點其實指出了兩個問題的處理辦法: - mRetryCount表示重試次數,它針對的是這樣一個問題:如果一個Track調用了start卻沒有write數據,該怎么辦?如果MixerThread嘗試了mRetryCount次后還沒有可讀數據,工作線程就會把該Track從激活隊列中去掉了。 - mFillingUpStatus能解決這樣的問題:假設分配了1MB的數據緩沖,那么至少需要寫多少數據的工作線程才會讓Track覺得AT是真的需要它工作呢?難道AT寫一個字節就需要工作線程興師動眾嗎?其實,這個狀態最初為Track::FS_FILLING,表示正在填充數據緩沖。在這種狀態下,除非AT設置了強制讀數據標志(CB對象中的forceReady變量),否則工作線程是不會讀取該Track的數據的。該狀態還有其他的值,讀者可以自行研究。 * * * * * **說明**:我們在介紹大流程的同時也把一些細節問題指出來,希望這些細節問題能激發讀者深入研究的欲望。 * * * * * Track加入了工作線程的活躍數組后,又觸發了一個同步事件,MixerThread是否真的動起來了呢?一起來看: (1) MixerThread動起來 Thread類的線程工作都是在threadLoop中完成的,那么MixerThread的線程又會做什么呢? **AudioFlinger.cpp** ~~~ bool AudioFlinger::MixerThread::threadLoop() { int16_t* curBuf = mMixBuffer; Vector< sp<Track> > tracksToRemove; uint32_t mixerStatus = MIXER_IDLE; nsecs_tstandbyTime = systemTime(); ...... uint32_t sleepTime = idleSleepTime; while(!exitPending()) { //① 處理一些請求和通知消息,如之前在構造函數中發出的OUTPUT_OPEN消息等 processConfigEvents(); mixerStatus = MIXER_IDLE; {// scope for mLock Mutex::Autolock _l(mLock); //檢查配置參數,如有需要則重新設置內部參數值 if (checkForNewParameters_l()) { mixBufferSize = mFrameCount * mFrameSize; maxPeriod = seconds(mFrameCount) / mSampleRate * 3; ...... } //獲得當前的已激活track數組 const SortedVector< wp<Track> >& activeTracks =mActiveTracks; ...... /* ②prepareTracks_l將檢查mActiveTracks數組,判斷是否有AT的數據需要處理。 例如有些AudioTrack雖然調用了start,但是沒有及時write數據,這時就無須 進行混音工作。我們待會再分析prepareTracks_l函數 */ mixerStatus = prepareTracks_l(activeTracks, &tracksToRemove); } //MIXER_TRACKS_READY表示AT已經把數據準備好了 if(LIKELY(mixerStatus == MIXER_TRACKS_READY)) { //③ 由混音對象進行混音工作,混音的結果放在curBuf中 mAudioMixer->process(curBuf); sleepTime = 0;//等待時間設置為零,表示需要馬上輸出到Audio HAL standbyTime = systemTime() + kStandbyTimeInNsecs; } ....... if(sleepTime == 0) { ...... //④ 往Audio HAL的OutputStream中write混音后的數據,這是音頻數據的最終歸宿 int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize); if (bytesWritten < 0) mBytesWritten -= mixBufferSize; ...... mStandby = false; }else { usleep(sleepTime); } tracksToRemove.clear(); } if(!mStandby) { mOutput->standby(); } returnfalse; } ~~~ 從上面的分析可以看出,MixerThread的線程函數大致工作流程是: - 如果有通知信息或配置請求,則先完成這些工作。比如向監聽者通知AF的一些信息,或者根據配置請求進行音量控制,聲音設備切換等。 - 調用prepareTracks _l函數,檢查活躍Tracks是否有數據準備好。 - 調用混音器對象mAudioMixer的process,并且傳入一個存儲結果數據的緩沖,混音后的結果就存儲在這個緩沖中。 - 調用代表音頻輸出設備的AudioOutputStream對象的write,把結果數據寫入設備。 其中,配置請求處理的工作將在AudioPolicyService的分析中,以一個耳機插入處理實例進行講解。這里主要分析代碼中②③兩個步驟。 (2) prepareTracks_l和process分析 prepareTracks_l函數檢查激活Track數組,看看其中是否有數據等待使用,代碼如下所示: **AudioFlinger.cpp** ~~~ uint32_tAudioFlinger::MixerThread::prepareTracks_l( constSortedVector<wp<Track>>& activeTracks, Vector<sp<Track>>*tracksToRemove) { uint32_t mixerStatus = MIXER_IDLE; //激活Track的個數 size_tcount = activeTracks.size(); floatmasterVolume = mMasterVolume; bool masterMute = mMasterMute; //依次查詢這些Track的情況 for(size_t i=0 ; i<count ; i++) { sp<Track> t = activeTracks[i].promote(); if(t == 0) continue; Track* const track = t.get(); //怎么查?通過audio_track_cblk_t對象 audio_track_cblk_t* cblk = track->cblk(); /* 一個混音器可支持32個Track,它內部有一個32元素的數組,name函數返回的就是Track在 這個數組中的索引。混音器每次通過setActiveTrack設置一個活躍Track, 后續所有操作都會針對當前設置的這個活躍Track */ mAudioMixer->setActiveTrack(track->name()); //下面這個判斷語句決定了什么情況下Track數據可用 if (cblk->framesReady() &&(track->isReady() || track->isStopped()) && !track->isPaused()&& !track->isTerminated()) { ...... /* 設置活躍Track的數據提供者為Track本身,因為Track從AudioBufferProvider 派生。混音器工作時,需從Track得到待混音的數據,也就是AT寫入的數據由混音 器取出并消費 */ mAudioMixer->setBufferProvider(track); //設置對應Track的混音標志 mAudioMixer->enable(AudioMixer::MIXING); ...... //設置該Track的音量等信息,這在以后的混音操作中會使用 mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left); mAudioMixer->setParameter(param,AudioMixer::VOLUME1, right); mAudioMixer->setParameter( AudioMixer::TRACK, AudioMixer::FORMAT, track->format()); ...... mixerStatus = MIXER_TRACKS_READY; }else {//如果不滿足上面的條件,則走else分支 if (track->isStopped()) { track->reset();//reset會清零讀寫位置,表示沒有可讀數據 } //如果處于這三種狀態之一,則加入移除隊列 if (track->isTerminated() || track->isStopped() || track->isPaused()) { tracksToRemove->add(track); mAudioMixer->disable(AudioMixer::MIXING); } else { //不處于上面三種狀態時,表示暫時沒有可讀數據,則重試mRetryCount次 if (--(track->mRetryCount) <= 0) { tracksToRemove->add(track); } else if (mixerStatus != MIXER_TRACKS_READY) { mixerStatus =MIXER_TRACKS_ENABLED; } //禁止這個Track的混音 mAudioMixer->disable(AudioMixer::MIXING); ...... } } } //對那些被移除的Track做最后的處理 ...... returnmixerStatus; } ~~~ 當所有Track準備就緒后,最重要的工作就是混音。混音對象的process就派上了用場。來看這個process函數,代碼如下所示: **AudioMixer.cpp** ~~~ void AudioMixer::process(void* output) { mState.hook(&mState, output);//hook?這是一個函數指針 } ~~~ hook是函數指針,它根據Track的個數和它的音頻數據格式(采樣率等)等情況,使用不同的處理函數。為進一步了解混音器是如何工作的,需要先分析AudioMixer對象。 (3) AudioMixer對象的分析 AudioMixer實現AudioMixer.cpp中,先看構造函數: **AudioMixer.cpp** ~~~ AudioMixer::AudioMixer(size_t frameCount,uint32_t sampleRate) : mActiveTrack(0), mTrackNames(0),mSampleRate(sampleRate) { mState.enabledTracks= 0; mState.needsChanged = 0; mState.frameCount = frameCount;//這個值等于音頻輸出對象的緩沖大小 mState.outputTemp = 0; mState.resampleTemp= 0; //hook初始化的時候為process__nop,這個函數什么都不會做 mState.hook = process__nop; track_t*t = mState.tracks;//track_t是和Track相對應的一個結構 //最大支持32路混音,也很不錯了 for(int i=0 ; i<32 ; i++) { ...... t->channelCount = 2; t->enabled = 0; t->format = 16; t->buffer.raw = 0; t->bufferProvider = 0; // bufferProvider為這一路Track的數據提供者 t->hook = 0;//每一個Track也有一個hook函數 ...... } int mActiveTrack; uint32_t mTrackNames; constuint32_t mSampleRate; state_t mState } ~~~ 其中,mState是在AudioMixer類中定義的一個數據結構。 ~~~ struct state_t { uint32_t enabledTracks; uint32_t needsChanged; size_t frameCount; mix_t hook; int32_t *outputTemp; int32_t *resampleTemp; int32_t reserved[2]; /* aligned表示32字節對齊,由于source insight不認識這個標志,導致 state_t不能被解析。在看代碼時,可以注釋掉后面的attribute,這樣source insight 就可以識別state_t結構了 */ track_t tracks[32]; __attribute__((aligned(32))); }; ~~~ AudioMixer為hook準備了多個實現函數,來看: - process__validate:根據Track的格式、數量等信息選擇其他的處理函數。 - process__nop:什么都不做。 - process__genericNoResampling:普通無需重采樣。 - process__genericResampling:普通需重采樣。 - process__OneTrack16BitsStereoNoResampling:一路音頻流,雙聲道,PCM16格式,無需重采樣。 - process__TwoTracks16BitsStereoNoResampling:兩路音頻流,雙聲道,PCM16格式,無需重采樣。 hook最初的值為process__nop,這一定不會是混音中最終使用的處理函數,難道有動態賦值的地方?是的。一起來看: (4) 殺雞不用宰牛刀 在AF的prepare_l中,會為每一個準備好的Track使能混音標志: ~~~ mAudioMixer->setBufferProvider(track); mAudioMixer->enable(AudioMixer::MIXING);//使能混音 ~~~ 請看enable的實現: **AudioMixer.cpp** ~~~ status_t AudioMixer::enable(int name) { switch(name) { case MIXING: { if (mState.tracks[ mActiveTrack ].enabled != 1) { mState.tracks[ mActiveTrack ].enabled = 1; //注意這個invalidateState調用 invalidateState(1<<mActiveTrack); } }break; default: return NAME_NOT_FOUND; } returnNO_ERROR; } ~~~ **AudioMixer.cpp** ~~~ void AudioMixer::invalidateState(uint32_t mask) { if(mask) { mState.needsChanged |= mask; mState.hook = process__validate;//將hook設置為process_validate } } ~~~ process_validate會根據當前Track的情況選擇不同的處理函數,所以不會出現殺雞卻用災牛刀的情況。 **AudioMixer.cpp** ~~~ void AudioMixer::process__validate(state_t*state, void* output) { uint32_t changed = state->needsChanged; state->needsChanged = 0; uint32_t enabled = 0; uint32_t disabled = 0; ...... if(countActiveTracks) { if(resampling) { ...... //如果需要重采樣,則選擇process__genericResampling state->hook = process__genericResampling; }else { ...... state->hook = process__genericNoResampling; if (all16BitsStereoNoResample && !volumeRamp) { if (countActiveTracks == 1) { //如果只有一個Track,則使用process__OneTrack16BitsStereoNoResampling state->hook =process__OneTrack16BitsStereoNoResampling; } } } } state->hook(state, output); ...... } ~~~ 假設用例運行時,系統只有這么一個Track,那么hook函數使用的就是process__OneTrack16BitsStereoNoResampling處理。process_XXX函數會涉及很多數字音頻處理的專業知識,先不用去討論它。數據緩沖的消費工作是在這個函數中完成的,因此應重點關注它是如何通過CB對象使用數據緩沖的。 * * * * * **說明**:在這個數據消費和之前破解AT的過程中所講的數據生產是對應的,先來提煉AT和AF在生產和消費這兩個環節上與CB交互的流程。 * * * * * (5) 怎么消費數據 在AudioTrack中,曾講到數據的生產流程: - ObtainBuffer,得到一塊數據緩沖。 - memcpy數據到該緩沖。 - releaseBuffer,釋放這個緩沖。 那么做為消費者,AudioFlinger是怎么獲得這些數據的呢? **AudioMixer.cpp** ~~~ voidAudioMixer::process__OneTrack16BitsStereoNoResampling( state_t*state, void* output) { //找到被激活的Track,此時只能有一個Track,否則就不會選擇這個process函數了 constint i = 31 - __builtin_clz(state->enabledTracks); consttrack_t& t = state->tracks[i]; AudioBufferProvider::Buffer& b(t.buffer); ...... while(numFrames) { b.frameCount = numFrames; //BufferProvider就是Track對象,調用它的getNextBuffer獲得可讀數據緩沖 t.bufferProvider->getNextBuffer(&b); int16_t const *in = b.i16; ...... size_t outFrames = b.frameCount; do {//數據處理,也即是混音 uint32_t rl = *reinterpret_cast<uint32_t const *>(in); in += 2; int32_t l = mulRL(1, rl, vrl) >> 12; int32_t r = mulRL(0, rl, vrl) >> 12; //把數據復制給out緩沖 *out++ = (r<<16) | (l & 0xFFFF); } while (--outFrames); } numFrames -= b.frameCount; //調用Track的releaseBuffer釋放緩沖 t.bufferProvider->releaseBuffer(&b); } } ~~~ bufferProvider就是Track對象,總結一下它使用數據緩沖的調用流程: - 調用Track的getNextBuffer,得到可讀數據緩沖。 - 調用Track的releaseBuffer,釋放數據緩沖。 現在來分析上面這兩個函數:getNextBuffer和releaseBuffer。 (6) getNextBuffer和releaseBuffer的分析 先看getNextBuffer。它從數據緩沖中得到一塊可讀空間: **AudioFlinger.cpp** ~~~ status_tAudioFlinger::PlaybackThread::Track::getNextBuffer( AudioBufferProvider::Buffer*buffer) { audio_track_cblk_t*cblk = this->cblk();//通過CB對象完成 uint32_t framesReady; //frameCount為AudioOutput音頻輸出對象的緩沖區大小 uint32_t framesReq = buffer->frameCount; ...... //根據CB的讀寫指針計算有多少幀數據可讀 framesReady = cblk->framesReady(); if (LIKELY(framesReady)){ uint32_t s = cblk->server; //當前讀位置 //可讀的最大位置,為當前讀位置加上frameCount uint32_tbufferEnd = cblk->serverBase + cblk->frameCount; //AT可以通過setLooping設置播放的起點和終點,如果有終點的話,需要以loopEnd //作為數據緩沖的末尾 bufferEnd = (cblk->loopEnd < bufferEnd) ? cblk->loopEnd :bufferEnd; if(framesReq > framesReady) { //如果要求的讀取幀數大于可讀幀數,則只能選擇實際可讀的幀數 framesReq = framesReady; } //如果可讀幀數的最后位置超過了AT設置的末端點,則需要重新計算可讀幀數 if(s + framesReq > bufferEnd) { framesReq = bufferEnd - s; } //根據讀起始位置得到數據緩沖的起始地址,framesReq參數用來做內部檢查,防止出錯 buffer->raw = getBuffer(s, framesReq); if (buffer->raw == 0) goto getNextBuffer_exit; buffer->frameCount = framesReq; return NO_ERROR; } getNextBuffer_exit: buffer->raw = 0; buffer->frameCount = 0; return NOT_ENOUGH_DATA; } ~~~ getNextBuffer非常簡單,不過就是根據CB記錄的讀寫位置等計算可讀的緩沖位置。下面來看releaseBuffer的操作。 **AudioFlinger.cpp** ~~~ void AudioFlinger::ThreadBase::TrackBase::releaseBuffer( AudioBufferProvider::Buffer*buffer) { buffer->raw = 0; mFrameCount = buffer->frameCount;//frameCount為getNextBuffer中分配的可讀幀數 step();//調用step函數 buffer->frameCount = 0; } ~~~ **AudioFlinger.cpp** ~~~ bool AudioFlinger::ThreadBase::TrackBase::step(){ boolresult; audio_track_cblk_t* cblk = this->cblk(); //調用stepServer更新讀位置 result= cblk->stepServer(mFrameCount); if(!result) { mFlags |= STEPSERVER_FAILED; } returnresult; } ~~~ getNextBuffer和releaseBuffer這兩個函數相對比較簡單。把它和CB交互的流程總結一下,為后面進行CB對象的分析做鋪墊: - getNextBuffer通過frameReady得到可讀幀數。 - getBuffer函數將根據可讀幀數等信息得到可讀空間的首地址。 - releaseBuffer通過stepServer更新讀位置。 5. stop的分析 (1) TrackHandle和Track的回收 來自AT的stop請求最終會通過TrackHandle這個Proxy交給Track的stop處理。請直接看Track的stop: **AudioFlinger.cpp** ~~~ void AudioFlinger::PlaybackThread::Track::stop() { sp<ThreadBase> thread = mThread.promote(); if(thread != 0) { Mutex::Autolock _l(thread->mLock); int state = mState;//保存舊的狀態 if(mState > STOPPED) { mState = STOPPED;//設置新狀態為STOPPED PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); if (playbackThread->mActiveTracks.indexOf(this) < 0) { reset();//如果該線程的活躍數組中沒有Track,則重置讀寫位置 } } //和APS相關,我們不在這里討論,它不直接影響AudioFlinger if(!isOutputTrack() && (state == ACTIVE || state == RESUMING)) { thread->mLock.unlock(); AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType); thread->mLock.lock(); } } } ~~~ 如果Track最初處于活躍數組,那么這個stop函數無非是把mState設置為STOPPED了,但播放該怎么停止呢?請再回頭看prepareTrack_l中的那個判斷: ~~~ if (cblk->framesReady() &&(track->isReady() || track->isStopped()) && !track->isPaused() &&!track->isTerminated()) ~~~ 假設AT寫數據快,而AF消耗數據慢,那么上面這個判斷語句在一定時間內是成立的,換言之,如果僅僅調用了stop,還是會聽到聲音,該怎么辦?在一般情況下,AT端stop后會很快被delete,這將導致AF端的TrackHandle也被delete。 說明:在介紹Track和TrackHandle一節中,曾在最后提到了那個野指針問題。相信讀者這時候會知道那個問題的答案了,是嗎? 看TrackHandle的析構函數: **AudioFlinger.cpp** ~~~ AudioFlinger::TrackHandle::~TrackHandle() { mTrack->destroy(); } ~~~ **AudioFlinger.cpp** ~~~ voidAudioFlinger::PlaybackThread::Track::destroy() { sp<Track> keep(this); { sp<ThreadBase> thread = mThread.promote(); if(thread != 0) { if (!isOutputTrack()) { //和AudioSystem相關,以后再分析 if (mState == ACTIVE || mState == RESUMING) { AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType); } AudioSystem::releaseOutput(thread->id()); } Mutex::Autolock _l(thread->mLock); PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); //調用回放線程對象的destroyTrack_l playbackThread->destroyTrack_l(this); } } } ~~~ **AudioFlinger.cpp** ~~~ voidAudioFlinger::PlaybackThread::destroyTrack_l(const sp<Track>& track) { track->mState = TrackBase::TERMINATED;//設置狀態為TERMINATED if(mActiveTracks.indexOf(track) < 0) { mTracks.remove(track);//如果不在mActiveTracks數組中,則把它從mTracks中去掉。 //由PlaybackThread的子類實現,一般就是回收一些資源等工作 deleteTrackName_l(track->name()); } } ~~~ TrackHandle的delete最后會導致它所代理的Track對象也被刪除,那么Client對象什么時候被回收呢? (2) Client的回收 直接看TrackBase的析構,因為Track的析構會導致它的基類TrackBase析構函數被調用,代碼如下所示: **AudioFlinger.cpp** ~~~ AudioFlinger::ThreadBase::TrackBase::~TrackBase() { if (mCblk) { //placementnew出來的對象需要顯示調用的析構函數 mCblk->~audio_track_cblk_t(); if(mClient == NULL) { delete mCblk;//先調用析構,再釋放內存,這是placement new的用法 } } mCblkMemory.clear(); if(mClient != NULL) { Mutex::Autolock _l(mClient->audioFlinger()->mLock); mClient.clear();//如果mClient的強弱引用計數都為0,則會導致該Client被delete } } ~~~ 資源回收的工作相對比較簡單,這里就不做過多的討論了,讀者可自行分析研究。 * * * * * **說明**:其實,要找到TrackHandle是什么時候被delete,會更有難度。 * * * * *
                  <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>

                              哎呀哎呀视频在线观看