文章目录- 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. 代码示例 :
代码语言:javascript复制 //获取 欠载 或 超限 计数 , 这里是播放 , 是欠载
// 该值只是用于判定当前是否欠载
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 burst
shouldChangeBufferSize = 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 函数原型 :
代码语言:javascript复制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 个采样 ;