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
有图有真相:
- publicclassEX07extendsActivity{
- privateImageButtonmyButton1;
- privateImageButtonmyButton2;
- privateImageButtonmyButton3;
- privateImageButtonmyButton4;
- privateButtonmyButton;
- privateListViewmyListView1;
- privateStringstrTempFile="YYT_";
- privateFilemyRecAudioFile;
- /**录音保存路径**/
- privateFilemyRecAudioDir;
- privateFilemyPlayFile;
- privateMediaRecordermMediaRecorder01;
- privateintmMinute;
- privatebooleanxx=true;
- /**存放音频文件列表**/
- privateArrayList<String>recordFiles;
- privateArrayAdapter<String>adapter;
- privateTextViewmyTextView1;
- /**文件存在**/
- privatebooleansdcardExit;
- /**是否停止录音**/
- privatebooleanisStopRecord;
- /**按钮背景图片的标志位**/
- privatebooleansigle=false;
- privateStringlength1=null;
- privatefinalStringSUFFIX=".amr";
- /**暂停按钮**/
- Buttonbuttonpause;
- /**记录需要合成的几段amr语音文件**/
- privateArrayList<String>list;
- intsecond=0;
- intminute=0;
- /**计时器**/
- Timertimer;
- /**是否暂停标志位**/
- privatebooleanisPause;
- /**在暂停状态中**/
- privatebooleaninThePause;
- /**Calledwhentheactivityisfirstcreated.*/
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- //暂停标志位为false
- isPause=false;
- //暂停状态标志位
- inThePause=false;
- //初始化list
- list=newArrayList<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);
- buttοnpause=(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;
- //判断sdCard是否插入
- sdcardExit=Environment.getExternalStorageState().equals(
- android.os.Environment.MEDIA_MOUNTED);
- //取得sdcard路径作为录音文件的位置
- if(sdcardExit){
- StringpathStr=Environment.getExternalStorageDirectory().getPath()+"/YYT";
- myRecAudioDir=newFile(pathStr);
- if(!myRecAudioDir.exists()){
- myRecAudioDir.mkdirs();
- Log.v("录音","创建录音文件!"+myRecAudioDir.exists());
- }
- //Environment.getExternalStorageDirectory().getPath()+"/"+PREFIX+"/";
- }
- //取得sdcard目录里的.arm文件
- getRecordFiles();
- adapter=newArrayAdapter<String>(this,
- android.R.layout.simple_list_item_1,recordFiles);
- //将ArrayAdater添加ListView对象中
- myListView1.setAdapter(adapter);
- //录音
- myButton1.setOnClickListener(newImageButton.OnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- second=0;
- minute=0;
- list.clear();
- //Calendarc=Calendar.getInstance();
- //intmMinute1=c.get(Calendar.MINUTE);
- sigle=true;
- //TODOAuto-generatedmethodstub
- 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(newImageButton.OnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- xx=false;
- sigle=true;
- timer.cancel();
- //TODOAuto-generatedmethodstub
- //这里写暂停处理的文件!加上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());
- DecimalFormatdf=newDecimalFormat("#.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)+"";
- //DecimalFormatdf=newDecimalFormat("#.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(newImageButton.OnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- sigle=true;
- //TODOAuto-generatedmethodstub
- 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(newOnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- sigle=true;
- //TODOAuto-generatedmethodstub
- 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(newOnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- //TODOAuto-generatedmethodstub
- isPause=true;
- //已经暂停过了,再次点击按钮开始录音,录音状态在录音中
- if(inThePause){
- buttonpause.setText("暂停录音");
- start();
- inThePause=false;
- }
- //正在录音,点击暂停,现在录音状态为暂停
- else{
- //当前正在录音的文件名,全程
- list.add(myRecAudioFile.getPath());
- inThePause=true;
- recodeStop();
- //start();
- buttonpause.setText("继续录音");
- //计时停止
- timer.cancel();
- }
- }
- });
- myListView1
- .setOnItemClickListener(newAdapterView.OnItemClickListener(){
- @Override
- publicvoidonItemClick(AdapterView<?>arg,Viewarg1,
- intarg2,longarg3){
- //TODOAuto-generatedmethodstub
- //当有单点击文件名时将删除按钮及播放按钮Enable
- myButton3.setEnabled(true);
- myButton4.setEnabled(true);
- myPlayFile=newFile(myRecAudioDir.getAbsolutePath()
- +File.separator
- +((TextView)arg1).getText().toString());
- DecimalFormatdf=newDecimalFormat("#.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(newButton.OnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- //TODOAuto-generatedmethodstub
- showSizeshow=newshowSize();
- Stringtext=show.showsize();
- Toast.makeText(EX07.this,text,Toast.LENGTH_LONG).show();
- }
- });
- }
- protectedvoidrecodeStop(){
- if(mMediaRecorder01!=null&&!isStopRecord){
- //停止录音
- mMediaRecorder01.stop();
- mMediaRecorder01.release();
- mMediaRecorder01=null;
- }
- timer.cancel();
- }
- /**
- *activity的生命周期,stop时关闭录音资源
- */
- @Override
- protectedvoidonStop(){
- //TODOAuto-generatedmethodstub
- if(mMediaRecorder01!=null&&!isStopRecord){
- //停止录音
- mMediaRecorder01.stop();
- mMediaRecorder01.release();
- mMediaRecorder01=null;
- }
- super.onStop();
- }
- /**
- *获取目录下的所有音频文件
- */
- privatevoidgetRecordFiles(){
- //TODOAuto-generatedmethodstub
- recordFiles=newArrayList<String>();
- if(sdcardExit){
- Filefiles[]=myRecAudioDir.listFiles();
- if(files!=null){
- for(inti=0;i<files.length;i++){
- if(files[i].getName().indexOf(".")>=0){//只取.amr文件
- StringfileS=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());
- }
- }
- }
- }
- }
- //打开录音播放程序
- privatevoidopenFile(Filef){
- Intentintent=newIntent();
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.setAction(android.content.Intent.ACTION_VIEW);
- Stringtype=getMIMEType(f);
- intent.setDataAndType(Uri.fromFile(f),type);
- startActivity(intent);
- //Uriuri=Uri.fromFile(f);
- //MediaPlayermediaPlayer=MediaPlayer.create(this,uri);
- //try{
- //mediaPlayer.prepare();
- //}catch(IllegalStateExceptione){
- TODOAuto-generatedcatchblock
- //e.printStackTrace();
- //}catch(IOExceptione){
- TODOAuto-generatedcatchblock
- //e.printStackTrace();
- //}
- //mediaPlayer.start();
- }
- privateStringgetMIMEType(Filef){
- Stringend=f.getName().substring(f.getName().lastIndexOf(".")+1,
- f.getName().length()).toLowerCase();
- Stringtype="";
- if(end.equals("mp3")||end.equals("aac")||end.equals("amr")
- ||end.equals("mpeg")||end.equals("mp4")){
- type="audio";
- }elseif(end.equals("jpg")||end.equals("gif")||end.equals("png")
- ||end.equals("jpeg")){
- type="image";
- }else{
- type="*";
- }
- type+="/";
- returntype;
- }
- privatevoidstart(){
- TimerTasktimerTask=newTimerTask(){
- @Override
- publicvoidrun(){
- //TODOAuto-generatedmethodstub
- second++;
- if(second>=60){
- second=0;
- minute++;
- }
- handler.sendEmptyMessage(1);
- }
- };
- timer=newTimer();
- timer.schedule(timerTask,1000,1000);
- try{
- if(!sdcardExit){
- Toast.makeText(EX07.this,"请插入SDcard",
- Toast.LENGTH_LONG).show();
- return;
- }
- StringmMinute1=getTime();
- Toast.makeText(EX07.this,"当前时间是:"+mMinute1,Toast.LENGTH_LONG).show();
- //创建音频文件
- //myRecAudioFile=File.createTempFile(mMinute1,".amr",
- //myRecAudioDir);
- myRecAudioFile=newFile(myRecAudioDir,mMinute1+SUFFIX);
- mMediaRecorder01=newMediaRecorder();
- //设置录音为麦克风
- 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(newOnInfoListener(){
- @Override
- publicvoidonInfo(MediaRecordermr,intwhat,intextra){
- //TODOAuto-generatedmethodstub
- inta=mr.getMaxAmplitude();
- Toast.makeText(EX07.this,a,500).show();
- }
- });
- myTextView1.setText("录音中......");
- myButton2.setEnabled(true);
- myButton3.setEnabled(false);
- myButton4.setEnabled(false);
- isStopRecord=false;
- }catch(IOExceptione){
- e.printStackTrace();
- }
- }
- privateStringgetTime(){
- SimpleDateFormatformatter=newSimpleDateFormat("yyyy年MM月dd日HH:mm:ss");
- DatecurDate=newDate(System.currentTimeMillis());//获取当前时间
- Stringtime=formatter.format(curDate);
- System.out.println("当前时间");
- returntime;
- }
- Handlerhandler=newHandler(){
- @Override
- publicvoidhandleMessage(Messagemsg){
- //TODOAuto-generatedmethodstub
- super.handleMessage(msg);
- myTextView1.setText("录音时间:"+minute+":"+second);
- }
- };
- /**
- *@paramisAddLastRecord是否需要添加list之外的最新录音,一起合并
- *@return将合并的流用字符保存
- */
- publicvoidgetInputCollection(Listlist,booleanisAddLastRecord){
- StringmMinute1=getTime();
- Toast.makeText(EX07.this,"当前时间是:"+mMinute1,Toast.LENGTH_LONG).show();
- //创建音频文件,合并的文件放这里
- Filefile1=newFile(myRecAudioDir,mMinute1+SUFFIX);
- FileOutputStreamfileOutputStream=null;
- if(!file1.exists()){
- try{
- file1.createNewFile();
- }catch(IOExceptione){
- //TODOAuto-generatedcatchblock
- e.printStackTrace();
- }
- }
- try{
- fileOutputStream=newFileOutputStream(file1);
- }catch(IOExceptione){
- //TODOAuto-generatedcatchblock
- e.printStackTrace();
- }
- //list里面为暂停录音所产生的几段录音文件的名字,中间几段文件的减去前面的6个字节头文件
- for(inti=0;i<list.size();i++){
- Filefile=newFile((String)list.get(i));
- Log.d("list的长度",list.size()+"");
- try{
- FileInputStreamfileInputStream=newFileInputStream(file);
- byte[]myByte=newbyte[fileInputStream.available()];
- //文件长度
- intlength=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(Exceptione){
- //TODOAuto-generatedcatchblock
- e.printStackTrace();
- }
- }
- //结束后关闭流
- try{
- fileOutputStream.close();
- }catch(IOExceptione){
- //TODOAuto-generatedcatchblock
- e.printStackTrace();
- }
- //加上当前正在录音的这一段
- //if(isAddLastRecord){
- //
- //
- 刚刚录音的
- //try{
- //FileInputStreamfileInputStream=newFileInputStream(myRecAudioFile);
- //byte[]myByte=newbyte[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(Exceptione){
- TODOAuto-generatedcatchblock
- //e.printStackTrace();
- //}
- //
- //}
- //合成一个文件后,删除之前暂停录音所保存的零碎合成文件
- deleteListRecord(isAddLastRecord);
- //
- adapter.add(file1.getName());
- }
- privatevoiddeleteListRecord(booleanisAddLastRecord){
- for(inti=0;i<list.size();i++){
- Filefile=newFile((String)list.get(i));
- if(file.exists()){
- file.delete();
- }
- }
- //正在暂停后,继续录音的这一段音频文件
- if(isAddLastRecord){
- myRecAudioFile.delete();
- }
- }
- }