1,创建引擎
2,创建AudioRecorder并开始录音
3,暂停录音
4,释放资源
5,数据是通过回调函数处理的。
好处:缓冲区不用通过AudioRecord.getMinBufferSize获取,设置很小也能正常工作。比如设置80字节bytes

前面的文章我们讲解的是OpenSL ES音频播放,OpenSL ES非常强大,有音频播放当然有录音

下面我们编写OpenSL PCM录音,完成的功能是录制麦克风的声音存储PCM到data私有目录。

二、布局XML 创建文件 /res/layout/open_sl_audio_record.xml

[html]view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:orientation="vertical" >
  6. <Button
  7. android:id="@+id/start"
  8. android:layout_width="wrap_content"
  9. android:layout_height="wrap_content"
  10. android:text="开始" />
  11. <LinearLayout
  12. android:layout_width="match_parent"
  13. android:layout_height="wrap_content"
  14. android:orientation="horizontal" >
  15. <Button
  16. android:id="@+id/stop"
  17. android:layout_width="wrap_content"
  18. android:layout_height="wrap_content"
  19. android:text="暂停" />
  20. </LinearLayout>
  21. </LinearLayout>

布局文件:开始和暂停两个Button控制录音

三、Activity类  创建/src/com/example/testopensl/AudioRecordActivity.java

[java]view plaincopy
  1. package com.example.testopensl;
  2. import java.io.File;
  3. import android.app.Activity;
  4. import android.os.Bundle;
  5. import android.view.View;
  6. import android.view.View.OnClickListener;
  7. import com.example.audio.R;
  8. public class AudioRecordActivity extends Activity implements OnClickListener {
  9. static {
  10. System.loadLibrary("TestAudio");
  11. }
  12. private boolean mRecording;
  13. @Override
  14. protected void onCreate(Bundle savedInstanceState) {
  15. super.onCreate(savedInstanceState);
  16. setContentView(R.layout.open_sl_audio_record);
  17. findViewById(R.id.start).setOnClickListener(this);
  18. findViewById(R.id.stop).setOnClickListener(this);
  19. createEngine();
  20. }
  21. @Override
  22. public void onClick(View v) {
  23. switch (v.getId()) {
  24. case R.id.start:
  25. File file = new File(getCacheDir(), "audio.pcm");
  26. createAudioRecord(file.getAbsolutePath());
  27. mRecording = true;
  28. break;
  29. case R.id.stop:
  30. stop();
  31. mRecording = false;
  32. break;
  33. }
  34. }
  35. @Override
  36. protected void onDestroy() {
  37. super.onDestroy();
  38. if (mRecording) {
  39. stop();
  40. }
  41. shutdown();
  42. }
  43. /** Native methods, implemented in jni folder */
  44. public native void createEngine();
  45. public native void createAudioRecord(String uri);
  46. public native void stop();
  47. public native void shutdown();
  48. }

文件存储位置:/data/data/com.example.audio/cache/audio.pcm

四、编写日志头文件,用于日志输出, 创建/jni/log.h 文件

[cpp]view plaincopy
  1. #ifndef LOG_H_
  2. #define LOG_H_
  3. #include <android/log.h>
  4. #ifndef DGB
  5. #define DGB 0
  6. #endif
  7. #ifndef LOG_TAG
  8. #define LOG_TAG __FILE__
  9. #endif
  10. #ifndef ALOGD
  11. #if DGB
  12. #define ALOGD(...) \
  13. __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
  14. #else
  15. #define ALOGD(...)   ((void)0)
  16. #endif
  17. #endif
  18. #endif /* LOG_H_ */

六、JNI的实现 /jni/com_example_testopensl_AudioRecordActivity.cpp

[cpp]view plaincopy
  1. /** log */
  2. #define LOG_TAG "NATVIE-AudioRecordActivity"
  3. #define DGB 1
  4. #include <jni.h>
  5. #include "com_example_testopensl_AudioRecordActivity.h"
  6. #include "log.h"
  7. #include <stdio.h>
  8. #include <assert.h>
  9. #include <SLES/OpenSLES.h>
  10. #include <SLES/OpenSLES_Android.h>
  11. /* Size of the recording buffer queue */
  12. #define NB_BUFFERS_IN_QUEUE 1
  13. /* Explicitly requesting SL_IID_ANDROIDSIMPLEBUFFERQUEUE and SL_IID_ANDROIDCONFIGURATION
  14. * on the AudioRecorder object */
  15. #define NUM_EXPLICIT_INTERFACES_FOR_RECORDER 2
  16. /* Size of the recording buffer queue */
  17. #define NB_BUFFERS_IN_QUEUE 1
  18. /* Size of each buffer in the queue */
  19. #define BUFFER_SIZE_IN_SAMPLES 8192
  20. #define BUFFER_SIZE_IN_BYTES   (2 * BUFFER_SIZE_IN_SAMPLES)
  21. /* Local storage for Audio data */
  22. int8_t pcmData[NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES];
  23. // engine interfaces
  24. static SLObjectItf engineObject = NULL;
  25. static SLEngineItf engineEngine = NULL;
  26. //audio record interfaces
  27. static SLObjectItf recorderObject = NULL;
  28. static SLRecordItf recordItf = NULL;
  29. static SLAndroidSimpleBufferQueueItf recBuffQueueItf = NULL;
  30. static SLAndroidConfigurationItf configItf = NULL;
  31. static FILE * gFile = NULL;
  32. //-----------------------------------------------------------------
  33. /* Structure for passing information to callback function */
  34. typedef struct CallbackCntxt_ {
  35. SLPlayItf  playItf;
  36. SLuint32   size;
  37. SLint8*   pDataBase;    // Base address of local audio data storage
  38. SLint8*   pData;        // Current address of local audio data storage
  39. } CallbackCntxt;
  40. static CallbackCntxt cntxt;
  41. /* Callback for recording buffer queue events */
  42. void recCallback(SLRecordItf caller, void *pContext, SLuint32 event) {
  43. if (SL_RECORDEVENT_HEADATNEWPOS & event) {
  44. SLmillisecond pMsec = 0;
  45. (*caller)->GetPosition(caller, &pMsec);
  46. ALOGD("SL_RECORDEVENT_HEADATNEWPOS current position=%ums\n", pMsec);
  47. }
  48. if (SL_RECORDEVENT_HEADATMARKER & event) {
  49. SLmillisecond pMsec = 0;
  50. (*caller)->GetPosition(caller, &pMsec);
  51. ALOGD("SL_RECORDEVENT_HEADATMARKER current position=%ums\n", pMsec);
  52. }
  53. }
  54. /* Callback for recording buffer queue events */
  55. void recBufferQueueCallback(SLAndroidSimpleBufferQueueItf queueItf, void *pContext) {
  56. CallbackCntxt *pCntxt = (CallbackCntxt*) pContext;
  57. /* Save the recorded data  */
  58. fwrite(pCntxt->pDataBase, BUFFER_SIZE_IN_BYTES, 1, gFile);
  59. /* Increase data pointer by buffer size */
  60. pCntxt->pData += BUFFER_SIZE_IN_BYTES;
  61. if (pCntxt->pData >= pCntxt->pDataBase + (NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES)) {
  62. pCntxt->pData = pCntxt->pDataBase;
  63. }
  64. (*queueItf)->Enqueue(queueItf, pCntxt->pDataBase, BUFFER_SIZE_IN_BYTES);
  65. SLAndroidSimpleBufferQueueState recQueueState;
  66. (*queueItf)->GetState(queueItf, &recQueueState);
  67. }
  68. /*
  69. * Class:     com_example_testopensl_AudioRecordActivity
  70. * Method:    createEngine
  71. * Signature: ()V
  72. */
  73. JNIEXPORT void JNICALL Java_com_example_testopensl_AudioRecordActivity_createEngine(JNIEnv *, jobject) {
  74. SLEngineOption EngineOption[] = {
  75. {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE}
  76. };
  77. SLresult result;
  78. result = slCreateEngine(&engineObject, 1, EngineOption, 0, NULL, NULL);
  79. assert(SL_RESULT_SUCCESS == result);
  80. /* Realizing the SL Engine in synchronous mode. */
  81. result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
  82. assert(SL_RESULT_SUCCESS == result);
  83. // get the engine interface, which is needed in order to create other objects
  84. result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
  85. assert(SL_RESULT_SUCCESS == result);
  86. }
  87. /*
  88. * Class:     com_example_testopensl_AudioRecordActivity
  89. * Method:    createAudioRecord
  90. * Signature: (Ljava/lang/String;)V
  91. */
  92. JNIEXPORT void JNICALL Java_com_example_testopensl_AudioRecordActivity_createAudioRecord(JNIEnv *env, jobject, jstring uri) {
  93. if (recorderObject != NULL) {
  94. ALOGD(" already create auido record");
  95. return ;
  96. }
  97. const char* utf8 = env->GetStringUTFChars(uri, NULL);
  98. gFile = fopen(utf8, "w");
  99. env->ReleaseStringUTFChars(uri, utf8);
  100. if (gFile == NULL) {
  101. ALOGD(" open file fail ");
  102. return ;
  103. }
  104. SLresult result;
  105. /* setup the data source*/
  106. SLDataLocator_IODevice ioDevice = {
  107. SL_DATALOCATOR_IODEVICE,
  108. SL_IODEVICE_AUDIOINPUT,
  109. SL_DEFAULTDEVICEID_AUDIOINPUT,
  110. NULL
  111. };
  112. SLDataSource recSource = {&ioDevice, NULL};
  113. SLDataLocator_AndroidSimpleBufferQueue recBufferQueue = {
  114. SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
  115. NB_BUFFERS_IN_QUEUE
  116. };
  117. SLDataFormat_PCM pcm = {
  118. SL_DATAFORMAT_PCM,
  119. 2,
  120. SL_SAMPLINGRATE_44_1,
  121. SL_PCMSAMPLEFORMAT_FIXED_16,
  122. 16,
  123. SL_SPEAKER_FRONT_LEFT| SL_SPEAKER_FRONT_RIGHT,
  124. SL_BYTEORDER_LITTLEENDIAN
  125. };
  126. SLDataSink dataSink = { &recBufferQueue, &pcm };
  127. SLInterfaceID iids[NUM_EXPLICIT_INTERFACES_FOR_RECORDER] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION};
  128. SLboolean required[NUM_EXPLICIT_INTERFACES_FOR_RECORDER] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
  129. /* Create the audio recorder */
  130. result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject , &recSource, &dataSink,
  131. NUM_EXPLICIT_INTERFACES_FOR_RECORDER, iids, required);
  132. assert(SL_RESULT_SUCCESS == result);
  133. /* get the android configuration interface*/
  134. result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDCONFIGURATION, &configItf);
  135. assert(SL_RESULT_SUCCESS == result);
  136. /* Realize the recorder in synchronous mode. */
  137. result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);
  138. assert(SL_RESULT_SUCCESS == result);
  139. /* Get the buffer queue interface which was explicitly requested */
  140. result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, (void*) &recBuffQueueItf);
  141. assert(SL_RESULT_SUCCESS == result);
  142. /* get the record interface */
  143. result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recordItf);
  144. assert(SL_RESULT_SUCCESS == result);
  145. /* Set up the recorder callback to get events during the recording */
  146. result = (*recordItf)->SetMarkerPosition(recordItf, 2000);
  147. assert(SL_RESULT_SUCCESS == result);
  148. result = (*recordItf)->SetPositionUpdatePeriod(recordItf, 500);
  149. assert(SL_RESULT_SUCCESS == result);
  150. result = (*recordItf)->SetCallbackEventsMask(recordItf,
  151. SL_RECORDEVENT_HEADATMARKER | SL_RECORDEVENT_HEADATNEWPOS);
  152. assert(SL_RESULT_SUCCESS == result);
  153. result = (*recordItf)->RegisterCallback(recordItf, recCallback, NULL);
  154. assert(SL_RESULT_SUCCESS == result);
  155. /* Initialize the callback and its context for the recording buffer queue */
  156. cntxt.pDataBase = (int8_t*) &pcmData;
  157. cntxt.pData = cntxt.pDataBase;
  158. cntxt.size = sizeof(pcmData);
  159. result = (*recBuffQueueItf)->RegisterCallback(recBuffQueueItf, recBufferQueueCallback, &cntxt);
  160. assert(SL_RESULT_SUCCESS == result);
  161. /* Enqueue buffers to map the region of memory allocated to store the recorded data */
  162. ALOGD("Enqueueing buffer ");
  163. for (int i = 0; i < NB_BUFFERS_IN_QUEUE; i++) {
  164. ALOGD("%d ", i);
  165. result = (*recBuffQueueItf)->Enqueue(recBuffQueueItf, cntxt.pData, BUFFER_SIZE_IN_BYTES);
  166. assert(SL_RESULT_SUCCESS == result);
  167. cntxt.pData += BUFFER_SIZE_IN_BYTES;
  168. }
  169. cntxt.pData = cntxt.pDataBase;
  170. /* Start recording */
  171. result = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_RECORDING);
  172. assert(SL_RESULT_SUCCESS == result);
  173. ALOGD("Starting to record");
  174. }
  175. /*
  176. * Class:     com_example_testopensl_AudioRecordActivity
  177. * Method:    stop
  178. * Signature: ()V
  179. */
  180. JNIEXPORT void JNICALL Java_com_example_testopensl_AudioRecordActivity_stop(JNIEnv *, jobject) {
  181. if (recordItf != NULL) {
  182. SLresult result = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED);
  183. assert(SL_RESULT_SUCCESS == result);
  184. }
  185. }
  186. /*
  187. * Class:     com_example_testopensl_AudioRecordActivity
  188. * Method:    shutdown
  189. * Signature: ()V
  190. */
  191. JNIEXPORT void JNICALL Java_com_example_testopensl_AudioRecordActivity_shutdown(JNIEnv *, jobject) {
  192. //destroy recorder object , and invlidate all associated interfaces
  193. if (recorderObject != NULL) {
  194. (*recorderObject)->Destroy(recorderObject);
  195. recorderObject = NULL;
  196. recordItf = NULL;
  197. recBuffQueueItf = NULL;
  198. configItf = NULL;
  199. }
  200. // destroy engine object, and invalidate all associated interfaces
  201. if (engineObject != NULL) {
  202. (*engineObject)->Destroy(engineObject);
  203. engineObject = NULL;
  204. engineEngine = NULL;
  205. }
  206. //colse the file
  207. if (gFile != NULL) {
  208. fclose(gFile);
  209. gFile == NULL;
  210. }
  211. }

方法说明:
        Java_com_example_testopensl_AudioRecordActivity_createEngine 创建引擎
        Java_com_example_testopensl_AudioRecordActivity_createAudioRecord创建AudioRecorder并开始录音
        Java_com_example_testopensl_AudioRecordActivity_stop 暂停录音
        Java_com_example_testopensl_AudioRecordActivity_shutdown 释放资源
七、创建/jni/Android.mk 编译文件

[plain]view plaincopy
  1. LOCAL_PATH := $(call my-dir)
  2. include $(CLEAR_VARS)
  3. LOCAL_MODULE    := TestAudio
  4. LOCAL_SRC_FILES := com_example_testopensl_AudioRecordActivity.cpp
  5. LOCAL_LDLIBS += -llog -lOpenSLES -landroid
  6. include $(BUILD_SHARED_LIBRARY)

LOCAL_LDLIBS 需要加llog、lOpenSLES、landroid 编译链接库

八、AndroidManifest 配置

录音时记得加上权限

[html]view plaincopy
  1. <uses-permission android:name="android.permission.RECORD_AUDIO" />

编写完Eclipse 结构图如下:

运行之后界面图如下:

代码编写完毕.点击开始就可以录音

在代码中需要注意的是录音的缓冲区大小,缓存区太小会导致录音失败(每个设备的最小缓冲区是不一样的),太大当音频实时传输会延迟比较大。这时候可以使用Java API获取最小的缓冲区,文中是写死的2*8192,在实际项目中建议使用API获取,下面是Java API:

[java]view plaincopy
  1. int sampleRateInHz = 44100;
  2. int channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
  3. int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
  4. int bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat) * 2;

这个可以通过jni访问java类AudioRecord实现,从而封装代码。

Android 音频 OpenSL ES 录音 采集相关推荐

  1. android open es录像,音频采集:Android基于OpenSL ES的实现

    前言 这篇文章简单介绍下移动端Android系统下利用OpenSL ES进行音频采集方法. 按照惯例先上一份源码 AudioRecordLib . OpenSL ES采集的核心实现在于 opensle ...

  2. Android通过OpenSL ES播放音频套路详解

    我的视频课程(基础):<(NDK)FFmpeg打造Android万能音频播放器> 我的视频课程(进阶):<(NDK)FFmpeg打造Android视频播放器> 我的视频课程(编 ...

  3. android4.0 音频框架 opensl openmax,适用于android的OpenSL ES指南-面向Android的OpenSL ES

    本文将详细说明NDK中OpenSL ES™的实现与OpenSL ES 1.0.1参考规范的不同.在使用规范中的示例代码时,可能需要修改它以在Android上工作. 除非另有说明,所有功能都可以在And ...

  4. 适用于Android的OpenSL ES指南-OpenSL ES的Android扩展

    翻译自Android Extensions 针对Android的OpenSL ES扩展了参考OpenSL ES规范,使其与Android兼容,并利用Android平台的强大功能和灵活性. Androi ...

  5. 使用Android高性能音频--OpenSL ES和AAudio

    AAudio的概念介绍: AAudio 是作为 OpenSL ES 库的轻量级原生 Android 替代项而开发. 与 OpenSL ES 相比,AAudio API 不仅较小,而且容易使用. AAu ...

  6. Android 音频开发——AudioRecord录音

    Android 音频--PCM转WAV  AudioRecord类管理Java应用程序的音频资源,以录制音频数据. 这一篇文章主要记录下AudioRecord使用方法,通过AudioRecord录制音 ...

  7. Android高性能音频之OpenSL ES录音流程(一)

    左图:音频硬件加速 右图:音频软件实现 一.栗子static XAEngineItf engineEngine = NULL;//创建引擎对象,获取引擎接口 (*pEngine)->Realiz ...

  8. android同时录四路音频,Android音频捕获(录音)

    Android有一个内置的麦克风,通过它可以捕获音频和存储,或在手机进行播放.有很多方法可以做到这一点,但最常见的方法是通过MediaRecorder类. Android提供MediaRecorder ...

  9. OpenSL ES录音流程(一)

    左图:音频硬件加速 右图:音频软件实现 一.栗子static XAEngineItf engineEngine = NULL;//创建引擎对象,获取引擎接口 (*pEngine)->Realiz ...

最新文章

  1. 6 种不同情况下写的代码
  2. 首次使用Cesium加载3D数据成功
  3. POJ3694 Network
  4. 从补码的来源剖析到为啥补码=原码按位取反+1
  5. spring boot在运行测试类Error creating bean with name ‘serverEndpointExporter‘ defined...问题解决方案
  6. Basic各编码每个字符占用字节个数
  7. springmvc 组合注解
  8. [vue] 你了解什么是函数式组件吗?
  9. 【Java】在eclipse中使用maven进行项目构建 入门篇
  10. python三维图怎么显示_如何在python中绘制多个回归3D图
  11. input隐藏域赋值数组
  12. HTML分页符怎么设置,HTML中的分页符
  13. “飞扬小字典” -- 辅助记忆的小工具
  14. 如何下载windows自带的锁屏壁纸
  15. 雷达图的实现(R语言及Python)
  16. 多元线性回归拟合公式
  17. 找了这么多毕业设计题目,反而不知道选什么了
  18. 【win7安装composer错误】:The quot;https://getcomposer.org/download/1.6.2/composer.phar.sigquot; file cou
  19. 富芮坤蓝牙FR801xH开发环境搭建
  20. 最全各种浏览器网页星号点号密码查看最简方法(技术小白也能看懂使用)

热门文章

  1. vb中SendMessage函数
  2. 换股也是一种解套方法
  3. 反装逼指南:掀起机器学习的神秘面纱
  4. 过程、性能基线、性能模型与目标之间的关系
  5. symbian使用活动对象时返回-2147483647错误值的解决办法
  6. MOSS关于Workflow
  7. 使用for of循环遍历获取的nodeList,配置babel编译,webpack打包之后在iphone5下报错...
  8. 奇幻RPG(角色技能 与 Strategy模式)
  9. 抓取Crash不让崩溃
  10. 常用排序算法(八)桶排序