歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Android MediaRecorder實現暫停斷點錄音功能

Android MediaRecorder實現暫停斷點錄音功能

日期:2017/3/1 10:17:56   编辑:Linux編程

最近研究了下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等之類的格式,合成的原理大同小異,只需要注意他們的音頻文件頭的格式就可以了。)

資源代碼:

免費下載地址在 http://linux.linuxidc.com/

用戶名與密碼都是www.linuxidc.com

具體下載目錄在 /2012年資料/7月/4日/Android MediaRecorder實現暫停斷點錄音功能

有圖有真相:

  1. public class EX07 extends Activity {
  2. private ImageButton myButton1;
  3. private ImageButton myButton2;
  4. private ImageButton myButton3;
  5. private ImageButton myButton4;
  6. private Button myButton;
  7. private ListView myListView1;
  8. private String strTempFile = "YYT_";
  9. private File myRecAudioFile;
  10. /**錄音保存路徑**/
  11. private File myRecAudioDir;
  12. private File myPlayFile;
  13. private MediaRecorder mMediaRecorder01;
  14. private int mMinute;
  15. private boolean xx=true;
  16. /**存放音頻文件列表**/
  17. private ArrayList<String> recordFiles;
  18. private ArrayAdapter<String> adapter;
  19. private TextView myTextView1;
  20. /**文件存在**/
  21. private boolean sdcardExit;
  22. /**是否停止錄音**/
  23. private boolean isStopRecord;
  24. /**按鈕背景圖片的標志位**/
  25. private boolean sigle = false;
  26. private String length1 = null;
  27. private final String SUFFIX=".amr";
  28. /**暫停按鈕**/
  29. Button buttonpause;
  30. /**記錄需要合成的幾段amr語音文件**/
  31. private ArrayList<String> list;
  32. int second=0;
  33. int minute=0;
  34. /**計時器**/
  35. Timer timer;
  36. /**是否暫停標志位**/
  37. private boolean isPause;
  38. /**在暫停狀態中**/
  39. private boolean inThePause;
  40. /** Called when the activity is first created. */
  41. @Override
  42. public void onCreate(Bundle savedInstanceState) {
  43. super.onCreate(savedInstanceState);
  44. setContentView(R.layout.main);
  45. //暫停標志位 為false
  46. isPause=false;
  47. //暫停狀態標志位
  48. inThePause=false;
  49. //初始化list
  50. list=new ArrayList<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. // 判斷sd Card是否插入
  65. sdcardExit = Environment.getExternalStorageState().equals(
  66. android.os.Environment.MEDIA_MOUNTED);
  67. // 取得sd card路徑作為錄音文件的位置
  68. if (sdcardExit){
  69. String pathStr = Environment.getExternalStorageDirectory().getPath()+"/YYT";
  70. myRecAudioDir= new File(pathStr);
  71. if(!myRecAudioDir.exists()){
  72. myRecAudioDir.mkdirs();
  73. Log.v("錄音", "創建錄音文件!" + myRecAudioDir.exists());
  74. }
  75. // Environment.getExternalStorageDirectory().getPath() + "/" + PREFIX + "/";
  76. }
  77. // 取得sd card 目錄裡的.arm文件
  78. getRecordFiles();
  79. adapter = new ArrayAdapter<String>(this,
  80. android.R.layout.simple_list_item_1, recordFiles);
  81. // 將ArrayAdater添加ListView對象中
  82. myListView1.setAdapter(adapter);
  83. // 錄音
  84. myButton1.setOnClickListener(new ImageButton.OnClickListener() {
  85. @Override
  86. public void onClick(View v) {
  87. second=0;
  88. minute=0;
  89. list.clear();
  90. // Calendar c=Calendar.getInstance();
  91. // int mMinute1=c.get(Calendar.MINUTE);
  92. sigle = true;
  93. // TODO Auto-generated method stub
  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(new ImageButton.OnClickListener() {
  107. @Override
  108. public void onClick(View v) {
  109. xx=false;
  110. sigle = true;
  111. timer.cancel();
  112. // TODO Auto-generated method stub
  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. DecimalFormat df = new DecimalFormat("#.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. //DecimalFormat df = new DecimalFormat("#.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(new ImageButton.OnClickListener() {
  169. @Override
  170. public void onClick(View v) {
  171. sigle = true;
  172. // TODO Auto-generated method stub
  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(new OnClickListener() {
  193. @Override
  194. public void onClick(View v) {
  195. sigle = true;
  196. // TODO Auto-generated method stub
  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(new OnClickListener() {
  219. @Override
  220. public void onClick(View v) {
  221. // TODO Auto-generated method stub
  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(new AdapterView.OnItemClickListener() {
  244. @Override
  245. public void onItemClick(AdapterView<?> arg, View arg1,
  246. int arg2, long arg3) {
  247. // TODO Auto-generated method stub
  248. // 當有單點擊文件名時將刪除按鈕及播放按鈕Enable
  249. myButton3.setEnabled(true);
  250. myButton4.setEnabled(true);
  251. myPlayFile = new File(myRecAudioDir.getAbsolutePath()
  252. + File.separator
  253. + ((TextView) arg1).getText().toString());
  254. DecimalFormat df = new DecimalFormat("#.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(new Button.OnClickListener() {
  268. @Override
  269. public void onClick(View v) {
  270. // TODO Auto-generated method stub
  271. showSize show = new showSize();
  272. String text = show.showsize();
  273. Toast.makeText(EX07.this, text, Toast.LENGTH_LONG).show();
  274. }
  275. });
  276. }
  277. protected void recodeStop() {
  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. protected void onStop() {
  291. // TODO Auto-generated method stub
  292. if (mMediaRecorder01 != null && !isStopRecord) {
  293. // 停止錄音
  294. mMediaRecorder01.stop();
  295. mMediaRecorder01.release();
  296. mMediaRecorder01 = null;
  297. }
  298. super.onStop();
  299. }
  300. /**
  301. * 獲取目錄下的所有音頻文件
  302. */
  303. private void getRecordFiles() {
  304. // TODO Auto-generated method stub
  305. recordFiles = new ArrayList<String>();
  306. if (sdcardExit) {
  307. File files[] = myRecAudioDir.listFiles();
  308. if (files != null) {
  309. for (int i = 0; i < files.length; i++) {
  310. if (files[i].getName().indexOf(".") >= 0) { // 只取.amr 文件
  311. String fileS = 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. private void openFile(File f) {
  324. Intent intent = new Intent();
  325. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  326. intent.setAction(android.content.Intent.ACTION_VIEW);
  327. String type = getMIMEType(f);
  328. intent.setDataAndType(Uri.fromFile(f), type);
  329. startActivity(intent);
  330. // Uri uri=Uri.fromFile(f);
  331. // MediaPlayer mediaPlayer=MediaPlayer.create(this, uri);
  332. // try {
  333. // mediaPlayer.prepare();
  334. // } catch (IllegalStateException e) {
  335. // // TODO Auto-generated catch block
  336. // e.printStackTrace();
  337. // } catch (IOException e) {
  338. // // TODO Auto-generated catch block
  339. // e.printStackTrace();
  340. // }
  341. // mediaPlayer.start();
  342. }
  343. private String getMIMEType(File f) {
  344. String end = f.getName().substring(f.getName().lastIndexOf(".") + 1,
  345. f.getName().length()).toLowerCase();
  346. String type = "";
  347. if (end.equals("mp3") || end.equals("aac") || end.equals("amr")
  348. || end.equals("mpeg") || end.equals("mp4")) {
  349. type = "audio";
  350. } else if (end.equals("jpg") || end.equals("gif") || end.equals("png")
  351. || end.equals("jpeg")) {
  352. type = "image";
  353. } else {
  354. type = "*";
  355. }
  356. type += "/";
  357. return type;
  358. }
  359. private void start(){
  360. TimerTask timerTask=new TimerTask() {
  361. @Override
  362. public void run() {
  363. // TODO Auto-generated method stub
  364. second++;
  365. if(second>=60){
  366. second=0;
  367. minute++;
  368. }
  369. handler.sendEmptyMessage(1);
  370. }
  371. };
  372. timer=new Timer();
  373. timer.schedule(timerTask, 1000,1000);
  374. try {
  375. if (!sdcardExit) {
  376. Toast.makeText(EX07.this, "請插入SD card",
  377. Toast.LENGTH_LONG).show();
  378. return;
  379. }
  380. String mMinute1=getTime();
  381. Toast.makeText(EX07.this, "當前時間是:"+mMinute1,Toast.LENGTH_LONG).show();
  382. // 創建音頻文件
  383. // myRecAudioFile = File.createTempFile(mMinute1, ".amr",
  384. // myRecAudioDir);
  385. myRecAudioFile=new File(myRecAudioDir,mMinute1+SUFFIX);
  386. mMediaRecorder01 = new MediaRecorder();
  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(new OnInfoListener() {
  402. @Override
  403. public void onInfo(MediaRecorder mr, int what, int extra) {
  404. // TODO Auto-generated method stub
  405. int a=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 (IOException e) {
  415. e.printStackTrace();
  416. }
  417. }
  418. private String getTime(){
  419. SimpleDateFormat formatter = new SimpleDateFormat ("yyyy年MM月dd日HH:mm:ss");
  420. Date curDate=new Date(System.currentTimeMillis());//獲取當前時間
  421. String time = formatter.format(curDate);
  422. System.out.println("當前時間");
  423. return time;
  424. }
  425. Handler handler=new Handler(){
  426. @Override
  427. public void handleMessage(Message msg) {
  428. // TODO Auto-generated method stub
  429. super.handleMessage(msg);
  430. myTextView1.setText("錄音時間:"+minute+":"+second);
  431. }
  432. };
  433. /**
  434. * @param isAddLastRecord 是否需要添加list之外的最新錄音,一起合並
  435. * @return 將合並的流用字符保存
  436. */
  437. public void getInputCollection(List list,boolean isAddLastRecord){
  438. String mMinute1=getTime();
  439. Toast.makeText(EX07.this, "當前時間是:"+mMinute1,Toast.LENGTH_LONG).show();
  440. // 創建音頻文件,合並的文件放這裡
  441. File file1=new File(myRecAudioDir,mMinute1+SUFFIX);
  442. FileOutputStream fileOutputStream = null;
  443. if(!file1.exists()){
  444. try {
  445. file1.createNewFile();
  446. } catch (IOException e) {
  447. // TODO Auto-generated catch block
  448. e.printStackTrace();
  449. }
  450. }
  451. try {
  452. fileOutputStream=new FileOutputStream(file1);
  453. } catch (IOException e) {
  454. // TODO Auto-generated catch block
  455. e.printStackTrace();
  456. }
  457. //list裡面為暫停錄音 所產生的 幾段錄音文件的名字,中間幾段文件的減去前面的6個字節頭文件
  458. for(int i=0;i<list.size();i++){
  459. File file=new File((String) list.get(i));
  460. Log.d("list的長度", list.size()+"");
  461. try {
  462. FileInputStream fileInputStream=new FileInputStream(file);
  463. byte []myByte=new byte[fileInputStream.available()];
  464. //文件長度
  465. int length = 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 (Exception e) {
  482. // TODO Auto-generated catch block
  483. e.printStackTrace();
  484. }
  485. }
  486. //結束後關閉流
  487. try {
  488. fileOutputStream.close();
  489. } catch (IOException e) {
  490. // TODO Auto-generated catch block
  491. e.printStackTrace();
  492. }
  493. //加上當前正在錄音的這一段
  494. // if(isAddLastRecord){
  495. //
  496. //
  497. // //剛剛錄音的
  498. // try {
  499. // FileInputStream fileInputStream=new FileInputStream(myRecAudioFile);
  500. // byte []myByte=new byte[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 (Exception e) {
  512. // // TODO Auto-generated catch block
  513. // e.printStackTrace();
  514. // }
  515. //
  516. // }
  517. //合成一個文件後,刪除之前暫停錄音所保存的零碎合成文件
  518. deleteListRecord(isAddLastRecord);
  519. //
  520. adapter.add(file1.getName());
  521. }
  522. private void deleteListRecord(boolean isAddLastRecord){
  523. for(int i=0;i<list.size();i++){
  524. File file=new File((String) list.get(i));
  525. if(file.exists()){
  526. file.delete();
  527. }
  528. }
  529. //正在暫停後,繼續錄音的這一段音頻文件
  530. if(isAddLastRecord){
  531. myRecAudioFile.delete();
  532. }
  533. }
  534. }
Copyright © Linux教程網 All Rights Reserved