OpenSL介绍 并实现播放PCM功能
简单来说OpenSL ES是一个嵌入式、跨平台、免费的、音频 处理库,本文旨在介绍OpenSL的使用方法和参数设置,绝大部分内容参考Android官方NDKdemo,地址为android NDK demo,想学NDK开发的伙伴可以去参考一下,受益良多。
1、创建接口对象
2、设置混音器
3、创建播放器(录音器)
4、设置缓冲队列和回调函数
5、设置播放状态
6、启动回调函数
1、类接口:SLObjectItf
通过SLObjectItf接口类我们可以创建所需要的各种类型的类接口,比如:
创建引擎接口对象:SLObjectItf engineObject
创建混音器接口对象:SLObjectItf outputMixObject
创建播放器接口对象:SLObjectItf playerObject
2、具体的接口类
引擎:SLEngineItf
播放器:SLPlayItf
声音控制器:SLVolumeItf等等
创建三部曲
如:创建引擎接口对象( createrealizeget )
SLObjectItf engineObject = NULL;//用SLObjectItf声明引擎接口对象
SLEngineItf engineEngine = NULL;//声明具体的引擎对象实例
void createEngine()
{
SLresult result;//返回结果
//第一步:创建引擎
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
//第二步:实现(Realize)engineObject接口对象
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
//第三部:通过engineObject的GetInterface方法初始化engineEngine
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
#include
#include
#include
#include
#include "androidLog.h"
#include
#include
//引擎对象
SLObjectItf enginObject = NULL;
//引擎接口
SLEngineItf engineItf = NULL;
//混音器对象(混音器作用是做声音处理)
SLObjectItf outputmixObject = NULL;
//混音器环境接口
SLEnvironmentalReverbItf outputEnvironmentalReverbItf = NULL;
const SLEnvironmentalReverbSettings reverbSettings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;
//播放器对象
SLObjectItf pcmPlayerObject = NULL;
//播放接口
SLPlayItf playItf = NULL;
//播放队列
SLAndroidSimpleBufferQueueItf simpleBufferQueueItf = NULL;
FILE *pcmFile = NULL;
uint8_t *outbuffer;
void* buffer;
//从pcm文件中读取数据
int getPCMbuffer(void** pcm){
//读取到的字节数
int size = 0;
while (!feof(pcmFile)){
size = fread(outbuffer,1,44100 * 2 * 2 / 2,pcmFile);
if (outbuffer==NULL){
LOGI("pcm文件读取完毕");
break;
} else{
LOGI("pcm文件读取中");
}
*pcm = outbuffer;
break;
}
return size;
}
void pcmBufferCallBack(SLAndroidSimpleBufferQueueItf simpleBufferQueueItf1,void* data){
int size = getPCMbuffer(&buffer);
LOGI("pcm读取大小为:%d",size);
if (buffer!=NULL){
LOGI("放入播放队列");
//放入播放队列
(*simpleBufferQueueItf1)->Enqueue(simpleBufferQueueItf1,buffer,size);
}
}
extern "C"
JNIEXPORT void JNICALL
Java_com_zhongcheng_opensl_MainActivity_playPCM(JNIEnv *env, jobject instance, jstring url_) {
const char *url = env->GetStringUTFChars(url_, 0);
SLresult result;
pcmFile = fopen(url,"r");
if (pcmFile==NULL){
LOGI("文件不存在");
return;
}
LOGI("文件存在");
outbuffer = (uint8_t *) malloc(44100 * 2 * 2 / 2);
//初始化引擎对象并由对象得到接口
slCreateEngine(&enginObject, 0, 0, 0, 0, 0);
(*enginObject)->Realize(enginObject, SL_BOOLEAN_FALSE);
result = (*enginObject)->GetInterface(enginObject, SL_IID_ENGINE, &engineItf);
if (SL_RESULT_SUCCESS!=result){
LOGI("引擎接口创建失败!");
return;
}
//需要做的声音处理功能数组
const SLInterfaceID mid[1] = {SL_IID_ENVIRONMENTALREVERB};
const SLboolean mird[1] = {SL_BOOLEAN_FALSE};
result = (*engineItf)->CreateOutputMix(engineItf, &outputmixObject,1,mid,mird);
if (SL_RESULT_SUCCESS!=result){
LOGI("混音器对象创建失败!");
return;
}
//得到上面声明的处理功能的接口
(*outputmixObject)->Realize(outputmixObject,SL_BOOLEAN_FALSE);
result = (*outputmixObject)->GetInterface(outputmixObject,SL_IID_ENVIRONMENTALREVERB,&outputEnvironmentalReverbItf);
if (SL_RESULT_SUCCESS!=result){
LOGI("混音器接口创建失败!");
return;
}
//混音器环境属性设置
result = (*outputEnvironmentalReverbItf)->SetEnvironmentalReverbProperties(outputEnvironmentalReverbItf,&reverbSettings);
if (SL_RESULT_SUCCESS!=result){
LOGI("混音器参数设置失败!");
}
//播放队列
SLDataLocator_AndroidBufferQueue android_queue = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,2};
SLDataFormat_PCM format_pcm = {
SL_DATAFORMAT_PCM, //格式
2,//声道数
SL_SAMPLINGRATE_44_1,//采样率
SL_PCMSAMPLEFORMAT_FIXED_16,//采样位数 一定要与播放的pcm的一样 要不然可能快也可能会慢
SL_PCMSAMPLEFORMAT_FIXED_16,
SL_SPEAKER_FRONT_RIGHT|SL_SPEAKER_FRONT_LEFT,//声道布局 前右|前左
SL_BYTEORDER_LITTLEENDIAN
};
//播放源
SLDataSource dataSource = {&android_queue,&format_pcm};
//混音器
SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX,outputmixObject};
//关联混音器
SLDataSink audiosnk = {&outputMix,NULL};
//要实现的功能
const SLInterfaceID ids[1] = {SL_IID_BUFFERQUEUE};//队列播放
const SLboolean irds[1] = {SL_BOOLEAN_FALSE};
(*engineItf)->CreateAudioPlayer(engineItf,&pcmPlayerObject,&dataSource,&audiosnk,1,ids,irds);
(*pcmPlayerObject)->Realize(pcmPlayerObject,SL_BOOLEAN_FALSE);
//创建播放接口
result = (*pcmPlayerObject)->GetInterface(pcmPlayerObject,SL_IID_PLAY,&playItf);
if (SL_RESULT_SUCCESS!=result){
LOGI("播放器接口创建失败!");
return;
}
//得到Androidbufferqueue接口
(*pcmPlayerObject)->GetInterface(pcmPlayerObject,SL_IID_BUFFERQUEUE,&simpleBufferQueueItf);
//注册回掉函数
(*simpleBufferQueueItf)->RegisterCallback(simpleBufferQueueItf,pcmBufferCallBack,NULL);
//设置播放状态
(*playItf)->SetPlayState(playItf,SL_PLAYSTATE_PLAYING);
//第一次手动调用回掉函数 开始播放
pcmBufferCallBack(simpleBufferQueueItf,NULL);
env->ReleaseStringUTFChars(url_, url);
}