Android OpenSL ES 开发:使用 OpenSL 播放 PCM 数据

OpenSL ES 是基于NDK也就是c语言的底层开发音频的公开API,经过使用它可以作到标准化, 高性能,低响应时间的音频功能实现方法。git

此次是使用OpenSL ES来作一个音乐播放器,它可以播放m4a、mp3文件,并可以暂停和调整音量。github

播放音乐须要作一些步骤:缓存

1.建立声音引擎

首先建立声音引擎的对象接口 app

result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);

而后实现它性能

result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);

从声音引擎的对象中抓取声音引擎ui

result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);

建立"输出混音器"spa

result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);

实现输出混合音.net

result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);

2.建立声音播放器

建立和实现播放器code

// realize the player
result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
assert(SL_RESULT_SUCCESS == result);
(void)result;

// get the play interface
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
assert(SL_RESULT_SUCCESS == result);
(void)result;

3.设置播放缓冲

数据格式配置orm

SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_8,
                               SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
                               SL_SPEAKER_FRONT_CENTER, SL_BYTEORDER_LITTLEENDIAN};

数据定位器 就是定位要播放声音数据的存放位置,分为4种:内存位置,输入/输出设备位置,缓冲区队列位置,和midi缓冲区队列位置。
数据定位器配置

SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};

获得了缓存队列接口,并注册

// get the buffer queue interface
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
                                         &bqPlayerBufferQueue);
assert(SL_RESULT_SUCCESS == result);
(void)result;

// register callback on the buffer queue
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
assert(SL_RESULT_SUCCESS == result);
(void)result;

4.得到其余接口用来控制播放

获得声音特效接口

// get the effect send interface
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND,
                                         &bqPlayerEffectSend);
assert(SL_RESULT_SUCCESS == result);
(void)result;

获得音量接口

// get the volume interface
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
assert(SL_RESULT_SUCCESS == result);
(void)result;

// set the player's state to playing
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
assert(SL_RESULT_SUCCESS == result);
(void)result;

5.提供播放数据

打开音乐文件

// convert Java string to UTF-8
const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL);
assert(NULL != utf8);

// use asset manager to open asset by filename
AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
assert(NULL != mgr);
AAsset* asset = AAssetManager_open(mgr, utf8, AASSET_MODE_UNKNOWN);

// release the Java string and UTF-8
(*env)->ReleaseStringUTFChars(env, filename, utf8);

// the asset might not be found
if (NULL == asset) {
    return JNI_FALSE;
}

// open asset as file descriptor
off_t start, length;
int fd = AAsset_openFileDescriptor(asset, &start, &length);
assert(0 <= fd);
AAsset_close(asset); 

设置播放数据

SLDataLocator_AndroidFD loc_fd = {SL_DATALOCATOR_ANDROIDFD, fd, start, length};
SLDataFormat_MIME format_mime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
SLDataSource audioSrc = {&loc_fd, &format_mime};

6.播放音乐

播放音乐只须要经过播放接口改变播放状态就能够了,暂停也是,中止也是,可是暂停必须以前的播放缓存作了才行,不然那暂停就至关于中止了

result = (*fdPlayerPlay)->SetPlayState(fdPlayerPlay, isPlaying ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_PAUSED);

7.调解音量

SLVolumeItf getVolume()
{
if (fdPlayerVolume != NULL)
return fdPlayerVolume;
else
return bqPlayerVolume;
}

void Java_com_renhui_openslaudio_MainActivity_setVolumeAudioPlayer(JNIEnv env, jclass clazz,
jint millibel)
{
SLresult result;
SLVolumeItf volumeItf = getVolume();
if (NULL != volumeItf) {
result = (volumeItf)->SetVolumeLevel(volumeItf, millibel);
assert(SL_RESULT_SUCCESS == result);
(void)result;
}
}

8.释放资源

关闭app时释放占用资源

void Java_com_renhui_openslaudio_MainActivity_shutdown(JNIEnv* env, jclass clazz)
{

// destroy buffer queue audio player object, and invalidate all associated interfaces
if (bqPlayerObject != NULL) {
    (*bqPlayerObject)->Destroy(bqPlayerObject);
    bqPlayerObject = NULL;
    bqPlayerPlay = NULL;
    bqPlayerBufferQueue = NULL;
    bqPlayerEffectSend = NULL;
    bqPlayerMuteSolo = NULL;
    bqPlayerVolume = NULL;
}

// destroy file descriptor audio player object, and invalidate all associated interfaces
if (fdPlayerObject != NULL) {
    (*fdPlayerObject)->Destroy(fdPlayerObject);
    fdPlayerObject = NULL;
    fdPlayerPlay = NULL;
    fdPlayerSeek = NULL;
    fdPlayerMuteSolo = NULL;
    fdPlayerVolume = NULL;
}

// destroy output mix object, and invalidate all associated interfaces
if (outputMixObject != NULL) {
    (*outputMixObject)->Destroy(outputMixObject);
    outputMixObject = NULL;
    outputMixEnvironmentalReverb = NULL;
}

// destroy engine object, and invalidate all associated interfaces
if (engineObject != NULL) {
    (*engineObject)->Destroy(engineObject);
    engineObject = NULL;
    engineEngine = NULL;
}
}

参考文章

http://blog.csdn.net/u013898698/article/details/72822595

http://blog.csdn.net/ywl5320/article/details/78503768

参考源码

https://github.com/renhui/OpenSL_Audio

相关文章
相关标签/搜索