Android OpenSL ES播放pcm音頻

OpenSL ES是一個(gè)嵌入式、跨平臺(tái)、免費(fèi)的以舒、音頻處理庫,android ndk也引入了它慢哈,在android-ndk-r14b/platforms/android-21/arch-arm/usr/lib/libOpenSLES.so的目錄下蔓钟,libOpenSLES.so就是適用于Android平臺(tái)的開發(fā)庫。OpenELES對(duì)于android平臺(tái)的支持只有部分API卵贱,因此滥沫,對(duì)于 OpenSL ES API 的使用,我們還需要特別留意哪些是 Android 支持的键俱,哪些是不支持的兰绣,具體相關(guān)文檔的地址位于 NDK docs 目錄下:
NDK根目錄/docs/Additional_library_docs/opensles/index.html
NDK根目錄/docs/Additional_library_docs/opensles/OpenSL_ES_Specification_1.0.1.pdf
OpenSLES詳情請(qǐng)參考Google官網(wǎng)介紹:https://developer.android.com/ndk/guides/audio/opensl-for-android?hl=es

接口解釋:

類接口:SLObjectltf
通過SLObjectltf接口類,可以創(chuàng)建所需要的各種類型的類接口编振,比如:
創(chuàng)建引擎接口對(duì)象:SLObjectltf engineObject
創(chuàng)建混音器接口對(duì)象:SLObjectltf outputMixObject
創(chuàng)建播放器接口對(duì)象:SLObjectltf playerObject
具體接口類
引擎:SLEngineltf
播放器:SLPlayltf
聲音控制器:SLVolumeltf等

創(chuàng)建三部曲

以創(chuàng)建引擎接口對(duì)象為例(create->realize->get)

SLObjectltf engineObject = NULL;//用SLObjectltf聲明引擎接口對(duì)象
SLEngineltf engineEngine = NULL;//聲明具體的引擎對(duì)象實(shí)例
void createEnngine()
{
SLresult result;//返回結(jié)果
//第一步:創(chuàng)建引擎
result=slCreateEngine(&engineObject,0,NULL,0,NULL,NULL);
//第二步:實(shí)現(xiàn)(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狭魂、創(chuàng)建接口對(duì)象;

 // 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;
    // 創(chuàng)建引擎對(duì)象
   slCreateEngine(&engineObject, 0, 0, 0, 0, 0);
    (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);

2党觅、設(shè)置混音器雌澄;

//設(shè)置混音器;
  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杯瞻、創(chuàng)建播放器(錄音器)镐牺;

 // 創(chuàng)建播放器
 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//結(jié)束標(biāo)志
    };

    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);
    //得到接口后調(diào)用  獲取Player接口
    (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, &pcmPlayerPlay);

4、設(shè)置緩沖隊(duì)列和回調(diào)函數(shù)魁莉;

  // 創(chuàng)建緩沖區(qū)和回調(diào)函數(shù)
    (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_BUFFERQUEUE, &pcmBufferQueue);

    //緩沖接口回調(diào)
    (*pcmBufferQueue)->RegisterCallback(pcmBufferQueue, pcmBufferCallBack, NULL);
    //獲取音量接口
    (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_VOLUME, &pcmPlayerVolume);
    //初始化pcm文件數(shù)據(jù)
    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;
    }
}
//取出緩沖數(shù)據(jù)
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睬涧、設(shè)置播放狀態(tài)募胃;

// 設(shè)置播放狀態(tài)
    (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PLAYING);

6、啟動(dòng)回到函數(shù)畦浓;

   // 主動(dòng)調(diào)用回調(diào)函數(shù)開始工作
    pcmBufferCallBack(pcmBufferQueue, NULL);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末痹束,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子讶请,更是在濱河造成了極大的恐慌祷嘶,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夺溢,死亡現(xiàn)場(chǎng)離奇詭異论巍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)风响,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門嘉汰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人状勤,你說我怎么就攤上這事鞋怀。” “怎么了持搜?”我有些...
    開封第一講書人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵密似,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我朵诫,道長(zhǎng)辛友,這世上最難降的妖魔是什么薄扁? 我笑而不...
    開封第一講書人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任剪返,我火速辦了婚禮,結(jié)果婚禮上邓梅,老公的妹妹穿的比我還像新娘脱盲。我一直安慰自己,他們只是感情好日缨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開白布钱反。 她就那樣靜靜地躺著,像睡著了一般匣距。 火紅的嫁衣襯著肌膚如雪面哥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,215評(píng)論 1 299
  • 那天毅待,我揣著相機(jī)與錄音尚卫,去河邊找鬼。 笑死尸红,一個(gè)胖子當(dāng)著我的面吹牛吱涉,可吹牛的內(nèi)容都是我干的刹泄。 我是一名探鬼主播,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼怎爵,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼特石!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鳖链,我...
    開封第一講書人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤姆蘸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后撒轮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乞旦,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年题山,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了兰粉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡顶瞳,死狀恐怖玖姑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情慨菱,我是刑警寧澤焰络,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站符喝,受9級(jí)特大地震影響闪彼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜协饲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一畏腕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧茉稠,春花似錦描馅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至膀篮,卻和暖如春嘹狞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背誓竿。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來泰國打工磅网, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人烤黍。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓知市,卻偏偏與公主長(zhǎng)得像傻盟,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嫂丙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,085評(píng)論 25 707
  • [TOC] 以下內(nèi)容基于Android 8.0 Project Treble Project treble是And...
    Joe_HUST閱讀 3,120評(píng)論 0 1