Android MediaRecorder实现暂停断点录音功能

最近研究了下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等之类的格式,合成的原理大同小异,只需要注意他们的音频文件头的格式就可以了。

资源代码:

http://download.csdn.net/detail/wanli_smile/4410240

有图有真相:

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=0;int minute=0;/**计时器**/Timer timer;/**是否暂停标志位**/private boolean isPause;/**在暂停状态中**/private boolean inThePause;/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);//暂停标志位 为falseisPause=false;//暂停状态标志位inThePause=false;//初始化listlist=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() {     @Overridepublic void onClick(View v) {second=0;minute=0;list.clear();//Calendar c=Calendar.getInstance();//intmMinute1=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() {@Overridepublic 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;// 将录音频文件给Adapteradapter.add(myRecAudioFile.getName());DecimalFormat df = new DecimalFormat("#.000");if (myRecAudioFile.length() <= 1024*1024) {//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 / 1024)+"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() {@Overridepublic void onClick(View v) {sigle = true;// TODO Auto-generated method stubif (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() {@Overridepublic void onClick(View v) {sigle = true;// TODO Auto-generated method stubif (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() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubisPause=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() {@Overridepublic void onItemClick(AdapterView<?> arg, View arg1,int arg2, long arg3) {// TODO Auto-generated method stub// 当有单点击文件名时将删除按钮及播放按钮EnablemyButton3.setEnabled(true);myButton4.setEnabled(true);myPlayFile = new File(myRecAudioDir.getAbsolutePath()+ File.separator+ ((TextView) arg1).getText().toString());DecimalFormat df = new DecimalFormat("#.000");if (myPlayFile.length() <= 1024*1024) {length1=df.format(myPlayFile.length() / 1024.0)+"K";} else {length1=df.format(myPlayFile.length() / 1024.0/1024)+"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() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubshowSize 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时关闭录音资源 */@Overrideprotected void onStop() {// TODO Auto-generated method stubif (mMediaRecorder01 != null && !isStopRecord) {// 停止录音mMediaRecorder01.stop();mMediaRecorder01.release();mMediaRecorder01 = null;}super.onStop();}/** * 获取目录下的所有音频文件 */private void getRecordFiles() {// TODO Auto-generated method stubrecordFiles = new ArrayList<String>();if (sdcardExit) {File files[] = myRecAudioDir.listFiles();if (files != null) {for (int i = 0; i < files.length; i++) {if (files[i].getName().indexOf(".") >= 0) { // 只取.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(".") + 1,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() {@Overridepublic void run() {// TODO Auto-generated method stubsecond++;if(second>=60){second=0;minute++;}handler.sendEmptyMessage(1);}}; timer=new Timer(); timer.schedule(timerTask, 1000,1000);try {if (!sdcardExit) {Toast.makeText(EX07.this, "请插入SD card",Toast.LENGTH_LONG).show();return;}StringmMinute1=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() {@Overridepublic void onInfo(MediaRecorder mr, int what, int extra) {// TODO Auto-generated method stubint a=mr.getMaxAmplitude();Toast.makeText(EX07.this, a, 500).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(){@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubsuper.handleMessage(msg);myTextView1.setText("录音时间:"+minute+":"+second);}};/** *  @param isAddLastRecord 是否需要添加list之外的最新录音,一起合并 *  @return 将合并的流用字符保存 */public  void getInputCollection(List list,boolean isAddLastRecord){StringmMinute1=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 blocke.printStackTrace();}}try {fileOutputStream=new FileOutputStream(file1);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}//list里面为暂停录音 所产生的 几段录音文件的名字,中间几段文件的减去前面的6个字节头文件for(int i=0;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==0){while(fileInputStream.read(myByte)!=-1){fileOutputStream.write(myByte, 0,length);}}//之后的文件,去掉头文件就可以了else{while(fileInputStream.read(myByte)!=-1){fileOutputStream.write(myByte, 6, length-6);}}fileOutputStream.flush();fileInputStream.close();System.out.println("合成文件长度:"+file1.length());} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}//结束后关闭流try {fileOutputStream.close();} catch (IOException e) {// TODO Auto-generated catch blocke.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=0;i<list.size();i++){File file=new File((String) list.get(i));if(file.exists()){file.delete();}}//正在暂停后,继续录音的这一段音频文件if(isAddLastRecord){myRecAudioFile.delete();}}}


技术交流群:

187651345

更多相关文章

  1. 一款常用的 Squid 日志分析工具
  2. GitHub 标星 8K+!一款开源替代 ls 的工具你值得拥有!
  3. RHEL 6 下 DHCP+TFTP+FTP+PXE+Kickstart 实现无人值守安装
  4. Linux 环境下实战 Rsync 备份工具及配置 rsync+inotify 实时同步
  5. 打包状态下百度的ak的获得
  6. android音乐播放器开发在线加载歌词
  7. 多图片上传Android,服务器端实现
  8. 【Android】查看程序每个方法所花费的时间
  9. 生成安卓证书keystor命令文件

随机推荐

  1. Android(安卓)如何删除list中的某一项ite
  2. Android(安卓)模拟器参数
  3. Android之Service相关
  4. Android(安卓)Studio 绑定下拉框数据(网
  5. Android(安卓)Okhttp主流程源码分析
  6. Android(安卓)Ap 开发 设计模式第一篇:迭
  7. 下载 编译 Android源代码 和 Android(安
  8. 用git下载Android自带app的源代码
  9. Android之蓝牙startDiscovery()搜索不到
  10. Android开发者指南(4) —— Application