blob: 027ed14cf7b1b4c6ab9da6cc1e66ebdfe378e4f7 [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
Henrik Kjellander9b72af92015-11-11 20:16:11 +010011#include "webrtc/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>
17
peah27045122016-04-10 22:38:14 -070018extern "C" {
peahfaed4ab2016-04-05 14:57:48 -070019#include "webrtc/common_audio/ring_buffer.h"
andrew@webrtc.org9ae13542013-02-25 17:07:35 +000020#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
peah27045122016-04-10 22:38:14 -070021}
andrew@webrtc.org9ae13542013-02-25 17:07:35 +000022#include "webrtc/modules/audio_processing/aecm/aecm_core.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000023
24#define BUF_SIZE_FRAMES 50 // buffer size (frames)
25// Maximum length of resampled signal. Must be an integer multiple of frames
26// (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN
27// The factor of 2 handles wb, and the + 1 is as a safety margin
28#define MAX_RESAMP_LEN (5 * FRAME_LEN)
29
bjornv@webrtc.org80d28b22012-01-04 09:55:09 +000030static const size_t kBufSizeSamp = BUF_SIZE_FRAMES * FRAME_LEN; // buffer size (samples)
niklase@google.com470e71d2011-07-07 08:21:25 +000031static const int kSampMsNb = 8; // samples per ms in nb
32// Target suppression levels for nlp modes
33// log{0.001, 0.00001, 0.00000001}
34static const int kInitCheck = 42;
35
36typedef struct
37{
38 int sampFreq;
39 int scSampFreq;
40 short bufSizeStart;
41 int knownDelay;
42
43 // Stores the last frame added to the farend buffer
44 short farendOld[2][FRAME_LEN];
45 short initFlag; // indicates if AEC has been initialized
46
47 // Variables used for averaging far end buffer size
48 short counter;
49 short sum;
50 short firstVal;
51 short checkBufSizeCtr;
52
53 // Variables used for delay shifts
54 short msInSndCardBuf;
55 short filtDelay;
56 int timeForDelayChange;
57 int ECstartup;
58 int checkBuffSize;
59 int delayChange;
60 short lastDelayDiff;
61
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000062 int16_t echoMode;
niklase@google.com470e71d2011-07-07 08:21:25 +000063
64#ifdef AEC_DEBUG
65 FILE *bufFile;
66 FILE *delayFile;
67 FILE *preCompFile;
68 FILE *postCompFile;
69#endif // AEC_DEBUG
70 // Structures
andrew@webrtc.org9ae13542013-02-25 17:07:35 +000071 RingBuffer *farendBuf;
niklase@google.com470e71d2011-07-07 08:21:25 +000072
pbos@webrtc.orge468bc92014-12-18 09:11:33 +000073 AecmCore* aecmCore;
74} AecMobile;
niklase@google.com470e71d2011-07-07 08:21:25 +000075
76// Estimates delay to set the position of the farend buffer read pointer
77// (controlled by knownDelay)
Alex Loiko890988c2017-08-31 10:25:48 +020078static int WebRtcAecm_EstBufDelay(AecMobile* aecm, short msInSndCardBuf);
niklase@google.com470e71d2011-07-07 08:21:25 +000079
80// Stuffs the farend buffer if the estimated delay is too large
Alex Loiko890988c2017-08-31 10:25:48 +020081static int WebRtcAecm_DelayComp(AecMobile* aecm);
niklase@google.com470e71d2011-07-07 08:21:25 +000082
Bjorn Volckera7437942015-05-28 15:58:42 +020083void* WebRtcAecm_Create() {
peah27045122016-04-10 22:38:14 -070084 AecMobile* aecm = static_cast<AecMobile*>(malloc(sizeof(AecMobile)));
niklase@google.com470e71d2011-07-07 08:21:25 +000085
kma@webrtc.org31829a72013-03-19 00:25:01 +000086 WebRtcSpl_Init();
87
Bjorn Volckera7437942015-05-28 15:58:42 +020088 aecm->aecmCore = WebRtcAecm_CreateCore();
89 if (!aecm->aecmCore) {
niklase@google.com470e71d2011-07-07 08:21:25 +000090 WebRtcAecm_Free(aecm);
Bjorn Volckera7437942015-05-28 15:58:42 +020091 return NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +000092 }
93
andrew@webrtc.org91f32552013-02-27 00:35:06 +000094 aecm->farendBuf = WebRtc_CreateBuffer(kBufSizeSamp,
95 sizeof(int16_t));
96 if (!aecm->farendBuf)
niklase@google.com470e71d2011-07-07 08:21:25 +000097 {
98 WebRtcAecm_Free(aecm);
Bjorn Volckera7437942015-05-28 15:58:42 +020099 return NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000100 }
101
102 aecm->initFlag = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000103
104#ifdef AEC_DEBUG
105 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");
109
110 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
Bjorn Volckera7437942015-05-28 15:58:42 +0200115 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
Bjorn Volckerf6a99e62015-04-10 07:56:57 +0200121 if (aecm == NULL) {
122 return;
niklase@google.com470e71d2011-07-07 08:21:25 +0000123 }
124
125#ifdef AEC_DEBUG
126 fclose(aecm->aecmCore->farFile);
127 fclose(aecm->aecmCore->nearFile);
128 fclose(aecm->aecmCore->outFile);
129 //fclose(aecm->aecmCore->outLpFile);
130
131 fclose(aecm->bufFile);
132 fclose(aecm->delayFile);
133 fclose(aecm->preCompFile);
134 fclose(aecm->postCompFile);
135#endif // AEC_DEBUG
136 WebRtcAecm_FreeCore(aecm->aecmCore);
bjornv@webrtc.org80d28b22012-01-04 09:55:09 +0000137 WebRtc_FreeBuffer(aecm->farendBuf);
niklase@google.com470e71d2011-07-07 08:21:25 +0000138 free(aecm);
niklase@google.com470e71d2011-07-07 08:21:25 +0000139}
140
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000141int32_t WebRtcAecm_Init(void *aecmInst, int32_t sampFreq)
niklase@google.com470e71d2011-07-07 08:21:25 +0000142{
peah27045122016-04-10 22:38:14 -0700143 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
niklase@google.com470e71d2011-07-07 08:21:25 +0000144 AecmConfig aecConfig;
145
146 if (aecm == NULL)
147 {
148 return -1;
149 }
150
151 if (sampFreq != 8000 && sampFreq != 16000)
152 {
peahc12be392015-11-09 23:53:50 -0800153 return AECM_BAD_PARAMETER_ERROR;
niklase@google.com470e71d2011-07-07 08:21:25 +0000154 }
155 aecm->sampFreq = sampFreq;
156
niklase@google.com470e71d2011-07-07 08:21:25 +0000157 // Initialize AECM core
158 if (WebRtcAecm_InitCore(aecm->aecmCore, aecm->sampFreq) == -1)
159 {
peahc12be392015-11-09 23:53:50 -0800160 return AECM_UNSPECIFIED_ERROR;
niklase@google.com470e71d2011-07-07 08:21:25 +0000161 }
162
163 // Initialize farend buffer
andrew@webrtc.org6b630152015-01-15 00:09:53 +0000164 WebRtc_InitBuffer(aecm->farendBuf);
niklase@google.com470e71d2011-07-07 08:21:25 +0000165
166 aecm->initFlag = kInitCheck; // indicates that initialization has been done
167
168 aecm->delayChange = 1;
169
170 aecm->sum = 0;
171 aecm->counter = 0;
172 aecm->checkBuffSize = 1;
173 aecm->firstVal = 0;
174
175 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;
182
183 memset(&aecm->farendOld[0][0], 0, 160);
184
185 // Default settings.
186 aecConfig.cngMode = AecmTrue;
187 aecConfig.echoMode = 3;
188
189 if (WebRtcAecm_set_config(aecm, aecConfig) == -1)
190 {
peahc12be392015-11-09 23:53:50 -0800191 return AECM_UNSPECIFIED_ERROR;
niklase@google.com470e71d2011-07-07 08:21:25 +0000192 }
193
194 return 0;
195}
196
peahc12be392015-11-09 23:53:50 -0800197// Returns any error that is caused when buffering the
198// farend signal.
199int32_t WebRtcAecm_GetBufferFarendError(void *aecmInst, 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
niklase@google.com470e71d2011-07-07 08:21:25 +0000218
peahc12be392015-11-09 23:53:50 -0800219int32_t WebRtcAecm_BufferFarend(void *aecmInst, const int16_t *farend,
220 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?
230 if (!aecm->ECstartup)
231 {
232 WebRtcAecm_DelayComp(aecm);
233 }
234
235 WebRtc_WriteBuffer(aecm->farendBuf, farend, nrOfSamples);
236
237 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000238}
239
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000240int32_t WebRtcAecm_Process(void *aecmInst, const int16_t *nearendNoisy,
241 const int16_t *nearendClean, int16_t *out,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700242 size_t nrOfSamples, int16_t msInSndCardBuf)
niklase@google.com470e71d2011-07-07 08:21:25 +0000243{
peah27045122016-04-10 22:38:14 -0700244 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000245 int32_t retVal = 0;
Peter Kastingdce40cf2015-08-24 14:52:23 -0700246 size_t i;
niklase@google.com470e71d2011-07-07 08:21:25 +0000247 short nmbrOfFilledBuffers;
Peter Kastingdce40cf2015-08-24 14:52:23 -0700248 size_t nBlocks10ms;
249 size_t nFrames;
niklase@google.com470e71d2011-07-07 08:21:25 +0000250#ifdef AEC_DEBUG
251 short msInAECBuf;
252#endif
253
niklase@google.com470e71d2011-07-07 08:21:25 +0000254 if (aecm == NULL)
255 {
256 return -1;
257 }
258
259 if (nearendNoisy == NULL)
260 {
peahc12be392015-11-09 23:53:50 -0800261 return AECM_NULL_POINTER_ERROR;
niklase@google.com470e71d2011-07-07 08:21:25 +0000262 }
263
264 if (out == NULL)
265 {
peahc12be392015-11-09 23:53:50 -0800266 return AECM_NULL_POINTER_ERROR;
niklase@google.com470e71d2011-07-07 08:21:25 +0000267 }
268
269 if (aecm->initFlag != kInitCheck)
270 {
peahc12be392015-11-09 23:53:50 -0800271 return AECM_UNINITIALIZED_ERROR;
niklase@google.com470e71d2011-07-07 08:21:25 +0000272 }
273
274 if (nrOfSamples != 80 && nrOfSamples != 160)
275 {
peahc12be392015-11-09 23:53:50 -0800276 return AECM_BAD_PARAMETER_ERROR;
niklase@google.com470e71d2011-07-07 08:21:25 +0000277 }
278
279 if (msInSndCardBuf < 0)
280 {
281 msInSndCardBuf = 0;
peahc12be392015-11-09 23:53:50 -0800282 retVal = AECM_BAD_PARAMETER_WARNING;
niklase@google.com470e71d2011-07-07 08:21:25 +0000283 } else if (msInSndCardBuf > 500)
284 {
285 msInSndCardBuf = 500;
peahc12be392015-11-09 23:53:50 -0800286 retVal = AECM_BAD_PARAMETER_WARNING;
niklase@google.com470e71d2011-07-07 08:21:25 +0000287 }
288 msInSndCardBuf += 10;
289 aecm->msInSndCardBuf = msInSndCardBuf;
290
291 nFrames = nrOfSamples / FRAME_LEN;
292 nBlocks10ms = nFrames / aecm->aecmCore->mult;
293
294 if (aecm->ECstartup)
295 {
wu@webrtc.orga8084b02012-02-08 17:56:39 +0000296 if (nearendClean == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000297 {
andrew@webrtc.org75f19482012-02-09 17:16:18 +0000298 if (out != nearendNoisy)
299 {
300 memcpy(out, nearendNoisy, sizeof(short) * nrOfSamples);
301 }
302 } else if (out != nearendClean)
niklase@google.com470e71d2011-07-07 08:21:25 +0000303 {
304 memcpy(out, nearendClean, sizeof(short) * nrOfSamples);
305 }
306
bjornv@webrtc.org80d28b22012-01-04 09:55:09 +0000307 nmbrOfFilledBuffers =
308 (short) WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
niklase@google.com470e71d2011-07-07 08:21:25 +0000309 // The AECM is in the start up mode
310 // AECM is disabled until the soundcard buffer and farend buffers are OK
311
312 // Mechanism to ensure that the soundcard buffer is reasonably stable.
313 if (aecm->checkBuffSize)
314 {
315 aecm->checkBufSizeCtr++;
316 // Before we fill up the far end buffer we require the amount of data on the
317 // sound card to be stable (+/-8 ms) compared to the first value. This
318 // comparison is made during the following 4 consecutive frames. If it seems
319 // to be stable then we start to fill up the far end buffer.
320
321 if (aecm->counter == 0)
322 {
323 aecm->firstVal = aecm->msInSndCardBuf;
324 aecm->sum = 0;
325 }
326
327 if (abs(aecm->firstVal - aecm->msInSndCardBuf)
328 < WEBRTC_SPL_MAX(0.2 * aecm->msInSndCardBuf, kSampMsNb))
329 {
330 aecm->sum += aecm->msInSndCardBuf;
331 aecm->counter++;
332 } else
333 {
334 aecm->counter = 0;
335 }
336
337 if (aecm->counter * nBlocks10ms >= 6)
338 {
339 // The farend buffer size is determined in blocks of 80 samples
340 // Use 75% of the average value of the soundcard buffer
341 aecm->bufSizeStart
342 = WEBRTC_SPL_MIN((3 * aecm->sum
343 * aecm->aecmCore->mult) / (aecm->counter * 40), BUF_SIZE_FRAMES);
344 // buffersize has now been determined
345 aecm->checkBuffSize = 0;
346 }
347
348 if (aecm->checkBufSizeCtr * nBlocks10ms > 50)
349 {
350 // for really bad sound cards, don't disable echocanceller for more than 0.5 sec
351 aecm->bufSizeStart = WEBRTC_SPL_MIN((3 * aecm->msInSndCardBuf
352 * aecm->aecmCore->mult) / 40, BUF_SIZE_FRAMES);
353 aecm->checkBuffSize = 0;
354 }
355 }
356
357 // if checkBuffSize changed in the if-statement above
358 if (!aecm->checkBuffSize)
359 {
360 // soundcard buffer is now reasonably stable
361 // When the far end buffer is filled with approximately the same amount of
362 // data as the amount on the sound card we end the start up phase and start
363 // to cancel echoes.
364
365 if (nmbrOfFilledBuffers == aecm->bufSizeStart)
366 {
367 aecm->ECstartup = 0; // Enable the AECM
368 } else if (nmbrOfFilledBuffers > aecm->bufSizeStart)
369 {
bjornv@webrtc.org80d28b22012-01-04 09:55:09 +0000370 WebRtc_MoveReadPtr(aecm->farendBuf,
371 (int) WebRtc_available_read(aecm->farendBuf)
372 - (int) aecm->bufSizeStart * FRAME_LEN);
niklase@google.com470e71d2011-07-07 08:21:25 +0000373 aecm->ECstartup = 0;
374 }
375 }
376
377 } else
378 {
379 // AECM is enabled
380
381 // Note only 1 block supported for nb and 2 blocks for wb
382 for (i = 0; i < nFrames; i++)
383 {
bjornv@webrtc.org80d28b22012-01-04 09:55:09 +0000384 int16_t farend[FRAME_LEN];
385 const int16_t* farend_ptr = NULL;
386
387 nmbrOfFilledBuffers =
388 (short) WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
niklase@google.com470e71d2011-07-07 08:21:25 +0000389
390 // Check that there is data in the far end buffer
391 if (nmbrOfFilledBuffers > 0)
392 {
393 // Get the next 80 samples from the farend buffer
bjornv@webrtc.org80d28b22012-01-04 09:55:09 +0000394 WebRtc_ReadBuffer(aecm->farendBuf, (void**) &farend_ptr, farend,
395 FRAME_LEN);
niklase@google.com470e71d2011-07-07 08:21:25 +0000396
397 // Always store the last frame for use when we run out of data
bjornv@webrtc.org80d28b22012-01-04 09:55:09 +0000398 memcpy(&(aecm->farendOld[i][0]), farend_ptr,
399 FRAME_LEN * sizeof(short));
niklase@google.com470e71d2011-07-07 08:21:25 +0000400 } else
401 {
402 // We have no data so we use the last played frame
403 memcpy(farend, &(aecm->farendOld[i][0]), FRAME_LEN * sizeof(short));
bjornv@webrtc.org80d28b22012-01-04 09:55:09 +0000404 farend_ptr = farend;
niklase@google.com470e71d2011-07-07 08:21:25 +0000405 }
406
407 // Call buffer delay estimator when all data is extracted,
408 // i,e. i = 0 for NB and i = 1 for WB
409 if ((i == 0 && aecm->sampFreq == 8000) || (i == 1 && aecm->sampFreq == 16000))
410 {
411 WebRtcAecm_EstBufDelay(aecm, aecm->msInSndCardBuf);
412 }
413
niklase@google.com470e71d2011-07-07 08:21:25 +0000414 // Call the AECM
415 /*WebRtcAecm_ProcessFrame(aecm->aecmCore, farend, &nearend[FRAME_LEN * i],
416 &out[FRAME_LEN * i], aecm->knownDelay);*/
kwiberg@webrtc.orge57ae022014-04-17 12:28:33 +0000417 if (WebRtcAecm_ProcessFrame(aecm->aecmCore,
418 farend_ptr,
419 &nearendNoisy[FRAME_LEN * i],
420 (nearendClean
421 ? &nearendClean[FRAME_LEN * i]
422 : NULL),
423 &out[FRAME_LEN * i]) == -1)
424 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000425 }
426 }
427
428#ifdef AEC_DEBUG
bjornv@webrtc.org80d28b22012-01-04 09:55:09 +0000429 msInAECBuf = (short) WebRtc_available_read(aecm->farendBuf) /
430 (kSampMsNb * aecm->aecmCore->mult);
niklase@google.com470e71d2011-07-07 08:21:25 +0000431 fwrite(&msInAECBuf, 2, 1, aecm->bufFile);
432 fwrite(&(aecm->knownDelay), sizeof(aecm->knownDelay), 1, aecm->delayFile);
433#endif
434
435 return retVal;
436}
437
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000438int32_t WebRtcAecm_set_config(void *aecmInst, AecmConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000439{
peah27045122016-04-10 22:38:14 -0700440 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
niklase@google.com470e71d2011-07-07 08:21:25 +0000441
442 if (aecm == NULL)
443 {
444 return -1;
445 }
446
447 if (aecm->initFlag != kInitCheck)
448 {
peahc12be392015-11-09 23:53:50 -0800449 return AECM_UNINITIALIZED_ERROR;
niklase@google.com470e71d2011-07-07 08:21:25 +0000450 }
451
452 if (config.cngMode != AecmFalse && config.cngMode != AecmTrue)
453 {
peahc12be392015-11-09 23:53:50 -0800454 return AECM_BAD_PARAMETER_ERROR;
niklase@google.com470e71d2011-07-07 08:21:25 +0000455 }
456 aecm->aecmCore->cngMode = config.cngMode;
457
458 if (config.echoMode < 0 || config.echoMode > 4)
459 {
peahc12be392015-11-09 23:53:50 -0800460 return AECM_BAD_PARAMETER_ERROR;
niklase@google.com470e71d2011-07-07 08:21:25 +0000461 }
462 aecm->echoMode = config.echoMode;
463
464 if (aecm->echoMode == 0)
465 {
466 aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 3;
467 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 3;
468 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 3;
469 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 3;
470 aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 3)
471 - (SUPGAIN_ERROR_PARAM_B >> 3);
472 aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 3)
473 - (SUPGAIN_ERROR_PARAM_D >> 3);
474 } else if (aecm->echoMode == 1)
475 {
476 aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 2;
477 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 2;
478 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 2;
479 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 2;
480 aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 2)
481 - (SUPGAIN_ERROR_PARAM_B >> 2);
482 aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 2)
483 - (SUPGAIN_ERROR_PARAM_D >> 2);
484 } else if (aecm->echoMode == 2)
485 {
486 aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 1;
487 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 1;
488 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 1;
489 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 1;
490 aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 1)
491 - (SUPGAIN_ERROR_PARAM_B >> 1);
492 aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 1)
493 - (SUPGAIN_ERROR_PARAM_D >> 1);
494 } else if (aecm->echoMode == 3)
495 {
496 aecm->aecmCore->supGain = SUPGAIN_DEFAULT;
497 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT;
498 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A;
499 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D;
500 aecm->aecmCore->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B;
501 aecm->aecmCore->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D;
502 } else if (aecm->echoMode == 4)
503 {
504 aecm->aecmCore->supGain = SUPGAIN_DEFAULT << 1;
505 aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT << 1;
506 aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A << 1;
507 aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D << 1;
508 aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A << 1)
509 - (SUPGAIN_ERROR_PARAM_B << 1);
510 aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B << 1)
511 - (SUPGAIN_ERROR_PARAM_D << 1);
512 }
513
514 return 0;
515}
516
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000517int32_t WebRtcAecm_InitEchoPath(void* aecmInst,
518 const void* echo_path,
519 size_t size_bytes)
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000520{
peah27045122016-04-10 22:38:14 -0700521 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
522 const int16_t* echo_path_ptr = static_cast<const int16_t*>(echo_path);
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000523
bjornv@webrtc.org61d07452012-05-11 07:51:44 +0000524 if (aecmInst == NULL) {
525 return -1;
526 }
527 if (echo_path == NULL) {
peahc12be392015-11-09 23:53:50 -0800528 return AECM_NULL_POINTER_ERROR;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000529 }
530 if (size_bytes != WebRtcAecm_echo_path_size_bytes())
531 {
532 // Input channel size does not match the size of AECM
peahc12be392015-11-09 23:53:50 -0800533 return AECM_BAD_PARAMETER_ERROR;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000534 }
535 if (aecm->initFlag != kInitCheck)
536 {
peahc12be392015-11-09 23:53:50 -0800537 return AECM_UNINITIALIZED_ERROR;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000538 }
539
540 WebRtcAecm_InitEchoPathCore(aecm->aecmCore, echo_path_ptr);
541
542 return 0;
543}
544
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000545int32_t WebRtcAecm_GetEchoPath(void* aecmInst,
546 void* echo_path,
547 size_t size_bytes)
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000548{
peah27045122016-04-10 22:38:14 -0700549 AecMobile* aecm = static_cast<AecMobile*>(aecmInst);
550 int16_t* echo_path_ptr = static_cast<int16_t*>(echo_path);
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000551
bjornv@webrtc.org61d07452012-05-11 07:51:44 +0000552 if (aecmInst == NULL) {
553 return -1;
554 }
555 if (echo_path == NULL) {
peahc12be392015-11-09 23:53:50 -0800556 return AECM_NULL_POINTER_ERROR;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000557 }
558 if (size_bytes != WebRtcAecm_echo_path_size_bytes())
559 {
560 // Input channel size does not match the size of AECM
peahc12be392015-11-09 23:53:50 -0800561 return AECM_BAD_PARAMETER_ERROR;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000562 }
563 if (aecm->initFlag != kInitCheck)
564 {
peahc12be392015-11-09 23:53:50 -0800565 return AECM_UNINITIALIZED_ERROR;
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000566 }
567
568 memcpy(echo_path_ptr, aecm->aecmCore->channelStored, size_bytes);
569 return 0;
570}
571
ajm@google.com22e65152011-07-18 18:03:01 +0000572size_t WebRtcAecm_echo_path_size_bytes()
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000573{
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000574 return (PART_LEN1 * sizeof(int16_t));
bjornv@google.comc4b939c2011-07-13 08:09:56 +0000575}
576
niklase@google.com470e71d2011-07-07 08:21:25 +0000577
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000578static int WebRtcAecm_EstBufDelay(AecMobile* aecm, short msInSndCardBuf) {
bjornv@webrtc.org80d28b22012-01-04 09:55:09 +0000579 short delayNew, nSampSndCard;
580 short nSampFar = (short) WebRtc_available_read(aecm->farendBuf);
niklase@google.com470e71d2011-07-07 08:21:25 +0000581 short diff;
582
niklase@google.com470e71d2011-07-07 08:21:25 +0000583 nSampSndCard = msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
584
585 delayNew = nSampSndCard - nSampFar;
586
587 if (delayNew < FRAME_LEN)
588 {
bjornv@webrtc.org80d28b22012-01-04 09:55:09 +0000589 WebRtc_MoveReadPtr(aecm->farendBuf, FRAME_LEN);
niklase@google.com470e71d2011-07-07 08:21:25 +0000590 delayNew += FRAME_LEN;
591 }
592
593 aecm->filtDelay = WEBRTC_SPL_MAX(0, (8 * aecm->filtDelay + 2 * delayNew) / 10);
594
595 diff = aecm->filtDelay - aecm->knownDelay;
596 if (diff > 224)
597 {
598 if (aecm->lastDelayDiff < 96)
599 {
600 aecm->timeForDelayChange = 0;
601 } else
602 {
603 aecm->timeForDelayChange++;
604 }
605 } else if (diff < 96 && aecm->knownDelay > 0)
606 {
607 if (aecm->lastDelayDiff > 224)
608 {
609 aecm->timeForDelayChange = 0;
610 } else
611 {
612 aecm->timeForDelayChange++;
613 }
614 } else
615 {
616 aecm->timeForDelayChange = 0;
617 }
618 aecm->lastDelayDiff = diff;
619
620 if (aecm->timeForDelayChange > 25)
621 {
622 aecm->knownDelay = WEBRTC_SPL_MAX((int)aecm->filtDelay - 160, 0);
623 }
624 return 0;
625}
626
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000627static int WebRtcAecm_DelayComp(AecMobile* aecm) {
bjornv@webrtc.org80d28b22012-01-04 09:55:09 +0000628 int nSampFar = (int) WebRtc_available_read(aecm->farendBuf);
629 int nSampSndCard, delayNew, nSampAdd;
niklase@google.com470e71d2011-07-07 08:21:25 +0000630 const int maxStuffSamp = 10 * FRAME_LEN;
631
niklase@google.com470e71d2011-07-07 08:21:25 +0000632 nSampSndCard = aecm->msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
633 delayNew = nSampSndCard - nSampFar;
634
635 if (delayNew > FAR_BUF_LEN - FRAME_LEN * aecm->aecmCore->mult)
636 {
637 // The difference of the buffer sizes is larger than the maximum
638 // allowed known delay. Compensate by stuffing the buffer.
639 nSampAdd = (int)(WEBRTC_SPL_MAX(((nSampSndCard >> 1) - nSampFar),
640 FRAME_LEN));
641 nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp);
642
bjornv@webrtc.org80d28b22012-01-04 09:55:09 +0000643 WebRtc_MoveReadPtr(aecm->farendBuf, -nSampAdd);
niklase@google.com470e71d2011-07-07 08:21:25 +0000644 aecm->delayChange = 1; // the delay needs to be updated
645 }
646
647 return 0;
648}