文章目录

  • I . AAudio 音频流 缓冲区控制
  • II . AAudio 音频流 XRun ( UnderRun | OverRun )
  • III . AAudio 音频流 当前每次读写帧数
  • IV . AAudio 音频流 获取最大帧数
  • V . AAudio 音频流 设置缓冲区大小

注意 : 本文讲的是 AAudio 播放器的音频流缓冲区控制 , 可以将帧数理解成音频采样个数 ;
实际的采样帧数 , 与每帧的采样数 , 每帧的大小 是用户自己控制的 , 向 AAudio 音频流读写多少字节的采样 , 是用户自己控制的 ;

2 个缓冲区 : 播放器缓冲区 和 采样缓冲区 ;

  • ① 播放器缓冲区 : 本文讲解的是 播放器缓冲区 设置与调整 ;
  • ② 采样缓冲区 : 采样缓冲区指的是 , 一次性采集多少个字节的数据 , 写入到播放器中 ;
  • ③ 理解 : 这两个缓冲区是不同的概念 , 注意区分 ;

每帧采样数 : 该值就是通道数 , 如果是单声道 , 每帧只有一个采样 , 如果是 双声道立体声 , 每帧有 2 个采样 ;

I . AAudio 音频流 缓冲区控制


1. 判定现状 : 首先要判定当前的 AAudio 音频流是否需要调整 , 判定的依据是是否出现了 XRun , 即 欠载 ( UnderRun ) 或 超限 ( OverRun ) 的状况 ;

2. 计算缓冲区调整值 : 获取本次的 XRun 值 , 然后与上一次的进行对比 , 如果本次的 XRun 值高于上一次 , 那么增加本次缓冲区的帧数 ;

3. 代码示例 :

    //获取 欠载 或 超限 计数 , 这里是播放 , 是欠载// 该值只是用于判定当前是否欠载int32_t underrunCount = AAudioStream_getXRunCount(playStream_);// 获取 AAudio 音频流在不阻塞的情况下 , 可以读取 或 写入的最大帧数 ( 文档说法 感觉不对 )// 获取 当前缓冲区的值aaudio_result_t bufferSize = AAudioStream_getBufferSizeInFrames(playStream_);// 欠载数值是否增加bool hasUnderrunCountIncreased = false;// 是否应该改变缓冲区大小bool shouldChangeBufferSize = false;// 处理 播放完毕 数据还没来得及写入的情况// playStreamUnderrunCount_ 是打开音频流时的 欠载值 , 一般是 0// 如果当前的欠载值 大于 上一次的 欠载值// 将本次的欠载值 更新// 本次的欠载值将作为重新调整缓冲区大小的依据if (underrunCount > playStreamUnderrunCount_) {// 记录 本次的欠载值playStreamUnderrunCount_ = underrunCount;// 设置需要更新缓冲区大小hasUnderrunCountIncreased = true;}if (hasUnderrunCountIncreased && bufferSizeSelection_ == BUFFER_SIZE_AUTOMATIC) {// 用户没有设置缓冲区大小 , 此时 bufferSizeSelection_ 的值 为 BUFFER_SIZE_AUTOMATIC , 即 0/*** 这是一个调整缓冲区大小的算法 ;* 如果本次的 欠载 ( UnderRun ) 值 与 上一次回时的欠载值进行对比 , 本次高于上次的值 ,*  此时需要增加缓冲区的大小 , 增加数值为 单次写出的大小 ( Burst Size ) ;*  增加的 Burst Size 会防止未来出现 欠载 情形 , 同时该操作会以增加延迟为代价 ;** 欠载 ( UnderRun ) 即 现有数据播放完毕 , 新数据还没有写入 , 出现空档 , 造成电流 ;*      无法提供足够的音频采样数据 ;*/bufferSize += framesPerBurst_; // 缓冲区的大小增加 每次写入的帧数大小 Increase buffer size by one burstshouldChangeBufferSize = true;} else if (bufferSizeSelection_ > 0 && (bufferSizeSelection_ * framesPerBurst_) != bufferSize) {// 用户有设置缓冲区大小 , 并且这个大小与之前的大小不一致的情况 , 才修改缓冲区大小数值// 用户每次修改缓冲区大小 , 该分支代码逻辑就会执行一次// 如果用户修改了缓冲区大小 , 那么执行该逻辑bufferSize = bufferSizeSelection_ * framesPerBurst_;shouldChangeBufferSize = true;}//是否修改了缓冲区大小if (shouldChangeBufferSize) {LOGD("Setting buffer size to %d", bufferSize);//设置当前缓冲区是多少帧bufferSize = AAudioStream_setBufferSizeInFrames(stream, bufferSize);if (bufferSize > 0) {//更新当前类中维护的每帧缓冲区大小数值bufSizeInFrames_ = bufferSize;} else {LOGE("Error setting buffer size: %s", AAudio_convertResultToText(bufferSize));}}

II . AAudio 音频流 XRun ( UnderRun | OverRun )


1. XRun 概念 : XRun 是指 AAudio 音频流的 欠载 ( UnderRun ) 或 超限 ( OverRun ) ;

  • ① 欠载 ( UnderRun ) : 播放音频流时 , 如果当前现有数据已经播放完毕 , 新数据还没有来得及写入 , 此时会发生欠载情况 ;
  • ② 超限 ( OverRun ) : 录制音频流时 , 如果没有及时读取音频流数据 , 并且这些数据没有妥善保存 , 发生溢出 , 导致数据丢失 , 这种情况叫做超限 ;

2. 获取 XRun 数据 : 使用 AAudioStream_getXRunCount() 方法 , 可以获取该 XRun 数值 ;

3. AAudioStream_getXRunCount 函数原型 :

AAUDIO_API int32_t AAudioStream_getXRunCount(AAudioStream *stream
)

4. AAudioStream_getXRunCount 方法参数 : 传入 AAudio 音频流 指针类型 , 可以获取该音频流的 欠载 ( UnderRun ) 或 超限 ( OverRun ) 值 ;

5. 欠载 ( UnderRun ) 或 超限 ( OverRun ) 导致的问题 : 会导致出现电流问题 ;

6. 不支持 XRun 统计 的情况 : 某些设备可能不支持统计该数据 , 此时返回的 XRun 值为 0 ;

III . AAudio 音频流 当前每次读写帧数


1. AAudio 音频流 每次读写的帧数 :

  • ① 当前读写帧数查询 : 在 AAudio 音频流读写音频数据时 , 为了达到性能最佳 , 需要查询当前音频流一次性可以读写的帧数 ;
  • ② 查询方法 : 为了达到流读写的最佳性能 , 可以使用 AAudioStream_getFramesPerBurst 方法 , 查询该数值 ;
  • ③ 帧数调整 : 应用中可以向 AAudio 音频流 读写 不同帧数的音频采样数据 , 但是为了避免 欠载 ( UnderRun ) 或 超限 ( OverRun ) , 我们可以增加该值 , 防止出现 数据不足 或 数据溢出 的情况 ;
  • ④ 帧数变动后果 : 实际音频设备一次性读写数据量可能与该帧数不匹配 ; 对于某些音频设备 , 该 Brust ( 一次性读写数据量 ) 大小可以动态改变 ; 该操作可能会增大音频的延迟 ;
  • ⑤ 每帧采样数 : 该值就是通道数 , 如果是单声道 , 每帧只有一个采样 , 如果是 双声道立体声 , 每帧有 2 个采样 ;

2. 获取每次读写帧数的函数 :

  • ① 函数原型 :
AAUDIO_API int32_t AAudioStream_getFramesPerBurst(AAudioStream *stream
)
  • ② 方法简介 : 该方法 传入 AAudioStream 指针类型参数 ( 代表 AAudio 音频流 ) , 可以获取该 AAudio 音频流每次读写的帧数 ;
  • ③ 代码示例 :
            // 获取每次写入的帧数framesPerBurst_ = AAudioStream_getFramesPerBurst(playStream_);

IV . AAudio 音频流 获取最大帧数


AAudio 音频流 获取最大帧数 : 调用 AAudioStream_getBufferSizeInFrames() 方法 , 可以获取 AAudio 音频流在不阻塞的情况下 , 可以读取 或 写入的最大帧数 ;

  • ① 方法原型 :
AAUDIO_API int32_t AAudioStream_getBufferSizeInFrames(AAudioStream *stream
)
  • ② 代码示例 :
    // 获取 AAudio 音频流在不阻塞的情况下 , 可以读取 或 写入的最大帧数 aaudio_result_t bufferSize = AAudioStream_getBufferSizeInFrames(playStream_);

V . AAudio 音频流 设置缓冲区大小


1. 函数作用 : 在音频流播放时 , 有可能会产生阻塞 , 即 采样播放完毕 , 新采样还没到达 , 该函数可以 通过 改变 缓冲区大小阈值 , 调整 缓冲区的延迟 , 即 如果出现 阻塞 , 可以增大该缓冲区大小 ( 帧数 ) ;

2. 结合 XRun 值使用 : 通过 AAudioStream_getXRunCount() 方法 , 可以获取 欠载 ( UnderRun ) 或 超限 ( OverRun ) 的值 , 根据该 XRun 值进行缓冲区大小的调整 , 达到为每个音频设备设置合适的延迟的目的 ;

3. 可设置的最大值 : 通过 AAudioStream_getBufferCapacityInFrames() 函数可以获取 缓冲区可设置的最大帧数 , 设置帧数时 , 不能超过该数值 ;

4. 查看当前缓冲区大小 : 调用 AAudioStream_getBufferSizeInFrames() 方法 , 可以查看当前的缓冲区帧数 ;

文档中的说法是 : 获取 AAudio 音频流在不阻塞的情况下 , 可以读取 或 写入的最大帧数 , 理解不通 ;

5. AAudioStream_setBufferSizeInFrames 函数简介 :

  • ① 函数原型 : numFrames 是设置的新的缓冲区帧数 , stream 代表 AAudio 音频流指针 ;
AAUDIO_API aaudio_result_t AAudioStream_setBufferSizeInFrames(AAudioStream *stream,int32_t numFrames
)
  • ② 代码示例 :
        //设置当前缓冲区是多少帧bufferSize = AAudioStream_setBufferSizeInFrames(stream, bufferSize);

每帧采样数 : 该值就是通道数 , 如果是单声道 , 每帧只有一个采样 , 如果是 双声道立体声 , 每帧有 2 个采样 ;

【Android 高性能音频】AAudio 缓冲区控制 ( XRun | 欠载 UnderRun | 超限 OverRun | 获取缓冲区大小 | 设置缓冲区大小 )相关推荐

  1. 【Android 高性能音频】Oboe 开发流程 ( 包含头 Oboe 头文件 | 创建音频流 | 设置音频流 | 音频流回调类 AudioStreamCallback )

    文章目录 一.包含头 Oboe 头文件 二.音频流构建器 AudioStreamBuilder 三.音频流回调 AudioStreamCallback Oboe GitHub 主页 : GitHub/ ...

  2. 【Android 高性能音频】AAudio 音频流 数据回调细节 ( 数据回调函数优先级 | 数据回调函数 | 采样率 | 采样数 | 缓冲区调整 | 线程不安全 )

    文章目录 I . 数据回调函数优先级 II . 数据回调函数 相关内容 III . 采样率 处理细节 IV . 数据回调函数 每次 采样个数 numFrames V . 数据回调函数 缓冲区 ( AA ...

  3. 【Android 高性能音频】AAudio 音频流 缓冲区 简介 ( AAudio 音频流内部缓冲区 | 缓冲区帧容量 | 缓冲区帧大小 | 音频数据读写缓冲区 )

    文章目录 I . AAudio 音频流内部缓冲区 与 音频数据读写缓冲区 概念 II . AAudio 音频流内部缓冲区 缓冲区帧容量 BufferCapacityInFrames 与 缓冲区帧大小 ...

  4. 【Android 高性能音频】OboeTest 音频性能测试应用 ( 应用简介 | 测试内容 | 输出测试 | Oboe 缓冲区 与 工作负载修改 | 测试案例 )

    文章目录 一.Oboe 测试应用 二.Oboe 测试内容 三.Oboe 输出测试 四.Oboe 缓冲区 与 工作负载修改 五.Oboe 输出测试 ( Pixel 2 | Android 10 ) 一. ...

  5. 【Android 高性能音频】Oboe 播放器开发 ( 为 OpenSL ES 配置参数以获得最佳延迟 | Oboe 音频流 | Oboe 音频设备 )

    文章目录 一.获得最佳延迟 二.Oboe 音频流 三.Oboe 音频设备 Oboe GitHub 主页 : GitHub/Oboe ① 简单使用 : Getting Started ② Oboe 全指 ...

  6. 【Android 高性能音频】Oboe 开发流程 ( Oboe 音频帧简介 | AudioStreamCallback 中的数据帧说明 )

    文章目录 一.音频帧概念 二.AudioStreamCallback 中的音频数据帧说明 Oboe GitHub 主页 : GitHub/Oboe ① 简单使用 : Getting Started ② ...

  7. 【Android 高性能音频】Oboe 开发流程 ( Oboe 完整代码示例 )

    文章目录 一.GitHub 地址 二.Oboe C++ 代码 三.日志封装 四.Activity 代码 五.AndroidManifest.xml 配置文件 六.CMakeLists.txt 构建脚本 ...

  8. 【Android 高性能音频】Oboe 开发流程 ( 检查 Oboe 音频流属性 | 开始播放 | 停止播放 | 关闭 Oboe 音频流 | 重新配置 Oboe 音频流属性 )

    文章目录 一.检查 Oboe 音频流属性 二.开始播放 三.停止播放 四.关闭音频流 五.重新配置 Oboe 音频流属性 Oboe GitHub 主页 : GitHub/Oboe ① 简单使用 : G ...

  9. 【Android 高性能音频】Oboe 开发流程 ( 创建并设置 AudioStreamCallback 对象 | 打开 Oboe 音频流 | 日志封装 logging_macros.h )

    文章目录 一.创建并设置 AudioStreamCallback 对象 二.打开 Oboe 音频流 三.日志封装 Oboe GitHub 主页 : GitHub/Oboe ① 简单使用 : Getti ...

最新文章

  1. 5教程 watchout_Unit 5单元复习学案设计
  2. 1102面向对象和类原型
  3. 如何生成文件夹目录树文件
  4. Java初学者不得不知的概念,JDK,JRE,JVM的区别?
  5. java客户端传递参数_java – 在客户端传递参数
  6. BZOJ 3156: 防御准备( dp + 斜率优化 )
  7. 浅析C++中的this指针 通过空指针(NULL)可以正确调用一些类的成员函数?
  8. Android官方开发文档Training系列课程中文版:使用Fragment构建动态UI之Fragment创建
  9. python zipfile 乱码_python zipfile文件名乱码问题
  10. 100万并发连接服务器笔记之1M并发连接目标达成
  11. 利用os模块生成 文件夹和文件
  12. 测试人员必看——掌握7大技能,做好自动化测试就不是问题!
  13. python 单例模式,一个类只能生成唯一的一个实例,重写__new__方法详解
  14. json文件编辑器android版,json editor手机版下载
  15. python 欠采样_欠采样(undersampling)和过采样(oversampling)会对模型带来怎样的影响?...
  16. 指数的增长和衰退问题
  17. 服务器4块固态硬盘做raid5,RAID 5与RAID 10、硬盘和固态硬盘
  18. ImageWarping变形算法研究---反距离加权插值(IDW)
  19. EXCEL篇—时间序列分析(季节指数法)
  20. SQL查询语句分步详解——多字段分组查询

热门文章

  1. PMP高效工作---鱼骨图分析法
  2. Sensors传感器介绍(一)
  3. 什么人群适合考PMP?
  4. 神经反馈4——“组合”训练方案
  5. 牛客[水]悠悠碧波(Next数组+kmp小运用)
  6. Windows平台关于Qt+QML应用文件的发布
  7. Word公式键入——UnicodeMath语法对照简表
  8. 港科夜闻|香港科大与香港科大(广州)管理层联席会议顺利召开
  9. mysql5 workbench教程_详解MySQL Workbench使用教程
  10. Java获取图片||图标