obtainBuffer數據是如何傳輸

MediaPlayer那邊就不看了,從AudioTrack開始研究。


1、AudioTrack::write函數
調用函數obtainBuffer獲取到一塊buffer,然後把傳入的數據copy到獲取的buffer中。


2、AudioTrack::obtainBuffer函數
該函數的主要功能就是對傳入的audioBuffer進行賦值。
看看audioBuffer的類型:
class Buffer
    {
    public:
        enum {
            MUTE    = 0x00000001
        };
        uint32_t    flags;
        int         channelCount;
        int         format;
        size_t      frameCount;
        size_t      size;
        union {
            void*       raw;
            short*      i16;
            int8_t*     i8;
        };
    };

其中存放數據的是下面這個東東:
union {
            void*       raw;
            short*      i16;
            int8_t*     i8;
        };

對這塊東東賦值的代碼如下:
audioBuffer->raw = (int8_t *)cblk->buffer(u);


先看其中cblk的來歷:
audio_track_cblk_t* cblk = mCblk;


mCblk的賦值在函數AudioTrack::createTrack中:
mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());


cblk的由來:
sp<IMemory> cblk = track->getCblk();


track的由來:
    sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
                                                      streamType,
                                                      sampleRate,
                                                      format,
                                                      channelCount,
                                                      frameCount,
                                                      ((uint16_t)flags) << 16,
                                                      sharedBuffer,
                                                      output,
                                                      &mSessionId,
                                                      &status);
 
函數AudioFlinger::createTrack返回的是一個TrackHandle對象:
trackHandle = new TrackHandle(track);
return trackHandle;


track的由來:
        track = thread->createTrack_l(client, streamType, sampleRate, format,
                channelCount, frameCount, sharedBuffer, lSessionId, &lStatus);

函數AudioFlinger::PlaybackThread::createTrack_l返回的是一個Track對象:
        track = new Track(this, client, streamType, sampleRate, format,
                channelCount, frameCount, sharedBuffer, sessionId);
    return track;

看看函數TrackHandle::getCblk() :
return mTrack->getCblk();


mTrack就是作爲構造函數傳入的track對象。


函數AudioFlinger::ThreadBase::TrackBase::getCblk() 的實現:
return mCblkMemory;


mCblkMemory的賦值在構造函數AudioFlinger::ThreadBase::TrackBase::TrackBase中:
mCblkMemory = client->heap()->allocate(size);
mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer()); // 這個成員變量也很重要


client是構造函數參數:
const sp<Client>& client


函數AudioFlinger::Client::heap:
return mMemoryDealer;


mMemoryDealer的賦值在函數AudioFlinger::Client::Client中:
mMemoryDealer(new MemoryDealer(1024*1024, "AudioFlinger::Client"))


看看函數MemoryDealer::allocate:
sp<IMemory> MemoryDealer::allocate(size_t size)
{
    sp<IMemory> memory;
// allocator()直接返回mAllocator
// mAllocator的賦值在構造函數中:mAllocator(new SimpleBestFitAllocator(size))
/× 函數SimpleBestFitAllocator::allocate的實現:
size_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags)
{
Mutex::Autolock _l(mLock);
// 暫止
ssize_t offset = alloc(size, flags);
return offset;
}
×/
    const ssize_t offset = allocator()->allocate(size);
    if (offset >= 0) {
// heap()直接返回mHeap
// mHeap的賦值在構造函數中:mHeap(new MemoryHeapBase(size, 0, name))
        memory = new Allocation(this, heap(), offset, size);
    }
    return memory;
}


可見前面的mCblkMemory其實就是一個Allocation對象。


可見AudioTrack的成員變量mCblk和AudioFlinger::ThreadBase::TrackBase的成員變量mCblk的值相同,
都是:static_cast<audio_track_cblk_t *>(mCblkMemory->pointer())。


函數IMemory::pointer的實現:
void* IMemory::pointer() const {
    ssize_t offset;
    sp<IMemoryHeap> heap = getMemory(&offset);
    void* const base = heap!=0 ? heap->base() : MAP_FAILED;
    if (base == MAP_FAILED)
        return 0;
    return static_cast<char*>(base) + offset;
}


回頭過去,看看函數audio_track_cblk_t::buffer:
return (int8_t *)this->buffers + (offset - userBase) * this->frameSize;


可見audio_track_cblk_t的主要作用是申請了一塊內存空間。
調用函數AudioTrack::write的時候,會先將數據寫到這個內存空間中。


3、數據寫入到了audio_track_cblk_t中,誰又會來使用這些數據呢?
看代碼可知,函數AudioTrack::obtainBuffer中會先調用audio_track_cblk_t::framesAvailable。
同時,我們發現還有一個函數audio_track_cblk_t::framesReady。
單從字面上也可以看出來,這是告訴用戶準備好了多少數據。
搜搜哪兒調用了函數audio_track_cblk_t::framesReady吧。
搜了下,發現有三個函數中調用了它,分別是:
AudioFlinger::MixerThread::prepareTracks_l函數
AudioFlinger::DirectOutputThread::threadLoop函數
AudioFlinger::PlaybackThread::Track::getNextBuffer函數


4、先看看函數AudioFlinger::MixerThread::prepareTracks_l函數。
字面上看,應該是準備提供數據的Tracks。
果然不錯,函數中調用AudioMixer::setBufferProvider將Track設置到mAudioMixer(AudioMixer)中。
函數AudioMixer::setBufferProvider實現:
status_t AudioMixer::setBufferProvider(AudioBufferProvider* buffer)
{
    mState.tracks[ mActiveTrack ].bufferProvider = buffer;
    return NO_ERROR;
}
然後調用函數AudioMixer::setParameter將Track的main buffer也設置到mAudioMixer(AudioMixer)中。
函數AudioMixer::setParameter中與main buffer相關的部分代碼:
        if (name == MAIN_BUFFER) {
            if (mState.tracks[ mActiveTrack ].mainBuffer != valueBuf) {
                mState.tracks[ mActiveTrack ].mainBuffer = valueBuf;
                LOGV("setParameter(TRACK, MAIN_BUFFER, %p)", valueBuf);
                invalidateState(1<<mActiveTrack);
            }
            return NO_ERROR;
        }


類函數AudioMixer中是如何來使用bufferProvider的呢?
AudioMixer中的以process__爲前綴的幾個函數都是有到了bufferProvider。
但從數據傳輸上來說,這幾個函數是類似的。
我們只看其中的AudioMixer::process__OneTrack16BitsStereoNoResampling函數。
函數中有代碼:
t.bufferProvider->getNextBuffer(&b);
我們知道,bufferProvider其實就是Track,而我們探討的是音頻播放,所以就跳到了函數:AudioFlinger::PlaybackThread::Track::getNextBuffer,
也就是前面我們搜到的,調用audio_track_cblk_t::framesReady的三個函數之一。
函數AudioFlinger::PlaybackThread::Track::getNextBuffer是從audio_track_cblk_t中取得已準備好的音頻數據,
寫到什麼地方去,下面我們開始研究。


回到函數process__OneTrack16BitsStereoNoResampling中,我們知道,調用AudioFlinger::PlaybackThread::Track::getNextBuffer獲取的地址賦值給了in:
int16_t const *in = b.i16;


後來取in的數據給了rl:
uint32_t rl = *reinterpret_cast<uint32_t const *>(in);


然後將rl賦值給out:
*out++ = (r<<16) | (l & 0xFFFF);


由此可見,我們剛纔疑惑的“寫到什麼地方去”,其實就是寫到out裏了。


out的來歷:
int32_t* out = t.mainBuffer;


這不就是函數AudioMixer::setParameter中賦值的main buffer麼???
搞了一圈,原來AudioMixer的功能就是將Track裏audio_track_cblk_t中的數據,賦值給Track裏的mainBuffer。


下面好好看看這個main buffer的來歷吧。


由前面的分析可知,調用函數AudioMixer::setParameter,來設置main buffer的地方是函數AudioFlinger::MixerThread::prepareTracks_l。
回過去看看對函數AudioMixer::setParameter的調用:
            mAudioMixer->setParameter(
                AudioMixer::TRACK,
                AudioMixer::MAIN_BUFFER, (void *)track->mainBuffer());
函數mainBuffer()實現:
 return mMainBuffer; 
 
 mMainBuffer的賦值在函數setMainBuffer中:
 setMainBuffer(int16_t *buffer) { mMainBuffer = buffer; }
 
 看看誰調用了函數setMainBuffer吧。
 
 有三個地方調用了函數setMainBuffer:
 a、AudioFlinger::PlaybackThread::createTrack_l函數
 b、AudioFlinger::PlaybackThread::addEffectChain_l函數
 c、AudioFlinger::PlaybackThread::removeEffectChain_l函數
 
 b和c類似,都是將PlaybackThread的mMixBuffer賦值給了main buffer。
 
 先看看a.
 track->setMainBuffer(chain->inBuffer());
 作爲main buffer的是chain->inBuffer()這個東東。
 
 inBuffer()函數實現:return mInBuffer;
 mInBuffer中函數setInBuffer中被賦值:
 mInBuffer = buffer;
 
 看看調用setInBuffer函數的地方:
 AudioFlinger::PlaybackThread::addEffectChain_l函數
 AudioFlinger::EffectChain::addEffect_l函數
 
 先看看AudioFlinger::PlaybackThread::addEffectChain_l函數中的處理,
 函數中根據是否爲DIRECT output thread,有兩種處理方式:
 一種是處理direct output thread:
調用函數setMainBuffer將PlaybackThread的mMixBuffer告訴給Track,即告訴Track,在AudioMixer中往PlaybackThread的mMixBuffer中copy數據。
然後將effect  chain的input buffer和output buffer都設置爲PlaybackThread的mMixBuffer。
(目的是讓該effect chain不起作用?存在註釋“Only one effect chain can be present in direct output thread and it usesthe mix buffer as input”)
另一種是處理非direct output thread:
new一段buffer出來。
調用函數setMainBuffer將新buffer告訴給Track,即告訴Track,在AudioMixer中往新buffer中copy數據。
調用函數setInBuffer來實裝chain的input buffer。(發現函數AudioFlinger::PlaybackThread::createTrack_l中其實有將chain的input buffer賦值給Track的main buffer)。
然後將PlaybackThread的mMixBuffer賦值給chain的output buffer。
也就是說,Track將數據copy到自己的main buffer(即effect chain的input buffer),
effect chain對數據進行處理,然後將處理過的數據賦值給自己的output buffer(即PlaybackThread的mMixBuffer)

mMixBuffer是如何被使用的呢?


函數AudioFlinger::MixerThread::threadLoop中調用函數AudioStreamOutALSA::write(HAL側)。
函數AudioStreamOutALSA::write中調用了函數snd_pcm_mmap_writei或者snd_pcm_writei。
函數snd_pcm_mmap_writei或者snd_pcm_writei將mMixBuffer中的數據寫入到底層。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章