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数据,存放在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 &timestamp);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;
}

其工作流程如下:

  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之一,可以从这个地方写入数据;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/871524.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

11计算机视觉—语义分割与转置卷积

目录 1.语义分割应用语义分割和实例分割2.语义分割数据集:Pascal VOC2012 语义分割数据集预处理数据:我们使用图像增广中的随机裁剪,裁剪输入图像和标签的相同区域。3.转置卷积 上采样填充、步幅和多通道填充步幅多通道转置卷积是一种卷积:重新排列输入和核转置卷积是一种卷…

Java高级重点知识点-22-缓冲流、转换流、序列化流、打印流

文章目录 缓冲流字节缓冲流字符缓冲流 转换流InputStreamReader类OutputStreamWriter类 序列化ObjectOutputStream类ObjectInputStream类 打印流 缓冲流 缓冲流,也叫高效流&#xff0c;是对4个基本的 FileXxx 流的增强&#xff0c;所以也是4个流 基本原理&#xff1a; 缓冲流的…

ES13的4个改革性新特性

1、类字段声明 在 ES13 之前,类字段只能在构造函数中声明, ES13 消除了这个限制 // 之前 class Car {constructor() {this.color = blue;this.age = 2

C++ | Leetcode C++题解之第232题用栈实现队列

题目&#xff1a; 题解&#xff1a; class MyQueue { private:stack<int> inStack, outStack;void in2out() {while (!inStack.empty()) {outStack.push(inStack.top());inStack.pop();}}public:MyQueue() {}void push(int x) {inStack.push(x);}int pop() {if (outStac…

linux_进程周边知识——理解冯诺依曼体系结构

前言&#xff1a; 本篇内容是为了让友友们较好地理解进程的概念&#xff0c; 而在真正了解进行概念之前&#xff0c; 要先了解一下冯诺依曼体系结构。 所以博主会先对冯诺伊曼体系结构进行解释&#xff0c; 然后再讲解进程的概念。 ps&#xff1a; 本篇内容适合了解一些linux指…

大模型时代,还需要跨端framework吗?

跨端 在我近十年的大前端从业经验中&#xff0c;有一半是在和flutter/rn打交道。虽然&#xff0c;flutter和rn官方和社区已经在非常努力的优化、填坑了&#xff0c;但是这两者的坑还是远远高于原生开发。 但是&#xff0c;在锁表的大周期下&#xff0c;华为带着鸿蒙来了&#…

基于复旦微JFMQL100TAI的全国产化FPGA+AI人工智能异构计算平台,兼容XC7Z045-2FFG900I

基于上海复旦微电子FMQL45T900的全国产化ARM核心板。该核心板将复旦微的FMQL45T900&#xff08;与XILINX的XC7Z045-2FFG900I兼容&#xff09;的最小系统集成在了一个87*117mm的核心板上&#xff0c;可以作为一个核心模块&#xff0c;进行功能性扩展&#xff0c;能够快速的搭建起…

springboot大学校园二手书交易APP

摘 要 在数字化与移动互联网迅猛发展的今天&#xff0c;人们对于图书的需求与消费方式也在悄然改变。为了满足广大读者对图书的热爱与追求&#xff0c;我们倾力打造了一款基于Android平台的图书交易APP。这款APP不仅汇聚了海量的图书资源&#xff0c;提供了便捷的交易平台&…

【产品经理】WMS多仓调拨转移说明

对于仓储管理来说&#xff0c;越来越多企业开始应用WMS进行系统化的管理&#xff0c;以提升仓库的作业效率。本文作者从业务流程和基础功能两个方面展开介绍&#xff0c;希望对你有帮助。 一、业务流程 。在线下业务流程拓展&#xff0c;仓库不断增多的过程中&#xff0c;由于…

vscode终端(控制台打印乱码)

乱码出现的两种可能&#xff08;重点是下面标题2&#xff09; 1、文件中的汉字本来就是乱码&#xff0c;输出到控制台(终端)那就当然是乱码 在vscode中设置文件的编码格式为UTF-8&#xff0c; 2、输出到控制台(终端)之前的汉字不是乱码&#xff0c;针对此种情况如下设置 原因…

k8s资源管理中request和limit的区别

在 Kubernetes&#xff08;K8s&#xff09;中&#xff0c;request和limit是两个重要的概念&#xff0c;用于控制和管理容器的资源使用。 Request&#xff08;请求&#xff09;&#xff1a; request定义了容器启动时需要保证的最小资源量。这表示Kubernetes在调度Pod到节点时&a…

用“坦克”来更形象的理解面向对象编程的类的访问权限

我们可以 把私有变量比喻为坦克里面的人&#xff0c;把公共方法比作是驾驶室的门&#xff0c;然后把其他的代码比喻为 子弹&#xff0c;坦克就是一个封装&#xff0c;来保护人 这个比喻非常形象&#xff0c;它很好地解释了封装的概念和它在面向对象编程中的作用。下面我将根据你…

如何隐藏 Ubuntu 顶部状态栏

如何隐藏 Ubuntu 顶部状态栏 Chapter1 如何隐藏 Ubuntu 顶部状态栏Chapter2 Ubuntu增大屏幕可用面积之——自动隐藏顶部状态栏Chapter3 Ubuntu18.04隐藏顶栏与侧栏 Chapter1 如何隐藏 Ubuntu 顶部状态栏 https://www.sysgeek.cn/hide-top-bar-ubuntu/ 准备工作&#xff1a;安…

GuLi商城-商品服务-API-品牌管理-JSR303分组校验

注解:@Validated 实体类: package com.nanjing.gulimall.product.entity;import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.nanjing.common.valid.ListValue; import com.nanjing.common.valid.Updat…

【Python学习笔记】Optuna + Transformer B站视频实践

【Python学习笔记】Optuna Transformer 实践 背景前摇&#xff08;省流可不看&#xff09;&#xff1a; 之前以泰坦尼克号数据集为案例&#xff0c;学习了Optuna的基本操作&#xff0c;为了进一步巩固知识和便于包装简历&#xff0c;决定找个唬人一点的项目练练手。 ————…

conda激活的虚拟环境的python版本不对应

这个大坑&#xff0c;要看看虚拟环境下envs下有没有bin文件夹 python -Vecho $PATH镜像源的问题&#xff0c;参考

Day20—Scrapy与Redis的分布式爬取

分布式爬虫能够利用多台机器的计算能力,同时进行数据的抓取工作,这不仅可以显著提高爬取效率,还可以在面对大规模数据抓取任务时,提供更好的扩展性和稳定性。Scrapy-Redis是一个将Scrapy与Redis结合使用的库,它允许Scrapy爬虫将待爬取的URL和待处理的数据存储在Redis中,从…

Unity脚步.txt

private void OnGUI(){if (GUILayout.Button("test")){}}获取下级物体GameObject spawnList new GameObject[transform.childCount]; // 创建一个敌人生成器 链表for (int i 0; i < spawnList.Length; i){spawnList[i] transform.GetChild(i).gameObject;}、、…

[读论文]Transformers are SSMs

Notation T T T: Sequence length/ time length $$: 摘要 虽然transformer一直是深度学习在语言建模方面成功的主要架构&#xff0c;但状态空间模型(ssm)&#xff0c;如Mamba&#xff0c;最近被证明在中小规模上与transformer相匹配或优于transformer。这些模型族实际上是非常…

数据结构(4.1)——串的存储结构

串的顺序存储 串&#xff08;String&#xff09;的顺序存储是指使用一段连续的存储单元来存储字符串中的字符。 计算串的长度 静态存储(定长顺序存储) #define MAXLEN 255//预定义最大串为255typedef struct {char ch[MAXLEN];//每个分量存储一个字符int length;//串的实际长…