Search code examples
androidsocketsechoaudiorecordandroid-audiorecord

AudioRecord and AudioTrack echo


I'm streaming the mic audio between two devices, everything is working but i have a bad echo.

Here what i'm doing

Reading thread

int sampleFreq = 22050; 
        int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
        int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
        int minBuffer = 2*AudioTrack.getMinBufferSize(sampleFreq, channelConfig, audioFormat);

        AudioTrack atrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                        sampleFreq,
                        channelConfig,
                        audioFormat,
                        minBuffer,
                        AudioTrack.MODE_STREAM);
        atrack.play();

        byte[] buffer = new byte[minBuffer];
        while (true) {
            try {                
                // Read from the InputStream                
                bytes = mmInStream.read(buffer);                    
                atrack.write(buffer, 0, buffer.length);
                atrack.flush();                         
            } catch (IOException e) {
                Log.e(TAG, "disconnected", e);
                break;
            }
        }

Here the recording thread

int sampleRate = 22050; 
    int channelMode = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    int buffersize = 2*AudioTrack.getMinBufferSize(sampleRate, channelMode, audioFormat);

    AudioRecord arec = new AudioRecord(MediaRecorder.AudioSource.MIC,
            sampleRate, channelMode,
            AudioFormat.ENCODING_PCM_16BIT, buffersize);

    buffer = new byte[buffersize];
    arec.startRecording();

    while (true) {  
        arec.read(buffer, 0, buffersize);
        new Thread( new Runnable(){
            @Override
            public void run() {
                try {               
                    mOutputStream.write(buffer);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }                   
            }               
        }).start();
    }

Am I doing something wrong?


Solution

  • You need echo cancellation logic. Here is what I did on my Arm5 (WM8650) processor (Android 2.2) to remove the echo.

    1. I wrapped Speex with JNI and called echo processing routines before sending PCM frames to encoder. No echo was canceled no matter what Speex settings I tried.

    2. Because Speex is very sensitive to delay between playback and echo frames I implemented a queue and queued all packets sent to AudioTrack. The size of the queue should be roughly equal to the size of internal AudioTrack buffer. This way packet were sent to echo_playback roughly at the time when AudioTrack send packets to the sound card from its internal buffer. The delay was removed with this approach but echo was still not cancelled

    3. I wrapped WebRtc echo cancellation part with JNI and called its methods before sending packets to encoder. The echo was still present but the library obviously was trying to cancel it.

    4. I applied the buffer technique described in P2 and it finally started to work. The delay needs to be adjusted for each device though. Note also that WebRtc has mobile and full version of echo cancellation. The full version substantially slows the processor and should probably be run on ARM7 only. The mobile version works but with lower quality

    I hope this will help someone.