2012-07-05 5 views
2

임베디드 장치에서 VoIP 프로젝트를 수행하고 있습니다. 필자는 저급 오디오 코덱을 갖춘 32 비트 MCU를 사용하여 샘플을 제작했습니다. 이제 장치에서 에코 문제가 있다는 것을 알았습니다. 즉 스피커에서 말한 것을들을 수 있습니다. 몇 가지 연구를 해본 결과, 대부분의 애플리케이션에서는 음향 반향 제거 기능이있는 DSP 코덱을 사용합니다. 그러나 32 비트 MCU를 사용하여 소프트웨어에서 음향 에코 제거를 수행 할 수 있습니까?임베디드 소프트웨어의 음향 반향 제거 (AEC)

음향 반향 제거를 수행하기 위해 알고리즘 또는 소스 코드 : P까지도 부탁 할 수 있습니까? 나는 정교한 방법은 MCU에서 불가능하다는 것을 알지만, 간단한 알고리즘도 환영합니다.

는 감사

[후속] : 나는 몇 가지 AEC 코드를 시도했지만 그들은 아마는 MCU 전력의 한계는, 내 MCU에서 잘 작동하지 않을 수 있습니다. 나는 내 장치가 이러한 코드를 구현할 때 실시간이 아닌 것으로 나타났습니다 (그러나 VoIP는 실시간 응답이 필요합니다). 마침내 다른 DSP 칩에 코드를 다시 쓰고 싶지 않기 때문에 AEC 칩을 추가하여 아날로그 하드웨어 솔루션을 구현했습니다.

+1

당신은 소프트웨어에서 EC를 할 수있는 그 꽤 많은 아날로그 솔루션은 잘 작동하지 않기 때문에이 (모든 경우) 현재 수행되고있어 방법 . 하지만 쉬운 일은 아닙니다. 먼저 하드웨어에 충분한 CPU 전력과 메모리가 있어야하며 아날로그 부분이 선형이어야합니다. 높은 비선형 왜곡은 일반적으로 EC를 불가능하게 만듭니다. –

+4

나는 이것이 [dsp.stackexchange.com] (http://dsp.stackexchange.com/)에 대해 더 좋은 질문이라고 생각한다. –

답변

0

쉬운 프로젝트 프로젝트를 수행하고 있다면. VoIP 응용 프로그램에 상용 오디오 취소 소프트웨어를 통합 할 수 있습니다.

3

에코 제거와 함께 시간이 지났습니다. 나는 소프트 폰을 썼고 사용자는 자신의 오디오 입력 및 출력 장치를 자신의 멋대로 맞게 바꿀 수 있습니다. 나는 Speex echo cancellation 라이브러리와 온라인에서 찾은 몇 가지 다른 오픈 소스 라이브러리를 시도했다. 나에게 잘 맞는 것은 없다. 나는 다른 스피커/마이크 구성을 시도하고 메아리는 항상 어떤 형태로 또는 패션에 있었다.

나는 가능한 모든 스피커 구성/실내 크기/배경 소음 등을 위해 작동하는 AEC 코드를 만드는 것이 매우 어려울 것이라고 생각합니다. 마지막으로 나는 앉아서이 알고리즘으로 내 소프트 폰에 대한 내 자신의 반향 제거 모듈을 썼다.

약간 원유이지만 잘 작동하고 신뢰할 수 있습니다.

variable1 : 말하는 사람이 말할 때의 평균 진폭을 기록하십시오. (조용한 시간을 배제하지 마십시오)

variable2 : 평균 진폭이 입력 (마이크)에 무엇인지 기록하고 음성 만있을 때만 다시 말하면서 조용한 시간을 배제하십시오.

재생할 오디오가 들리면 마이크를 자르십시오. 듣고있는 사람이 말하고 있지 않다고 가정하면, 마지막 청취 가능한 오디오 프레임이 재생 된 후 150-300ms 후에 마이크를 켜십시오.

(재생 중에 떨어지는) 오디오가 오 (예 : variable2 * 1.5)보다 큰 경우 지정된 기간 동안 오디오 입력 프레임 보내기를 시작하고 입력 진폭 도달 (variable2 * 1.5).

그런 식으로 말하는 사람은 그들이 방해 받고 있음을 알게되고 그 사람이 말하는 것을 보지 마세요. 이야기하는 사람이 배경이 너무 시끄럽지 않은 경우에는 방해가 아니라고해도 대부분 듣게됩니다.

내가 말했듯이, 가장 우아하지는 않지만 많은 리소스 (CPU, 메모리)를 사용하지 않고 실제로는 꽤 잘 작동합니다. 나는 내 소리가 얼마나 대단히 기쁘다.

구현하려면 몇 가지 기능을 만들었습니다.

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 *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; 

당신이 필요하고 아이디어를 연주 당신은 적응할 수에 대한 호출에서 반환 AEC 구조체의 타이머 및 진폭 평균처럼 내 모든 변수를 유지하지만, 같은 나는 말했다. 그것은 실제로 꽤 좋은 소리를 낸다. 그들이 가지고있는 유일한 문제는 배경 잡음이 많은 경우입니다. 하지만 나에게 USB 송수화기를 들거나 헤드셋을 사용하면 에코 제거 기능을 끄고 걱정하지 않아도된다.하지만 마이크가있는 PC 스피커는 정말 행복하다. 내가 도움이, 또는 당신에 구축 무엇인가를 줄 희망

...