我做的嵌入式设备上的网络电话项目。 我已经建立了采用32位MCU与低级别音频编解码器的样品。 现在我发现我的设备上的回声问题,这是我能听到我从发言者说。 我做了一些研究,发现大多数appliaction使用带有回音消除功能,一个DSP编解码器。 但是,是有可能,我做的声学回声消除软件中的,用我的32位MCU?
你能adive算法,甚至源代码:P,做声学回声消除? 我知道复杂的方法是不可能在MCU,而一个简单的算法也很欢迎。
谢谢
[后续]:我已经尝试了一些AEC代码,但他们不能在我的MCU工作得很好,大概是MCU电源的限制。 我发现,执行这些代码时(但在VoIP需要实时响应)我的设备成为非实时性。 最后,我通过添加AEC芯片,因为我不想在另一个DSP芯片重新编写代码实现的模拟硬件的解决方案。
我有与回声消除时间赫克。 我写了一个软电话,并且用户可以切换周围的音频输入和输出设备,以满足他们的幻想。 我试过Speex语音回声消除库,和其他几个开源库我在网上找到。 无工作很适合我。 我尝试不同的扬声器/话筒的配置和回波总是在那里以某种形式或方式。
我相信这将是很难创建AEC代码,将适用于所有可能的扬声器配置/房间大小/背景noises..etc。 最后,我坐下来,写我自己的回声消除模块为我的网络电话这一算法。
这有点粗糙,但它运作良好,是可靠的。
变量1:保持的平均幅度是当人你说谁是讲一个什么样的记录。 (不要因素安静时)
变量2:保持的平均幅度是输入(麦克)什么记录,但只有当支持语音再次 - 不要因素安静的时间。
只要有音频播放 - 切麦克风。 并假设人听就是不说话,打开麦克150-300ms最后Audible音频帧成为后播放。
如果从麦克风音频(你正在播放过程中掉落)大于OH-说(变量2 * 1.5),开始发送音频输入帧指定的持续时间,每次重置该持续时间输入幅度达到(变量2 * 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结构,这是我从一个呼叫到
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或者使用耳机是,他们可以把回声消除掉,而不用担心...但虽然PC扬声器,一个麦克风...我与它很高兴。
我希望它能帮助,或给你的东西的基础上...
如果你正在做一个商业项目,这应该很容易。 您可以集成在VoIP应用商业消音软件。