blob: 506c7930df9ecc433d0f7d56a03c3732c10bc082 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
bjornv@webrtc.org0c6f9312012-01-30 09:39:08 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/audio_processing/aecm/echo_control_mobile.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
niklase@google.com470e71d2011-07-07 08:21:25 +000013#ifdef AEC_DEBUG
14#include <stdio.h>
15#endif
andrew@webrtc.org9ae13542013-02-25 17:07:35 +000016#include <stdlib.h>
Yves Gerey988cc082018-10-23 12:03:01 +020017#include <string.h>
andrew@webrtc.org9ae13542013-02-25 17:07:35 +000018
peah27045122016-04-10 22:38:14 -070019extern "C" {
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "common_audio/ring_buffer.h"
21#include "common_audio/signal_processing/include/signal_processing_library.h"
Yves Gerey988cc082018-10-23 12:03:01 +020022#include "modules/audio_processing/aecm/aecm_defines.h"
peah27045122016-04-10 22:38:14 -070023}
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "modules/audio_processing/aecm/aecm_core.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000025
Per Åhgrenbe36db12020-03-20 16:45:09 +010026namespace webrtc {
27
28namespace {
29
Yves Gerey665174f2018-06-19 15:03:05 +020030#define BUF_SIZE_FRAMES 50 // buffer size (frames)
niklase@google.com470e71d2011-07-07 08:21:25 +000031// Maximum length of resampled signal. Must be an integer multiple of frames
32// (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN
33// The factor of 2 handles wb, and the + 1 is as a safety margin
34#define MAX_RESAMP_LEN (5 * FRAME_LEN)
35
Yves Gerey665174f2018-06-19 15:03:05 +020036static const size_t kBufSizeSamp =
37 BUF_SIZE_FRAMES * FRAME_LEN; // buffer size (samples)
38static const int kSampMsNb = 8; // samples per ms in nb
niklase@google.com470e71d2011-07-07 08:21:25 +000039// Target suppression levels for nlp modes
40// log{0.001, 0.00001, 0.00000001}
41static const int kInitCheck = 42;
42
Yves Gerey665174f2018-06-19 15:03:05 +020043typedef struct {
44 int sampFreq;
45 int scSampFreq;
46 short bufSizeStart;
47 int knownDelay;
niklase@google.com470e71d2011-07-07 08:21:25 +000048
Yves Gerey665174f2018-06-19 15:03:05 +020049 // Stores the last frame added to the farend buffer
50 short farendOld[2][FRAME_LEN];
51 short initFlag; // indicates if AEC has been initialized
niklase@google.com470e71d2011-07-07 08:21:25 +000052
Yves Gerey665174f2018-06-19 15:03:05 +020053 // Variables used for averaging far end buffer size
54 short counter;
55 short sum;
56 short firstVal;
57 short checkBufSizeCtr;
niklase@google.com470e71d2011-07-07 08:21:25 +000058
Yves Gerey665174f2018-06-19 15:03:05 +020059 // Variables used for delay shifts
60 short msInSndCardBuf;
61 short filtDelay;
62 int timeForDelayChange;
63 int ECstartup;
64 int checkBuffSize;
65 int delayChange;
66 short lastDelayDiff;
niklase@google.com470e71d2011-07-07 08:21:25 +000067
Yves Gerey665174f2018-06-19 15:03:05 +020068 int16_t echoMode;
niklase@google.com470e71d2011-07-07 08:21:25 +000069
70#ifdef AEC_DEBUG
Yves Gerey665174f2018-06-19 15:03:05 +020071 FILE* bufFile;
72 FILE* delayFile;
73 FILE* preCompFile;
74 FILE* postCompFile;
75#endif // AEC_DEBUG
76 // Structures
77 RingBuffer* farendBuf;
niklase@google.com470e71d2011-07-07 08:21:25 +000078
Yves Gerey665174f2018-06-19 15:03:05 +020079 AecmCore* aecmCore;
pbos@webrtc.orge468bc92014-12-18 09:11:33 +000080} AecMobile;
niklase@google.com470e71d2011-07-07 08:21:25 +000081
Per Åhgrenbe36db12020-03-20 16:45:09 +010082} // namespace
83
niklase@google.com470e71d2011-07-07 08:21:25 +000084// Estimates delay to set the position of the farend buffer read pointer
85// (controlled by knownDelay)
Alex Loiko890988c2017-08-31 10:25:48 +020086static int WebRtcAecm_EstBufDelay(AecMobile* aecm, short msInSndCardBuf);
niklase@google.com470e71d2011-07-07 08:21:25 +000087
88// Stuffs the farend buffer if the estimated delay is too large
Alex Loiko890988c2017-08-31 10:25:48 +020089static int WebRtcAecm_DelayComp(AecMobile* aecm);
niklase@google.com470e71d2011-07-07 08:21:25 +000090
Bjorn Volckera7437942015-05-28 15:58:42 +020091void* WebRtcAecm_Create() {
Yves Gerey665174f2018-06-19 15:03:05 +020092 AecMobile* aecm = static_cast<AecMobile*>(malloc(sizeof(AecMobile)));
niklase@google.com470e71d2011-07-07 08:21:25 +000093
Yves Gerey665174f2018-06-19 15:03:05 +020094 aecm->aecmCore = WebRtcAecm_CreateCore();
95 if (!aecm->aecmCore) {
96 WebRtcAecm_Free(aecm);
97 return NULL;
98 }
niklase@google.com470e71d2011-07-07 08:21:25 +000099
Yves Gerey665174f2018-06-19 15:03:05 +0200100 aecm->farendBuf = WebRtc_CreateBuffer(kBufSizeSamp, sizeof(int16_t));
101 if (!aecm->farendBuf) {
102 WebRtcAecm_Free(aecm);
103 return NULL;
104 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000105
Yves Gerey665174f2018-06-19 15:03:05 +0200106 aecm->initFlag = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000107
108#ifdef AEC_DEBUG
Yves Gerey665174f2018-06-19 15:03:05 +0200109 aecm->aecmCore->farFile = fopen("aecFar.pcm", "wb");
110 aecm->aecmCore->nearFile = fopen("aecNear.pcm", "wb");
111 aecm->aecmCore->outFile = fopen("aecOut.pcm", "wb");
112 // aecm->aecmCore->outLpFile = fopen("aecOutLp.pcm","wb");
niklase@google.com470e71d2011-07-07 08:21:25 +0000113
Yves Gerey665174f2018-06-19 15:03:05 +0200114 aecm->bufFile = fopen("aecBuf.dat", "wb");
115 aecm->delayFile = fopen("aecDelay.dat", "wb");
116 aecm->preCompFile = fopen("preComp.pcm", "wb");
117 aecm->postCompFile = fopen("postComp.pcm", "wb");
118#endif // AEC_DEBUG
119 return aecm;
niklase@google.com470e71d2011-07-07 08:21:25 +0000120}
121
Bjorn Volckerf6a99e62015-04-10 07:56:57 +0200122void WebRtcAecm_Free(void* aecmInst) {
peah27045122016-04-10 22:38:14 -0700123 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
niklase@google.com470e71d2011-07-07 08:21:25 +0000124
Yves Gerey665174f2018-06-19 15:03:05 +0200125 if (aecm == NULL) {
126 return;
127 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000128
129#ifdef AEC_DEBUG
Yves Gerey665174f2018-06-19 15:03:05 +0200130 fclose(aecm->aecmCore->farFile);
131 fclose(aecm->aecmCore->nearFile);
132 fclose(aecm->aecmCore->outFile);
133 // fclose(aecm->aecmCore->outLpFile);
niklase@google.com470e71d2011-07-07 08:21:25 +0000134
Yves Gerey665174f2018-06-19 15:03:05 +0200135 fclose(aecm->bufFile);
136 fclose(aecm->delayFile);
137 fclose(aecm->preCompFile);
138 fclose(aecm->postCompFile);
139#endif // AEC_DEBUG
140 WebRtcAecm_FreeCore(aecm->aecmCore);
141 WebRtc_FreeBuffer(aecm->farendBuf);
142 free(aecm);
niklase@google.com470e71d2011-07-07 08:21:25 +0000143}
144
Yves Gerey665174f2018-06-19 15:03:05 +0200145int32_t WebRtcAecm_Init(void* aecmInst, int32_t sampFreq) {
146 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
147 AecmConfig aecConfig;
niklase@google.com470e71d2011-07-07 08:21:25 +0000148
Yves Gerey665174f2018-06-19 15:03:05 +0200149 if (aecm == NULL) {
150 return -1;
151 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000152
Yves Gerey665174f2018-06-19 15:03:05 +0200153 if (sampFreq != 8000 && sampFreq != 16000) {
154 return AECM_BAD_PARAMETER_ERROR;
155 }
156 aecm->sampFreq = sampFreq;
niklase@google.com470e71d2011-07-07 08:21:25 +0000157
Yves Gerey665174f2018-06-19 15:03:05 +0200158 // Initialize AECM core
159 if (WebRtcAecm_InitCore(aecm->aecmCore, aecm->sampFreq) == -1) {
160 return AECM_UNSPECIFIED_ERROR;
161 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000162
Yves Gerey665174f2018-06-19 15:03:05 +0200163 // Initialize farend buffer
164 WebRtc_InitBuffer(aecm->farendBuf);
niklase@google.com470e71d2011-07-07 08:21:25 +0000165
Yves Gerey665174f2018-06-19 15:03:05 +0200166 aecm->initFlag = kInitCheck; // indicates that initialization has been done
niklase@google.com470e71d2011-07-07 08:21:25 +0000167
Yves Gerey665174f2018-06-19 15:03:05 +0200168 aecm->delayChange = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000169
Yves Gerey665174f2018-06-19 15:03:05 +0200170 aecm->sum = 0;
171 aecm->counter = 0;
172 aecm->checkBuffSize = 1;
173 aecm->firstVal = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000174
Yves Gerey665174f2018-06-19 15:03:05 +0200175 aecm->ECstartup = 1;
176 aecm->bufSizeStart = 0;
177 aecm->checkBufSizeCtr = 0;
178 aecm->filtDelay = 0;
179 aecm->timeForDelayChange = 0;
180 aecm->knownDelay = 0;
181 aecm->lastDelayDiff = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000182
Yves Gerey665174f2018-06-19 15:03:05 +0200183 memset(&aecm->farendOld, 0, sizeof(aecm->farendOld));
niklase@google.com470e71d2011-07-07 08:21:25 +0000184
Yves Gerey665174f2018-06-19 15:03:05 +0200185 // Default settings.
186 aecConfig.cngMode = AecmTrue;
187 aecConfig.echoMode = 3;
niklase@google.com470e71d2011-07-07 08:21:25 +0000188
Yves Gerey665174f2018-06-19 15:03:05 +0200189 if (WebRtcAecm_set_config(aecm, aecConfig) == -1) {
190 return AECM_UNSPECIFIED_ERROR;
191 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000192
Yves Gerey665174f2018-06-19 15:03:05 +0200193 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000194}
195
peahc12be392015-11-09 23:53:50 -0800196// Returns any error that is caused when buffering the
197// farend signal.
Yves Gerey665174f2018-06-19 15:03:05 +0200198int32_t WebRtcAecm_GetBufferFarendError(void* aecmInst,
199 const int16_t* farend,
200 size_t nrOfSamples) {
peah27045122016-04-10 22:38:14 -0700201 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
niklase@google.com470e71d2011-07-07 08:21:25 +0000202
peahc12be392015-11-09 23:53:50 -0800203 if (aecm == NULL)
204 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000205
peahc12be392015-11-09 23:53:50 -0800206 if (farend == NULL)
207 return AECM_NULL_POINTER_ERROR;
niklase@google.com470e71d2011-07-07 08:21:25 +0000208
peahc12be392015-11-09 23:53:50 -0800209 if (aecm->initFlag != kInitCheck)
210 return AECM_UNINITIALIZED_ERROR;
niklase@google.com470e71d2011-07-07 08:21:25 +0000211
peahc12be392015-11-09 23:53:50 -0800212 if (nrOfSamples != 80 && nrOfSamples != 160)
213 return AECM_BAD_PARAMETER_ERROR;
niklase@google.com470e71d2011-07-07 08:21:25 +0000214
peahc12be392015-11-09 23:53:50 -0800215 return 0;
216}
niklase@google.com470e71d2011-07-07 08:21:25 +0000217
Yves Gerey665174f2018-06-19 15:03:05 +0200218int32_t WebRtcAecm_BufferFarend(void* aecmInst,
219 const int16_t* farend,
peahc12be392015-11-09 23:53:50 -0800220 size_t nrOfSamples) {
peah27045122016-04-10 22:38:14 -0700221 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
peahc12be392015-11-09 23:53:50 -0800222
223 const int32_t err =
224 WebRtcAecm_GetBufferFarendError(aecmInst, farend, nrOfSamples);
225
226 if (err != 0)
227 return err;
228
229 // TODO(unknown): Is this really a good idea?
Yves Gerey665174f2018-06-19 15:03:05 +0200230 if (!aecm->ECstartup) {
peahc12be392015-11-09 23:53:50 -0800231 WebRtcAecm_DelayComp(aecm);
232 }
233
234 WebRtc_WriteBuffer(aecm->farendBuf, farend, nrOfSamples);
235
236 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000237}
238
Yves Gerey665174f2018-06-19 15:03:05 +0200239int32_t WebRtcAecm_Process(void* aecmInst,
240 const int16_t* nearendNoisy,
241 const int16_t* nearendClean,
242 int16_t* out,
243 size_t nrOfSamples,
244 int16_t msInSndCardBuf) {
245 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
246 int32_t retVal = 0;
247 size_t i;
248 short nmbrOfFilledBuffers;
249 size_t nBlocks10ms;
250 size_t nFrames;
niklase@google.com470e71d2011-07-07 08:21:25 +0000251#ifdef AEC_DEBUG
Yves Gerey665174f2018-06-19 15:03:05 +0200252 short msInAECBuf;
niklase@google.com470e71d2011-07-07 08:21:25 +0000253#endif
254
Yves Gerey665174f2018-06-19 15:03:05 +0200255 if (aecm == NULL) {
256 return -1;
257 }
258
259 if (nearendNoisy == NULL) {
260 return AECM_NULL_POINTER_ERROR;
261 }
262
263 if (out == NULL) {
264 return AECM_NULL_POINTER_ERROR;
265 }
266
267 if (aecm->initFlag != kInitCheck) {
268 return AECM_UNINITIALIZED_ERROR;
269 }
270
271 if (nrOfSamples != 80 && nrOfSamples != 160) {
272 return AECM_BAD_PARAMETER_ERROR;
273 }
274
275 if (msInSndCardBuf < 0) {
276 msInSndCardBuf = 0;
277 retVal = AECM_BAD_PARAMETER_WARNING;
278 } else if (msInSndCardBuf > 500) {
279 msInSndCardBuf = 500;
280 retVal = AECM_BAD_PARAMETER_WARNING;
281 }
282 msInSndCardBuf += 10;
283 aecm->msInSndCardBuf = msInSndCardBuf;
284
285 nFrames = nrOfSamples / FRAME_LEN;
286 nBlocks10ms = nFrames / aecm->aecmCore->mult;
287
288 if (aecm->ECstartup) {
289 if (nearendClean == NULL) {
290 if (out != nearendNoisy) {
291 memcpy(out, nearendNoisy, sizeof(short) * nrOfSamples);
292 }
293 } else if (out != nearendClean) {
294 memcpy(out, nearendClean, sizeof(short) * nrOfSamples);
295 }
296
297 nmbrOfFilledBuffers =
298 (short)WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
299 // The AECM is in the start up mode
300 // AECM is disabled until the soundcard buffer and farend buffers are OK
301
302 // Mechanism to ensure that the soundcard buffer is reasonably stable.
303 if (aecm->checkBuffSize) {
304 aecm->checkBufSizeCtr++;
305 // Before we fill up the far end buffer we require the amount of data on
306 // the sound card to be stable (+/-8 ms) compared to the first value. This
307 // comparison is made during the following 4 consecutive frames. If it
308 // seems to be stable then we start to fill up the far end buffer.
309
310 if (aecm->counter == 0) {
311 aecm->firstVal = aecm->msInSndCardBuf;
312 aecm->sum = 0;
313 }
314
315 if (abs(aecm->firstVal - aecm->msInSndCardBuf) <
316 WEBRTC_SPL_MAX(0.2 * aecm->msInSndCardBuf, kSampMsNb)) {
317 aecm->sum += aecm->msInSndCardBuf;
318 aecm->counter++;
319 } else {
320 aecm->counter = 0;
321 }
322
323 if (aecm->counter * nBlocks10ms >= 6) {
324 // The farend buffer size is determined in blocks of 80 samples
325 // Use 75% of the average value of the soundcard buffer
326 aecm->bufSizeStart = WEBRTC_SPL_MIN(
327 (3 * aecm->sum * aecm->aecmCore->mult) / (aecm->counter * 40),
328 BUF_SIZE_FRAMES);
329 // buffersize has now been determined
330 aecm->checkBuffSize = 0;
331 }
332
333 if (aecm->checkBufSizeCtr * nBlocks10ms > 50) {
334 // for really bad sound cards, don't disable echocanceller for more than
335 // 0.5 sec
336 aecm->bufSizeStart = WEBRTC_SPL_MIN(
337 (3 * aecm->msInSndCardBuf * aecm->aecmCore->mult) / 40,
338 BUF_SIZE_FRAMES);
339 aecm->checkBuffSize = 0;
340 }
341 }
342
343 // if checkBuffSize changed in the if-statement above
344 if (!aecm->checkBuffSize) {
345 // soundcard buffer is now reasonably stable
346 // When the far end buffer is filled with approximately the same amount of
347 // data as the amount on the sound card we end the start up phase and
348 // start to cancel echoes.
349
350 if (nmbrOfFilledBuffers == aecm->bufSizeStart) {
351 aecm->ECstartup = 0; // Enable the AECM
352 } else if (nmbrOfFilledBuffers > aecm->bufSizeStart) {
353 WebRtc_MoveReadPtr(aecm->farendBuf,
354 (int)WebRtc_available_read(aecm->farendBuf) -
355 (int)aecm->bufSizeStart * FRAME_LEN);
356 aecm->ECstartup = 0;
357 }
358 }
359
360 } else {
361 // AECM is enabled
362
363 // Note only 1 block supported for nb and 2 blocks for wb
364 for (i = 0; i < nFrames; i++) {
365 int16_t farend[FRAME_LEN];
366 const int16_t* farend_ptr = NULL;
367
368 nmbrOfFilledBuffers =
369 (short)WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
370
371 // Check that there is data in the far end buffer
372 if (nmbrOfFilledBuffers > 0) {
373 // Get the next 80 samples from the farend buffer
374 WebRtc_ReadBuffer(aecm->farendBuf, (void**)&farend_ptr, farend,
375 FRAME_LEN);
376
377 // Always store the last frame for use when we run out of data
378 memcpy(&(aecm->farendOld[i][0]), farend_ptr, FRAME_LEN * sizeof(short));
379 } else {
380 // We have no data so we use the last played frame
381 memcpy(farend, &(aecm->farendOld[i][0]), FRAME_LEN * sizeof(short));
382 farend_ptr = farend;
383 }
384
385 // Call buffer delay estimator when all data is extracted,
386 // i,e. i = 0 for NB and i = 1 for WB
387 if ((i == 0 && aecm->sampFreq == 8000) ||
388 (i == 1 && aecm->sampFreq == 16000)) {
389 WebRtcAecm_EstBufDelay(aecm, aecm->msInSndCardBuf);
390 }
391
392 // Call the AECM
393 /*WebRtcAecm_ProcessFrame(aecm->aecmCore, farend, &nearend[FRAME_LEN * i],
394 &out[FRAME_LEN * i], aecm->knownDelay);*/
395 if (WebRtcAecm_ProcessFrame(
396 aecm->aecmCore, farend_ptr, &nearendNoisy[FRAME_LEN * i],
397 (nearendClean ? &nearendClean[FRAME_LEN * i] : NULL),
398 &out[FRAME_LEN * i]) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000399 return -1;
400 }
Yves Gerey665174f2018-06-19 15:03:05 +0200401 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000402
403#ifdef AEC_DEBUG
Yves Gerey665174f2018-06-19 15:03:05 +0200404 msInAECBuf = (short)WebRtc_available_read(aecm->farendBuf) /
405 (kSampMsNb * aecm->aecmCore->mult);
406 fwrite(&msInAECBuf, 2, 1, aecm->bufFile);
407 fwrite(&(aecm->knownDelay), sizeof(aecm->knownDelay), 1, aecm->delayFile);
niklase@google.com470e71d2011-07-07 08:21:25 +0000408#endif
409
Yves Gerey665174f2018-06-19 15:03:05 +0200410 return retVal;
niklase@google.com470e71d2011-07-07 08:21:25 +0000411}
412
Yves Gerey665174f2018-06-19 15:03:05 +0200413int32_t WebRtcAecm_set_config(void* aecmInst, AecmConfig config) {
414 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
niklase@google.com470e71d2011-07-07 08:21:25 +0000415
Yves Gerey665174f2018-06-19 15:03:05 +0200416 if (aecm == NULL) {
417 return -1;
418 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000419
Yves Gerey665174f2018-06-19 15:03:05 +0200420 if (aecm->initFlag != kInitCheck) {
421 return AECM_UNINITIALIZED_ERROR;
422 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000423
Yves Gerey665174f2018-06-19 15:03:05 +0200424 if (config.cngMode != AecmFalse && config.cngMode != AecmTrue) {
425 return AECM_BAD_PARAMETER_ERROR;
426 }
427 aecm->aecmCore->cngMode = config.cngMode;
niklase@google.com470e71d2011-07-07 08:21:25 +0000428
Yves Gerey665174f2018-06-19 15:03:05 +0200429 if (config.echoMode < 0 || config.echoMode > 4) {
430 return AECM_BAD_PARAMETER_ERROR;
431 }
432 aecm->echoMode = config.echoMode;
niklase@google.com470e71d2011-07-07 08:21:25 +0000433
Yves Gerey665174f2018-06-19 15:03:05 +0200434 if (aecm->echoMode == 0) {
435 aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 3;
436 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 3;
437 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 3;
438 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 3;
439 aecm->aecmCore->supGainErrParamDiffAB =
440 (SUPGAIN_ERROR_PARAM_A >> 3) - (SUPGAIN_ERROR_PARAM_B >> 3);
441 aecm->aecmCore->supGainErrParamDiffBD =
442 (SUPGAIN_ERROR_PARAM_B >> 3) - (SUPGAIN_ERROR_PARAM_D >> 3);
443 } else if (aecm->echoMode == 1) {
444 aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 2;
445 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 2;
446 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 2;
447 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 2;
448 aecm->aecmCore->supGainErrParamDiffAB =
449 (SUPGAIN_ERROR_PARAM_A >> 2) - (SUPGAIN_ERROR_PARAM_B >> 2);
450 aecm->aecmCore->supGainErrParamDiffBD =
451 (SUPGAIN_ERROR_PARAM_B >> 2) - (SUPGAIN_ERROR_PARAM_D >> 2);
452 } else if (aecm->echoMode == 2) {
453 aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 1;
454 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 1;
455 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 1;
456 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 1;
457 aecm->aecmCore->supGainErrParamDiffAB =
458 (SUPGAIN_ERROR_PARAM_A >> 1) - (SUPGAIN_ERROR_PARAM_B >> 1);
459 aecm->aecmCore->supGainErrParamDiffBD =
460 (SUPGAIN_ERROR_PARAM_B >> 1) - (SUPGAIN_ERROR_PARAM_D >> 1);
461 } else if (aecm->echoMode == 3) {
462 aecm->aecmCore->supGain = SUPGAIN_DEFAULT;
463 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT;
464 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
465 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
466 aecm->aecmCore->supGainErrParamDiffAB =
467 SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
468 aecm->aecmCore->supGainErrParamDiffBD =
469 SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
470 } else if (aecm->echoMode == 4) {
471 aecm->aecmCore->supGain = SUPGAIN_DEFAULT << 1;
472 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT << 1;
473 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A << 1;
474 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D << 1;
475 aecm->aecmCore->supGainErrParamDiffAB =
476 (SUPGAIN_ERROR_PARAM_A << 1) - (SUPGAIN_ERROR_PARAM_B << 1);
477 aecm->aecmCore->supGainErrParamDiffBD =
478 (SUPGAIN_ERROR_PARAM_B << 1) - (SUPGAIN_ERROR_PARAM_D << 1);
479 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000480
Yves Gerey665174f2018-06-19 15:03:05 +0200481 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000482}
483
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000484int32_t WebRtcAecm_InitEchoPath(void* aecmInst,
485 const void* echo_path,
Yves Gerey665174f2018-06-19 15:03:05 +0200486 size_t size_bytes) {
487 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
488 const int16_t* echo_path_ptr = static_cast<const int16_t*>(echo_path);
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000489
Yves Gerey665174f2018-06-19 15:03:05 +0200490 if (aecmInst == NULL) {
491 return -1;
492 }
493 if (echo_path == NULL) {
494 return AECM_NULL_POINTER_ERROR;
495 }
496 if (size_bytes != WebRtcAecm_echo_path_size_bytes()) {
497 // Input channel size does not match the size of AECM
498 return AECM_BAD_PARAMETER_ERROR;
499 }
500 if (aecm->initFlag != kInitCheck) {
501 return AECM_UNINITIALIZED_ERROR;
502 }
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000503
Yves Gerey665174f2018-06-19 15:03:05 +0200504 WebRtcAecm_InitEchoPathCore(aecm->aecmCore, echo_path_ptr);
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000505
Yves Gerey665174f2018-06-19 15:03:05 +0200506 return 0;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000507}
508
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000509int32_t WebRtcAecm_GetEchoPath(void* aecmInst,
510 void* echo_path,
Yves Gerey665174f2018-06-19 15:03:05 +0200511 size_t size_bytes) {
512 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
513 int16_t* echo_path_ptr = static_cast<int16_t*>(echo_path);
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000514
Yves Gerey665174f2018-06-19 15:03:05 +0200515 if (aecmInst == NULL) {
516 return -1;
517 }
518 if (echo_path == NULL) {
519 return AECM_NULL_POINTER_ERROR;
520 }
521 if (size_bytes != WebRtcAecm_echo_path_size_bytes()) {
522 // Input channel size does not match the size of AECM
523 return AECM_BAD_PARAMETER_ERROR;
524 }
525 if (aecm->initFlag != kInitCheck) {
526 return AECM_UNINITIALIZED_ERROR;
527 }
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000528
Yves Gerey665174f2018-06-19 15:03:05 +0200529 memcpy(echo_path_ptr, aecm->aecmCore->channelStored, size_bytes);
530 return 0;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000531}
532
Yves Gerey665174f2018-06-19 15:03:05 +0200533size_t WebRtcAecm_echo_path_size_bytes() {
534 return (PART_LEN1 * sizeof(int16_t));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000535}
536
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000537static int WebRtcAecm_EstBufDelay(AecMobile* aecm, short msInSndCardBuf) {
Yves Gerey665174f2018-06-19 15:03:05 +0200538 short delayNew, nSampSndCard;
539 short nSampFar = (short)WebRtc_available_read(aecm->farendBuf);
540 short diff;
niklase@google.com470e71d2011-07-07 08:21:25 +0000541
Yves Gerey665174f2018-06-19 15:03:05 +0200542 nSampSndCard = msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
niklase@google.com470e71d2011-07-07 08:21:25 +0000543
Yves Gerey665174f2018-06-19 15:03:05 +0200544 delayNew = nSampSndCard - nSampFar;
niklase@google.com470e71d2011-07-07 08:21:25 +0000545
Yves Gerey665174f2018-06-19 15:03:05 +0200546 if (delayNew < FRAME_LEN) {
547 WebRtc_MoveReadPtr(aecm->farendBuf, FRAME_LEN);
548 delayNew += FRAME_LEN;
549 }
550
551 aecm->filtDelay =
552 WEBRTC_SPL_MAX(0, (8 * aecm->filtDelay + 2 * delayNew) / 10);
553
554 diff = aecm->filtDelay - aecm->knownDelay;
555 if (diff > 224) {
556 if (aecm->lastDelayDiff < 96) {
557 aecm->timeForDelayChange = 0;
558 } else {
559 aecm->timeForDelayChange++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000560 }
Yves Gerey665174f2018-06-19 15:03:05 +0200561 } else if (diff < 96 && aecm->knownDelay > 0) {
562 if (aecm->lastDelayDiff > 224) {
563 aecm->timeForDelayChange = 0;
564 } else {
565 aecm->timeForDelayChange++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000566 }
Yves Gerey665174f2018-06-19 15:03:05 +0200567 } else {
568 aecm->timeForDelayChange = 0;
569 }
570 aecm->lastDelayDiff = diff;
niklase@google.com470e71d2011-07-07 08:21:25 +0000571
Yves Gerey665174f2018-06-19 15:03:05 +0200572 if (aecm->timeForDelayChange > 25) {
573 aecm->knownDelay = WEBRTC_SPL_MAX((int)aecm->filtDelay - 160, 0);
574 }
575 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000576}
577
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000578static int WebRtcAecm_DelayComp(AecMobile* aecm) {
Yves Gerey665174f2018-06-19 15:03:05 +0200579 int nSampFar = (int)WebRtc_available_read(aecm->farendBuf);
580 int nSampSndCard, delayNew, nSampAdd;
581 const int maxStuffSamp = 10 * FRAME_LEN;
niklase@google.com470e71d2011-07-07 08:21:25 +0000582
Yves Gerey665174f2018-06-19 15:03:05 +0200583 nSampSndCard = aecm->msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
584 delayNew = nSampSndCard - nSampFar;
niklase@google.com470e71d2011-07-07 08:21:25 +0000585
Yves Gerey665174f2018-06-19 15:03:05 +0200586 if (delayNew > FAR_BUF_LEN - FRAME_LEN * aecm->aecmCore->mult) {
587 // The difference of the buffer sizes is larger than the maximum
588 // allowed known delay. Compensate by stuffing the buffer.
589 nSampAdd =
590 (int)(WEBRTC_SPL_MAX(((nSampSndCard >> 1) - nSampFar), FRAME_LEN));
591 nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp);
niklase@google.com470e71d2011-07-07 08:21:25 +0000592
Yves Gerey665174f2018-06-19 15:03:05 +0200593 WebRtc_MoveReadPtr(aecm->farendBuf, -nSampAdd);
594 aecm->delayChange = 1; // the delay needs to be updated
595 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000596
Yves Gerey665174f2018-06-19 15:03:05 +0200597 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000598}
Per Åhgrenbe36db12020-03-20 16:45:09 +0100599
600} // namespace webrtc