Android录音支持的格式有amr、aac、3gp,但这三种音频格式在跨平台上表现并不好。而mp3格式是跨平台最好的音频格式,所以如果能转成mp3格式的音频文件,那是极好的。
那转成mp3格式又有两种方式:
一、录音完毕再转,再将amr、aac、3gp三种音频文件转成mp3格式的文件。
二、边录边转,使用libmp3lame直接转为mp3格式。
这里先主要介绍第二种,即 使用lame库实现边录边转mp3的方式。这样在录音完毕时,也就转完了,效率比较高。

AudioRecord

录音需要使用到AudioRecord类,这里说一下他的构造方法中的参数的意义
public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes);
构造器参数很多,我们一点一点来看:
- audioSource : 声源,一般使用MediaRecorder.AudioSource.MIC表示来自于麦克风
- sampleRateInHz :官方明确说到只有44100Hz是所有设备都支持的。其他22050、16000和11025只能在某些设备上使用。
- channelConfig : 有立体声(CHANNEL_IN_STEREO)和单声道(CHANNEL_IN_MONO)两种。但只有单声道(CHANNEL_IN_MONO)是所有设备都支持的。
- audioFormat : 有ENCODING_PCM_16BIT和ENCODING_PCM_8BIT两种音频编码格式。同样的,官方声明只有ENCODING_PCM_16BIT是所有设备都支持的。
- bufferSizeInBytes : 录音期间声音数据的写入缓冲区大小(单位是字节)。
这里参数audioSource 、sampleRateInHz 、channelConfig 、audioFormat 都是可以根据需要进行选择,只有bufferSizeInBytes 这个参数,需要通过计算来获得。在介绍计算方法之前,先看一下音频数据的读取与转换。

音频数据的读取与转换

录音过程中需要不断的读取数据。既然是不断,那么我们当然需要循环读取,意味着我们需要一个线程来单独读取录音,避免阻塞主线程。如果不及时读取,数据超过缓冲区大小,会造成这段录音数据的丢失。
上面提到过,我们想要实现的是边录边转。那么问题来了,如果我们读取完数据后接着将数据传给Lame进行MP3编码,Lame的编码时间是不确定的,是不是有可能造成数据的丢失呢?答案当然是有可能,所以我们不能巧合编程。
我们需要另外一个线程,即数据编码线程来专门进行MP3编码,而当前的录音读取线程只负责读取录音PCM数据。有了两条线程,我们还需要确认一点,什么时候编码线程开始处理数据?

编码线程处理数据的时机

传统的方法是当线程中有数据的时候开始处理,这就需要在这个线程里面不断循环查看是否有数据需要处理,有数据就开始处理,没有数据我们可以暂时休息几毫秒(当然一直不sleep也可以,但造成的系统消耗太多)。这种方式显然也是低效的,因为无论我们让线程休息多久都可以判定为不合理。因为我们并不知道准确的时间。
那么还有别的方法么?显然录音这个类是知道什么时候该处理数据,什么时候可以休息。
Don’t call me , I will call you.
是的,我们应该去看看有没有监听器,让录音来通知编码线程开始工作。
AudioRecord为我们提供了这样的方法:

public int setPositionNotificationPeriod (int periodInFrames)Added in API level 3
Sets the period at which the listener is called, if set with setRecordPositionUpdateListener(OnRecordPositionUpdateListener) or setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler). It is possible for notifications to be lost if the period is too small.

设置通知周期。 以帧为单位。
到这里,我们可以回来来解释bufferSizeInBytes大小的传入了。

缓冲区的大小

其实AudioRecord类提供了一个方便的方法getMinBufferSize来获取缓冲区的大小。
public static int getMinBufferSize (int sampleRateInHz, int channelConfig, int audioFormat)
这里的3个参数,其实我们都可以从构造器的参数里看到,因此传入并没有什么问题。
但关键在如上面我们设置了周期单位,如果获得的缓冲区大小不是周期单位的整数倍呢?
不是整数倍当然会如我们猜想的一样造成数据丢失,因此我们还需要一些数据的纠正来保证缓冲区大小是整数倍。

mBufferSize = AudioRecord.getMinBufferSize(DEFAULT_SAMPLING_RATE,DEFAULT_CHANNEL_CONFIG, DEFAULT_AUDIO_FORMAT.getAudioFormat());int bytesPerFrame = DEFAULT_AUDIO_FORMAT.getBytesPerFrame();
/* Get number of samples. Calculate the buffer size * (round up to the factor of given frame size) * 使能被整除,方便下面的周期性通知* */
int frameSize = mBufferSize / bytesPerFrame;
if (frameSize % FRAME_COUNT != 0) {frameSize += (FRAME_COUNT - frameSize % FRAME_COUNT);mBufferSize = frameSize * bytesPerFrame;
}

讲完了数据的获取线程和编码线程,我们来仔细看看帮助我们实现MP3编码的功臣:Lame

Lame的获取与编译

Lame在线下载地址
步骤
1、解压libmp3lame 到jni目录.
2、拷贝 lame.h (include目录下)。
3、创建Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := mp3lame
LOCAL_SRC_FILES := bitstream.c fft.c id3tag.c mpglib_interface.c presets.c  quantize.c   reservoir.c tables.c  util.c  VbrTag.c encoder.c  gain_analysis.c lame.c  newmdct.c   psymodel.c quantize_pvt.c set_get.c  takehiro.c vbrquantize.c version.c
include $(BUILD_SHARED_LIBRARY)

4、删除非.c/.h文件:GNU autotools, Makefile.am Makefile.in libmp3lame_vc8.vcproj logoe.ico depcomp, folders i386 等无用文件。
5、编辑 jni/utils.h。把extern ieee754_float32_t fast_log2(ieee754_float32_t x);替换为extern float fast_log2(float x);。如果忘了替换,编译时会报出以下错误:

[armeabi] Compile thumb  : mp3lame <= bitstream.c
In file included from jni/bitstream.c:36:0:
jni/util.h:574:5: error: unknown type name 'ieee754_float32_t'
jni/util.h:574:40: error: unknown type name 'ieee754_float32_t'
make.exe: *** [obj/local/armeabi/objs/mp3lame/bitstream.o] Error 1

Lame需要对外提供的方法

init 初始化
inSamplerate : 输入采样频率 Hz
inChannel : 输入声道数
outSamplerate : 输出采样频率 Hz
outBitrate : Encoded bit rate. KHz
quality : MP3音频质量。0~9。 其中0是最好,非常慢,9是最差。
推荐:
2 :near-best quality, not too slow
5 :good quality, fast
7 :ok quality, really fast

//=======================AudioRecord Default Settings=======================private static final int DEFAULT_AUDIO_SOURCE = MediaRecorder.AudioSource.MIC;/*** 以下三项为默认配置参数。Google Android文档明确表明只有以下3个参数是可以在所有设备上保证支持的。*/private static final int DEFAULT_SAMPLING_RATE = 44100;//模拟器仅支持从麦克风输入8kHz采样率private static final int DEFAULT_CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO;//立体声的选择private static final int STEREO_CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_STEREO;/*** 下面是对此的封装* private static final int DEFAULT_AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;*/private static final PCMFormat DEFAULT_AUDIO_FORMAT = PCMFormat.PCM_16BIT;//======================Lame Default Settings=====================private static final int DEFAULT_LAME_MP3_QUALITY = 7;/*** 与DEFAULT_CHANNEL_CONFIG相关,因为是mono单声,所以是1*///private static final int DEFAULT_LAME_IN_CHANNEL = 1;/*** STEREO_CHANNEL_CONFIG左声道和右声道,实现立体声的选择*/private static final int STEREO_LAME_IN_CHANNEL = 2;/***  Encoded bit rate. MP3 file will be encoded with bit rate 32kbps */ private static final int DEFAULT_LAME_MP3_BIT_RATE = 32;LameUtil.init(DEFAULT_SAMPLING_RATE, STEREO_LAME_IN_CHANNEL, DEFAULT_SAMPLING_RATE, DEFAULT_LAME_MP3_BIT_RATE, DEFAULT_LAME_MP3_QUALITY);

encode
bufferLeft : 左声道数据
bufferRight:右声道数据
samples :每个声道输入数据大小
mp3buf :用于接收转换后的数据。7200 + (1.25 * buffer_l.length)
这里需要解释一下:

Task task = mTasks.remove(0);
short[] buffer = task.getData();
int readSize = task.getReadSize();
int encodedSize = LameUtil.encode(buffer, buffer, readSize, mMp3Buffer);

左右声道 :当前声道选的是单声道,因此两边传入一样的buffer。
输入数据大小 :录音线程读取到buffer中的数据不一定是占满的,所以read方法会返回当前大小size,即前size个数据是有效的音频数据,后面的数据是以前留下的废数据。 这个size同样需要传入到Lame编码器中用于编码。
mp3的buffer:官方规定了计算公式:7200 + (1.25 * buffer_l.length)。(可以在lame.h文件中看到)
flush
将MP3结尾信息写入buffer中。
传入参数:mp3buf至少7200字节。这里还是用以前定义的mp3buf来传入,避免创建过多的数组。
close
关闭释放Lame
OK,到这里,核心的转换代码就完成了,我们再来点锦上添花的东西。
音量
一般我们在做录音的时候,都会有一个需求,根据音量的大小显示一个动画,让录音显得更生动一些。
当然,我在这个库里也提供了。
那么怎么来计算音量呢?
我参考了三星的音量计算。
总结如下:

/**
* 此计算方法来自samsung开发范例
*
* @param buffer
* @param readSize
*/
private void calculateRealVolume(short[] buffer, int readSize) {int sum = 0;for (int i = 0; i < readSize; i++) {  sum += buffer[i] * buffer[i]; } if (readSize > 0) {double amplitude = sum / readSize;mVolume = (int) Math.sqrt(amplitude);}
};

现有的一个项目:AndroidMP3Recorder
原文:http://www.cnblogs.com/ct2011/p/4080193.html

Android变录音边转换为mp3格式的声音---libmp3lame库的使用相关推荐

  1. 如何将录音m4a转换为mp3格式?

    如何将录音m4a转换为mp3格式?前段时间由于工作原因,需要上传录音文件到一个网站上,可是这个录音文件怎么也上传不上去,查看原因后才发现原来网站只支持mp4的音频文件,而我是用苹果手机录音的,录音文件 ...

  2. java 将微信录音amr转换为mp3格式

    2020年更新,这是4前写的了文章了,今天找东西,登录账号发现一堆几年前的评论,真抱歉,我没回复你们 如果有需要,尽量参考评论中的解决办法吧. https://blog.csdn.net/dadiya ...

  3. lame,把ios录音转换为mp3格式

    在ios设备中进行录音,录音文件的格式为caf.但这种格式在很多设备中没法播放.为了适应终端的播放功能,特将caf转换为mp3格式文件来使用. 在录制caf文件时,需要使用双通道,否则在转换为MP3格 ...

  4. amr格式转换为MP3格式

    最近做html5移动开发,在android端录音生成的amr格式在ios端无法播放,ios无法不支持amr.所以需在服务端对amr格式文件进行转换生成MP3格式文件进行播放. 通过网上查的资料,使用j ...

  5. 电脑录制的音频文件如何转换为MP3格式

    很多人认为,电脑录制的文件是不能转换格式,其实并不是这样的,电脑录制的音频文件转换为MP3格式大家是可以借助工具完成,如今市面上出现了很多的音频转换工具,它可以把音频的格式进行不同的变化但是大家却不知 ...

  6. 怎么将flac格式的音乐转换为MP3格式

    格式转换,大家多少也有过接触,音频我们在下载歌曲的时候经常会遇到这种问题,所以如果还有不了解的小伙伴们不妨看看小编是如何介绍音频格式转换的文章吧,没接触之前,肯定会有许多人觉得转换格式是一件有难度的事 ...

  7. 在线qmc0转换mp3工具_如何将M4A格式的音频转换为MP3格式?只需一步搞定

    随着网络技术的发达,会有很多人喜欢在网上下载东西,特别是很喜欢在网上下载音乐,但是下载音乐之后发现是M4A格式?这样用起来很不方便,都喜欢MP3格式的,那么如何将M4A格式的音频转换为MP3格式?今天 ...

  8. linux java amr转mp3_本工具用于将微信语音 amr 格式转换为 mp3 格式以便在 html5 的 audio 标签中进行播放...

    音频转码工具 本工具主要用于将微信语音 amr 格式转换为 mp3 格式以便在 html5 的 audio 标签中进行播放. 支持 Linux/Windows/Mac 平台 因为是基于 JAVE 项目 ...

  9. amr转换成mp3 java_java将amr文件转换为MP3格式(windowslinux均可使用,亲测)

    使用场景: 业务中需要使用微信语音接口,由于微信上传语音只保存3天,所以需要将语音文件下载到服务器. 但是amr格式文件,前端无法识别,需要将其转换为mp3格式. 装换方法如下: 1.需安装ffmpe ...

最新文章

  1. TensorFlow中Session.run和Tensor.eval的区别
  2. [Joomla] 利用joomla内置的表单验证功能
  3. golang执行linux命令
  4. 关于SAP Commerce Cloud OCC API url里不包含user信息的问题
  5. 今天听说了一个压缩解压整型的方式-group-varint
  6. 阿里云张献涛:公共云正不断向外延伸,一云多态是未来趋势
  7. UI2CODE再进化!结合Redux的框架升级!
  8. 在互联网和信息快速整合的时代
  9. HDU1293+Java+大整数
  10. 吴恩达深度学习笔记 course2 week2 优化算法
  11. Redhat Linux系列(Fedora,CentOS,Redhat enterprise)中一些常用软件
  12. 泛型类,泛型接口,泛型方法,底层擦除机制,可变参数,限类型通配符,反编译xjad
  13. java实现微信订阅消息(服务通知)
  14. chrome打不开网页 转圈圈
  15. mysql库函数说明_MySQL 数据库函数库
  16. 弥散阴影html,超赞!一份简单易上手的青春弥散阴影修炼手册
  17. thinkadmin打印sql语句调试sql
  18. win10常用软件汇总
  19. 又一大佬加盟OpenAI!他还是姚班学霸陈立杰的导师
  20. 华为会议终端TE10 SIP配置范例

热门文章

  1. java 庖丁解牛_庖丁解牛 --JAVA 栈的实现
  2. 卸载Resharper
  3. [转]Google Dremel 原理 - 如何能3秒分析1PB
  4. GPU显存占满利用率GPU-util为0
  5. 【QA】集成高德地图SDK闪退问题
  6. Elasticsearch基础11——索引之别名使用
  7. html设置背景颜色无效,设置背景颜色无效果(第二种实现方式 背景颜色设置不起作用)...
  8. 解决ubuntu+windows双系统安装时无法修改SATA Mode为AHCI模式的问题(安装类型页是空白)
  9. Android 酒店客房管理简单小程序
  10. 计算机常用英语对话,英语口语对话之买电脑时常用基本口语