OpenSLES 播放音頻

一、播放流程

流程

二、步驟

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參數(shù)

? SL_API SLresult SLAPIENTRY slCreateEngine(
? SLObjectItf *pEngine,
? SLuint32 numOptions
? const SLEngineOption *pEngineOptions, //選擇項(xiàng)目 默認(rèn)參數(shù)
? SLuint32 numInterfaces,
? const SLInterfaceID *pInterfaceIds, //支持的接口
? const SLboolean * pInterfaceRequired //接口標(biāo)識(shí)數(shù)值,是否支持
? )

3、SLObjectItf 創(chuàng)建

? SLresult (*Realize) (
? SLObjectItf self,
? SLboolean async
? );
? 對(duì)象已實(shí)現(xiàn)狀態(tài) (false阻塞)

4、GetInterface 獲取接口

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

5、創(chuàng)建輸出設(shè)備

? 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格式的數(shù)據(jù)
? 2,//2個(gè)聲道(立體聲)
? SL_SAMPLINGRATE_44_1,//44100hz的頻率
? SL_PCMSAMPLEFORMAT_FIXED_16,//位數(shù) 16位
? SL_PCMSAMPLEFORMAT_FIXED_16,//和位數(shù)一致就行
? 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);
? // 得到接口后調(diào)用 獲取Player接口
? (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, &pcmPlayerPlay);

8、播放和緩沖隊(duì)列

? 注冊(cè)回調(diào)緩沖區(qū) 獲取緩沖隊(duì)列接口(*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){ //沒到結(jié)尾
        int len = (int) fread(buf, 1, 1024, fp);
        LOGD("fp len ",len);
        if (len > 0){
            // 加入隊(duì)列
            (*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 創(chuàng)建引擎
    SLEngineItf eng = CreateSL();
    if(eng)
    {
        LOGD("CreateSL success! ");
    }
    else
    {
        LOGD("CreateSL failed! ");
    }

    //2 創(chuàng)建混音器
    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、配置音頻信息
    // 緩存隊(duì)列
    SLDataLocator_AndroidSimpleBufferQueue que = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,10};
    //音頻格式
    SLDataFormat_PCM pcm = {
            SL_DATAFORMAT_PCM,
            2, // 聲道數(shù)
            SL_SAMPLINGRATE_44_1,
            SL_PCMSAMPLEFORMAT_FIXED_16,
            SL_PCMSAMPLEFORMAT_FIXED_16,
            SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT,
            SL_BYTEORDER_LITTLEENDIAN //字節(jié)序 小段
    };

    SLDataSource ds = {&que,&pcm};

    // 4 創(chuàng)建播放器
    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")
    }

    // 設(shè)置回調(diào)函數(shù) 播放回調(diào)為空時(shí)候使用
    (*pcmQue)->RegisterCallback(pcmQue,PcmCall,0);
    (*iplayer)->SetPlayState(iplayer,SL_PLAYSTATE_PLAYING);

    // 啟動(dòng)隊(duì)列回調(diào)
    (*pcmQue)->Enqueue(pcmQue,"",1);

    return env->NewStringUTF(hello.c_str());
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容