Android 系統爲我們提供了三種錄製音頻的方式
- MediaRecord( Java API)
- AudioRecord( Java API)
- OpenSL ES( Native API)
上兩節說了 MediaRecord 和 AudioRecord,他們都是應用層提供的 Java Api。這節呢就來說下 native 層爲我們提供的相關 api。
什麼是 OpenSL ES
先來看下 OpenSL ES 官方文檔 是怎麼介紹的。
This library allows you to use C or C++ to implement high-performance, low-latency audio, whether you are writing a synthesizer, digital audio workstation, karaoke, game, or other real-time app.
The OpenSL ES™ standard exposes audio features similar to those in the MediaPlayer and MediaRecorder APIs in the Android Java framework. OpenSL ES provides a C language interface as well as C++ bindings, allowing you to call the API from code written in either language.
這兩段話的大致意思就是。我這個庫在音頻處理方面老牛逼了,性能高不說,延時還短的不要不要的。而且使用方法和 MediaPlayer 與 MeidaRecord 基本上差別不大,唯一的要求就是得會 C 或者 C艹 呀。
OpenSL ES 在哪
要進行 NDK 開發就必須得先集成相應環境,正如需要 Android SDK 一樣。同樣需要 Android NDK,如果已經科學上網,則直接在 Android Studio 的 SDk Manager 中直接下載即可
下載完成後新建項目時就會看到有一個 Native C++ 的選項,創建出來的項目是一個 Native 版本的 Hello Word。
OpenSL ES 錄製
OpenSL ES 錄製音頻有如下相關流程
-
創建接口對象
void createEngine() { SLresult result; result = slCreateEngine(&engineObj, 0, nullptr, 0, nullptr, nullptr); assert(result == SL_RESULT_SUCCESS); (void) result; result = (*engineObj)->Realize(engineObj, SL_BOOLEAN_FALSE); assert(SL_RESULT_SUCCESS == result); (void) result; result = (*engineObj)->GetInterface(engineObj, SL_IID_ENGINE, &engine); assert(SL_RESULT_SUCCESS == result); (void) result; const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB}; const SLboolean req[1] = {SL_BOOLEAN_FALSE}; // outputMixObj 用於輸出聲音數據 (*engine)->CreateOutputMix(engine, &outputMixObj, 1, ids, req); result = (*outputMixObj)->Realize(outputMixObj, SL_BOOLEAN_FALSE); assert(SL_RESULT_SUCCESS == result); (void) result; }
-
創建錄音器
result = (*mAudioEngine->engine)->CreateAudioRecorder(mAudioEngine->engine, &mRecorderObj, &audioSrc, &audioSink, 1, id, req); if (SL_RESULT_SUCCESS != result) { return false; } result = (*mRecorderObj)->Realize(mRecorderObj, SL_BOOLEAN_FALSE); if (SL_RESULT_SUCCESS != result) { return false; }
-
設置緩衝隊列和回調函數
result = (*mBufferQueue)->RegisterCallback(mBufferQueue, recorderCallback, this);
-
設置錄音狀態,開始錄製
bool AudioRecorder::start() { if (!mIsInitialized) { if (!initRecorder()) { return false; } mIsInitialized = true; } SLresult result; result = (*mRecorder)->SetRecordState(mRecorder, SL_RECORDSTATE_STOPPED); if (SL_RESULT_SUCCESS != result) { return false; } result = (*mBufferQueue)->Clear(mBufferQueue); if (SL_RESULT_SUCCESS != result) { return false; } // enqueue an empty buffer to be filled by the recorder // (for streaming recording, we would enqueue at least 2 empty buffers to start things off) result = (*mBufferQueue)->Enqueue(mBufferQueue, mBuffers[mIndex], mBufSize * sizeof(short)); if (SL_RESULT_SUCCESS != result) { return false; } // 開始錄製 result = (*mRecorder)->SetRecordState(mRecorder, SL_RECORDSTATE_RECORDING); if (SL_RESULT_SUCCESS != result) { return false; } mIsRecording = true; LOGI("start recording..."); return true; }
最後附上 完整源碼