美文网首页我爱编程
Android OpenSL ES播放pcm音频

Android OpenSL ES播放pcm音频

作者: 航行在蓝天的蚂蚱 | 来源:发表于2018-05-27 21:07 被阅读172次

    OpenSL ES是一个嵌入式、跨平台、免费的、音频处理库,android ndk也引入了它,在android-ndk-r14b/platforms/android-21/arch-arm/usr/lib/libOpenSLES.so的目录下,libOpenSLES.so就是适用于Android平台的开发库。OpenELES对于android平台的支持只有部分API,因此,对于 OpenSL ES API 的使用,我们还需要特别留意哪些是 Android 支持的,哪些是不支持的,具体相关文档的地址位于 NDK docs 目录下:
    NDK根目录/docs/Additional_library_docs/opensles/index.html
    NDK根目录/docs/Additional_library_docs/opensles/OpenSL_ES_Specification_1.0.1.pdf
    OpenSLES详情请参考Google官网介绍:https://developer.android.com/ndk/guides/audio/opensl-for-android?hl=es

    接口解释:

    类接口:SLObjectltf
    通过SLObjectltf接口类,可以创建所需要的各种类型的类接口,比如:
    创建引擎接口对象:SLObjectltf engineObject
    创建混音器接口对象:SLObjectltf outputMixObject
    创建播放器接口对象:SLObjectltf playerObject
    具体接口类
    引擎:SLEngineltf
    播放器:SLPlayltf
    声音控制器:SLVolumeltf等

    创建三部曲

    以创建引擎接口对象为例(create->realize->get)

    SLObjectltf engineObject = NULL;//用SLObjectltf声明引擎接口对象
    SLEngineltf engineEngine = NULL;//声明具体的引擎对象实例
    void createEnngine()
    {
    SLresult result;//返回结果
    //第一步:创建引擎
    result=slCreateEngine(&engineObject,0,NULL,0,NULL,NULL);
    //第二步:实现(Realize)engineObject,SL_BOOLEAN_FALSE);
    result=(*engineObject)->Realize(engineObject,SL_BOOLEAN_FALSE);
    //第三步:通过engineObject的GetInterface方法初始化enngineEngine
    result=(*engineObject)->GetInterface(engineObject,SL_IID_ENGINNE,&engineEngine);
    }
    //销毁
    (*engineObject)->Destroy(engineObject);
    

    OpenEL ES使用流程:
    1、创建接口对象;

     // TODO
        //读取pcm文件
        pcmFile = fopen(url, "r");
        if(pcmFile == NULL)
        {
            LOGE("%s", "fopen file error");
            return;
        }
        out_buffer = (uint8_t *) malloc(44100 * 2 * 2);
        SLresult result;
        // 创建引擎对象
       slCreateEngine(&engineObject, 0, 0, 0, 0, 0);
        (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
        (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
    

    2、设置混音器;

    //设置混音器;
      const SLInterfaceID mids[1] = {SL_IID_ENVIRONMENTALREVERB};
        const SLboolean mreq[1] = {SL_BOOLEAN_FALSE};
        result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, mids, mreq);
        (void)result;
        result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
        (void)result;
        result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB, &outputMixEnvironmentalReverb);
        if (SL_RESULT_SUCCESS == result) {
            result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(
                    outputMixEnvironmentalReverb, &reverbSettings);
            (void)result;
        }
        SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
    

    3、创建播放器(录音器);

     // 创建播放器
     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};
        SLDataSink audioSnk = {&outputMix, NULL};
        const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND, SL_IID_VOLUME};
        const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
    
        result = (*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject, &slDataSource, &audioSnk, 3, ids, req);
        // 初始化播放器
        (*pcmPlayerObject)->Realize(pcmPlayerObject, SL_BOOLEAN_FALSE);
        //得到接口后调用  获取Player接口
        (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, &pcmPlayerPlay);
    

    4、设置缓冲队列和回调函数;

      // 创建缓冲区和回调函数
        (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_BUFFERQUEUE, &pcmBufferQueue);
    
        //缓冲接口回调
        (*pcmBufferQueue)->RegisterCallback(pcmBufferQueue, pcmBufferCallBack, NULL);
        //获取音量接口
        (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_VOLUME, &pcmPlayerVolume);
        //初始化pcm文件数据
        void getPcmData(void **pcm)
    {
        while(!feof(pcmFile))
        {
            fread(out_buffer, 44100 * 2 * 2, 1, pcmFile);
            if(out_buffer == NULL)
            {
                LOGI("%s", "read end");
                break;
            } else{
                LOGI("%s", "reading");
            }
            *pcm = out_buffer;
            break;
        }
    }
    //取出缓冲数据
    void pcmBufferCallBack(SLAndroidSimpleBufferQueueItf bf, void * context)
    {
        //assert(NULL == context);
        getPcmData(&buffer);
        // for streaming playback, replace this test by logic to find and fill the next buffer
        if (NULL != buffer) {
            SLresult result;
            // enqueue another buffer
            result = (*pcmBufferQueue)->Enqueue(pcmBufferQueue, buffer, 44100 * 2 * 2);
            // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
            // which for this code example would indicate a programming error
        }
    }
    

    5、设置播放状态;

    // 设置播放状态
        (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PLAYING);
    

    6、启动回到函数;

       // 主动调用回调函数开始工作
        pcmBufferCallBack(pcmBufferQueue, NULL);
    

    相关文章

      网友评论

        本文标题:Android OpenSL ES播放pcm音频

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