Android录音转为MP2的实现
利用Android提供的AudioRecord类以及开源编码库twolame,实现了android手机边录音边编码,录音完成直接得到MP2音频文件。由于Android本身不支持MP2的编码,所以要借助NDK将mp2编码库twolame移植到android工程中。MP
2的帧格式参见另一篇博文MP2帧格式介绍。
源码下载地址
http://download.csdn.net/detail/u012741756/9789885
- 开发环境:Windows
- 开发工具:Android Studio 2.2.3和NDK
- 开发包:twolame 0.3.13 twolame下载地址
一 设计思路
利用Android提供的AudioRecord类,采集声音样本PCM数据,MP2规定1152个声音样本构成一帧,所以在新的线程中循环读1152个样本数据,当读到数据后立即进行编码,将1152个PCM数据转为一帧MP2,保存到文件中,录音结束直接得到MP2音频文件。其中编码部分采用开源MP2编码库twolame,利用JNI将twolame整合到Android工程中。如果想存为MP3音频文件,将twolame编码库换成lame编码库,再修改一些地方即可。
二 twolame的Android平台移植,生成.so文件
2.1 新建Android工程
新建android empty project,工程目录切换到Project视图,app右键新建jni文件夹,如下图:
找到你的工程目录,比如我的在F:\AndroidStudioProjects\RecMicToMp2Doc\app\src\main\jni,将twolame 0.3.13文件夹下的libtwolame文件夹拷贝到jni文件夹下,此时你的工程目录应该是这样子的:
2.2 引用c代码,生成.so库
强大的JNI使得我们可以在Android中使用C/C++语言编写代码,JNI提供了一种方式使得在java中能够调用C/C++函数。大致意思就是通过编写符合JNI要求的C/C++代码,配合Android.mk和Application.mk,生成.so文件(动态链接库),例如本文生成了libmp2twolame.so,在java类中通过System.loadLibrary(“mp2twolame”);就能在这个java类中调用.so中包含的c函数了。
- 编写twolame.java:详情参见源码。这个类里面包含了要用到的native方法,native方法的代码在后面的userTwolame.c中编写。
- 生成头文件:在Android Studio的Terminal中,cd到java目录下,本例: cd F:\AndroidStudioProjects\RecMicToMp2Doc\app\src\main\java
再输入命令:javah -jni com.example.administrator.recmictomp2doc.twolame
即可得到com_example_administrator_recmictomp2doc_twolame.h头文件,打开这个头文件,可以看到Java_com_example_administrator_recmictomp2doc_twolame_init等方法名,这些方法名将在userTwolame.c的编写中用到,JNI要求userTwolame.c中的函数名必须与此相同,这是为什么要生成h头文件的原因。 - 编写userTwolame.c
在jni下新建C source file,命名为userTwolame,详情参见源码。 - 编写Android.mk和Application.mk
在jni目录下新建连个File,分别命名为Android.mk和Application.mk,代码如下,给出了注释便于理解。
LOCAL_PATH := $(call my-dir) #给出当前文件的路径
include $(CLEAR_VARS) #把CLEAR_VARS变量所指向的脚本文件包含进来
LIBTWOLAME_DIR := libtwolame
LOCAL_MODULE := mp2twolame #生成的so文件名
#将要编译打包进so中的源代码文件
LOCAL_SRC_FILES := $(LIBTWOLAME_DIR)/ath.c $(LIBTWOLAME_DIR)/availbits.c $(LIBTWOLAME_DIR)/bitbuffer.c $(LIBTWOLAME_DIR)/crc.c $(LIBTWOLAME_DIR)/dab.c $(LIBTWOLAME_DIR)/encode.c $(LIBTWOLAME_DIR)/energy.c $(LIBTWOLAME_DIR)/fft.c $(LIBTWOLAME_DIR)/get_set.c $(LIBTWOLAME_DIR)/mem.c $(LIBTWOLAME_DIR)/psycho_0.c $(LIBTWOLAME_DIR)/psycho_1.c $(LIBTWOLAME_DIR)/psycho_2.c $(LIBTWOLAME_DIR)/psycho_3.c $(LIBTWOLAME_DIR)/psycho_4.c $(LIBTWOLAME_DIR)/psycho_n1.c $(LIBTWOLAME_DIR)/subband.c $(LIBTWOLAME_DIR)/twolame.c $(LIBTWOLAME_DIR)/util.c userTwoLame.c
include $(BUILD_SHARED_LIBRARY)
Application.mk中代码如下,armeabi改为all即生成所有平台的so库:
APP_ABI :=armeabi
此时jni目录下应该包含这些文件:
- 编译生成so,在Android Studio的Terminal中先定位到jni文件夹所在目录,本例输入命令:cd F:\AndroidStudioProjects\RecMicToMp2Doc\app\src\main
然后输入命令 ndk-build,编译成功如下:
然后找到app/src/main下生成的libs文件夹,重命名为jniLibs。
在gradle.properties 文件末尾加入一句代码():android.useDeprecatedNdk=true
因为存在c文件,所以工程编译会报错,所以要在app(build.gradle)的android标签下加入
//remove the default jni source code directory
sourceSets {
main {
jni.srcDirs = []
}
}
- 在AndroidMaitfest.xml中开启麦克风权限和存储权限:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- 至此,工程可以编译成功,由于使用了麦克风,不要在模拟机上运行,直接在真机上运行。
三 总结
本文对代码细节方面没有过多解释,源码中有详细注释,看源码就能理解。本文重点在于学会在Android Studio下使用C/C++代码,对于新手来说,值得参考。