Android利用AudioRecord類實現(xiàn)音頻錄制程序
AudioRecord類相對于MediaRecorder來說,更加接近底層,為我們封裝的方法也更少。然而實現(xiàn)一個AudioRecord的音頻錄制程序也很簡單。本實例代碼如下:
package demo.camera; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import android.app.Activity; import android.content.ContentValues; import android.content.Intent; import android.hardware.Camera.AutoFocusCallback; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioRecord; import android.media.AudioTrack; import android.media.MediaPlayer; import android.media.MediaRecorder; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; /** * 該實例中,我們使用AudioRecord類來完成我們的音頻錄制程序 * AudioRecord類,我們可以使用三種不同的read方法來完成錄制工作, * 每種方法都有其實用的場合 * 一、實例化一個AudioRecord類我們需要傳入幾種參數(shù) * 1、AudioSource:這里可以是MediaRecorder.AudioSource.MIC * 2、SampleRateInHz:錄制頻率,可以為8000hz或者11025hz等,不同的硬件設(shè)備這個值不同 * 3、ChannelConfig:錄制通道,可以為AudioFormat.CHANNEL_CONFIGURATION_MONO和AudioFormat.CHANNEL_CONFIGURATION_STEREO * 4、AudioFormat:錄制編碼格式,可以為AudioFormat.ENCODING_16BIT和8BIT,其中16BIT的仿真性比8BIT好,但是需要消耗更多的電量和存儲空間 * 5、BufferSize:錄制緩沖大?。嚎梢酝ㄟ^getMinBufferSize來獲取 * 這樣我們就可以實例化一個AudioRecord對象了 * 二、創(chuàng)建一個文件,用于保存錄制的內(nèi)容 * 同上篇 * 三、打開一個輸出流,指向創(chuàng)建的文件 * DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))) * 四、現(xiàn)在就可以開始錄制了,我們需要創(chuàng)建一個字節(jié)數(shù)組來存儲從AudioRecorder中返回的音頻數(shù)據(jù),但是 * 注意,我們定義的數(shù)組要小于定義AudioRecord時指定的那個BufferSize * short[]buffer = new short[BufferSize/4]; * startRecording(); * 然后一個循環(huán),調(diào)用AudioRecord的read方法實現(xiàn)讀取 * 另外使用MediaPlayer是無法播放使用AudioRecord錄制的音頻的,為了實現(xiàn)播放,我們需要 * 使用AudioTrack類來實現(xiàn) * AudioTrack類允許我們播放原始的音頻數(shù)據(jù) * * * 一、實例化一個AudioTrack同樣要傳入幾個參數(shù) * 1、StreamType:在AudioManager中有幾個常量,其中一個是STREAM_MUSIC; * 2、SampleRateInHz:最好和AudioRecord使用的是同一個值 * 3、ChannelConfig:同上 * 4、AudioFormat:同上 * 5、BufferSize:通過AudioTrack的靜態(tài)方法getMinBufferSize來獲取 * 6、Mode:可以是AudioTrack.MODE_STREAM和MODE_STATIC,關(guān)于這兩種不同之處,可以查閱文檔 * 二、打開一個輸入流,指向剛剛錄制內(nèi)容保存的文件,然后開始播放,邊讀取邊播放 * * 實現(xiàn)時,音頻的錄制和播放分別使用兩個AsyncTask來完成 */ public class MyAudioRecord2 extends Activity{ private TextView stateView; private Button btnStart,btnStop,btnPlay,btnFinish; private RecordTask recorder; private PlayTask player; private File audioFile; private boolean isRecording=true, isPlaying=false; //標(biāo)記 private int frequence = 8000; //錄制頻率,單位hz.這里的值注意了,寫的不好,可能實例化AudioRecord對象的時候,會出錯。我開始寫成11025就不行。這取決于硬件設(shè)備 private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO; private int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.my_audio_record); stateView = (TextView)this.findViewById(R.id.view_state); stateView.setText("準(zhǔn)備開始"); btnStart = (Button)this.findViewById(R.id.btn_start); btnStop = (Button)this.findViewById(R.id.btn_stop); btnPlay = (Button)this.findViewById(R.id.btn_play); btnFinish = (Button)this.findViewById(R.id.btn_finish); btnFinish.setText("停止播放"); btnStop.setEnabled(false); btnPlay.setEnabled(false); btnFinish.setEnabled(false); //在這里我們創(chuàng)建一個文件,用于保存錄制內(nèi)容 File fpath = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/data/files/"); fpath.mkdirs();//創(chuàng)建文件夾 try { //創(chuàng)建臨時文件,注意這里的格式為.pcm audioFile = File.createTempFile("recording", ".pcm", fpath); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void onClick(View v){ int id = v.getId(); switch(id){ case R.id.btn_start: //開始錄制 //這里啟動錄制任務(wù) recorder = new RecordTask(); recorder.execute(); break; case R.id.btn_stop: //停止錄制 this.isRecording = false; //更新狀態(tài) //在錄制完成時設(shè)置,在RecordTask的onPostExecute中完成 break; case R.id.btn_play: player = new PlayTask(); player.execute(); break; case R.id.btn_finish: //完成播放 this.isPlaying = false; break; } } class RecordTask extends AsyncTask<Void, Integer, Void>{ @Override protected Void doInBackground(Void... arg0) { isRecording = true; try { //開通輸出流到指定的文件 DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(audioFile))); //根據(jù)定義好的幾個配置,來獲取合適的緩沖大小 int bufferSize = AudioRecord.getMinBufferSize(frequence, channelConfig, audioEncoding); //實例化AudioRecord AudioRecord record = new AudioRecord(MediaRecorder.AudioSource.MIC, frequence, channelConfig, audioEncoding, bufferSize); //定義緩沖 short[] buffer = new short[bufferSize]; //開始錄制 record.startRecording(); int r = 0; //存儲錄制進度 //定義循環(huán),根據(jù)isRecording的值來判斷是否繼續(xù)錄制 while(isRecording){ //從bufferSize中讀取字節(jié),返回讀取的short個數(shù) //這里老是出現(xiàn)buffer overflow,不知道是什么原因,試了好幾個值,都沒用,TODO:待解決 int bufferReadResult = record.read(buffer, 0, buffer.length); //循環(huán)將buffer中的音頻數(shù)據(jù)寫入到OutputStream中 for(int i=0; i<bufferReadResult; i++){ dos.writeShort(buffer[i]); } publishProgress(new Integer(r)); //向UI線程報告當(dāng)前進度 r++; //自增進度值 } //錄制結(jié)束 record.stop(); Log.v("The DOS available:", "::"+audioFile.length()); dos.close(); } catch (Exception e) { // TODO: handle exception } return null; } //當(dāng)在上面方法中調(diào)用publishProgress時,該方法觸發(fā),該方法在UI線程中被執(zhí)行 protected void onProgressUpdate(Integer...progress){ stateView.setText(progress[0].toString()); } protected void onPostExecute(Void result){ btnStop.setEnabled(false); btnStart.setEnabled(true); btnPlay.setEnabled(true); btnFinish.setEnabled(false); } protected void onPreExecute(){ //stateView.setText("正在錄制"); btnStart.setEnabled(false); btnPlay.setEnabled(false); btnFinish.setEnabled(false); btnStop.setEnabled(true); } } class PlayTask extends AsyncTask<Void, Integer, Void>{ @Override protected Void doInBackground(Void... arg0) { isPlaying = true; int bufferSize = AudioTrack.getMinBufferSize(frequence, channelConfig, audioEncoding); short[] buffer = new short[bufferSize/4]; try { //定義輸入流,將音頻寫入到AudioTrack類中,實現(xiàn)播放 DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(audioFile))); //實例AudioTrack AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, frequence, channelConfig, audioEncoding, bufferSize, AudioTrack.MODE_STREAM); //開始播放 track.play(); //由于AudioTrack播放的是流,所以,我們需要一邊播放一邊讀取 while(isPlaying && dis.available()>0){ int i = 0; while(dis.available()>0 && i<buffer.length){ buffer[i] = dis.readShort(); i++; } //然后將數(shù)據(jù)寫入到AudioTrack中 track.write(buffer, 0, buffer.length); } //播放結(jié)束 track.stop(); dis.close(); } catch (Exception e) { // TODO: handle exception } return null; } protected void onPostExecute(Void result){ btnPlay.setEnabled(true); btnFinish.setEnabled(false); btnStart.setEnabled(true); btnStop.setEnabled(false); } protected void onPreExecute(){ //stateView.setText("正在播放"); btnStart.setEnabled(false); btnStop.setEnabled(false); btnPlay.setEnabled(false); btnFinish.setEnabled(true); } } }
可惜,本實例測試時有個問題,在錄制的時候,會出現(xiàn)buffer over。緩存泄露,待解決。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
基于Android應(yīng)用中如何反饋Crash報告的詳解
本篇文章是對在Android應(yīng)用中如何反饋Crash報告的詳細(xì)分析介紹。需要的朋友參考下2013-05-05Android ListView數(shù)據(jù)的分批顯示功能
本文通過實例代碼給大家分享了Android ListView數(shù)據(jù)的分批顯示功能,非常不錯具有參考借鑒價值,需要的朋友參考下吧2017-04-04android輸入框內(nèi)容改變的監(jiān)聽事件實例
下面小編就為大家分享一篇android輸入框內(nèi)容改變的監(jiān)聽事件實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-02-02Android應(yīng)用實踐之?dāng)?shù)獨游戲開發(fā)
這篇文章主要為大家詳細(xì)介紹了Android應(yīng)用實踐之?dāng)?shù)獨游戲開發(fā),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-12-12Android.mk引入第三方j(luò)ar包和so庫文件的方法
這篇文章主要介紹了Android.mk引入第三方j(luò)ar包和so庫文件的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05Android開發(fā)使用HttpURLConnection進行網(wǎng)絡(luò)編程詳解【附源碼下載】
這篇文章主要介紹了Android開發(fā)使用HttpURLConnection進行網(wǎng)絡(luò)編程的方法,結(jié)合實例形式分析了Android基于HttpURLConnection實現(xiàn)顯示圖片與文本功能,涉及Android布局、文本解析、數(shù)據(jù)傳輸、權(quán)限控制等相關(guān)操作技巧,需要的朋友可以參考下2018-01-01