Android AcousticEchoCanceler doesn't seem to work on most devices

I am creating an application that requires the microphone to cancel the sound coming from the speaker. This question seems to be almost an online conspiracy, as others with the same problem have never responded to a long duration.

The original hardware acceleration of Android AcousticEchoCanceler does not seem to work on most devices. Tests performed on many devices, and those that seemed to work, included the Nexus 5 and Moto X, while almost all of Samsung's tested devices failed to remove background sound. Note. All verified phones return true forAcousticEchoCanceler.isAvailable()

However, there must be a solution, since applications such as Skype or WhatsApp seem to cancel sounds outside the context of their application, i.e. a call on the speaker, and the microphone cancels the feedback received.

This simplified recording application writes sound to a file and plays it later when the play button is pressed.

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>

Permissions 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"/>

To check if the device is working, just play something in the background, and then click Start Recordingwrite down a small sector, and then click Stop Recordingat that moment click Play Backand check if background sound is heard. If you hear background sound, AEC does not work. But why does this inconsistency arise or how can I achieve echo cancellation (I already use WebRTC in my application for noise reduction in the context of my applications)

!

+4
2

S6. , , , AEC. :

  • 16k
  • audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);

, AEC. ,

  • 48 .
  • NO audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
  • NO android.permission.MODIFY_AUDIO_SETTINGS

AEC.

+2

:

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()
0

Source: https://habr.com/ru/post/1628387/


All Articles