文章目录
- 一、包含头 Oboe 头文件
- 二、音频流构建器 AudioStreamBuilder
- 三、音频流回调 AudioStreamCallback
Oboe GitHub 主页 : GitHub/Oboe
- ① 简单使用 : Getting Started
- ② Oboe 全指南 : Full Guide To Oboe
- ③ Oboe API 参考 : API reference
- ④ Android 音频框架发展 : Android audio history
在 【Android 高性能音频】Oboe 开发流程 ( 导入 Oboe 库 | 使用预构建的二进制库和头文件 | 编译 Oboe 源码 ) 博客中介绍了 如何导入 Oboe 函数库到项目中 , 本博客中在导入 Oboe 函数库的基础上 , 进行 Oboe 播放器功能开发 ;
一、包含头 Oboe 头文件
代码语言:javascript复制#include <oboe/Oboe.h>
二、音频流构建器 AudioStreamBuilder
创建 AudioStreamBuilder 对象 :
代码语言:javascript复制// 音频流构建器
oboe::AudioStreamBuilder builder = oboe::AudioStreamBuilder();
通过 AudioStreamBuilder 配置 Oboe 音频流 : 配置 音频流方向 , 性能优先级 , 共享模式 , 音频采样格式 , 声道数 ;
代码语言:javascript复制// 设置音频流方向
builder.setDirection(oboe::Direction::Output);
// 设置性能优先级
builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);
// 设置共享模式 , 独占
builder.setSharingMode(oboe::SharingMode::Exclusive);
// 设置音频采样格式
builder.setFormat(oboe::AudioFormat::Float);
// 设置声道数 , 单声道/立体声
builder.setChannelCount(oboe::ChannelCount::Mono);
三、音频流回调 AudioStreamCallback
定义 音频流回调类 AudioStreamCallback , 当 音频流需要新的 PCM 音频数据时 , 会自动回调 AudioStreamCallback 类 中的 onAudioReady 方法 ;
下面是文档中给出的代码示例 : 这是 Google 文档中给出的示例 , 仅做参考 ;
代码语言:javascript复制class MyCallback : public oboe::AudioStreamCallback {
public:
oboe::DataCallbackResult
onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames) {
// 请求音频格式 AudioFormat::Float , 假设已经得到了相应数据.
// 对于生产者 ( 生产音频 ) 代码 ,
// 检查音频流中的音频数据格式 , 与自己生产的音频数据格式是否一致
// 如果不一致需要转转数据类型
// 这里将数据类型转为生产的数据类型
auto *outputData = static_cast<float *>(audioData);
// 生成随机数 (白噪音) 以 0 为中心值 .
const float amplitude = 0.2f;
for (int i = 0; i < numFrames; i){
outputData[i] = ((float)drand48() - 0.5f) * 2 * amplitude;
}
return oboe::DataCallbackResult::Continue;
}
};
AudioStreamCallback 类简介 : 该类定义在 oboe 命名空间下 ,
① 数据格式 : 对于输出流 , 该方法应该渲染和写出指定帧数的数据到音频数据缓冲区中 , 这些数据的格式与当前流的格式相同 , 如果不一致需要转转数据类型 ;
② 输出流 : 对于输出流 , 该方法应该 渲染和写出指定帧数的数据到音频数据缓冲区中 , 这些数据的格式与当前流的格式相同 ;
③ 输入流 : 对于输入流 , 该方法应该 从音频数据缓冲区中读取和处理相应帧数的数据 ;
④ 数据传递 : 音频数据通过缓冲区传递 , 不需要额外在音频流中调用 read() 或 write() 方法 ;
⑤ 该方法中不能进行如下操作 :
- 分配内存操作 , 如 malloc() 或者 new 操作
- 文件操作 , 如打开 , 读取 , 写出 , 关闭 等文件操作
- 网络相关操作
- 使用互斥操作 或 同步操作 , 即不能在该方法中阻塞等待
- 休眠 sleep
- Oboe 音频流的 oboeStream->stop(), pause(), flush() or close() 操作
- Oboe 音频流的 oboeStream->read() 操作
- Oboe 音频流的 boeStream->write() 操作
总的来说 , 该方法可能要在 1 秒钟内调用几百上千次 , 不能做任何耗时操作 ;
⑥ 在该回调函数中可以进行的操作:
- oboeStream->get*()
- oboe::convertToText()
- oboeStream->setBufferSizeInFrames()
#ifndef OBOE_STREAM_CALLBACK_H
#define OBOE_STREAM_CALLBACK_H
#include "oboe/Definitions.h"
namespace oboe {
class AudioStream;
/**
* AudioStreamCallback 定义了如下回调接口:
*
* 1) 通过 'onAudioReady' 方法 , 将数据放入/取出音频流
* 2) 当音频流出现错误 , 回调 `onError*` 方法用于示警
*
*/
class AudioStreamCallback {
public:
virtual ~AudioStreamCallback() = default;
/**
* 缓冲区已经准备好进行相应处理.
*
* 对于输出流 , 该方法应该渲染和写出指定帧数的数据到音频数据缓冲区中 ,
* 这些数据的格式与当前流的格式相同
*
* 对于输入流 , 该方法应该从音频数据缓冲区中读取和处理相应帧数的数据 .
*
* 音频数据通过缓冲区传递 .
* 不需要额外在音频流中调用 read() 或 write() 方法 .
*
* 除非调用 AudioStreamBuilder::setFramesPerCallback() 方法 ,
* 读写的帧数可以改变 .
*
* 该回调函数应该被看做实时的 .
* 在该函数中不应该执行任何耗时操作 , 否则会导致音频电流等故障 ;
*
* 该方法中不能进行如下操作 :
* 1. 分配内存操作 , 如 malloc() 或者 new 操作
* 2. 文件操作 , 如打开 , 读取 , 写出 , 关闭 等文件操作
* 3. 网络相关操作
* 4. 使用互斥操作 或 同步操作 , 即不能在该方法中阻塞等待
* 5. 休眠 sleep
* 6. Oboe 音频流的 oboeStream->stop(), pause(), flush() or close() 操作
* 7. Oboe 音频流的 oboeStream->read() 操作
* 8. Oboe 音频流的 boeStream->write() 操作
* 总的来说 , 该方法可能要在 1 秒钟内调用几百上千次 , 不能做任何耗时操作 ;
*
* 在该回调函数中可以进行的操作:
* 1. oboeStream->get*()
* 2. oboe::convertToText()
* 3. oboeStream->setBufferSizeInFrames()
*
* 如果你需要移动数据 , 如 MIDI 指令 , 传入/传输到该回调类方法中 , 推荐使用非阻塞技术 , 如 atomic FIFO .
*
* @param oboeStream Oboe 音频流指针
* @param audioData 输入/输出 音频数据缓冲区
* @param numFrames 要处理的帧数
* @return DataCallbackResult::Continue or DataCallbackResult::Stop
*/
virtual DataCallbackResult onAudioReady(
AudioStream *oboeStream,
void *audioData,
int32_t numFrames) = 0;
};
} // namespace oboe
#endif //OBOE_STREAM_CALLBACK_H