Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b5eba903 authored by Eric Laurent's avatar Eric Laurent Committed by Android (Google) Code Review
Browse files

Merge "Issue 3370834: No Echo canceler for SIP"

parents 7e7e18e4 5fb3ba60
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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

+64 −17
Original line number Diff line number Diff line
@@ -40,7 +40,8 @@
#include <media/AudioRecord.h>
#include <media/AudioTrack.h>
#include <media/mediarecorder.h>

#include <media/AudioEffect.h>
#include <audio_effects/effect_aec.h>
#include <system/audio.h>

#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;
}

//------------------------------------------------------------------------------