From 5fb3ba60afe68060ac1ed291f4a108fef8c622c3 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Mon, 25 Jul 2011 12:02:16 -0700 Subject: Issue 3370834: No Echo canceler for SIP Added detection of platfrom AEC in AudioGroup. If an AEC is present, the SIP stack will use it, otherwise the echo suppressor of the stack will be used. Change-Id: I4aa45a8868466120f5f9fae71b491fe4ae1162c2 --- voip/jni/rtp/Android.mk | 3 +- voip/jni/rtp/AudioGroup.cpp | 81 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 66 insertions(+), 18 deletions(-) (limited to 'voip/jni') diff --git a/voip/jni/rtp/Android.mk b/voip/jni/rtp/Android.mk index 47ed658..0815294 100644 --- a/voip/jni/rtp/Android.mk +++ b/voip/jni/rtp/Android.mk @@ -49,7 +49,8 @@ LOCAL_C_INCLUDES += \ frameworks/base/media/libstagefright/codecs/amrnb/enc/include \ frameworks/base/media/libstagefright/codecs/amrnb/enc/src \ frameworks/base/media/libstagefright/codecs/amrnb/dec/include \ - frameworks/base/media/libstagefright/codecs/amrnb/dec/src + frameworks/base/media/libstagefright/codecs/amrnb/dec/src \ + system/media/audio_effects/include LOCAL_CFLAGS += -fvisibility=hidden diff --git a/voip/jni/rtp/AudioGroup.cpp b/voip/jni/rtp/AudioGroup.cpp index 85ed1c8..529b425 100644 --- a/voip/jni/rtp/AudioGroup.cpp +++ b/voip/jni/rtp/AudioGroup.cpp @@ -40,7 +40,8 @@ #include #include #include - +#include +#include #include #include "jni.h" @@ -481,6 +482,7 @@ public: bool sendDtmf(int event); bool add(AudioStream *stream); bool remove(int socket); + bool platformHasAec() { return mPlatformHasAec; } private: enum { @@ -491,6 +493,8 @@ private: LAST_MODE = 3, }; + bool checkPlatformAec(); + AudioStream *mChain; int mEventQueue; volatile int mDtmfEvent; @@ -499,6 +503,7 @@ private: int mSampleRate; int mSampleCount; int mDeviceSocket; + bool mPlatformHasAec; class NetworkThread : public Thread { @@ -550,6 +555,7 @@ AudioGroup::AudioGroup() mDeviceSocket = -1; mNetworkThread = new NetworkThread(this); mDeviceThread = new DeviceThread(this); + mPlatformHasAec = checkPlatformAec(); } AudioGroup::~AudioGroup() @@ -630,10 +636,6 @@ bool AudioGroup::setMode(int mode) if (mode == NORMAL && !strcmp(value, "herring")) { mode = ECHO_SUPPRESSION; } - if (mode == ECHO_SUPPRESSION && AudioSystem::getParameters( - 0, String8("ec_supported")) == "ec_supported=yes") { - mode = NORMAL; - } if (mMode == mode) { return true; } @@ -759,6 +761,25 @@ bool AudioGroup::NetworkThread::threadLoop() return true; } +bool AudioGroup::checkPlatformAec() +{ + effect_descriptor_t fxDesc; + uint32_t numFx; + + if (AudioEffect::queryNumberEffects(&numFx) != NO_ERROR) { + return false; + } + for (uint32_t i = 0; i < numFx; i++) { + if (AudioEffect::queryEffect(i, &fxDesc) != NO_ERROR) { + continue; + } + if (memcmp(&fxDesc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) { + return true; + } + } + return false; +} + bool AudioGroup::DeviceThread::threadLoop() { int mode = mGroup->mMode; @@ -798,10 +819,6 @@ bool AudioGroup::DeviceThread::threadLoop() } LOGD("latency: output %d, input %d", track.latency(), record.latency()); - // Initialize echo canceler. - EchoSuppressor echo(sampleCount, - (track.latency() + record.latency()) * sampleRate / 1000); - // Give device socket a reasonable buffer size. setsockopt(deviceSocket, SOL_SOCKET, SO_RCVBUF, &output, sizeof(output)); setsockopt(deviceSocket, SOL_SOCKET, SO_SNDBUF, &output, sizeof(output)); @@ -810,6 +827,33 @@ bool AudioGroup::DeviceThread::threadLoop() char c; while (recv(deviceSocket, &c, 1, MSG_DONTWAIT) == 1); + // check if platform supports echo cancellation and do not active local echo suppression in + // this case + EchoSuppressor *echo = NULL; + AudioEffect *aec = NULL; + if (mode == ECHO_SUPPRESSION) { + if (mGroup->platformHasAec()) { + aec = new AudioEffect(FX_IID_AEC, + NULL, + 0, + 0, + 0, + record.getSessionId(), + record.getInput()); + status_t status = aec->initCheck(); + if (status == NO_ERROR || status == ALREADY_EXISTS) { + aec->setEnabled(true); + } else { + delete aec; + aec = NULL; + } + } + // Create local echo suppressor if platform AEC cannot be used. + if (aec == NULL) { + echo = new EchoSuppressor(sampleCount, + (track.latency() + record.latency()) * sampleRate / 1000); + } + } // Start AudioRecord before AudioTrack. This prevents AudioTrack from being // disabled due to buffer underrun while waiting for AudioRecord. if (mode != MUTED) { @@ -843,7 +887,7 @@ bool AudioGroup::DeviceThread::threadLoop() track.releaseBuffer(&buffer); } else if (status != TIMED_OUT && status != WOULD_BLOCK) { LOGE("cannot write to AudioTrack"); - return true; + goto exit; } } @@ -859,7 +903,7 @@ bool AudioGroup::DeviceThread::threadLoop() record.releaseBuffer(&buffer); } else if (status != TIMED_OUT && status != WOULD_BLOCK) { LOGE("cannot read from AudioRecord"); - return true; + goto exit; } } } @@ -870,15 +914,18 @@ bool AudioGroup::DeviceThread::threadLoop() } if (mode != MUTED) { - if (mode == NORMAL) { - send(deviceSocket, input, sizeof(input), MSG_DONTWAIT); - } else { - echo.run(output, input); - send(deviceSocket, input, sizeof(input), MSG_DONTWAIT); + if (echo != NULL) { + LOGV("echo->run()"); + echo->run(output, input); } + send(deviceSocket, input, sizeof(input), MSG_DONTWAIT); } } - return false; + +exit: + delete echo; + delete aec; + return true; } //------------------------------------------------------------------------------ -- cgit v1.1