Provider(2)- SourceAudioBufferProvider

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 &timestamp);

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;
}

其工作流程如下:

  1. 传入的buffer参数,buffer.raw=NULL,buffer.frameCount有值表示预期要读取的数据长度
  2. 判断mRemaining是否大于0,true表示上一次getNextBuffer没有读完,保存在mAllocated中,根据mOffset记录的偏移,把mAllocated偏移地址赋值给buffer.raw即可。
  3. 第2步骤为false,说明数据之前从mSource读取的数据已经全部转给buffer了;但是mAllocated的分配的内存还有没有free,就要判断以下mAllocated还能不能被复用;
  4. 复用的条件就是此次buffer.frameCount < mSize,false就不能复用了,重新根据buffer.frameCount大小分配内存,并将地址赋值给mAllocated
  5. 从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之一,可以从这个地方写入数据;

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帅气好男人_Jack

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值