Android Audio代码分析10 - audio_track_cblk_t::framesReady函数
在看AudioTrack的write函数的时候,了解到,音频数据最终都写到了audio_track_cblk_t的结构体中。
这个结构体是在AudioFlinger中创建的。
AudioFlinger是如何来使用这些数据的呢?
今天就来学习学习。
我们写数据的时候,调用了audio_track_cblk_t::framesAvailable_l函数,来判断是否有可用的空间,以供写用。
类audio_track_cblk_t中还有另外一个函数framesReady,看名字,应该是告诉我们已经准备好了多少东东。
看样子,AudioFlinger在使用音频数据的时候,应该是先调用了framesReady函数,来看看我们已经写进去多少音频数据了,然后再使用这些数据。
*****************************************源码*************************************************
uint32_t audio_track_cblk_t::framesReady()
{
uint64_t u = this->user;
uint64_t s = this->server;
if (flags & CBLK_DIRECTION_MSK) {
if (u < loopEnd) {
return u - s;
} else {
Mutex::Autolock _l(lock);
if (loopCount >= 0) {
return (loopEnd - loopStart)*loopCount + u - s;
} else {
return UINT_MAX;
}
}
} else {
return s - u;
}
}
**********************************************************************************************
源码路径:
frameworks\base\media\libmedia\AudioTrack.cpp
#######################说明################################
之前看代码都是顺藤摸瓜,今天要顺瓜摸藤了。
看看什么地方调用了函数framesReady。
搜了一下,调用的地方还真不少。
不过,很多地方只是用调用结果来作判断,
只有在函数AudioFlinger::PlaybackThread::Track::getNextBuffer中,把返回值保存了下来。
以前看代码知道,写数据的时候,framesAvailable返回值是被保存起来,并使用的。
类推一下,读数据的时候,framesReady的返回值也应该被保存使用。
于是就来到了函数AudioFlinger::PlaybackThread::Track::getNextBuffer中:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
{
audio_track_cblk_t* cblk = this->cblk();
uint32_t framesReady;
uint32_t framesReq = buffer->frameCount;
// Check if last stepServer failed, try to step now
if (mFlags & TrackBase::STEPSERVER_FAILED) {
if (!step()) goto getNextBuffer_exit;
LOGV("stepServer recovered");
mFlags &= ~TrackBase::STEPSERVER_FAILED;
}
framesReady = cblk->framesReady();
if (LIKELY(framesReady)) {
uint64_t s = cblk->server;
uint64_t bufferEnd = cblk->serverBase + cblk->frameCount;
bufferEnd = (cblk->loopEnd < bufferEnd) ? cblk->loopEnd : bufferEnd;
if (framesReq > framesReady) {
framesReq = framesReady;
}
if (s + framesReq > bufferEnd) {
framesReq = bufferEnd - s;
}
buffer->raw = getBuffer(s, framesReq);
if (buffer->raw == 0) goto getNextBuffer_exit;
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void* AudioFlinger::ThreadBase::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
audio_track_cblk_t* cblk = this->cblk();
int8_t *bufferStart = (int8_t *)mBuffer + (offset-cblk->serverBase)*cblk->frameSize;
int8_t *bufferEnd = bufferStart + frames * cblk->frameSize;
// Check validity of returned pointer in case the track control block would have been corrupted.
if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd ||
((unsigned long)bufferStart & (unsigned long)(cblk->frameSize - 1))) {
LOGE("TrackBase::getBuffer buffer out of range:\n start: %p, end %p , mBuffer %p mBufferEnd %p\n \
server %lld, serverBase %lld, user %lld, userBase %lld, channelCount %d",
bufferStart, bufferEnd, mBuffer, mBufferEnd,
cblk->server, cblk->serverBase, cblk->user, cblk->userBase, cblk->channelCount);
return 0;
}
return bufferStart;
}
----------------------------------------------------------------
buffer->frameCount = framesReq;
return NO_ERROR;
}
getNextBuffer_exit:
buffer->raw = 0;
buffer->frameCount = 0;
LOGV("getNextBuffer() no more data for track %d on thread %p", mName, mThread.unsafe_get());
return NOT_ENOUGH_DATA;
}
----------------------------------------------------------------
下面看看哪个地方调用了函数AudioFlinger::PlaybackThread::Track::getNextBuffer。
搜索发现,AudioFlinger中只有函数AudioFlinger::DirectOutputThread::threadLoop调用了,
而我们说的AudioTrack是播放音乐用的,所以,肯定不是这儿。
另外,发现AudioMixer中有几个地方调用了函数getNextBuffer,不过调用代码如下:
t.bufferProvider->getNextBuffer(&t.buffer);
bufferProvider和AudioFlinger::PlaybackThread::Track又存在怎样的关系呢?
bufferProvider的定义代码:AudioBufferProvider* bufferProvider;
存在以下继承关系:
class Track : public TrackBase
class TrackBase : public AudioBufferProvider, public RefBase
可见,bufferProvider最终指向的是AudioFlinger::Pla
补充:移动开发 , Android ,