您好,登錄后才能下訂單哦!
AudioRecord類相對(duì)于MediaRecorder來說,更加接近底層,為我們封裝的方法也更少。然而實(shí)現(xiàn)一個(gè)AudioRecord的音頻錄制程序也很簡(jiǎn)單。本實(shí)例代碼如下:
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; /** * 該實(shí)例中,我們使用AudioRecord類來完成我們的音頻錄制程序 * AudioRecord類,我們可以使用三種不同的read方法來完成錄制工作, * 每種方法都有其實(shí)用的場(chǎng)合 * 一、實(shí)例化一個(gè)AudioRecord類我們需要傳入幾種參數(shù) * 1、AudioSource:這里可以是MediaRecorder.AudioSource.MIC * 2、SampleRateInHz:錄制頻率,可以為8000hz或者11025hz等,不同的硬件設(shè)備這個(gè)值不同 * 3、ChannelConfig:錄制通道,可以為AudioFormat.CHANNEL_CONFIGURATION_MONO和AudioFormat.CHANNEL_CONFIGURATION_STEREO * 4、AudioFormat:錄制編碼格式,可以為AudioFormat.ENCODING_16BIT和8BIT,其中16BIT的仿真性比8BIT好,但是需要消耗更多的電量和存儲(chǔ)空間 * 5、BufferSize:錄制緩沖大小:可以通過getMinBufferSize來獲取 * 這樣我們就可以實(shí)例化一個(gè)AudioRecord對(duì)象了 * 二、創(chuàng)建一個(gè)文件,用于保存錄制的內(nèi)容 * 同上篇 * 三、打開一個(gè)輸出流,指向創(chuàng)建的文件 * DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))) * 四、現(xiàn)在就可以開始錄制了,我們需要?jiǎng)?chuàng)建一個(gè)字節(jié)數(shù)組來存儲(chǔ)從AudioRecorder中返回的音頻數(shù)據(jù),但是 * 注意,我們定義的數(shù)組要小于定義AudioRecord時(shí)指定的那個(gè)BufferSize * short[]buffer = new short[BufferSize/4]; * startRecording(); * 然后一個(gè)循環(huán),調(diào)用AudioRecord的read方法實(shí)現(xiàn)讀取 * 另外使用MediaPlayer是無法播放使用AudioRecord錄制的音頻的,為了實(shí)現(xiàn)播放,我們需要 * 使用AudioTrack類來實(shí)現(xiàn) * AudioTrack類允許我們播放原始的音頻數(shù)據(jù) * * * 一、實(shí)例化一個(gè)AudioTrack同樣要傳入幾個(gè)參數(shù) * 1、StreamType:在AudioManager中有幾個(gè)常量,其中一個(gè)是STREAM_MUSIC; * 2、SampleRateInHz:最好和AudioRecord使用的是同一個(gè)值 * 3、ChannelConfig:同上 * 4、AudioFormat:同上 * 5、BufferSize:通過AudioTrack的靜態(tài)方法getMinBufferSize來獲取 * 6、Mode:可以是AudioTrack.MODE_STREAM和MODE_STATIC,關(guān)于這兩種不同之處,可以查閱文檔 * 二、打開一個(gè)輸入流,指向剛剛錄制內(nèi)容保存的文件,然后開始播放,邊讀取邊播放 * * 實(shí)現(xiàn)時(shí),音頻的錄制和播放分別使用兩個(gè)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.這里的值注意了,寫的不好,可能實(shí)例化AudioRecord對(duì)象的時(shí)候,會(huì)出錯(cuò)。我開始寫成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)建一個(gè)文件,用于保存錄制內(nèi)容 File fpath = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/data/files/"); fpath.mkdirs();//創(chuàng)建文件夾 try { //創(chuàng)建臨時(shí)文件,注意這里的格式為.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: //開始錄制 //這里啟動(dòng)錄制任務(wù) recorder = new RecordTask(); recorder.execute(); break; case R.id.btn_stop: //停止錄制 this.isRecording = false; //更新狀態(tài) //在錄制完成時(shí)設(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ù)定義好的幾個(gè)配置,來獲取合適的緩沖大小 int bufferSize = AudioRecord.getMinBufferSize(frequence, channelConfig, audioEncoding); //實(shí)例化AudioRecord AudioRecord record = new AudioRecord(MediaRecorder.AudioSource.MIC, frequence, channelConfig, audioEncoding, bufferSize); //定義緩沖 short[] buffer = new short[bufferSize]; //開始錄制 record.startRecording(); int r = 0; //存儲(chǔ)錄制進(jìn)度 //定義循環(huán),根據(jù)isRecording的值來判斷是否繼續(xù)錄制 while(isRecording){ //從bufferSize中讀取字節(jié),返回讀取的short個(gè)數(shù) //這里老是出現(xiàn)buffer overflow,不知道是什么原因,試了好幾個(gè)值,都沒用,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線程報(bào)告當(dāng)前進(jìn)度 r++; //自增進(jìn)度值 } //錄制結(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時(shí),該方法觸發(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類中,實(shí)現(xiàn)播放 DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(audioFile))); //實(shí)例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); } } }
可惜,本實(shí)例測(cè)試時(shí)有個(gè)問題,在錄制的時(shí)候,會(huì)出現(xiàn)buffer over。緩存泄露,待解決。
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。