单独编译和使用webrtc音频回声消除模块(附完整源码+测试音频文件)(转)
单独编译和使用webrtc音频降噪模块(附完整源码+测试音频文件)
单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件)
说实话很不想写这篇文章,因为这和我一贯推崇的最好全部编译并使用webrtc音频处理模块相悖。可是不知不觉已经把降噪和增益写出来,回声消除如果用户可以得到完美利用也不失为一个很好的方法。但是还是那句话,最好还是全部编译和使用webrtc的整个音频处理模块。另外这篇文章已经不单单的回声消除模块了,其中包括了降噪,增益,静音检测,如果有需要可以选择其中的一部分单独提取调试。
相对而言回声消除比起其他模块要复杂很多,不光光是计算量大(之前在一部380MHz的摄像头中测试过,其消耗的时间为降噪的三倍以上,如果音频延迟更大甚至根本跑不起来),而且其中也涉及到一个delay的计算,delay计算是否精确完全影响回声消除的效果。
至于delay的计算,网上有很多说明,有复杂也有简单的。在这里我还是简单的提一下:
这张图很多东西可以无视,我们重点看T0,T1,T2三项。
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 }
https://www.cnblogs.com/mod109/p/5827918.html