【Android 高性能音频】AAudio 状态机 ( 创建 | 打开 Open | 开始 Started | 暂停 Paused | 刷写 Flushed | 停止 Stopped | 关闭 )



I . AAudio 音频流 创建 配置 使用 销毁 流程



红色标题是本博客讲解的内容 , 黑色是前几篇讲过的内容 ;

使用 AAudio 音频库 , 首先需要导入 AAudio.h 头文件 ;

#include <AAudio.h>

创建 AAudio 音频流 , 需要先创建 AAudio 音频流构建器 , 然后在通过该构建器创建音频流 ;

    //创建构建器 , AAudio 音频流通过该构建器创建
    //声明 AAudio 音频流构建器 指针
    AAudioStreamBuilder *builder = nullptr;
    //创建 AAudio 音频流构建器 , 注意传入二维指针
    aaudio_result_t result = AAudio_createStreamBuilder(&builder);

设置音频设备 ID ;

    // 设置音频流设备 ID
    AAudioStreamBuilder_setDeviceId(builder, playbackDeviceId_);

设置音频流方向 ;

    // 设置音频流方向
    AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT);

设置音频设备共享模式 ;

    // 设置共享模式 , 独占模式性能更高 , 延迟更低 ; 如果 该音频设备正在被使用 , 设置失败会自动设置成 共享模式
    AAudioStreamBuilder_setSharingMode(builder, AAUDIO_SHARING_MODE_EXCLUSIVE);

设置性能模式 ;

    // 设置性能模式
    AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);

设置 AAudio 音频流通道数 :

    // 设置通道个数
    AAudioStreamBuilder_setChannelCount(builder, sampleChannels_);

设置 AAudio 音频流样本格式 :

    // 设置音频格式
    AAudioStreamBuilder_setFormat(builder, sampleFormat_);

设置 AAudio 音频流缓冲区大小 : 这里的缓冲区是播放器的缓冲区 , 单位是帧 , 每帧的采样数就是通道数 , 单声道 每帧 1 个采样, 双声道立体声每帧 2 个采样 , 分别对应左右声道的采样 ;

    // 设置每帧的缓冲区大小 , 可以通过该设置达到尽可能低的延迟
    AAudioStream_setBufferSizeInFrames(playStream_, framesPerBurst_);

创建 AAudio 音频流 : 创建 AAudio 音频流 , 就是打开音频流 , 注意要在音频流参数设置完毕后才能打开音频流 ;

    // 打开音频流 ( 该步骤就是创建音频流 )
    aaudio_result_t result = AAudioStreamBuilder_openStream(builder, &playStream_);

销毁 AAudio 音频流构建器 : 在音频流创建 ( 打开 ) 完毕后 , 应该马上销毁 AAudio 音频流构建器 ;

    //销毁音频流构建器
    AAudioStreamBuilder_delete(builder);

使用 AAudio 音频流 进行 录音 或 播放操作 , 使用完毕后需要 销毁 AAudio 音频流 ;

停止 AAudio 音频流 : 如果 AAudio 音频流不再使用 , 需要马上销毁 AAudio 音频流 , 销毁前需要先将音频流停止 , 然后才能销毁 ;

    //先停止音频流 , 然后才能关闭
    aaudio_result_t result = AAudioStream_requestStop(playStream_);

关闭 AAudio 音频流 : 如果 AAudio 音频流不再使用 , 需要马上销毁 AAudio 音频流 , 该流会占据音频设备资源 , 不用应马上销毁 ;

    //关闭音频流 , 关闭后 , 该音频流就彻底释放了 , 如果在使用 , 必须重新创建
    result = AAudioStream_close(playStream_);


II . AAudio 音频流 稳定状态 与 过渡状态



1 . AAudio 音频流有 6 种稳定状态 :

  • ① Open : 音频流打开后的状态 , 就是 Open 状态 , 该状态时间很短 , 马上回自动转到下一状态 ;
  • ② Started : 音频流打开后 , 会自动从 Open 状态转为 Started 状态 , 该状态下音频流的音频数据 , 处于流动状态 , 这个过程占生命周期的 99.999% 的时间 ;
  • ③ Paused : 暂停状态 , 在 Started 状态下 , 如果调用 AAudioStream_requestPause() 方法 , 就会进入该状态 ; 此时播放器是暂停的 , 可以随时恢复播放 , 调用 AAudioStream_requestStart() 方法 , 可以恢复播放 , 进入 Started 状态 ;
  • ④ Flushed : 刷写状态 , 在 Paused 状态下 , 调用 AAudioStream_requestFlush() 方法 , 就会进入该状态 , 这是将播放器缓冲区中的数据播放完毕 , 可以清空缓冲区 ; 调用 AAudioStream_requestStart() 方法 , 可以恢复播放 , 进入 Started 状态 ;
  • ⑤ Stopped : 停止状态 , 在 Started 状态下 , 如果调用 AAudioStream_requestStop() 方法 , 就会进入该状态 ; 此时如果要恢复成 Started 状态 , 需要调用 AAudioStream_requestStart() 方法 ;
  • ⑥ Closed : 关闭状态 , 在 Stopped 状态下 , 如果调用 AAudioStream_close() 方法 , 就会进入 Closed 状态 ; 该状态意味着 AAudio 音频流被销毁 , 无法再继续使用 ;

总结 :
处于 暂停 ( Paused ) , 停止 ( Stopped ) , 刷写 ( Flushed ) 状态下 , 可以调用 AAudioStream_requestStart() 方法 , 恢复成 Started 状态 ;
刷写 ( Flushed ) 状态 必须 有前置状态 暂停状态 ( Paused ) 才能进入该状态 , 其它状态下是无法进入 刷写状态的 ;


2 . AAudio 音频流有 5 种 过渡状态 : 过渡状态是两种稳定状态之间的状态 ;

  • ① Starting 状态 : Open 状态 与 Started 状态 之间的 过渡状态 ;
  • ② Pausing 状态 : Started 状态 与 Paused 状态之间的 过渡状态 ;
  • ③ Flushing 状态 : Paused 状态 与 Flushed 状态之间的 过渡状态 ;
  • ④ Stopping 状态 : Started 状态 与 Stopped 状态 之间的过渡状态 ;
  • ⑤ Closing 状态 : Stopped 状态 与 Closed 状态 之间的过渡状态 ;

3 . 11 个状态之间的状态机转化关系如下图 :
在这里插入图片描述



III . AAudio 音频流 状态改变 监听



1 . AAudio 音频流状态监听简介 :

  • ① 没有回调函数 : AAudio 没有提供 监听 音频流状态的 回调函数 ;
  • ② 等待变更方法 : 目前只能使用 AAudioStream_waitForStateChange() 方法 , 该方法调用后 , 开始阻塞 , 等待 AAudio 音频流变更成 不同于 开发者指定的状态 的 其它状态后 , 继续执行下面的代码 ;

2 . AAudioStream_waitForStateChange 方法简介 :

  • ① 函数原型 : 调用该函数时 , 当前状态应该是 inputState 状态 , 之后一直阻塞 , 该函数会等待 当前状态 , 不是 inputState 状态时 , 接触阻塞 , 继续执行下面的代码 ;
AAUDIO_API aaudio_result_t AAudioStream_waitForStateChange(
  AAudioStream *stream,
  aaudio_stream_state_t inputState,
  aaudio_stream_state_t *nextState,
  int64_t timeoutNanoseconds
)
  • ② 参数 1 AAudioStream *stream : 状态机所属的 AAudio 音频流 ;
  • ③ 参数 2 aaudio_stream_state_t inputState : 初始状态 , 调用该方法时的状态 ; 当 AAudio 音频流状态不是该状态时 , 方法阻塞解除 ;
  • ④ 参数 3 aaudio_stream_state_t *nextState : 下一个状态的指针 , 指向一个状态值 , 该值是 解除阻塞的时刻的 AAudio 音频流状态 ; 用于在后续执行时获取当前是什么状态 ;
  • ⑤ 参数 4 int64_t timeoutNanoseconds : 超时时间 , 该方法不可能一直阻塞代码执行 , 当超过一定时间后 , 继续执行后续的代码 ;
  • ⑥ 返回值 aaudio_result_t : 如果成功 , 返回 AAUDIO_OK , 如果失败会返回对应的错误码 ;


IV . AAudio 音频流 状态改变 监听 实例 ( 暂停操作 )



1 . 监听暂停操作 : 在 Started 状态下 , 调用 AAudioStream_requestPause() 方法 , 设置 AAudio 音频流暂停操作 ;

2 . 理论上的状态改变 : 方法调用后 , AAudio 音频流 会立刻进入 Pausing 过渡状态 , 然后处理过渡操作 , 处理完毕后 , 进入 Paused 状态 ;

3 . 代码实现 :

  • ① 申请暂停 : 调用 AAudioStream_requestPause() 方法之后 ;
  • ② 当前状态 : 申请暂停后 , 当前状态马上切换成了 Pausing 状态 ;
  • ③ 阻塞程序 : 此时 立刻调用 AAudioStream_waitForStateChange() 方法 , 其中的 第二个参数 inputState 设置成 Pausing 状态 , 该方法阻塞了程序运行 ;
  • ④ 解除阻塞 : 当状态由 Pausing 转为其它状态 ( 一般是 Paused 状态 ) , 或者超时 , 阻塞解除 , 继续执行下面的代码 ;
//设置当状态与该状态不一致时解除阻塞
aaudio_stream_state_t inputState = AAUDIO_STREAM_STATE_PAUSING;

//用于记录下一个状态 , 将其地址传入 AAudioStream_waitForStateChange 方法 第三个参数
aaudio_stream_state_t nextState = AAUDIO_STREAM_STATE_UNINITIALIZED;

//超时时间
int64_t timeoutNanos = 100 * AAUDIO_NANOS_PER_MILLISECOND;

//申请暂停 , 方法执行后 , 状态立刻变成 Pausing 状态
result = AAudioStream_requestPause(stream);

//阻塞程序 , 直到状态由 Pausing 转为 Paused 状态 , 或超时 , 才能解除阻塞 
result = AAudioStream_waitForStateChange(stream, inputState, &nextState, timeoutNanos);


V . AAudio 音频流 状态改变 监听 注意事项



1 . 申请关闭 操作 无法监听状态 : 当前如果是 Stopped 状态 , 调用 AAudioStream_close() 方法后 AAudio 音频流会直接被删除 , 无法调用 AAudioStream_waitForStateChange 方法监听 音频流 状态 ;

2 . 监听时不要关闭流 : 如果调用了 AAudioStream_waitForStateChange () 方法监听 AAudio 音频流 状态 , 当前线程虽然在阻塞状态 , 无法操作 , 但是不要在另外的线程中关闭该 AAudio 音频流 ;

发布了252 篇原创文章 · 获赞 1013 · 访问量 168万+

猜你喜欢

转载自blog.csdn.net/han1202012/article/details/103149009
今日推荐