当前位置:操作系统 > 安卓/Android >>

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 ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,