Акустическое эхоподавление (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.