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中的數據寫入到底層。
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中的數據寫入到底層。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.