回音消除Google 开发文档原文:
/**
* Acoustic Echo Canceler (AEC).
* <p>Acoustic Echo Canceler (AEC) is an audio pre-processor which removes the contribution of the
* signal received from the remote party from the captured audio signal.
* <p>AEC is used by voice communication applications (voice chat, video conferencing, SIP calls)
* where the presence of echo with significant delay in the signal received from the remote party
* is highly disturbing. AEC is often used in conjunction with noise suppression (NS).
* <p>An application creates an AcousticEchoCanceler object to instantiate and control an AEC
* engine in the audio capture path.
* <p>To attach the AcousticEchoCanceler to a particular {@link android.media.AudioRecord},
* specify the audio session ID of this AudioRecord when creating the AcousticEchoCanceler.
* The audio session is retrieved by calling
* {@link android.media.AudioRecord#getAudioSessionId()} on the AudioRecord instance.
* <p>On some devices, an AEC can be inserted by default in the capture path by the platform
* according to the {@link android.media.MediaRecorder.AudioSource} used. The application should
* call AcousticEchoCanceler.getEnable() after creating the AEC to check the default AEC activation
* state on a particular AudioRecord session.
* <p>See {@link android.media.audiofx.AudioEffect} class for more details on
* controlling audio effects.
*/
场景就是在手机播放声音和声音录制同时进行,但是手机播放的声音不会被本机录制,达到了消除的效果。微信对讲的最适合不过了,但是微信的回音消除好像是不是自己弄的。
文档大致意思:创建android.media.AudioRecord 的对象的时候,可以通过这个对象获取到一个audio session 的ID(获取的方法:getAudioSessionId()),这个ID的话在创建AcousticEchoCanceler的时候用到(创建对象:AcousticEchoCanceler.create(audioSessionId)),最后播放音频的时候(这里是用AudioTrack播放)传入这个ID就行了。
首先创建AudioRecord。这里就不啰嗦里面的参数是干嘛的了,可以自己查资料知道什么是采样率,声道,位数。
private AudioRecord mRecorder;
private byte[] pcm;
private int mRecorderBufferSize;
/**
* 初始化录音
*/
public void initRecorder() {
mRecorderBufferSize = AudioRecord.getMinBufferSize(8000,
AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
pcm = new byte[320];
mRecorder = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
mRecorderBufferSize);
}
初始化AudioTrack(注意下传入的audioSessionId)。
private AudioTrack mAudioTrack;
private int audioSessionId = -1;
private void initAudioTrack() {
if (mAudioTrack == null) {
if (audioSessionId == -1) {
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, mRecorderBufferSize * 2
, AudioTrack.MODE_STREAM);
} else {
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, mRecorderBufferSize * 2
, AudioTrack.MODE_STREAM, audioSessionId);
}
}
}
最后创建AcousticEchoCanceler
private AcousticEchoCanceler acousticEchoCanceler;
private void initAEC() {
if (AcousticEchoCanceler.isAvailable()) {
if (acousticEchoCanceler == null) {
acousticEchoCanceler = AcousticEchoCanceler.create(audioSessionId);
Log.d(TAG, "initAEC: ---->" + acousticEchoCanceler + "\t" + audioSessionId);
if (acousticEchoCanceler == null) {
Log.e(TAG, "initAEC: ----->AcousticEchoCanceler create fail.");
} else {
acousticEchoCanceler.setEnabled(true);
}
}
}
}
最后播放的时候就可以了(验证是ok的)
public void write(byte[] data) {
if (mAudioTrack != null && mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
mAudioTrack.write(data, 0, data.length);
}
}