blob: 257dfbf56e4e81634ca881691349a16dcfb687be [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
Yves Gerey665174f2018-06-19 15:03:05 +020026#define BUF_SIZE_FRAMES 50 // buffer size (frames)
niklase@google.com470e71d2011-07-07 08:21:25 +000027// Maximum length of resampled signal. Must be an integer multiple of frames
28// (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN
29// The factor of 2 handles wb, and the + 1 is as a safety margin
30#define MAX_RESAMP_LEN (5 * FRAME_LEN)
31
Yves Gerey665174f2018-06-19 15:03:05 +020032static const size_t kBufSizeSamp =
33 BUF_SIZE_FRAMES * FRAME_LEN; // buffer size (samples)
34static const int kSampMsNb = 8; // samples per ms in nb
niklase@google.com470e71d2011-07-07 08:21:25 +000035// Target suppression levels for nlp modes
36// log{0.001, 0.00001, 0.00000001}
37static const int kInitCheck = 42;
38
Yves Gerey665174f2018-06-19 15:03:05 +020039typedef struct {
40 int sampFreq;
41 int scSampFreq;
42 short bufSizeStart;
43 int knownDelay;
niklase@google.com470e71d2011-07-07 08:21:25 +000044
Yves Gerey665174f2018-06-19 15:03:05 +020045 // Stores the last frame added to the farend buffer
46 short farendOld[2][FRAME_LEN];
47 short initFlag; // indicates if AEC has been initialized
niklase@google.com470e71d2011-07-07 08:21:25 +000048
Yves Gerey665174f2018-06-19 15:03:05 +020049 // Variables used for averaging far end buffer size
50 short counter;
51 short sum;
52 short firstVal;
53 short checkBufSizeCtr;
niklase@google.com470e71d2011-07-07 08:21:25 +000054
Yves Gerey665174f2018-06-19 15:03:05 +020055 // Variables used for delay shifts
56 short msInSndCardBuf;
57 short filtDelay;
58 int timeForDelayChange;
59 int ECstartup;
60 int checkBuffSize;
61 int delayChange;
62 short lastDelayDiff;
niklase@google.com470e71d2011-07-07 08:21:25 +000063
Yves Gerey665174f2018-06-19 15:03:05 +020064 int16_t echoMode;
niklase@google.com470e71d2011-07-07 08:21:25 +000065
66#ifdef AEC_DEBUG
Yves Gerey665174f2018-06-19 15:03:05 +020067 FILE* bufFile;
68 FILE* delayFile;
69 FILE* preCompFile;
70 FILE* postCompFile;
71#endif // AEC_DEBUG
72 // Structures
73 RingBuffer* farendBuf;
niklase@google.com470e71d2011-07-07 08:21:25 +000074
Yves Gerey665174f2018-06-19 15:03:05 +020075 AecmCore* aecmCore;
pbos@webrtc.orge468bc92014-12-18 09:11:33 +000076} AecMobile;
niklase@google.com470e71d2011-07-07 08:21:25 +000077
78// Estimates delay to set the position of the farend buffer read pointer
79// (controlled by knownDelay)
Alex Loiko890988c2017-08-31 10:25:48 +020080static int WebRtcAecm_EstBufDelay(AecMobile* aecm, short msInSndCardBuf);
niklase@google.com470e71d2011-07-07 08:21:25 +000081
82// Stuffs the farend buffer if the estimated delay is too large
Alex Loiko890988c2017-08-31 10:25:48 +020083static int WebRtcAecm_DelayComp(AecMobile* aecm);
niklase@google.com470e71d2011-07-07 08:21:25 +000084
Bjorn Volckera7437942015-05-28 15:58:42 +020085void* WebRtcAecm_Create() {
Yves Gerey665174f2018-06-19 15:03:05 +020086 AecMobile* aecm = static_cast<AecMobile*>(malloc(sizeof(AecMobile)));
niklase@google.com470e71d2011-07-07 08:21:25 +000087
Yves Gerey665174f2018-06-19 15:03:05 +020088 WebRtcSpl_Init();
kma@webrtc.org31829a72013-03-19 00:25:01 +000089
Yves Gerey665174f2018-06-19 15:03:05 +020090 aecm->aecmCore = WebRtcAecm_CreateCore();
91 if (!aecm->aecmCore) {
92 WebRtcAecm_Free(aecm);
93 return NULL;
94 }
niklase@google.com470e71d2011-07-07 08:21:25 +000095
Yves Gerey665174f2018-06-19 15:03:05 +020096 aecm->farendBuf = WebRtc_CreateBuffer(kBufSizeSamp, sizeof(int16_t));
97 if (!aecm->farendBuf) {
98 WebRtcAecm_Free(aecm);
99 return NULL;
100 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000101
Yves Gerey665174f2018-06-19 15:03:05 +0200102 aecm->initFlag = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000103
104#ifdef AEC_DEBUG
Yves Gerey665174f2018-06-19 15:03:05 +0200105 aecm->aecmCore->farFile = fopen("aecFar.pcm", "wb");
106 aecm->aecmCore->nearFile = fopen("aecNear.pcm", "wb");
107 aecm->aecmCore->outFile = fopen("aecOut.pcm", "wb");
108 // aecm->aecmCore->outLpFile = fopen("aecOutLp.pcm","wb");
niklase@google.com470e71d2011-07-07 08:21:25 +0000109
Yves Gerey665174f2018-06-19 15:03:05 +0200110 aecm->bufFile = fopen("aecBuf.dat", "wb");
111 aecm->delayFile = fopen("aecDelay.dat", "wb");
112 aecm->preCompFile = fopen("preComp.pcm", "wb");
113 aecm->postCompFile = fopen("postComp.pcm", "wb");
114#endif // AEC_DEBUG
115 return aecm;
niklase@google.com470e71d2011-07-07 08:21:25 +0000116}
117
Bjorn Volckerf6a99e62015-04-10 07:56:57 +0200118void WebRtcAecm_Free(void* aecmInst) {
peah27045122016-04-10 22:38:14 -0700119 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
niklase@google.com470e71d2011-07-07 08:21:25 +0000120
Yves Gerey665174f2018-06-19 15:03:05 +0200121 if (aecm == NULL) {
122 return;
123 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000124
125#ifdef AEC_DEBUG
Yves Gerey665174f2018-06-19 15:03:05 +0200126 fclose(aecm->aecmCore->farFile);
127 fclose(aecm->aecmCore->nearFile);
128 fclose(aecm->aecmCore->outFile);
129 // fclose(aecm->aecmCore->outLpFile);
niklase@google.com470e71d2011-07-07 08:21:25 +0000130
Yves Gerey665174f2018-06-19 15:03:05 +0200131 fclose(aecm->bufFile);
132 fclose(aecm->delayFile);
133 fclose(aecm->preCompFile);
134 fclose(aecm->postCompFile);
135#endif // AEC_DEBUG
136 WebRtcAecm_FreeCore(aecm->aecmCore);
137 WebRtc_FreeBuffer(aecm->farendBuf);
138 free(aecm);
niklase@google.com470e71d2011-07-07 08:21:25 +0000139}
140
Yves Gerey665174f2018-06-19 15:03:05 +0200141int32_t WebRtcAecm_Init(void* aecmInst, int32_t sampFreq) {
142 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
143 AecmConfig aecConfig;
niklase@google.com470e71d2011-07-07 08:21:25 +0000144
Yves Gerey665174f2018-06-19 15:03:05 +0200145 if (aecm == NULL) {
146 return -1;
147 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000148
Yves Gerey665174f2018-06-19 15:03:05 +0200149 if (sampFreq != 8000 && sampFreq != 16000) {
150 return AECM_BAD_PARAMETER_ERROR;
151 }
152 aecm->sampFreq = sampFreq;
niklase@google.com470e71d2011-07-07 08:21:25 +0000153
Yves Gerey665174f2018-06-19 15:03:05 +0200154 // Initialize AECM core
155 if (WebRtcAecm_InitCore(aecm->aecmCore, aecm->sampFreq) == -1) {
156 return AECM_UNSPECIFIED_ERROR;
157 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000158
Yves Gerey665174f2018-06-19 15:03:05 +0200159 // Initialize farend buffer
160 WebRtc_InitBuffer(aecm->farendBuf);
niklase@google.com470e71d2011-07-07 08:21:25 +0000161
Yves Gerey665174f2018-06-19 15:03:05 +0200162 aecm->initFlag = kInitCheck; // indicates that initialization has been done
niklase@google.com470e71d2011-07-07 08:21:25 +0000163
Yves Gerey665174f2018-06-19 15:03:05 +0200164 aecm->delayChange = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000165
Yves Gerey665174f2018-06-19 15:03:05 +0200166 aecm->sum = 0;
167 aecm->counter = 0;
168 aecm->checkBuffSize = 1;
169 aecm->firstVal = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000170
Yves Gerey665174f2018-06-19 15:03:05 +0200171 aecm->ECstartup = 1;
172 aecm->bufSizeStart = 0;
173 aecm->checkBufSizeCtr = 0;
174 aecm->filtDelay = 0;
175 aecm->timeForDelayChange = 0;
176 aecm->knownDelay = 0;
177 aecm->lastDelayDiff = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000178
Yves Gerey665174f2018-06-19 15:03:05 +0200179 memset(&aecm->farendOld, 0, sizeof(aecm->farendOld));
niklase@google.com470e71d2011-07-07 08:21:25 +0000180
Yves Gerey665174f2018-06-19 15:03:05 +0200181 // Default settings.
182 aecConfig.cngMode = AecmTrue;
183 aecConfig.echoMode = 3;
niklase@google.com470e71d2011-07-07 08:21:25 +0000184
Yves Gerey665174f2018-06-19 15:03:05 +0200185 if (WebRtcAecm_set_config(aecm, aecConfig) == -1) {
186 return AECM_UNSPECIFIED_ERROR;
187 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000188
Yves Gerey665174f2018-06-19 15:03:05 +0200189 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000190}
191
peahc12be392015-11-09 23:53:50 -0800192// Returns any error that is caused when buffering the
193// farend signal.
Yves Gerey665174f2018-06-19 15:03:05 +0200194int32_t WebRtcAecm_GetBufferFarendError(void* aecmInst,
195 const int16_t* farend,
196 size_t nrOfSamples) {
peah27045122016-04-10 22:38:14 -0700197 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
niklase@google.com470e71d2011-07-07 08:21:25 +0000198
peahc12be392015-11-09 23:53:50 -0800199 if (aecm == NULL)
200 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000201
peahc12be392015-11-09 23:53:50 -0800202 if (farend == NULL)
203 return AECM_NULL_POINTER_ERROR;
niklase@google.com470e71d2011-07-07 08:21:25 +0000204
peahc12be392015-11-09 23:53:50 -0800205 if (aecm->initFlag != kInitCheck)
206 return AECM_UNINITIALIZED_ERROR;
niklase@google.com470e71d2011-07-07 08:21:25 +0000207
peahc12be392015-11-09 23:53:50 -0800208 if (nrOfSamples != 80 && nrOfSamples != 160)
209 return AECM_BAD_PARAMETER_ERROR;
niklase@google.com470e71d2011-07-07 08:21:25 +0000210
peahc12be392015-11-09 23:53:50 -0800211 return 0;
212}
niklase@google.com470e71d2011-07-07 08:21:25 +0000213
Yves Gerey665174f2018-06-19 15:03:05 +0200214int32_t WebRtcAecm_BufferFarend(void* aecmInst,
215 const int16_t* farend,
peahc12be392015-11-09 23:53:50 -0800216 size_t nrOfSamples) {
peah27045122016-04-10 22:38:14 -0700217 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
peahc12be392015-11-09 23:53:50 -0800218
219 const int32_t err =
220 WebRtcAecm_GetBufferFarendError(aecmInst, farend, nrOfSamples);
221
222 if (err != 0)
223 return err;
224
225 // TODO(unknown): Is this really a good idea?
Yves Gerey665174f2018-06-19 15:03:05 +0200226 if (!aecm->ECstartup) {
peahc12be392015-11-09 23:53:50 -0800227 WebRtcAecm_DelayComp(aecm);
228 }
229
230 WebRtc_WriteBuffer(aecm->farendBuf, farend, nrOfSamples);
231
232 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000233}
234
Yves Gerey665174f2018-06-19 15:03:05 +0200235int32_t WebRtcAecm_Process(void* aecmInst,
236 const int16_t* nearendNoisy,
237 const int16_t* nearendClean,
238 int16_t* out,
239 size_t nrOfSamples,
240 int16_t msInSndCardBuf) {
241 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
242 int32_t retVal = 0;
243 size_t i;
244 short nmbrOfFilledBuffers;
245 size_t nBlocks10ms;
246 size_t nFrames;
niklase@google.com470e71d2011-07-07 08:21:25 +0000247#ifdef AEC_DEBUG
Yves Gerey665174f2018-06-19 15:03:05 +0200248 short msInAECBuf;
niklase@google.com470e71d2011-07-07 08:21:25 +0000249#endif
250
Yves Gerey665174f2018-06-19 15:03:05 +0200251 if (aecm == NULL) {
252 return -1;
253 }
254
255 if (nearendNoisy == NULL) {
256 return AECM_NULL_POINTER_ERROR;
257 }
258
259 if (out == NULL) {
260 return AECM_NULL_POINTER_ERROR;
261 }
262
263 if (aecm->initFlag != kInitCheck) {
264 return AECM_UNINITIALIZED_ERROR;
265 }
266
267 if (nrOfSamples != 80 && nrOfSamples != 160) {
268 return AECM_BAD_PARAMETER_ERROR;
269 }
270
271 if (msInSndCardBuf < 0) {
272 msInSndCardBuf = 0;
273 retVal = AECM_BAD_PARAMETER_WARNING;
274 } else if (msInSndCardBuf > 500) {
275 msInSndCardBuf = 500;
276 retVal = AECM_BAD_PARAMETER_WARNING;
277 }
278 msInSndCardBuf += 10;
279 aecm->msInSndCardBuf = msInSndCardBuf;
280
281 nFrames = nrOfSamples / FRAME_LEN;
282 nBlocks10ms = nFrames / aecm->aecmCore->mult;
283
284 if (aecm->ECstartup) {
285 if (nearendClean == NULL) {
286 if (out != nearendNoisy) {
287 memcpy(out, nearendNoisy, sizeof(short) * nrOfSamples);
288 }
289 } else if (out != nearendClean) {
290 memcpy(out, nearendClean, sizeof(short) * nrOfSamples);
291 }
292
293 nmbrOfFilledBuffers =
294 (short)WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
295 // The AECM is in the start up mode
296 // AECM is disabled until the soundcard buffer and farend buffers are OK
297
298 // Mechanism to ensure that the soundcard buffer is reasonably stable.
299 if (aecm->checkBuffSize) {
300 aecm->checkBufSizeCtr++;
301 // Before we fill up the far end buffer we require the amount of data on
302 // the sound card to be stable (+/-8 ms) compared to the first value. This
303 // comparison is made during the following 4 consecutive frames. If it
304 // seems to be stable then we start to fill up the far end buffer.
305
306 if (aecm->counter == 0) {
307 aecm->firstVal = aecm->msInSndCardBuf;
308 aecm->sum = 0;
309 }
310
311 if (abs(aecm->firstVal - aecm->msInSndCardBuf) <
312 WEBRTC_SPL_MAX(0.2 * aecm->msInSndCardBuf, kSampMsNb)) {
313 aecm->sum += aecm->msInSndCardBuf;
314 aecm->counter++;
315 } else {
316 aecm->counter = 0;
317 }
318
319 if (aecm->counter * nBlocks10ms >= 6) {
320 // The farend buffer size is determined in blocks of 80 samples
321 // Use 75% of the average value of the soundcard buffer
322 aecm->bufSizeStart = WEBRTC_SPL_MIN(
323 (3 * aecm->sum * aecm->aecmCore->mult) / (aecm->counter * 40),
324 BUF_SIZE_FRAMES);
325 // buffersize has now been determined
326 aecm->checkBuffSize = 0;
327 }
328
329 if (aecm->checkBufSizeCtr * nBlocks10ms > 50) {
330 // for really bad sound cards, don't disable echocanceller for more than
331 // 0.5 sec
332 aecm->bufSizeStart = WEBRTC_SPL_MIN(
333 (3 * aecm->msInSndCardBuf * aecm->aecmCore->mult) / 40,
334 BUF_SIZE_FRAMES);
335 aecm->checkBuffSize = 0;
336 }
337 }
338
339 // if checkBuffSize changed in the if-statement above
340 if (!aecm->checkBuffSize) {
341 // soundcard buffer is now reasonably stable
342 // When the far end buffer is filled with approximately the same amount of
343 // data as the amount on the sound card we end the start up phase and
344 // start to cancel echoes.
345
346 if (nmbrOfFilledBuffers == aecm->bufSizeStart) {
347 aecm->ECstartup = 0; // Enable the AECM
348 } else if (nmbrOfFilledBuffers > aecm->bufSizeStart) {
349 WebRtc_MoveReadPtr(aecm->farendBuf,
350 (int)WebRtc_available_read(aecm->farendBuf) -
351 (int)aecm->bufSizeStart * FRAME_LEN);
352 aecm->ECstartup = 0;
353 }
354 }
355
356 } else {
357 // AECM is enabled
358
359 // Note only 1 block supported for nb and 2 blocks for wb
360 for (i = 0; i < nFrames; i++) {
361 int16_t farend[FRAME_LEN];
362 const int16_t* farend_ptr = NULL;
363
364 nmbrOfFilledBuffers =
365 (short)WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
366
367 // Check that there is data in the far end buffer
368 if (nmbrOfFilledBuffers > 0) {
369 // Get the next 80 samples from the farend buffer
370 WebRtc_ReadBuffer(aecm->farendBuf, (void**)&farend_ptr, farend,
371 FRAME_LEN);
372
373 // Always store the last frame for use when we run out of data
374 memcpy(&(aecm->farendOld[i][0]), farend_ptr, FRAME_LEN * sizeof(short));
375 } else {
376 // We have no data so we use the last played frame
377 memcpy(farend, &(aecm->farendOld[i][0]), FRAME_LEN * sizeof(short));
378 farend_ptr = farend;
379 }
380
381 // Call buffer delay estimator when all data is extracted,
382 // i,e. i = 0 for NB and i = 1 for WB
383 if ((i == 0 && aecm->sampFreq == 8000) ||
384 (i == 1 && aecm->sampFreq == 16000)) {
385 WebRtcAecm_EstBufDelay(aecm, aecm->msInSndCardBuf);
386 }
387
388 // Call the AECM
389 /*WebRtcAecm_ProcessFrame(aecm->aecmCore, farend, &nearend[FRAME_LEN * i],
390 &out[FRAME_LEN * i], aecm->knownDelay);*/
391 if (WebRtcAecm_ProcessFrame(
392 aecm->aecmCore, farend_ptr, &nearendNoisy[FRAME_LEN * i],
393 (nearendClean ? &nearendClean[FRAME_LEN * i] : NULL),
394 &out[FRAME_LEN * i]) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000395 return -1;
396 }
Yves Gerey665174f2018-06-19 15:03:05 +0200397 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000398
399#ifdef AEC_DEBUG
Yves Gerey665174f2018-06-19 15:03:05 +0200400 msInAECBuf = (short)WebRtc_available_read(aecm->farendBuf) /
401 (kSampMsNb * aecm->aecmCore->mult);
402 fwrite(&msInAECBuf, 2, 1, aecm->bufFile);
403 fwrite(&(aecm->knownDelay), sizeof(aecm->knownDelay), 1, aecm->delayFile);
niklase@google.com470e71d2011-07-07 08:21:25 +0000404#endif
405
Yves Gerey665174f2018-06-19 15:03:05 +0200406 return retVal;
niklase@google.com470e71d2011-07-07 08:21:25 +0000407}
408
Yves Gerey665174f2018-06-19 15:03:05 +0200409int32_t WebRtcAecm_set_config(void* aecmInst, AecmConfig config) {
410 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
niklase@google.com470e71d2011-07-07 08:21:25 +0000411
Yves Gerey665174f2018-06-19 15:03:05 +0200412 if (aecm == NULL) {
413 return -1;
414 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000415
Yves Gerey665174f2018-06-19 15:03:05 +0200416 if (aecm->initFlag != kInitCheck) {
417 return AECM_UNINITIALIZED_ERROR;
418 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000419
Yves Gerey665174f2018-06-19 15:03:05 +0200420 if (config.cngMode != AecmFalse && config.cngMode != AecmTrue) {
421 return AECM_BAD_PARAMETER_ERROR;
422 }
423 aecm->aecmCore->cngMode = config.cngMode;
niklase@google.com470e71d2011-07-07 08:21:25 +0000424
Yves Gerey665174f2018-06-19 15:03:05 +0200425 if (config.echoMode < 0 || config.echoMode > 4) {
426 return AECM_BAD_PARAMETER_ERROR;
427 }
428 aecm->echoMode = config.echoMode;
niklase@google.com470e71d2011-07-07 08:21:25 +0000429
Yves Gerey665174f2018-06-19 15:03:05 +0200430 if (aecm->echoMode == 0) {
431 aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 3;
432 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 3;
433 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 3;
434 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 3;
435 aecm->aecmCore->supGainErrParamDiffAB =
436 (SUPGAIN_ERROR_PARAM_A >> 3) - (SUPGAIN_ERROR_PARAM_B >> 3);
437 aecm->aecmCore->supGainErrParamDiffBD =
438 (SUPGAIN_ERROR_PARAM_B >> 3) - (SUPGAIN_ERROR_PARAM_D >> 3);
439 } else if (aecm->echoMode == 1) {
440 aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 2;
441 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 2;
442 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 2;
443 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 2;
444 aecm->aecmCore->supGainErrParamDiffAB =
445 (SUPGAIN_ERROR_PARAM_A >> 2) - (SUPGAIN_ERROR_PARAM_B >> 2);
446 aecm->aecmCore->supGainErrParamDiffBD =
447 (SUPGAIN_ERROR_PARAM_B >> 2) - (SUPGAIN_ERROR_PARAM_D >> 2);
448 } else if (aecm->echoMode == 2) {
449 aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 1;
450 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 1;
451 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 1;
452 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 1;
453 aecm->aecmCore->supGainErrParamDiffAB =
454 (SUPGAIN_ERROR_PARAM_A >> 1) - (SUPGAIN_ERROR_PARAM_B >> 1);
455 aecm->aecmCore->supGainErrParamDiffBD =
456 (SUPGAIN_ERROR_PARAM_B >> 1) - (SUPGAIN_ERROR_PARAM_D >> 1);
457 } else if (aecm->echoMode == 3) {
458 aecm->aecmCore->supGain = SUPGAIN_DEFAULT;
459 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT;
460 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
461 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
462 aecm->aecmCore->supGainErrParamDiffAB =
463 SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
464 aecm->aecmCore->supGainErrParamDiffBD =
465 SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
466 } else if (aecm->echoMode == 4) {
467 aecm->aecmCore->supGain = SUPGAIN_DEFAULT << 1;
468 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT << 1;
469 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A << 1;
470 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D << 1;
471 aecm->aecmCore->supGainErrParamDiffAB =
472 (SUPGAIN_ERROR_PARAM_A << 1) - (SUPGAIN_ERROR_PARAM_B << 1);
473 aecm->aecmCore->supGainErrParamDiffBD =
474 (SUPGAIN_ERROR_PARAM_B << 1) - (SUPGAIN_ERROR_PARAM_D << 1);
475 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000476
Yves Gerey665174f2018-06-19 15:03:05 +0200477 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000478}
479
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000480int32_t WebRtcAecm_InitEchoPath(void* aecmInst,
481 const void* echo_path,
Yves Gerey665174f2018-06-19 15:03:05 +0200482 size_t size_bytes) {
483 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
484 const int16_t* echo_path_ptr = static_cast<const int16_t*>(echo_path);
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000485
Yves Gerey665174f2018-06-19 15:03:05 +0200486 if (aecmInst == NULL) {
487 return -1;
488 }
489 if (echo_path == NULL) {
490 return AECM_NULL_POINTER_ERROR;
491 }
492 if (size_bytes != WebRtcAecm_echo_path_size_bytes()) {
493 // Input channel size does not match the size of AECM
494 return AECM_BAD_PARAMETER_ERROR;
495 }
496 if (aecm->initFlag != kInitCheck) {
497 return AECM_UNINITIALIZED_ERROR;
498 }
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000499
Yves Gerey665174f2018-06-19 15:03:05 +0200500 WebRtcAecm_InitEchoPathCore(aecm->aecmCore, echo_path_ptr);
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000501
Yves Gerey665174f2018-06-19 15:03:05 +0200502 return 0;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000503}
504
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000505int32_t WebRtcAecm_GetEchoPath(void* aecmInst,
506 void* echo_path,
Yves Gerey665174f2018-06-19 15:03:05 +0200507 size_t size_bytes) {
508 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
509 int16_t* echo_path_ptr = static_cast<int16_t*>(echo_path);
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000510
Yves Gerey665174f2018-06-19 15:03:05 +0200511 if (aecmInst == NULL) {
512 return -1;
513 }
514 if (echo_path == NULL) {
515 return AECM_NULL_POINTER_ERROR;
516 }
517 if (size_bytes != WebRtcAecm_echo_path_size_bytes()) {
518 // Input channel size does not match the size of AECM
519 return AECM_BAD_PARAMETER_ERROR;
520 }
521 if (aecm->initFlag != kInitCheck) {
522 return AECM_UNINITIALIZED_ERROR;
523 }
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000524
Yves Gerey665174f2018-06-19 15:03:05 +0200525 memcpy(echo_path_ptr, aecm->aecmCore->channelStored, size_bytes);
526 return 0;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000527}
528
Yves Gerey665174f2018-06-19 15:03:05 +0200529size_t WebRtcAecm_echo_path_size_bytes() {
530 return (PART_LEN1 * sizeof(int16_t));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000531}
532
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000533static int WebRtcAecm_EstBufDelay(AecMobile* aecm, short msInSndCardBuf) {
Yves Gerey665174f2018-06-19 15:03:05 +0200534 short delayNew, nSampSndCard;
535 short nSampFar = (short)WebRtc_available_read(aecm->farendBuf);
536 short diff;
niklase@google.com470e71d2011-07-07 08:21:25 +0000537
Yves Gerey665174f2018-06-19 15:03:05 +0200538 nSampSndCard = msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
niklase@google.com470e71d2011-07-07 08:21:25 +0000539
Yves Gerey665174f2018-06-19 15:03:05 +0200540 delayNew = nSampSndCard - nSampFar;
niklase@google.com470e71d2011-07-07 08:21:25 +0000541
Yves Gerey665174f2018-06-19 15:03:05 +0200542 if (delayNew < FRAME_LEN) {
543 WebRtc_MoveReadPtr(aecm->farendBuf, FRAME_LEN);
544 delayNew += FRAME_LEN;
545 }
546
547 aecm->filtDelay =
548 WEBRTC_SPL_MAX(0, (8 * aecm->filtDelay + 2 * delayNew) / 10);
549
550 diff = aecm->filtDelay - aecm->knownDelay;
551 if (diff > 224) {
552 if (aecm->lastDelayDiff < 96) {
553 aecm->timeForDelayChange = 0;
554 } else {
555 aecm->timeForDelayChange++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000556 }
Yves Gerey665174f2018-06-19 15:03:05 +0200557 } else if (diff < 96 && aecm->knownDelay > 0) {
558 if (aecm->lastDelayDiff > 224) {
559 aecm->timeForDelayChange = 0;
560 } else {
561 aecm->timeForDelayChange++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000562 }
Yves Gerey665174f2018-06-19 15:03:05 +0200563 } else {
564 aecm->timeForDelayChange = 0;
565 }
566 aecm->lastDelayDiff = diff;
niklase@google.com470e71d2011-07-07 08:21:25 +0000567
Yves Gerey665174f2018-06-19 15:03:05 +0200568 if (aecm->timeForDelayChange > 25) {
569 aecm->knownDelay = WEBRTC_SPL_MAX((int)aecm->filtDelay - 160, 0);
570 }
571 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000572}
573
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000574static int WebRtcAecm_DelayComp(AecMobile* aecm) {
Yves Gerey665174f2018-06-19 15:03:05 +0200575 int nSampFar = (int)WebRtc_available_read(aecm->farendBuf);
576 int nSampSndCard, delayNew, nSampAdd;
577 const int maxStuffSamp = 10 * FRAME_LEN;
niklase@google.com470e71d2011-07-07 08:21:25 +0000578
Yves Gerey665174f2018-06-19 15:03:05 +0200579 nSampSndCard = aecm->msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
580 delayNew = nSampSndCard - nSampFar;
niklase@google.com470e71d2011-07-07 08:21:25 +0000581
Yves Gerey665174f2018-06-19 15:03:05 +0200582 if (delayNew > FAR_BUF_LEN - FRAME_LEN * aecm->aecmCore->mult) {
583 // The difference of the buffer sizes is larger than the maximum
584 // allowed known delay. Compensate by stuffing the buffer.
585 nSampAdd =
586 (int)(WEBRTC_SPL_MAX(((nSampSndCard >> 1) - nSampFar), FRAME_LEN));
587 nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp);
niklase@google.com470e71d2011-07-07 08:21:25 +0000588
Yves Gerey665174f2018-06-19 15:03:05 +0200589 WebRtc_MoveReadPtr(aecm->farendBuf, -nSampAdd);
590 aecm->delayChange = 1; // the delay needs to be updated
591 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000592
Yves Gerey665174f2018-06-19 15:03:05 +0200593 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000594}