1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/audio_processing/aecm/aecm_core.h"
12
13 #include <stddef.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17 extern "C" {
18 #include "common_audio/ring_buffer.h"
19 #include "common_audio/signal_processing/include/real_fft.h"
20 }
21 #include "common_audio/signal_processing/include/signal_processing_library.h"
22 #include "modules/audio_processing/aecm/echo_control_mobile.h"
23 #include "modules/audio_processing/utility/delay_estimator_wrapper.h"
24
25 #include "rtc_base/checks.h"
26 #include "rtc_base/numerics/safe_conversions.h"
27
28 #ifdef AEC_DEBUG
29 FILE* dfile;
30 FILE* testfile;
31 #endif
32
33 const int16_t WebRtcAecm_kCosTable[] = {
34 8192, 8190, 8187, 8180, 8172, 8160, 8147, 8130, 8112, 8091, 8067,
35 8041, 8012, 7982, 7948, 7912, 7874, 7834, 7791, 7745, 7697, 7647,
36 7595, 7540, 7483, 7424, 7362, 7299, 7233, 7164, 7094, 7021, 6947,
37 6870, 6791, 6710, 6627, 6542, 6455, 6366, 6275, 6182, 6087, 5991,
38 5892, 5792, 5690, 5586, 5481, 5374, 5265, 5155, 5043, 4930, 4815,
39 4698, 4580, 4461, 4341, 4219, 4096, 3971, 3845, 3719, 3591, 3462,
40 3331, 3200, 3068, 2935, 2801, 2667, 2531, 2395, 2258, 2120, 1981,
41 1842, 1703, 1563, 1422, 1281, 1140, 998, 856, 713, 571, 428,
42 285, 142, 0, -142, -285, -428, -571, -713, -856, -998, -1140,
43 -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395, -2531, -2667,
44 -2801, -2935, -3068, -3200, -3331, -3462, -3591, -3719, -3845, -3971, -4095,
45 -4219, -4341, -4461, -4580, -4698, -4815, -4930, -5043, -5155, -5265, -5374,
46 -5481, -5586, -5690, -5792, -5892, -5991, -6087, -6182, -6275, -6366, -6455,
47 -6542, -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164, -7233, -7299,
48 -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745, -7791, -7834, -7874,
49 -7912, -7948, -7982, -8012, -8041, -8067, -8091, -8112, -8130, -8147, -8160,
50 -8172, -8180, -8187, -8190, -8191, -8190, -8187, -8180, -8172, -8160, -8147,
51 -8130, -8112, -8091, -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834,
52 -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362, -7299, -7233,
53 -7164, -7094, -7021, -6947, -6870, -6791, -6710, -6627, -6542, -6455, -6366,
54 -6275, -6182, -6087, -5991, -5892, -5792, -5690, -5586, -5481, -5374, -5265,
55 -5155, -5043, -4930, -4815, -4698, -4580, -4461, -4341, -4219, -4096, -3971,
56 -3845, -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801, -2667, -2531,
57 -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422, -1281, -1140, -998,
58 -856, -713, -571, -428, -285, -142, 0, 142, 285, 428, 571,
59 713, 856, 998, 1140, 1281, 1422, 1563, 1703, 1842, 1981, 2120,
60 2258, 2395, 2531, 2667, 2801, 2935, 3068, 3200, 3331, 3462, 3591,
61 3719, 3845, 3971, 4095, 4219, 4341, 4461, 4580, 4698, 4815, 4930,
62 5043, 5155, 5265, 5374, 5481, 5586, 5690, 5792, 5892, 5991, 6087,
63 6182, 6275, 6366, 6455, 6542, 6627, 6710, 6791, 6870, 6947, 7021,
64 7094, 7164, 7233, 7299, 7362, 7424, 7483, 7540, 7595, 7647, 7697,
65 7745, 7791, 7834, 7874, 7912, 7948, 7982, 8012, 8041, 8067, 8091,
66 8112, 8130, 8147, 8160, 8172, 8180, 8187, 8190};
67
68 const int16_t WebRtcAecm_kSinTable[] = {
69 0, 142, 285, 428, 571, 713, 856, 998, 1140, 1281, 1422,
70 1563, 1703, 1842, 1981, 2120, 2258, 2395, 2531, 2667, 2801, 2935,
71 3068, 3200, 3331, 3462, 3591, 3719, 3845, 3971, 4095, 4219, 4341,
72 4461, 4580, 4698, 4815, 4930, 5043, 5155, 5265, 5374, 5481, 5586,
73 5690, 5792, 5892, 5991, 6087, 6182, 6275, 6366, 6455, 6542, 6627,
74 6710, 6791, 6870, 6947, 7021, 7094, 7164, 7233, 7299, 7362, 7424,
75 7483, 7540, 7595, 7647, 7697, 7745, 7791, 7834, 7874, 7912, 7948,
76 7982, 8012, 8041, 8067, 8091, 8112, 8130, 8147, 8160, 8172, 8180,
77 8187, 8190, 8191, 8190, 8187, 8180, 8172, 8160, 8147, 8130, 8112,
78 8091, 8067, 8041, 8012, 7982, 7948, 7912, 7874, 7834, 7791, 7745,
79 7697, 7647, 7595, 7540, 7483, 7424, 7362, 7299, 7233, 7164, 7094,
80 7021, 6947, 6870, 6791, 6710, 6627, 6542, 6455, 6366, 6275, 6182,
81 6087, 5991, 5892, 5792, 5690, 5586, 5481, 5374, 5265, 5155, 5043,
82 4930, 4815, 4698, 4580, 4461, 4341, 4219, 4096, 3971, 3845, 3719,
83 3591, 3462, 3331, 3200, 3068, 2935, 2801, 2667, 2531, 2395, 2258,
84 2120, 1981, 1842, 1703, 1563, 1422, 1281, 1140, 998, 856, 713,
85 571, 428, 285, 142, 0, -142, -285, -428, -571, -713, -856,
86 -998, -1140, -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395,
87 -2531, -2667, -2801, -2935, -3068, -3200, -3331, -3462, -3591, -3719, -3845,
88 -3971, -4095, -4219, -4341, -4461, -4580, -4698, -4815, -4930, -5043, -5155,
89 -5265, -5374, -5481, -5586, -5690, -5792, -5892, -5991, -6087, -6182, -6275,
90 -6366, -6455, -6542, -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164,
91 -7233, -7299, -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745, -7791,
92 -7834, -7874, -7912, -7948, -7982, -8012, -8041, -8067, -8091, -8112, -8130,
93 -8147, -8160, -8172, -8180, -8187, -8190, -8191, -8190, -8187, -8180, -8172,
94 -8160, -8147, -8130, -8112, -8091, -8067, -8041, -8012, -7982, -7948, -7912,
95 -7874, -7834, -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362,
96 -7299, -7233, -7164, -7094, -7021, -6947, -6870, -6791, -6710, -6627, -6542,
97 -6455, -6366, -6275, -6182, -6087, -5991, -5892, -5792, -5690, -5586, -5481,
98 -5374, -5265, -5155, -5043, -4930, -4815, -4698, -4580, -4461, -4341, -4219,
99 -4096, -3971, -3845, -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801,
100 -2667, -2531, -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422, -1281,
101 -1140, -998, -856, -713, -571, -428, -285, -142};
102
103 // Initialization table for echo channel in 8 kHz
104 static const int16_t kChannelStored8kHz[PART_LEN1] = {
105 2040, 1815, 1590, 1498, 1405, 1395, 1385, 1418, 1451, 1506, 1562,
106 1644, 1726, 1804, 1882, 1918, 1953, 1982, 2010, 2025, 2040, 2034,
107 2027, 2021, 2014, 1997, 1980, 1925, 1869, 1800, 1732, 1683, 1635,
108 1604, 1572, 1545, 1517, 1481, 1444, 1405, 1367, 1331, 1294, 1270,
109 1245, 1239, 1233, 1247, 1260, 1282, 1303, 1338, 1373, 1407, 1441,
110 1470, 1499, 1524, 1549, 1565, 1582, 1601, 1621, 1649, 1676};
111
112 // Initialization table for echo channel in 16 kHz
113 static const int16_t kChannelStored16kHz[PART_LEN1] = {
114 2040, 1590, 1405, 1385, 1451, 1562, 1726, 1882, 1953, 2010, 2040,
115 2027, 2014, 1980, 1869, 1732, 1635, 1572, 1517, 1444, 1367, 1294,
116 1245, 1233, 1260, 1303, 1373, 1441, 1499, 1549, 1582, 1621, 1676,
117 1741, 1802, 1861, 1921, 1983, 2040, 2102, 2170, 2265, 2375, 2515,
118 2651, 2781, 2922, 3075, 3253, 3471, 3738, 3976, 4151, 4258, 4308,
119 4288, 4270, 4253, 4237, 4179, 4086, 3947, 3757, 3484, 3153};
120
121 // Moves the pointer to the next entry and inserts |far_spectrum| and
122 // corresponding Q-domain in its buffer.
123 //
124 // Inputs:
125 // - self : Pointer to the delay estimation instance
126 // - far_spectrum : Pointer to the far end spectrum
127 // - far_q : Q-domain of far end spectrum
128 //
WebRtcAecm_UpdateFarHistory(AecmCore * self,uint16_t * far_spectrum,int far_q)129 void WebRtcAecm_UpdateFarHistory(AecmCore* self,
130 uint16_t* far_spectrum,
131 int far_q) {
132 // Get new buffer position
133 self->far_history_pos++;
134 if (self->far_history_pos >= MAX_DELAY) {
135 self->far_history_pos = 0;
136 }
137 // Update Q-domain buffer
138 self->far_q_domains[self->far_history_pos] = far_q;
139 // Update far end spectrum buffer
140 memcpy(&(self->far_history[self->far_history_pos * PART_LEN1]), far_spectrum,
141 sizeof(uint16_t) * PART_LEN1);
142 }
143
144 // Returns a pointer to the far end spectrum aligned to current near end
145 // spectrum. The function WebRtc_DelayEstimatorProcessFix(...) should have been
146 // called before AlignedFarend(...). Otherwise, you get the pointer to the
147 // previous frame. The memory is only valid until the next call of
148 // WebRtc_DelayEstimatorProcessFix(...).
149 //
150 // Inputs:
151 // - self : Pointer to the AECM instance.
152 // - delay : Current delay estimate.
153 //
154 // Output:
155 // - far_q : The Q-domain of the aligned far end spectrum
156 //
157 // Return value:
158 // - far_spectrum : Pointer to the aligned far end spectrum
159 // NULL - Error
160 //
WebRtcAecm_AlignedFarend(AecmCore * self,int * far_q,int delay)161 const uint16_t* WebRtcAecm_AlignedFarend(AecmCore* self,
162 int* far_q,
163 int delay) {
164 int buffer_position = 0;
165 RTC_DCHECK(self);
166 buffer_position = self->far_history_pos - delay;
167
168 // Check buffer position
169 if (buffer_position < 0) {
170 buffer_position += MAX_DELAY;
171 }
172 // Get Q-domain
173 *far_q = self->far_q_domains[buffer_position];
174 // Return far end spectrum
175 return &(self->far_history[buffer_position * PART_LEN1]);
176 }
177
178 // Declare function pointers.
179 CalcLinearEnergies WebRtcAecm_CalcLinearEnergies;
180 StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel;
181 ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel;
182
WebRtcAecm_CreateCore()183 AecmCore* WebRtcAecm_CreateCore() {
184 AecmCore* aecm = static_cast<AecmCore*>(malloc(sizeof(AecmCore)));
185
186 aecm->farFrameBuf =
187 WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(int16_t));
188 if (!aecm->farFrameBuf) {
189 WebRtcAecm_FreeCore(aecm);
190 return NULL;
191 }
192
193 aecm->nearNoisyFrameBuf =
194 WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(int16_t));
195 if (!aecm->nearNoisyFrameBuf) {
196 WebRtcAecm_FreeCore(aecm);
197 return NULL;
198 }
199
200 aecm->nearCleanFrameBuf =
201 WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(int16_t));
202 if (!aecm->nearCleanFrameBuf) {
203 WebRtcAecm_FreeCore(aecm);
204 return NULL;
205 }
206
207 aecm->outFrameBuf =
208 WebRtc_CreateBuffer(FRAME_LEN + PART_LEN, sizeof(int16_t));
209 if (!aecm->outFrameBuf) {
210 WebRtcAecm_FreeCore(aecm);
211 return NULL;
212 }
213
214 aecm->delay_estimator_farend =
215 WebRtc_CreateDelayEstimatorFarend(PART_LEN1, MAX_DELAY);
216 if (aecm->delay_estimator_farend == NULL) {
217 WebRtcAecm_FreeCore(aecm);
218 return NULL;
219 }
220 aecm->delay_estimator =
221 WebRtc_CreateDelayEstimator(aecm->delay_estimator_farend, 0);
222 if (aecm->delay_estimator == NULL) {
223 WebRtcAecm_FreeCore(aecm);
224 return NULL;
225 }
226 // TODO(bjornv): Explicitly disable robust delay validation until no
227 // performance regression has been established. Then remove the line.
228 WebRtc_enable_robust_validation(aecm->delay_estimator, 0);
229
230 aecm->real_fft = WebRtcSpl_CreateRealFFT(PART_LEN_SHIFT);
231 if (aecm->real_fft == NULL) {
232 WebRtcAecm_FreeCore(aecm);
233 return NULL;
234 }
235
236 // Init some aecm pointers. 16 and 32 byte alignment is only necessary
237 // for Neon code currently.
238 aecm->xBuf = (int16_t*)(((uintptr_t)aecm->xBuf_buf + 31) & ~31);
239 aecm->dBufClean = (int16_t*)(((uintptr_t)aecm->dBufClean_buf + 31) & ~31);
240 aecm->dBufNoisy = (int16_t*)(((uintptr_t)aecm->dBufNoisy_buf + 31) & ~31);
241 aecm->outBuf = (int16_t*)(((uintptr_t)aecm->outBuf_buf + 15) & ~15);
242 aecm->channelStored =
243 (int16_t*)(((uintptr_t)aecm->channelStored_buf + 15) & ~15);
244 aecm->channelAdapt16 =
245 (int16_t*)(((uintptr_t)aecm->channelAdapt16_buf + 15) & ~15);
246 aecm->channelAdapt32 =
247 (int32_t*)(((uintptr_t)aecm->channelAdapt32_buf + 31) & ~31);
248
249 return aecm;
250 }
251
WebRtcAecm_InitEchoPathCore(AecmCore * aecm,const int16_t * echo_path)252 void WebRtcAecm_InitEchoPathCore(AecmCore* aecm, const int16_t* echo_path) {
253 int i = 0;
254
255 // Reset the stored channel
256 memcpy(aecm->channelStored, echo_path, sizeof(int16_t) * PART_LEN1);
257 // Reset the adapted channels
258 memcpy(aecm->channelAdapt16, echo_path, sizeof(int16_t) * PART_LEN1);
259 for (i = 0; i < PART_LEN1; i++) {
260 aecm->channelAdapt32[i] = (int32_t)aecm->channelAdapt16[i] << 16;
261 }
262
263 // Reset channel storing variables
264 aecm->mseAdaptOld = 1000;
265 aecm->mseStoredOld = 1000;
266 aecm->mseThreshold = WEBRTC_SPL_WORD32_MAX;
267 aecm->mseChannelCount = 0;
268 }
269
CalcLinearEnergiesC(AecmCore * aecm,const uint16_t * far_spectrum,int32_t * echo_est,uint32_t * far_energy,uint32_t * echo_energy_adapt,uint32_t * echo_energy_stored)270 static void CalcLinearEnergiesC(AecmCore* aecm,
271 const uint16_t* far_spectrum,
272 int32_t* echo_est,
273 uint32_t* far_energy,
274 uint32_t* echo_energy_adapt,
275 uint32_t* echo_energy_stored) {
276 int i;
277
278 // Get energy for the delayed far end signal and estimated
279 // echo using both stored and adapted channels.
280 for (i = 0; i < PART_LEN1; i++) {
281 echo_est[i] =
282 WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
283 (*far_energy) += (uint32_t)(far_spectrum[i]);
284 *echo_energy_adapt += aecm->channelAdapt16[i] * far_spectrum[i];
285 (*echo_energy_stored) += (uint32_t)echo_est[i];
286 }
287 }
288
StoreAdaptiveChannelC(AecmCore * aecm,const uint16_t * far_spectrum,int32_t * echo_est)289 static void StoreAdaptiveChannelC(AecmCore* aecm,
290 const uint16_t* far_spectrum,
291 int32_t* echo_est) {
292 int i;
293
294 // During startup we store the channel every block.
295 memcpy(aecm->channelStored, aecm->channelAdapt16,
296 sizeof(int16_t) * PART_LEN1);
297 // Recalculate echo estimate
298 for (i = 0; i < PART_LEN; i += 4) {
299 echo_est[i] =
300 WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
301 echo_est[i + 1] =
302 WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1], far_spectrum[i + 1]);
303 echo_est[i + 2] =
304 WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2], far_spectrum[i + 2]);
305 echo_est[i + 3] =
306 WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3], far_spectrum[i + 3]);
307 }
308 echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
309 }
310
ResetAdaptiveChannelC(AecmCore * aecm)311 static void ResetAdaptiveChannelC(AecmCore* aecm) {
312 int i;
313
314 // The stored channel has a significantly lower MSE than the adaptive one for
315 // two consecutive calculations. Reset the adaptive channel.
316 memcpy(aecm->channelAdapt16, aecm->channelStored,
317 sizeof(int16_t) * PART_LEN1);
318 // Restore the W32 channel
319 for (i = 0; i < PART_LEN; i += 4) {
320 aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16;
321 aecm->channelAdapt32[i + 1] = (int32_t)aecm->channelStored[i + 1] << 16;
322 aecm->channelAdapt32[i + 2] = (int32_t)aecm->channelStored[i + 2] << 16;
323 aecm->channelAdapt32[i + 3] = (int32_t)aecm->channelStored[i + 3] << 16;
324 }
325 aecm->channelAdapt32[i] = (int32_t)aecm->channelStored[i] << 16;
326 }
327
328 // Initialize function pointers for ARM Neon platform.
329 #if defined(WEBRTC_ARCH_ARM_FAMILY) && defined(WEBRTC_HAS_NEON)
WebRtcAecm_InitNeon(void)330 static void WebRtcAecm_InitNeon(void) {
331 WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannelNeon;
332 WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannelNeon;
333 WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergiesNeon;
334 }
335 #endif
336
337 // Initialize function pointers for MIPS platform.
338 #if defined(MIPS32_LE)
WebRtcAecm_InitMips(void)339 static void WebRtcAecm_InitMips(void) {
340 #if defined(MIPS_DSP_R1_LE)
341 WebRtcAecm_StoreAdaptiveChannel = WebRtcAecm_StoreAdaptiveChannel_mips;
342 WebRtcAecm_ResetAdaptiveChannel = WebRtcAecm_ResetAdaptiveChannel_mips;
343 #endif
344 WebRtcAecm_CalcLinearEnergies = WebRtcAecm_CalcLinearEnergies_mips;
345 }
346 #endif
347
348 // WebRtcAecm_InitCore(...)
349 //
350 // This function initializes the AECM instant created with
351 // WebRtcAecm_CreateCore(...) Input:
352 // - aecm : Pointer to the Echo Suppression instance
353 // - samplingFreq : Sampling Frequency
354 //
355 // Output:
356 // - aecm : Initialized instance
357 //
358 // Return value : 0 - Ok
359 // -1 - Error
360 //
WebRtcAecm_InitCore(AecmCore * const aecm,int samplingFreq)361 int WebRtcAecm_InitCore(AecmCore* const aecm, int samplingFreq) {
362 int i = 0;
363 int32_t tmp32 = PART_LEN1 * PART_LEN1;
364 int16_t tmp16 = PART_LEN1;
365
366 if (samplingFreq != 8000 && samplingFreq != 16000) {
367 samplingFreq = 8000;
368 return -1;
369 }
370 // sanity check of sampling frequency
371 aecm->mult = (int16_t)samplingFreq / 8000;
372
373 aecm->farBufWritePos = 0;
374 aecm->farBufReadPos = 0;
375 aecm->knownDelay = 0;
376 aecm->lastKnownDelay = 0;
377
378 WebRtc_InitBuffer(aecm->farFrameBuf);
379 WebRtc_InitBuffer(aecm->nearNoisyFrameBuf);
380 WebRtc_InitBuffer(aecm->nearCleanFrameBuf);
381 WebRtc_InitBuffer(aecm->outFrameBuf);
382
383 memset(aecm->xBuf_buf, 0, sizeof(aecm->xBuf_buf));
384 memset(aecm->dBufClean_buf, 0, sizeof(aecm->dBufClean_buf));
385 memset(aecm->dBufNoisy_buf, 0, sizeof(aecm->dBufNoisy_buf));
386 memset(aecm->outBuf_buf, 0, sizeof(aecm->outBuf_buf));
387
388 aecm->seed = 666;
389 aecm->totCount = 0;
390
391 if (WebRtc_InitDelayEstimatorFarend(aecm->delay_estimator_farend) != 0) {
392 return -1;
393 }
394 if (WebRtc_InitDelayEstimator(aecm->delay_estimator) != 0) {
395 return -1;
396 }
397 // Set far end histories to zero
398 memset(aecm->far_history, 0, sizeof(uint16_t) * PART_LEN1 * MAX_DELAY);
399 memset(aecm->far_q_domains, 0, sizeof(int) * MAX_DELAY);
400 aecm->far_history_pos = MAX_DELAY;
401
402 aecm->nlpFlag = 1;
403 aecm->fixedDelay = -1;
404
405 aecm->dfaCleanQDomain = 0;
406 aecm->dfaCleanQDomainOld = 0;
407 aecm->dfaNoisyQDomain = 0;
408 aecm->dfaNoisyQDomainOld = 0;
409
410 memset(aecm->nearLogEnergy, 0, sizeof(aecm->nearLogEnergy));
411 aecm->farLogEnergy = 0;
412 memset(aecm->echoAdaptLogEnergy, 0, sizeof(aecm->echoAdaptLogEnergy));
413 memset(aecm->echoStoredLogEnergy, 0, sizeof(aecm->echoStoredLogEnergy));
414
415 // Initialize the echo channels with a stored shape.
416 if (samplingFreq == 8000) {
417 WebRtcAecm_InitEchoPathCore(aecm, kChannelStored8kHz);
418 } else {
419 WebRtcAecm_InitEchoPathCore(aecm, kChannelStored16kHz);
420 }
421
422 memset(aecm->echoFilt, 0, sizeof(aecm->echoFilt));
423 memset(aecm->nearFilt, 0, sizeof(aecm->nearFilt));
424 aecm->noiseEstCtr = 0;
425
426 aecm->cngMode = AecmTrue;
427
428 memset(aecm->noiseEstTooLowCtr, 0, sizeof(aecm->noiseEstTooLowCtr));
429 memset(aecm->noiseEstTooHighCtr, 0, sizeof(aecm->noiseEstTooHighCtr));
430 // Shape the initial noise level to an approximate pink noise.
431 for (i = 0; i < (PART_LEN1 >> 1) - 1; i++) {
432 aecm->noiseEst[i] = (tmp32 << 8);
433 tmp16--;
434 tmp32 -= (int32_t)((tmp16 << 1) + 1);
435 }
436 for (; i < PART_LEN1; i++) {
437 aecm->noiseEst[i] = (tmp32 << 8);
438 }
439
440 aecm->farEnergyMin = WEBRTC_SPL_WORD16_MAX;
441 aecm->farEnergyMax = WEBRTC_SPL_WORD16_MIN;
442 aecm->farEnergyMaxMin = 0;
443 aecm->farEnergyVAD =
444 FAR_ENERGY_MIN; // This prevents false speech detection at the
445 // beginning.
446 aecm->farEnergyMSE = 0;
447 aecm->currentVADValue = 0;
448 aecm->vadUpdateCount = 0;
449 aecm->firstVAD = 1;
450
451 aecm->startupState = 0;
452 aecm->supGain = SUPGAIN_DEFAULT;
453 aecm->supGainOld = SUPGAIN_DEFAULT;
454
455 aecm->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
456 aecm->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
457 aecm->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
458 aecm->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
459
460 // Assert a preprocessor definition at compile-time. It's an assumption
461 // used in assembly code, so check the assembly files before any change.
462 static_assert(PART_LEN % 16 == 0, "PART_LEN is not a multiple of 16");
463
464 // Initialize function pointers.
465 WebRtcAecm_CalcLinearEnergies = CalcLinearEnergiesC;
466 WebRtcAecm_StoreAdaptiveChannel = StoreAdaptiveChannelC;
467 WebRtcAecm_ResetAdaptiveChannel = ResetAdaptiveChannelC;
468
469 #if defined(WEBRTC_ARCH_ARM_FAMILY) && defined(WEBRTC_HAS_NEON)
470 WebRtcAecm_InitNeon();
471 #endif
472
473 #if defined(MIPS32_LE)
474 WebRtcAecm_InitMips();
475 #endif
476 return 0;
477 }
478
479 // TODO(bjornv): This function is currently not used. Add support for these
480 // parameters from a higher level
WebRtcAecm_Control(AecmCore * aecm,int delay,int nlpFlag)481 int WebRtcAecm_Control(AecmCore* aecm, int delay, int nlpFlag) {
482 aecm->nlpFlag = nlpFlag;
483 aecm->fixedDelay = delay;
484
485 return 0;
486 }
487
WebRtcAecm_FreeCore(AecmCore * aecm)488 void WebRtcAecm_FreeCore(AecmCore* aecm) {
489 if (aecm == NULL) {
490 return;
491 }
492
493 WebRtc_FreeBuffer(aecm->farFrameBuf);
494 WebRtc_FreeBuffer(aecm->nearNoisyFrameBuf);
495 WebRtc_FreeBuffer(aecm->nearCleanFrameBuf);
496 WebRtc_FreeBuffer(aecm->outFrameBuf);
497
498 WebRtc_FreeDelayEstimator(aecm->delay_estimator);
499 WebRtc_FreeDelayEstimatorFarend(aecm->delay_estimator_farend);
500 WebRtcSpl_FreeRealFFT(aecm->real_fft);
501
502 free(aecm);
503 }
504
WebRtcAecm_ProcessFrame(AecmCore * aecm,const int16_t * farend,const int16_t * nearendNoisy,const int16_t * nearendClean,int16_t * out)505 int WebRtcAecm_ProcessFrame(AecmCore* aecm,
506 const int16_t* farend,
507 const int16_t* nearendNoisy,
508 const int16_t* nearendClean,
509 int16_t* out) {
510 int16_t outBlock_buf[PART_LEN + 8]; // Align buffer to 8-byte boundary.
511 int16_t* outBlock = (int16_t*)(((uintptr_t)outBlock_buf + 15) & ~15);
512
513 int16_t farFrame[FRAME_LEN];
514 const int16_t* out_ptr = NULL;
515 int size = 0;
516
517 // Buffer the current frame.
518 // Fetch an older one corresponding to the delay.
519 WebRtcAecm_BufferFarFrame(aecm, farend, FRAME_LEN);
520 WebRtcAecm_FetchFarFrame(aecm, farFrame, FRAME_LEN, aecm->knownDelay);
521
522 // Buffer the synchronized far and near frames,
523 // to pass the smaller blocks individually.
524 WebRtc_WriteBuffer(aecm->farFrameBuf, farFrame, FRAME_LEN);
525 WebRtc_WriteBuffer(aecm->nearNoisyFrameBuf, nearendNoisy, FRAME_LEN);
526 if (nearendClean != NULL) {
527 WebRtc_WriteBuffer(aecm->nearCleanFrameBuf, nearendClean, FRAME_LEN);
528 }
529
530 // Process as many blocks as possible.
531 while (WebRtc_available_read(aecm->farFrameBuf) >= PART_LEN) {
532 int16_t far_block[PART_LEN];
533 const int16_t* far_block_ptr = NULL;
534 int16_t near_noisy_block[PART_LEN];
535 const int16_t* near_noisy_block_ptr = NULL;
536
537 WebRtc_ReadBuffer(aecm->farFrameBuf, (void**)&far_block_ptr, far_block,
538 PART_LEN);
539 WebRtc_ReadBuffer(aecm->nearNoisyFrameBuf, (void**)&near_noisy_block_ptr,
540 near_noisy_block, PART_LEN);
541 if (nearendClean != NULL) {
542 int16_t near_clean_block[PART_LEN];
543 const int16_t* near_clean_block_ptr = NULL;
544
545 WebRtc_ReadBuffer(aecm->nearCleanFrameBuf, (void**)&near_clean_block_ptr,
546 near_clean_block, PART_LEN);
547 if (WebRtcAecm_ProcessBlock(aecm, far_block_ptr, near_noisy_block_ptr,
548 near_clean_block_ptr, outBlock) == -1) {
549 return -1;
550 }
551 } else {
552 if (WebRtcAecm_ProcessBlock(aecm, far_block_ptr, near_noisy_block_ptr,
553 NULL, outBlock) == -1) {
554 return -1;
555 }
556 }
557
558 WebRtc_WriteBuffer(aecm->outFrameBuf, outBlock, PART_LEN);
559 }
560
561 // Stuff the out buffer if we have less than a frame to output.
562 // This should only happen for the first frame.
563 size = (int)WebRtc_available_read(aecm->outFrameBuf);
564 if (size < FRAME_LEN) {
565 WebRtc_MoveReadPtr(aecm->outFrameBuf, size - FRAME_LEN);
566 }
567
568 // Obtain an output frame.
569 WebRtc_ReadBuffer(aecm->outFrameBuf, (void**)&out_ptr, out, FRAME_LEN);
570 if (out_ptr != out) {
571 // ReadBuffer() hasn't copied to |out| in this case.
572 memcpy(out, out_ptr, FRAME_LEN * sizeof(int16_t));
573 }
574
575 return 0;
576 }
577
578 // WebRtcAecm_AsymFilt(...)
579 //
580 // Performs asymmetric filtering.
581 //
582 // Inputs:
583 // - filtOld : Previous filtered value.
584 // - inVal : New input value.
585 // - stepSizePos : Step size when we have a positive contribution.
586 // - stepSizeNeg : Step size when we have a negative contribution.
587 //
588 // Output:
589 //
590 // Return: - Filtered value.
591 //
WebRtcAecm_AsymFilt(const int16_t filtOld,const int16_t inVal,const int16_t stepSizePos,const int16_t stepSizeNeg)592 int16_t WebRtcAecm_AsymFilt(const int16_t filtOld,
593 const int16_t inVal,
594 const int16_t stepSizePos,
595 const int16_t stepSizeNeg) {
596 int16_t retVal;
597
598 if ((filtOld == WEBRTC_SPL_WORD16_MAX) | (filtOld == WEBRTC_SPL_WORD16_MIN)) {
599 return inVal;
600 }
601 retVal = filtOld;
602 if (filtOld > inVal) {
603 retVal -= (filtOld - inVal) >> stepSizeNeg;
604 } else {
605 retVal += (inVal - filtOld) >> stepSizePos;
606 }
607
608 return retVal;
609 }
610
611 // ExtractFractionPart(a, zeros)
612 //
613 // returns the fraction part of |a|, with |zeros| number of leading zeros, as an
614 // int16_t scaled to Q8. There is no sanity check of |a| in the sense that the
615 // number of zeros match.
ExtractFractionPart(uint32_t a,int zeros)616 static int16_t ExtractFractionPart(uint32_t a, int zeros) {
617 return (int16_t)(((a << zeros) & 0x7FFFFFFF) >> 23);
618 }
619
620 // Calculates and returns the log of |energy| in Q8. The input |energy| is
621 // supposed to be in Q(|q_domain|).
LogOfEnergyInQ8(uint32_t energy,int q_domain)622 static int16_t LogOfEnergyInQ8(uint32_t energy, int q_domain) {
623 static const int16_t kLogLowValue = PART_LEN_SHIFT << 7;
624 int16_t log_energy_q8 = kLogLowValue;
625 if (energy > 0) {
626 int zeros = WebRtcSpl_NormU32(energy);
627 int16_t frac = ExtractFractionPart(energy, zeros);
628 // log2 of |energy| in Q8.
629 log_energy_q8 += ((31 - zeros) << 8) + frac - (q_domain << 8);
630 }
631 return log_energy_q8;
632 }
633
634 // WebRtcAecm_CalcEnergies(...)
635 //
636 // This function calculates the log of energies for nearend, farend and
637 // estimated echoes. There is also an update of energy decision levels, i.e.
638 // internal VAD.
639 //
640 //
641 // @param aecm [i/o] Handle of the AECM instance.
642 // @param far_spectrum [in] Pointer to farend spectrum.
643 // @param far_q [in] Q-domain of farend spectrum.
644 // @param nearEner [in] Near end energy for current block in
645 // Q(aecm->dfaQDomain).
646 // @param echoEst [out] Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16).
647 //
WebRtcAecm_CalcEnergies(AecmCore * aecm,const uint16_t * far_spectrum,const int16_t far_q,const uint32_t nearEner,int32_t * echoEst)648 void WebRtcAecm_CalcEnergies(AecmCore* aecm,
649 const uint16_t* far_spectrum,
650 const int16_t far_q,
651 const uint32_t nearEner,
652 int32_t* echoEst) {
653 // Local variables
654 uint32_t tmpAdapt = 0;
655 uint32_t tmpStored = 0;
656 uint32_t tmpFar = 0;
657
658 int i;
659
660 int16_t tmp16;
661 int16_t increase_max_shifts = 4;
662 int16_t decrease_max_shifts = 11;
663 int16_t increase_min_shifts = 11;
664 int16_t decrease_min_shifts = 3;
665
666 // Get log of near end energy and store in buffer
667
668 // Shift buffer
669 memmove(aecm->nearLogEnergy + 1, aecm->nearLogEnergy,
670 sizeof(int16_t) * (MAX_BUF_LEN - 1));
671
672 // Logarithm of integrated magnitude spectrum (nearEner)
673 aecm->nearLogEnergy[0] = LogOfEnergyInQ8(nearEner, aecm->dfaNoisyQDomain);
674
675 WebRtcAecm_CalcLinearEnergies(aecm, far_spectrum, echoEst, &tmpFar, &tmpAdapt,
676 &tmpStored);
677
678 // Shift buffers
679 memmove(aecm->echoAdaptLogEnergy + 1, aecm->echoAdaptLogEnergy,
680 sizeof(int16_t) * (MAX_BUF_LEN - 1));
681 memmove(aecm->echoStoredLogEnergy + 1, aecm->echoStoredLogEnergy,
682 sizeof(int16_t) * (MAX_BUF_LEN - 1));
683
684 // Logarithm of delayed far end energy
685 aecm->farLogEnergy = LogOfEnergyInQ8(tmpFar, far_q);
686
687 // Logarithm of estimated echo energy through adapted channel
688 aecm->echoAdaptLogEnergy[0] =
689 LogOfEnergyInQ8(tmpAdapt, RESOLUTION_CHANNEL16 + far_q);
690
691 // Logarithm of estimated echo energy through stored channel
692 aecm->echoStoredLogEnergy[0] =
693 LogOfEnergyInQ8(tmpStored, RESOLUTION_CHANNEL16 + far_q);
694
695 // Update farend energy levels (min, max, vad, mse)
696 if (aecm->farLogEnergy > FAR_ENERGY_MIN) {
697 if (aecm->startupState == 0) {
698 increase_max_shifts = 2;
699 decrease_min_shifts = 2;
700 increase_min_shifts = 8;
701 }
702
703 aecm->farEnergyMin =
704 WebRtcAecm_AsymFilt(aecm->farEnergyMin, aecm->farLogEnergy,
705 increase_min_shifts, decrease_min_shifts);
706 aecm->farEnergyMax =
707 WebRtcAecm_AsymFilt(aecm->farEnergyMax, aecm->farLogEnergy,
708 increase_max_shifts, decrease_max_shifts);
709 aecm->farEnergyMaxMin = (aecm->farEnergyMax - aecm->farEnergyMin);
710
711 // Dynamic VAD region size
712 tmp16 = 2560 - aecm->farEnergyMin;
713 if (tmp16 > 0) {
714 tmp16 = (int16_t)((tmp16 * FAR_ENERGY_VAD_REGION) >> 9);
715 } else {
716 tmp16 = 0;
717 }
718 tmp16 += FAR_ENERGY_VAD_REGION;
719
720 if ((aecm->startupState == 0) | (aecm->vadUpdateCount > 1024)) {
721 // In startup phase or VAD update halted
722 aecm->farEnergyVAD = aecm->farEnergyMin + tmp16;
723 } else {
724 if (aecm->farEnergyVAD > aecm->farLogEnergy) {
725 aecm->farEnergyVAD +=
726 (aecm->farLogEnergy + tmp16 - aecm->farEnergyVAD) >> 6;
727 aecm->vadUpdateCount = 0;
728 } else {
729 aecm->vadUpdateCount++;
730 }
731 }
732 // Put MSE threshold higher than VAD
733 aecm->farEnergyMSE = aecm->farEnergyVAD + (1 << 8);
734 }
735
736 // Update VAD variables
737 if (aecm->farLogEnergy > aecm->farEnergyVAD) {
738 if ((aecm->startupState == 0) | (aecm->farEnergyMaxMin > FAR_ENERGY_DIFF)) {
739 // We are in startup or have significant dynamics in input speech level
740 aecm->currentVADValue = 1;
741 }
742 } else {
743 aecm->currentVADValue = 0;
744 }
745 if ((aecm->currentVADValue) && (aecm->firstVAD)) {
746 aecm->firstVAD = 0;
747 if (aecm->echoAdaptLogEnergy[0] > aecm->nearLogEnergy[0]) {
748 // The estimated echo has higher energy than the near end signal.
749 // This means that the initialization was too aggressive. Scale
750 // down by a factor 8
751 for (i = 0; i < PART_LEN1; i++) {
752 aecm->channelAdapt16[i] >>= 3;
753 }
754 // Compensate the adapted echo energy level accordingly.
755 aecm->echoAdaptLogEnergy[0] -= (3 << 8);
756 aecm->firstVAD = 1;
757 }
758 }
759 }
760
761 // WebRtcAecm_CalcStepSize(...)
762 //
763 // This function calculates the step size used in channel estimation
764 //
765 //
766 // @param aecm [in] Handle of the AECM instance.
767 // @param mu [out] (Return value) Stepsize in log2(), i.e. number of
768 // shifts.
769 //
770 //
WebRtcAecm_CalcStepSize(AecmCore * const aecm)771 int16_t WebRtcAecm_CalcStepSize(AecmCore* const aecm) {
772 int32_t tmp32;
773 int16_t tmp16;
774 int16_t mu = MU_MAX;
775
776 // Here we calculate the step size mu used in the
777 // following NLMS based Channel estimation algorithm
778 if (!aecm->currentVADValue) {
779 // Far end energy level too low, no channel update
780 mu = 0;
781 } else if (aecm->startupState > 0) {
782 if (aecm->farEnergyMin >= aecm->farEnergyMax) {
783 mu = MU_MIN;
784 } else {
785 tmp16 = (aecm->farLogEnergy - aecm->farEnergyMin);
786 tmp32 = tmp16 * MU_DIFF;
787 tmp32 = WebRtcSpl_DivW32W16(tmp32, aecm->farEnergyMaxMin);
788 mu = MU_MIN - 1 - (int16_t)(tmp32);
789 // The -1 is an alternative to rounding. This way we get a larger
790 // stepsize, so we in some sense compensate for truncation in NLMS
791 }
792 if (mu < MU_MAX) {
793 mu = MU_MAX; // Equivalent with maximum step size of 2^-MU_MAX
794 }
795 }
796
797 return mu;
798 }
799
800 // WebRtcAecm_UpdateChannel(...)
801 //
802 // This function performs channel estimation. NLMS and decision on channel
803 // storage.
804 //
805 //
806 // @param aecm [i/o] Handle of the AECM instance.
807 // @param far_spectrum [in] Absolute value of the farend signal in Q(far_q)
808 // @param far_q [in] Q-domain of the farend signal
809 // @param dfa [in] Absolute value of the nearend signal
810 // (Q[aecm->dfaQDomain])
811 // @param mu [in] NLMS step size.
812 // @param echoEst [i/o] Estimated echo in Q(far_q+RESOLUTION_CHANNEL16).
813 //
WebRtcAecm_UpdateChannel(AecmCore * aecm,const uint16_t * far_spectrum,const int16_t far_q,const uint16_t * const dfa,const int16_t mu,int32_t * echoEst)814 void WebRtcAecm_UpdateChannel(AecmCore* aecm,
815 const uint16_t* far_spectrum,
816 const int16_t far_q,
817 const uint16_t* const dfa,
818 const int16_t mu,
819 int32_t* echoEst) {
820 uint32_t tmpU32no1, tmpU32no2;
821 int32_t tmp32no1, tmp32no2;
822 int32_t mseStored;
823 int32_t mseAdapt;
824
825 int i;
826
827 int16_t zerosFar, zerosNum, zerosCh, zerosDfa;
828 int16_t shiftChFar, shiftNum, shift2ResChan;
829 int16_t tmp16no1;
830 int16_t xfaQ, dfaQ;
831
832 // This is the channel estimation algorithm. It is base on NLMS but has a
833 // variable step length, which was calculated above.
834 if (mu) {
835 for (i = 0; i < PART_LEN1; i++) {
836 // Determine norm of channel and farend to make sure we don't get overflow
837 // in multiplication
838 zerosCh = WebRtcSpl_NormU32(aecm->channelAdapt32[i]);
839 zerosFar = WebRtcSpl_NormU32((uint32_t)far_spectrum[i]);
840 if (zerosCh + zerosFar > 31) {
841 // Multiplication is safe
842 tmpU32no1 =
843 WEBRTC_SPL_UMUL_32_16(aecm->channelAdapt32[i], far_spectrum[i]);
844 shiftChFar = 0;
845 } else {
846 // We need to shift down before multiplication
847 shiftChFar = 32 - zerosCh - zerosFar;
848 // If zerosCh == zerosFar == 0, shiftChFar is 32. A
849 // right shift of 32 is undefined. To avoid that, we
850 // do this check.
851 tmpU32no1 =
852 rtc::dchecked_cast<uint32_t>(
853 shiftChFar >= 32 ? 0 : aecm->channelAdapt32[i] >> shiftChFar) *
854 far_spectrum[i];
855 }
856 // Determine Q-domain of numerator
857 zerosNum = WebRtcSpl_NormU32(tmpU32no1);
858 if (dfa[i]) {
859 zerosDfa = WebRtcSpl_NormU32((uint32_t)dfa[i]);
860 } else {
861 zerosDfa = 32;
862 }
863 tmp16no1 = zerosDfa - 2 + aecm->dfaNoisyQDomain - RESOLUTION_CHANNEL32 -
864 far_q + shiftChFar;
865 if (zerosNum > tmp16no1 + 1) {
866 xfaQ = tmp16no1;
867 dfaQ = zerosDfa - 2;
868 } else {
869 xfaQ = zerosNum - 2;
870 dfaQ = RESOLUTION_CHANNEL32 + far_q - aecm->dfaNoisyQDomain -
871 shiftChFar + xfaQ;
872 }
873 // Add in the same Q-domain
874 tmpU32no1 = WEBRTC_SPL_SHIFT_W32(tmpU32no1, xfaQ);
875 tmpU32no2 = WEBRTC_SPL_SHIFT_W32((uint32_t)dfa[i], dfaQ);
876 tmp32no1 = (int32_t)tmpU32no2 - (int32_t)tmpU32no1;
877 zerosNum = WebRtcSpl_NormW32(tmp32no1);
878 if ((tmp32no1) && (far_spectrum[i] > (CHANNEL_VAD << far_q))) {
879 //
880 // Update is needed
881 //
882 // This is what we would like to compute
883 //
884 // tmp32no1 = dfa[i] - (aecm->channelAdapt[i] * far_spectrum[i])
885 // tmp32norm = (i + 1)
886 // aecm->channelAdapt[i] += (2^mu) * tmp32no1
887 // / (tmp32norm * far_spectrum[i])
888 //
889
890 // Make sure we don't get overflow in multiplication.
891 if (zerosNum + zerosFar > 31) {
892 if (tmp32no1 > 0) {
893 tmp32no2 =
894 (int32_t)WEBRTC_SPL_UMUL_32_16(tmp32no1, far_spectrum[i]);
895 } else {
896 tmp32no2 =
897 -(int32_t)WEBRTC_SPL_UMUL_32_16(-tmp32no1, far_spectrum[i]);
898 }
899 shiftNum = 0;
900 } else {
901 shiftNum = 32 - (zerosNum + zerosFar);
902 if (tmp32no1 > 0) {
903 tmp32no2 = (tmp32no1 >> shiftNum) * far_spectrum[i];
904 } else {
905 tmp32no2 = -((-tmp32no1 >> shiftNum) * far_spectrum[i]);
906 }
907 }
908 // Normalize with respect to frequency bin
909 tmp32no2 = WebRtcSpl_DivW32W16(tmp32no2, i + 1);
910 // Make sure we are in the right Q-domain
911 shift2ResChan =
912 shiftNum + shiftChFar - xfaQ - mu - ((30 - zerosFar) << 1);
913 if (WebRtcSpl_NormW32(tmp32no2) < shift2ResChan) {
914 tmp32no2 = WEBRTC_SPL_WORD32_MAX;
915 } else {
916 tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, shift2ResChan);
917 }
918 aecm->channelAdapt32[i] =
919 WebRtcSpl_AddSatW32(aecm->channelAdapt32[i], tmp32no2);
920 if (aecm->channelAdapt32[i] < 0) {
921 // We can never have negative channel gain
922 aecm->channelAdapt32[i] = 0;
923 }
924 aecm->channelAdapt16[i] = (int16_t)(aecm->channelAdapt32[i] >> 16);
925 }
926 }
927 }
928 // END: Adaptive channel update
929
930 // Determine if we should store or restore the channel
931 if ((aecm->startupState == 0) & (aecm->currentVADValue)) {
932 // During startup we store the channel every block,
933 // and we recalculate echo estimate
934 WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
935 } else {
936 if (aecm->farLogEnergy < aecm->farEnergyMSE) {
937 aecm->mseChannelCount = 0;
938 } else {
939 aecm->mseChannelCount++;
940 }
941 // Enough data for validation. Store channel if we can.
942 if (aecm->mseChannelCount >= (MIN_MSE_COUNT + 10)) {
943 // We have enough data.
944 // Calculate MSE of "Adapt" and "Stored" versions.
945 // It is actually not MSE, but average absolute error.
946 mseStored = 0;
947 mseAdapt = 0;
948 for (i = 0; i < MIN_MSE_COUNT; i++) {
949 tmp32no1 = ((int32_t)aecm->echoStoredLogEnergy[i] -
950 (int32_t)aecm->nearLogEnergy[i]);
951 tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
952 mseStored += tmp32no2;
953
954 tmp32no1 = ((int32_t)aecm->echoAdaptLogEnergy[i] -
955 (int32_t)aecm->nearLogEnergy[i]);
956 tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1);
957 mseAdapt += tmp32no2;
958 }
959 if (((mseStored << MSE_RESOLUTION) < (MIN_MSE_DIFF * mseAdapt)) &
960 ((aecm->mseStoredOld << MSE_RESOLUTION) <
961 (MIN_MSE_DIFF * aecm->mseAdaptOld))) {
962 // The stored channel has a significantly lower MSE than the adaptive
963 // one for two consecutive calculations. Reset the adaptive channel.
964 WebRtcAecm_ResetAdaptiveChannel(aecm);
965 } else if (((MIN_MSE_DIFF * mseStored) > (mseAdapt << MSE_RESOLUTION)) &
966 (mseAdapt < aecm->mseThreshold) &
967 (aecm->mseAdaptOld < aecm->mseThreshold)) {
968 // The adaptive channel has a significantly lower MSE than the stored
969 // one. The MSE for the adaptive channel has also been low for two
970 // consecutive calculations. Store the adaptive channel.
971 WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst);
972
973 // Update threshold
974 if (aecm->mseThreshold == WEBRTC_SPL_WORD32_MAX) {
975 aecm->mseThreshold = (mseAdapt + aecm->mseAdaptOld);
976 } else {
977 int scaled_threshold = aecm->mseThreshold * 5 / 8;
978 aecm->mseThreshold += ((mseAdapt - scaled_threshold) * 205) >> 8;
979 }
980 }
981
982 // Reset counter
983 aecm->mseChannelCount = 0;
984
985 // Store the MSE values.
986 aecm->mseStoredOld = mseStored;
987 aecm->mseAdaptOld = mseAdapt;
988 }
989 }
990 // END: Determine if we should store or reset channel estimate.
991 }
992
993 // CalcSuppressionGain(...)
994 //
995 // This function calculates the suppression gain that is used in the Wiener
996 // filter.
997 //
998 //
999 // @param aecm [i/n] Handle of the AECM instance.
1000 // @param supGain [out] (Return value) Suppression gain with which to scale
1001 // the noise
1002 // level (Q14).
1003 //
1004 //
WebRtcAecm_CalcSuppressionGain(AecmCore * const aecm)1005 int16_t WebRtcAecm_CalcSuppressionGain(AecmCore* const aecm) {
1006 int32_t tmp32no1;
1007
1008 int16_t supGain = SUPGAIN_DEFAULT;
1009 int16_t tmp16no1;
1010 int16_t dE = 0;
1011
1012 // Determine suppression gain used in the Wiener filter. The gain is based on
1013 // a mix of far end energy and echo estimation error. Adjust for the far end
1014 // signal level. A low signal level indicates no far end signal, hence we set
1015 // the suppression gain to 0
1016 if (!aecm->currentVADValue) {
1017 supGain = 0;
1018 } else {
1019 // Adjust for possible double talk. If we have large variations in
1020 // estimation error we likely have double talk (or poor channel).
1021 tmp16no1 = (aecm->nearLogEnergy[0] - aecm->echoStoredLogEnergy[0] -
1022 ENERGY_DEV_OFFSET);
1023 dE = WEBRTC_SPL_ABS_W16(tmp16no1);
1024
1025 if (dE < ENERGY_DEV_TOL) {
1026 // Likely no double talk. The better estimation, the more we can suppress
1027 // signal. Update counters
1028 if (dE < SUPGAIN_EPC_DT) {
1029 tmp32no1 = aecm->supGainErrParamDiffAB * dE;
1030 tmp32no1 += (SUPGAIN_EPC_DT >> 1);
1031 tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(tmp32no1, SUPGAIN_EPC_DT);
1032 supGain = aecm->supGainErrParamA - tmp16no1;
1033 } else {
1034 tmp32no1 = aecm->supGainErrParamDiffBD * (ENERGY_DEV_TOL - dE);
1035 tmp32no1 += ((ENERGY_DEV_TOL - SUPGAIN_EPC_DT) >> 1);
1036 tmp16no1 = (int16_t)WebRtcSpl_DivW32W16(
1037 tmp32no1, (ENERGY_DEV_TOL - SUPGAIN_EPC_DT));
1038 supGain = aecm->supGainErrParamD + tmp16no1;
1039 }
1040 } else {
1041 // Likely in double talk. Use default value
1042 supGain = aecm->supGainErrParamD;
1043 }
1044 }
1045
1046 if (supGain > aecm->supGainOld) {
1047 tmp16no1 = supGain;
1048 } else {
1049 tmp16no1 = aecm->supGainOld;
1050 }
1051 aecm->supGainOld = supGain;
1052 if (tmp16no1 < aecm->supGain) {
1053 aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4);
1054 } else {
1055 aecm->supGain += (int16_t)((tmp16no1 - aecm->supGain) >> 4);
1056 }
1057
1058 // END: Update suppression gain
1059
1060 return aecm->supGain;
1061 }
1062
WebRtcAecm_BufferFarFrame(AecmCore * const aecm,const int16_t * const farend,const int farLen)1063 void WebRtcAecm_BufferFarFrame(AecmCore* const aecm,
1064 const int16_t* const farend,
1065 const int farLen) {
1066 int writeLen = farLen, writePos = 0;
1067
1068 // Check if the write position must be wrapped
1069 while (aecm->farBufWritePos + writeLen > FAR_BUF_LEN) {
1070 // Write to remaining buffer space before wrapping
1071 writeLen = FAR_BUF_LEN - aecm->farBufWritePos;
1072 memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
1073 sizeof(int16_t) * writeLen);
1074 aecm->farBufWritePos = 0;
1075 writePos = writeLen;
1076 writeLen = farLen - writeLen;
1077 }
1078
1079 memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos,
1080 sizeof(int16_t) * writeLen);
1081 aecm->farBufWritePos += writeLen;
1082 }
1083
WebRtcAecm_FetchFarFrame(AecmCore * const aecm,int16_t * const farend,const int farLen,const int knownDelay)1084 void WebRtcAecm_FetchFarFrame(AecmCore* const aecm,
1085 int16_t* const farend,
1086 const int farLen,
1087 const int knownDelay) {
1088 int readLen = farLen;
1089 int readPos = 0;
1090 int delayChange = knownDelay - aecm->lastKnownDelay;
1091
1092 aecm->farBufReadPos -= delayChange;
1093
1094 // Check if delay forces a read position wrap
1095 while (aecm->farBufReadPos < 0) {
1096 aecm->farBufReadPos += FAR_BUF_LEN;
1097 }
1098 while (aecm->farBufReadPos > FAR_BUF_LEN - 1) {
1099 aecm->farBufReadPos -= FAR_BUF_LEN;
1100 }
1101
1102 aecm->lastKnownDelay = knownDelay;
1103
1104 // Check if read position must be wrapped
1105 while (aecm->farBufReadPos + readLen > FAR_BUF_LEN) {
1106 // Read from remaining buffer space before wrapping
1107 readLen = FAR_BUF_LEN - aecm->farBufReadPos;
1108 memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
1109 sizeof(int16_t) * readLen);
1110 aecm->farBufReadPos = 0;
1111 readPos = readLen;
1112 readLen = farLen - readLen;
1113 }
1114 memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos,
1115 sizeof(int16_t) * readLen);
1116 aecm->farBufReadPos += readLen;
1117 }
1118