一、播放流程
二、步骤
1、初始化引擎
• SLObjectItf engineObject = NULL;
• SLEngineItf engineEngine = NULL;
• slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
• (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
• (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
2、slCreateEngine参数
• SL_API SLresult SLAPIENTRY slCreateEngine(
• SLObjectItf *pEngine,
• SLuint32 numOptions
• const SLEngineOption *pEngineOptions, //选择项目 默认参数
• SLuint32 numInterfaces,
• const SLInterfaceID *pInterfaceIds, //支持的接口
• const SLboolean * pInterfaceRequired //接口标识数值,是否支持
• )
3、SLObjectItf 创建
• SLresult (*Realize) (
• SLObjectItf self,
• SLboolean async
• );
• 对象已实现状态 (false阻塞)
4、GetInterface 获取接口
• SLresult (*GetInterface) (
• SLObjectItf self,
• const SLInterfaceID iid,
• void * pInterface
• );
5、创建输出设备
• SLEngineItf engineEngine = NULL;
• SLObjectItf outputMixObject = NULL;
• (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, 0, 0);
• (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
• SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX,
outputMixObject};
• SLDataSink audioSnk = {&outputMix, NULL};
6、配置PCM格式信息
• SLDataLocator_AndroidSimpleBufferQueue
android_queue={SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,2};
• SLDataFormat_PCM pcm={
• SL_DATAFORMAT_PCM,//播放pcm格式的数据
• 2,//2个声道(立体声)
• SL_SAMPLINGRATE_44_1,//44100hz的频率
• SL_PCMSAMPLEFORMAT_FIXED_16,//位数 16位
• SL_PCMSAMPLEFORMAT_FIXED_16,//和位数一致就行
• SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,//立体声(前左前右)
• SL_BYTEORDER_LITTLEENDIAN//小端模式
• };
• SLDataSource slDataSource = {&android_queue, &pcm};
7、初始化播放器
• const SLInterfaceID ids[1] = {SL_IID_BUFFERQUEUE};
• const SLboolean req[1] = {SL_BOOLEAN_TRUE};
• (*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject, &slDataSource,
&audioSnk, 1, ids, req);
• //初始化播放器
• (*pcmPlayerObject)->Realize(pcmPlayerObject, SL_BOOLEAN_FALSE);
• // 得到接口后调用 获取Player接口
• (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, &pcmPlayerPlay);
8、播放和缓冲队列
• 注册回调缓冲区 获取缓冲队列接口(*pcmPlayerObject)-
>GetInterface(pcmPlayerObject, SL_IID_BUFFERQUEUE, &pcmBufferQueue);
• (*pcmBufferQueue)->RegisterCallback(pcmBufferQueue, pcmBufferCallBack,
NULL);
• (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PLAYING);
• (*pcmBufferQueue)->Enqueue(pcmBufferQueue, "", 1);
三、源码
#include <jni.h>
#include <string>
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#include <android/log.h>
#define LOGD(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"ywl5320",FORMAT,##__VA_ARGS__);
static SLObjectItf engineSL = NULL;
SLEngineItf CreateSL()
{
SLresult re;
SLEngineItf en;
re = slCreateEngine(&engineSL,0,0,0,0,0);
if(re != SL_RESULT_SUCCESS) return NULL;
re = (*engineSL)->Realize(engineSL,SL_BOOLEAN_FALSE);
if(re != SL_RESULT_SUCCESS) return NULL;
re = (*engineSL)->GetInterface(engineSL,SL_IID_ENGINE,&en);
if(re != SL_RESULT_SUCCESS) return NULL;
return en;
}
void PcmCall(SLAndroidSimpleBufferQueueItf bf,void *content){
LOGD("PcmCall");
static FILE *fp = NULL;
static char *buf = NULL;
if (!buf){
buf = new char[1024*1024];
}
if (!fp){
fp = fopen("/sdcard/test.pcm","rb");
LOGD("fp failed 1 ");
}
if (!fp){
LOGD("fp failed 2 ");
return;
}
if (feof(fp) == 0){ //没到结尾
int len = (int) fread(buf, 1, 1024, fp);
LOGD("fp len ",len);
if (len > 0){
// 加入队列
(*bf)->Enqueue(bf,buf,len);
}
}
}
extern "C"
JNIEXPORT jstring
JNICALL
Java_com_phj_testopensl_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
//1 创建引擎
SLEngineItf eng = CreateSL();
if(eng)
{
LOGD("CreateSL success! ");
}
else
{
LOGD("CreateSL failed! ");
}
//2 创建混音器
SLObjectItf mix = NULL;
SLresult re = 0;
re = (*eng)->CreateOutputMix(eng,&mix,0,0,0);
if(re !=SL_RESULT_SUCCESS )
{
LOGD("SL_RESULT_SUCCESS failed!");
}
re = (*mix)->Realize(mix,SL_BOOLEAN_FALSE);
if(re !=SL_RESULT_SUCCESS )
{
LOGD("(*mix)->Realize failed!");
}
SLDataLocator_OutputMix outmix = {SL_DATALOCATOR_OUTPUTMIX,mix};
SLDataSink audioSink= {&outmix,0};
//3、配置音频信息
// 缓存队列
SLDataLocator_AndroidSimpleBufferQueue que = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,10};
//音频格式
SLDataFormat_PCM 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 ds = {&que,&pcm};
// 4 创建播放器
SLObjectItf player = NULL;
SLPlayItf iplayer = NULL;
SLAndroidSimpleBufferQueueItf pcmQue = NULL;
const SLInterfaceID ids[] = {SL_IID_BUFFERQUEUE};
const SLboolean req[] = {SL_BOOLEAN_TRUE};
re = (*eng)->CreateAudioPlayer(eng,&player,&ds,&audioSink, sizeof(ids)/ sizeof(SLInterfaceID),ids,req);
if (re != SL_RESULT_SUCCESS){
LOGD("CreateAudioPlayer failed")
} else {
LOGD("CreateAudioPlayer SUCCESS")
}
(*player)->Realize(player,SL_BOOLEAN_FALSE);
// 获取player接口
re = (*player)->GetInterface(player,SL_IID_PLAY,&iplayer);
if (re != SL_RESULT_SUCCESS){
LOGD("GetInterface failed")
} else {
LOGD("GetInterface SUCCESS")
}
re = (*player)->GetInterface(player,SL_IID_BUFFERQUEUE,&pcmQue);
if (re != SL_RESULT_SUCCESS){
LOGD("GetInterface failed")
} else {
LOGD("GetInterface SUCCESS")
}
// 设置回调函数 播放回调为空时候使用
(*pcmQue)->RegisterCallback(pcmQue,PcmCall,0);
(*iplayer)->SetPlayState(iplayer,SL_PLAYSTATE_PLAYING);
// 启动队列回调
(*pcmQue)->Enqueue(pcmQue,"",1);
return env->NewStringUTF(hello.c_str());
}