当前位置: 首页 > 工具软件 > oboe > 使用案例 >

【Android 高性能音频】Oboe 开发流程 ( Oboe 音频帧简介 | AudioStreamCallback 中的数据帧说明 )

刘修能
2023-12-01



Oboe GitHub 主页 : GitHub/Oboe


【Android 高性能音频】Oboe 开发流程 ( 导入 Oboe 库 | 使用预构建的二进制库和头文件 | 编译 Oboe 源码 ) 博客中介绍了 如何导入 Oboe 函数库到项目中 , 本博客中在导入 Oboe 函数库的基础上 , 进行 Oboe 播放器功能开发 ;

【Android 高性能音频】Oboe 开发流程 ( 包含头 Oboe 头文件 | 创建音频流 | 设置音频流 | 音频流回调类 AudioStreamCallback ) 介绍了如何创建 AudioStreamBuilder , 以及 创建 AudioStreamCallback 回调 ;

【Android 高性能音频】Oboe 开发流程 ( 创建并设置 AudioStreamCallback 对象 | 打开 Oboe 音频流 | 日志封装 logging_macros.h ) 博客中介绍了 设置 AudioStreamCallback 对象 , 打开 Oboe 音频流 操作 , 以及 Google 官方提供的日志封装有文件 ;

【Android 高性能音频】Oboe 开发流程 ( 检查 Oboe 音频流属性 | 开始播放 | 停止播放 | 关闭 Oboe 音频流 | 重新配置 Oboe 音频流属性 ) 博客中介绍了 如何开始 Oboe 音频流播放 , 以及 播放完毕后的收尾工作 ;

【Android 高性能音频】Oboe 开发流程 ( Oboe 完整代码示例 ) 中展示了一个 完整的 Oboe 播放器案例 ;







一、音频帧概念



代表一个 声音单元 , 该单元中的 采样个数 声道数 ;

该 声音单元 ( 帧 ) 中的 采样大小样本位数声道数 乘积 ;


下面的代码是 【Android 高性能音频】Oboe 开发流程 ( Oboe 完整代码示例 ) 博客中的 Oboe 音频流创建时 的代码 , 设置 Oboe 音频流 的参数如下 ;


设置的 采样格式 是 oboe::AudioFormat::Float , 每个采样都是一个 float 单精度浮点数 , 4 4 4 字节 ;

设置的 声道数 是 oboe::ChannelCount::Stereo , 立体声 , 左右双声道 ;

则对应的 1 1 1 个音频帧 中包含 2 2 2 个采样 , 左声道 1 1 1 个采样 , 右声道 1 1 1 个采样 , 每个采样是 4 4 4 字节的单精度浮点类型 float 类型 ;

上述 1 1 1 个音频帧的字节大小是 2 × 4 = 8 2\times 4 = 8 2×4=8 字节 ;

    // 1. 音频流构建器
    oboe::AudioStreamBuilder builder = oboe::AudioStreamBuilder();
    // 设置音频流方向
    builder.setDirection(oboe::Direction::Output);
    // 设置性能优先级
    builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);
    // 设置共享模式 , 独占
    builder.setSharingMode(oboe::SharingMode::Exclusive);
    // 设置音频采样格式
    builder.setFormat(oboe::AudioFormat::Float);
    // 设置声道数 , 单声道/立体声
    builder.setChannelCount(oboe::ChannelCount::Stereo);
    // 设置采样率
    builder.setSampleRate(48000);
    // 设置回调对象 , 注意要设置 AudioStreamCallback * 指针类型
    builder.setCallback(&myCallback);

如果设置的 采样格式 是 oboe::AudioFormat::I16 , 每个采样都是一个 16 16 16 位整型 , 2 2 2 字节 , 相当于 short 类型 ;

设置的 声道数 是 oboe::ChannelCount::Stereo , 立体声 , 左右双声道 ;

则对应的 1 1 1 个音频帧 中包含 2 2 2 个采样 , 左声道 1 1 1 个采样 , 右声道 1 1 1 个采样 , 每个采样是 2 2 2 字节的 short 类型 ;

上述 1 1 1 个音频帧的字节大小是 2 × 2 = 4 2\times 2 = 4 2×2=4 字节 ;





二、AudioStreamCallback 中的音频数据帧说明



在 Oboe 播放器回调类 oboe::AudioStreamCallback 中 , 实现的 onAudioReady 方法 ,

其中的 int32_t numFrames 就是本次需要采样的帧数 ,

注意单位是音频帧 ,

这里的音频帧就是上面所说的

采样格式 是 oboe::AudioFormat::Float , 每个采样都是一个 float 单精度浮点数 , 4 4 4 字节 ,

声道数 是 oboe::ChannelCount::Stereo , 立体声 , 左右双声道 ,

对应的 1 1 1 个音频帧 中包含 2 2 2 个采样 , 左声道 1 1 1 个采样 , 右声道 1 1 1 个采样 , 每个采样是 4 4 4 字节的单精度浮点类型 float 类型 ;

上述 1 1 1 个音频帧的字节大小是 2 × 4 = 8 2\times 4 = 8 2×4=8 字节 ;


因此在该方法中的后续采样 , 每帧都要采集 2 2 2 个样本 , 每个样本 4 4 4 字节 , 每帧采集 8 8 8 字节的样本 ,

总共 numFrames 帧需要采集 numFrames 乘以 8 8 8 字节的音频采样 ;


在 onAudioReady 方法中 , 需要 采集 8 × 8 \times 8× numFrames 字节 的音频数据样本 , 并将数据拷贝到 void *audioData 指针指向的内存中 ;

// Oboe 音频流回调类
class MyCallback : public oboe::AudioStreamCallback {
public:
    oboe::DataCallbackResult
    onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames) {

        // 需要生成 AudioFormat::Float 类型数据 , 该缓冲区类型也是该类型
        // 生产者需要检查该格式
        // oboe::AudioStream *audioStream 已经转换为适当的类型
        // 获取音频数据缓冲区
        auto *floatData = static_cast<float *>(audioData);

        // 生成正弦波数据
        for (int i = 0; i < numFrames; ++i) {
            float sampleValue = kAmplitude * sinf(mPhase);
            for (int j = 0; j < kChannelCount; j++) {
                floatData[i * kChannelCount + j] = sampleValue;
            }
            mPhase += mPhaseIncrement;
            if (mPhase >= kTwoPi) mPhase -= kTwoPi;
        }

        LOGI("回调 onAudioReady");

        return oboe::DataCallbackResult::Continue;
    }
};
 类似资料: