1 /* 2 * Copyright (c) 2011 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 "aecm_core.h" 12 13 #include <assert.h> 14 #include <stdlib.h> 15 16 #include "cpu_features_wrapper.h" 17 #include "delay_estimator_wrapper.h" 18 #include "echo_control_mobile.h" 19 #include "ring_buffer.h" 20 #include "typedefs.h" 21 22 #ifdef ARM_WINM_LOG 23 #include <stdio.h> 24 #include <windows.h> 25 #endif 26 27 #ifdef AEC_DEBUG 28 FILE *dfile; 29 FILE *testfile; 30 #endif 31 32 #ifdef _MSC_VER // visual c++ 33 #define ALIGN8_BEG __declspec(align(8)) 34 #define ALIGN8_END 35 #else // gcc or icc 36 #define ALIGN8_BEG 37 #define ALIGN8_END __attribute__((aligned(8))) 38 #endif 39 40 #ifdef AECM_SHORT 41 42 // Square root of Hanning window in Q14 43 const WebRtc_Word16 WebRtcAecm_kSqrtHanning[] = 44 { 45 0, 804, 1606, 2404, 3196, 3981, 4756, 5520, 46 6270, 7005, 7723, 8423, 9102, 9760, 10394, 11003, 47 11585, 12140, 12665, 13160, 13623, 14053, 14449, 14811, 48 15137, 15426, 15679, 15893, 16069, 16207, 16305, 16364, 49 16384 50 }; 51 52 #else 53 54 // Square root of Hanning window in Q14 55 const ALIGN8_BEG WebRtc_Word16 WebRtcAecm_kSqrtHanning[] ALIGN8_END = 56 { 57 0, 399, 798, 1196, 1594, 1990, 2386, 2780, 3172, 58 3562, 3951, 4337, 4720, 5101, 5478, 5853, 6224, 6591, 6954, 7313, 7668, 8019, 8364, 59 8705, 9040, 9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514, 11795, 12068, 12335, 60 12594, 12845, 13089, 13325, 13553, 13773, 13985, 14189, 14384, 14571, 14749, 14918, 61 15079, 15231, 15373, 15506, 15631, 15746, 15851, 15947, 16034, 16111, 16179, 16237, 62 16286, 16325, 16354, 16373, 16384 63 }; 64 65 #endif 66 67 //Q15 alpha = 0.99439986968132 const Factor for magnitude approximation 68 static const WebRtc_UWord16 kAlpha1 = 32584; 69 //Q15 beta = 0.12967166976970 const Factor for magnitude approximation 70 static const WebRtc_UWord16 kBeta1 = 4249; 71 //Q15 alpha = 0.94234827210087 const Factor for magnitude approximation 72 static const WebRtc_UWord16 kAlpha2 = 30879; 73 //Q15 beta = 0.33787806009150 const Factor for magnitude approximation 74 static const WebRtc_UWord16 kBeta2 = 11072; 75 //Q15 alpha = 0.82247698684306 const Factor for magnitude approximation 76 static const WebRtc_UWord16 kAlpha3 = 26951; 77 //Q15 beta = 0.57762063060713 const Factor for magnitude approximation 78 static const WebRtc_UWord16 kBeta3 = 18927; 79 80 // Initialization table for echo channel in 8 kHz 81 static const WebRtc_Word16 kChannelStored8kHz[PART_LEN1] = { 82 2040, 1815, 1590, 1498, 1405, 1395, 1385, 1418, 83 1451, 1506, 1562, 1644, 1726, 1804, 1882, 1918, 84 1953, 1982, 2010, 2025, 2040, 2034, 2027, 2021, 85 2014, 1997, 1980, 1925, 1869, 1800, 1732, 1683, 86 1635, 1604, 1572, 1545, 1517, 1481, 1444, 1405, 87 1367, 1331, 1294, 1270, 1245, 1239, 1233, 1247, 88 1260, 1282, 1303, 1338, 1373, 1407, 1441, 1470, 89 1499, 1524, 1549, 1565, 1582, 1601, 1621, 1649, 90 1676 91 }; 92 93 // Initialization table for echo channel in 16 kHz 94 static const WebRtc_Word16 kChannelStored16kHz[PART_LEN1] = { 95 2040, 1590, 1405, 1385, 1451, 1562, 1726, 1882, 96 1953, 2010, 2040, 2027, 2014, 1980, 1869, 1732, 97 1635, 1572, 1517, 1444, 1367, 1294, 1245, 1233, 98 1260, 1303, 1373, 1441, 1499, 1549, 1582, 1621, 99 1676, 1741, 1802, 1861, 1921, 1983, 2040, 2102, 100 2170, 2265, 2375, 2515, 2651, 2781, 2922, 3075, 101 3253, 3471, 3738, 3976, 4151, 4258, 4308, 4288, 102 4270, 4253, 4237, 4179, 4086, 3947, 3757, 3484, 103 3153 104 }; 105 106 static const WebRtc_Word16 kCosTable[] = { 107 8192, 8190, 8187, 8180, 8172, 8160, 8147, 8130, 8112, 108 8091, 8067, 8041, 8012, 7982, 7948, 7912, 7874, 7834, 109 7791, 7745, 7697, 7647, 7595, 7540, 7483, 7424, 7362, 110 7299, 7233, 7164, 7094, 7021, 6947, 6870, 6791, 6710, 111 6627, 6542, 6455, 6366, 6275, 6182, 6087, 5991, 5892, 112 5792, 5690, 5586, 5481, 5374, 5265, 5155, 5043, 4930, 113 4815, 4698, 4580, 4461, 4341, 4219, 4096, 3971, 3845, 114 3719, 3591, 3462, 3331, 3200, 3068, 2935, 2801, 2667, 115 2531, 2395, 2258, 2120, 1981, 1842, 1703, 1563, 1422, 116 1281, 1140, 998, 856, 713, 571, 428, 285, 142, 117 0, -142, -285, -428, -571, -713, -856, -998, -1140, 118 -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395, 119 -2531, -2667, -2801, -2935, -3068, -3200, -3331, -3462, -3591, 120 -3719, -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698, 121 -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586, -5690, 122 -5792, -5892, -5991, -6087, -6182, -6275, -6366, -6455, -6542, 123 -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164, -7233, 124 -7299, -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745, 125 -7791, -7834, -7874, -7912, -7948, -7982, -8012, -8041, -8067, 126 -8091, -8112, -8130, -8147, -8160, -8172, -8180, -8187, -8190, 127 -8191, -8190, -8187, -8180, -8172, -8160, -8147, -8130, -8112, 128 -8091, -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834, 129 -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362, 130 -7299, -7233, -7164, -7094, -7021, -6947, -6870, -6791, -6710, 131 -6627, -6542, -6455, -6366, -6275, -6182, -6087, -5991, -5892, 132 -5792, -5690, -5586, -5481, -5374, -5265, -5155, -5043, -4930, 133 -4815, -4698, -4580, -4461, -4341, -4219, -4096, -3971, -3845, 134 -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801, -2667, 135 -2531, -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422, 136 -1281, -1140, -998, -856, -713, -571, -428, -285, -142, 137 0, 142, 285, 428, 571, 713, 856, 998, 1140, 138 1281, 1422, 1563, 1703, 1842, 1981, 2120, 2258, 2395, 139 2531, 2667, 2801, 2935, 3068, 3200, 3331, 3462, 3591, 140 3719, 3845, 3971, 4095, 4219, 4341, 4461, 4580, 4698, 141 4815, 4930, 5043, 5155, 5265, 5374, 5481, 5586, 5690, 142 5792, 5892, 5991, 6087, 6182, 6275, 6366, 6455, 6542, 143 6627, 6710, 6791, 6870, 6947, 7021, 7094, 7164, 7233, 144 7299, 7362, 7424, 7483, 7540, 7595, 7647, 7697, 7745, 145 7791, 7834, 7874, 7912, 7948, 7982, 8012, 8041, 8067, 146 8091, 8112, 8130, 8147, 8160, 8172, 8180, 8187, 8190 147 }; 148 149 static const WebRtc_Word16 kSinTable[] = { 150 0, 142, 285, 428, 571, 713, 856, 998, 151 1140, 1281, 1422, 1563, 1703, 1842, 1981, 2120, 152 2258, 2395, 2531, 2667, 2801, 2935, 3068, 3200, 153 3331, 3462, 3591, 3719, 3845, 3971, 4095, 4219, 154 4341, 4461, 4580, 4698, 4815, 4930, 5043, 5155, 155 5265, 5374, 5481, 5586, 5690, 5792, 5892, 5991, 156 6087, 6182, 6275, 6366, 6455, 6542, 6627, 6710, 157 6791, 6870, 6947, 7021, 7094, 7164, 7233, 7299, 158 7362, 7424, 7483, 7540, 7595, 7647, 7697, 7745, 159 7791, 7834, 7874, 7912, 7948, 7982, 8012, 8041, 160 8067, 8091, 8112, 8130, 8147, 8160, 8172, 8180, 161 8187, 8190, 8191, 8190, 8187, 8180, 8172, 8160, 162 8147, 8130, 8112, 8091, 8067, 8041, 8012, 7982, 163 7948, 7912, 7874, 7834, 7791, 7745, 7697, 7647, 164 7595, 7540, 7483, 7424, 7362, 7299, 7233, 7164, 165 7094, 7021, 6947, 6870, 6791, 6710, 6627, 6542, 166 6455, 6366, 6275, 6182, 6087, 5991, 5892, 5792, 167 5690, 5586, 5481, 5374, 5265, 5155, 5043, 4930, 168 4815, 4698, 4580, 4461, 4341, 4219, 4096, 3971, 169 3845, 3719, 3591, 3462, 3331, 3200, 3068, 2935, 170 2801, 2667, 2531, 2395, 2258, 2120, 1981, 1842, 171 1703, 1563, 1422, 1281, 1140, 998, 856, 713, 172 571, 428, 285, 142, 0, -142, -285, -428, 173 -571, -713, -856, -998, -1140, -1281, -1422, -1563, 174 -1703, -1842, -1981, -2120, -2258, -2395, -2531, -2667, 175 -2801, -2935, -3068, -3200, -3331, -3462, -3591, -3719, 176 -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698, 177 -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586, 178 -5690, -5792, -5892, -5991, -6087, -6182, -6275, -6366, 179 -6455, -6542, -6627, -6710, -6791, -6870, -6947, -7021, 180 -7094, -7164, -7233, -7299, -7362, -7424, -7483, -7540, 181 -7595, -7647, -7697, -7745, -7791, -7834, -7874, -7912, 182 -7948, -7982, -8012, -8041, -8067, -8091, -8112, -8130, 183 -8147, -8160, -8172, -8180, -8187, -8190, -8191, -8190, 184 -8187, -8180, -8172, -8160, -8147, -8130, -8112, -8091, 185 -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834, 186 -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, 187 -7362, -7299, -7233, -7164, -7094, -7021, -6947, -6870, 188 -6791, -6710, -6627, -6542, -6455, -6366, -6275, -6182, 189 -6087, -5991, -5892, -5792, -5690, -5586, -5481, -5374, 190 -5265, -5155, -5043, -4930, -4815, -4698, -4580, -4461, 191 -4341, -4219, -4096, -3971, -3845, -3719, -3591, -3462, 192 -3331, -3200, -3068, -2935, -2801, -2667, -2531, -2395, 193 -2258, -2120, -1981, -1842, -1703, -1563, -1422, -1281, 194 -1140, -998, -856, -713, -571, -428, -285, -142 195 }; 196 197 static const WebRtc_Word16 kNoiseEstQDomain = 15; 198 static const WebRtc_Word16 kNoiseEstIncCount = 5; 199 200 static void ComfortNoise(AecmCore_t* aecm, 201 const WebRtc_UWord16* dfa, 202 complex16_t* out, 203 const WebRtc_Word16* lambda); 204 205 static WebRtc_Word16 CalcSuppressionGain(AecmCore_t * const aecm); 206 207 // Moves the pointer to the next entry and inserts |far_spectrum| and 208 // corresponding Q-domain in its buffer. 209 // 210 // Inputs: 211 // - self : Pointer to the delay estimation instance 212 // - far_spectrum : Pointer to the far end spectrum 213 // - far_q : Q-domain of far end spectrum 214 // 215 static void UpdateFarHistory(AecmCore_t* self, 216 uint16_t* far_spectrum, 217 int far_q) { 218 // Get new buffer position 219 self->far_history_pos++; 220 if (self->far_history_pos >= MAX_DELAY) { 221 self->far_history_pos = 0; 222 } 223 // Update Q-domain buffer 224 self->far_q_domains[self->far_history_pos] = far_q; 225 // Update far end spectrum buffer 226 memcpy(&(self->far_history[self->far_history_pos * PART_LEN1]), 227 far_spectrum, 228 sizeof(uint16_t) * PART_LEN1); 229 } 230 231 // Returns a pointer to the far end spectrum aligned to current near end 232 // spectrum. The function WebRtc_DelayEstimatorProcessFix(...) should have been 233 // called before AlignedFarend(...). Otherwise, you get the pointer to the 234 // previous frame. The memory is only valid until the next call of 235 // WebRtc_DelayEstimatorProcessFix(...). 236 // 237 // Inputs: 238 // - self : Pointer to the AECM instance. 239 // - delay : Current delay estimate. 240 // 241 // Output: 242 // - far_q : The Q-domain of the aligned far end spectrum 243 // 244 // Return value: 245 // - far_spectrum : Pointer to the aligned far end spectrum 246 // NULL - Error 247 // 248 static const uint16_t* AlignedFarend(AecmCore_t* self, int* far_q, int delay) { 249 int buffer_position = 0; 250 assert(self != NULL); 251 buffer_position = self->far_history_pos - delay; 252 253 // Check buffer position 254 if (buffer_position < 0) { 255 buffer_position += MAX_DELAY; 256 } 257 // Get Q-domain 258 *far_q = self->far_q_domains[buffer_position]; 259 // Return far end spectrum 260 return &(self->far_history[buffer_position * PART_LEN1]); 261 } 262 263 #ifdef ARM_WINM_LOG 264 HANDLE logFile = NULL; 265 #endif 266 267 // Declare function pointers. 268 CalcLinearEnergies WebRtcAecm_CalcLinearEnergies; 269 StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel; 270 ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel; 271 WindowAndFFT WebRtcAecm_WindowAndFFT; 272 InverseFFTAndWindow WebRtcAecm_InverseFFTAndWindow; 273 274 int WebRtcAecm_CreateCore(AecmCore_t **aecmInst) 275 { 276 AecmCore_t *aecm = malloc(sizeof(AecmCore_t)); 277 *aecmInst = aecm; 278 if (aecm == NULL) 279 { 280 return -1; 281 } 282 283 if (WebRtc_CreateBuffer(&aecm->farFrameBuf, FRAME_LEN + PART_LEN, 284 sizeof(int16_t)) == -1) 285 { 286 WebRtcAecm_FreeCore(aecm); 287 aecm = NULL; 288 return -1; 289 } 290 291 if (WebRtc_CreateBuffer(&aecm->nearNoisyFrameBuf, FRAME_LEN + PART_LEN, 292 sizeof(int16_t)) == -1) 293 { 294 WebRtcAecm_FreeCore(aecm); 295 aecm = NULL; 296 return -1; 297 } 298 299 if (WebRtc_CreateBuffer(&aecm->nearCleanFrameBuf, FRAME_LEN + PART_LEN, 300 sizeof(int16_t)) == -1) 301 { 302 WebRtcAecm_FreeCore(aecm); 303 aecm = NULL; 304 return -1; 305 } 306 307 if (WebRtc_CreateBuffer(&aecm->outFrameBuf, FRAME_LEN + PART_LEN, 308 sizeof(int16_t)) == -1) 309 { 310 WebRtcAecm_FreeCore(aecm); 311 aecm = NULL; 312 return -1; 313 } 314 315 if (WebRtc_CreateDelayEstimator(&aecm->delay_estimator, 316 PART_LEN1, 317 MAX_DELAY, 318 0) == -1) { 319 WebRtcAecm_FreeCore(aecm); 320 aecm = NULL; 321 return -1; 322 } 323 324 // Init some aecm pointers. 16 and 32 byte alignment is only necessary 325 // for Neon code currently. 326 aecm->xBuf = (WebRtc_Word16*) (((uintptr_t)aecm->xBuf_buf + 31) & ~ 31); 327 aecm->dBufClean = (WebRtc_Word16*) (((uintptr_t)aecm->dBufClean_buf + 31) & ~ 31); 328 aecm->dBufNoisy = (WebRtc_Word16*) (((uintptr_t)aecm->dBufNoisy_buf + 31) & ~ 31); 329 aecm->outBuf = (WebRtc_Word16*) (((uintptr_t)aecm->outBuf_buf + 15) & ~ 15); 330 aecm->channelStored = (WebRtc_Word16*) (((uintptr_t) 331 aecm->channelStored_buf + 15) & ~ 15); 332 aecm->channelAdapt16 = (WebRtc_Word16*) (((uintptr_t) 333 aecm->channelAdapt16_buf + 15) & ~ 15); 334 aecm->channelAdapt32 = (WebRtc_Word32*) (((uintptr_t) 335 aecm->channelAdapt32_buf + 31) & ~ 31); 336 337 return 0; 338 } 339 340 void WebRtcAecm_InitEchoPathCore(AecmCore_t* aecm, const WebRtc_Word16* echo_path) 341 { 342 int i = 0; 343 344 // Reset the stored channel 345 memcpy(aecm->channelStored, echo_path, sizeof(WebRtc_Word16) * PART_LEN1); 346 // Reset the adapted channels 347 memcpy(aecm->channelAdapt16, echo_path, sizeof(WebRtc_Word16) * PART_LEN1); 348 for (i = 0; i < PART_LEN1; i++) 349 { 350 aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32( 351 (WebRtc_Word32)(aecm->channelAdapt16[i]), 16); 352 } 353 354 // Reset channel storing variables 355 aecm->mseAdaptOld = 1000; 356 aecm->mseStoredOld = 1000; 357 aecm->mseThreshold = WEBRTC_SPL_WORD32_MAX; 358 aecm->mseChannelCount = 0; 359 } 360 361 static void WindowAndFFTC(WebRtc_Word16* fft, 362 const WebRtc_Word16* time_signal, 363 complex16_t* freq_signal, 364 int time_signal_scaling) 365 { 366 int i, j; 367 368 memset(fft, 0, sizeof(WebRtc_Word16) * PART_LEN4); 369 // FFT of signal 370 for (i = 0, j = 0; i < PART_LEN; i++, j += 2) 371 { 372 // Window time domain signal and insert into real part of 373 // transformation array |fft| 374 fft[j] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( 375 (time_signal[i] << time_signal_scaling), 376 WebRtcAecm_kSqrtHanning[i], 377 14); 378 fft[PART_LEN2 + j] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( 379 (time_signal[i + PART_LEN] << time_signal_scaling), 380 WebRtcAecm_kSqrtHanning[PART_LEN - i], 381 14); 382 // Inserting zeros in imaginary parts not necessary since we 383 // initialized the array with all zeros 384 } 385 386 WebRtcSpl_ComplexBitReverse(fft, PART_LEN_SHIFT); 387 WebRtcSpl_ComplexFFT(fft, PART_LEN_SHIFT, 1); 388 389 // Take only the first PART_LEN2 samples 390 for (i = 0, j = 0; j < PART_LEN2; i += 1, j += 2) 391 { 392 freq_signal[i].real = fft[j]; 393 394 // The imaginary part has to switch sign 395 freq_signal[i].imag = - fft[j+1]; 396 } 397 } 398 399 static void InverseFFTAndWindowC(AecmCore_t* aecm, 400 WebRtc_Word16* fft, 401 complex16_t* efw, 402 WebRtc_Word16* output, 403 const WebRtc_Word16* nearendClean) 404 { 405 int i, j, outCFFT; 406 WebRtc_Word32 tmp32no1; 407 408 // Synthesis 409 for (i = 1; i < PART_LEN; i++) 410 { 411 j = WEBRTC_SPL_LSHIFT_W32(i, 1); 412 fft[j] = efw[i].real; 413 414 // mirrored data, even 415 fft[PART_LEN4 - j] = efw[i].real; 416 fft[j + 1] = -efw[i].imag; 417 418 //mirrored data, odd 419 fft[PART_LEN4 - (j - 1)] = efw[i].imag; 420 } 421 fft[0] = efw[0].real; 422 fft[1] = -efw[0].imag; 423 424 fft[PART_LEN2] = efw[PART_LEN].real; 425 fft[PART_LEN2 + 1] = -efw[PART_LEN].imag; 426 427 // inverse FFT, result should be scaled with outCFFT 428 WebRtcSpl_ComplexBitReverse(fft, PART_LEN_SHIFT); 429 outCFFT = WebRtcSpl_ComplexIFFT(fft, PART_LEN_SHIFT, 1); 430 431 //take only the real values and scale with outCFFT 432 for (i = 0; i < PART_LEN2; i++) 433 { 434 j = WEBRTC_SPL_LSHIFT_W32(i, 1); 435 fft[i] = fft[j]; 436 } 437 438 for (i = 0; i < PART_LEN; i++) 439 { 440 fft[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( 441 fft[i], 442 WebRtcAecm_kSqrtHanning[i], 443 14); 444 tmp32no1 = WEBRTC_SPL_SHIFT_W32((WebRtc_Word32)fft[i], 445 outCFFT - aecm->dfaCleanQDomain); 446 fft[i] = (WebRtc_Word16)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, 447 tmp32no1 + aecm->outBuf[i], 448 WEBRTC_SPL_WORD16_MIN); 449 output[i] = fft[i]; 450 451 tmp32no1 = WEBRTC_SPL_MUL_16_16_RSFT( 452 fft[PART_LEN + i], 453 WebRtcAecm_kSqrtHanning[PART_LEN - i], 454 14); 455 tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, 456 outCFFT - aecm->dfaCleanQDomain); 457 aecm->outBuf[i] = (WebRtc_Word16)WEBRTC_SPL_SAT( 458 WEBRTC_SPL_WORD16_MAX, 459 tmp32no1, 460 WEBRTC_SPL_WORD16_MIN); 461 } 462 463 #ifdef ARM_WINM_LOG_ 464 // measure tick end 465 QueryPerformanceCounter((LARGE_INTEGER*)&end); 466 diff__ = ((end - start) * 1000) / (freq/1000); 467 milliseconds = (unsigned int)(diff__ & 0xffffffff); 468 WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL); 469 #endif 470 471 // Copy the current block to the old position (aecm->outBuf is shifted elsewhere) 472 memcpy(aecm->xBuf, aecm->xBuf + PART_LEN, sizeof(WebRtc_Word16) * PART_LEN); 473 memcpy(aecm->dBufNoisy, aecm->dBufNoisy + PART_LEN, sizeof(WebRtc_Word16) * PART_LEN); 474 if (nearendClean != NULL) 475 { 476 memcpy(aecm->dBufClean, aecm->dBufClean + PART_LEN, sizeof(WebRtc_Word16) * PART_LEN); 477 } 478 } 479 480 static void CalcLinearEnergiesC(AecmCore_t* aecm, 481 const WebRtc_UWord16* far_spectrum, 482 WebRtc_Word32* echo_est, 483 WebRtc_UWord32* far_energy, 484 WebRtc_UWord32* echo_energy_adapt, 485 WebRtc_UWord32* echo_energy_stored) 486 { 487 int i; 488 489 // Get energy for the delayed far end signal and estimated 490 // echo using both stored and adapted channels. 491 for (i = 0; i < PART_LEN1; i++) 492 { 493 echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], 494 far_spectrum[i]); 495 (*far_energy) += (WebRtc_UWord32)(far_spectrum[i]); 496 (*echo_energy_adapt) += WEBRTC_SPL_UMUL_16_16(aecm->channelAdapt16[i], 497 far_spectrum[i]); 498 (*echo_energy_stored) += (WebRtc_UWord32)echo_est[i]; 499 } 500 } 501 502 static void StoreAdaptiveChannelC(AecmCore_t* aecm, 503 const WebRtc_UWord16* far_spectrum, 504 WebRtc_Word32* echo_est) 505 { 506 int i; 507 508 // During startup we store the channel every block. 509 memcpy(aecm->channelStored, aecm->channelAdapt16, sizeof(WebRtc_Word16) * PART_LEN1); 510 // Recalculate echo estimate 511 for (i = 0; i < PART_LEN; i += 4) 512 { 513 echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], 514 far_spectrum[i]); 515 echo_est[i + 1] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1], 516 far_spectrum[i + 1]); 517 echo_est[i + 2] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2], 518 far_spectrum[i + 2]); 519 echo_est[i + 3] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3], 520 far_spectrum[i + 3]); 521 } 522 echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], 523 far_spectrum[i]); 524 } 525 526 static void ResetAdaptiveChannelC(AecmCore_t* aecm) 527 { 528 int i; 529 530 // The stored channel has a significantly lower MSE than the adaptive one for 531 // two consecutive calculations. Reset the adaptive channel. 532 memcpy(aecm->channelAdapt16, aecm->channelStored, 533 sizeof(WebRtc_Word16) * PART_LEN1); 534 // Restore the W32 channel 535 for (i = 0; i < PART_LEN; i += 4) 536 { 537 aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32( 538 (WebRtc_Word32)aecm->channelStored[i], 16); 539 aecm->channelAdapt32[i + 1] = WEBRTC_SPL_LSHIFT_W32( 540 (WebRtc_Word32)aecm->channelStored[i + 1], 16); 541 aecm->channelAdapt32[i + 2] = WEBRTC_SPL_LSHIFT_W32( 542 (WebRtc_Word32)aecm->channelStored[i + 2], 16); 543 aecm->channelAdapt32[i + 3] = WEBRTC_SPL_LSHIFT_W32( 544 (WebRtc_Word32)aecm->channelStored[i + 3], 16); 545 } 546 aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)aecm->channelStored[i], 16); 547 } 548 549 // WebRtcAecm_InitCore(...) 550 // 551 // This function initializes the AECM instant created with WebRtcAecm_CreateCore(...) 552 // Input: 553 // - aecm : Pointer to the Echo Suppression instance 554 // - samplingFreq : Sampling Frequency 555 // 556 // Output: 557 // - aecm : Initialized instance 558 // 559 // Return value : 0 - Ok 560 // -1 - Error 561 // 562 int WebRtcAecm_InitCore(AecmCore_t * const aecm, int samplingFreq) 563 { 564 int i = 0; 565 WebRtc_Word32 tmp32 = PART_LEN1 * PART_LEN1; 566 WebRtc_Word16 tmp16 = PART_LEN1; 567 568 if (samplingFreq != 8000 && samplingFreq != 16000) 569 { 570 samplingFreq = 8000; 571 return -1; 572 } 573 // sanity check of sampling frequency 574 aecm->mult = (WebRtc_Word16)samplingFreq / 8000; 575 576 aecm->farBufWritePos = 0; 577 aecm->farBufReadPos = 0; 578 aecm->knownDelay = 0; 579 aecm->lastKnownDelay = 0; 580 581 WebRtc_InitBuffer(aecm->farFrameBuf); 582 WebRtc_InitBuffer(aecm->nearNoisyFrameBuf); 583 WebRtc_InitBuffer(aecm->nearCleanFrameBuf); 584 WebRtc_InitBuffer(aecm->outFrameBuf); 585 586 memset(aecm->xBuf_buf, 0, sizeof(aecm->xBuf_buf)); 587 memset(aecm->dBufClean_buf, 0, sizeof(aecm->dBufClean_buf)); 588 memset(aecm->dBufNoisy_buf, 0, sizeof(aecm->dBufNoisy_buf)); 589 memset(aecm->outBuf_buf, 0, sizeof(aecm->outBuf_buf)); 590 591 aecm->seed = 666; 592 aecm->totCount = 0; 593 594 if (WebRtc_InitDelayEstimator(aecm->delay_estimator) != 0) { 595 return -1; 596 } 597 // Set far end histories to zero 598 memset(aecm->far_history, 0, sizeof(uint16_t) * PART_LEN1 * MAX_DELAY); 599 memset(aecm->far_q_domains, 0, sizeof(int) * MAX_DELAY); 600 aecm->far_history_pos = MAX_DELAY; 601 602 aecm->nlpFlag = 1; 603 aecm->fixedDelay = -1; 604 605 aecm->dfaCleanQDomain = 0; 606 aecm->dfaCleanQDomainOld = 0; 607 aecm->dfaNoisyQDomain = 0; 608 aecm->dfaNoisyQDomainOld = 0; 609 610 memset(aecm->nearLogEnergy, 0, sizeof(aecm->nearLogEnergy)); 611 aecm->farLogEnergy = 0; 612 memset(aecm->echoAdaptLogEnergy, 0, sizeof(aecm->echoAdaptLogEnergy)); 613 memset(aecm->echoStoredLogEnergy, 0, sizeof(aecm->echoStoredLogEnergy)); 614 615 // Initialize the echo channels with a stored shape. 616 if (samplingFreq == 8000) 617 { 618 WebRtcAecm_InitEchoPathCore(aecm, kChannelStored8kHz); 619 } 620 else 621 { 622 WebRtcAecm_InitEchoPathCore(aecm, kChannelStored16kHz); 623 } 624 625 memset(aecm->echoFilt, 0, sizeof(aecm->echoFilt)); 626 memset(aecm->nearFilt, 0, sizeof(aecm->nearFilt)); 627 aecm->noiseEstCtr = 0; 628 629 aecm->cngMode = AecmTrue; 630 631 memset(aecm->noiseEstTooLowCtr, 0, sizeof(aecm->noiseEstTooLowCtr)); 632 memset(aecm->noiseEstTooHighCtr, 0, sizeof(aecm->noiseEstTooHighCtr)); 633 // Shape the initial noise level to an approximate pink noise. 634 for (i = 0; i < (PART_LEN1 >> 1) - 1; i++) 635 { 636 aecm->noiseEst[i] = (tmp32 << 8); 637 tmp16--; 638 tmp32 -= (WebRtc_Word32)((tmp16 << 1) + 1); 639 } 640 for (; i < PART_LEN1; i++) 641 { 642 aecm->noiseEst[i] = (tmp32 << 8); 643 } 644 645 aecm->farEnergyMin = WEBRTC_SPL_WORD16_MAX; 646 aecm->farEnergyMax = WEBRTC_SPL_WORD16_MIN; 647 aecm->farEnergyMaxMin = 0; 648 aecm->farEnergyVAD = FAR_ENERGY_MIN; // This prevents false speech detection at the 649 // beginning. 650 aecm->farEnergyMSE = 0; 651 aecm->currentVADValue = 0; 652 aecm->vadUpdateCount = 0; 653 aecm->firstVAD = 1; 654 655 aecm->startupState = 0; 656 aecm->supGain = SUPGAIN_DEFAULT; 657 aecm->supGainOld = SUPGAIN_DEFAULT; 658 659 aecm->supGainErrParamA = SUPGAIN_ERROR_PARAM_A; 660 aecm->supGainErrParamD = SUPGAIN_ERROR_PARAM_D; 661 aecm->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B; 662 aecm->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D; 663 664 assert(PART_LEN % 16 == 0); 665 666 // Initialize function pointers. 667 WebRtcAecm_WindowAndFFT = WindowAndFFTC; 668 WebRtcAecm_InverseFFTAndWindow = InverseFFTAndWindowC; 669 WebRtcAecm_CalcLinearEnergies = CalcLinearEnergiesC; 670 WebRtcAecm_StoreAdaptiveChannel = StoreAdaptiveChannelC; 671 WebRtcAecm_ResetAdaptiveChannel = ResetAdaptiveChannelC; 672 673 #ifdef WEBRTC_DETECT_ARM_NEON 674 uint64_t features = WebRtc_GetCPUFeaturesARM(); 675 if ((features & kCPUFeatureNEON) != 0) 676 { 677 WebRtcAecm_InitNeon(); 678 } 679 #elif defined(WEBRTC_ARCH_ARM_NEON) 680 WebRtcAecm_InitNeon(); 681 #endif 682 683 return 0; 684 } 685 686 // TODO(bjornv): This function is currently not used. Add support for these 687 // parameters from a higher level 688 int WebRtcAecm_Control(AecmCore_t *aecm, int delay, int nlpFlag) 689 { 690 aecm->nlpFlag = nlpFlag; 691 aecm->fixedDelay = delay; 692 693 return 0; 694 } 695 696 int WebRtcAecm_FreeCore(AecmCore_t *aecm) 697 { 698 if (aecm == NULL) 699 { 700 return -1; 701 } 702 703 WebRtc_FreeBuffer(aecm->farFrameBuf); 704 WebRtc_FreeBuffer(aecm->nearNoisyFrameBuf); 705 WebRtc_FreeBuffer(aecm->nearCleanFrameBuf); 706 WebRtc_FreeBuffer(aecm->outFrameBuf); 707 708 WebRtc_FreeDelayEstimator(aecm->delay_estimator); 709 free(aecm); 710 711 return 0; 712 } 713 714 int WebRtcAecm_ProcessFrame(AecmCore_t * aecm, 715 const WebRtc_Word16 * farend, 716 const WebRtc_Word16 * nearendNoisy, 717 const WebRtc_Word16 * nearendClean, 718 WebRtc_Word16 * out) 719 { 720 WebRtc_Word16 outBlock_buf[PART_LEN + 8]; // Align buffer to 8-byte boundary. 721 WebRtc_Word16* outBlock = (WebRtc_Word16*) (((uintptr_t) outBlock_buf + 15) & ~ 15); 722 723 WebRtc_Word16 farFrame[FRAME_LEN]; 724 const int16_t* out_ptr = NULL; 725 int size = 0; 726 727 // Buffer the current frame. 728 // Fetch an older one corresponding to the delay. 729 WebRtcAecm_BufferFarFrame(aecm, farend, FRAME_LEN); 730 WebRtcAecm_FetchFarFrame(aecm, farFrame, FRAME_LEN, aecm->knownDelay); 731 732 // Buffer the synchronized far and near frames, 733 // to pass the smaller blocks individually. 734 WebRtc_WriteBuffer(aecm->farFrameBuf, farFrame, FRAME_LEN); 735 WebRtc_WriteBuffer(aecm->nearNoisyFrameBuf, nearendNoisy, FRAME_LEN); 736 if (nearendClean != NULL) 737 { 738 WebRtc_WriteBuffer(aecm->nearCleanFrameBuf, nearendClean, FRAME_LEN); 739 } 740 741 // Process as many blocks as possible. 742 while (WebRtc_available_read(aecm->farFrameBuf) >= PART_LEN) 743 { 744 int16_t far_block[PART_LEN]; 745 const int16_t* far_block_ptr = NULL; 746 int16_t near_noisy_block[PART_LEN]; 747 const int16_t* near_noisy_block_ptr = NULL; 748 749 WebRtc_ReadBuffer(aecm->farFrameBuf, (void**) &far_block_ptr, far_block, 750 PART_LEN); 751 WebRtc_ReadBuffer(aecm->nearNoisyFrameBuf, 752 (void**) &near_noisy_block_ptr, 753 near_noisy_block, 754 PART_LEN); 755 if (nearendClean != NULL) 756 { 757 int16_t near_clean_block[PART_LEN]; 758 const int16_t* near_clean_block_ptr = NULL; 759 760 WebRtc_ReadBuffer(aecm->nearCleanFrameBuf, 761 (void**) &near_clean_block_ptr, 762 near_clean_block, 763 PART_LEN); 764 if (WebRtcAecm_ProcessBlock(aecm, 765 far_block_ptr, 766 near_noisy_block_ptr, 767 near_clean_block_ptr, 768 outBlock) == -1) 769 { 770 return -1; 771 } 772 } else 773 { 774 if (WebRtcAecm_ProcessBlock(aecm, 775 far_block_ptr, 776 near_noisy_block_ptr, 777 NULL, 778 outBlock) == -1) 779 { 780 return -1; 781 } 782 } 783 784 WebRtc_WriteBuffer(aecm->outFrameBuf, outBlock, PART_LEN); 785 } 786 787 // Stuff the out buffer if we have less than a frame to output. 788 // This should only happen for the first frame. 789 size = (int) WebRtc_available_read(aecm->outFrameBuf); 790 if (size < FRAME_LEN) 791 { 792 WebRtc_MoveReadPtr(aecm->outFrameBuf, size - FRAME_LEN); 793 } 794 795 // Obtain an output frame. 796 WebRtc_ReadBuffer(aecm->outFrameBuf, (void**) &out_ptr, out, FRAME_LEN); 797 if (out_ptr != out) { 798 // ReadBuffer() hasn't copied to |out| in this case. 799 memcpy(out, out_ptr, FRAME_LEN * sizeof(int16_t)); 800 } 801 802 return 0; 803 } 804 805 // WebRtcAecm_AsymFilt(...) 806 // 807 // Performs asymmetric filtering. 808 // 809 // Inputs: 810 // - filtOld : Previous filtered value. 811 // - inVal : New input value. 812 // - stepSizePos : Step size when we have a positive contribution. 813 // - stepSizeNeg : Step size when we have a negative contribution. 814 // 815 // Output: 816 // 817 // Return: - Filtered value. 818 // 819 WebRtc_Word16 WebRtcAecm_AsymFilt(const WebRtc_Word16 filtOld, const WebRtc_Word16 inVal, 820 const WebRtc_Word16 stepSizePos, 821 const WebRtc_Word16 stepSizeNeg) 822 { 823 WebRtc_Word16 retVal; 824 825 if ((filtOld == WEBRTC_SPL_WORD16_MAX) | (filtOld == WEBRTC_SPL_WORD16_MIN)) 826 { 827 return inVal; 828 } 829 retVal = filtOld; 830 if (filtOld > inVal) 831 { 832 retVal -= WEBRTC_SPL_RSHIFT_W16(filtOld - inVal, stepSizeNeg); 833 } else 834 { 835 retVal += WEBRTC_SPL_RSHIFT_W16(inVal - filtOld, stepSizePos); 836 } 837 838 return retVal; 839 } 840 841 // WebRtcAecm_CalcEnergies(...) 842 // 843 // This function calculates the log of energies for nearend, farend and estimated 844 // echoes. There is also an update of energy decision levels, i.e. internal VAD. 845 // 846 // 847 // @param aecm [i/o] Handle of the AECM instance. 848 // @param far_spectrum [in] Pointer to farend spectrum. 849 // @param far_q [in] Q-domain of farend spectrum. 850 // @param nearEner [in] Near end energy for current block in 851 // Q(aecm->dfaQDomain). 852 // @param echoEst [out] Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16). 853 // 854 void WebRtcAecm_CalcEnergies(AecmCore_t * aecm, 855 const WebRtc_UWord16* far_spectrum, 856 const WebRtc_Word16 far_q, 857 const WebRtc_UWord32 nearEner, 858 WebRtc_Word32 * echoEst) 859 { 860 // Local variables 861 WebRtc_UWord32 tmpAdapt = 0; 862 WebRtc_UWord32 tmpStored = 0; 863 WebRtc_UWord32 tmpFar = 0; 864 865 int i; 866 867 WebRtc_Word16 zeros, frac; 868 WebRtc_Word16 tmp16; 869 WebRtc_Word16 increase_max_shifts = 4; 870 WebRtc_Word16 decrease_max_shifts = 11; 871 WebRtc_Word16 increase_min_shifts = 11; 872 WebRtc_Word16 decrease_min_shifts = 3; 873 WebRtc_Word16 kLogLowValue = WEBRTC_SPL_LSHIFT_W16(PART_LEN_SHIFT, 7); 874 875 // Get log of near end energy and store in buffer 876 877 // Shift buffer 878 memmove(aecm->nearLogEnergy + 1, aecm->nearLogEnergy, 879 sizeof(WebRtc_Word16) * (MAX_BUF_LEN - 1)); 880 881 // Logarithm of integrated magnitude spectrum (nearEner) 882 tmp16 = kLogLowValue; 883 if (nearEner) 884 { 885 zeros = WebRtcSpl_NormU32(nearEner); 886 frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32( 887 (WEBRTC_SPL_LSHIFT_U32(nearEner, zeros) & 0x7FFFFFFF), 888 23); 889 // log2 in Q8 890 tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac; 891 tmp16 -= WEBRTC_SPL_LSHIFT_W16(aecm->dfaNoisyQDomain, 8); 892 } 893 aecm->nearLogEnergy[0] = tmp16; 894 // END: Get log of near end energy 895 896 WebRtcAecm_CalcLinearEnergies(aecm, far_spectrum, echoEst, &tmpFar, &tmpAdapt, &tmpStored); 897 898 // Shift buffers 899 memmove(aecm->echoAdaptLogEnergy + 1, aecm->echoAdaptLogEnergy, 900 sizeof(WebRtc_Word16) * (MAX_BUF_LEN - 1)); 901 memmove(aecm->echoStoredLogEnergy + 1, aecm->echoStoredLogEnergy, 902 sizeof(WebRtc_Word16) * (MAX_BUF_LEN - 1)); 903 904 // Logarithm of delayed far end energy 905 tmp16 = kLogLowValue; 906 if (tmpFar) 907 { 908 zeros = WebRtcSpl_NormU32(tmpFar); 909 frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32((WEBRTC_SPL_LSHIFT_U32(tmpFar, zeros) 910 & 0x7FFFFFFF), 23); 911 // log2 in Q8 912 tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac; 913 tmp16 -= WEBRTC_SPL_LSHIFT_W16(far_q, 8); 914 } 915 aecm->farLogEnergy = tmp16; 916 917 // Logarithm of estimated echo energy through adapted channel 918 tmp16 = kLogLowValue; 919 if (tmpAdapt) 920 { 921 zeros = WebRtcSpl_NormU32(tmpAdapt); 922 frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32((WEBRTC_SPL_LSHIFT_U32(tmpAdapt, zeros) 923 & 0x7FFFFFFF), 23); 924 //log2 in Q8 925 tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac; 926 tmp16 -= WEBRTC_SPL_LSHIFT_W16(RESOLUTION_CHANNEL16 + far_q, 8); 927 } 928 aecm->echoAdaptLogEnergy[0] = tmp16; 929 930 // Logarithm of estimated echo energy through stored channel 931 tmp16 = kLogLowValue; 932 if (tmpStored) 933 { 934 zeros = WebRtcSpl_NormU32(tmpStored); 935 frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32((WEBRTC_SPL_LSHIFT_U32(tmpStored, zeros) 936 & 0x7FFFFFFF), 23); 937 //log2 in Q8 938 tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac; 939 tmp16 -= WEBRTC_SPL_LSHIFT_W16(RESOLUTION_CHANNEL16 + far_q, 8); 940 } 941 aecm->echoStoredLogEnergy[0] = tmp16; 942 943 // Update farend energy levels (min, max, vad, mse) 944 if (aecm->farLogEnergy > FAR_ENERGY_MIN) 945 { 946 if (aecm->startupState == 0) 947 { 948 increase_max_shifts = 2; 949 decrease_min_shifts = 2; 950 increase_min_shifts = 8; 951 } 952 953 aecm->farEnergyMin = WebRtcAecm_AsymFilt(aecm->farEnergyMin, aecm->farLogEnergy, 954 increase_min_shifts, decrease_min_shifts); 955 aecm->farEnergyMax = WebRtcAecm_AsymFilt(aecm->farEnergyMax, aecm->farLogEnergy, 956 increase_max_shifts, decrease_max_shifts); 957 aecm->farEnergyMaxMin = (aecm->farEnergyMax - aecm->farEnergyMin); 958 959 // Dynamic VAD region size 960 tmp16 = 2560 - aecm->farEnergyMin; 961 if (tmp16 > 0) 962 { 963 tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16, FAR_ENERGY_VAD_REGION, 9); 964 } else 965 { 966 tmp16 = 0; 967 } 968 tmp16 += FAR_ENERGY_VAD_REGION; 969 970 if ((aecm->startupState == 0) | (aecm->vadUpdateCount > 1024)) 971 { 972 // In startup phase or VAD update halted 973 aecm->farEnergyVAD = aecm->farEnergyMin + tmp16; 974 } else 975 { 976 if (aecm->farEnergyVAD > aecm->farLogEnergy) 977 { 978 aecm->farEnergyVAD += WEBRTC_SPL_RSHIFT_W16(aecm->farLogEnergy + 979 tmp16 - 980 aecm->farEnergyVAD, 981 6); 982 aecm->vadUpdateCount = 0; 983 } else 984 { 985 aecm->vadUpdateCount++; 986 } 987 } 988 // Put MSE threshold higher than VAD 989 aecm->farEnergyMSE = aecm->farEnergyVAD + (1 << 8); 990 } 991 992 // Update VAD variables 993 if (aecm->farLogEnergy > aecm->farEnergyVAD) 994 { 995 if ((aecm->startupState == 0) | (aecm->farEnergyMaxMin > FAR_ENERGY_DIFF)) 996 { 997 // We are in startup or have significant dynamics in input speech level 998 aecm->currentVADValue = 1; 999 } 1000 } else 1001 { 1002 aecm->currentVADValue = 0; 1003 } 1004 if ((aecm->currentVADValue) && (aecm->firstVAD)) 1005 { 1006 aecm->firstVAD = 0; 1007 if (aecm->echoAdaptLogEnergy[0] > aecm->nearLogEnergy[0]) 1008 { 1009 // The estimated echo has higher energy than the near end signal. 1010 // This means that the initialization was too aggressive. Scale 1011 // down by a factor 8 1012 for (i = 0; i < PART_LEN1; i++) 1013 { 1014 aecm->channelAdapt16[i] >>= 3; 1015 } 1016 // Compensate the adapted echo energy level accordingly. 1017 aecm->echoAdaptLogEnergy[0] -= (3 << 8); 1018 aecm->firstVAD = 1; 1019 } 1020 } 1021 } 1022 1023 // WebRtcAecm_CalcStepSize(...) 1024 // 1025 // This function calculates the step size used in channel estimation 1026 // 1027 // 1028 // @param aecm [in] Handle of the AECM instance. 1029 // @param mu [out] (Return value) Stepsize in log2(), i.e. number of shifts. 1030 // 1031 // 1032 WebRtc_Word16 WebRtcAecm_CalcStepSize(AecmCore_t * const aecm) 1033 { 1034 1035 WebRtc_Word32 tmp32; 1036 WebRtc_Word16 tmp16; 1037 WebRtc_Word16 mu = MU_MAX; 1038 1039 // Here we calculate the step size mu used in the 1040 // following NLMS based Channel estimation algorithm 1041 if (!aecm->currentVADValue) 1042 { 1043 // Far end energy level too low, no channel update 1044 mu = 0; 1045 } else if (aecm->startupState > 0) 1046 { 1047 if (aecm->farEnergyMin >= aecm->farEnergyMax) 1048 { 1049 mu = MU_MIN; 1050 } else 1051 { 1052 tmp16 = (aecm->farLogEnergy - aecm->farEnergyMin); 1053 tmp32 = WEBRTC_SPL_MUL_16_16(tmp16, MU_DIFF); 1054 tmp32 = WebRtcSpl_DivW32W16(tmp32, aecm->farEnergyMaxMin); 1055 mu = MU_MIN - 1 - (WebRtc_Word16)(tmp32); 1056 // The -1 is an alternative to rounding. This way we get a larger 1057 // stepsize, so we in some sense compensate for truncation in NLMS 1058 } 1059 if (mu < MU_MAX) 1060 { 1061 mu = MU_MAX; // Equivalent with maximum step size of 2^-MU_MAX 1062 } 1063 } 1064 1065 return mu; 1066 } 1067 1068 // WebRtcAecm_UpdateChannel(...) 1069 // 1070 // This function performs channel estimation. NLMS and decision on channel storage. 1071 // 1072 // 1073 // @param aecm [i/o] Handle of the AECM instance. 1074 // @param far_spectrum [in] Absolute value of the farend signal in Q(far_q) 1075 // @param far_q [in] Q-domain of the farend signal 1076 // @param dfa [in] Absolute value of the nearend signal (Q[aecm->dfaQDomain]) 1077 // @param mu [in] NLMS step size. 1078 // @param echoEst [i/o] Estimated echo in Q(far_q+RESOLUTION_CHANNEL16). 1079 // 1080 void WebRtcAecm_UpdateChannel(AecmCore_t * aecm, 1081 const WebRtc_UWord16* far_spectrum, 1082 const WebRtc_Word16 far_q, 1083 const WebRtc_UWord16 * const dfa, 1084 const WebRtc_Word16 mu, 1085 WebRtc_Word32 * echoEst) 1086 { 1087 1088 WebRtc_UWord32 tmpU32no1, tmpU32no2; 1089 WebRtc_Word32 tmp32no1, tmp32no2; 1090 WebRtc_Word32 mseStored; 1091 WebRtc_Word32 mseAdapt; 1092 1093 int i; 1094 1095 WebRtc_Word16 zerosFar, zerosNum, zerosCh, zerosDfa; 1096 WebRtc_Word16 shiftChFar, shiftNum, shift2ResChan; 1097 WebRtc_Word16 tmp16no1; 1098 WebRtc_Word16 xfaQ, dfaQ; 1099 1100 // This is the channel estimation algorithm. It is base on NLMS but has a variable step 1101 // length, which was calculated above. 1102 if (mu) 1103 { 1104 for (i = 0; i < PART_LEN1; i++) 1105 { 1106 // Determine norm of channel and farend to make sure we don't get overflow in 1107 // multiplication 1108 zerosCh = WebRtcSpl_NormU32(aecm->channelAdapt32[i]); 1109 zerosFar = WebRtcSpl_NormU32((WebRtc_UWord32)far_spectrum[i]); 1110 if (zerosCh + zerosFar > 31) 1111 { 1112 // Multiplication is safe 1113 tmpU32no1 = WEBRTC_SPL_UMUL_32_16(aecm->channelAdapt32[i], 1114 far_spectrum[i]); 1115 shiftChFar = 0; 1116 } else 1117 { 1118 // We need to shift down before multiplication 1119 shiftChFar = 32 - zerosCh - zerosFar; 1120 tmpU32no1 = WEBRTC_SPL_UMUL_32_16( 1121 WEBRTC_SPL_RSHIFT_W32(aecm->channelAdapt32[i], shiftChFar), 1122 far_spectrum[i]); 1123 } 1124 // Determine Q-domain of numerator 1125 zerosNum = WebRtcSpl_NormU32(tmpU32no1); 1126 if (dfa[i]) 1127 { 1128 zerosDfa = WebRtcSpl_NormU32((WebRtc_UWord32)dfa[i]); 1129 } else 1130 { 1131 zerosDfa = 32; 1132 } 1133 tmp16no1 = zerosDfa - 2 + aecm->dfaNoisyQDomain - 1134 RESOLUTION_CHANNEL32 - far_q + shiftChFar; 1135 if (zerosNum > tmp16no1 + 1) 1136 { 1137 xfaQ = tmp16no1; 1138 dfaQ = zerosDfa - 2; 1139 } else 1140 { 1141 xfaQ = zerosNum - 2; 1142 dfaQ = RESOLUTION_CHANNEL32 + far_q - aecm->dfaNoisyQDomain - 1143 shiftChFar + xfaQ; 1144 } 1145 // Add in the same Q-domain 1146 tmpU32no1 = WEBRTC_SPL_SHIFT_W32(tmpU32no1, xfaQ); 1147 tmpU32no2 = WEBRTC_SPL_SHIFT_W32((WebRtc_UWord32)dfa[i], dfaQ); 1148 tmp32no1 = (WebRtc_Word32)tmpU32no2 - (WebRtc_Word32)tmpU32no1; 1149 zerosNum = WebRtcSpl_NormW32(tmp32no1); 1150 if ((tmp32no1) && (far_spectrum[i] > (CHANNEL_VAD << far_q))) 1151 { 1152 // 1153 // Update is needed 1154 // 1155 // This is what we would like to compute 1156 // 1157 // tmp32no1 = dfa[i] - (aecm->channelAdapt[i] * far_spectrum[i]) 1158 // tmp32norm = (i + 1) 1159 // aecm->channelAdapt[i] += (2^mu) * tmp32no1 1160 // / (tmp32norm * far_spectrum[i]) 1161 // 1162 1163 // Make sure we don't get overflow in multiplication. 1164 if (zerosNum + zerosFar > 31) 1165 { 1166 if (tmp32no1 > 0) 1167 { 1168 tmp32no2 = (WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(tmp32no1, 1169 far_spectrum[i]); 1170 } else 1171 { 1172 tmp32no2 = -(WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(-tmp32no1, 1173 far_spectrum[i]); 1174 } 1175 shiftNum = 0; 1176 } else 1177 { 1178 shiftNum = 32 - (zerosNum + zerosFar); 1179 if (tmp32no1 > 0) 1180 { 1181 tmp32no2 = (WebRtc_Word32)WEBRTC_SPL_UMUL_32_16( 1182 WEBRTC_SPL_RSHIFT_W32(tmp32no1, shiftNum), 1183 far_spectrum[i]); 1184 } else 1185 { 1186 tmp32no2 = -(WebRtc_Word32)WEBRTC_SPL_UMUL_32_16( 1187 WEBRTC_SPL_RSHIFT_W32(-tmp32no1, shiftNum), 1188 far_spectrum[i]); 1189 } 1190 } 1191 // Normalize with respect to frequency bin 1192 tmp32no2 = WebRtcSpl_DivW32W16(tmp32no2, i + 1); 1193 // Make sure we are in the right Q-domain 1194 shift2ResChan = shiftNum + shiftChFar - xfaQ - mu - ((30 - zerosFar) << 1); 1195 if (WebRtcSpl_NormW32(tmp32no2) < shift2ResChan) 1196 { 1197 tmp32no2 = WEBRTC_SPL_WORD32_MAX; 1198 } else 1199 { 1200 tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, shift2ResChan); 1201 } 1202 aecm->channelAdapt32[i] = WEBRTC_SPL_ADD_SAT_W32(aecm->channelAdapt32[i], 1203 tmp32no2); 1204 if (aecm->channelAdapt32[i] < 0) 1205 { 1206 // We can never have negative channel gain 1207 aecm->channelAdapt32[i] = 0; 1208 } 1209 aecm->channelAdapt16[i] 1210 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(aecm->channelAdapt32[i], 16); 1211 } 1212 } 1213 } 1214 // END: Adaptive channel update 1215 1216 // Determine if we should store or restore the channel 1217 if ((aecm->startupState == 0) & (aecm->currentVADValue)) 1218 { 1219 // During startup we store the channel every block, 1220 // and we recalculate echo estimate 1221 WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst); 1222 } else 1223 { 1224 if (aecm->farLogEnergy < aecm->farEnergyMSE) 1225 { 1226 aecm->mseChannelCount = 0; 1227 } else 1228 { 1229 aecm->mseChannelCount++; 1230 } 1231 // Enough data for validation. Store channel if we can. 1232 if (aecm->mseChannelCount >= (MIN_MSE_COUNT + 10)) 1233 { 1234 // We have enough data. 1235 // Calculate MSE of "Adapt" and "Stored" versions. 1236 // It is actually not MSE, but average absolute error. 1237 mseStored = 0; 1238 mseAdapt = 0; 1239 for (i = 0; i < MIN_MSE_COUNT; i++) 1240 { 1241 tmp32no1 = ((WebRtc_Word32)aecm->echoStoredLogEnergy[i] 1242 - (WebRtc_Word32)aecm->nearLogEnergy[i]); 1243 tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1); 1244 mseStored += tmp32no2; 1245 1246 tmp32no1 = ((WebRtc_Word32)aecm->echoAdaptLogEnergy[i] 1247 - (WebRtc_Word32)aecm->nearLogEnergy[i]); 1248 tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1); 1249 mseAdapt += tmp32no2; 1250 } 1251 if (((mseStored << MSE_RESOLUTION) < (MIN_MSE_DIFF * mseAdapt)) 1252 & ((aecm->mseStoredOld << MSE_RESOLUTION) < (MIN_MSE_DIFF 1253 * aecm->mseAdaptOld))) 1254 { 1255 // The stored channel has a significantly lower MSE than the adaptive one for 1256 // two consecutive calculations. Reset the adaptive channel. 1257 WebRtcAecm_ResetAdaptiveChannel(aecm); 1258 } else if (((MIN_MSE_DIFF * mseStored) > (mseAdapt << MSE_RESOLUTION)) & (mseAdapt 1259 < aecm->mseThreshold) & (aecm->mseAdaptOld < aecm->mseThreshold)) 1260 { 1261 // The adaptive channel has a significantly lower MSE than the stored one. 1262 // The MSE for the adaptive channel has also been low for two consecutive 1263 // calculations. Store the adaptive channel. 1264 WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst); 1265 1266 // Update threshold 1267 if (aecm->mseThreshold == WEBRTC_SPL_WORD32_MAX) 1268 { 1269 aecm->mseThreshold = (mseAdapt + aecm->mseAdaptOld); 1270 } else 1271 { 1272 aecm->mseThreshold += WEBRTC_SPL_MUL_16_16_RSFT(mseAdapt 1273 - WEBRTC_SPL_MUL_16_16_RSFT(aecm->mseThreshold, 5, 3), 205, 8); 1274 } 1275 1276 } 1277 1278 // Reset counter 1279 aecm->mseChannelCount = 0; 1280 1281 // Store the MSE values. 1282 aecm->mseStoredOld = mseStored; 1283 aecm->mseAdaptOld = mseAdapt; 1284 } 1285 } 1286 // END: Determine if we should store or reset channel estimate. 1287 } 1288 1289 // CalcSuppressionGain(...) 1290 // 1291 // This function calculates the suppression gain that is used in the Wiener filter. 1292 // 1293 // 1294 // @param aecm [i/n] Handle of the AECM instance. 1295 // @param supGain [out] (Return value) Suppression gain with which to scale the noise 1296 // level (Q14). 1297 // 1298 // 1299 static WebRtc_Word16 CalcSuppressionGain(AecmCore_t * const aecm) 1300 { 1301 WebRtc_Word32 tmp32no1; 1302 1303 WebRtc_Word16 supGain = SUPGAIN_DEFAULT; 1304 WebRtc_Word16 tmp16no1; 1305 WebRtc_Word16 dE = 0; 1306 1307 // Determine suppression gain used in the Wiener filter. The gain is based on a mix of far 1308 // end energy and echo estimation error. 1309 // Adjust for the far end signal level. A low signal level indicates no far end signal, 1310 // hence we set the suppression gain to 0 1311 if (!aecm->currentVADValue) 1312 { 1313 supGain = 0; 1314 } else 1315 { 1316 // Adjust for possible double talk. If we have large variations in estimation error we 1317 // likely have double talk (or poor channel). 1318 tmp16no1 = (aecm->nearLogEnergy[0] - aecm->echoStoredLogEnergy[0] - ENERGY_DEV_OFFSET); 1319 dE = WEBRTC_SPL_ABS_W16(tmp16no1); 1320 1321 if (dE < ENERGY_DEV_TOL) 1322 { 1323 // Likely no double talk. The better estimation, the more we can suppress signal. 1324 // Update counters 1325 if (dE < SUPGAIN_EPC_DT) 1326 { 1327 tmp32no1 = WEBRTC_SPL_MUL_16_16(aecm->supGainErrParamDiffAB, dE); 1328 tmp32no1 += (SUPGAIN_EPC_DT >> 1); 1329 tmp16no1 = (WebRtc_Word16)WebRtcSpl_DivW32W16(tmp32no1, SUPGAIN_EPC_DT); 1330 supGain = aecm->supGainErrParamA - tmp16no1; 1331 } else 1332 { 1333 tmp32no1 = WEBRTC_SPL_MUL_16_16(aecm->supGainErrParamDiffBD, 1334 (ENERGY_DEV_TOL - dE)); 1335 tmp32no1 += ((ENERGY_DEV_TOL - SUPGAIN_EPC_DT) >> 1); 1336 tmp16no1 = (WebRtc_Word16)WebRtcSpl_DivW32W16(tmp32no1, (ENERGY_DEV_TOL 1337 - SUPGAIN_EPC_DT)); 1338 supGain = aecm->supGainErrParamD + tmp16no1; 1339 } 1340 } else 1341 { 1342 // Likely in double talk. Use default value 1343 supGain = aecm->supGainErrParamD; 1344 } 1345 } 1346 1347 if (supGain > aecm->supGainOld) 1348 { 1349 tmp16no1 = supGain; 1350 } else 1351 { 1352 tmp16no1 = aecm->supGainOld; 1353 } 1354 aecm->supGainOld = supGain; 1355 if (tmp16no1 < aecm->supGain) 1356 { 1357 aecm->supGain += (WebRtc_Word16)((tmp16no1 - aecm->supGain) >> 4); 1358 } else 1359 { 1360 aecm->supGain += (WebRtc_Word16)((tmp16no1 - aecm->supGain) >> 4); 1361 } 1362 1363 // END: Update suppression gain 1364 1365 return aecm->supGain; 1366 } 1367 1368 // Transforms a time domain signal into the frequency domain, outputting the 1369 // complex valued signal, absolute value and sum of absolute values. 1370 // 1371 // time_signal [in] Pointer to time domain signal 1372 // freq_signal_real [out] Pointer to real part of frequency domain array 1373 // freq_signal_imag [out] Pointer to imaginary part of frequency domain 1374 // array 1375 // freq_signal_abs [out] Pointer to absolute value of frequency domain 1376 // array 1377 // freq_signal_sum_abs [out] Pointer to the sum of all absolute values in 1378 // the frequency domain array 1379 // return value The Q-domain of current frequency values 1380 // 1381 static int TimeToFrequencyDomain(const WebRtc_Word16* time_signal, 1382 complex16_t* freq_signal, 1383 WebRtc_UWord16* freq_signal_abs, 1384 WebRtc_UWord32* freq_signal_sum_abs) 1385 { 1386 int i = 0; 1387 int time_signal_scaling = 0; 1388 1389 WebRtc_Word32 tmp32no1; 1390 WebRtc_Word32 tmp32no2; 1391 1392 // In fft_buf, +16 for 32-byte alignment. 1393 WebRtc_Word16 fft_buf[PART_LEN4 + 16]; 1394 WebRtc_Word16 *fft = (WebRtc_Word16 *) (((uintptr_t) fft_buf + 31) & ~31); 1395 1396 WebRtc_Word16 tmp16no1; 1397 WebRtc_Word16 tmp16no2; 1398 #ifdef AECM_WITH_ABS_APPROX 1399 WebRtc_Word16 max_value = 0; 1400 WebRtc_Word16 min_value = 0; 1401 WebRtc_UWord16 alpha = 0; 1402 WebRtc_UWord16 beta = 0; 1403 #endif 1404 1405 #ifdef AECM_DYNAMIC_Q 1406 tmp16no1 = WebRtcSpl_MaxAbsValueW16(time_signal, PART_LEN2); 1407 time_signal_scaling = WebRtcSpl_NormW16(tmp16no1); 1408 #endif 1409 1410 WebRtcAecm_WindowAndFFT(fft, time_signal, freq_signal, time_signal_scaling); 1411 1412 // Extract imaginary and real part, calculate the magnitude for all frequency bins 1413 freq_signal[0].imag = 0; 1414 freq_signal[PART_LEN].imag = 0; 1415 freq_signal[PART_LEN].real = fft[PART_LEN2]; 1416 freq_signal_abs[0] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16( 1417 freq_signal[0].real); 1418 freq_signal_abs[PART_LEN] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16( 1419 freq_signal[PART_LEN].real); 1420 (*freq_signal_sum_abs) = (WebRtc_UWord32)(freq_signal_abs[0]) + 1421 (WebRtc_UWord32)(freq_signal_abs[PART_LEN]); 1422 1423 for (i = 1; i < PART_LEN; i++) 1424 { 1425 if (freq_signal[i].real == 0) 1426 { 1427 freq_signal_abs[i] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16( 1428 freq_signal[i].imag); 1429 } 1430 else if (freq_signal[i].imag == 0) 1431 { 1432 freq_signal_abs[i] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16( 1433 freq_signal[i].real); 1434 } 1435 else 1436 { 1437 // Approximation for magnitude of complex fft output 1438 // magn = sqrt(real^2 + imag^2) 1439 // magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|) 1440 // 1441 // The parameters alpha and beta are stored in Q15 1442 1443 #ifdef AECM_WITH_ABS_APPROX 1444 tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real); 1445 tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag); 1446 1447 if(tmp16no1 > tmp16no2) 1448 { 1449 max_value = tmp16no1; 1450 min_value = tmp16no2; 1451 } else 1452 { 1453 max_value = tmp16no2; 1454 min_value = tmp16no1; 1455 } 1456 1457 // Magnitude in Q(-6) 1458 if ((max_value >> 2) > min_value) 1459 { 1460 alpha = kAlpha1; 1461 beta = kBeta1; 1462 } else if ((max_value >> 1) > min_value) 1463 { 1464 alpha = kAlpha2; 1465 beta = kBeta2; 1466 } else 1467 { 1468 alpha = kAlpha3; 1469 beta = kBeta3; 1470 } 1471 tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(max_value, 1472 alpha, 1473 15); 1474 tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(min_value, 1475 beta, 1476 15); 1477 freq_signal_abs[i] = (WebRtc_UWord16)tmp16no1 + 1478 (WebRtc_UWord16)tmp16no2; 1479 #else 1480 #ifdef WEBRTC_ARCH_ARM_V7A 1481 __asm__("smulbb %0, %1, %2" : "=r"(tmp32no1) : "r"(freq_signal[i].real), 1482 "r"(freq_signal[i].real)); 1483 __asm__("smlabb %0, %1, %2, %3" :: "r"(tmp32no2), "r"(freq_signal[i].imag), 1484 "r"(freq_signal[i].imag), "r"(tmp32no1)); 1485 #else 1486 tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real); 1487 tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag); 1488 tmp32no1 = WEBRTC_SPL_MUL_16_16(tmp16no1, tmp16no1); 1489 tmp32no2 = WEBRTC_SPL_MUL_16_16(tmp16no2, tmp16no2); 1490 tmp32no2 = WEBRTC_SPL_ADD_SAT_W32(tmp32no1, tmp32no2); 1491 #endif // WEBRTC_ARCH_ARM_V7A 1492 tmp32no1 = WebRtcSpl_SqrtFloor(tmp32no2); 1493 1494 freq_signal_abs[i] = (WebRtc_UWord16)tmp32no1; 1495 #endif // AECM_WITH_ABS_APPROX 1496 } 1497 (*freq_signal_sum_abs) += (WebRtc_UWord32)freq_signal_abs[i]; 1498 } 1499 1500 return time_signal_scaling; 1501 } 1502 1503 int WebRtcAecm_ProcessBlock(AecmCore_t * aecm, 1504 const WebRtc_Word16 * farend, 1505 const WebRtc_Word16 * nearendNoisy, 1506 const WebRtc_Word16 * nearendClean, 1507 WebRtc_Word16 * output) 1508 { 1509 int i; 1510 1511 WebRtc_UWord32 xfaSum; 1512 WebRtc_UWord32 dfaNoisySum; 1513 WebRtc_UWord32 dfaCleanSum; 1514 WebRtc_UWord32 echoEst32Gained; 1515 WebRtc_UWord32 tmpU32; 1516 1517 WebRtc_Word32 tmp32no1; 1518 1519 WebRtc_UWord16 xfa[PART_LEN1]; 1520 WebRtc_UWord16 dfaNoisy[PART_LEN1]; 1521 WebRtc_UWord16 dfaClean[PART_LEN1]; 1522 WebRtc_UWord16* ptrDfaClean = dfaClean; 1523 const WebRtc_UWord16* far_spectrum_ptr = NULL; 1524 1525 // 32 byte aligned buffers (with +8 or +16). 1526 // TODO (kma): define fft with complex16_t. 1527 WebRtc_Word16 fft_buf[PART_LEN4 + 2 + 16]; // +2 to make a loop safe. 1528 WebRtc_Word32 echoEst32_buf[PART_LEN1 + 8]; 1529 WebRtc_Word32 dfw_buf[PART_LEN1 + 8]; 1530 WebRtc_Word32 efw_buf[PART_LEN1 + 8]; 1531 1532 WebRtc_Word16* fft = (WebRtc_Word16*) (((uintptr_t) fft_buf + 31) & ~ 31); 1533 WebRtc_Word32* echoEst32 = (WebRtc_Word32*) (((uintptr_t) echoEst32_buf + 31) & ~ 31); 1534 complex16_t* dfw = (complex16_t*) (((uintptr_t) dfw_buf + 31) & ~ 31); 1535 complex16_t* efw = (complex16_t*) (((uintptr_t) efw_buf + 31) & ~ 31); 1536 1537 WebRtc_Word16 hnl[PART_LEN1]; 1538 WebRtc_Word16 numPosCoef = 0; 1539 WebRtc_Word16 nlpGain = ONE_Q14; 1540 int delay; 1541 WebRtc_Word16 tmp16no1; 1542 WebRtc_Word16 tmp16no2; 1543 WebRtc_Word16 mu; 1544 WebRtc_Word16 supGain; 1545 WebRtc_Word16 zeros32, zeros16; 1546 WebRtc_Word16 zerosDBufNoisy, zerosDBufClean, zerosXBuf; 1547 int far_q; 1548 WebRtc_Word16 resolutionDiff, qDomainDiff; 1549 1550 const int kMinPrefBand = 4; 1551 const int kMaxPrefBand = 24; 1552 WebRtc_Word32 avgHnl32 = 0; 1553 1554 #ifdef ARM_WINM_LOG_ 1555 DWORD temp; 1556 static int flag0 = 0; 1557 __int64 freq, start, end, diff__; 1558 unsigned int milliseconds; 1559 #endif 1560 1561 // Determine startup state. There are three states: 1562 // (0) the first CONV_LEN blocks 1563 // (1) another CONV_LEN blocks 1564 // (2) the rest 1565 1566 if (aecm->startupState < 2) 1567 { 1568 aecm->startupState = (aecm->totCount >= CONV_LEN) + (aecm->totCount >= CONV_LEN2); 1569 } 1570 // END: Determine startup state 1571 1572 // Buffer near and far end signals 1573 memcpy(aecm->xBuf + PART_LEN, farend, sizeof(WebRtc_Word16) * PART_LEN); 1574 memcpy(aecm->dBufNoisy + PART_LEN, nearendNoisy, sizeof(WebRtc_Word16) * PART_LEN); 1575 if (nearendClean != NULL) 1576 { 1577 memcpy(aecm->dBufClean + PART_LEN, nearendClean, sizeof(WebRtc_Word16) * PART_LEN); 1578 } 1579 1580 #ifdef ARM_WINM_LOG_ 1581 // measure tick start 1582 QueryPerformanceFrequency((LARGE_INTEGER*)&freq); 1583 QueryPerformanceCounter((LARGE_INTEGER*)&start); 1584 #endif 1585 1586 // Transform far end signal from time domain to frequency domain. 1587 far_q = TimeToFrequencyDomain(aecm->xBuf, 1588 dfw, 1589 xfa, 1590 &xfaSum); 1591 1592 // Transform noisy near end signal from time domain to frequency domain. 1593 zerosDBufNoisy = TimeToFrequencyDomain(aecm->dBufNoisy, 1594 dfw, 1595 dfaNoisy, 1596 &dfaNoisySum); 1597 aecm->dfaNoisyQDomainOld = aecm->dfaNoisyQDomain; 1598 aecm->dfaNoisyQDomain = (WebRtc_Word16)zerosDBufNoisy; 1599 1600 1601 if (nearendClean == NULL) 1602 { 1603 ptrDfaClean = dfaNoisy; 1604 aecm->dfaCleanQDomainOld = aecm->dfaNoisyQDomainOld; 1605 aecm->dfaCleanQDomain = aecm->dfaNoisyQDomain; 1606 dfaCleanSum = dfaNoisySum; 1607 } else 1608 { 1609 // Transform clean near end signal from time domain to frequency domain. 1610 zerosDBufClean = TimeToFrequencyDomain(aecm->dBufClean, 1611 dfw, 1612 dfaClean, 1613 &dfaCleanSum); 1614 aecm->dfaCleanQDomainOld = aecm->dfaCleanQDomain; 1615 aecm->dfaCleanQDomain = (WebRtc_Word16)zerosDBufClean; 1616 } 1617 1618 #ifdef ARM_WINM_LOG_ 1619 // measure tick end 1620 QueryPerformanceCounter((LARGE_INTEGER*)&end); 1621 diff__ = ((end - start) * 1000) / (freq/1000); 1622 milliseconds = (unsigned int)(diff__ & 0xffffffff); 1623 WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL); 1624 // measure tick start 1625 QueryPerformanceCounter((LARGE_INTEGER*)&start); 1626 #endif 1627 1628 // Get the delay 1629 // Save far-end history and estimate delay 1630 UpdateFarHistory(aecm, xfa, far_q); 1631 delay = WebRtc_DelayEstimatorProcessFix(aecm->delay_estimator, 1632 xfa, 1633 dfaNoisy, 1634 PART_LEN1, 1635 far_q, 1636 zerosDBufNoisy); 1637 if (delay == -1) 1638 { 1639 return -1; 1640 } 1641 else if (delay == -2) 1642 { 1643 // If the delay is unknown, we assume zero. 1644 // NOTE: this will have to be adjusted if we ever add lookahead. 1645 delay = 0; 1646 } 1647 1648 if (aecm->fixedDelay >= 0) 1649 { 1650 // Use fixed delay 1651 delay = aecm->fixedDelay; 1652 } 1653 1654 #ifdef ARM_WINM_LOG_ 1655 // measure tick end 1656 QueryPerformanceCounter((LARGE_INTEGER*)&end); 1657 diff__ = ((end - start) * 1000) / (freq/1000); 1658 milliseconds = (unsigned int)(diff__ & 0xffffffff); 1659 WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL); 1660 // measure tick start 1661 QueryPerformanceCounter((LARGE_INTEGER*)&start); 1662 #endif 1663 // Get aligned far end spectrum 1664 far_spectrum_ptr = AlignedFarend(aecm, &far_q, delay); 1665 zerosXBuf = (WebRtc_Word16) far_q; 1666 if (far_spectrum_ptr == NULL) 1667 { 1668 return -1; 1669 } 1670 1671 // Calculate log(energy) and update energy threshold levels 1672 WebRtcAecm_CalcEnergies(aecm, 1673 far_spectrum_ptr, 1674 zerosXBuf, 1675 dfaNoisySum, 1676 echoEst32); 1677 1678 // Calculate stepsize 1679 mu = WebRtcAecm_CalcStepSize(aecm); 1680 1681 // Update counters 1682 aecm->totCount++; 1683 1684 // This is the channel estimation algorithm. 1685 // It is base on NLMS but has a variable step length, which was calculated above. 1686 WebRtcAecm_UpdateChannel(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisy, mu, echoEst32); 1687 supGain = CalcSuppressionGain(aecm); 1688 1689 #ifdef ARM_WINM_LOG_ 1690 // measure tick end 1691 QueryPerformanceCounter((LARGE_INTEGER*)&end); 1692 diff__ = ((end - start) * 1000) / (freq/1000); 1693 milliseconds = (unsigned int)(diff__ & 0xffffffff); 1694 WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL); 1695 // measure tick start 1696 QueryPerformanceCounter((LARGE_INTEGER*)&start); 1697 #endif 1698 1699 // Calculate Wiener filter hnl[] 1700 for (i = 0; i < PART_LEN1; i++) 1701 { 1702 // Far end signal through channel estimate in Q8 1703 // How much can we shift right to preserve resolution 1704 tmp32no1 = echoEst32[i] - aecm->echoFilt[i]; 1705 aecm->echoFilt[i] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_32_16(tmp32no1, 50), 8); 1706 1707 zeros32 = WebRtcSpl_NormW32(aecm->echoFilt[i]) + 1; 1708 zeros16 = WebRtcSpl_NormW16(supGain) + 1; 1709 if (zeros32 + zeros16 > 16) 1710 { 1711 // Multiplication is safe 1712 // Result in Q(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN+aecm->xfaQDomainBuf[diff]) 1713 echoEst32Gained = WEBRTC_SPL_UMUL_32_16((WebRtc_UWord32)aecm->echoFilt[i], 1714 (WebRtc_UWord16)supGain); 1715 resolutionDiff = 14 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN; 1716 resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf); 1717 } else 1718 { 1719 tmp16no1 = 17 - zeros32 - zeros16; 1720 resolutionDiff = 14 + tmp16no1 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN; 1721 resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf); 1722 if (zeros32 > tmp16no1) 1723 { 1724 echoEst32Gained = WEBRTC_SPL_UMUL_32_16((WebRtc_UWord32)aecm->echoFilt[i], 1725 (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_W16(supGain, 1726 tmp16no1)); // Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16) 1727 } else 1728 { 1729 // Result in Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16) 1730 echoEst32Gained = WEBRTC_SPL_UMUL_32_16( 1731 (WebRtc_UWord32)WEBRTC_SPL_RSHIFT_W32(aecm->echoFilt[i], tmp16no1), 1732 (WebRtc_UWord16)supGain); 1733 } 1734 } 1735 1736 zeros16 = WebRtcSpl_NormW16(aecm->nearFilt[i]); 1737 if ((zeros16 < (aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld)) 1738 & (aecm->nearFilt[i])) 1739 { 1740 tmp16no1 = WEBRTC_SPL_SHIFT_W16(aecm->nearFilt[i], zeros16); 1741 qDomainDiff = zeros16 - aecm->dfaCleanQDomain + aecm->dfaCleanQDomainOld; 1742 } else 1743 { 1744 tmp16no1 = WEBRTC_SPL_SHIFT_W16(aecm->nearFilt[i], 1745 aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld); 1746 qDomainDiff = 0; 1747 } 1748 tmp16no2 = WEBRTC_SPL_SHIFT_W16(ptrDfaClean[i], qDomainDiff); 1749 tmp32no1 = (WebRtc_Word32)(tmp16no2 - tmp16no1); 1750 tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 4); 1751 tmp16no2 += tmp16no1; 1752 zeros16 = WebRtcSpl_NormW16(tmp16no2); 1753 if ((tmp16no2) & (-qDomainDiff > zeros16)) 1754 { 1755 aecm->nearFilt[i] = WEBRTC_SPL_WORD16_MAX; 1756 } else 1757 { 1758 aecm->nearFilt[i] = WEBRTC_SPL_SHIFT_W16(tmp16no2, -qDomainDiff); 1759 } 1760 1761 // Wiener filter coefficients, resulting hnl in Q14 1762 if (echoEst32Gained == 0) 1763 { 1764 hnl[i] = ONE_Q14; 1765 } else if (aecm->nearFilt[i] == 0) 1766 { 1767 hnl[i] = 0; 1768 } else 1769 { 1770 // Multiply the suppression gain 1771 // Rounding 1772 echoEst32Gained += (WebRtc_UWord32)(aecm->nearFilt[i] >> 1); 1773 tmpU32 = WebRtcSpl_DivU32U16(echoEst32Gained, (WebRtc_UWord16)aecm->nearFilt[i]); 1774 1775 // Current resolution is 1776 // Q-(RESOLUTION_CHANNEL + RESOLUTION_SUPGAIN - max(0, 17 - zeros16 - zeros32)) 1777 // Make sure we are in Q14 1778 tmp32no1 = (WebRtc_Word32)WEBRTC_SPL_SHIFT_W32(tmpU32, resolutionDiff); 1779 if (tmp32no1 > ONE_Q14) 1780 { 1781 hnl[i] = 0; 1782 } else if (tmp32no1 < 0) 1783 { 1784 hnl[i] = ONE_Q14; 1785 } else 1786 { 1787 // 1-echoEst/dfa 1788 hnl[i] = ONE_Q14 - (WebRtc_Word16)tmp32no1; 1789 if (hnl[i] < 0) 1790 { 1791 hnl[i] = 0; 1792 } 1793 } 1794 } 1795 if (hnl[i]) 1796 { 1797 numPosCoef++; 1798 } 1799 } 1800 // Only in wideband. Prevent the gain in upper band from being larger than 1801 // in lower band. 1802 if (aecm->mult == 2) 1803 { 1804 // TODO(bjornv): Investigate if the scaling of hnl[i] below can cause 1805 // speech distortion in double-talk. 1806 for (i = 0; i < PART_LEN1; i++) 1807 { 1808 hnl[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(hnl[i], hnl[i], 14); 1809 } 1810 1811 for (i = kMinPrefBand; i <= kMaxPrefBand; i++) 1812 { 1813 avgHnl32 += (WebRtc_Word32)hnl[i]; 1814 } 1815 assert(kMaxPrefBand - kMinPrefBand + 1 > 0); 1816 avgHnl32 /= (kMaxPrefBand - kMinPrefBand + 1); 1817 1818 for (i = kMaxPrefBand; i < PART_LEN1; i++) 1819 { 1820 if (hnl[i] > (WebRtc_Word16)avgHnl32) 1821 { 1822 hnl[i] = (WebRtc_Word16)avgHnl32; 1823 } 1824 } 1825 } 1826 1827 #ifdef ARM_WINM_LOG_ 1828 // measure tick end 1829 QueryPerformanceCounter((LARGE_INTEGER*)&end); 1830 diff__ = ((end - start) * 1000) / (freq/1000); 1831 milliseconds = (unsigned int)(diff__ & 0xffffffff); 1832 WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL); 1833 // measure tick start 1834 QueryPerformanceCounter((LARGE_INTEGER*)&start); 1835 #endif 1836 1837 // Calculate NLP gain, result is in Q14 1838 if (aecm->nlpFlag) 1839 { 1840 for (i = 0; i < PART_LEN1; i++) 1841 { 1842 // Truncate values close to zero and one. 1843 if (hnl[i] > NLP_COMP_HIGH) 1844 { 1845 hnl[i] = ONE_Q14; 1846 } else if (hnl[i] < NLP_COMP_LOW) 1847 { 1848 hnl[i] = 0; 1849 } 1850 1851 // Remove outliers 1852 if (numPosCoef < 3) 1853 { 1854 nlpGain = 0; 1855 } else 1856 { 1857 nlpGain = ONE_Q14; 1858 } 1859 1860 // NLP 1861 if ((hnl[i] == ONE_Q14) && (nlpGain == ONE_Q14)) 1862 { 1863 hnl[i] = ONE_Q14; 1864 } else 1865 { 1866 hnl[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(hnl[i], nlpGain, 14); 1867 } 1868 1869 // multiply with Wiener coefficients 1870 efw[i].real = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real, 1871 hnl[i], 14)); 1872 efw[i].imag = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag, 1873 hnl[i], 14)); 1874 } 1875 } 1876 else 1877 { 1878 // multiply with Wiener coefficients 1879 for (i = 0; i < PART_LEN1; i++) 1880 { 1881 efw[i].real = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real, 1882 hnl[i], 14)); 1883 efw[i].imag = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag, 1884 hnl[i], 14)); 1885 } 1886 } 1887 1888 if (aecm->cngMode == AecmTrue) 1889 { 1890 ComfortNoise(aecm, ptrDfaClean, efw, hnl); 1891 } 1892 1893 #ifdef ARM_WINM_LOG_ 1894 // measure tick end 1895 QueryPerformanceCounter((LARGE_INTEGER*)&end); 1896 diff__ = ((end - start) * 1000) / (freq/1000); 1897 milliseconds = (unsigned int)(diff__ & 0xffffffff); 1898 WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL); 1899 // measure tick start 1900 QueryPerformanceCounter((LARGE_INTEGER*)&start); 1901 #endif 1902 1903 WebRtcAecm_InverseFFTAndWindow(aecm, fft, efw, output, nearendClean); 1904 1905 return 0; 1906 } 1907 1908 1909 // Generate comfort noise and add to output signal. 1910 // 1911 // \param[in] aecm Handle of the AECM instance. 1912 // \param[in] dfa Absolute value of the nearend signal (Q[aecm->dfaQDomain]). 1913 // \param[in,out] outReal Real part of the output signal (Q[aecm->dfaQDomain]). 1914 // \param[in,out] outImag Imaginary part of the output signal (Q[aecm->dfaQDomain]). 1915 // \param[in] lambda Suppression gain with which to scale the noise level (Q14). 1916 // 1917 static void ComfortNoise(AecmCore_t* aecm, 1918 const WebRtc_UWord16* dfa, 1919 complex16_t* out, 1920 const WebRtc_Word16* lambda) 1921 { 1922 WebRtc_Word16 i; 1923 WebRtc_Word16 tmp16; 1924 WebRtc_Word32 tmp32; 1925 1926 WebRtc_Word16 randW16[PART_LEN]; 1927 WebRtc_Word16 uReal[PART_LEN1]; 1928 WebRtc_Word16 uImag[PART_LEN1]; 1929 WebRtc_Word32 outLShift32; 1930 WebRtc_Word16 noiseRShift16[PART_LEN1]; 1931 1932 WebRtc_Word16 shiftFromNearToNoise = kNoiseEstQDomain - aecm->dfaCleanQDomain; 1933 WebRtc_Word16 minTrackShift; 1934 1935 assert(shiftFromNearToNoise >= 0); 1936 assert(shiftFromNearToNoise < 16); 1937 1938 if (aecm->noiseEstCtr < 100) 1939 { 1940 // Track the minimum more quickly initially. 1941 aecm->noiseEstCtr++; 1942 minTrackShift = 6; 1943 } else 1944 { 1945 minTrackShift = 9; 1946 } 1947 1948 // Estimate noise power. 1949 for (i = 0; i < PART_LEN1; i++) 1950 { 1951 1952 // Shift to the noise domain. 1953 tmp32 = (WebRtc_Word32)dfa[i]; 1954 outLShift32 = WEBRTC_SPL_LSHIFT_W32(tmp32, shiftFromNearToNoise); 1955 1956 if (outLShift32 < aecm->noiseEst[i]) 1957 { 1958 // Reset "too low" counter 1959 aecm->noiseEstTooLowCtr[i] = 0; 1960 // Track the minimum. 1961 if (aecm->noiseEst[i] < (1 << minTrackShift)) 1962 { 1963 // For small values, decrease noiseEst[i] every 1964 // |kNoiseEstIncCount| block. The regular approach below can not 1965 // go further down due to truncation. 1966 aecm->noiseEstTooHighCtr[i]++; 1967 if (aecm->noiseEstTooHighCtr[i] >= kNoiseEstIncCount) 1968 { 1969 aecm->noiseEst[i]--; 1970 aecm->noiseEstTooHighCtr[i] = 0; // Reset the counter 1971 } 1972 } 1973 else 1974 { 1975 aecm->noiseEst[i] -= ((aecm->noiseEst[i] - outLShift32) >> minTrackShift); 1976 } 1977 } else 1978 { 1979 // Reset "too high" counter 1980 aecm->noiseEstTooHighCtr[i] = 0; 1981 // Ramp slowly upwards until we hit the minimum again. 1982 if ((aecm->noiseEst[i] >> 19) > 0) 1983 { 1984 // Avoid overflow. 1985 // Multiplication with 2049 will cause wrap around. Scale 1986 // down first and then multiply 1987 aecm->noiseEst[i] >>= 11; 1988 aecm->noiseEst[i] *= 2049; 1989 } 1990 else if ((aecm->noiseEst[i] >> 11) > 0) 1991 { 1992 // Large enough for relative increase 1993 aecm->noiseEst[i] *= 2049; 1994 aecm->noiseEst[i] >>= 11; 1995 } 1996 else 1997 { 1998 // Make incremental increases based on size every 1999 // |kNoiseEstIncCount| block 2000 aecm->noiseEstTooLowCtr[i]++; 2001 if (aecm->noiseEstTooLowCtr[i] >= kNoiseEstIncCount) 2002 { 2003 aecm->noiseEst[i] += (aecm->noiseEst[i] >> 9) + 1; 2004 aecm->noiseEstTooLowCtr[i] = 0; // Reset counter 2005 } 2006 } 2007 } 2008 } 2009 2010 for (i = 0; i < PART_LEN1; i++) 2011 { 2012 tmp32 = WEBRTC_SPL_RSHIFT_W32(aecm->noiseEst[i], shiftFromNearToNoise); 2013 if (tmp32 > 32767) 2014 { 2015 tmp32 = 32767; 2016 aecm->noiseEst[i] = WEBRTC_SPL_LSHIFT_W32(tmp32, shiftFromNearToNoise); 2017 } 2018 noiseRShift16[i] = (WebRtc_Word16)tmp32; 2019 2020 tmp16 = ONE_Q14 - lambda[i]; 2021 noiseRShift16[i] 2022 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16, noiseRShift16[i], 14); 2023 } 2024 2025 // Generate a uniform random array on [0 2^15-1]. 2026 WebRtcSpl_RandUArray(randW16, PART_LEN, &aecm->seed); 2027 2028 // Generate noise according to estimated energy. 2029 uReal[0] = 0; // Reject LF noise. 2030 uImag[0] = 0; 2031 for (i = 1; i < PART_LEN1; i++) 2032 { 2033 // Get a random index for the cos and sin tables over [0 359]. 2034 tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(359, randW16[i - 1], 15); 2035 2036 // Tables are in Q13. 2037 uReal[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(noiseRShift16[i], 2038 kCosTable[tmp16], 13); 2039 uImag[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(-noiseRShift16[i], 2040 kSinTable[tmp16], 13); 2041 } 2042 uImag[PART_LEN] = 0; 2043 2044 #if (!defined ARM_WINM) && (!defined ARM9E_GCC) && (!defined ANDROID_AECOPT) 2045 for (i = 0; i < PART_LEN1; i++) 2046 { 2047 out[i].real = WEBRTC_SPL_ADD_SAT_W16(out[i].real, uReal[i]); 2048 out[i].imag = WEBRTC_SPL_ADD_SAT_W16(out[i].imag, uImag[i]); 2049 } 2050 #else 2051 for (i = 0; i < PART_LEN1 -1; ) 2052 { 2053 out[i].real = WEBRTC_SPL_ADD_SAT_W16(out[i].real, uReal[i]); 2054 out[i].imag = WEBRTC_SPL_ADD_SAT_W16(out[i].imag, uImag[i]); 2055 i++; 2056 2057 out[i].real = WEBRTC_SPL_ADD_SAT_W16(out[i].real, uReal[i]); 2058 out[i].imag = WEBRTC_SPL_ADD_SAT_W16(out[i].imag, uImag[i]); 2059 i++; 2060 } 2061 out[i].real = WEBRTC_SPL_ADD_SAT_W16(out[i].real, uReal[i]); 2062 out[i].imag = WEBRTC_SPL_ADD_SAT_W16(out[i].imag, uImag[i]); 2063 #endif 2064 } 2065 2066 void WebRtcAecm_BufferFarFrame(AecmCore_t* const aecm, 2067 const WebRtc_Word16* const farend, 2068 const int farLen) 2069 { 2070 int writeLen = farLen, writePos = 0; 2071 2072 // Check if the write position must be wrapped 2073 while (aecm->farBufWritePos + writeLen > FAR_BUF_LEN) 2074 { 2075 // Write to remaining buffer space before wrapping 2076 writeLen = FAR_BUF_LEN - aecm->farBufWritePos; 2077 memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos, 2078 sizeof(WebRtc_Word16) * writeLen); 2079 aecm->farBufWritePos = 0; 2080 writePos = writeLen; 2081 writeLen = farLen - writeLen; 2082 } 2083 2084 memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos, 2085 sizeof(WebRtc_Word16) * writeLen); 2086 aecm->farBufWritePos += writeLen; 2087 } 2088 2089 void WebRtcAecm_FetchFarFrame(AecmCore_t * const aecm, WebRtc_Word16 * const farend, 2090 const int farLen, const int knownDelay) 2091 { 2092 int readLen = farLen; 2093 int readPos = 0; 2094 int delayChange = knownDelay - aecm->lastKnownDelay; 2095 2096 aecm->farBufReadPos -= delayChange; 2097 2098 // Check if delay forces a read position wrap 2099 while (aecm->farBufReadPos < 0) 2100 { 2101 aecm->farBufReadPos += FAR_BUF_LEN; 2102 } 2103 while (aecm->farBufReadPos > FAR_BUF_LEN - 1) 2104 { 2105 aecm->farBufReadPos -= FAR_BUF_LEN; 2106 } 2107 2108 aecm->lastKnownDelay = knownDelay; 2109 2110 // Check if read position must be wrapped 2111 while (aecm->farBufReadPos + readLen > FAR_BUF_LEN) 2112 { 2113 2114 // Read from remaining buffer space before wrapping 2115 readLen = FAR_BUF_LEN - aecm->farBufReadPos; 2116 memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos, 2117 sizeof(WebRtc_Word16) * readLen); 2118 aecm->farBufReadPos = 0; 2119 readPos = readLen; 2120 readLen = farLen - readLen; 2121 } 2122 memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos, 2123 sizeof(WebRtc_Word16) * readLen); 2124 aecm->farBufReadPos += readLen; 2125 } 2126 2127