Android OpenSL ES 音频播放器

目录

OpenSL ES 介绍
OpenSL 编程说明
Android 平台下 OpenSL ES 开发准备
OpenSL 播放流程概览
代码实战

OpenSL ES 介绍

OpenSL ES (Open Sound Library for Embedded Systems) 是一个跨平台、无授权费用的音频处理库,它为移动多媒体设备的应用开发者提供了标准化、高性能、低响应的音频功能实现方法,统一的 API 使得通过 OpenSL ES 开发的音频处理程序能够很好的在多个平台上运行。

OpenSL 编程说明

OpenSL ES 对象类似于 Java 编程语言中的对象概念,OpenSL ES 中的对象类型为 SLObjectItf,如果需要使用对象中的具体方法,则需要通过 GetInterfaces 的方式得到具体的接口对象,从而使用具体的个性功能,Interface 对象类型需要在创建时指定为显示接口,否则会默认隐藏;
另外 OpenSL ES 中的对象在创建完成后,并不会立即初始化,创建仅仅是构建对象分配基础的内存空间,需要通过 Realize 来对此对象进行初始化。

Android 平台下 OpenSL ES 开发准备

CMakeList 引入基础库

target_link_libraries(
${PROJECT_NAME}

OpenSLES
)

基础库头文件

#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>

OpenSL 播放流程概览

opensl audio player.png

OpenSL 中的 Engine 是一个非常关键的对象:
1、通过 Engine EngineItf 创建出音频播放器、音频采集器等各种关键对象
2、通过 Engine SLEngineCapabilitiesItf 查询各项能力在相关平台上的兼容性

DataSource 与 DataSink:
DataSource 音频播放器中的数据输入源,DataSink 音频播放器中的数据输出对象(一般为系统中的音频设备)

代码实战

1、创建Engine并获取Engine接口对象

// 创建并初始化Engine对象
SLObjectItf engineObj;
SLresult result = slCreateEngine(&engineObj, 0, NULL, 0, NULL, NULL);
if (result != SL_RESULT_SUCCESS) {
  // 创建Engine失败
  return;
}
result = (*engineObj)->Realize(engineObj, SL_BOOLEAN_FALSE); // TRU表示异步初始化,这里同步初始化即可
if (result != SL_RESULT_SUCCESS) {
  // Engine初始化失败
  return;
}

// 获取Engine接口对象
SLEngineItf engineItf;
result = (*engineObj)->GetInterfaces(engine, SL_IID_ENGINE, &engine);
if (result != SL_RESULT_TRUE) {
  // Engine接口对象获取失败
  return;
}

2、通过SLEngineItf创建音频输出对象SLDataSink(即默认设备)

// 创建混音器(它默认与系统音频设备绑定)
SLObjectItf outputMix;
SLInterfaceID outputMixItfIds[1] = {SL_IID_ENVIRONMENTALREVERB}; // 导出混音效果设置接口
SLboolean outputMixItfReq[1] = {SL_BOOLEAN_FALSE}; // FALSE:该接口不支持,也不影响对象的初始化流程;TRUE:接口不支持,会导致初始化失败
result = (*engineItf)->CreateOutputMix(engineItf, &outputMix, 1, outputMixItfIds, outputMixItfReq);
if (result != SL_RESULT_SUCCESS) {
  // 混音器对象创建失败
  return;
}

result = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE); // 同步初始化
if (result != SL_RESULT_SUCCESS) {
  // 混音器对象初始化失败
  return;
}

// 混音效果设置接口对象
SLEnvironmentalReverbItf envReverbItf;
result = (*outputMix)->GetInterface(outputMix, SL_IID_ENVIRONMENTREVERB, &envRevertbItf);
if (result == SL_RESULT_SUCCESS) {
  // 接口对象获取成功,设置混音效果
  SLEnvironmentalReverbSettings stonecorridor = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR; // 走廊效果
  (*envReverbItf)->SetEnvironmentReverbProperties(envReverbItf, &stonecorridor);
  return;
}

// 音频数据输出对象
SLDataLocator_OutputMix locaterOutputMix;
locaterOutputMix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
locaterOutputMix.outputMix = output_mix_itf;

SLDataSink dataSink;
dataSink.pLocater = &locaterOutputMix;
dataSink.pFormat = NULL; // 不需要限制格式,音频输入源会指定好格式

3、创建音频数据源SLDataSource

// 指定数据送入形式,AndroidSimpleBufferQueue
SLDataLocater_AndroidSimpleBufferQueue locaterAndroidBufferQueue;
locaterAndroidBufferQueue.locaterType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
locaterAndroidBufferQueue.numBuffers = 2; // 越多播放越流畅、同时内存占用也越多

// 指定PCM数据格式限制
SLDataFormat_PCM formatPcm;
formatPcm.formatType = SL_DATAFORMAT_PCM;
formatPcm.numChannels = 2;                                    // 声道数 2
formatPcm.samplesPerSec = SL_SAMPLINGRATE_44_1;               // 采样率 44100HZ
formatPcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;        // 采样位深 16(2字节)
formatPcm.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;        // 与位深一样即可
formatPcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; // 立体声: 左前 | 右前
formatPcm.endianness = SL_BYTEORDER_LITTLEENDIAN;  // 小端

// 音频数据输入对象
SLDataSource dataSource;
dataSource.pLocater = &locaterAndroidBufferQueue;
dataSource.pFormat = &formatPcm;

4、通过SLEngineItf创建音频播放器

// 创建播放器对象
SLObjectItf playerObj;
SLInterfaceID playerItfIds[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};// 导出AndroidSimpleBufferQueue接口,需要此接口送入PCM原始数据进行播放
SLboolean playerItfReq[] = {SL_BOOLEAN_TRUE}; // 强依赖此接口,因此接口检查为TRUE,创建时如果发现不支持此接口,创建流程会返回失败
result = (*engineItf)->CreateAudioPlayer(engineItf, &playerObj, &dataSource, &dataSink, 1, playerItfIds, playerItfReq);
if (result != SL_RESULT_SUCCESS) {
  // 创建Player对象失败
  return;
}

result = (*playerObj)->Realize(playerObj, SL_BOOLEAN_FALSE); // 同步初始化
if (result != SL_RESULT_SUCCESS) {
  // Player初始化失败
  return;
}

// 导出播放控制接口对象
SLPlayerItf playerItf;
result = (*playerObj)->GetInterface(playerObj, SL_IID_PLAYER, &playerItf);
if (result != SL_RESULT_SUCCESS) {
  // 导出播放控制接口对象失败
  return;
}

// 导出BufferQueue接口对象
SLAndroidSimpleBufferQueueItf androidBufferQueueItf;
result = (*playerObj)->GetInterface(playerObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &androidBufferQueueItf);
if (result != SL_RESULT_SUCCESS) {
  // 导出BufferQueue对象接口失败
  return;
}

// BufferQueue 注册回调,OpenSL播放时通过回调主动要数据的形式进行播放的,开发者无法直接塞入数据
void AndroidSimpleBufferQueueCallback(const SLAndroidSimpleBufferQueueItf queue, void *data) {
  // 输入pcm原始数据,此原始数据需要与前面规范的格式一一对应上,否则播放异常
  (*queue)->Enqueue(queue, uint8_t* data, int dataSize);
}

result = (*androidBufferQueueItf)->RegisterCallback(androidBufferQueueItf, AndroidSimpleBufferQueueCallback, this);
if (result != SL_RESULT_SUCCESS) {
  // BufferQueue回调注册失败
  return;
}

5、播放控制

// 播放
(*playerItf)->SetPlayState(playerItf, SL_PLAYSTATE_PLAYING); 
// 激活回调,此后会循环回调获取PCM数据进行播放
(*androidBufferQueueItf)->Enqueue(androidBufferQueueItf, "", 1);

// 暂停
(*playerItf)->SetPlayState(playerItf, SL_PLAYSTATE_PAUSED);

6、资源释放

// 释放播放器
if (playerObj) {
  (*playerObj)->Destroy(playerObj);
  playerObj = NULL;
}

// 释放混音器 
if (outputMix) {
  (*outputMix)->Destroy(outputMix);
  outputMix = NULL;
}

// 释放Engine
if (engineObj) {
  (*engineObj)->Destroy(engineObj);
  engineObj = NULL;
}

通过以上方式就能在Android平台上完成OpenSL ES音频播放器的创建,下一节将会结合FFmpeg完成音频文件的播放能力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Table of Contents PART 1: USER MANUAL ......................................................................................... 1 1 OVERVIEW ..................................................................................................... 2 2 FEATURES AND PROFILES .............................................................................. 9 3 DESIGN OVERVIEW ...................................................................................... 14 FUNCTIONAL OVERVIEW .............................................................................. 30 PART 2: API REFERENCE ..................................................................................... 60 5 BASE TYPES AND UNITS ............................................................................... 61 6 FUNCTIONS .................................................................................................. 64 7 OBJECT DEFINITIONS .................................................................................. 67 8 INTERFACE DEFINITIONS ............................................................................ 93 9 MACROS AND TYPEDEFS............................................................................. 439 PART 3: APPENDICES ........................................................................................ 501 APPENDIX A: REFERENCES ............................................................................... 502 APPENDIX B: SAMPLE CODE.............................................................................. 504 APPENDIX C: USE CASE SAMPLE CODE .............................................................. 555 APPENDIX D: OBJECT-INTERFACE MAPPING..................................................... 585

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值