开发者

Using Android's build-in acoustic echo cancellation

Does anyone know how to use Android device's built-in acoustic echo cancellation? It is located somewher开发者_StackOverflowe in silicon and is used for GSM/CDMA speakerphone calls. We'd really like to tap into it for a VoIP application instead of rolling our own.

Ben


I was finally able to get echo cancellation to work on my Arm5 (WM8650) processor (Android 2.2). Below are the steps I took.

  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.


I've been to the same place, successfully ported Speex AEC to Android and used it in 2 different Android VoIP clients. Most of the echo gets cancelled when on speakerphone at full volume - tested on a variety of devices. The Speex official docs and googling should be enough to get it to work.


Since API Level 11, there is a new value for MediaRecorder.AudioSource, it is VOICE_COMMUNICATION. Android docs say: "Microphone audio source tuned for voice communications such as VoIP. It will for instance take advantage of echo cancellation or automatic gain control if available. It otherwise behaves like DEFAULT if no voice processing is applied." I tried this, but couldn't make it worked. The problem may be the device I'd used, which is Sony Tablet S. Worth trying, though.


I tried all methods described here and found them not efficiency.

Finally I decided that the best echo canceller is gain controller.

I have written in the play audio thread the next code:

float volume = ((float)audioManager.getStreamVolume(audioManager.STREAM_VOICE_CALL))/
    audioManager.getStreamMaxVolume(audioManager.STREAM_VOICE_CALL);
track.setStereoVolume(0.5f, 0.5f);

for (int i = 0; i < FRAME_SIZE; i++)
{
    int gained_low_byte = (int) ((outBuf[2*i] & 0xFF) * 2.0f*volume*.75f);
    outBuf[2*i] = (byte) (gained_low_byte & 0xFF);
    outBuf[2*i+1] = (byte) (outBuf[2*i+1] * 2.0f*volume*.75f + (gained_low_byte >> 8));
}

float avg = 0.0f;
for (int i = 0; i < FRAME_SIZE; i++)
{
    avg += Math.abs((float)((outBuf[2*i+1] << 8) | (outBuf[2*i] & 0xFF))) / 32768.0f;
}
avg /= FRAME_SIZE;

if (avg > max_onair*9/10 || onair_counter == 0)
{
    if (avg > max_onair || onair_counter == 0)
        max_onair = avg;
    else
        Log.v(TAG, "On Air: support max_onair level " + max_onair + " by "+avg);
    onair_counter = 75; // You can play with this value to make the effect more fit
}
else onair_counter--;

And the next in the record thread

float control_number = max_onair*333; // Other important value
//Log.v(TAG, "Control microphone number is "+control_number);
if (control_number > 1.0f)
{
    control_number = (float) Math.exp(control_number);
    for (int i = 0; i < FRAME_SIZE; i++)
    {
        clearedBuf[2*i] = (byte) ((clearedBuf[2*i] & 0xFF) / control_number);
        clearedBuf[2*i+1] /= control_number;
    }
}

So it is not real echo canceller, but at least it works.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜