27
2017
09

android使用opensl es进行简单的音频播放

OpenSL ES 全称是:Open Sound Library for Embedded Systems,是一套无授权费、跨平台、针对嵌入式系统精心优化的硬件音频加速API。它为嵌入式移动多媒体设备上的本地应用程序开发者提供标准化, 高性能, 低响应时间的音频功能实现方法,并实现软硬件音频性能的直接跨平台部署,降低android执行难度,促进高级音频市场的发展。

在android系统中是自带了opensl es的so库的,所以我们只需要在CMakeLists中链接以下就可以了,在引入头文件

#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>

声明native方法

//设置播放状态
public  native void setPlayingAssetAudioPlayer(boolean isPlaying);
//释放资源
public  native void shutdown();
//创建引擎
public native void createEngine();
//播放 assets对象,文件名
public native boolean player(AssetManager assetManager, String filename);
extern "C"
JNIEXPORT void JNICALL
Java_com_xiukun_lxkaudio_MainActivity_createEngine(JNIEnv *env, jobject instance) {

    // TODO
    SLresult result;
    //初始化引擎
    slCreateEngine(&engineObject,0,NULL,0,NULL,NULL);

    (*engineObject)->Realize(engineObject,SL_BOOLEAN_FALSE);
    //获取引擎接口
    (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);

    //创建音频输出,配置相关参数
    const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
    const SLboolean req[1] = {SL_BOOLEAN_FALSE};
    (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);

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

    //环境混响
    result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,
                                              &outputMixEnvironmentalReverb);
    if (SL_RESULT_SUCCESS == result) {
        (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(
                outputMixEnvironmentalReverb, &reverbSettings);
    }


}

extern "C"
JNIEXPORT jboolean JNICALL
Java_com_xiukun_lxkaudio_MainActivity_player(JNIEnv *env, jobject instance, jobject assetManager,
                                             jstring filename_) {
    const char *filename = env->GetStringUTFChars(filename_, 0);

    // TODO
    // 读取assets文件
    AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
    AAsset* asset = AAssetManager_open(mgr, filename, AASSET_MODE_UNKNOWN);

    if (NULL == asset) {
        LOGE("读取失败。。。");
        return JNI_FALSE;
    }


    // open asset as file descriptor
    off_t start, length;
    int fd = AAsset_openFileDescriptor(asset, &start, &length);
    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 audioSrc1 = {&loc_fd, &format_mime};

    // configure audio sink
    SLDataLocator_OutputMix loc_outmix1 = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
    SLDataSink audioSnk1 = {&loc_outmix1, NULL};

    // 创建播放器
    const SLInterfaceID audio_ids1[3] = {SL_IID_SEEK, SL_IID_MUTESOLO, SL_IID_VOLUME};
    const SLboolean audio_req1[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};

    (*engineEngine)->CreateAudioPlayer(engineEngine, &fdPlayerObject, &audioSrc1, &audioSnk1,
                                       3, audio_ids1, audio_req1);

    (*fdPlayerObject)->Realize(fdPlayerObject, SL_BOOLEAN_FALSE);

    // 获取播放器接口
    (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_PLAY, &fdPlayerPlay);

    // 定位
    (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_SEEK, &fdPlayerSeek);

    // 静音独奏
    (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_MUTESOLO, &fdPlayerMuteSolo);

    // 音量
    (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_VOLUME, &fdPlayerVolume);

    // 开启重复播放
    (*fdPlayerSeek)->SetLoop(fdPlayerSeek, SL_BOOLEAN_TRUE, 0, SL_TIME_UNKNOWN);


    env->ReleaseStringUTFChars(filename_, filename);

    return JNI_TRUE;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_xiukun_lxkaudio_MainActivity_setPlayingAssetAudioPlayer(JNIEnv *env, jobject instance,
                                                                 jboolean isPlaying) {


    //设置播放状态
    if (NULL != fdPlayerPlay) {

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

}


extern "C"
JNIEXPORT void JNICALL
Java_com_xiukun_lxkaudio_MainActivity_shutdown(JNIEnv *env, jobject instance) {


    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;
    }

    pthread_mutex_destroy(&audioEngineLock);

}

在c中读取assets中的文件,还需引入两个头文件,这两个头文件需要链接android这个库

cmakelists文件:
target_link_libraries( # Specifies the target library.
                       native-lib
                        OpenSLES
                       android
                       ${log-lib} )
 c文件:
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>

这样就可以进行播放了,后面会进行音频录制、分割等方面的研究。

源码地址:https://github.com/luXiuKun/LxkAudio

上一篇:组件化开发之利用SVN搭建私有SpecRepo 下一篇:第三章ReactNative组件的封装