美文网首页
OpenSLES 播放音频

OpenSLES 播放音频

作者: PuHJ | 来源:发表于2018-08-16 12:05 被阅读227次

    一、播放流程

    流程

    二、步骤

    1、初始化引擎

    • SLObjectItf engineObject = NULL;
    • SLEngineItf engineEngine = NULL;
    • slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
    • (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    • (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
    

    2、slCreateEngine参数

    • SL_API SLresult SLAPIENTRY slCreateEngine(
    • SLObjectItf *pEngine,
    • SLuint32 numOptions
    • const SLEngineOption *pEngineOptions, //选择项目 默认参数
    • SLuint32 numInterfaces,
    • const SLInterfaceID *pInterfaceIds, //支持的接口
    • const SLboolean * pInterfaceRequired //接口标识数值,是否支持
    • )
    

    3、SLObjectItf 创建

    • SLresult (*Realize) (
    • SLObjectItf self,
    • SLboolean async
    • );
    • 对象已实现状态 (false阻塞)
    

    4、GetInterface 获取接口

    • SLresult (*GetInterface) (
    • SLObjectItf self,
    • const SLInterfaceID iid,
    • void * pInterface
    • );
    

    5、创建输出设备

    • SLEngineItf engineEngine = NULL;
    • SLObjectItf outputMixObject = NULL;
    • (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, 0, 0);
    • (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
    • SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX,
    outputMixObject};
    • SLDataSink audioSnk = {&outputMix, NULL};
    

    6、配置PCM格式信息

    • SLDataLocator_AndroidSimpleBufferQueue
    android_queue={SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,2};
    • SLDataFormat_PCM pcm={
    • SL_DATAFORMAT_PCM,//播放pcm格式的数据
    • 2,//2个声道(立体声)
    • SL_SAMPLINGRATE_44_1,//44100hz的频率
    • SL_PCMSAMPLEFORMAT_FIXED_16,//位数 16位
    • SL_PCMSAMPLEFORMAT_FIXED_16,//和位数一致就行
    • SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,//立体声(前左前右)
    • SL_BYTEORDER_LITTLEENDIAN//小端模式
    • };
    • SLDataSource slDataSource = {&android_queue, &pcm};
    

    7、初始化播放器

    • const SLInterfaceID ids[1] = {SL_IID_BUFFERQUEUE};
    • const SLboolean req[1] = {SL_BOOLEAN_TRUE};
    • (*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject, &slDataSource,
    &audioSnk, 1, ids, req);
    • //初始化播放器
    • (*pcmPlayerObject)->Realize(pcmPlayerObject, SL_BOOLEAN_FALSE);
    • // 得到接口后调用 获取Player接口
    • (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, &pcmPlayerPlay);
    

    8、播放和缓冲队列

    • 注册回调缓冲区 获取缓冲队列接口(*pcmPlayerObject)-
    >GetInterface(pcmPlayerObject, SL_IID_BUFFERQUEUE, &pcmBufferQueue);
    • (*pcmBufferQueue)->RegisterCallback(pcmBufferQueue, pcmBufferCallBack,
    NULL);
    • (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PLAYING);
    • (*pcmBufferQueue)->Enqueue(pcmBufferQueue, "", 1);
    

    三、源码

    #include <jni.h>
    #include <string>
    #include <SLES/OpenSLES.h>
    #include <SLES/OpenSLES_Android.h>
    #include <android/log.h>
    #define LOGD(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"ywl5320",FORMAT,##__VA_ARGS__);
    
    
    static SLObjectItf  engineSL = NULL;
    SLEngineItf CreateSL()
    {
        SLresult re;
        SLEngineItf en;
        re = slCreateEngine(&engineSL,0,0,0,0,0);
        if(re != SL_RESULT_SUCCESS) return NULL;
        re = (*engineSL)->Realize(engineSL,SL_BOOLEAN_FALSE);
        if(re != SL_RESULT_SUCCESS) return NULL;
        re = (*engineSL)->GetInterface(engineSL,SL_IID_ENGINE,&en);
        if(re != SL_RESULT_SUCCESS) return NULL;
        return en;
    }
    
    void PcmCall(SLAndroidSimpleBufferQueueItf bf,void *content){
        LOGD("PcmCall");
        static FILE *fp = NULL;
        static char *buf = NULL;
        if (!buf){
            buf = new char[1024*1024];
        }
        if (!fp){
            fp = fopen("/sdcard/test.pcm","rb");
            LOGD("fp failed 1 ");
        }
        if (!fp){
            LOGD("fp failed 2 ");
            return;
        }
        if (feof(fp) == 0){ //没到结尾
            int len = (int) fread(buf, 1, 1024, fp);
            LOGD("fp len ",len);
            if (len > 0){
                // 加入队列
                (*bf)->Enqueue(bf,buf,len);
            }
        }
    }
    
    extern "C"
    JNIEXPORT jstring
    
    JNICALL
    Java_com_phj_testopensl_MainActivity_stringFromJNI(
            JNIEnv *env,
            jobject /* this */) {
        std::string hello = "Hello from C++";
    
        //1 创建引擎
        SLEngineItf eng = CreateSL();
        if(eng)
        {
            LOGD("CreateSL success! ");
        }
        else
        {
            LOGD("CreateSL failed! ");
        }
    
        //2 创建混音器
        SLObjectItf mix = NULL;
        SLresult re = 0;
        re = (*eng)->CreateOutputMix(eng,&mix,0,0,0);
        if(re !=SL_RESULT_SUCCESS )
        {
            LOGD("SL_RESULT_SUCCESS failed!");
        }
        re = (*mix)->Realize(mix,SL_BOOLEAN_FALSE);
        if(re !=SL_RESULT_SUCCESS )
        {
            LOGD("(*mix)->Realize failed!");
        }
        SLDataLocator_OutputMix outmix = {SL_DATALOCATOR_OUTPUTMIX,mix};
        SLDataSink audioSink= {&outmix,0};
    
    
        //3、配置音频信息
        // 缓存队列
        SLDataLocator_AndroidSimpleBufferQueue que = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,10};
        //音频格式
        SLDataFormat_PCM pcm = {
                SL_DATAFORMAT_PCM,
                2, // 声道数
                SL_SAMPLINGRATE_44_1,
                SL_PCMSAMPLEFORMAT_FIXED_16,
                SL_PCMSAMPLEFORMAT_FIXED_16,
                SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT,
                SL_BYTEORDER_LITTLEENDIAN //字节序 小段
        };
    
        SLDataSource ds = {&que,&pcm};
    
        // 4 创建播放器
        SLObjectItf player = NULL;
        SLPlayItf iplayer = NULL;
        SLAndroidSimpleBufferQueueItf pcmQue = NULL;
        const SLInterfaceID ids[] = {SL_IID_BUFFERQUEUE};
        const SLboolean req[] = {SL_BOOLEAN_TRUE};
        re = (*eng)->CreateAudioPlayer(eng,&player,&ds,&audioSink, sizeof(ids)/ sizeof(SLInterfaceID),ids,req);
        if (re != SL_RESULT_SUCCESS){
            LOGD("CreateAudioPlayer failed")
        } else {
            LOGD("CreateAudioPlayer SUCCESS")
        }
    
        (*player)->Realize(player,SL_BOOLEAN_FALSE);
        // 获取player接口
        re = (*player)->GetInterface(player,SL_IID_PLAY,&iplayer);
    
        if (re != SL_RESULT_SUCCESS){
            LOGD("GetInterface failed")
        } else {
            LOGD("GetInterface SUCCESS")
        }
    
        re = (*player)->GetInterface(player,SL_IID_BUFFERQUEUE,&pcmQue);
        if (re != SL_RESULT_SUCCESS){
            LOGD("GetInterface failed")
        } else {
            LOGD("GetInterface SUCCESS")
        }
    
        // 设置回调函数 播放回调为空时候使用
        (*pcmQue)->RegisterCallback(pcmQue,PcmCall,0);
        (*iplayer)->SetPlayState(iplayer,SL_PLAYSTATE_PLAYING);
    
        // 启动队列回调
        (*pcmQue)->Enqueue(pcmQue,"",1);
    
        return env->NewStringUTF(hello.c_str());
    }
    
    

    相关文章

      网友评论

          本文标题:OpenSLES 播放音频

          本文链接:https://www.haomeiwen.com/subject/dxbnbftx.html