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等之類的格式,合成的原理大同小異,隻需要註意他們的音頻文件頭的格式就可以瞭。)

 

 

 

有圖有真相:

 

 

 

 

 

 

[java]
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. */ 
    @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=0; 
            minute=0; 
                 
            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() <= 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() { 
 
            @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() <= 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() { 
 
            @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 = 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() { 
             
            @Override 
            public void run() { 
                // TODO Auto-generated method stub  
                second++; 
                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; 
            } 
            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, 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(){ 
 
        @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=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 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=0;i<list.size();i++){ 
            File file=new File((String) list.get(i)); 
            if(file.exists()){ 
                file.delete(); 
            } 
        } 
        //正在暫停後,繼續錄音的這一段音頻文件  
        if(isAddLastRecord){ 
            myRecAudioFile.delete(); 
        } 
    } 

 

發佈留言