Android MediaRecorder实现暂停断点录音功能
基本原理如下:MediaRecorder通过MIC录音,系统没有自带的pause功能,每次暂停录音,都会结束本次的录音。现在本人的设计思路是:MediaRecorder录音暂停时,保存这段所录下的音频A,继续录音后,再次暂停,保留录音音频B;以此类推直到最终的录音结束时,依次读取之前保存的A、B……的录音文件,并将其合并在一起。涉及的技术:文件的保存读取、音频的合并等
音频的合并:设置MediaRecorder的音频输出格式mMediaRecorder01.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
mMediaRecorder01 .setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
输出的是amr格式。amr的音频文件的文件头,相对来说是固定的6个字节的固定字符,A.amr文件和B.amr文件的合并,只需将B以字节流读取,去
掉前6个字节,和A的字节流合并后保存,就实现了音频合并,不涉及复杂的音频编码问题。(MediaRecorder的音频输出格式比较多,有jpgg、MP3等之类的格式,合成的原理大同小异,只需要注意他们的音频文件头的格式就可以了。)

public class EX07 extends Activity {
private ImageButton myButton1;
private ImageButton myButton2;
private ImageButton myButton3;
private ImageButton myButton4;
private Button myButton;
private ListView myListView1;
private String strTempFile = "YYT_";
private File myRecAudioFile;
/**录音保存路径**/
private File myRecAudioDir;
private File myPlayFile;
private MediaRecorder mMediaRecorder01;
private int mMinute;
private boolean xx=true;
/**存放音频文件列表**/
private ArrayList<String> recordFiles;
private ArrayAdapter<String> adapter;
private TextView myTextView1;
/**文件存在**/
private boolean sdcardExit;
/**是否停止录音**/
private boolean isStopRecord;
/**按钮背景图片的标志位**/
private boolean sigle = false;
private String length1 = null;
private final String SUFFIX=".amr";
/**暂停按钮**/
Button buttonpause;
/**记录需要合成的几段amr语音文件**/
private ArrayList<String> list;
int second=;
int minute=;
/**计时器**/
Timer timer;
/**是否暂停标志位**/
private boolean isPause;
/**在暂停状态中**/
private boolean inThePause;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//暂停标志位 为false
isPause=false;
//暂停状态标志位
inThePause=false;
//初始化list
list=new ArrayList<String>();
//四个按钮
myButton1 = (ImageButton) findViewById(R.id.ImageButton01);
myButton2 = (ImageButton) findViewById(R.id.ImageButton02);
myButton3 = (ImageButton) findViewById(R.id.ImageButton03);
myButton4 = (ImageButton) findViewById(R.id.ImageButton04);
myButton = (Button) findViewById(R.id.myButton);
buttonpause=(Button)findViewById(R.id.mypuase);
myListView1 = (ListView) findViewById(R.id.ListView01);
myTextView1 = (TextView) findViewById(R.id.TextView01);
myButton2.setEnabled(false);
myButton3.setEnabled(false);
myButton4.setEnabled(false);
myPlayFile=null;
// 判断sd Card是否插入
sdcardExit = Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED);
// 取得sd card路径作为录音文件的位置
if (sdcardExit){
String pathStr = Environment.getExternalStorageDirectory().getPath()+"/YYT";
myRecAudioDir= new File(pathStr);
if(!myRecAudioDir.exists()){
myRecAudioDir.mkdirs();
Log.v("录音", "创建录音文件!" + myRecAudioDir.exists());
}
// Environment.getExternalStorageDirectory().getPath() + "/" + PREFIX + "/";
}
// 取得sd card 目录里的.arm文件
getRecordFiles();
adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, recordFiles);
// 将ArrayAdater添加ListView对象中
myListView1.setAdapter(adapter);
// 录音
myButton1.setOnClickListener(new ImageButton.OnClickListener() {
@Override
public void onClick(View v) {
second=;
minute=;
list.clear();
// Calendar c=Calendar.getInstance();
// int mMinute1=c.get(Calendar.MINUTE);
sigle = true;
// TODO Auto-generated method stub
start();
if (sigle = false) {
myButton1.setBackgroundResource(R.drawable.record_hover1);
} else {
myButton1.setBackgroundResource(R.drawable.record_dis1);
myButton2.setBackgroundResource(R.drawable.stop_hover2);
myButton3.setBackgroundResource(R.drawable.play_hover1);
myButton4.setBackgroundResource(R.drawable.delete_hover);
}
}
});
// 停止
myButton2.setOnClickListener(new ImageButton.OnClickListener() {
@Override
public void onClick(View v) {
xx=false;
sigle = true;
timer.cancel();
// TODO Auto-generated method stub
//这里写暂停处理的 文件!加上list里面 语音合成起来
if(isPause){
//在暂停状态按下结束键,处理list就可以了
if(inThePause){
getInputCollection(list, false);
}
//在正在录音时,处理list里面的和正在录音的语音
else{
list.add(myRecAudioFile.getPath());
recodeStop();
getInputCollection(list, true);
}
//还原标志位
isPause=false;
inThePause=false;
buttonpause.setText("暂停录音");
// adapter.add(myRecAudioFile.getName());
}
//若录音没有经过任何暂停
else{
if (myRecAudioFile != null) {
// 停止录音
mMediaRecorder01.stop();
mMediaRecorder01.release();
mMediaRecorder01 = null;
// 将录音频文件给Adapter
adapter.add(myRecAudioFile.getName());
DecimalFormat df = new DecimalFormat("#.000");
if (myRecAudioFile.length() <= *) {
//length1 = (myRecAudioFile.length() / 1024.0)+"";
length1=df.format(myRecAudioFile.length() / 1024.0)+"K";
} else {
//length1 = (myRecAudioFile.length() / 1024.0 / 1024)+"";
//DecimalFormat df = new DecimalFormat("#.000");
length1=df.format(myRecAudioFile.length() / 1024.0 / )+"M";
}
System.out.println(length1);
myTextView1.setText("停 止" + myRecAudioFile.getName()
+ "文件大小为:" + length1);
myButton2.setEnabled(false);
}
}
if (sigle = false) {
myButton2.setBackgroundResource(R.drawable.stop_hover2);
} else {
myButton1.setBackgroundResource(R.drawable.record_hover1);
myButton2.setBackgroundResource(R.drawable.stop1);
myButton3.setBackgroundResource(R.drawable.play_hover1);
myButton4.setBackgroundResource(R.drawable.delete_hover);
}
//停止录音了
isStopRecord = true;
}
});
// 播放
myButton3.setOnClickListener(new ImageButton.OnClickListener() {
@Override
public void onClick(View v) {
sigle = true;
// TODO Auto-generated method stub
if (myPlayFile != null && myPlayFile.exists()) {
// 打开播放程序
openFile(myPlayFile);
} else {
Toast.makeText(EX07.this, "你选的是一个空文件", Toast.LENGTH_LONG)
.show();
Log.d("没有选择文件","没有选择文件");
}
if (sigle = false) {
myButton3.setBackgroundResource(R.drawable.play_hover1);
} else {
myButton1.setBackgroundResource(R.drawable.record_hover1);
myButton2.setBackgroundResource(R.drawable.stop_hover2);
myButton3.setBackgroundResource(R.drawable.play1);
myButton4.setBackgroundResource(R.drawable.delete_hover);
}
}
});
// 删除
myButton4.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
sigle = true;
// TODO Auto-generated method stub
if (myPlayFile != null) {
// 先将Adapter删除文件名
adapter.remove(myPlayFile.getName());
// 删除文件
if (myPlayFile.exists())
myPlayFile.delete();
myTextView1.setText("完成删除!");
}
if (sigle = false) {
myButton4.setBackgroundResource(R.drawable.delete_hover);
} else {
myButton1.setBackgroundResource(R.drawable.record_hover1);
myButton2.setBackgroundResource(R.drawable.stop_hover2);
myButton3.setBackgroundResource(R.drawable.play_hover1);
myButton4.setBackgroundResource(R.drawable.delete_dis);
}
}
});
/**
* 暂停按钮,记录之前保存的语音文件
*/
buttonpause.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
isPause=true;
//已经暂停过了,再次点击按钮 开始录音,录音状态在录音中
if(inThePause){
buttonpause.setText("暂停录音");
start();
inThePause=false;
}
//正在录音,点击暂停,现在录音状态为暂停
else{
//当前正在录音的文件名,全程
list.add(myRecAudioFile.getPath());
inThePause=true;
recodeStop();
//start();
buttonpause.setText("继续录音");
//计时停止
timer.cancel();
}
}
});
myListView1
.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg, View arg1,
int arg2, long arg3) {
// TODO Auto-generated method stub
// 当有单点击文件名时将删除按钮及播放按钮Enable
myButton3.setEnabled(true);
myButton4.setEnabled(true);
myPlayFile = new File(myRecAudioDir.getAbsolutePath()
+ File.separator
+ ((TextView) arg1).getText().toString());
DecimalFormat df = new DecimalFormat("#.000");
if (myPlayFile.length() <= *) {
length1=df.format(myPlayFile.length() / 1024.0)+"K";
} else {
length1=df.format(myPlayFile.length() / 1024.0/)+"M";
}
myTextView1.setText("你选的是"
+ ((TextView) arg1).getText().toString()
+ "文件大小为:" + length1);
Toast.makeText(EX07.this,"你选的是" + (((TextView) arg1).getText())+ "文件大小为:" + length1,
Toast.LENGTH_LONG).show();
}
});
myButton.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
showSize show = new showSize();
String text = show.showsize();
Toast.makeText(EX07.this, text, Toast.LENGTH_LONG).show();
}
});
}
protected void recodeStop() {
if (mMediaRecorder01 != null && !isStopRecord) {
// 停止录音
mMediaRecorder01.stop();
mMediaRecorder01.release();
mMediaRecorder01 = null;
}
timer.cancel();
}
/**
* activity的生命周期,stop时关闭录音资源
*/
@Override
protected void onStop() {
// TODO Auto-generated method stub
if (mMediaRecorder01 != null && !isStopRecord) {
// 停止录音
mMediaRecorder01.stop();
mMediaRecorder01.release();
mMediaRecorder01 = null;
}
super.onStop();
}
/**
* 获取目录下的所有音频文件
*/
private void getRecordFiles() {
// TODO Auto-generated method stub
recordFiles = new ArrayList<String>();
if (sdcardExit) {
File files[] = myRecAudioDir.listFiles();
if (files != null) {
for (int i = ; i < files.length; i++) {
if (files[i].getName().indexOf(".") >= ) { // 只取.amr 文件
String fileS = files[i].getName().substring(
files[i].getName().indexOf("."));
if (fileS.toLowerCase().equals(".mp3")
|| fileS.toLowerCase().equals(".amr")
|| fileS.toLowerCase().equals(".mp4"))
recordFiles.add(files[i].getName());
}
}
}
}
}
// 打开录音播放程序
private void openFile(File f) {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(android.content.Intent.ACTION_VIEW);
String type = getMIMEType(f);
intent.setDataAndType(Uri.fromFile(f), type);
startActivity(intent);
// Uri uri=Uri.fromFile(f);
// MediaPlayer mediaPlayer=MediaPlayer.create(this, uri);
// try {
// mediaPlayer.prepare();
// } catch (IllegalStateException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// mediaPlayer.start();
}
private String getMIMEType(File f) {
String end = f.getName().substring(f.getName().lastIndexOf(".") + ,
f.getName().length()).toLowerCase();
String type = "";
if (end.equals("mp3") || end.equals("aac") || end.equals("amr")
|| end.equals("mpeg") || end.equals("mp4")) {
type = "audio";
} else if (end.equals("jpg") || end.equals("gif") || end.equals("png")
|| end.equals("jpeg")) {
type = "image";
} else {
type = "*";
}
type += "/";
return type;
}
private void start(){
TimerTask timerTask=new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
second++;
if(second>=){
second=;
minute++;
}
handler.sendEmptyMessage();
}
};
timer=new Timer();
timer.schedule(timerTask, ,);
try {
if (!sdcardExit) {
Toast.makeText(EX07.this, "请插入SD card",
Toast.LENGTH_LONG).show();
return;
}
String mMinute1=getTime();
Toast.makeText(EX07.this, "当前时间是:"+mMinute1,Toast.LENGTH_LONG).show();
// 创建音频文件
// myRecAudioFile = File.createTempFile(mMinute1, ".amr",
// myRecAudioDir);
myRecAudioFile=new File(myRecAudioDir,mMinute1+SUFFIX);
mMediaRecorder01 = new MediaRecorder();
// 设置录音为麦克风
mMediaRecorder01
.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder01
.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
mMediaRecorder01
.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
//录音文件保存这里
mMediaRecorder01.setOutputFile(myRecAudioFile
.getAbsolutePath());
mMediaRecorder01.prepare();
mMediaRecorder01.start();
// mMediaRecorder01.getMaxAmplitude();
// mMediaRecorder01.getAudioSourceMax();
mMediaRecorder01.setOnInfoListener(new OnInfoListener() {
@Override
public void onInfo(MediaRecorder mr, int what, int extra) {
// TODO Auto-generated method stub
int a=mr.getMaxAmplitude();
Toast.makeText(EX07.this, a, ).show();
}
});
myTextView1.setText("录音中......");
myButton2.setEnabled(true);
myButton3.setEnabled(false);
myButton4.setEnabled(false);
isStopRecord = false;
} catch (IOException e) {
e.printStackTrace();
}
}
private String getTime(){
SimpleDateFormat formatter = new SimpleDateFormat ("yyyy年MM月dd日HH:mm:ss");
Date curDate=new Date(System.currentTimeMillis());//获取当前时间
String time = formatter.format(curDate);
System.out.println("当前时间");
return time;
}
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
myTextView1.setText("录音时间:"+minute+":"+second);
}
};
/**
* @param isAddLastRecord 是否需要添加list之外的最新录音,一起合并
* @return 将合并的流用字符保存
*/
public void getInputCollection(List list,boolean isAddLastRecord){
String mMinute1=getTime();
Toast.makeText(EX07.this, "当前时间是:"+mMinute1,Toast.LENGTH_LONG).show();
// 创建音频文件,合并的文件放这里
File file1=new File(myRecAudioDir,mMinute1+SUFFIX);
FileOutputStream fileOutputStream = null;
if(!file1.exists()){
try {
file1.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
fileOutputStream=new FileOutputStream(file1);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//list里面为暂停录音 所产生的 几段录音文件的名字,中间几段文件的减去前面的6个字节头文件
for(int i=;i<list.size();i++){
File file=new File((String) list.get(i));
Log.d("list的长度", list.size()+"");
try {
FileInputStream fileInputStream=new FileInputStream(file);
byte []myByte=new byte[fileInputStream.available()];
//文件长度
int length = myByte.length;
//头文件
if(i==){
while(fileInputStream.read(myByte)!=-){
fileOutputStream.write(myByte, ,length);
}
}
//之后的文件,去掉头文件就可以了
else{
while(fileInputStream.read(myByte)!=-){
fileOutputStream.write(myByte, , length-);
}
}
fileOutputStream.flush();
fileInputStream.close();
System.out.println("合成文件长度:"+file1.length());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//结束后关闭流
try {
fileOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//加上当前正在录音的这一段
// if(isAddLastRecord){
//
//
// //刚刚录音的
// try {
// FileInputStream fileInputStream=new FileInputStream(myRecAudioFile);
// byte []myByte=new byte[fileInputStream.available()];
// System.out.println(fileInputStream.available()+"");
// while(fileInputStream.read(myByte)!=-1){
// //outputStream.
// fileOutputStream.write(myByte, 6, (fileInputStream.available()-6));
// }
//
// fileOutputStream.flush();
// fileInputStream.close();
// fileOutputStream.close();
// System.out.println("合成文件长度:"+file1.length());
// } catch (Exception e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
//
// }
//合成一个文件后,删除之前暂停录音所保存的零碎合成文件
deleteListRecord(isAddLastRecord);
//
adapter.add(file1.getName());
}
private void deleteListRecord(boolean isAddLastRecord){
for(int i=;i<list.size();i++){
File file=new File((String) list.get(i));
if(file.exists()){
file.delete();
}
}
//正在暂停后,继续录音的这一段音频文件
if(isAddLastRecord){
myRecAudioFile.delete();
}
}
}
Android MediaRecorder实现暂停断点录音功能的更多相关文章
- Android 能够暂停的录音功能
Android ApI提供了MediaRecorder和AudioRecord两个类给开发者来很方便地实现音视频的录制(前者可以实现音频和视频的录制,后者只能实 现音频的录制).这两个类都提供了sta ...
- Android MediaRecorder解析
源码路径:frameworks/base/media/java/android/media/MediaRecorder.javaframeworks/base/media/jni/android_me ...
- android 脱壳 之 dvmDexFileOpenPartial断点脱壳原理分析
android 脱壳 之 dvmDexFileOpenPartial断点脱壳原理分析 导语: 笔者主要研究方向是网络通信协议的加密解密, 对应用程序加固脱壳技术很少研究, 脱壳壳经历更是经历少之甚少. ...
- Android MediaRecorder自定义分辨率
Android MediaRecorder自定义分辨率 工作这么久了,确实积累了不少东西,但都是以文档的形式存在U盘里的,为什么不写博客呢?因为懒啊!!!总感觉博客太难写了(大概是上学时候写作文恐惧症 ...
- Android MediaRecorder录制播放音频
1.请求录制音频权限 <user-permission android:name="android.permission.RECORD_AUDIO"/> RECORD_ ...
- android studio学习----调试---断点调试
Android Studio调试其实也非常方便,一般问题直接通过AS的DDMS的Logcat就可以搞定.AS支持类似Eclipse的DDMS的所有功能.这里要说的是疑难问题的调试方式,即断点调试. 首 ...
- Android MediaRecorder录制音频
今天介绍一下在Android中怎么录制音频,在Android中使用MediaRecorder来录制音频,步骤: 1.创建MediaRecorder对象. 2.调用MediaRecorder对象的set ...
- VS2015 使用 Visual Studio Emulator For Android 调试无法命中断点的解决办法?
源解决方案是英文版的,地址:https://dzone.com/articles/fix-for-could-not-connect-to-the-debugger-while-de 问题现象: 1. ...
- Android -- 多线程下载, 断点下载
1. 原理图 2. 示例代码 需要权限 <uses-permission android:name="android.permission.INTERNET"/> &l ...
随机推荐
- Android Fragment之间的通信(用fragment替换掉XML布局文件中的一个线性布局)
1.XML布局 (1)主界面 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xml ...
- BZOJ - 3295 三维偏序 空间转换
题意:动态逆序对,共m次删除操作,求每次操作前的逆序对个数 删除操作转换为添加操作,首先对时间a进行简单排序 然后用cdq分治处理b维,树状数组处理c维 此时需要求的是对于某有序组\((a,b,c)\ ...
- Vue项目中使用HighChart
记:初次在Vue项目中使用 HighChart 的时候要走的坑 感谢这位哥们的思路 传送门 Vue-cli项目使用 npm install highcharts --save 让我们看看 highch ...
- 第七次 Scrum Meeting
第七次 Scrum Meeting 写在前面 会议时间 会议时长 会议地点 2019/4/11 22:00 10min 大运村1号楼6F 附Github仓库:WEDO 例会照片 工作情况总结(4.11 ...
- 删除centos 7 系统自带的 openjdk
1. 查看是否系统自带openjdk. java -version 2. 查看jdk位置 rpm -qa | grep java 3. 删除jdk rpm -e --nodeps java--ope ...
- laravel 运用
查看路由:php artisan route:list 查看路由
- oracle12c之三 控制PDB中CPU 资源使用
CPU资源隔离 数据库中,不同的PDB对主机CPU资源使用要求不同,那么我们就可以使用CDB resourceplans来管理不同pdb对CPU资源的使用. CDB Resource Plans ...
- oracle--dump->buffer cache (dump 深入实践一)
1,dump 取值 ALTER SESSION SET EVENTS 'immediate trace name buffers level n'; 只转储buffer header. 在level ...
- SpringBoot读取静态资源文件
ClassPathResource resource = new ClassPathResource(publicKeyCer); File file = null; try { file = res ...
- AngularJs学习笔记--Creating Services
原版地址:http://docs.angularjs.org/guide/dev_guide.services.creating_services 虽然angular提供许多有用的service,在一 ...