这里是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 interfaces
SLObjectItf engineObject;
SLEngineItf engineEngine;
// output mix interfaces
SLObjectItf outputMixObject;
// buffer queue player interfaces
SLObjectItf bqPlayerObject;
SLPlayItf bqPlayerPlay;
SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
SLObjectItf pitchObject;
SLPitchItf bqPitchEngne;
SLPlaybackRateItf bqPlayerRate;
SLPitchItf bqPlayerVolume;
// buffer indexes
int 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 size
in 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 engine
result = slCreateEngine(&(p->engineObject), 0, NULL, 0, NULL, NULL);
if(result != SL_RESULT_SUCCESS) goto engine_end;
// realize the engine
result = (*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 objects
result = (*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 source
SLDataLocator_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 mix
result = (*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 sink
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, p->outputMixObject};
SLDataSink audioSnk = {&loc_outmix, NULL};
// create audio player
const 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 player
result = (*p->bqPlayerObject)->Realize(p->bqPlayerObject, SL_BOOLEAN_FALSE);
if(result != SL_RESULT_SUCCESS) return result;
// get the play interface
result = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_PLAY, &(p->bqPlayerPlay));
if(result != SL_RESULT_SUCCESS) return result;
// get the play rate
result = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_VOLUME, &(p->bqPlayerVolume));
if(result != SL_RESULT_SUCCESS) return result;
// get the play volume
result = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_PLAYBACKRATE, &(p->bqPlayerRate));
if(result != SL_RESULT_SUCCESS) return result;
// get the buffer queue interface
result = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
&(p->bqPlayerBufferQueue));
if(result != SL_RESULT_SUCCESS) return result;
// register callback on the buffer queue
result = (*p->bqPlayerBufferQueue)->RegisterCallback(p->bqPlayerBufferQueue, bqPlayerCallback, p);
if(result != SL_RESULT_SUCCESS) return result;
// set the player's state to playing
result = (*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 interfaces
if (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 interfaces
if (p->outputMixObject != NULL) {
(*p->outputMixObject)->Destroy(p->outputMixObject);
p->outputMixObject = NULL;
}
// destroy engine object, and invalidate all associated interfaces
if (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;
} else
value += 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;
} else
return -1;
}