Android 音视频深入 十三 OpenSL ES 制作音乐播放器,能暂停和调整音量(附源码下载)

行是知之始,知是行之成。这篇文章主要讲述Android 音视频深入 十三 OpenSL ES 制作音乐播放器,能暂停和调整音量(附源码下载)相关的知识,希望能为你提供帮助。
项目地址
https://github.com/979451341/OpenSLAudio
OpenSL ES 是基于NDK也就是c语言的底层开发音频的公开API,通过使用它能够做到标准化, 高性能,低响应时间的音频功能实现方法。
这次是使用OpenSL ES来做一个音乐播放器,它能够播放m4a、mp3文件,并能够暂停和调整音量
播放音乐需要做一些步骤
1.创建声音引擎
首先创建声音引擎的对象接口
result = slCreateEngine(& engineObject, 0, NULL, 0, NULL, NULL);
然后实现它
result = (*engineObject)-> Realize(engineObject, SL_BOOLEAN_FALSE);
从声音引擎的对象中抓取声音引擎
result = (*engineObject)-> GetInterface(engineObject, SL_IID_ENGINE, & engineEngine);
创建" 输出混音器"
result = (*engineEngine)-> CreateOutputMix(engineEngine, & outputMixObject, 1, ids, req);
【Android 音视频深入 十三 OpenSL ES 制作音乐播放器,能暂停和调整音量(附源码下载)】实现输出混合音
result = (*outputMixObject)-> Realize(outputMixObject, SL_BOOLEAN_FALSE);
2.创建声音播放器
创建和实现播放器

// 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.设置播放缓冲
数据格式配置
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 = https://www.songbingjia.com/android/{& 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_ywl5320_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_ywl5320_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

    推荐阅读