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