介绍
OpenSL ES (Open Sound Library for Embedded Systems)是针对嵌入式系统的一套无授权费,跨平台, 硬件加速的音频API。它提供了一套标准化,高性能,低延时的方法, 本地应用(C/C++)的开发者可以通过这套方对音频进行操作, 实现软/硬件音频性能的直接跨平台部署,降低执行难度,促进高级音频市场的发展
NDK 软件包中包括 Khronos Group 开发的 OpenSL ES™ 1.0.1 API 规范的 Android 专用实现。利用这个库,可以使用 C 或 C++ 实现高性能、低延迟的音频应用。
标准 OpenSL ES 头文件 <SLES/OpenSLES.h> 和 <SLES/OpenSLES_Platform.h> 允许音频输入和输出。<SLES/OpenSLES_Android.h> 和 <SLES/OpenSLES_AndroidConfiguration.h> 中提供了其他 Android 专用功能。
如何在Android中使用OpenSL ES
- 在CMakeList.txt中添加OpenSL ES的引用
target_link_libraries( # Specifies the target library.
OpenSLES
)
- 添加必要的头文件
添加核心 OpenSL ES 功能集OpenSLES.h
添加 OpenSL ES [Android 扩展]OpenSLES_Android.h
代码示例
GitHub 页面提供了以下示例应用:
- audio-echo 创建从输入到输出的往返循环。
- native-audio 是一个简单的音频录制器/播放器。
Note that OpenSL ES is deprecated from Android 11, developers are recommended to use Oboe library instead.
OpenSL ES简单使用
- 使用OpenSL相关API的通用步骤是:
1,创建对象(通过带有create的函数)
2,初始化(通过Realize函数)
3,获取接口来使用相关功能(通过GetInterface函数)
-
OpenSL使用回调机制来访问音频IO,回调方法仅仅是告诉我们:BufferQueue已经就绪,可以接受/获取数据了
-
OpenSL使用SLBufferQueueItf. Enqueue函数从(往)音频设备获取(放入)数据。
关于使用FFmpeg + opensl 实现Android播放器播放音频, 可以在回调函数里面获取解码后的音频数据,并调用Enqueue函数进行播放. 在开始播放的时候,需要手动启动回调机制,否则回调将不会被调用到。
- 一个简单的音频播放大概需要以下的object:
//引擎
SLObjectItf engineObject = 0;
//引擎接口
SLEngineItf engineInterface = 0;
//混音器
SLObjectItf outputMixObject = 0;
//播放器
SLObjectItf bqPlayerObject = 0;
//播放器接口
SLPlayItf bqPlayerPlay = 0;
//播放器队列接口
SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue = 0;
-
基本流程
opensles.png
代码还在整理,先简单贴一下
void AudioChannel::audio_play() {
/**
* 1、创建引擎并获取引擎接口
*/
SLresult result;
// 1.1 创建引擎对象:SLObjectItf engineObject
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
if (SL_RESULT_SUCCESS != result) {
return;
}
// 1.2 初始化引擎
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
if (SL_RESULT_SUCCESS != result) {
return;
}
// 1.3 获取引擎接口 SLEngineItf engineInterface
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineInterface);
if (SL_RESULT_SUCCESS != result) {
return;
}
/**
* 2、设置混音器
*/
// 2.1 创建混音器:SLObjectItf outputMixObject
result = (*engineInterface)->CreateOutputMix(engineInterface, &outputMixObject, 0,
0, 0);
if (SL_RESULT_SUCCESS != result) {
return;
}
// 2.2 初始化混音器
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
if (SL_RESULT_SUCCESS != result) {
return;
}
/**
* 3、创建播放器
*/
//3.1 配置输入声音信息
//创建buffer缓冲类型的队列 2个队列
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
2};
//pcm数据格式
//SL_DATAFORMAT_PCM:数据格式为pcm格式
//2:双声道
//SL_SAMPLINGRATE_44_1:采样率为44100
//SL_PCMSAMPLEFORMAT_FIXED_16:采样格式为16bit
//SL_PCMSAMPLEFORMAT_FIXED_16:数据大小为16bit
//SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT:左右声道(双声道)
//SL_BYTEORDER_LITTLEENDIAN:小端模式
SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 2, SL_SAMPLINGRATE_44_1,
SL_PCMSAMPLEFORMAT_FIXED_16,
SL_PCMSAMPLEFORMAT_FIXED_16,
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
SL_BYTEORDER_LITTLEENDIAN};
//数据源 将上述配置信息放到这个数据源中
SLDataSource audioSrc = {&loc_bufq, &format_pcm};
//3.2 配置音轨(输出)
//设置混音器
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
SLDataSink audioSnk = {&loc_outmix, NULL};
//需要的接口 操作队列的接口
const SLInterfaceID ids[1] = {SL_IID_BUFFERQUEUE};
const SLboolean req[1] = {SL_BOOLEAN_TRUE};
//3.3 创建播放器
result = (*engineInterface)->CreateAudioPlayer(engineInterface, &bqPlayerObject, &audioSrc,
&audioSnk, 1, ids, req);
if (SL_RESULT_SUCCESS != result) {
return;
}
//3.4 初始化播放器:SLObjectItf bqPlayerObject
result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
if (SL_RESULT_SUCCESS != result) {
return;
}
//3.5 获取播放器接口:SLPlayItf bqPlayerPlay
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
if (SL_RESULT_SUCCESS != result) {
return;
}
/**
* 4、设置播放回调函数
*/
//4.1 获取播放器队列接口:SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue
(*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, &bqPlayerBufferQueue);
//4.2 设置回调 void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
(*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, this);
/**
* 5、设置播放器状态为播放状态
*/
(*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
/**
* 6、手动激活回调函数
*/
bqPlayerCallback(bqPlayerBufferQueue, this);
}
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
AudioChannel *audioChannel = static_cast<AudioChannel *>(context);
int pcm_size = audioChannel->getPCM();
if (pcm_size > 0) {
(*bq)->Enqueue(bq, audioChannel->out_buffers, pcm_size);
}
}
代码还在整理当中https://github.com/yizhongliu/FFMediaPlayer
官网
https://www.khronos.org/opensles/
https://developer.android.google.cn/ndk/guides/audio/opensl
参考
https://www.jianshu.com/p/2b8d2de9a47b
https://blog.csdn.net/Poisx/article/details/78336404
网友评论