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

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

文章目录

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 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 函数原型 :


AAUDIO_API int32_t AAudioStream_getXRunCount(

 AAudioStream *stream

)

1

2

3

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

)

1

2

3

② 方法简介 : 该方法 传入 AAudioStream 指针类型参数 ( 代表 AAudio 音频流 ) , 可以获取该 AAudio 音频流每次读写的帧数 ;

③ 代码示例 :

           // 获取每次写入的帧数

           framesPerBurst_ = AAudioStream_getFramesPerBurst(playStream_);

1

2



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 个采样 ;


目录
相关文章
|
1月前
|
数据库 Android开发 开发者
构建高性能微服务架构:从理论到实践构建高效Android应用:探究Kotlin协程的优势
【2月更文挑战第16天】 在当今快速迭代和竞争激烈的软件市场中,微服务架构以其灵活性、可扩展性和独立部署能力而受到企业的青睐。本文将深入探讨如何构建一个高性能的微服务系统,涵盖从理论基础到具体实现的各个方面。我们将重点讨论服务拆分策略、通信机制、数据一致性以及性能优化等关键主题,为读者提供一个清晰、实用的指南,以便在复杂多变的业务环境中构建和维护健壮的微服务体系结构。 【2月更文挑战第16天】 在移动开发领域,性能优化和流畅的用户体验是至关重要的。随着技术的不断进步,Kotlin作为一种现代编程语言,在Android开发中被广泛采用,尤其是其协程特性为异步编程带来了革命性的改进。本文旨在深入
241 5
|
2月前
|
监控 安全 Android开发
【新手必读】Airtest测试Android手机常见的设置问题
【新手必读】Airtest测试Android手机常见的设置问题
|
4月前
|
Android开发
【Android App】蓝牙的设备配对、音频传输、点对点通信的讲解及实战(附源码和演示 超详细)
【Android App】蓝牙的设备配对、音频传输、点对点通信的讲解及实战(附源码和演示 超详细)
92 0
|
1天前
|
存储 Java Android开发
Android系统 设置第三方应用为默认Launcher实现和原理分析
Android系统 设置第三方应用为默认Launcher实现和原理分析
4 0
|
4月前
|
XML 编解码 算法
Android开发音效中录制WAV音频和录制MP3音频的讲解及实战(超详细 附源码)
Android开发音效中录制WAV音频和录制MP3音频的讲解及实战(超详细 附源码)
65 0
|
3月前
|
网络安全 Android开发
2023安卓逆向 -- 抓包环境设置(Charles+Postern)
2023安卓逆向 -- 抓包环境设置(Charles+Postern)
33 0
|
4月前
|
XML Java Android开发
Android 开发中原始音频的录播和和自定义音频控制条的讲解及实战(超详细 附源码)
Android 开发中原始音频的录播和和自定义音频控制条的讲解及实战(超详细 附源码)
27 0
|
4月前
|
XML 存储 Java
Android 开发音频录播中媒体录制器MediaRecorder和媒体播放器MediaPlayer的讲解及实战(超详细 附源码)
Android 开发音频录播中媒体录制器MediaRecorder和媒体播放器MediaPlayer的讲解及实战(超详细 附源码)
42 0
|
Android开发
Android MediaPlayer播放音频与视频
播放音频 首先创建出一个MediaPlayer对象 MediaPlayer mMediaPlayer = new MediaPlayer(); 设置声音源 public static final String FILENAME = "deserve.
1218 0
|
XML Android开发 数据格式