在android手机上,如果喇叭和mic离得过近,没有采取硬件上的降噪手段(比如采取双mic,一个装在上面,一个装在下面,利用两个mic录取声音时的音量差来过滤掉远处的噪音),那么在回路测试的过程中,mic会将你对着mic说话的声音,和喇叭发出的声音全部录入,从而产生尖锐的回声,也就是啸叫声。针对这个情况,要么硬件上来修改,要么在软件上,利用AcousticEchoCanceler接口来消除部份噪音. 完整代码如下:
import com.android.autotest.R;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Handler;
import android.widget.Toast;
import android.util.Log;
import android.media.audiofx.AcousticEchoCanceler;
import android.media.AudioSystem;
public class LoopActivity extends BaseItemActivity {
private String TAG = "LoopActivity";
boolean isRecording = false;
boolean isExit = false;
static final int frequency = 16000;
static final int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_DEFAULT;
static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
int recBufSize, playBufSize;
AudioRecord mAudioRecord;
AudioTrack mAudioTrack;
RecordPlayThread mRecordPlayThread = null;
int note = 0;
// Handler mHandler;
AudioManager mAudioManager;
// Runnable mNotiRunnable = null;
private BroadcastReceiver mHeadsetPlugReceiver;
boolean isHeadSetPlugIn = false;
Toast mToast = null;
private AcousticEchoCanceler canceler;
private int audioSession = -1;
public class HeadsetPlugReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.hasExtra("state")) {
if (intent.getIntExtra("state", 0) == 0) {
isHeadSetPlugIn = false;
isRecording = false;
note = R.string.loop_headset_plug_out;
} else if (intent.getIntExtra("state", 0) == 1) {
isHeadSetPlugIn = true;
isRecording = true;
note = R.string.loop_headset_plug_in;
if(mRecordPlayThread == null){
mRecordPlayThread = new RecordPlayThread();
mRecordPlayThread.start();
}
}
if(mToast == null){
mToast = Toast.makeText(LoopActivity.this, note, Toast.LENGTH_SHORT);
}
mToast.setText(note);
mToast.show();
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addItemView(R.layout.activity_item_loop);
// recBufSize = AudioRecord.getMinBufferSize(frequency,
// channelConfiguration, audioEncoding);
// playBufSize = AudioTrack.getMinBufferSize(frequency,
// channelConfiguration, audioEncoding);
int bufferSize = AudioRecord
.getMinBufferSize(frequency, AudioFormat.CHANNEL_CONFIGURATION_DEFAULT,
AudioFormat.ENCODING_PCM_16BIT);
recBufSize = bufferSize;
playBufSize = Math.max(bufferSize, AudioTrack.getMinBufferSize(
frequency, AudioFormat.CHANNEL_CONFIGURATION_DEFAULT,
AudioFormat.ENCODING_PCM_16BIT));
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION,
frequency, channelConfiguration, audioEncoding, recBufSize);
audioSession = mAudioRecord.getAudioSessionId();
Log.d(TAG, "onCreate audioSession is: "+audioSession);
if(audioSession == -1)
{
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, frequency,
AudioFormat.CHANNEL_CONFIGURATION_DEFAULT, audioEncoding, playBufSize,
AudioTrack.MODE_STREAM);
}
else
{
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, frequency,
AudioFormat.CHANNEL_CONFIGURATION_DEFAULT, audioEncoding, playBufSize,
AudioTrack.MODE_STREAM, audioSession);
if(isDeviceSupport())
{
boolean result = initAEC(audioSession);
Log.d(TAG, "onCreate initAEC result is: "+result);
result = setAECEnabled(true);
Log.d(TAG, "onCreate setAECEnabled result is: "+result);
}
}
mAudioTrack.setStereoVolume(1f, 1f);
mAudioTrack.setPlaybackRate(frequency);
isRecording = true;
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
mAudioManager.setSpeakerphoneOn(true);
isHeadSetPlugIn = true;//mAudioManager.isWiredHeadsetOn();
if (!isHeadSetPlugIn) {
} else {
mRecordPlayThread = new RecordPlayThread();
mRecordPlayThread.start();
}
/* mHandler = new Handler();
mNotiRunnable = new Runnable() {
@Override
public void run() {
isHeadSetPlugIn = mAudioManager.isWiredHeadsetOn();
if (!isHeadSetPlugIn) {
note = R.string.loop_headset_plug_please;
} else {
note = R.string.loop_headset_plug_in;
}
if(mToast == null){
mToast = Toast.makeText(LoopActivity.this, note, Toast.LENGTH_SHORT);
mToast.show();
}
}
};
mHandler.postDelayed(mNotiRunnable, 1000);*/
}
@Override
protected void onDestroy() {
super.onDestroy();
// mAudioTrack.stop();
// mAudioRecord.stop();
mAudioTrack.release();
mAudioRecord.release();
// mHandler.removeCallbacks(mNotiRunnable);
isExit = true;
isRecording = false;
release();
}
@Override
protected void onResume() {
super.onResume();
// registerHeadsetPlugReceiver();
}
@Override
protected void onPause() {
super.onPause();
// unregisterReceiver(mHeadsetPlugReceiver);
}
private void registerHeadsetPlugReceiver() {
mHeadsetPlugReceiver = new HeadsetPlugReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.HEADSET_PLUG");
registerReceiver(mHeadsetPlugReceiver, intentFilter);
}
class RecordPlayThread extends Thread {
public void run() {
//if (isHeadSetPlugIn)
if(true)
{
try {
byte[] buffer = new byte[recBufSize];
mAudioRecord.startRecording();
mAudioTrack.play();
while (isRecording) {
int bufferReadResult = mAudioRecord.read(buffer, 0,
recBufSize);
byte[] tmpBuf = new byte[bufferReadResult];
System.arraycopy(buffer, 0, tmpBuf, 0, bufferReadResult);
mAudioTrack.write(tmpBuf, 0, tmpBuf.length);
}
mAudioTrack.stop();
mAudioRecord.stop();
mRecordPlayThread = null;
//if (isExit) {
// mAudioTrack.release();
// mAudioRecord.release();
//}
} catch (Throwable t) {
// cannot be call at not mainthread
// Toast.makeText(LoopActivity.this, t.getMessage(),
// Toast.LENGTH_SHORT).show();
}
}
}
};
public boolean isDeviceSupport()
{
boolean isSupport = AcousticEchoCanceler.isAvailable();
Log.d(TAG, "isDeviceSupport isSupport is: "+isSupport);
return isSupport;
}
public boolean initAEC( int audioSession)
{
if(canceler != null)
{
return false;
}
canceler = AcousticEchoCanceler.create(audioSession);
if(canceler == null)
{
return false;
}
canceler.setEnabled(true);
return canceler.getEnabled();
}
public boolean setAECEnabled( boolean enable)
{
if( null == canceler)
{
return false;
}
canceler.setEnabled(enable);
return canceler.getEnabled();
}
public boolean release()
{
if( null == canceler)
{
return false;
}
canceler.setEnabled(false);
canceler.release();
return true;
}
}