录音器 AudioRecorder
实现录音器有两种方式可以选择:
1.AudioRecord(基于字节流录音)
优点:可以实现语音的实时处理,进行边录边播,对音频的实时处理。
缺点:输出的是PCM的语音数据,如果保存成音频文件是不能被播放器播放的。要用到AudioTrack这个去进行处理。
2.MediaRecorder(基于文件录音)
已集成了录音,编码,压缩等,支持少量的音频格式文件。
优点:封装度很高,操作简单
缺点:无法实现实时处理音频,输出的音频格式少。
权限:
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
AudioRecorder录音工具类代码如下:
package com.example.m_evolution.Utils; import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Environment;
import android.os.Handler;
import android.util.Log; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date; public class AudioRecoderUtils { //文件路径
private String filePath;
//文件夹路径
private String FolderPath; //录音的线程
private Thread mThread; // private MediaRecorder mMediaRecorder;
private AudioRecord audioRecord;
private boolean isRecording;
private int channelConfiguration = AudioFormat.CHANNEL_IN_MONO;
private int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
private int sampleRate = 44100;
private int bufferSizeInBytes; private final String TAG = "fan";
public static final int MAX_LENGTH = 1000 * 60 * 10;// 最大录音时长1000*60*10; private OnAudioStatusUpdateListener audioStatusUpdateListener; /**
* 文件存储默认sdcard/record
*/
public AudioRecoderUtils(){ //默认保存路径为/sdcard/record/下
FolderPath = Environment.getExternalStorageDirectory()+"/record/";
bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRate,
channelConfiguration, audioEncoding); // need to be larger than size of a frame audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
sampleRate, channelConfiguration, audioEncoding,
bufferSizeInBytes); //麦克风
} public void startRecord(){
mThread = new Thread(new Runnable() {
@Override
public void run() {
/* 获取开始时间* */
startTime = System.currentTimeMillis();
//设置录制指标
isRecording = true;
//自动更新界面
updateMicStatus();
//设置存储路径
filePath = FolderPath+getCurrentDate("yyyyMMddHHmmss") + ".wav";
File recordingFile = new File(filePath);
OutputStream out = null;
ByteArrayOutputStream baos = null;
try {
baos = new ByteArrayOutputStream();
audioRecord.startRecording();
byte[] buffer = new byte[bufferSizeInBytes];
int bufferReadResult = 0;
while (isRecording) {
bufferReadResult = audioRecord.read(buffer, 0,
bufferSizeInBytes);
if(bufferReadResult>0){
baos.write(buffer, 0, bufferReadResult);
}
}
Log.i(TAG, "stop recording,file=" + recordingFile.getAbsolutePath());
buffer = baos.toByteArray();
Log.i(TAG, "audio byte len="+buffer.length);
out = new FileOutputStream(recordingFile);
out.write(getWavHeader(buffer.length));
out.write(buffer);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(baos!=null){
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
});
mThread.start();
} public void stopRecord(){
stopRecording();
audioStatusUpdateListener.onStop(filePath);
filePath = "";
} public byte[] getWavHeader(long totalAudioLen){
int mChannels = 1;
long totalDataLen = totalAudioLen + 36;
long longSampleRate = sampleRate;
long byteRate = sampleRate * 2 * mChannels; byte[] header = new byte[44];
header[0] = 'R'; // RIFF/WAVE header
header[1] = 'I';
header[2] = 'F';
header[3] = 'F';
header[4] = (byte) (totalDataLen & 0xff);
header[5] = (byte) ((totalDataLen >> 8) & 0xff);
header[6] = (byte) ((totalDataLen >> 16) & 0xff);
header[7] = (byte) ((totalDataLen >> 24) & 0xff);
header[8] = 'W';
header[9] = 'A';
header[10] = 'V';
header[11] = 'E';
header[12] = 'f'; // 'fmt ' chunk
header[13] = 'm';
header[14] = 't';
header[15] = ' ';
header[16] = 16; // 4 bytes: size of 'fmt ' chunk
header[17] = 0;
header[18] = 0;
header[19] = 0;
header[20] = 1; // format = 1
header[21] = 0;
header[22] = (byte) mChannels;
header[23] = 0;
header[24] = (byte) (longSampleRate & 0xff);
header[25] = (byte) ((longSampleRate >> 8) & 0xff);
header[26] = (byte) ((longSampleRate >> 16) & 0xff);
header[27] = (byte) ((longSampleRate >> 24) & 0xff);
header[28] = (byte) (byteRate & 0xff);
header[29] = (byte) ((byteRate >> 8) & 0xff);
header[30] = (byte) ((byteRate >> 16) & 0xff);
header[31] = (byte) ((byteRate >> 24) & 0xff);
header[32] = (byte) (2 * mChannels); // block align
header[33] = 0;
header[34] = 16; // bits per sample
header[35] = 0;
header[36] = 'd';
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
header[40] = (byte) (totalAudioLen & 0xff);
header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
header[43] = (byte) ((totalAudioLen >> 24) & 0xff); return header;
} private long startTime;
private long endTime; public static String getCurrentDate(String pattern) {
SimpleDateFormat formatter = new SimpleDateFormat(pattern);
Date curDate = new Date(System.currentTimeMillis());// 获取当前时间
String timestamp = formatter.format(curDate);
return timestamp;
} public void stopRecording() {
try {
isRecording = false;
audioRecord.stop();
audioRecord.release();
audioRecord = null;
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
sampleRate, channelConfiguration, audioEncoding,
bufferSizeInBytes); //麦克风
} catch (Exception e) {
e.printStackTrace();
}
} private final Handler mHandler = new Handler();
private Runnable mUpdateMicStatusTimer = new Runnable() {
public void run() {
updateMicStatus();
}
}; private int SPACE = 100;//显示时间的间隔时间 public void setOnAudioStatusUpdateListener(OnAudioStatusUpdateListener audioStatusUpdateListener) {
this.audioStatusUpdateListener = audioStatusUpdateListener;
} /**
* 更新麦克状态
*/
private void updateMicStatus() { if (isRecording) {
if(null != audioStatusUpdateListener) {
audioStatusUpdateListener.onUpdate(System.currentTimeMillis()-startTime);
}
mHandler.postDelayed(mUpdateMicStatusTimer, SPACE);
}
} public interface OnAudioStatusUpdateListener {
/**
* 录音中...
* @param db 当前声音分贝
* @param time 录音时长
*/
public void onUpdate(long time); /**
* 停止录音
* @param filePath 保存路径
*/
public void onStop(String filePath);
} }
录音器 AudioRecorder的更多相关文章
- Android 录音器
Android自带的mediarecoder录音器不含pause暂停功能,解决方法:录制多个音频片段,最后合成一个文件. 参照 : http://blog.csdn.net/a601445984/ar ...
- 用swift实现自动录音器
基本介绍 自动录音与一般录音区别在:不用像微信那样按下录音-松手结束,而是根据说话声音的大小自动判断该录音和该停止的点,然后可以做到结束录音之后马上播放出来.类似于达到会说话的汤姆猫那样的效果. 在自 ...
- PJMEDIA之录音器的使用(capture sound to avi file)
为了熟悉pjmedia的相关函数以及使用方法,这里练习了官网上的一个录音器的例子. 核心函数: pj_status_t pjmedia_wav_writer_port_create ( pj_pool ...
- IOS 实现 AAC格式 录音 录音后自动播放
废话不说了 不知道aac可以百度一下 下面直接上代码,一个h文件 一个m文件 搞定! #import <AVFoundation/AVFoundation.h> #import <U ...
- Android MP3录音实现
给APP做语音功能,必须考虑到IOS和Android平台的通用性.wav录音质量高,文件太大,AAC和AMR格式在IOS平台却不支持,所以采用libmp3lame把AudioRecord音频流直接转换 ...
- ios开发——实用技术篇Swift篇&录音
录音 // MARK: - 录音 /*----- 录音 ------*/ var recorder:AVAudioRecorder? //录音器 var player:AVAudioPlayer? / ...
- 【Android】20.4 录音
分类:C#.Android.VS2015: 创建日期:2016-03-13 一.简介 利用Android提供的MediaRecorder类可直接录制音频. 1.权限要求 录制音频和视频需要下面的权限: ...
- IOS中录音后再播放声音太小问题解决
1.AVAudioSessionCategory说明 1.1 AVAudioSessionCategoryAmbient 或 kAudioSessionCategory_AmbientSound 用于 ...
- JavaScript 实现页面中录音功能
页面中实现录音需要使用浏览器提供的 MediaRecorder API,所以前提是需要浏览器支持 MediaStream Recording 相关的功能. 以下代码默认工作在 Chrome 环境中. ...
随机推荐
- enum使用方法
DK1.5引入了新的类型——枚举.在 Java 中它虽然算个“小”功能,却给我的开发带来了“大”方便. 用法一:常量 在JDK1.5 之前,我们定义常量都是: publicstaticfianl... ...
- golang 操作redis 错误:failed redigo: unexpected type for String, got type int64
报错的代码: isExist,err := redis.String(conn.Do("EXISTS", key)) 这个操作返回的应该是bool类型,所有改成 isExist,e ...
- day39-异常处理
一.程序中难免出现错误,而错误分成两种 1.语法错误(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正) #语法错误示范一 if #语法错误示范二 def test: pass ...
- 26个Jquery使用小技巧(转)
下面列出了一些Jquery使用技巧.比如有禁止右键点击.隐藏搜索文本框文字.在新窗口中打开链接.检测浏览器.预加载图片.页面样式切换.所有列等 高.动态控制页面字体大小.获得鼠标指针的X值Y值.验证元 ...
- Django下的templates 和 static静态文件
如果Django顶层目录中没有templates的话,就自己新建一个Directory ,这个文件是存放html文件的 1)如果在views里面用render(request,"" ...
- google event
一目了然,也不用多说了,随便记录下,内部实现基于观察者模式 TestEvent public class TestEvent { private final int message; public T ...
- linux查询硬件信息
硬件信息查询 sudo dmidecode -t baseboard
- java.util.Arrays$ArrayList addAll报错
执行下面代码时报错: List<String> centerList = WebConstants.SUPPORT_BIG_CENTERS_LIST; // WebConstants.SU ...
- ReactiveX 学习笔记(13)基础类型
Key Types and Life Management 本文主题是 Rx 中的基础类型 Subject 类及其生命周期的管理. 公共代码 RxNET private static void Wri ...
- ReactiveX 学习笔记(3)转换数据流
Transforming Observables 本文的主题为转换 Observable 的操作符. 这里的 Observable 实质上是可观察的数据流. RxJava操作符(二)Transform ...