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

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

文章目录

一、音频帧概念

二、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 44 字节 ;


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


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


上述 1 11 个音频帧的字节大小是 2 × 4 = 8 2\times 4 = 82×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 1616 位整型 , 2 22 字节 , 相当于 short 类型 ;


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


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


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






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


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


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


注意单位是音频帧 ,


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


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


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


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


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



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


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



在 onAudioReady 方法中 , 需要 采集 8 × 8 \times8× 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;
    }
};



目录
相关文章
|
1月前
|
数据库 Android开发 开发者
构建高性能微服务架构:从理论到实践构建高效Android应用:探究Kotlin协程的优势
【2月更文挑战第16天】 在当今快速迭代和竞争激烈的软件市场中,微服务架构以其灵活性、可扩展性和独立部署能力而受到企业的青睐。本文将深入探讨如何构建一个高性能的微服务系统,涵盖从理论基础到具体实现的各个方面。我们将重点讨论服务拆分策略、通信机制、数据一致性以及性能优化等关键主题,为读者提供一个清晰、实用的指南,以便在复杂多变的业务环境中构建和维护健壮的微服务体系结构。 【2月更文挑战第16天】 在移动开发领域,性能优化和流畅的用户体验是至关重要的。随着技术的不断进步,Kotlin作为一种现代编程语言,在Android开发中被广泛采用,尤其是其协程特性为异步编程带来了革命性的改进。本文旨在深入
241 5
|
4月前
|
Android开发
【Android App】蓝牙的设备配对、音频传输、点对点通信的讲解及实战(附源码和演示 超详细)
【Android App】蓝牙的设备配对、音频传输、点对点通信的讲解及实战(附源码和演示 超详细)
96 0
|
2天前
|
Android开发 内存技术
Android 通过tinyalsa调试解决录制和播放音频问题
Android 通过tinyalsa调试解决录制和播放音频问题
20 1
|
4月前
|
缓存 算法 Java
Linux内核新特性年终大盘点-安卓杀后台现象减少的背后功臣MGLRU算法简介
MGLRU是一种新型内存管理算法,它的出现是为了弥补传统LRU(Least Recently Used)和LFU(Least Frequently Used)算法在缓存替换选择上的不足,LRU和LFU的共同缺点就是在做内存页面替换时,只考虑内存页面在最近一段时间内被访问的次数和最后一次的访问时间,但是一个页面的最近访问次数少或者最近一次的访问时间较早,可能仅仅是因为这个内存页面新近才被创建,属于刚刚完成初始化的年代代页面,它的频繁访问往往会出现在初始化之后的一段时间里,那么这时候就把这种年轻代的页面迁移出去
|
4月前
|
XML 编解码 算法
Android开发音效中录制WAV音频和录制MP3音频的讲解及实战(超详细 附源码)
Android开发音效中录制WAV音频和录制MP3音频的讲解及实战(超详细 附源码)
68 0
|
4月前
|
XML Java Android开发
Android 开发中原始音频的录播和和自定义音频控制条的讲解及实战(超详细 附源码)
Android 开发中原始音频的录播和和自定义音频控制条的讲解及实战(超详细 附源码)
27 0
|
4月前
|
XML 存储 Java
Android 开发音频录播中媒体录制器MediaRecorder和媒体播放器MediaPlayer的讲解及实战(超详细 附源码)
Android 开发音频录播中媒体录制器MediaRecorder和媒体播放器MediaPlayer的讲解及实战(超详细 附源码)
42 0
|
4月前
|
XML Java Android开发
Android App开发音量调节中实现拖动条和滑动条和音频管理器AudioManager讲解及实战(超详细 附源码和演示视频)
Android App开发音量调节中实现拖动条和滑动条和音频管理器AudioManager讲解及实战(超详细 附源码和演示视频)
75 0
|
Android开发 C++
【Android 高性能音频】Oboe 开发流程 ( Oboe 完整代码示例 )(一)
【Android 高性能音频】Oboe 开发流程 ( Oboe 完整代码示例 )(一)
269 0
|
API Android开发
【Android 高性能音频】Oboe 开发流程 ( 检查 Oboe 音频流属性 | 开始播放 | 停止播放 | 关闭 Oboe 音频流 | 重新配置 Oboe 音频流属性 )
【Android 高性能音频】Oboe 开发流程 ( 检查 Oboe 音频流属性 | 开始播放 | 停止播放 | 关闭 Oboe 音频流 | 重新配置 Oboe 音频流属性 )
196 0