原文转载于:http://www.cnblogs.com/mod109/p/5827918.html#top 非常感谢。
相对而言回声消除比起其他模块要复杂很多,不光光是计算量大(之前在一部380MHz的摄像头中测试过,其消耗的时间为降噪的三倍以上,如果音频延迟更大甚至根本跑不起来),而且其中也涉及到一个delay的计算,delay计算是否精确完全影响回声消除的效果。
至于delay的计算,网上有很多说明,有复杂也有简单的。在这里我还是简单的提一下:
![](https://i-blog.csdnimg.cn/blog_migrate/9beda59fc25464f62ee3ee394b31ed00.jpeg)
T0代表着声音从扬声器传到麦克风的时间,这个时间可以忽略,因为一般来说话筒和扬声器之间距离不会太远,考虑到声音340米每秒的速度,这个时间都不会超过1毫秒。
T1代表远处传到你这来的声音,这个声音被传递到回声消除远端接口(WebRtcAec_BufferFarend)的到播放出来的时间。一般来说接收到的音频数据传入这个接口的时候也就是上层传入扬声器的时刻,所以可以理解成该声音防到播放队列中开始计时,到播放出来的时间。
T2代表一段声音被扬声器采集到,然后到被送到近端处理函数(WebRtcAec_Process)的时刻,由于声音被采集到马上会做回声消除处理,所以这个时间可以理解成麦克风采集到声音开始计时,然后到你的代码拿到音频PCM数据所用的时间。
好了,delay=T0+T1+T2,其实也就是T1+T2。
一般来说,一个设备如果能找到合适的delay,那么这个设备再做回声消除处理就和降噪增益一样几乎没什么难度了。从网上看iPhone的固定delay是60ms,不过不确定,MacBook挂了,在等四季度新MacBook上市,所以暂时没办法做验证。
因为回声消除过程,可以理解成已经把蓝黑两种颜色的墨水完全混合,然后分离出来所需要的蓝色或者黑色颜色。事实上完全混在一起的音频数据是无法彻底分开的,但是我们可以把混在一起的声音理解成两段声音,其中有一段声音可以找到一段几乎相近的对比原声,然后在混音中找到和原声近似的数据,这样就可以分离了。delay的意义显而易见就是要把原声和混在一起的声音数据作对比时,校正时刻所用,这个时刻越是精确,那么回声消除的效果越好。不过从实际效果来看这个delay也并不需要特别精确,在这段测试音频数据里面范围可以接近100毫秒。
从两段音频波形起始位置看delay的时间应该超过100毫秒,那么可以用一段代码做测试,测试代码和音频文件来自于网上:
1 int WebRtcAecTest()
2 {
3 #define NN 160
4 short far_frame[NN];
5 short near_frame[NN];
6 short out_frame[NN];
7
8 void *aecmInst = NULL;
9 FILE *fp_far = fopen("speaker.pcm", "rb");
10 FILE *fp_near = fopen("micin.pcm", "rb");
11 FILE *fp_out = fopen("out.pcm", "wb");
12
13 do
14 {
15 if(!fp_far || !fp_near || !fp_out)
16 {
17 printf("WebRtcAecTest open file err \n");
18 break;
19 }
20
21 WebRtcAec_Create(&aecmInst);
22 WebRtcAec_Init(aecmInst, 8000, 8000);
23
24 AecConfig config;
25 config.nlpMode = kAecNlpConservative;
26 WebRtcAec_set_config(aecmInst, config);
27
28 while(1)
29 {
30 if (NN == fread(far_frame, sizeof(short), NN, fp_far))
31 {
32 fread(near_frame, sizeof(short), NN, fp_near);
33 WebRtcAec_BufferFarend(aecmInst, far_frame, NN);//对参考声音(回声)的处理
34
35 WebRtcAec_Process(aecmInst, near_frame, NULL, out_frame, NULL, NN,109,0);//回声消除
36 fwrite(out_frame, sizeof(short), NN, fp_out);
37 }
38 else
39 {
40 break;
41 }
42 }
43 } while (0);
44
45 fclose(fp_far);
46 fclose(fp_near);
47 fclose(fp_out);
48 WebRtcAec_Free(aecmInst);
49 return 0;
50 }