这里是c语言写的给android用的,可以拿到其他平台使用。既然是最简单的,肯定使用起来就是超级简单如回调方法就一句代码。这里简单说一下使用要注意的地方:
1.如果想要使用opensl的一些功能如音量控制:
只是这样是不可以的,拿到的bqPlayerVolume为空值,还需要在这个地方打开一下:
这是我碰到的坑,帮助大家直接跳过。
2. opensl播放音频速率是一定的,那么给opensl更新数据的速率也是一定的,opensl跟openal一样也是有播放缓存的,每播放完毕缓存中一个pcm音频数据包就会有回调,回调方法就是:
// this callback handler is called every time a buffer finishes playing
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{p->inputDataCount --;
}
我这里处理超简单,就是一个数据包计数,传进去一个pcm数据包就计数加一,这个回调就计数减一,这个计数就表示音频播放器里面将要播放的pcm音频数据包的数量。就根据这个计数来控制pcm数据的更新速率就可以了。如果缓存中播放完毕再更新数据会断片,就是计数为零时。
3.这里处理不好会有内存泄漏,就是传给opensl的数据包地址要用数组或者链表存起来,播放完毕再释放掉。
完整播放器demo:
http://blog.csdn.net/m0_37677536/article/details/78775007
Opensl_io.h
//
// Created by huizai on 2017/12/4.
//#ifndef FFMPEG_DEMO_OPENSL_IO_H
#define FFMPEG_DEMO_OPENSL_IO_H#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>typedef struct opensl_stream {// engine interfacesSLObjectItf engineObject;SLEngineItf engineEngine;// output mix interfacesSLObjectItf outputMixObject;// buffer queue player interfacesSLObjectItf bqPlayerObject;SLPlayItf bqPlayerPlay;SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;SLObjectItf pitchObject;SLPitchItf bqPitchEngne;SLPlaybackRateItf bqPlayerRate;SLPitchItf bqPlayerVolume;// buffer indexesint inputDataCount;double time;uint32_t outchannels; //输出的声道数量uint32_t sampleRate; //采样率} OPENSL_STREAM;int android_SetPlayRate(OPENSL_STREAM *p,int playRate);/*Open the audio device with a given sampling rate (sr), input and output channels and IO buffer sizein frames. Returns a handle to the OpenSL stream
*/
OPENSL_STREAM* android_OpenAudioDevice(uint32_t sr, uint32_t inchannels, uint32_t outchannels, uint32_t bufferframes);/*Close the audio device
*/
void android_CloseAudioDevice(OPENSL_STREAM *p);/*Write a buffer to the OpenSL stream *p, of size samples. Returns the number of samples written.
*/
uint32_t android_AudioOut(OPENSL_STREAM *p, uint16_t *buffer,uint32_t size);#endif //FFMPEG_DEMO_OPENSL_IO_H
Opensl_io.c
//
// Created by huizai on 2017/12/4.
//#include "Opensl_io.h"static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context);// creates the OpenSL ES audio engine
static SLresult openSLCreateEngine(OPENSL_STREAM *p)
{SLresult result;// create engineresult = slCreateEngine(&(p->engineObject), 0, NULL, 0, NULL, NULL);if(result != SL_RESULT_SUCCESS) goto engine_end;// realize the engineresult = (*p->engineObject)->Realize(p->engineObject, SL_BOOLEAN_FALSE);if(result != SL_RESULT_SUCCESS) goto engine_end;// get the engine interface, which is needed in order to create other objectsresult = (*p->engineObject)->GetInterface(p->engineObject, SL_IID_ENGINE, &(p->engineEngine));if(result != SL_RESULT_SUCCESS) goto engine_end;engine_end:return result;
}// opens the OpenSL ES device for output
static SLresult openSLPlayOpen(OPENSL_STREAM *p)
{SLresult result;SLuint32 sr = p->sampleRate;SLuint32 channels = p->outchannels;if(channels) {// configure audio sourceSLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};switch(sr){case 8000:sr = SL_SAMPLINGRATE_8;break;case 11025:sr = SL_SAMPLINGRATE_11_025;break;case 16000:sr = SL_SAMPLINGRATE_16;break;case 22050:sr = SL_SAMPLINGRATE_22_05;break;case 24000:sr = SL_SAMPLINGRATE_24;break;case 32000:sr = SL_SAMPLINGRATE_32;break;case 44100:sr = SL_SAMPLINGRATE_44_1;break;case 48000:sr = SL_SAMPLINGRATE_48;break;case 64000:sr = SL_SAMPLINGRATE_64;break;case 88200:sr = SL_SAMPLINGRATE_88_2;break;case 96000:sr = SL_SAMPLINGRATE_96;break;case 192000:sr = SL_SAMPLINGRATE_192;break;default:break;return -1;}const SLInterfaceID ids[] = {SL_IID_VOLUME};const SLboolean req[] = {SL_BOOLEAN_FALSE};result = (*p->engineEngine)->CreateOutputMix(p->engineEngine, &(p->outputMixObject), 1, ids, req);if(result != SL_RESULT_SUCCESS) return result;// realize the output mixresult = (*p->outputMixObject)->Realize(p->outputMixObject, SL_BOOLEAN_FALSE);int speakers;if(channels > 1)speakers = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;else speakers = SL_SPEAKER_FRONT_CENTER;SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM,channels, sr,SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,(SLuint32)speakers, SL_BYTEORDER_LITTLEENDIAN};SLDataSource audioSrc = {&loc_bufq, &format_pcm};// configure audio sinkSLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, p->outputMixObject};SLDataSink audioSnk = {&loc_outmix, NULL};// create audio playerconst SLInterfaceID ids1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE,SL_IID_PLAYBACKRATE,SL_IID_VOLUME};const SLboolean req1[] = {SL_BOOLEAN_TRUE,SL_BOOLEAN_TRUE,SL_BOOLEAN_TRUE};result = (*p->engineEngine)->CreateAudioPlayer(p->engineEngine, &(p->bqPlayerObject), &audioSrc, &audioSnk,3, ids1, req1);if(result != SL_RESULT_SUCCESS) return result;// realize the playerresult = (*p->bqPlayerObject)->Realize(p->bqPlayerObject, SL_BOOLEAN_FALSE);if(result != SL_RESULT_SUCCESS) return result;// get the play interfaceresult = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_PLAY, &(p->bqPlayerPlay));if(result != SL_RESULT_SUCCESS) return result;// get the play rateresult = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_VOLUME, &(p->bqPlayerVolume));if(result != SL_RESULT_SUCCESS) return result;// get the play volumeresult = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_PLAYBACKRATE, &(p->bqPlayerRate));if(result != SL_RESULT_SUCCESS) return result;// get the buffer queue interfaceresult = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,&(p->bqPlayerBufferQueue));if(result != SL_RESULT_SUCCESS) return result;// register callback on the buffer queueresult = (*p->bqPlayerBufferQueue)->RegisterCallback(p->bqPlayerBufferQueue, bqPlayerCallback, p);if(result != SL_RESULT_SUCCESS) return result;// set the player's state to playingresult = (*p->bqPlayerPlay)->SetPlayState(p->bqPlayerPlay, SL_PLAYSTATE_PLAYING);return result;}return SL_RESULT_SUCCESS;
}// close the OpenSL IO and destroy the audio engine
static void openSLDestroyEngine(OPENSL_STREAM *p)
{// destroy buffer queue audio player object, and invalidate all associated interfacesif (p->bqPlayerObject != NULL) {(*p->bqPlayerObject)->Destroy(p->bqPlayerObject);p->bqPlayerObject = NULL;p->bqPlayerPlay = NULL;p->bqPlayerBufferQueue = NULL;}// destroy output mix object, and invalidate all associated interfacesif (p->outputMixObject != NULL) {(*p->outputMixObject)->Destroy(p->outputMixObject);p->outputMixObject = NULL;}// destroy engine object, and invalidate all associated interfacesif (p->engineObject != NULL) {(*p->engineObject)->Destroy(p->engineObject);p->engineObject = NULL;p->engineEngine = NULL;}
}// open the android audio device for input and/or output
OPENSL_STREAM *android_OpenAudioDevice(uint32_t sr, uint32_t inchannels, uint32_t outchannels, uint32_t bufferframes)
{OPENSL_STREAM *p;//分配内存空间并初始化p = (OPENSL_STREAM *) calloc(1,sizeof(OPENSL_STREAM));//采样率p->sampleRate = sr;//创建引擎对象及接口if(openSLCreateEngine(p) != SL_RESULT_SUCCESS) {android_CloseAudioDevice(p);return NULL;}p->inputDataCount = 0;//输出声道数p->outchannels = outchannels;if(openSLPlayOpen(p) != SL_RESULT_SUCCESS) {android_CloseAudioDevice(p);return NULL;}return p;
}// close the android audio device
void android_CloseAudioDevice(OPENSL_STREAM *p)
{if (p == NULL)return;openSLDestroyEngine(p);free(p);
}// returns timestamp of the processed stream
double android_GetTimestamp(OPENSL_STREAM *p)
{return p->time;
}// this callback handler is called every time a buffer finishes playing
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{OPENSL_STREAM *p = (OPENSL_STREAM *) context;p->inputDataCount --;// free(p->inputBuffer);
}// puts a buffer of size samples to the device
uint32_t android_AudioOut(OPENSL_STREAM *p, uint16_t *buffer,uint32_t size)
{(*p->bqPlayerBufferQueue)->Enqueue(p->bqPlayerBufferQueue,buffer, size);p->inputDataCount ++;return 0;
}int android_SetPlayRate(OPENSL_STREAM *p,int rateChange){SLmillibel value;SLresult result;if (!p) return -1;if (!p->bqPlayerRate) return -1;result = (*p->bqPlayerRate)->GetRate(p->bqPlayerRate,&value);if (result != SL_RESULT_SUCCESS)return -1;if (rateChange<0){value -= 100;} elsevalue += 100;if (value < 500) value = 500;if (value > 2000) value = 2000;result = (*p->bqPlayerRate)->SetRate(p->bqPlayerRate,value);if (result == SL_RESULT_SUCCESS){return 0;} elsereturn -1;
}