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数据,存放在buffer
virtual status_t getNextBuffer(Buffer *buffer);
//buffer使用完后,release掉buffer
virtual void releaseBuffer(Buffer *buffer);
// ExtendedAudioBufferProvider interface
virtual 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 bytes
void* mAllocated; // pointer to base of allocated memory
size_t mSize; // size of mAllocated in frames
size_t mOffset; // frame offset within mAllocated of valid data
size_t mRemaining; // frame count within mAllocated of valid data
size_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函数第一个参数是数量,第二个是每一个的大小,并且
// 初始化为0
mAllocated = calloc(buffer->frameCount, mFrameSize);
if (mAllocated == NULL) {
mSize = 0;
goto fail;
}
mSize = buffer->frameCount;
}
{
// read from source
ssize_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之一,可以从这个地方写入数据;