Speex語音壓縮和消除回聲
阿新 • • 發佈:2019-01-02
/** * 錄音類 */ public class AudioRecordUtil { private AudioRecord audioRecord; private final static int AUDIO_SOURCE= MediaRecorder.AudioSource.MIC;//錄取源 private final static int SAMPLE_RATE=8000;//取樣率 private final static int CHANNEL_CONFIG= AudioFormat.CHANNEL_IN_MONO;//聲道配置,和日常左右聲道的意思一樣 private final static intAUDIO_FORMAT=AudioFormat.ENCODING_PCM_16BIT;//音訊量化所採用的方案 private int minBufferSize;//最小的快取長度 private boolean isRecord=false;//用於標誌迴圈中是否錄音 private int audioFrame; private Speex speex; private OnAudioStreamCallback onAudioStreamCallback; public void setOnAudioStreamCallback(OnAudioStreamCallback onAudioStreamCallback) { this.onAudioStreamCallback = onAudioStreamCallback; } public AudioRecordUtil(){ minBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE,CHANNEL_CONFIG,AUDIO_FORMAT);//獲取最小的快取長度 // audioRecord = new AudioRecord(AUDIO_SOURCE, SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT, minBufferSize);//新建AudioRecord物件audioRecord= EchoCancel.createAudioRecorder(SAMPLE_RATE,CHANNEL_CONFIG,AUDIO_FORMAT,minBufferSize); speex = new Speex(); speex.init(); audioFrame=speex.getFrameSize(); startRecord(); } public synchronized void startRecord(){ if(!isRecord){ isRecord=true; audioRecord.startRecording();//開始錄音 new Thread(recordRunnable).start();//啟動錄音執行緒 } } public synchronized void stopRecord(){ if(isRecord){ isRecord=false; audioRecord.stop();//停止錄音 } } Runnable recordRunnable = new Runnable() { @Override public void run() { while (isRecord){ /******************錄音(start)*************************/ short[] audioData = new short[audioFrame];//新建陣列用於保存錄音資料; int readSize=audioRecord.read(audioData, 0, audioFrame); /******************錄音(end)*************************/ /*************音訊編碼壓縮(start)*******************/ byte encodeData[] = new byte[audioFrame]; readSize = speex.echoCancellationEncode(audioData,encodeData);//進行回聲消除和壓縮 /*************音訊編碼壓縮(end)*******************/ if(onAudioStreamCallback!=null){ onAudioStreamCallback.onAudioStream(encodeData,readSize); } } } }; public interface OnAudioStreamCallback{ void onAudioStream(byte audioData[],int len); }
}
/** * 播放類 */ public class AudioTrackUtil { private AudioTrack audioTrack; private final static int STREAM_TYPE= AudioManager.STREAM_MUSIC;//播放方式 private final static int SAMPLE_RATE=8000;//取樣率 private final static int CHANNEL_CONFIG= AudioFormat.CHANNEL_OUT_MONO;//聲道配置,和日常左右聲道的意思一樣 private final static int AUDIO_FORMAT=AudioFormat.ENCODING_PCM_16BIT;//音訊量化所採用的方案 private final static int MODE=AudioTrack.MODE_STREAM;//播放模式 private int minBufferSize;//快取音訊的最小尺寸 private boolean isPlay=false; private Queue<AudioData> audioDataQueue=new LinkedList<>(); private Speex speex; private int audioFrame; public AudioTrackUtil(Context context){ minBufferSize=AudioTrack.getMinBufferSize(SAMPLE_RATE,CHANNEL_CONFIG,AUDIO_FORMAT); // audioTrack = new AudioTrack(STREAM_TYPE,SAMPLE_RATE,CHANNEL_CONFIG,AUDIO_FORMAT,minBufferSize,MODE); audioTrack = EchoCancel.createAudioTrack(SAMPLE_RATE,CHANNEL_CONFIG,AUDIO_FORMAT,minBufferSize); if (audioTrack!=null) { EchoCancel.setplayertospeaker(context); } speex = new Speex(); speex.init(); audioFrame = speex.getFrameSize(); startPlay(); } public void startPlay(){ if(!isPlay){ isPlay=true; audioTrack.play(); new Thread(playRunnable).start(); } } public void stopPlay(){ if(isPlay){ isPlay = false; audioTrack.stop(); } } public void write( byte[] audioData, int offsetInBytes, int sizeInBytes){ AudioData data = new AudioData(); data.setData(audioData); data.setLen(sizeInBytes); audioDataQueue.offer(data); } Runnable playRunnable=new Runnable() { @Override public void run() { while (isPlay){ if(audioDataQueue!=null&&audioDataQueue.size()>0){ /**************讀取資料(start)*********************/ AudioData data =audioDataQueue.poll(); if (data==null) { continue; } /**************讀取資料(end)*********************/ /*************解碼資料(start)**********************/ short[] decodeData=new short[audioFrame]; int size=speex.decode(data.getData(),decodeData,data.getLen());//資料進行解碼 /*************解碼資料(end)**********************/ speex.capture(decodeData);//採集回聲,用於回聲消除 audioTrack.write(decodeData,0,decodeData.length); } } } }; }