SourceAudioBufferProvider
从Source源端出来的数据,通常是来自于应用层,但没有与应用层直接连接,通过MonoPipe相关类连接,其SourceAudioBufferProvider和MonoPipe相关类的包含关系图如下:
如上图,SourceAudioBufferProvider持有MonoPipeReader,依次持有audio_utils_reader,而audio_utils_fifo是一个队列fifo的管理类,应用侧逻辑通过audio_utils_writer往fifo队列写数据,而audio_utils_reader则从fifo队列中read数据,当SourceAudioBufferProvider调用getNextBuffer时就会从fifo读取数据,获得音频数据,也就是这样的一个逻辑
提个问题:audio_utils_writer是在哪块地方写入的数据?
成员和方法构成
class SourceAudioBufferProvider : public ExtendedAudioBufferProvider {public:SourceAudioBufferProvider(const sp<NBAIO_Source>& source);virtual ~SourceAudioBufferProvider();// AudioBufferProvider interface 从mSource中read数据,存放在buffervirtual status_t getNextBuffer(Buffer *buffer);//buffer使用完后,release掉buffervirtual void releaseBuffer(Buffer *buffer);// ExtendedAudioBufferProvider interfacevirtual size_t framesReady() const; //mSource准备好多少数据,可以去read了virtual int64_t framesReleased() const; //getNextBuffer获取的buffer,relase掉后的累计值virtual void onTimestamp(const ExtendedTimestamp ×tamp);private:const sp<NBAIO_Source> mSource; // 数据原包裹类the wrapped source/*const*/ size_t mFrameSize; // frame size in bytesvoid* mAllocated; // pointer to base of allocated memorysize_t mSize; // size of mAllocated in framessize_t mOffset; // frame offset within mAllocated of valid datasize_t mRemaining; // frame count within mAllocated of valid datasize_t mGetCount; // 最近调用getNextBuffer获取的长度int64_t mFramesReleased; // counter of the total number of frames released
};
每个意义在注释里面已经标注好了,重要的方法是getNextBuffer,用于去数据源mSource中read数据到参数buffer中去,而成员mAllocated就是read数据时分配的内存,其它成员用于描述mAllocated上的读取状态,最后将mAllocated的地址赋值给参数buffer,所以至关重要的弄清楚getNextBuffer的代码逻辑
getNextBuffer
如下源码:
/*参数buffer也就是读取数据的缓存,数据是读出去,放到buffer里面*/
status_t SourceAudioBufferProvider::getNextBuffer(Buffer *buffer)
{ALOG_ASSERT(buffer != NULL && buffer->frameCount > 0 && mGetCount == 0); // any leftover data available? 仍有有效数据,且还小于buffer的总长度,也就是mAllocated有遗留没读出去的数据// 重新更新一下读取位置即可if (mRemaining > 0) {ALOG_ASSERT(mOffset + mRemaining <= mSize);if (mRemaining < buffer->frameCount) {buffer->frameCount = mRemaining;}buffer->raw = (char *) mAllocated + (mOffset * mFrameSize);mGetCount = buffer->frameCount;return OK; } // do we need to reallocate?// 如果这次buffer读取的数据大于上一次的总大小,就要重新分配内存;那如果小于呢,就不重新分配?if (buffer->frameCount > mSize) {free(mAllocated);// Android convention is to _not_ check the return value of malloc and friends.// But in this case the calloc() can also fail due to integer overflow,// so we check and recover.callc函数第一个参数是数量,第二个是每一个的大小,并且// 初始化为0mAllocated = calloc(buffer->frameCount, mFrameSize);if (mAllocated == NULL) {mSize = 0;goto fail;}mSize = buffer->frameCount;}
{// read from sourcessize_t actual = mSource->read(mAllocated, buffer->frameCount);if (actual > 0) {ALOG_ASSERT((size_t) actual <= buffer->frameCount);mOffset = 0;mRemaining = actual;buffer->raw = mAllocated;buffer->frameCount = actual;mGetCount = actual;return OK;}}
fail:buffer->raw = NULL;buffer->frameCount = 0;mGetCount = 0;return NOT_ENOUGH_DATA;
}
其工作流程如下:
- 传入的buffer参数,buffer.raw=NULL,buffer.frameCount有值表示预期要读取的数据长度
- 判断mRemaining是否大于0,true表示上一次getNextBuffer没有读完,保存在mAllocated中,根据mOffset记录的偏移,把mAllocated偏移地址赋值给buffer.raw即可。
- 第2步骤为false,说明数据之前从mSource读取的数据已经全部转给buffer了;但是mAllocated的分配的内存还有没有free,就要判断以下mAllocated还能不能被复用;
- 复用的条件就是此次buffer.frameCount < mSize,false就不能复用了,重新根据buffer.frameCount大小分配内存,并将地址赋值给mAllocated
- 从mSource中read应用侧的数据到mAllocated,将实际读取的长度acutal给buffer.frameCount,完成数据转交,并且mRemaining也为acutal;
当调用releaseBuffer时才会把mRemaining中减掉清除
小结
SourceAudioBufferProvider逻辑相对简单,重点在getNextBuffer中,并且要理清整个数据传递流程,而不是仅限于当前函数;
回到开头提到的问题,audio_utils_writer什么时候往里面写数据的,还记得上面的包含图吗?audio_utils_writer被MonoPipe包裹,在Threads.cpp中的threadLoop_write中:
ssize_t AudioFlinger::PlaybackThread::threadLoop_write()
{.....ssize_t framesWritten = mNormalSink->write((char *)mSinkBuffer + offset, count);.....
}
这里mNormalSink就是MonoPipe之一,可以从这个地方写入数据;