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; }
最后附上 完整源码