Акустическое эхоподавление (AEC) во встроенном программном обеспечении

Я делаю проект VoIP на встроенном устройстве. Я построил образец с использованием 32-битного MCU с аудиокодеком низкого качества. Теперь я обнаружил, что на моем устройстве есть проблема с эхом, то есть я слышу, что я сказал из динамика. Я провел некоторые исследования и обнаружил, что большинство приложений используют кодек DSP с функцией акустического эхоподавления. Однако возможно ли, чтобы я делал акустическое эхоподавление в программном обеспечении, используя мой 32-битный MCU?

Можете ли вы добавить алгоритм или даже исходный код:P для подавления акустического эха? Я знаю, что сложный метод невозможен на MCU, тогда как простой алгоритм также приветствуется.

Спасибо

[Follow up]: я попробовал некоторый код AEC, но он не может хорошо работать в моем MCU, возможно, это предел мощности MCU. Я обнаружил, что мое устройство стало не в реальном времени, когда реализовал эти коды (но VoIP нужен ответ в реальном времени). Наконец, я реализовал аналоговое аппаратное решение, добавив чипы AEC, потому что я не хочу снова писать код в другом чипе DSP.

2 ответа

У меня было чертовски время с эхоподавлением. Я написал программный телефон, и пользователь может переключать свои устройства ввода и вывода звука в соответствии со своими предпочтениями. Я попробовал библиотеку эхоподавления Speex и несколько других библиотек с открытым исходным кодом, которые я нашел в Интернете. Никто не работал хорошо для меня. Я пробовал разные конфигурации динамика / микрофона, и эхо всегда было в той или иной форме.

Я считаю, что было бы очень трудно создать код AEC, который бы работал для всех возможных конфигураций колонок / размеров помещения / фоновых шумов и т. Д. Наконец я сел и написал свой собственный модуль эхоподавления для моего софтфона с этим алгоритмом.

Это несколько грубо, но это сработало хорошо и надежно.

переменная 1: ведите учет средней амплитуды, когда разговаривает человек, с которым вы разговариваете. (Не фактор спокойного времени)

переменная 2: ведите запись средней амплитуды на входе (микрофон), но только при наличии голоса - опять-таки, не учитывайте тихое время.

Как только появится звук для воспроизведения - отключите микрофон. Предполагая, что слушающий не разговаривает, включите микрофон на 150-300 мс после того, как будет воспроизведен последний слышимый звуковой кадр.

Если звук с микрофонов (который вы отбрасываете во время воспроизведения) больше, чем, скажем, (переменная 2 * 1,5), начните отправлять входные аудиокадры в течение указанной длительности, сбрасывая эту длительность каждый раз, когда амплитуда входного сигнала достигает (переменная 2 *) 1.5).

Таким образом, говорящий узнает, что его прерывают, и перестанет видеть, что говорит этот человек. Если говорящий не имеет слишком шумного фона, он, вероятно, услышит большинство, если не все прерывания.

Как я уже сказал, не самый изящный, но он не использует много ресурсов (процессор, память) и на самом деле работает чертовски хорошо. Я очень доволен тем, как звучит мой.

Чтобы реализовать это, я просто сделал несколько функций.

На полученном звуковом кадре я вызываю функцию, которую я назвал:

void audioin( AEC *ec, short *frame ) {
    unsigned int tas=0; /* Total sum of all audio in frame (absolute value) */
    int i=0;
    for (;i<160;i++)
        tas+=ABS(frame[i]);
    tas/=160; /* 320 byte frames muLaw */
    if (tas>300) { /* I assume this is audiable */
        lockecho(ec);
        ec->lastaudibleframe=GetTickCount64();
        unlockecho(ec);
    }
    return;
}

и перед отправкой кадра я делаю:

#define ECHO_THRESHOLD 300 /* Time to keep suppression alive after last audible frame */
#define ONE_MINUTE 3000 /* 3000 20ms samples */
#define AVG_PERIOD 250 /* 250 20ms samples */
#define ABS(x) (x>0?x:-x)


char removeecho( AEC *ec, short *aecinput ) {
    int tas=0; /* Average absolute amplitude in this signal */
    int i=0;
    unsigned long long *tot=0;
    unsigned int *ctr=0;
    unsigned short *avg=0;
    char suppressframe=0;
    lockecho(ec);
    if (ec->lastaudibleframe+ECHO_THRESHOLD > GetTickCount64() ) {
        /* If we're still within the threshold for echo (speaker state is ON) */
        tot=&ec->t_aiws;
        ctr=&ec->c_aiws;
        avg=&ec->aiws;
    } else {
        /* If we're outside the threshold for echo (speaker state is OFF) */
        tot=&ec->t_aiwos;
        ctr=&ec->c_aiwos;
        avg=&ec->aiwos;
    }
    for (;i<160;i++) {
        tas+=ABS(aecinput[i]);
    }
    tas/=160;
    if (tas>200) {
        (*tot)+=tas;
        (*avg)=(unsigned short)((*tot)/( (*ctr)?(*ctr):1));
        (*ctr)++;
        if ((*ctr)>AVG_PERIOD) {
            (*tot)=(*avg);
            (*ctr)=0;
        }
    }
    if ( (avg==&ec->aiws) ) {
        tas-=ec->aiwos;
        if (tas<0) {
            tas=0;
        }
        if ( ((unsigned short) tas > (ec->aiws*1.5)) && ((unsigned short)tas>=ec->aiwos) && (ec->aiwos!=0) ) {
            suppressframe=0;
        } else {
            suppressframe=1;
        }
    }
    if (suppressframe) { /* Silence frame */
        memset(aecinput, 0, 320);
    }
    unlockecho(ec);
    return suppressframe;
}

Что заставит кадр замолчать, если это необходимо. Я сохраняю все свои переменные, такие как таймеры и средние значения амплитуды в структуре AEC, которую я возвращаю из вызова

AEC *initecho( void ) {
    AEC *ec=0;
    ec=(AEC *)malloc(sizeof(AEC));
    memset(ec, 0, sizeof(AEC));
    ec->aiws=200; /* Just a default guess as to what the average amplitude would be */
    return ec;
}





typedef struct aec {
    unsigned long long lastaudibleframe; /* time stamp of last audible frame */
    unsigned short aiws; /* Average mike input when speaker is playing */
    unsigned short aiwos; /*Average mike input when speaker ISNT playing */
    unsigned long long t_aiws, t_aiwos; /* Internal running total (sum of PCM) */
    unsigned int c_aiws, c_aiwos; /* Internal counters for number of frames for     averaging */
    unsigned long lockthreadid; /* Thread ID with lock */
    int stlc; /* Same thread lock-count */
} AEC;

Вы можете адаптироваться, как вам нужно, и играть с идеей, но, как я уже сказал. Это на самом деле звучит чертовски хорошо. Единственная проблема, которую я имею, состоит в том, если они имеют много фонового шума. Но для меня, если они берут трубку USB или используют гарнитуру, они могут отключить эхоподавление и не беспокоиться об этом... но, хотя колонки для ПК с микрофоном... Я очень доволен этим.

Надеюсь, это поможет или даст вам что-то, на чем можно основываться

Если вы делаете коммерческий проект, это должно быть легко. Вы можете интегрировать коммерческое программное обеспечение для отмены звука в ваше приложение VoIP.

Другие вопросы по тегам