[英]android AcousticEchoCanceler doesn't seem to work on most devices
我正在構建一個應用程序,它要求麥克風取消來自揚聲器的任何聲音。 似乎這個問題幾乎是一個在線的陰謀,因為其他具有完全相同問題的問題從未得到長時間的回應。
Android的本機硬件加速AcousticEchoCanceler似乎不適用於大多數設備。 測試在許多設備上進行的測試以及似乎有效的設備包括Nexus 5和Moto X,而幾乎所有測試的三星設備都無法移除背景音。注意:所有測試的手機都返回真實的AcousticEchoCanceler.isAvailable()
但是,必須有一個解決方案,因為Skype或WhatsApp等應用程序似乎取消了應用程序上下文之外的聲音,即呼叫在揚聲器上,麥克風取消收到的任何反饋。
這個簡化的錄音應用程序將聲音錄制到文件中,並在單擊播放時播放。
MainActivity.java
public class MainActivity extends Activity {
Button startRec, stopRec, playBack;
int minBufferSizeIn;
AudioRecord audioRecord;
short[] audioData;
Boolean recording;
int sampleRateInHz = 48000;
private String TAG = "TAG";
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startRec = (Button) findViewById(R.id.startrec);
stopRec = (Button) findViewById(R.id.stoprec);
playBack = (Button) findViewById(R.id.playback);
startRec.setOnClickListener(startRecOnClickListener);
stopRec.setOnClickListener(stopRecOnClickListener);
playBack.setOnClickListener(playBackOnClickListener);
playBack.setEnabled(false);
startRec.setEnabled(true);
stopRec.setEnabled(false);
minBufferSizeIn = AudioRecord.getMinBufferSize(sampleRateInHz,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT);
audioData = new short[minBufferSizeIn];
audioRecord = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION,
sampleRateInHz,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
minBufferSizeIn);
}
OnClickListener startRecOnClickListener
= new OnClickListener() {
@Override
public void onClick(View arg0) {
playBack.setEnabled(false);
startRec.setEnabled(false);
stopRec.setEnabled(true);
Thread recordThread = new Thread(new Runnable() {
@Override
public void run() {
recording = true;
startRecord();
}
});
recordThread.start();
}
};
OnClickListener stopRecOnClickListener
= new OnClickListener() {
@Override
public void onClick(View arg0) {
playBack.setEnabled(true);
startRec.setEnabled(false);
stopRec.setEnabled(false);
recording = false;
}
};
OnClickListener playBackOnClickListener
= new OnClickListener() {
@Override
public void onClick(View v) {
playBack.setEnabled(false);
startRec.setEnabled(true);
stopRec.setEnabled(false);
playRecord();
}
};
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void startRecord() {
File file = new File(Environment.getExternalStorageDirectory(), "test.pcm");
try {
FileOutputStream outputStream = new FileOutputStream(file);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
DataOutputStream dataOutputStream = new DataOutputStream(bufferedOutputStream);
NoiseSuppressor ns;
AcousticEchoCanceler aec;
if (NoiseSuppressor.isAvailable()) {
ns = NoiseSuppressor.create(audioRecord.getAudioSessionId());
if (ns != null) {
ns.setEnabled(true);
} else {
Log.e(TAG, "AudioInput: NoiseSuppressor is null and not enabled");
}
}
if (AcousticEchoCanceler.isAvailable()) {
aec = AcousticEchoCanceler.create(audioRecord.getAudioSessionId());
if (aec != null) {
aec.setEnabled(true);
} else {
Log.e(TAG, "AudioInput: AcousticEchoCanceler is null and not enabled");
}
}
audioRecord.startRecording();
while (recording) {
int numberOfShort = audioRecord.read(audioData, 0, minBufferSizeIn);
for (int i = 0; i < numberOfShort; i++) {
dataOutputStream.writeShort(audioData[i]);
}
}
audioRecord.stop();
dataOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
void playRecord() {
File file = new File(Environment.getExternalStorageDirectory(), "test.pcm");
int shortSizeInBytes = Short.SIZE / Byte.SIZE;
int bufferSizeInBytes = (int) (file.length() / shortSizeInBytes);
short[] audioData = new short[bufferSizeInBytes];
try {
FileInputStream inputStream = new FileInputStream(file);
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
DataInputStream dataInputStream = new DataInputStream(bufferedInputStream);
int i = 0;
while (dataInputStream.available() > 0) {
audioData[i] = dataInputStream.readShort();
i++;
}
dataInputStream.close();
AudioTrack audioTrack = new AudioTrack(
AudioManager.STREAM_MUSIC, sampleRateInHz,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT,
bufferSizeInBytes,
AudioTrack.MODE_STREAM);
while(audioTrack.getState() != AudioTrack.STATE_INITIALIZED){
}
audioTrack.play();
audioTrack.write(audioData, 0, bufferSizeInBytes);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
activity_main.xml中
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<Button
android:id="@+id/startrec"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Start Recording Test" />
<Button
android:id="@+id/stoprec"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Stop Recording" />
<Button
android:id="@+id/playback"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Play Back" />
</LinearLayout>
AndroidManfist.xml權限
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
要驗證設備是否可以在后台播放內容,然后單擊Start Recording
記錄一個小扇區,然后單擊Stop Recording
此時單擊Play Back
並檢查是否聽到背景聲音。 如果您能聽到背景聲音,那么AEC無法正常工作。 但是為什么會出現這種不一致,或者我如何實現回聲消除(我已經在我的應用中使用WebRTC在我的應用上下文中進行噪聲消除)
任何幫助,將不勝感激 !
我的S6設備遇到了同樣的問題。 我玩了各種設置,發現了一套似乎能夠啟用AEC的設備。 我和您的設置之間的差異似乎是:
對於其他人,我不確定究竟需要什么設置才能讓AEC正常工作。 我知道我的同一個應用程序
沒有成功的AEC。
問題:
AudioTrack audioTrack = new AudioTrack(
AudioManager.STREAM_MUSIC, sampleRateInHz,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT,
bufferSizeInBytes,
AudioTrack.MODE_STREAM);
應該:
AudioTrack audioTrack = new AudioTrack(
AudioManager.STREAM_MUSIC, sampleRateInHz,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT,
bufferSizeInBytes,
AudioTrack.MODE_STREAM
sessionId); // this param is important, which is audioRecord. getAudioSessionId()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.