OpenSLES
OpenSLES 播放声音流程
播放队列
只要往播放队列中压入数据, 就会播放. 采用的是回调函数, 当取出的 buffer 数据播放完毕, 就会清理 buffer, 让队列空出
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HnqeTGvV-1688353498902)(C:\Users\Administrator\Desktop\readme\opensles_queue.png)]
SLObjectItf 的定义
typedef const struct SLObjectItf_ * const * SLObjectItf;
结构体 SLObjectItf_ 里面全是函数指针
struct SLObjectItf_ {
SLresult (*Realize) (
SLObjectItf self,
SLboolean async
);
SLresult (*Resume) (
SLObjectItf self,
SLboolean async
);
SLresult (*GetState) (
SLObjectItf self,
SLuint32 * pState
);
SLresult (*GetInterface) (
SLObjectItf self,
const SLInterfaceID iid,//获取的结构功能id
void * pInterface//存储接口功能的对象,即接口对象
);
SLresult (*RegisterCallback) (
SLObjectItf self,
slObjectCallback callback,
void * pContext
);
void (*AbortAsyncOperation) (
SLObjectItf self
);
void (*Destroy) (
SLObjectItf self
);
SLresult (*SetPriority) (
SLObjectItf self,
SLint32 priority,
SLboolean preemptable
);
SLresult (*GetPriority) (
SLObjectItf self,
SLint32 *pPriority,
SLboolean *pPreemptable
);
SLresult (*SetLossOfControlInterfaces) (
SLObjectItf self,
SLint16 numInterfaces,
SLInterfaceID * pInterfaceIDs,
SLboolean enabled
);
};
SLEngineItf 的定义
typedef const struct SLEngineItf_ * const * SLEngineItf;
结构体 SLEngineItf_ 里面全是函数指针
struct SLEngineItf_ {
SLresult (*CreateLEDDevice) (
SLEngineItf self,
SLObjectItf * pDevice,
SLuint32 deviceID,
SLuint32 numInterfaces,
const SLInterfaceID * pInterfaceIds,
const SLboolean * pInterfaceRequired
);
SLresult (*CreateVibraDevice) (
SLEngineItf self,
SLObjectItf * pDevice,
SLuint32 deviceID,
SLuint32 numInterfaces,
const SLInterfaceID * pInterfaceIds,
const SLboolean * pInterfaceRequired
);
SLresult (*CreateAudioPlayer) (
SLEngineItf self,//声音引擎
SLObjectItf * pPlayer,//声音播放器
SLDataSource *pAudioSrc,//声音数据源
SLDataSink *pAudioSnk,//声音输出池, 声音输出设备
SLuint32 numInterfaces,//功能清单数目
const SLInterfaceID * pInterfaceIds,//功能清单, 要让播放器支持的功能
const SLboolean * pInterfaceRequired//功能强制实现逻辑
);
SLresult (*CreateAudioRecorder) (
SLEngineItf self,
SLObjectItf * pRecorder,
SLDataSource *pAudioSrc,
SLDataSink *pAudioSnk,
SLuint32 numInterfaces,
const SLInterfaceID * pInterfaceIds,
const SLboolean * pInterfaceRequired
);
SLresult (*CreateMidiPlayer) (
SLEngineItf self,
SLObjectItf * pPlayer,
SLDataSource *pMIDISrc,
SLDataSource *pBankSrc,
SLDataSink *pAudioOutput,
SLDataSink *pVibra,
SLDataSink *pLEDArray,
SLuint32 numInterfaces,
const SLInterfaceID * pInterfaceIds,
const SLboolean * pInterfaceRequired
);
SLresult (*CreateListener) (
SLEngineItf self,
SLObjectItf * pListener,
SLuint32 numInterfaces,
const SLInterfaceID * pInterfaceIds,
const SLboolean * pInterfaceRequired
);
SLresult (*Create3DGroup) (
SLEngineItf self,
SLObjectItf * pGroup,
SLuint32 numInterfaces,
const SLInterfaceID * pInterfaceIds,
const SLboolean * pInterfaceRequired
);
SLresult (*CreateOutputMix) (
SLEngineItf self,
SLObjectItf * pMix,
SLuint32 numInterfaces,
const SLInterfaceID * pInterfaceIds,
const SLboolean * pInterfaceRequired
);
SLresult (*CreateMetadataExtractor) (
SLEngineItf self,
SLObjectItf * pMetadataExtractor,
SLDataSource * pDataSource,
SLuint32 numInterfaces,
const SLInterfaceID * pInterfaceIds,
const SLboolean * pInterfaceRequired
);
SLresult (*CreateExtensionObject) (
SLEngineItf self,
SLObjectItf * pObject,
void * pParameters,
SLuint32 objectID,
SLuint32 numInterfaces,
const SLInterfaceID * pInterfaceIds,
const SLboolean * pInterfaceRequired
);
SLresult (*QueryNumSupportedInterfaces) (
SLEngineItf self,
SLuint32 objectID,
SLuint32 * pNumSupportedInterfaces
);
SLresult (*QuerySupportedInterfaces) (
SLEngineItf self,
SLuint32 objectID,
SLuint32 index,
SLInterfaceID * pInterfaceId
);
SLresult (*QueryNumSupportedExtensions) (
SLEngineItf self,
SLuint32 * pNumExtensions
);
SLresult (*QuerySupportedExtension) (
SLEngineItf self,
SLuint32 index,
SLchar * pExtensionName,
SLint16 * pNameLength
);
SLresult (*IsExtensionSupported) (
SLEngineItf self,
const SLchar * pExtensionName,
SLboolean * pSupported
);
};
播放引擎创建与初始化
slCreateEngine(创建引擎)
**创建播放 engine **
SL_API SLresult SLAPIENTRY slCreateEngine(
SLObjectItf *pEngine,
SLuint32 numOptions,
const SLEngineOption *pEngineOptions,
SLuint32 numInterfaces,
const SLInterfaceID *pInterfaceIds,
const SLboolean * pInterfaceRequired
);
-
pEngine 引擎指针
-
numOptions 选择项数量
-
pEngineOptions 具体的选择项
-
numInterfaces 支持的接口数量
-
pInterfaceIds 支持的接口
-
pInterfaceRequired 接口是关闭还是开启
SLObjectItf engineObject;
slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr);
Realize(初始化引擎)
初始化化上一步创建的引擎结构体
(*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
GetInterface(获取引擎接口)
获取引擎接口
SLEngineItf engineInterface;//引擎接口
(*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineInterface);
创建输出设备
CreateOutputMix(创建混音器)
SLObjectItf outputMixObject;//混音器
(*engineInterface)->CreateOutputMix(
engineInterface, &outputMixObject,
SL_BOOLEAN_FALSE, nullptr, nullptr);
Realize(初始化混音器)
初始化化上一步创建的结构体
(*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
GetInterface(获取混音器接口)
获取混音器接口, 不启用混响, 可以不用获取此接口
SLEngineItf outputMixEnvironmentalReverb;//混音器接口
(*outputMixObject)->GetInterface(
outputMixObject, SL_IID_ENVIRONMENTALREVERB,
&outputMixEnvironmentalReverb);
定义输出接口
- 创建混音器 mix
- 创建一个混音器输出对象 audioSink, 而混音的输出对象 outmix,就存在audioSink中初始化的。
//设置混音器
SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
//声音输出数据
SLDataSink audioSink = {&outputMix, nullptr};
配置 PCM 音频格式信息
//创建 Buffer 缓冲队列, 大小为 10
SLDataLocator_AndroidSimpleBufferQueue simpleBufferQueue = {
SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 10};
// PCM数据格式
SLDataFormat_PCM formatPcm = {
SL_DATAFORMAT_PCM,//数据格式
2,//声道数
SL_SAMPLINGRATE_44_1,//采样率 44100(每秒采集44100个点)
SL_PCMSAMPLEFORMAT_FIXED_16,//每秒采样样本 存放大小 16bit
SL_PCMSAMPLEFORMAT_FIXED_16,//每个样本 存放大小 16bit
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, // 前左声道 前右声道
SL_BYTEORDER_LITTLEENDIAN//字节序(小端) 例如:int类型四个字节(到底是 高位在前 还是 低位在前 的排序方式,一般我们都是小端)
};
//音频数据源
SLDataSource audioSrc = {&simpleBufferQueue, &formatPcm};
创建播放器
const SLInterfaceID ids[1] = {SL_IID_BUFFERQUEUE};// 播放队列接口参数
const SLboolean req[1] = {SL_BOOLEAN_TRUE};//表示接口是否开放
SLObjectItf bpPlayerObject;//播放器
SLPlayItf bpPlayerInterface;//播放器接口
SLAndroidSimpleBufferQueueItf bpPlayerBufferQueue;//播放器采样缓冲队列
//创建播放器
int result = (*engineInterface)->CreateAudioPlayer(
engineInterface,
&bpPlayerObject,
&audioSrc,
&audioSink,
//工作队列
1,
ids,
req);
if (result != SL_RESULT_SUCCESS) {
return;
}
//初始化播放器
result = (*bpPlayerObject)->Realize(bpPlayerObject, SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS) {
return;
}
//获取播放器接口
result = (*bpPlayerObject)->GetInterface(bpPlayerObject, SL_IID_PLAY, &bpPlayerInterface);
if (result != SL_RESULT_SUCCESS) {
return;
}
//获取播放器队列接口
result = (*bpPlayerObject)->GetInterface(bpPlayerObject, SL_IID_BUFFERQUEUE, &bpPlayerBufferQueue);
if (result != SL_RESULT_SUCCESS) {
LOGE("获取播放器队列接口 error")
return;
}
设置回调函数,启动引擎播放
//回调函数
void bpPlayerCallback(SLAndroidSimpleBufferQueueItf caller,
void *pContext) {
auto *audio_channel = static_cast<AudioChannel *>(pContext);
int pcm_size = audio_channel->getPcm();//这里是从ffmpeg里面获取重采样后的 PCM 数据
(*caller)->Enqueue(caller, audio_channel->out_buffers, pcm_size);
}
SLAndroidSimpleBufferQueueItf bpPlayerBufferQueue;//播放器采样缓冲队列
//设置回调函数
(*bpPlayerBufferQueue)->RegisterCallback(bpPlayerBufferQueue, bpPlayerCallback, this);
//设置播放器播放状态
(*bpPlayerInterface)->SetPlayState(bpPlayerInterface, SL_PLAYSTATE_PLAYING);
//手动调用一次回调函数
bpPlayerCallback(bpPlayerBufferQueue, this);
在 android 中使用
-
链接 OpenSLES 库
target_link_libraries(OpenSLES )
-
导入头文件
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>