语音通话时,如果采用免提方式,麦克风会录到本机喇叭发出的声音并传回给对方。在对方一端就会明显的听到回声。如果仔细调整麦克风和喇叭的位置,可以很大程度减少麦克风录到喇叭声音的大小。但这样对设备的位置限制太多。
原本真正的解决办法应该是做滤波器将回声虑掉,考虑到几个方面:1。 原理不清楚,看代码也看得一头雾水。(真后悔逃了太多的高等数学课) 2。效果不知能否理想。麦克风和喇叭质量没保证,而且加了简单的放大电路,失真严重。导致一般的回声消除算法效果很可能并不理想。 3。 运算量不够,一般的回声消除算法运算量不低,原本不是很宽裕的系统可能承受不起。 总之一系列的原因让我现阶段采用MC34118的方法。
MC34118用在普通模拟电话机内消除侧音的一块芯片,能够比较满意的禁止麦克风录到本机喇叭播放的声音。它比较放音和录音的电平,谁小就禁止谁。晕哦,好好的全双工通信变成了半双工的。不过通话时一般感觉不到,并且软件实现起来很简单。
MC34118的工作原理看看datasheet就清楚了。它内部有点复杂,有4个电平比较器,两个背景噪音监视器,一个AGC,一个拨号音检测器,两个衰减器,一个控制衰减器的控制模块,还有一些放大。其实我们只需知道通过开关麦克风和喇叭的方法可以有效的避免回声就可以了。
语音的电平也就是能量的大小可以计算采样的平方和得到。为了计算简单,采用计算采样的绝对值和得到。
static int check_val(const short * pdata,int len)
{
int tmp = len;
int all = 0;
short val;
while(tmp--)
{
val = *pdata++;
if(val < 0)
val = -val;
all += val
}
return all/len;
}
由于信号的不稳定,可能播放和录音的计算结果虽然相差不大,但大小频繁交叉,从而频繁开关麦克风和喇叭。所以将计算出来的平方和划分到8个等级中。
if(check < 15)
r_level = 0;
else
if(check < 40)
r_level = 1;
else
if(check < 90)
r_level = 2;
else
if(check < 150)
r_level = 3;
else
if(check < 240)
r_level = 4;
else
if(check < 350)
r_level = 5;
else
if(check < 480)
r_level = 6;
else
r_level = 7;
另外,如果两台机的麦克风和喇叭的参数不一样,可修正这个等级来调整。
然后比较录音和播放的等级,谁低就关闭谁。
实践证明这样用非常少的计算量能很好的达到MC34118所做到的效果。