Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android多媒體學習十:利用AudioRecord類實現自己的音頻錄制程序

Android多媒體學習十:利用AudioRecord類實現自己的音頻錄制程序

編輯:Android開發實例

AudioRecord類相對於MediaRecorder來說,更加接近底層,為我們封裝的方法也更少。然而實現一個AudioRecord的音頻錄制程序也很

簡單。本實例代碼如下:

可惜,本實例測試時有個問題,在錄制的時候,會出現buffer over。緩存洩露,待解決。

 

  1. package demo.camera;  
  2. import java.io.BufferedInputStream;  
  3. import java.io.BufferedOutputStream;  
  4. import java.io.DataInputStream;  
  5. import java.io.DataOutputStream;  
  6. import java.io.File;  
  7. import java.io.FileInputStream;  
  8. import java.io.FileOutputStream;  
  9. import java.io.IOException;  
  10. import android.app.Activity;  
  11. import android.content.ContentValues;  
  12. import android.content.Intent;  
  13. import android.hardware.Camera.AutoFocusCallback;  
  14. import android.media.AudioFormat;  
  15. import android.media.AudioManager;  
  16. import android.media.AudioRecord;  
  17. import android.media.AudioTrack;  
  18. import android.media.MediaPlayer;  
  19. import android.media.MediaRecorder;  
  20. import android.net.Uri;  
  21. import android.os.AsyncTask;  
  22. import android.os.Bundle;  
  23. import android.os.Environment;  
  24. import android.provider.MediaStore;  
  25. import android.util.Log;  
  26. import android.view.View;  
  27. import android.widget.Button;  
  28. import android.widget.TextView;  
  29. /**  
  30.  * 該實例中,我們使用AudioRecord類來完成我們的音頻錄制程序  
  31.  * AudioRecord類,我們可以使用三種不同的read方法來完成錄制工作,  
  32.  * 每種方法都有其實用的場合  
  33.  * 一、實例化一個AudioRecord類我們需要傳入幾種參數  
  34.  * 1、AudioSource:這裡可以是MediaRecorder.AudioSource.MIC  
  35.  * 2、SampleRateInHz:錄制頻率,可以為8000hz或者11025hz等,不同的硬件設備這個值不同  
  36.  * 3、ChannelConfig:錄制通道,可以為AudioFormat.CHANNEL_CONFIGURATION_MONO和AudioFormat.CHANNEL_CONFIGURATION_STEREO  
  37.  * 4、AudioFormat:錄制編碼格式,可以為AudioFormat.ENCODING_16BIT和8BIT,其中16BIT的仿真性比8BIT好,但是需要消耗更多的電量和存儲空間  
  38.  * 5、BufferSize:錄制緩沖大小:可以通過getMinBufferSize來獲取  
  39.  * 這樣我們就可以實例化一個AudioRecord對象了  
  40.  * 二、創建一個文件,用於保存錄制的內容  
  41.  * 同上篇  
  42.  * 三、打開一個輸出流,指向創建的文件  
  43.  * DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)))  
  44.  * 四、現在就可以開始錄制了,我們需要創建一個字節數組來存儲從AudioRecorder中返回的音頻數據,但是  
  45.  * 注意,我們定義的數組要小於定義AudioRecord時指定的那個BufferSize  
  46.  * short[]buffer = new short[BufferSize/4];  
  47.  * startRecording();  
  48.  * 然後一個循環,調用AudioRecord的read方法實現讀取  
  49.  * 另外使用MediaPlayer是無法播放使用AudioRecord錄制的音頻的,為了實現播放,我們需要  
  50.  * 使用AudioTrack類來實現  
  51.  * AudioTrack類允許我們播放原始的音頻數據  
  52.  *   
  53.  *   
  54.  * 一、實例化一個AudioTrack同樣要傳入幾個參數  
  55.  * 1、StreamType:在AudioManager中有幾個常量,其中一個是STREAM_MUSIC;  
  56.  * 2、SampleRateInHz:最好和AudioRecord使用的是同一個值  
  57.  * 3、ChannelConfig:同上  
  58.  * 4、AudioFormat:同上  
  59.  * 5、BufferSize:通過AudioTrack的靜態方法getMinBufferSize來獲取  
  60.  * 6、Mode:可以是AudioTrack.MODE_STREAM和MODE_STATIC,關於這兩種不同之處,可以查閱文檔  
  61.  * 二、打開一個輸入流,指向剛剛錄制內容保存的文件,然後開始播放,邊讀取邊播放  
  62.  *   
  63.  * 實現時,音頻的錄制和播放分別使用兩個AsyncTask來完成   
  64.  */ 
  65. public class MyAudioRecord2 extends Activity{  
  66.       
  67.     private TextView stateView;  
  68.       
  69.     private Button btnStart,btnStop,btnPlay,btnFinish;  
  70.       
  71.     private RecordTask recorder;  
  72.     private PlayTask player;  
  73.       
  74.     private File audioFile;  
  75.       
  76.     private boolean isRecording=true, isPlaying=false; //標記  
  77.       
  78.     private int frequence = 8000; //錄制頻率,單位hz.這裡的值注意了,寫的不好,可能實例化AudioRecord對象的時候,會出錯。我開始寫成11025就不行。這取決於硬件設備  
  79.     private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;  
  80.     private int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;  
  81.       
  82.       
  83.     public void onCreate(Bundle savedInstanceState){  
  84.         super.onCreate(savedInstanceState);  
  85.         setContentView(R.layout.my_audio_record);  
  86.           
  87.         stateView = (TextView)this.findViewById(R.id.view_state);  
  88.         stateView.setText("准備開始");  
  89.         btnStart = (Button)this.findViewById(R.id.btn_start);  
  90.         btnStop = (Button)this.findViewById(R.id.btn_stop);  
  91.         btnPlay = (Button)this.findViewById(R.id.btn_play);  
  92.         btnFinish = (Button)this.findViewById(R.id.btn_finish);  
  93.         btnFinish.setText("停止播放");  
  94.         btnStop.setEnabled(false);  
  95.         btnPlay.setEnabled(false);  
  96.         btnFinish.setEnabled(false);  
  97.           
  98.         //在這裡我們創建一個文件,用於保存錄制內容  
  99.         File fpath = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/data/files/");  
  100.         fpath.mkdirs();//創建文件夾  
  101.         try {  
  102.             //創建臨時文件,注意這裡的格式為.pcm  
  103.             audioFile = File.createTempFile("recording", ".pcm", fpath);  
  104.         } catch (IOException e) {  
  105.             // TODO Auto-generated catch block  
  106.             e.printStackTrace();  
  107.         }         
  108.     }  
  109.       
  110.       
  111.     public void onClick(View v){  
  112.         int id = v.getId();  
  113.         switch(id){  
  114.         case R.id.btn_start:  
  115.             //開始錄制  
  116.               
  117.             //這裡啟動錄制任務  
  118.             recorder = new RecordTask();  
  119.             recorder.execute();  
  120.               
  121.             break;  
  122.         case R.id.btn_stop:  
  123.             //停止錄制  
  124.             this.isRecording = false;  
  125.             //更新狀態  
  126.             //在錄制完成時設置,在RecordTask的onPostExecute中完成  
  127.             break;  
  128.         case R.id.btn_play:  
  129.               
  130.             player = new PlayTask();  
  131.             player.execute();  
  132.             break;  
  133.         case R.id.btn_finish:  
  134.             //完成播放  
  135.             this.isPlaying = false;  
  136.             break;  
  137.               
  138.         }  
  139.     }  
  140.       
  141.     class RecordTask extends AsyncTask<Void, Integer, Void>{  
  142.         @Override 
  143.         protected Void doInBackground(Void... arg0) {  
  144.             isRecording = true;  
  145.             try {  
  146.                 //開通輸出流到指定的文件  
  147.                 DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(audioFile)));  
  148.                 //根據定義好的幾個配置,來獲取合適的緩沖大小  
  149.                 int bufferSize = AudioRecord.getMinBufferSize(frequence, channelConfig, audioEncoding);  
  150.                 //實例化AudioRecord  
  151.                 AudioRecord record = new AudioRecord(MediaRecorder.AudioSource.MIC, frequence, channelConfig, audioEncoding, bufferSize);  
  152.                 //定義緩沖  
  153.                 short[] buffer = new short[bufferSize];  
  154.                   
  155.                 //開始錄制  
  156.                 record.startRecording();  
  157.                   
  158.                 int r = 0; //存儲錄制進度  
  159.                 //定義循環,根據isRecording的值來判斷是否繼續錄制  
  160.                 while(isRecording){  
  161.                     //從bufferSize中讀取字節,返回讀取的short個數  
  162.                     //這裡老是出現buffer overflow,不知道是什麼原因,試了好幾個值,都沒用,TODO:待解決  
  163.                     int bufferReadResult = record.read(buffer, 0, buffer.length);  
  164.                     //循環將buffer中的音頻數據寫入到OutputStream中  
  165.                     for(int i=0; i<bufferReadResult; i++){  
  166.                         dos.writeShort(buffer[i]);  
  167.                     }  
  168.                     publishProgress(new Integer(r)); //向UI線程報告當前進度  
  169.                     r++; //自增進度值  
  170.                 }  
  171.                 //錄制結束  
  172.                 record.stop();  
  173.                 Log.v("The DOS available:", "::"+audioFile.length());  
  174.                 dos.close();  
  175.             } catch (Exception e) {  
  176.                 // TODO: handle exception  
  177.             }  
  178.             return null;  
  179.         }  
  180.           
  181.         //當在上面方法中調用publishProgress時,該方法觸發,該方法在UI線程中被執行  
  182.         protected void onProgressUpdate(Integer...progress){  
  183.             stateView.setText(progress[0].toString());  
  184.         }  
  185.           
  186.         protected void onPostExecute(Void result){  
  187.             btnStop.setEnabled(false);  
  188.             btnStart.setEnabled(true);  
  189.             btnPlay.setEnabled(true);  
  190.             btnFinish.setEnabled(false);  
  191.         }  
  192.           
  193.         protected void onPreExecute(){  
  194.             //stateView.setText("正在錄制");  
  195.             btnStart.setEnabled(false);  
  196.             btnPlay.setEnabled(false);  
  197.             btnFinish.setEnabled(false);  
  198.             btnStop.setEnabled(true);         
  199.         }  
  200.           
  201.     }  
  202.       
  203.     class PlayTask extends AsyncTask<Void, Integer, Void>{  
  204.         @Override 
  205.         protected Void doInBackground(Void... arg0) {  
  206.             isPlaying = true;  
  207.             int bufferSize = AudioTrack.getMinBufferSize(frequence, channelConfig, audioEncoding);  
  208.             short[] buffer = new short[bufferSize/4];  
  209.             try {  
  210.                 //定義輸入流,將音頻寫入到AudioTrack類中,實現播放  
  211.                 DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(audioFile)));  
  212.                 //實例AudioTrack  
  213.                 AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, frequence, channelConfig, audioEncoding, bufferSize, AudioTrack.MODE_STREAM);  
  214.                 //開始播放  
  215.                 track.play();  
  216.                 //由於AudioTrack播放的是流,所以,我們需要一邊播放一邊讀取  
  217.                 while(isPlaying && dis.available()>0){  
  218.                     int i = 0;  
  219.                     while(dis.available()>0 && i<buffer.length){  
  220.                         buffer[i] = dis.readShort();  
  221.                         i++;  
  222.                     }  
  223.                     //然後將數據寫入到AudioTrack中  
  224.                     track.write(buffer, 0, buffer.length);  
  225.                       
  226.                 }  
  227.                   
  228.                 //播放結束  
  229.                 track.stop();  
  230.                 dis.close();  
  231.             } catch (Exception e) {  
  232.                 // TODO: handle exception  
  233.             }  
  234.             return null;  
  235.         }  
  236.           
  237.         protected void onPostExecute(Void result){  
  238.             btnPlay.setEnabled(true);  
  239.             btnFinish.setEnabled(false);  
  240.             btnStart.setEnabled(true);  
  241.             btnStop.setEnabled(false);  
  242.         }  
  243.           
  244.         protected void onPreExecute(){    
  245.               
  246.             //stateView.setText("正在播放");  
  247.             btnStart.setEnabled(false);  
  248.             btnStop.setEnabled(false);  
  249.             btnPlay.setEnabled(false);  
  250.             btnFinish.setEnabled(true);           
  251.         }  
  252.           
  253.     }  
  254. }  

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved