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

2023-03-28 18:47:31 浏览数 (1)

文章目录

  • 一、音频帧概念
  • 二、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 播放器功能开发 ;

在 【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

字节 ;

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

则对应的

1

个音频帧 中包含

2

个采样 , 左声道

1

个采样 , 右声道

1

个采样 , 每个采样是

4

字节的单精度浮点类型 float 类型 ;

上述

1

个音频帧的字节大小是

2times 4 = 8

字节 ;

代码语言:javascript复制
    // 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

位整型 ,

2

字节 , 相当于 short 类型 ;

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

则对应的

1

个音频帧 中包含

2

个采样 , 左声道

1

个采样 , 右声道

1

个采样 , 每个采样是

2

字节的 short 类型 ;

上述

1

个音频帧的字节大小是

2times 2 = 4

字节 ;

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


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

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

注意单位是音频帧 ,

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

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

4

字节 ,

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

对应的

1

个音频帧 中包含

2

个采样 , 左声道

1

个采样 , 右声道

1

个采样 , 每个采样是

4

字节的单精度浮点类型 float 类型 ;

上述

1

个音频帧的字节大小是

2times 4 = 8

字节 ;

因此在该方法中的后续采样 , 每帧都要采集

2

个样本 , 每个样本

4

字节 , 每帧采集

8

字节的样本 ,

总共 numFrames 帧需要采集 numFrames 乘以

8

字节的音频采样 ;

在 onAudioReady 方法中 , 需要 采集

8 times

numFrames 字节 的音频数据样本 , 并将数据拷贝到 void *audioData 指针指向的内存中 ;

代码语言:javascript复制
// 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;
    }
};

0 人点赞