native-lib.cppandroid
#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,"xp.chen",FORMAT,##__VA_ARGS__); void bufferQueueCallback(SLAndroidSimpleBufferQueueItf bufferQueue, void *pContext) { static FILE *fp = NULL; static char *buf = NULL; if (!buf) { buf = new char[1024*1024]; } if (!fp) { fp = fopen("/sdcard/test.pcm", "rb"); } if (!fp) return; if (feof(fp) == 0) { int len = fread(buf, 1, 1024, fp); if (len > 0) (*bufferQueue)->Enqueue(bufferQueue, buf, len); } } extern "C" JNIEXPORT jstring JNICALL Java_com_yongdaimi_android_androidapitest_OpenSLESApiUseDemoActivity_stringFromJNI(JNIEnv* env, jobject object) { std::string hello = "Hello from C++"; SLresult re; SLObjectItf engineObject; SLEngineItf slAudioEngine; // 1. Create and init audio engine re = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); if (re != SL_RESULT_SUCCESS) { LOGD("slCreateEngine() failed"); } re = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); if (re != SL_RESULT_SUCCESS) { LOGD("engineObject Realize failed"); } re = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &slAudioEngine); if (re != SL_RESULT_SUCCESS) { LOGD("engineObject GetInterface SL_IID_ENGINE failed"); } // 2. Set output mix SLObjectItf outputMix; re = (*slAudioEngine)->CreateOutputMix(slAudioEngine, &outputMix, 0, NULL, NULL); if (re != SL_RESULT_SUCCESS) { LOGD("CreateOutputMix() failed"); } re = (*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE); if (re != SL_RESULT_SUCCESS) { LOGD("outputMix Realize failed"); } // 3. Configuring the input data source SLDataLocator_AndroidSimpleBufferQueue inputBuffQueueLocator = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 10}; SLDataFormat_PCM input_format_pcm = { SL_DATAFORMAT_PCM, // <<< 輸入的音頻格式,PCM 2, // <<< 輸入的聲道數,2(立體聲) SL_SAMPLINGRATE_44_1, // <<< 輸入的採樣率,44100hz SL_PCMSAMPLEFORMAT_FIXED_16, // <<< 輸入的採樣位數,16bit SL_PCMSAMPLEFORMAT_FIXED_16, // <<< 容器大小,同上 SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT, // <<< 聲道標記,這裏使用左前聲道和右前聲道 SL_BYTEORDER_LITTLEENDIAN // <<< 輸入的字節序,小端 }; SLDataSource dataSource = {&inputBuffQueueLocator, &input_format_pcm}; SLDataLocator_OutputMix outputMixLocator = {SL_DATALOCATOR_OUTPUTMIX, outputMix}; SLDataSink dataSink = {&outputMixLocator, 0}; // 4. Create Audio Player SLObjectItf audioPlayer; SLAndroidSimpleBufferQueueItf pcmBufferQueue; SLPlayItf playInterface; SLInterfaceID audioPlayerInterfaceIDs[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; SLboolean audioPlayerInterfaceRequired[] = {SL_BOOLEAN_TRUE}; re = (*slAudioEngine)->CreateAudioPlayer(slAudioEngine, &audioPlayer, &dataSource, &dataSink, 1, audioPlayerInterfaceIDs, audioPlayerInterfaceRequired); if (re != SL_RESULT_SUCCESS) { LOGD("CreateAudioPlayer() failed"); } re = (*audioPlayer)->Realize(audioPlayer, SL_BOOLEAN_FALSE); if (re != SL_RESULT_SUCCESS) { LOGD("AudioPlayer Realize failed"); } re = (*audioPlayer)->GetInterface(audioPlayer, SL_IID_PLAY, &playInterface); if (re != SL_RESULT_SUCCESS) { LOGD("AudioPlayer GetInterface SL_IID_PLAY failed"); } re = (*audioPlayer)->GetInterface(audioPlayer, SL_IID_BUFFERQUEUE, &pcmBufferQueue); if (re != SL_RESULT_SUCCESS) { LOGD("AudioPlayer GetInterface SL_IID_BUFFERQUEUE failed"); } (*pcmBufferQueue)->RegisterCallback(pcmBufferQueue, bufferQueueCallback, NULL); (*playInterface)->SetPlayState(playInterface, SL_PLAYSTATE_PLAYING); // Start queue callback (*pcmBufferQueue)->Enqueue(pcmBufferQueue, "", 1); return env->NewStringUTF(hello.c_str()); }
代碼中的一些概念補充:api
1.結構體中的 numInterfaces , pInterfaceIds , pInterfaceRequired ,這裏以建立播放器所調用的 CreateAudioPlayer 函數爲例說明:數組
SLresult (*CreateAudioPlayer) ( SLEngineItf self, SLObjectItf * pPlayer, SLDataSource *pAudioSrc, SLDataSink *pAudioSnk, SLuint32 numInterfaces, const SLInterfaceID * pInterfaceIds, const SLboolean * pInterfaceRequired );
各參數含義以下:函數
最後的三個參數用於指定AudioPlayerObject須要包含哪些Interface,若是不包含是否是要直接建立失敗。以前也提到過,並非每一個系統上都實現了 OpenSL ES 爲 Object 定義的全部 Interface,因此在獲取 Interface 的時候須要作一些選擇和判斷,若是建立成功的話咱們就能使用AudioPlayerObject的GetInterface方法獲取到這些Interface了。ui
2. DataSouce和DataSinkthis
OpenSL ES 裏面,這兩個結構體均是做爲建立 Media Object 對象時的參數而存在的,data source 表明着輸入源的信息,即數據從哪兒來、輸入的數據參數是怎樣的;而 data sink 則表明着輸出的信息,即數據輸出到哪兒、以什麼樣的參數來輸出。spa