文章目录

  • I . AAudio 音频流 采样 缓冲 播放 的连续机制
  • II . AAudio 音频流 数据回调函数 函数指针类型定义
  • III . AAudio 音频流 数据回调函数 实现
  • IV . AAudio 音频流 数据回调函数 设置

I . AAudio 音频流 采样 缓冲 播放 的连续机制


1 . AAudio 音频流的 采样 缓冲 播放 流程 : 样本采样完成后 , 存入缓冲区 , 然后将其通过 AAudio 播放出来 , 采样阶段采集 nnn 个样本 , 然后将其放入缓冲区 , 将缓冲区的数据 写出到 AAudio 音频流中播放出来 ;

2 . 采样速度高于播放速度 : 如果采样采集多了 , 不能立刻播放 , 此时就会产生延迟 , 并且如果超出缓冲区大小 , 超出部分采样就会溢出 , 造成数据损失 , 样本不连续 , 就会产生电流 ;

3 . 采样速度低于播放速度 : 如果采样少了 , 不能向 AAudio 音频流中写入足够的数据 , 就会造成电流杂音等情况 ;

4 . 数据回调函数 引入 : 数据回调函数就是为了解决上述问题 , 引入的机制 ;

5 . 数据回调函数 简介 :

  • ① 采样缓冲 : 采样后 , 将采集的样本存入缓冲区 ;
  • ② 播放采样 : 将缓冲区中的样本写入 AAudio 音频流 ;
  • ③ 调用回调函数 : AAudio 音频流如果播放完当前数据 , AAudio 就会自动调用 开发者按照 规范开发的 回调函数 申请后续采样数据 ;
  • ④ 回调函数内容 : 开发者自己实现该回调函数 , 在这个函数中实现采样 并将采样设置给 AAudio 音频流 , 之后继续播放音频采样 ;

之后如果采样播放完毕 , 继续调用回调函数 ;

下面会着重讲解该数据回调函数的细节

II . AAudio 音频流 数据回调函数 函数指针类型定义


数据回调函数原型 : AAudio 只定义了一个函数类型 , 该函数的实际内容需要开发者自己开发 , 一般是 采样 , 然后 设置数据给 AAudio 音频流 的操作 ;

typedef aaudio_data_callback_result_t (*AAudioStream_dataCallback)(AAudioStream *stream,void *userData,void *audioData,int32_t numFrames);
  • ① 函数类型 : 该数据回调函数类型如下 , 其返回值是 aaudio_data_callback_result_t 类型 , 四个参数分别如下 ;
aaudio_data_callback_result_t (*)(AAudioStream *stream,void *userData,void *audioData,int32_t numFrames)
  • ② 函数别名 : 使用 typedef 关键字为 上述函数指针类型 赋予一个类型别名 AAudioStream_dataCallback ;
  • ③ 参数一 AAudioStream *stream : AAudio 音频流指针 ;
  • ④ 参数二 void *userData : 该参数用于传递一些额外数据 , 与 AAudioStreamBuilder_setCallback() 中的 第三参数 void *userData 参数指向的地址一致 ;
  • ⑤ 参数三 void *audioData : 指向音频采样数据的指针 , AAudio 会自动将该数据输出或输入到音频流中 ;
  • ⑥ 参数四 int32_t numFrames : 要处理的帧数 , 需要将多少帧的 audioData 指针指向的音频采样数据 , 输入 或 输出到 AAudio 音频流中 ;

III . AAudio 音频流 数据回调函数 实现


aaudio_data_callback_result_t (*)(AAudioStream *stream,void *userData,void *audioData,int32_t numFrames)

1 . 数据回调函数设置给 AAudio 音频流 : AAudio 中通过 AAudioStreamBuilder_setDataCallback() 函数 , 将用户自己实现的 AAudioStream_dataCallback 回调函数的函数指针设置给 AAudio 音频流 , 当 AAudio 音频流需要数据时会自动回调该函数 ;

2 . 输出流回调函数实现内容 : 在该函数中需要 按照 AAudio 音频流的当前数据格式 ( 通道数/每帧样本数 , 采样率 ) , 采集 numFrames 帧的 PCM 音频样本数据 ( 每帧的采样数与通道数一致 ) , 将这些样本数据写出到 void *audioData 指针指向的内存中 , 之后这些数据会被自动输出到 AAudio 音频流中 ;

3 . 输入流回调函数实现内容 : 在函数中需要从 void *audioData 指针指向的内存中 , 读取 numFrames 帧 ( 每帧的采样数与通道数一致 ) 的采样数据 , 注意需要按照当前的 采样格式 ( 通道数/每帧样本数 , 采样率 ) 计算读取的字节大小 ;

4 . 采样数据自动传输 ( 不需要手动干预 ) : 在回调函数中 , 将 numFrames 帧的数据传递给 void *audioData , AAudio 在该回调函数执行完毕后 , 会自动将这些数据 读/写 到 AAudio 音频流中 , 不需要 开发者 手动调用 AAudioStream_read() 或 AAudioStream_write() 方法 , 一调用必出错 ;

5 . 每次读写的帧数 int32_t numFrames :

  • ① 固定帧数 : 通过调用 AAudioStreamBuilder_setFramesPerDataCallback() 方法可以设置每次回调都读写固定帧数的音频采样 ;
  • ② 自由帧数 : 如果用户没有指定帧数 , 那么在每次回调函数中的 numFrames 帧数可以由用户自己设置 ;

6 . 不能执行耗时操作 : 在该回调函数中 , 不能执行太耗时的操作 或 阻塞操作 , 如果阻塞时间超过了采样播放的时间 , 就会造成后续采样无法及时 读取 或 写入 到 AAudio 音频流中 , 出现音频故障 ;

7 . 回调函数中不能执行的操作 : 该回调函数的回调频率很高 , 可能达到每秒几百到几千次 , 因此有很多 耗时操作 或 访问本地资源 的逻辑不能再该函数中运行 , 尽可能只对内存数据进行操作 ;

  • ① 内存操作 : 使用 malloc() 或 new 分配堆内存 , 极大可能造成内存泄漏或内存溢出 ;
  • ② 文件操作 : 打开 open , 关闭 close , 读取 read , 写出 write 等针对文件的操作 ;
  • ③ 网络操作 : 访问网络操作 , 从网络中读取数据 , 或向远程端口发送数据 ;
  • ④ 同步线程 : 线程间的同步操作会造成阻塞 ;
  • ⑤ 休眠阻塞 : sleep 方法不能执行 , 会造成阻塞 ;
  • ⑥ 关音频流 : 停止 或 关闭 流操作 会造成不可预知故障 ;
  • ⑦ 读写操作 : 该函数中不用刻意调用 AAudioStream_read() 和 AAudioStream_write() 方法进行读写操作 ;

8 . 回调函数中可以进行的操作 :

  • ① 调用 AAudioStream_getXXX() 类方法 : 如下图中列举的方法可以直接调用 , 获取 AAudio 音频流的各种属性 ;
  • ② 调用 AAudio_convertResultToText() 方法 : 将返回值转为对应的 ASCII 字符 ;

9 . 非阻塞技术 : 如果需要在回调函数中 读取 或 输出 数据 , 建议使用非阻塞技术 , 如 FIFO 技术 ;

IV . AAudio 音频流 数据回调函数 设置


1 . 数据回调函数设置方法 :

  • ① 函数原型 : 该方法用于设置 AAudio 音频流回调函数 , 当 AAudio 需要 读取 / 写出数据时 , 会自动回调该 AAudioStream_dataCallback 类型 函数 ;
AAUDIO_API void AAudioStreamBuilder_setDataCallback(AAudioStreamBuilder *builder,AAudioStream_dataCallback callback,void *userData
)
  • ② 参数 一 AAudioStreamBuilder *builder : AAudio 音频流指针 ;
  • ③ 参数 二 AAudioStream_dataCallback callback : AAudioStream_dataCallback 是函数指针类型 , 开发者自己实现该函数 , 然后将函数的地址当做参数设置到此处 ;
typedef aaudio_data_callback_result_t (*AAudioStream_dataCallback)(AAudioStream *stream,void *userData,void *audioData,int32_t numFrames);
  • ④ 参数 三 void *userData : 该指针 与 AAudioStream_dataCallback 函数指针类型的第二个参数指向的地址是相同的 , 相当于传入一个用户自定义的指针 , 可以是任意类型任意数据任意变量 ;

2 . 音频数据传递方式 : 在 AAudioStream_dataCallback 函数指针类型的回调函数中 , 音频流的数据不是通过 AAudioStream_read 或 AAudioStream_write 方法进行读写的 , 只要将音频采样数据设置给函数的第三个参数 audioData 指针即可 , 第四个参数 numFrames 用于说明读写数据的帧数 , 每帧的采样数 就是 采样的通道数 ;

3 . 数据回调函数工作机制 :

  • ① 第一次回调 : 在 AAudio 音频流调用 AAudioStream_requestStart() 方法后 , 会立刻回调该数据回调函数 , 然后第一次 读写采样数据到 AAudio 音频流中 ;
  • ② 循环回调 : 当 AAudio 音频流 读取或写出数据完毕后 , 会自动回调该数据回调函数 , 在回调函数中准备下一次的采样 , 读写到 AAudio 音频流中 , 之后继续循环 , 直到 AAudio 音频流关闭销毁 ;
  • ③ 实时线程 : AAudio 拥有一个实时线程 , 该数据回调函数就是运行在这个线程上的 ;

【Android 高性能音频】AAudio 音频流 PCM 采样 的 采样 缓冲 播放 的 连续机制 ( 数据回调机制 | 数据回调函数指针 | 实现数据回调函数 | 设置数据回调函数 )相关推荐

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

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

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

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

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

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

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

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

  5. 【Android 高性能音频】OboeTester 音频性能测试应用 ( Oboe 输出测试参数 | API 选择 | 音频输出设备选择 | 采样率 | 通道 | 采样格式 | 播放偏好 )

    文章目录 一.Oboe 输出测试参数面板 二.Oboe 输出测试参数 API 及 设备选择 三.Oboe 输出测试参数 音频参数 四.Oboe 输出测试参数 播放偏好 五.Oboe 输出测试参数 ( ...

  6. 【Android 高性能音频】Oboe 音频流打开后 耳机 / 音箱 插拔事件处理 ( 动态注册广播接收者监听耳机插拔事件 | 重新打开 Oboe 音频流 )

    文章目录 一.动态注册广播接收者监听耳机插拔事件 二.jni 层的 Oboe 播放器代码 ( 重新打开 Oboe 音频流 ) 三.相关资料 基于 [Android 高性能音频]Oboe 开发流程 ( ...

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

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

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

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

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

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

最新文章

  1. 马尔可夫模型与条件随机场模型
  2. golang中的strings.ToTitle
  3. Educational Codeforces Round 8 D. Magic Numbers 数位DP
  4. Weka学习四(属性选择)
  5. 数据结构——Java Stack 类
  6. DCMTK:dcmseg模块的辅助功能
  7. C#中Monitor和Lock的用法区别
  8. 【NOI2016】网格,离散化+求割点
  9. 曾火爆一时的五笔输入法,为什么彻底衰落了?
  10. 乐橙tp6接入硬盘_乐橙“智能养殖”新概念,全套监管最佳组合方案曝光!
  11. Go语言:运行代码报错main redeclared in this block previous declaration at .\test.go:5:6
  12. 发现一个特给力的编写HTML/CSS的插件——Zen Coding
  13. juniper:opencontrail/contrail 作为SDN解决方案
  14. c语言答案-贾宗璞 许合利,C语言习题答案贾宗璞许合利较全-.doc-资源下载在线文库www.lddoc.cn...
  15. Mac如何给压缩文件加密
  16. color key在倒车显示功能上的至关重要性
  17. 视频编辑,如何截取视频片段
  18. 20145204张亚军第14周博客总结
  19. 【环境配置】MySQL timestamp的默认值设置问题
  20. SQLMap超详细的用户手册【收藏】

热门文章

  1. Programming Pearls: Chatper3 Problem6 [Form letter generator]
  2. 菜鸟requireJS教程---2、基本知识
  3. 项目范围和项目范围管理
  4. Ubuntu里解压tar.xz格式
  5. 【JSOI2008】最大数 线段树
  6. [转]批处理for命令使用指南
  7. 我的第一个Android程序
  8. Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(二)之Introduction to Objects...
  9. 《京东技术解密》读后感
  10. 一个编译不能通过的问题的解决