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