android mediarecord 实现暂停断点录音功能

原文出处:blog.csdn.net/wanli_smile/article/details/7715030


最近研究了下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

有图有真相:

[java] view plaincopy
  1. publicclassEX07extendsActivity{
  2. privateImageButtonmyButton1;
  3. privateImageButtonmyButton2;
  4. privateImageButtonmyButton3;
  5. privateImageButtonmyButton4;
  6. privateButtonmyButton;
  7. privateListViewmyListView1;
  8. privateStringstrTempFile="YYT_";
  9. privateFilemyRecAudioFile;
  10. /**录音保存路径**/
  11. privateFilemyRecAudioDir;
  12. privateFilemyPlayFile;
  13. privateMediaRecordermMediaRecorder01;
  14. privateintmMinute;
  15. privatebooleanxx=true;
  16. /**存放音频文件列表**/
  17. privateArrayList<String>recordFiles;
  18. privateArrayAdapter<String>adapter;
  19. privateTextViewmyTextView1;
  20. /**文件存在**/
  21. privatebooleansdcardExit;
  22. /**是否停止录音**/
  23. privatebooleanisStopRecord;
  24. /**按钮背景图片的标志位**/
  25. privatebooleansigle=false;
  26. privateStringlength1=null;
  27. privatefinalStringSUFFIX=".amr";
  28. /**暂停按钮**/
  29. Buttonbuttonpause;
  30. /**记录需要合成的几段amr语音文件**/
  31. privateArrayList<String>list;
  32. intsecond=0;
  33. intminute=0;
  34. /**计时器**/
  35. Timertimer;
  36. /**是否暂停标志位**/
  37. privatebooleanisPause;
  38. /**在暂停状态中**/
  39. privatebooleaninThePause;
  40. /**Calledwhentheactivityisfirstcreated.*/
  41. @Override
  42. publicvoidonCreate(BundlesavedInstanceState){
  43. super.onCreate(savedInstanceState);
  44. setContentView(R.layout.main);
  45. //暂停标志位为false
  46. isPause=false;
  47. //暂停状态标志位
  48. inThePause=false;
  49. //初始化list
  50. list=newArrayList<String>();
  51. //四个按钮
  52. myButton1=(ImageButton)findViewById(R.id.ImageButton01);
  53. myButton2=(ImageButton)findViewById(R.id.ImageButton02);
  54. myButton3=(ImageButton)findViewById(R.id.ImageButton03);
  55. myButton4=(ImageButton)findViewById(R.id.ImageButton04);
  56. myButton=(Button)findViewById(R.id.myButton);
  57. buttonpause=(Button)findViewById(R.id.mypuase);
  58. myListView1=(ListView)findViewById(R.id.ListView01);
  59. myTextView1=(TextView)findViewById(R.id.TextView01);
  60. myButton2.setEnabled(false);
  61. myButton3.setEnabled(false);
  62. myButton4.setEnabled(false);
  63. myPlayFile=null;
  64. //判断sdCard是否插入
  65. sdcardExit=Environment.getExternalStorageState().equals(
  66. android.os.Environment.MEDIA_MOUNTED);
  67. //取得sdcard路径作为录音文件的位置
  68. if(sdcardExit){
  69. StringpathStr=Environment.getExternalStorageDirectory().getPath()+"/YYT";
  70. myRecAudioDir=newFile(pathStr);
  71. if(!myRecAudioDir.exists()){
  72. myRecAudioDir.mkdirs();
  73. Log.v("录音","创建录音文件!"+myRecAudioDir.exists());
  74. }
  75. //Environment.getExternalStorageDirectory().getPath()+"/"+PREFIX+"/";
  76. }
  77. //取得sdcard目录里的.arm文件
  78. getRecordFiles();
  79. adapter=newArrayAdapter<String>(this,
  80. android.R.layout.simple_list_item_1,recordFiles);
  81. //将ArrayAdater添加ListView对象中
  82. myListView1.setAdapter(adapter);
  83. //录音
  84. myButton1.setOnClickListener(newImageButton.OnClickListener(){
  85. @Override
  86. publicvoidonClick(Viewv){
  87. second=0;
  88. minute=0;
  89. list.clear();
  90. //Calendarc=Calendar.getInstance();
  91. //intmMinute1=c.get(Calendar.MINUTE);
  92. sigle=true;
  93. //TODOAuto-generatedmethodstub
  94. start();
  95. if(sigle=false){
  96. myButton1.setBackgroundResource(R.drawable.record_hover1);
  97. }else{
  98. myButton1.setBackgroundResource(R.drawable.record_dis1);
  99. myButton2.setBackgroundResource(R.drawable.stop_hover2);
  100. myButton3.setBackgroundResource(R.drawable.play_hover1);
  101. myButton4.setBackgroundResource(R.drawable.delete_hover);
  102. }
  103. }
  104. });
  105. //停止
  106. myButton2.setOnClickListener(newImageButton.OnClickListener(){
  107. @Override
  108. publicvoidonClick(Viewv){
  109. xx=false;
  110. sigle=true;
  111. timer.cancel();
  112. //TODOAuto-generatedmethodstub
  113. //这里写暂停处理的文件!加上list里面语音合成起来
  114. if(isPause){
  115. //在暂停状态按下结束键,处理list就可以了
  116. if(inThePause){
  117. getInputCollection(list,false);
  118. }
  119. //在正在录音时,处理list里面的和正在录音的语音
  120. else{
  121. list.add(myRecAudioFile.getPath());
  122. recodeStop();
  123. getInputCollection(list,true);
  124. }
  125. //还原标志位
  126. isPause=false;
  127. inThePause=false;
  128. buttonpause.setText("暂停录音");
  129. //adapter.add(myRecAudioFile.getName());
  130. }
  131. //若录音没有经过任何暂停
  132. else{
  133. if(myRecAudioFile!=null){
  134. //停止录音
  135. mMediaRecorder01.stop();
  136. mMediaRecorder01.release();
  137. mMediaRecorder01=null;
  138. //将录音频文件给Adapter
  139. adapter.add(myRecAudioFile.getName());
  140. DecimalFormatdf=newDecimalFormat("#.000");
  141. if(myRecAudioFile.length()<=1024*1024){
  142. //length1=(myRecAudioFile.length()/1024.0)+"";
  143. length1=df.format(myRecAudioFile.length()/1024.0)+"K";
  144. }else{
  145. //length1=(myRecAudioFile.length()/1024.0/1024)+"";
  146. //DecimalFormatdf=newDecimalFormat("#.000");
  147. length1=df.format(myRecAudioFile.length()/1024.0/1024)+"M";
  148. }
  149. System.out.println(length1);
  150. myTextView1.setText("停止"+myRecAudioFile.getName()
  151. +"文件大小为:"+length1);
  152. myButton2.setEnabled(false);
  153. }
  154. }
  155. if(sigle=false){
  156. myButton2.setBackgroundResource(R.drawable.stop_hover2);
  157. }else{
  158. myButton1.setBackgroundResource(R.drawable.record_hover1);
  159. myButton2.setBackgroundResource(R.drawable.stop1);
  160. myButton3.setBackgroundResource(R.drawable.play_hover1);
  161. myButton4.setBackgroundResource(R.drawable.delete_hover);
  162. }
  163. //停止录音了
  164. isStopRecord=true;
  165. }
  166. });
  167. //播放
  168. myButton3.setOnClickListener(newImageButton.OnClickListener(){
  169. @Override
  170. publicvoidonClick(Viewv){
  171. sigle=true;
  172. //TODOAuto-generatedmethodstub
  173. if(myPlayFile!=null&&myPlayFile.exists()){
  174. //打开播放程序
  175. openFile(myPlayFile);
  176. }else{
  177. Toast.makeText(EX07.this,"你选的是一个空文件",Toast.LENGTH_LONG)
  178. .show();
  179. Log.d("没有选择文件","没有选择文件");
  180. }
  181. if(sigle=false){
  182. myButton3.setBackgroundResource(R.drawable.play_hover1);
  183. }else{
  184. myButton1.setBackgroundResource(R.drawable.record_hover1);
  185. myButton2.setBackgroundResource(R.drawable.stop_hover2);
  186. myButton3.setBackgroundResource(R.drawable.play1);
  187. myButton4.setBackgroundResource(R.drawable.delete_hover);
  188. }
  189. }
  190. });
  191. //删除
  192. myButton4.setOnClickListener(newOnClickListener(){
  193. @Override
  194. publicvoidonClick(Viewv){
  195. sigle=true;
  196. //TODOAuto-generatedmethodstub
  197. if(myPlayFile!=null){
  198. //先将Adapter删除文件名
  199. adapter.remove(myPlayFile.getName());
  200. //删除文件
  201. if(myPlayFile.exists())
  202. myPlayFile.delete();
  203. myTextView1.setText("完成删除!");
  204. }
  205. if(sigle=false){
  206. myButton4.setBackgroundResource(R.drawable.delete_hover);
  207. }else{
  208. myButton1.setBackgroundResource(R.drawable.record_hover1);
  209. myButton2.setBackgroundResource(R.drawable.stop_hover2);
  210. myButton3.setBackgroundResource(R.drawable.play_hover1);
  211. myButton4.setBackgroundResource(R.drawable.delete_dis);
  212. }
  213. }
  214. });
  215. /**
  216. *暂停按钮,记录之前保存的语音文件
  217. */
  218. buttonpause.setOnClickListener(newOnClickListener(){
  219. @Override
  220. publicvoidonClick(Viewv){
  221. //TODOAuto-generatedmethodstub
  222. isPause=true;
  223. //已经暂停过了,再次点击按钮开始录音,录音状态在录音中
  224. if(inThePause){
  225. buttonpause.setText("暂停录音");
  226. start();
  227. inThePause=false;
  228. }
  229. //正在录音,点击暂停,现在录音状态为暂停
  230. else{
  231. //当前正在录音的文件名,全程
  232. list.add(myRecAudioFile.getPath());
  233. inThePause=true;
  234. recodeStop();
  235. //start();
  236. buttonpause.setText("继续录音");
  237. //计时停止
  238. timer.cancel();
  239. }
  240. }
  241. });
  242. myListView1
  243. .setOnItemClickListener(newAdapterView.OnItemClickListener(){
  244. @Override
  245. publicvoidonItemClick(AdapterView<?>arg,Viewarg1,
  246. intarg2,longarg3){
  247. //TODOAuto-generatedmethodstub
  248. //当有单点击文件名时将删除按钮及播放按钮Enable
  249. myButton3.setEnabled(true);
  250. myButton4.setEnabled(true);
  251. myPlayFile=newFile(myRecAudioDir.getAbsolutePath()
  252. +File.separator
  253. +((TextView)arg1).getText().toString());
  254. DecimalFormatdf=newDecimalFormat("#.000");
  255. if(myPlayFile.length()<=1024*1024){
  256. length1=df.format(myPlayFile.length()/1024.0)+"K";
  257. }else{
  258. length1=df.format(myPlayFile.length()/1024.0/1024)+"M";
  259. }
  260. myTextView1.setText("你选的是"
  261. +((TextView)arg1).getText().toString()
  262. +"文件大小为:"+length1);
  263. Toast.makeText(EX07.this,"你选的是"+(((TextView)arg1).getText())+"文件大小为:"+length1,
  264. Toast.LENGTH_LONG).show();
  265. }
  266. });
  267. myButton.setOnClickListener(newButton.OnClickListener(){
  268. @Override
  269. publicvoidonClick(Viewv){
  270. //TODOAuto-generatedmethodstub
  271. showSizeshow=newshowSize();
  272. Stringtext=show.showsize();
  273. Toast.makeText(EX07.this,text,Toast.LENGTH_LONG).show();
  274. }
  275. });
  276. }
  277. protectedvoidrecodeStop(){
  278. if(mMediaRecorder01!=null&&!isStopRecord){
  279. //停止录音
  280. mMediaRecorder01.stop();
  281. mMediaRecorder01.release();
  282. mMediaRecorder01=null;
  283. }
  284. timer.cancel();
  285. }
  286. /**
  287. *activity的生命周期,stop时关闭录音资源
  288. */
  289. @Override
  290. protectedvoidonStop(){
  291. //TODOAuto-generatedmethodstub
  292. if(mMediaRecorder01!=null&&!isStopRecord){
  293. //停止录音
  294. mMediaRecorder01.stop();
  295. mMediaRecorder01.release();
  296. mMediaRecorder01=null;
  297. }
  298. super.onStop();
  299. }
  300. /**
  301. *获取目录下的所有音频文件
  302. */
  303. privatevoidgetRecordFiles(){
  304. //TODOAuto-generatedmethodstub
  305. recordFiles=newArrayList<String>();
  306. if(sdcardExit){
  307. Filefiles[]=myRecAudioDir.listFiles();
  308. if(files!=null){
  309. for(inti=0;i<files.length;i++){
  310. if(files[i].getName().indexOf(".")>=0){//只取.amr文件
  311. StringfileS=files[i].getName().substring(
  312. files[i].getName().indexOf("."));
  313. if(fileS.toLowerCase().equals(".mp3")
  314. ||fileS.toLowerCase().equals(".amr")
  315. ||fileS.toLowerCase().equals(".mp4"))
  316. recordFiles.add(files[i].getName());
  317. }
  318. }
  319. }
  320. }
  321. }
  322. //打开录音播放程序
  323. privatevoidopenFile(Filef){
  324. Intentintent=newIntent();
  325. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  326. intent.setAction(android.content.Intent.ACTION_VIEW);
  327. Stringtype=getMIMEType(f);
  328. intent.setDataAndType(Uri.fromFile(f),type);
  329. startActivity(intent);
  330. //Uriuri=Uri.fromFile(f);
  331. //MediaPlayermediaPlayer=MediaPlayer.create(this,uri);
  332. //try{
  333. //mediaPlayer.prepare();
  334. //}catch(IllegalStateExceptione){
  335. ////TODOAuto-generatedcatchblock
  336. //e.printStackTrace();
  337. //}catch(IOExceptione){
  338. ////TODOAuto-generatedcatchblock
  339. //e.printStackTrace();
  340. //}
  341. //mediaPlayer.start();
  342. }
  343. privateStringgetMIMEType(Filef){
  344. Stringend=f.getName().substring(f.getName().lastIndexOf(".")+1,
  345. f.getName().length()).toLowerCase();
  346. Stringtype="";
  347. if(end.equals("mp3")||end.equals("aac")||end.equals("amr")
  348. ||end.equals("mpeg")||end.equals("mp4")){
  349. type="audio";
  350. }elseif(end.equals("jpg")||end.equals("gif")||end.equals("png")
  351. ||end.equals("jpeg")){
  352. type="image";
  353. }else{
  354. type="*";
  355. }
  356. type+="/";
  357. returntype;
  358. }
  359. privatevoidstart(){
  360. TimerTasktimerTask=newTimerTask(){
  361. @Override
  362. publicvoidrun(){
  363. //TODOAuto-generatedmethodstub
  364. second++;
  365. if(second>=60){
  366. second=0;
  367. minute++;
  368. }
  369. handler.sendEmptyMessage(1);
  370. }
  371. };
  372. timer=newTimer();
  373. timer.schedule(timerTask,1000,1000);
  374. try{
  375. if(!sdcardExit){
  376. Toast.makeText(EX07.this,"请插入SDcard",
  377. Toast.LENGTH_LONG).show();
  378. return;
  379. }
  380. StringmMinute1=getTime();
  381. Toast.makeText(EX07.this,"当前时间是:"+mMinute1,Toast.LENGTH_LONG).show();
  382. //创建音频文件
  383. //myRecAudioFile=File.createTempFile(mMinute1,".amr",
  384. //myRecAudioDir);
  385. myRecAudioFile=newFile(myRecAudioDir,mMinute1+SUFFIX);
  386. mMediaRecorder01=newMediaRecorder();
  387. //设置录音为麦克风
  388. mMediaRecorder01
  389. .setAudioSource(MediaRecorder.AudioSource.MIC);
  390. mMediaRecorder01
  391. .setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
  392. mMediaRecorder01
  393. .setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
  394. //录音文件保存这里
  395. mMediaRecorder01.setOutputFile(myRecAudioFile
  396. .getAbsolutePath());
  397. mMediaRecorder01.prepare();
  398. mMediaRecorder01.start();
  399. //mMediaRecorder01.getMaxAmplitude();
  400. //mMediaRecorder01.getAudioSourceMax();
  401. mMediaRecorder01.setOnInfoListener(newOnInfoListener(){
  402. @Override
  403. publicvoidonInfo(MediaRecordermr,intwhat,intextra){
  404. //TODOAuto-generatedmethodstub
  405. inta=mr.getMaxAmplitude();
  406. Toast.makeText(EX07.this,a,500).show();
  407. }
  408. });
  409. myTextView1.setText("录音中......");
  410. myButton2.setEnabled(true);
  411. myButton3.setEnabled(false);
  412. myButton4.setEnabled(false);
  413. isStopRecord=false;
  414. }catch(IOExceptione){
  415. e.printStackTrace();
  416. }
  417. }
  418. privateStringgetTime(){
  419. SimpleDateFormatformatter=newSimpleDateFormat("yyyy年MM月dd日HH:mm:ss");
  420. DatecurDate=newDate(System.currentTimeMillis());//获取当前时间
  421. Stringtime=formatter.format(curDate);
  422. System.out.println("当前时间");
  423. returntime;
  424. }
  425. Handlerhandler=newHandler(){
  426. @Override
  427. publicvoidhandleMessage(Messagemsg){
  428. //TODOAuto-generatedmethodstub
  429. super.handleMessage(msg);
  430. myTextView1.setText("录音时间:"+minute+":"+second);
  431. }
  432. };
  433. /**
  434. *@paramisAddLastRecord是否需要添加list之外的最新录音,一起合并
  435. *@return将合并的流用字符保存
  436. */
  437. publicvoidgetInputCollection(Listlist,booleanisAddLastRecord){
  438. StringmMinute1=getTime();
  439. Toast.makeText(EX07.this,"当前时间是:"+mMinute1,Toast.LENGTH_LONG).show();
  440. //创建音频文件,合并的文件放这里
  441. Filefile1=newFile(myRecAudioDir,mMinute1+SUFFIX);
  442. FileOutputStreamfileOutputStream=null;
  443. if(!file1.exists()){
  444. try{
  445. file1.createNewFile();
  446. }catch(IOExceptione){
  447. //TODOAuto-generatedcatchblock
  448. e.printStackTrace();
  449. }
  450. }
  451. try{
  452. fileOutputStream=newFileOutputStream(file1);
  453. }catch(IOExceptione){
  454. //TODOAuto-generatedcatchblock
  455. e.printStackTrace();
  456. }
  457. //list里面为暂停录音所产生的几段录音文件的名字,中间几段文件的减去前面的6个字节头文件
  458. for(inti=0;i<list.size();i++){
  459. Filefile=newFile((String)list.get(i));
  460. Log.d("list的长度",list.size()+"");
  461. try{
  462. FileInputStreamfileInputStream=newFileInputStream(file);
  463. byte[]myByte=newbyte[fileInputStream.available()];
  464. //文件长度
  465. intlength=myByte.length;
  466. //头文件
  467. if(i==0){
  468. while(fileInputStream.read(myByte)!=-1){
  469. fileOutputStream.write(myByte,0,length);
  470. }
  471. }
  472. //之后的文件,去掉头文件就可以了
  473. else{
  474. while(fileInputStream.read(myByte)!=-1){
  475. fileOutputStream.write(myByte,6,length-6);
  476. }
  477. }
  478. fileOutputStream.flush();
  479. fileInputStream.close();
  480. System.out.println("合成文件长度:"+file1.length());
  481. }catch(Exceptione){
  482. //TODOAuto-generatedcatchblock
  483. e.printStackTrace();
  484. }
  485. }
  486. //结束后关闭流
  487. try{
  488. fileOutputStream.close();
  489. }catch(IOExceptione){
  490. //TODOAuto-generatedcatchblock
  491. e.printStackTrace();
  492. }
  493. //加上当前正在录音的这一段
  494. //if(isAddLastRecord){
  495. //
  496. //
  497. ////刚刚录音的
  498. //try{
  499. //FileInputStreamfileInputStream=newFileInputStream(myRecAudioFile);
  500. //byte[]myByte=newbyte[fileInputStream.available()];
  501. //System.out.println(fileInputStream.available()+"");
  502. //while(fileInputStream.read(myByte)!=-1){
  503. ////outputStream.
  504. //fileOutputStream.write(myByte,6,(fileInputStream.available()-6));
  505. //}
  506. //
  507. //fileOutputStream.flush();
  508. //fileInputStream.close();
  509. //fileOutputStream.close();
  510. //System.out.println("合成文件长度:"+file1.length());
  511. //}catch(Exceptione){
  512. ////TODOAuto-generatedcatchblock
  513. //e.printStackTrace();
  514. //}
  515. //
  516. //}
  517. //合成一个文件后,删除之前暂停录音所保存的零碎合成文件
  518. deleteListRecord(isAddLastRecord);
  519. //
  520. adapter.add(file1.getName());
  521. }
  522. privatevoiddeleteListRecord(booleanisAddLastRecord){
  523. for(inti=0;i<list.size();i++){
  524. Filefile=newFile((String)list.get(i));
  525. if(file.exists()){
  526. file.delete();
  527. }
  528. }
  529. //正在暂停后,继续录音的这一段音频文件
  530. if(isAddLastRecord){
  531. myRecAudioFile.delete();
  532. }
  533. }
  534. }

更多相关文章

  1. Android文件路径
  2. android读写文件函数代码
  3. 基于Android扫描sd卡与系统文件的介绍
  4. Android窗口抖动之动画实现
  5. 详解Android中实现热更新的原理
  6. Android(安卓)service实例
  7. Android(安卓)通过AudioRecord实时录音并转AAC
  8. android java 文件 设置 对应 layout 下 布局文件.xml
  9. NPM 和webpack 的基础使用

随机推荐

  1. Android之使用GPS和NetWork定位
  2. Android进程管理机制及优化
  3. 福利!!!你想要的Android、Java、Python、QT
  4. Android中文资源站专栏:五个好用的日常软
  5. React Native接入现有Android原生工程并
  6. Android面试看重你什么?(推荐!!!)
  7. Android获取设备唯一ID
  8. android布局基础及范例:人人android九宫格
  9. Android底部弹出iOS7风格对话选项框
  10. Android用户看过来,免ROOT和顽固后台拜拜