一.什么是回声消除(AEC)
在回答回声消除之前,我们看这幅图片,如下图所示:

当远端Far-end有说话者讲话时,声音会传到近端(Near-end)的扬声器,然后声音通过空间延时和传输延时重新回到了远端。这样就造成了声学回声。近端到远端的流程也有同样声学回声,在此仅仅描述近端的流程.
你可能问:我们手机为什么没有这个现象。因为我们手机安卓系统已经实现了回声消除的算法。
二.回声消除算法
我们本次讲解的芯片平台,主要是比较低端,频率比较低的芯片。比如SMT32 esp8266.比较高端的芯片绝大部分原厂已经实现了回声消除的功能。回声消除算法也是比较消耗CPU的,所以我们对于低端的芯片,需要去选择一个好的回声消除算法尤其重要。
常见的speex webrtc 都自带回声消除的功能
实际效果对比:如果样本非线性不严重,两者的效果都不错;对于非线性speex效果就很差,webrtc的效果好;双讲时,webrtc出来的音质就很差,有吃音现象。
所以本次我们主要讲解WEBRTC的回声消除算法,对于WEBRTC它有三个三种回音消除算法(aec aec3 aecm)。其中aec ,aec3 主要是给手机使用的,我们安卓系统就是用了这个2个。我们低端芯片可能就跑不动了,本次我们主要使用webrtc的aecm
三.aecm的使用
总体思路:喇叭播放音频数据时,先存储起来,存储在循环FIFO内,作为回声消除的Farend数据,建立一个aec线程,线程的主要工作流程:读取麦克风声音,读取喇叭存储的循环FIFO ,进行回声消除。
应用程序调用audio_capture_snddev_raw_pcm_read函数读取cap_ring_buff这个FIFO的数据,里面的音频数据是被回声消除过的干净的声音
应用调用audio_play_snddev_raw_pcm_write去播放音频数据,这个接口同时会把"播放的音频数据"放到 play_ring_buff 这个FIFO 作为回声消除的依据参数
aec_thread 这个线程主要做回声消除算法。 从硬件的麦克风读取杂乱,含有回声的音频数据,然后从play_ring_buff读取音频数据。根据这两个数据,进行回声消除算法处理。处理好的干净的数据放到cap_ring_buff
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80/* 从喇叭读取音频数据的接口函数 * 应用程序调用 */ void audio_capture_snddev_raw_pcm_read(BYTE_T *pcm_data ,UINT_T len) { for(;;){ /*cap_ring_buff 这个FIFO在 aec_thread线程被填充数据 * 应用程序从这个cap_ring_buff读取数据 是没有回声的 */ if(audio_ring_buff_used_size_get(cap_ring_buff) > len){ audio_ring_buff_read(cap_ring_buff, pcm_data, len); break; } } } /* 音频播放到喇叭的接口函数 * 应用程序调用 */ void audio_play_snddev_raw_pcm_write(BYTE_T *pcm_data ,UINT_T len) { UINT_T write_len = len; UINT_T free_len = 0; /*存储到play_ring_buff这个FIFO*/ free_len = audio_ring_buff_free_size_get(play_ring_buff); if(free_len >= len){ audio_ring_buff_write(play_ring_buff,pcm_data,len); write_len = len; } /*硬件喇叭播放声音*/ audio_speaker_play(pcm_data,write_len); } void aec_thread() { #define N_SAMPLE 80 BYTE_T pcm_uint_in[N_SAMPLE*2]; BYTE_T pcm_uint_out[N_SAMPLE*2]; BYTE_T pcm_uint_e[N_SAMPLE*2]; void *aecmInst = NULL; int status; unsigned int out_len; AecmConfig config; config.cngMode = 1; config.echoMode = 4;// 0, 1, 2, 3 (default), 4 /*初始化aec 设置aec的参数,比如音频采样率8000*/ if (aecmInst == NULL){ WebRtcAecm_Create(&aecmInst); status = WebRtcAecm_Init(aecmInst, 8000);//8000 or 16000 Sample rate if(status != 0){ AUDIO_DEG("WebRtcAecm_Init error"); } status = WebRtcAecm_set_config(aecmInst, config); if (status != 0) { AUDIO_DEG("WebRtcAecm_set_config fail"); } } while (1){ /*读取麦克风的声音 从硬件MIC*/ auido_mic(pcm_uint_in,sizeof(pcm_uint_in)); /*从 play_ring_buff 读取数据 。这个play_ring_buff 的数据是在audio_play_snddev_raw_pcm_write函数放入*/ out_len = aidio_ring_buff_used_size_get(play_ring_buff); if(out_len >= sizeof(pcm_uint_out)){ /*喇叭循环FIFO(play_ring_buff)有数据,则取出来开始回声消除*/ audio_ring_buff_read(play_ring_buff, pcm_uint_out, sizeof(pcm_uint_out)); out_len = N_SAMPLE; /*喇叭循环FIFO(play_ring_buff)作为aec的Farend数据*/ if(WebRtcAecm_BufferFarend(aecmInst,pcm_uint_out,out_len)){ AUDIO_DEG("WebRtcAecm_BufferFarend fail"); } /*回声消除处理*/ if(WebRtcAecm_Process(aecmInst, pcm_uint_in, NULL, pcm_uint_e, out_len, snd_dev_used_aec_config.msInSndCardBuf)){ AUDIO_DEG("WebRtcAecm_Process fail"); } /*写入capture fifo(cap_ring_buff)*/ auido_capture_pcm_fifo_write(pcm_uint_e,out_len*2); } } }
四.aecm效果
可以满足基本的使用,CPU需要占用40%(芯片主频192M),内存需要20k
觉得对看官有用的,看的高兴可以给个打赏,谢谢!

最后
以上就是飘逸季节最近收集整理的关于微处理器(STM32 wifi芯片)实现音频回声消除的全部内容,更多相关微处理器(STM32内容请搜索靠谱客的其他文章。
发表评论 取消回复