1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 /* analog_agc.c
12 *
13 * Using a feedback system, determines an appropriate analog volume level
14 * given an input signal and current volume level. Targets a conservative
15 * signal level and is intended for use with a digital AGC to apply
16 * additional gain.
17 *
18 */
19
20 #include "webrtc/modules/audio_processing/agc/legacy/analog_agc.h"
21
22 #include <assert.h>
23 #include <stdlib.h>
24 #ifdef WEBRTC_AGC_DEBUG_DUMP
25 #include <stdio.h>
26 #endif
27
28 /* The slope of in Q13*/
29 static const int16_t kSlope1[8] = {21793, 12517, 7189, 4129, 2372, 1362, 472, 78};
30
31 /* The offset in Q14 */
32 static const int16_t kOffset1[8] = {25395, 23911, 22206, 20737, 19612, 18805, 17951,
33 17367};
34
35 /* The slope of in Q13*/
36 static const int16_t kSlope2[8] = {2063, 1731, 1452, 1218, 1021, 857, 597, 337};
37
38 /* The offset in Q14 */
39 static const int16_t kOffset2[8] = {18432, 18379, 18290, 18177, 18052, 17920, 17670,
40 17286};
41
42 static const int16_t kMuteGuardTimeMs = 8000;
43 static const int16_t kInitCheck = 42;
44 static const size_t kNumSubframes = 10;
45
46 /* Default settings if config is not used */
47 #define AGC_DEFAULT_TARGET_LEVEL 3
48 #define AGC_DEFAULT_COMP_GAIN 9
49 /* This is the target level for the analog part in ENV scale. To convert to RMS scale you
50 * have to add OFFSET_ENV_TO_RMS.
51 */
52 #define ANALOG_TARGET_LEVEL 11
53 #define ANALOG_TARGET_LEVEL_2 5 // ANALOG_TARGET_LEVEL / 2
54 /* Offset between RMS scale (analog part) and ENV scale (digital part). This value actually
55 * varies with the FIXED_ANALOG_TARGET_LEVEL, hence we should in the future replace it with
56 * a table.
57 */
58 #define OFFSET_ENV_TO_RMS 9
59 /* The reference input level at which the digital part gives an output of targetLevelDbfs
60 * (desired level) if we have no compression gain. This level should be set high enough not
61 * to compress the peaks due to the dynamics.
62 */
63 #define DIGITAL_REF_AT_0_COMP_GAIN 4
64 /* Speed of reference level decrease.
65 */
66 #define DIFF_REF_TO_ANALOG 5
67
68 #ifdef MIC_LEVEL_FEEDBACK
69 #define NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET 7
70 #endif
71 /* Size of analog gain table */
72 #define GAIN_TBL_LEN 32
73 /* Matlab code:
74 * fprintf(1, '\t%i, %i, %i, %i,\n', round(10.^(linspace(0,10,32)/20) * 2^12));
75 */
76 /* Q12 */
77 static const uint16_t kGainTableAnalog[GAIN_TBL_LEN] = {4096, 4251, 4412, 4579, 4752,
78 4932, 5118, 5312, 5513, 5722, 5938, 6163, 6396, 6638, 6889, 7150, 7420, 7701, 7992,
79 8295, 8609, 8934, 9273, 9623, 9987, 10365, 10758, 11165, 11587, 12025, 12480, 12953};
80
81 /* Gain/Suppression tables for virtual Mic (in Q10) */
82 static const uint16_t kGainTableVirtualMic[128] = {1052, 1081, 1110, 1141, 1172, 1204,
83 1237, 1271, 1305, 1341, 1378, 1416, 1454, 1494, 1535, 1577, 1620, 1664, 1710, 1757,
84 1805, 1854, 1905, 1957, 2010, 2065, 2122, 2180, 2239, 2301, 2364, 2428, 2495, 2563,
85 2633, 2705, 2779, 2855, 2933, 3013, 3096, 3180, 3267, 3357, 3449, 3543, 3640, 3739,
86 3842, 3947, 4055, 4166, 4280, 4397, 4517, 4640, 4767, 4898, 5032, 5169, 5311, 5456,
87 5605, 5758, 5916, 6078, 6244, 6415, 6590, 6770, 6956, 7146, 7341, 7542, 7748, 7960,
88 8178, 8402, 8631, 8867, 9110, 9359, 9615, 9878, 10148, 10426, 10711, 11004, 11305,
89 11614, 11932, 12258, 12593, 12938, 13292, 13655, 14029, 14412, 14807, 15212, 15628,
90 16055, 16494, 16945, 17409, 17885, 18374, 18877, 19393, 19923, 20468, 21028, 21603,
91 22194, 22801, 23425, 24065, 24724, 25400, 26095, 26808, 27541, 28295, 29069, 29864,
92 30681, 31520, 32382};
93 static const uint16_t kSuppressionTableVirtualMic[128] = {1024, 1006, 988, 970, 952,
94 935, 918, 902, 886, 870, 854, 839, 824, 809, 794, 780, 766, 752, 739, 726, 713, 700,
95 687, 675, 663, 651, 639, 628, 616, 605, 594, 584, 573, 563, 553, 543, 533, 524, 514,
96 505, 496, 487, 478, 470, 461, 453, 445, 437, 429, 421, 414, 406, 399, 392, 385, 378,
97 371, 364, 358, 351, 345, 339, 333, 327, 321, 315, 309, 304, 298, 293, 288, 283, 278,
98 273, 268, 263, 258, 254, 249, 244, 240, 236, 232, 227, 223, 219, 215, 211, 208, 204,
99 200, 197, 193, 190, 186, 183, 180, 176, 173, 170, 167, 164, 161, 158, 155, 153, 150,
100 147, 145, 142, 139, 137, 134, 132, 130, 127, 125, 123, 121, 118, 116, 114, 112, 110,
101 108, 106, 104, 102};
102
103 /* Table for target energy levels. Values in Q(-7)
104 * Matlab code
105 * targetLevelTable = fprintf('%d,\t%d,\t%d,\t%d,\n', round((32767*10.^(-(0:63)'/20)).^2*16/2^7) */
106
107 static const int32_t kTargetLevelTable[64] = {134209536, 106606424, 84680493, 67264106,
108 53429779, 42440782, 33711911, 26778323, 21270778, 16895980, 13420954, 10660642,
109 8468049, 6726411, 5342978, 4244078, 3371191, 2677832, 2127078, 1689598, 1342095,
110 1066064, 846805, 672641, 534298, 424408, 337119, 267783, 212708, 168960, 134210,
111 106606, 84680, 67264, 53430, 42441, 33712, 26778, 21271, 16896, 13421, 10661, 8468,
112 6726, 5343, 4244, 3371, 2678, 2127, 1690, 1342, 1066, 847, 673, 534, 424, 337, 268,
113 213, 169, 134, 107, 85, 67};
114
WebRtcAgc_AddMic(void * state,int16_t * const * in_mic,size_t num_bands,size_t samples)115 int WebRtcAgc_AddMic(void *state, int16_t* const* in_mic, size_t num_bands,
116 size_t samples)
117 {
118 int32_t nrg, max_nrg, sample, tmp32;
119 int32_t *ptr;
120 uint16_t targetGainIdx, gain;
121 size_t i;
122 int16_t n, L, tmp16, tmp_speech[16];
123 LegacyAgc* stt;
124 stt = (LegacyAgc*)state;
125
126 if (stt->fs == 8000) {
127 L = 8;
128 if (samples != 80) {
129 return -1;
130 }
131 } else {
132 L = 16;
133 if (samples != 160) {
134 return -1;
135 }
136 }
137
138 /* apply slowly varying digital gain */
139 if (stt->micVol > stt->maxAnalog)
140 {
141 /* |maxLevel| is strictly >= |micVol|, so this condition should be
142 * satisfied here, ensuring there is no divide-by-zero. */
143 assert(stt->maxLevel > stt->maxAnalog);
144
145 /* Q1 */
146 tmp16 = (int16_t)(stt->micVol - stt->maxAnalog);
147 tmp32 = (GAIN_TBL_LEN - 1) * tmp16;
148 tmp16 = (int16_t)(stt->maxLevel - stt->maxAnalog);
149 targetGainIdx = tmp32 / tmp16;
150 assert(targetGainIdx < GAIN_TBL_LEN);
151
152 /* Increment through the table towards the target gain.
153 * If micVol drops below maxAnalog, we allow the gain
154 * to be dropped immediately. */
155 if (stt->gainTableIdx < targetGainIdx)
156 {
157 stt->gainTableIdx++;
158 } else if (stt->gainTableIdx > targetGainIdx)
159 {
160 stt->gainTableIdx--;
161 }
162
163 /* Q12 */
164 gain = kGainTableAnalog[stt->gainTableIdx];
165
166 for (i = 0; i < samples; i++)
167 {
168 size_t j;
169 for (j = 0; j < num_bands; ++j)
170 {
171 sample = (in_mic[j][i] * gain) >> 12;
172 if (sample > 32767)
173 {
174 in_mic[j][i] = 32767;
175 } else if (sample < -32768)
176 {
177 in_mic[j][i] = -32768;
178 } else
179 {
180 in_mic[j][i] = (int16_t)sample;
181 }
182 }
183 }
184 } else
185 {
186 stt->gainTableIdx = 0;
187 }
188
189 /* compute envelope */
190 if (stt->inQueue > 0)
191 {
192 ptr = stt->env[1];
193 } else
194 {
195 ptr = stt->env[0];
196 }
197
198 for (i = 0; i < kNumSubframes; i++)
199 {
200 /* iterate over samples */
201 max_nrg = 0;
202 for (n = 0; n < L; n++)
203 {
204 nrg = in_mic[0][i * L + n] * in_mic[0][i * L + n];
205 if (nrg > max_nrg)
206 {
207 max_nrg = nrg;
208 }
209 }
210 ptr[i] = max_nrg;
211 }
212
213 /* compute energy */
214 if (stt->inQueue > 0)
215 {
216 ptr = stt->Rxx16w32_array[1];
217 } else
218 {
219 ptr = stt->Rxx16w32_array[0];
220 }
221
222 for (i = 0; i < kNumSubframes / 2; i++)
223 {
224 if (stt->fs == 16000)
225 {
226 WebRtcSpl_DownsampleBy2(&in_mic[0][i * 32],
227 32,
228 tmp_speech,
229 stt->filterState);
230 } else
231 {
232 memcpy(tmp_speech, &in_mic[0][i * 16], 16 * sizeof(short));
233 }
234 /* Compute energy in blocks of 16 samples */
235 ptr[i] = WebRtcSpl_DotProductWithScale(tmp_speech, tmp_speech, 16, 4);
236 }
237
238 /* update queue information */
239 if (stt->inQueue == 0)
240 {
241 stt->inQueue = 1;
242 } else
243 {
244 stt->inQueue = 2;
245 }
246
247 /* call VAD (use low band only) */
248 WebRtcAgc_ProcessVad(&stt->vadMic, in_mic[0], samples);
249
250 return 0;
251 }
252
WebRtcAgc_AddFarend(void * state,const int16_t * in_far,size_t samples)253 int WebRtcAgc_AddFarend(void *state, const int16_t *in_far, size_t samples)
254 {
255 LegacyAgc* stt;
256 stt = (LegacyAgc*)state;
257
258 if (stt == NULL)
259 {
260 return -1;
261 }
262
263 if (stt->fs == 8000)
264 {
265 if (samples != 80)
266 {
267 return -1;
268 }
269 } else if (stt->fs == 16000 || stt->fs == 32000 || stt->fs == 48000)
270 {
271 if (samples != 160)
272 {
273 return -1;
274 }
275 } else
276 {
277 return -1;
278 }
279
280 return WebRtcAgc_AddFarendToDigital(&stt->digitalAgc, in_far, samples);
281 }
282
WebRtcAgc_VirtualMic(void * agcInst,int16_t * const * in_near,size_t num_bands,size_t samples,int32_t micLevelIn,int32_t * micLevelOut)283 int WebRtcAgc_VirtualMic(void *agcInst, int16_t* const* in_near,
284 size_t num_bands, size_t samples, int32_t micLevelIn,
285 int32_t *micLevelOut)
286 {
287 int32_t tmpFlt, micLevelTmp, gainIdx;
288 uint16_t gain;
289 size_t ii, j;
290 LegacyAgc* stt;
291
292 uint32_t nrg;
293 size_t sampleCntr;
294 uint32_t frameNrg = 0;
295 uint32_t frameNrgLimit = 5500;
296 int16_t numZeroCrossing = 0;
297 const int16_t kZeroCrossingLowLim = 15;
298 const int16_t kZeroCrossingHighLim = 20;
299
300 stt = (LegacyAgc*)agcInst;
301
302 /*
303 * Before applying gain decide if this is a low-level signal.
304 * The idea is that digital AGC will not adapt to low-level
305 * signals.
306 */
307 if (stt->fs != 8000)
308 {
309 frameNrgLimit = frameNrgLimit << 1;
310 }
311
312 frameNrg = (uint32_t)(in_near[0][0] * in_near[0][0]);
313 for (sampleCntr = 1; sampleCntr < samples; sampleCntr++)
314 {
315
316 // increment frame energy if it is less than the limit
317 // the correct value of the energy is not important
318 if (frameNrg < frameNrgLimit)
319 {
320 nrg = (uint32_t)(in_near[0][sampleCntr] * in_near[0][sampleCntr]);
321 frameNrg += nrg;
322 }
323
324 // Count the zero crossings
325 numZeroCrossing +=
326 ((in_near[0][sampleCntr] ^ in_near[0][sampleCntr - 1]) < 0);
327 }
328
329 if ((frameNrg < 500) || (numZeroCrossing <= 5))
330 {
331 stt->lowLevelSignal = 1;
332 } else if (numZeroCrossing <= kZeroCrossingLowLim)
333 {
334 stt->lowLevelSignal = 0;
335 } else if (frameNrg <= frameNrgLimit)
336 {
337 stt->lowLevelSignal = 1;
338 } else if (numZeroCrossing >= kZeroCrossingHighLim)
339 {
340 stt->lowLevelSignal = 1;
341 } else
342 {
343 stt->lowLevelSignal = 0;
344 }
345
346 micLevelTmp = micLevelIn << stt->scale;
347 /* Set desired level */
348 gainIdx = stt->micVol;
349 if (stt->micVol > stt->maxAnalog)
350 {
351 gainIdx = stt->maxAnalog;
352 }
353 if (micLevelTmp != stt->micRef)
354 {
355 /* Something has happened with the physical level, restart. */
356 stt->micRef = micLevelTmp;
357 stt->micVol = 127;
358 *micLevelOut = 127;
359 stt->micGainIdx = 127;
360 gainIdx = 127;
361 }
362 /* Pre-process the signal to emulate the microphone level. */
363 /* Take one step at a time in the gain table. */
364 if (gainIdx > 127)
365 {
366 gain = kGainTableVirtualMic[gainIdx - 128];
367 } else
368 {
369 gain = kSuppressionTableVirtualMic[127 - gainIdx];
370 }
371 for (ii = 0; ii < samples; ii++)
372 {
373 tmpFlt = (in_near[0][ii] * gain) >> 10;
374 if (tmpFlt > 32767)
375 {
376 tmpFlt = 32767;
377 gainIdx--;
378 if (gainIdx >= 127)
379 {
380 gain = kGainTableVirtualMic[gainIdx - 127];
381 } else
382 {
383 gain = kSuppressionTableVirtualMic[127 - gainIdx];
384 }
385 }
386 if (tmpFlt < -32768)
387 {
388 tmpFlt = -32768;
389 gainIdx--;
390 if (gainIdx >= 127)
391 {
392 gain = kGainTableVirtualMic[gainIdx - 127];
393 } else
394 {
395 gain = kSuppressionTableVirtualMic[127 - gainIdx];
396 }
397 }
398 in_near[0][ii] = (int16_t)tmpFlt;
399 for (j = 1; j < num_bands; ++j)
400 {
401 tmpFlt = (in_near[j][ii] * gain) >> 10;
402 if (tmpFlt > 32767)
403 {
404 tmpFlt = 32767;
405 }
406 if (tmpFlt < -32768)
407 {
408 tmpFlt = -32768;
409 }
410 in_near[j][ii] = (int16_t)tmpFlt;
411 }
412 }
413 /* Set the level we (finally) used */
414 stt->micGainIdx = gainIdx;
415 // *micLevelOut = stt->micGainIdx;
416 *micLevelOut = stt->micGainIdx >> stt->scale;
417 /* Add to Mic as if it was the output from a true microphone */
418 if (WebRtcAgc_AddMic(agcInst, in_near, num_bands, samples) != 0)
419 {
420 return -1;
421 }
422 return 0;
423 }
424
WebRtcAgc_UpdateAgcThresholds(LegacyAgc * stt)425 void WebRtcAgc_UpdateAgcThresholds(LegacyAgc* stt) {
426 int16_t tmp16;
427 #ifdef MIC_LEVEL_FEEDBACK
428 int zeros;
429
430 if (stt->micLvlSat)
431 {
432 /* Lower the analog target level since we have reached its maximum */
433 zeros = WebRtcSpl_NormW32(stt->Rxx160_LPw32);
434 stt->targetIdxOffset = (3 * zeros - stt->targetIdx - 2) / 4;
435 }
436 #endif
437
438 /* Set analog target level in envelope dBOv scale */
439 tmp16 = (DIFF_REF_TO_ANALOG * stt->compressionGaindB) + ANALOG_TARGET_LEVEL_2;
440 tmp16 = WebRtcSpl_DivW32W16ResW16((int32_t)tmp16, ANALOG_TARGET_LEVEL);
441 stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN + tmp16;
442 if (stt->analogTarget < DIGITAL_REF_AT_0_COMP_GAIN)
443 {
444 stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN;
445 }
446 if (stt->agcMode == kAgcModeFixedDigital)
447 {
448 /* Adjust for different parameter interpretation in FixedDigital mode */
449 stt->analogTarget = stt->compressionGaindB;
450 }
451 #ifdef MIC_LEVEL_FEEDBACK
452 stt->analogTarget += stt->targetIdxOffset;
453 #endif
454 /* Since the offset between RMS and ENV is not constant, we should make this into a
455 * table, but for now, we'll stick with a constant, tuned for the chosen analog
456 * target level.
457 */
458 stt->targetIdx = ANALOG_TARGET_LEVEL + OFFSET_ENV_TO_RMS;
459 #ifdef MIC_LEVEL_FEEDBACK
460 stt->targetIdx += stt->targetIdxOffset;
461 #endif
462 /* Analog adaptation limits */
463 /* analogTargetLevel = round((32767*10^(-targetIdx/20))^2*16/2^7) */
464 stt->analogTargetLevel = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx]; /* ex. -20 dBov */
465 stt->startUpperLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 1];/* -19 dBov */
466 stt->startLowerLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 1];/* -21 dBov */
467 stt->upperPrimaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 2];/* -18 dBov */
468 stt->lowerPrimaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 2];/* -22 dBov */
469 stt->upperSecondaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 5];/* -15 dBov */
470 stt->lowerSecondaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 5];/* -25 dBov */
471 stt->upperLimit = stt->startUpperLimit;
472 stt->lowerLimit = stt->startLowerLimit;
473 }
474
WebRtcAgc_SaturationCtrl(LegacyAgc * stt,uint8_t * saturated,int32_t * env)475 void WebRtcAgc_SaturationCtrl(LegacyAgc* stt,
476 uint8_t* saturated,
477 int32_t* env) {
478 int16_t i, tmpW16;
479
480 /* Check if the signal is saturated */
481 for (i = 0; i < 10; i++)
482 {
483 tmpW16 = (int16_t)(env[i] >> 20);
484 if (tmpW16 > 875)
485 {
486 stt->envSum += tmpW16;
487 }
488 }
489
490 if (stt->envSum > 25000)
491 {
492 *saturated = 1;
493 stt->envSum = 0;
494 }
495
496 /* stt->envSum *= 0.99; */
497 stt->envSum = (int16_t)((stt->envSum * 32440) >> 15);
498 }
499
WebRtcAgc_ZeroCtrl(LegacyAgc * stt,int32_t * inMicLevel,int32_t * env)500 void WebRtcAgc_ZeroCtrl(LegacyAgc* stt, int32_t* inMicLevel, int32_t* env) {
501 int16_t i;
502 int32_t tmp32 = 0;
503 int32_t midVal;
504
505 /* Is the input signal zero? */
506 for (i = 0; i < 10; i++)
507 {
508 tmp32 += env[i];
509 }
510
511 /* Each block is allowed to have a few non-zero
512 * samples.
513 */
514 if (tmp32 < 500)
515 {
516 stt->msZero += 10;
517 } else
518 {
519 stt->msZero = 0;
520 }
521
522 if (stt->muteGuardMs > 0)
523 {
524 stt->muteGuardMs -= 10;
525 }
526
527 if (stt->msZero > 500)
528 {
529 stt->msZero = 0;
530
531 /* Increase microphone level only if it's less than 50% */
532 midVal = (stt->maxAnalog + stt->minLevel + 1) / 2;
533 if (*inMicLevel < midVal)
534 {
535 /* *inMicLevel *= 1.1; */
536 *inMicLevel = (1126 * *inMicLevel) >> 10;
537 /* Reduces risk of a muted mic repeatedly triggering excessive levels due
538 * to zero signal detection. */
539 *inMicLevel = WEBRTC_SPL_MIN(*inMicLevel, stt->zeroCtrlMax);
540 stt->micVol = *inMicLevel;
541 }
542
543 #ifdef WEBRTC_AGC_DEBUG_DUMP
544 fprintf(stt->fpt,
545 "\t\tAGC->zeroCntrl, frame %d: 500 ms under threshold,"
546 " micVol: %d\n",
547 stt->fcount,
548 stt->micVol);
549 #endif
550
551 stt->activeSpeech = 0;
552 stt->Rxx16_LPw32Max = 0;
553
554 /* The AGC has a tendency (due to problems with the VAD parameters), to
555 * vastly increase the volume after a muting event. This timer prevents
556 * upwards adaptation for a short period. */
557 stt->muteGuardMs = kMuteGuardTimeMs;
558 }
559 }
560
WebRtcAgc_SpeakerInactiveCtrl(LegacyAgc * stt)561 void WebRtcAgc_SpeakerInactiveCtrl(LegacyAgc* stt) {
562 /* Check if the near end speaker is inactive.
563 * If that is the case the VAD threshold is
564 * increased since the VAD speech model gets
565 * more sensitive to any sound after a long
566 * silence.
567 */
568
569 int32_t tmp32;
570 int16_t vadThresh;
571
572 if (stt->vadMic.stdLongTerm < 2500)
573 {
574 stt->vadThreshold = 1500;
575 } else
576 {
577 vadThresh = kNormalVadThreshold;
578 if (stt->vadMic.stdLongTerm < 4500)
579 {
580 /* Scale between min and max threshold */
581 vadThresh += (4500 - stt->vadMic.stdLongTerm) / 2;
582 }
583
584 /* stt->vadThreshold = (31 * stt->vadThreshold + vadThresh) / 32; */
585 tmp32 = vadThresh + 31 * stt->vadThreshold;
586 stt->vadThreshold = (int16_t)(tmp32 >> 5);
587 }
588 }
589
WebRtcAgc_ExpCurve(int16_t volume,int16_t * index)590 void WebRtcAgc_ExpCurve(int16_t volume, int16_t *index)
591 {
592 // volume in Q14
593 // index in [0-7]
594 /* 8 different curves */
595 if (volume > 5243)
596 {
597 if (volume > 7864)
598 {
599 if (volume > 12124)
600 {
601 *index = 7;
602 } else
603 {
604 *index = 6;
605 }
606 } else
607 {
608 if (volume > 6554)
609 {
610 *index = 5;
611 } else
612 {
613 *index = 4;
614 }
615 }
616 } else
617 {
618 if (volume > 2621)
619 {
620 if (volume > 3932)
621 {
622 *index = 3;
623 } else
624 {
625 *index = 2;
626 }
627 } else
628 {
629 if (volume > 1311)
630 {
631 *index = 1;
632 } else
633 {
634 *index = 0;
635 }
636 }
637 }
638 }
639
WebRtcAgc_ProcessAnalog(void * state,int32_t inMicLevel,int32_t * outMicLevel,int16_t vadLogRatio,int16_t echo,uint8_t * saturationWarning)640 int32_t WebRtcAgc_ProcessAnalog(void *state, int32_t inMicLevel,
641 int32_t *outMicLevel,
642 int16_t vadLogRatio,
643 int16_t echo, uint8_t *saturationWarning)
644 {
645 uint32_t tmpU32;
646 int32_t Rxx16w32, tmp32;
647 int32_t inMicLevelTmp, lastMicVol;
648 int16_t i;
649 uint8_t saturated = 0;
650 LegacyAgc* stt;
651
652 stt = (LegacyAgc*)state;
653 inMicLevelTmp = inMicLevel << stt->scale;
654
655 if (inMicLevelTmp > stt->maxAnalog)
656 {
657 #ifdef WEBRTC_AGC_DEBUG_DUMP
658 fprintf(stt->fpt,
659 "\tAGC->ProcessAnalog, frame %d: micLvl > maxAnalog\n",
660 stt->fcount);
661 #endif
662 return -1;
663 } else if (inMicLevelTmp < stt->minLevel)
664 {
665 #ifdef WEBRTC_AGC_DEBUG_DUMP
666 fprintf(stt->fpt,
667 "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel\n",
668 stt->fcount);
669 #endif
670 return -1;
671 }
672
673 if (stt->firstCall == 0)
674 {
675 int32_t tmpVol;
676 stt->firstCall = 1;
677 tmp32 = ((stt->maxLevel - stt->minLevel) * 51) >> 9;
678 tmpVol = (stt->minLevel + tmp32);
679
680 /* If the mic level is very low at start, increase it! */
681 if ((inMicLevelTmp < tmpVol) && (stt->agcMode == kAgcModeAdaptiveAnalog))
682 {
683 inMicLevelTmp = tmpVol;
684 }
685 stt->micVol = inMicLevelTmp;
686 }
687
688 /* Set the mic level to the previous output value if there is digital input gain */
689 if ((inMicLevelTmp == stt->maxAnalog) && (stt->micVol > stt->maxAnalog))
690 {
691 inMicLevelTmp = stt->micVol;
692 }
693
694 /* If the mic level was manually changed to a very low value raise it! */
695 if ((inMicLevelTmp != stt->micVol) && (inMicLevelTmp < stt->minOutput))
696 {
697 tmp32 = ((stt->maxLevel - stt->minLevel) * 51) >> 9;
698 inMicLevelTmp = (stt->minLevel + tmp32);
699 stt->micVol = inMicLevelTmp;
700 #ifdef MIC_LEVEL_FEEDBACK
701 //stt->numBlocksMicLvlSat = 0;
702 #endif
703 #ifdef WEBRTC_AGC_DEBUG_DUMP
704 fprintf(stt->fpt,
705 "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel by manual"
706 " decrease, raise vol\n",
707 stt->fcount);
708 #endif
709 }
710
711 if (inMicLevelTmp != stt->micVol)
712 {
713 if (inMicLevel == stt->lastInMicLevel) {
714 // We requested a volume adjustment, but it didn't occur. This is
715 // probably due to a coarse quantization of the volume slider.
716 // Restore the requested value to prevent getting stuck.
717 inMicLevelTmp = stt->micVol;
718 }
719 else {
720 // As long as the value changed, update to match.
721 stt->micVol = inMicLevelTmp;
722 }
723 }
724
725 if (inMicLevelTmp > stt->maxLevel)
726 {
727 // Always allow the user to raise the volume above the maxLevel.
728 stt->maxLevel = inMicLevelTmp;
729 }
730
731 // Store last value here, after we've taken care of manual updates etc.
732 stt->lastInMicLevel = inMicLevel;
733 lastMicVol = stt->micVol;
734
735 /* Checks if the signal is saturated. Also a check if individual samples
736 * are larger than 12000 is done. If they are the counter for increasing
737 * the volume level is set to -100ms
738 */
739 WebRtcAgc_SaturationCtrl(stt, &saturated, stt->env[0]);
740
741 /* The AGC is always allowed to lower the level if the signal is saturated */
742 if (saturated == 1)
743 {
744 /* Lower the recording level
745 * Rxx160_LP is adjusted down because it is so slow it could
746 * cause the AGC to make wrong decisions. */
747 /* stt->Rxx160_LPw32 *= 0.875; */
748 stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 8) * 7;
749
750 stt->zeroCtrlMax = stt->micVol;
751
752 /* stt->micVol *= 0.903; */
753 tmp32 = inMicLevelTmp - stt->minLevel;
754 tmpU32 = WEBRTC_SPL_UMUL(29591, (uint32_t)(tmp32));
755 stt->micVol = (tmpU32 >> 15) + stt->minLevel;
756 if (stt->micVol > lastMicVol - 2)
757 {
758 stt->micVol = lastMicVol - 2;
759 }
760 inMicLevelTmp = stt->micVol;
761
762 #ifdef WEBRTC_AGC_DEBUG_DUMP
763 fprintf(stt->fpt,
764 "\tAGC->ProcessAnalog, frame %d: saturated, micVol = %d\n",
765 stt->fcount,
766 stt->micVol);
767 #endif
768
769 if (stt->micVol < stt->minOutput)
770 {
771 *saturationWarning = 1;
772 }
773
774 /* Reset counter for decrease of volume level to avoid
775 * decreasing too much. The saturation control can still
776 * lower the level if needed. */
777 stt->msTooHigh = -100;
778
779 /* Enable the control mechanism to ensure that our measure,
780 * Rxx160_LP, is in the correct range. This must be done since
781 * the measure is very slow. */
782 stt->activeSpeech = 0;
783 stt->Rxx16_LPw32Max = 0;
784
785 /* Reset to initial values */
786 stt->msecSpeechInnerChange = kMsecSpeechInner;
787 stt->msecSpeechOuterChange = kMsecSpeechOuter;
788 stt->changeToSlowMode = 0;
789
790 stt->muteGuardMs = 0;
791
792 stt->upperLimit = stt->startUpperLimit;
793 stt->lowerLimit = stt->startLowerLimit;
794 #ifdef MIC_LEVEL_FEEDBACK
795 //stt->numBlocksMicLvlSat = 0;
796 #endif
797 }
798
799 /* Check if the input speech is zero. If so the mic volume
800 * is increased. On some computers the input is zero up as high
801 * level as 17% */
802 WebRtcAgc_ZeroCtrl(stt, &inMicLevelTmp, stt->env[0]);
803
804 /* Check if the near end speaker is inactive.
805 * If that is the case the VAD threshold is
806 * increased since the VAD speech model gets
807 * more sensitive to any sound after a long
808 * silence.
809 */
810 WebRtcAgc_SpeakerInactiveCtrl(stt);
811
812 for (i = 0; i < 5; i++)
813 {
814 /* Computed on blocks of 16 samples */
815
816 Rxx16w32 = stt->Rxx16w32_array[0][i];
817
818 /* Rxx160w32 in Q(-7) */
819 tmp32 = (Rxx16w32 - stt->Rxx16_vectorw32[stt->Rxx16pos]) >> 3;
820 stt->Rxx160w32 = stt->Rxx160w32 + tmp32;
821 stt->Rxx16_vectorw32[stt->Rxx16pos] = Rxx16w32;
822
823 /* Circular buffer */
824 stt->Rxx16pos++;
825 if (stt->Rxx16pos == RXX_BUFFER_LEN)
826 {
827 stt->Rxx16pos = 0;
828 }
829
830 /* Rxx16_LPw32 in Q(-4) */
831 tmp32 = (Rxx16w32 - stt->Rxx16_LPw32) >> kAlphaShortTerm;
832 stt->Rxx16_LPw32 = (stt->Rxx16_LPw32) + tmp32;
833
834 if (vadLogRatio > stt->vadThreshold)
835 {
836 /* Speech detected! */
837
838 /* Check if Rxx160_LP is in the correct range. If
839 * it is too high/low then we set it to the maximum of
840 * Rxx16_LPw32 during the first 200ms of speech.
841 */
842 if (stt->activeSpeech < 250)
843 {
844 stt->activeSpeech += 2;
845
846 if (stt->Rxx16_LPw32 > stt->Rxx16_LPw32Max)
847 {
848 stt->Rxx16_LPw32Max = stt->Rxx16_LPw32;
849 }
850 } else if (stt->activeSpeech == 250)
851 {
852 stt->activeSpeech += 2;
853 tmp32 = stt->Rxx16_LPw32Max >> 3;
854 stt->Rxx160_LPw32 = tmp32 * RXX_BUFFER_LEN;
855 }
856
857 tmp32 = (stt->Rxx160w32 - stt->Rxx160_LPw32) >> kAlphaLongTerm;
858 stt->Rxx160_LPw32 = stt->Rxx160_LPw32 + tmp32;
859
860 if (stt->Rxx160_LPw32 > stt->upperSecondaryLimit)
861 {
862 stt->msTooHigh += 2;
863 stt->msTooLow = 0;
864 stt->changeToSlowMode = 0;
865
866 if (stt->msTooHigh > stt->msecSpeechOuterChange)
867 {
868 stt->msTooHigh = 0;
869
870 /* Lower the recording level */
871 /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
872 tmp32 = stt->Rxx160_LPw32 >> 6;
873 stt->Rxx160_LPw32 = tmp32 * 53;
874
875 /* Reduce the max gain to avoid excessive oscillation
876 * (but never drop below the maximum analog level).
877 */
878 stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
879 stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
880
881 stt->zeroCtrlMax = stt->micVol;
882
883 /* 0.95 in Q15 */
884 tmp32 = inMicLevelTmp - stt->minLevel;
885 tmpU32 = WEBRTC_SPL_UMUL(31130, (uint32_t)(tmp32));
886 stt->micVol = (tmpU32 >> 15) + stt->minLevel;
887 if (stt->micVol > lastMicVol - 1)
888 {
889 stt->micVol = lastMicVol - 1;
890 }
891 inMicLevelTmp = stt->micVol;
892
893 /* Enable the control mechanism to ensure that our measure,
894 * Rxx160_LP, is in the correct range.
895 */
896 stt->activeSpeech = 0;
897 stt->Rxx16_LPw32Max = 0;
898 #ifdef MIC_LEVEL_FEEDBACK
899 //stt->numBlocksMicLvlSat = 0;
900 #endif
901 #ifdef WEBRTC_AGC_DEBUG_DUMP
902 fprintf(stt->fpt,
903 "\tAGC->ProcessAnalog, frame %d: measure >"
904 " 2ndUpperLim, micVol = %d, maxLevel = %d\n",
905 stt->fcount,
906 stt->micVol,
907 stt->maxLevel);
908 #endif
909 }
910 } else if (stt->Rxx160_LPw32 > stt->upperLimit)
911 {
912 stt->msTooHigh += 2;
913 stt->msTooLow = 0;
914 stt->changeToSlowMode = 0;
915
916 if (stt->msTooHigh > stt->msecSpeechInnerChange)
917 {
918 /* Lower the recording level */
919 stt->msTooHigh = 0;
920 /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
921 stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 53;
922
923 /* Reduce the max gain to avoid excessive oscillation
924 * (but never drop below the maximum analog level).
925 */
926 stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
927 stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
928
929 stt->zeroCtrlMax = stt->micVol;
930
931 /* 0.965 in Q15 */
932 tmp32 = inMicLevelTmp - stt->minLevel;
933 tmpU32 = WEBRTC_SPL_UMUL(31621, (uint32_t)(inMicLevelTmp - stt->minLevel));
934 stt->micVol = (tmpU32 >> 15) + stt->minLevel;
935 if (stt->micVol > lastMicVol - 1)
936 {
937 stt->micVol = lastMicVol - 1;
938 }
939 inMicLevelTmp = stt->micVol;
940
941 #ifdef MIC_LEVEL_FEEDBACK
942 //stt->numBlocksMicLvlSat = 0;
943 #endif
944 #ifdef WEBRTC_AGC_DEBUG_DUMP
945 fprintf(stt->fpt,
946 "\tAGC->ProcessAnalog, frame %d: measure >"
947 " UpperLim, micVol = %d, maxLevel = %d\n",
948 stt->fcount,
949 stt->micVol,
950 stt->maxLevel);
951 #endif
952 }
953 } else if (stt->Rxx160_LPw32 < stt->lowerSecondaryLimit)
954 {
955 stt->msTooHigh = 0;
956 stt->changeToSlowMode = 0;
957 stt->msTooLow += 2;
958
959 if (stt->msTooLow > stt->msecSpeechOuterChange)
960 {
961 /* Raise the recording level */
962 int16_t index, weightFIX;
963 int16_t volNormFIX = 16384; // =1 in Q14.
964
965 stt->msTooLow = 0;
966
967 /* Normalize the volume level */
968 tmp32 = (inMicLevelTmp - stt->minLevel) << 14;
969 if (stt->maxInit != stt->minLevel)
970 {
971 volNormFIX = tmp32 / (stt->maxInit - stt->minLevel);
972 }
973
974 /* Find correct curve */
975 WebRtcAgc_ExpCurve(volNormFIX, &index);
976
977 /* Compute weighting factor for the volume increase, 32^(-2*X)/2+1.05 */
978 weightFIX = kOffset1[index] -
979 (int16_t)((kSlope1[index] * volNormFIX) >> 13);
980
981 /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
982 stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 67;
983
984 tmp32 = inMicLevelTmp - stt->minLevel;
985 tmpU32 = ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
986 stt->micVol = (tmpU32 >> 14) + stt->minLevel;
987 if (stt->micVol < lastMicVol + 2)
988 {
989 stt->micVol = lastMicVol + 2;
990 }
991
992 inMicLevelTmp = stt->micVol;
993
994 #ifdef MIC_LEVEL_FEEDBACK
995 /* Count ms in level saturation */
996 //if (stt->micVol > stt->maxAnalog) {
997 if (stt->micVol > 150)
998 {
999 /* mic level is saturated */
1000 stt->numBlocksMicLvlSat++;
1001 fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
1002 }
1003 #endif
1004 #ifdef WEBRTC_AGC_DEBUG_DUMP
1005 fprintf(stt->fpt,
1006 "\tAGC->ProcessAnalog, frame %d: measure <"
1007 " 2ndLowerLim, micVol = %d\n",
1008 stt->fcount,
1009 stt->micVol);
1010 #endif
1011 }
1012 } else if (stt->Rxx160_LPw32 < stt->lowerLimit)
1013 {
1014 stt->msTooHigh = 0;
1015 stt->changeToSlowMode = 0;
1016 stt->msTooLow += 2;
1017
1018 if (stt->msTooLow > stt->msecSpeechInnerChange)
1019 {
1020 /* Raise the recording level */
1021 int16_t index, weightFIX;
1022 int16_t volNormFIX = 16384; // =1 in Q14.
1023
1024 stt->msTooLow = 0;
1025
1026 /* Normalize the volume level */
1027 tmp32 = (inMicLevelTmp - stt->minLevel) << 14;
1028 if (stt->maxInit != stt->minLevel)
1029 {
1030 volNormFIX = tmp32 / (stt->maxInit - stt->minLevel);
1031 }
1032
1033 /* Find correct curve */
1034 WebRtcAgc_ExpCurve(volNormFIX, &index);
1035
1036 /* Compute weighting factor for the volume increase, (3.^(-2.*X))/8+1 */
1037 weightFIX = kOffset2[index] -
1038 (int16_t)((kSlope2[index] * volNormFIX) >> 13);
1039
1040 /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
1041 stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 67;
1042
1043 tmp32 = inMicLevelTmp - stt->minLevel;
1044 tmpU32 = ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
1045 stt->micVol = (tmpU32 >> 14) + stt->minLevel;
1046 if (stt->micVol < lastMicVol + 1)
1047 {
1048 stt->micVol = lastMicVol + 1;
1049 }
1050
1051 inMicLevelTmp = stt->micVol;
1052
1053 #ifdef MIC_LEVEL_FEEDBACK
1054 /* Count ms in level saturation */
1055 //if (stt->micVol > stt->maxAnalog) {
1056 if (stt->micVol > 150)
1057 {
1058 /* mic level is saturated */
1059 stt->numBlocksMicLvlSat++;
1060 fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
1061 }
1062 #endif
1063 #ifdef WEBRTC_AGC_DEBUG_DUMP
1064 fprintf(stt->fpt,
1065 "\tAGC->ProcessAnalog, frame %d: measure < LowerLim, micVol = %d\n",
1066 stt->fcount,
1067 stt->micVol);
1068 #endif
1069
1070 }
1071 } else
1072 {
1073 /* The signal is inside the desired range which is:
1074 * lowerLimit < Rxx160_LP/640 < upperLimit
1075 */
1076 if (stt->changeToSlowMode > 4000)
1077 {
1078 stt->msecSpeechInnerChange = 1000;
1079 stt->msecSpeechOuterChange = 500;
1080 stt->upperLimit = stt->upperPrimaryLimit;
1081 stt->lowerLimit = stt->lowerPrimaryLimit;
1082 } else
1083 {
1084 stt->changeToSlowMode += 2; // in milliseconds
1085 }
1086 stt->msTooLow = 0;
1087 stt->msTooHigh = 0;
1088
1089 stt->micVol = inMicLevelTmp;
1090
1091 }
1092 #ifdef MIC_LEVEL_FEEDBACK
1093 if (stt->numBlocksMicLvlSat > NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET)
1094 {
1095 stt->micLvlSat = 1;
1096 fprintf(stderr, "target before = %d (%d)\n", stt->analogTargetLevel, stt->targetIdx);
1097 WebRtcAgc_UpdateAgcThresholds(stt);
1098 WebRtcAgc_CalculateGainTable(&(stt->digitalAgc.gainTable[0]),
1099 stt->compressionGaindB, stt->targetLevelDbfs, stt->limiterEnable,
1100 stt->analogTarget);
1101 stt->numBlocksMicLvlSat = 0;
1102 stt->micLvlSat = 0;
1103 fprintf(stderr, "target offset = %d\n", stt->targetIdxOffset);
1104 fprintf(stderr, "target after = %d (%d)\n", stt->analogTargetLevel, stt->targetIdx);
1105 }
1106 #endif
1107 }
1108 }
1109
1110 /* Ensure gain is not increased in presence of echo or after a mute event
1111 * (but allow the zeroCtrl() increase on the frame of a mute detection).
1112 */
1113 if (echo == 1 || (stt->muteGuardMs > 0 && stt->muteGuardMs < kMuteGuardTimeMs))
1114 {
1115 if (stt->micVol > lastMicVol)
1116 {
1117 stt->micVol = lastMicVol;
1118 }
1119 }
1120
1121 /* limit the gain */
1122 if (stt->micVol > stt->maxLevel)
1123 {
1124 stt->micVol = stt->maxLevel;
1125 } else if (stt->micVol < stt->minOutput)
1126 {
1127 stt->micVol = stt->minOutput;
1128 }
1129
1130 *outMicLevel = WEBRTC_SPL_MIN(stt->micVol, stt->maxAnalog) >> stt->scale;
1131
1132 return 0;
1133 }
1134
WebRtcAgc_Process(void * agcInst,const int16_t * const * in_near,size_t num_bands,size_t samples,int16_t * const * out,int32_t inMicLevel,int32_t * outMicLevel,int16_t echo,uint8_t * saturationWarning)1135 int WebRtcAgc_Process(void *agcInst, const int16_t* const* in_near,
1136 size_t num_bands, size_t samples,
1137 int16_t* const* out, int32_t inMicLevel,
1138 int32_t *outMicLevel, int16_t echo,
1139 uint8_t *saturationWarning)
1140 {
1141 LegacyAgc* stt;
1142
1143 stt = (LegacyAgc*)agcInst;
1144
1145 //
1146 if (stt == NULL)
1147 {
1148 return -1;
1149 }
1150 //
1151
1152
1153 if (stt->fs == 8000)
1154 {
1155 if (samples != 80)
1156 {
1157 return -1;
1158 }
1159 } else if (stt->fs == 16000 || stt->fs == 32000 || stt->fs == 48000)
1160 {
1161 if (samples != 160)
1162 {
1163 return -1;
1164 }
1165 } else
1166 {
1167 return -1;
1168 }
1169
1170 *saturationWarning = 0;
1171 //TODO: PUT IN RANGE CHECKING FOR INPUT LEVELS
1172 *outMicLevel = inMicLevel;
1173
1174 #ifdef WEBRTC_AGC_DEBUG_DUMP
1175 stt->fcount++;
1176 #endif
1177
1178 if (WebRtcAgc_ProcessDigital(&stt->digitalAgc,
1179 in_near,
1180 num_bands,
1181 out,
1182 stt->fs,
1183 stt->lowLevelSignal) == -1)
1184 {
1185 #ifdef WEBRTC_AGC_DEBUG_DUMP
1186 fprintf(stt->fpt,
1187 "AGC->Process, frame %d: Error from DigAGC\n\n",
1188 stt->fcount);
1189 #endif
1190 return -1;
1191 }
1192 if (stt->agcMode < kAgcModeFixedDigital &&
1193 (stt->lowLevelSignal == 0 || stt->agcMode != kAgcModeAdaptiveDigital))
1194 {
1195 if (WebRtcAgc_ProcessAnalog(agcInst,
1196 inMicLevel,
1197 outMicLevel,
1198 stt->vadMic.logRatio,
1199 echo,
1200 saturationWarning) == -1)
1201 {
1202 return -1;
1203 }
1204 }
1205 #ifdef WEBRTC_AGC_DEBUG_DUMP
1206 fprintf(stt->agcLog,
1207 "%5d\t%d\t%d\t%d\t%d\n",
1208 stt->fcount,
1209 inMicLevel,
1210 *outMicLevel,
1211 stt->maxLevel,
1212 stt->micVol);
1213 #endif
1214
1215 /* update queue */
1216 if (stt->inQueue > 1)
1217 {
1218 memcpy(stt->env[0], stt->env[1], 10 * sizeof(int32_t));
1219 memcpy(stt->Rxx16w32_array[0],
1220 stt->Rxx16w32_array[1],
1221 5 * sizeof(int32_t));
1222 }
1223
1224 if (stt->inQueue > 0)
1225 {
1226 stt->inQueue--;
1227 }
1228
1229 return 0;
1230 }
1231
WebRtcAgc_set_config(void * agcInst,WebRtcAgcConfig agcConfig)1232 int WebRtcAgc_set_config(void* agcInst, WebRtcAgcConfig agcConfig) {
1233 LegacyAgc* stt;
1234 stt = (LegacyAgc*)agcInst;
1235
1236 if (stt == NULL)
1237 {
1238 return -1;
1239 }
1240
1241 if (stt->initFlag != kInitCheck)
1242 {
1243 stt->lastError = AGC_UNINITIALIZED_ERROR;
1244 return -1;
1245 }
1246
1247 if (agcConfig.limiterEnable != kAgcFalse && agcConfig.limiterEnable != kAgcTrue)
1248 {
1249 stt->lastError = AGC_BAD_PARAMETER_ERROR;
1250 return -1;
1251 }
1252 stt->limiterEnable = agcConfig.limiterEnable;
1253 stt->compressionGaindB = agcConfig.compressionGaindB;
1254 if ((agcConfig.targetLevelDbfs < 0) || (agcConfig.targetLevelDbfs > 31))
1255 {
1256 stt->lastError = AGC_BAD_PARAMETER_ERROR;
1257 return -1;
1258 }
1259 stt->targetLevelDbfs = agcConfig.targetLevelDbfs;
1260
1261 if (stt->agcMode == kAgcModeFixedDigital)
1262 {
1263 /* Adjust for different parameter interpretation in FixedDigital mode */
1264 stt->compressionGaindB += agcConfig.targetLevelDbfs;
1265 }
1266
1267 /* Update threshold levels for analog adaptation */
1268 WebRtcAgc_UpdateAgcThresholds(stt);
1269
1270 /* Recalculate gain table */
1271 if (WebRtcAgc_CalculateGainTable(&(stt->digitalAgc.gainTable[0]), stt->compressionGaindB,
1272 stt->targetLevelDbfs, stt->limiterEnable, stt->analogTarget) == -1)
1273 {
1274 #ifdef WEBRTC_AGC_DEBUG_DUMP
1275 fprintf(stt->fpt,
1276 "AGC->set_config, frame %d: Error from calcGainTable\n\n",
1277 stt->fcount);
1278 #endif
1279 return -1;
1280 }
1281 /* Store the config in a WebRtcAgcConfig */
1282 stt->usedConfig.compressionGaindB = agcConfig.compressionGaindB;
1283 stt->usedConfig.limiterEnable = agcConfig.limiterEnable;
1284 stt->usedConfig.targetLevelDbfs = agcConfig.targetLevelDbfs;
1285
1286 return 0;
1287 }
1288
WebRtcAgc_get_config(void * agcInst,WebRtcAgcConfig * config)1289 int WebRtcAgc_get_config(void* agcInst, WebRtcAgcConfig* config) {
1290 LegacyAgc* stt;
1291 stt = (LegacyAgc*)agcInst;
1292
1293 if (stt == NULL)
1294 {
1295 return -1;
1296 }
1297
1298 if (config == NULL)
1299 {
1300 stt->lastError = AGC_NULL_POINTER_ERROR;
1301 return -1;
1302 }
1303
1304 if (stt->initFlag != kInitCheck)
1305 {
1306 stt->lastError = AGC_UNINITIALIZED_ERROR;
1307 return -1;
1308 }
1309
1310 config->limiterEnable = stt->usedConfig.limiterEnable;
1311 config->targetLevelDbfs = stt->usedConfig.targetLevelDbfs;
1312 config->compressionGaindB = stt->usedConfig.compressionGaindB;
1313
1314 return 0;
1315 }
1316
WebRtcAgc_Create()1317 void* WebRtcAgc_Create() {
1318 LegacyAgc* stt = malloc(sizeof(LegacyAgc));
1319
1320 #ifdef WEBRTC_AGC_DEBUG_DUMP
1321 stt->fpt = fopen("./agc_test_log.txt", "wt");
1322 stt->agcLog = fopen("./agc_debug_log.txt", "wt");
1323 stt->digitalAgc.logFile = fopen("./agc_log.txt", "wt");
1324 #endif
1325
1326 stt->initFlag = 0;
1327 stt->lastError = 0;
1328
1329 return stt;
1330 }
1331
WebRtcAgc_Free(void * state)1332 void WebRtcAgc_Free(void *state) {
1333 LegacyAgc* stt;
1334
1335 stt = (LegacyAgc*)state;
1336 #ifdef WEBRTC_AGC_DEBUG_DUMP
1337 fclose(stt->fpt);
1338 fclose(stt->agcLog);
1339 fclose(stt->digitalAgc.logFile);
1340 #endif
1341 free(stt);
1342 }
1343
1344 /* minLevel - Minimum volume level
1345 * maxLevel - Maximum volume level
1346 */
WebRtcAgc_Init(void * agcInst,int32_t minLevel,int32_t maxLevel,int16_t agcMode,uint32_t fs)1347 int WebRtcAgc_Init(void *agcInst, int32_t minLevel, int32_t maxLevel,
1348 int16_t agcMode, uint32_t fs)
1349 {
1350 int32_t max_add, tmp32;
1351 int16_t i;
1352 int tmpNorm;
1353 LegacyAgc* stt;
1354
1355 /* typecast state pointer */
1356 stt = (LegacyAgc*)agcInst;
1357
1358 if (WebRtcAgc_InitDigital(&stt->digitalAgc, agcMode) != 0)
1359 {
1360 stt->lastError = AGC_UNINITIALIZED_ERROR;
1361 return -1;
1362 }
1363
1364 /* Analog AGC variables */
1365 stt->envSum = 0;
1366
1367 /* mode = 0 - Only saturation protection
1368 * 1 - Analog Automatic Gain Control [-targetLevelDbfs (default -3 dBOv)]
1369 * 2 - Digital Automatic Gain Control [-targetLevelDbfs (default -3 dBOv)]
1370 * 3 - Fixed Digital Gain [compressionGaindB (default 8 dB)]
1371 */
1372 #ifdef WEBRTC_AGC_DEBUG_DUMP
1373 stt->fcount = 0;
1374 fprintf(stt->fpt, "AGC->Init\n");
1375 #endif
1376 if (agcMode < kAgcModeUnchanged || agcMode > kAgcModeFixedDigital)
1377 {
1378 #ifdef WEBRTC_AGC_DEBUG_DUMP
1379 fprintf(stt->fpt, "AGC->Init: error, incorrect mode\n\n");
1380 #endif
1381 return -1;
1382 }
1383 stt->agcMode = agcMode;
1384 stt->fs = fs;
1385
1386 /* initialize input VAD */
1387 WebRtcAgc_InitVad(&stt->vadMic);
1388
1389 /* If the volume range is smaller than 0-256 then
1390 * the levels are shifted up to Q8-domain */
1391 tmpNorm = WebRtcSpl_NormU32((uint32_t)maxLevel);
1392 stt->scale = tmpNorm - 23;
1393 if (stt->scale < 0)
1394 {
1395 stt->scale = 0;
1396 }
1397 // TODO(bjornv): Investigate if we really need to scale up a small range now when we have
1398 // a guard against zero-increments. For now, we do not support scale up (scale = 0).
1399 stt->scale = 0;
1400 maxLevel <<= stt->scale;
1401 minLevel <<= stt->scale;
1402
1403 /* Make minLevel and maxLevel static in AdaptiveDigital */
1404 if (stt->agcMode == kAgcModeAdaptiveDigital)
1405 {
1406 minLevel = 0;
1407 maxLevel = 255;
1408 stt->scale = 0;
1409 }
1410 /* The maximum supplemental volume range is based on a vague idea
1411 * of how much lower the gain will be than the real analog gain. */
1412 max_add = (maxLevel - minLevel) / 4;
1413
1414 /* Minimum/maximum volume level that can be set */
1415 stt->minLevel = minLevel;
1416 stt->maxAnalog = maxLevel;
1417 stt->maxLevel = maxLevel + max_add;
1418 stt->maxInit = stt->maxLevel;
1419
1420 stt->zeroCtrlMax = stt->maxAnalog;
1421 stt->lastInMicLevel = 0;
1422
1423 /* Initialize micVol parameter */
1424 stt->micVol = stt->maxAnalog;
1425 if (stt->agcMode == kAgcModeAdaptiveDigital)
1426 {
1427 stt->micVol = 127; /* Mid-point of mic level */
1428 }
1429 stt->micRef = stt->micVol;
1430 stt->micGainIdx = 127;
1431 #ifdef MIC_LEVEL_FEEDBACK
1432 stt->numBlocksMicLvlSat = 0;
1433 stt->micLvlSat = 0;
1434 #endif
1435 #ifdef WEBRTC_AGC_DEBUG_DUMP
1436 fprintf(stt->fpt,
1437 "AGC->Init: minLevel = %d, maxAnalog = %d, maxLevel = %d\n",
1438 stt->minLevel,
1439 stt->maxAnalog,
1440 stt->maxLevel);
1441 #endif
1442
1443 /* Minimum output volume is 4% higher than the available lowest volume level */
1444 tmp32 = ((stt->maxLevel - stt->minLevel) * 10) >> 8;
1445 stt->minOutput = (stt->minLevel + tmp32);
1446
1447 stt->msTooLow = 0;
1448 stt->msTooHigh = 0;
1449 stt->changeToSlowMode = 0;
1450 stt->firstCall = 0;
1451 stt->msZero = 0;
1452 stt->muteGuardMs = 0;
1453 stt->gainTableIdx = 0;
1454
1455 stt->msecSpeechInnerChange = kMsecSpeechInner;
1456 stt->msecSpeechOuterChange = kMsecSpeechOuter;
1457
1458 stt->activeSpeech = 0;
1459 stt->Rxx16_LPw32Max = 0;
1460
1461 stt->vadThreshold = kNormalVadThreshold;
1462 stt->inActive = 0;
1463
1464 for (i = 0; i < RXX_BUFFER_LEN; i++)
1465 {
1466 stt->Rxx16_vectorw32[i] = (int32_t)1000; /* -54dBm0 */
1467 }
1468 stt->Rxx160w32 = 125 * RXX_BUFFER_LEN; /* (stt->Rxx16_vectorw32[0]>>3) = 125 */
1469
1470 stt->Rxx16pos = 0;
1471 stt->Rxx16_LPw32 = (int32_t)16284; /* Q(-4) */
1472
1473 for (i = 0; i < 5; i++)
1474 {
1475 stt->Rxx16w32_array[0][i] = 0;
1476 }
1477 for (i = 0; i < 10; i++)
1478 {
1479 stt->env[0][i] = 0;
1480 stt->env[1][i] = 0;
1481 }
1482 stt->inQueue = 0;
1483
1484 #ifdef MIC_LEVEL_FEEDBACK
1485 stt->targetIdxOffset = 0;
1486 #endif
1487
1488 WebRtcSpl_MemSetW32(stt->filterState, 0, 8);
1489
1490 stt->initFlag = kInitCheck;
1491 // Default config settings.
1492 stt->defaultConfig.limiterEnable = kAgcTrue;
1493 stt->defaultConfig.targetLevelDbfs = AGC_DEFAULT_TARGET_LEVEL;
1494 stt->defaultConfig.compressionGaindB = AGC_DEFAULT_COMP_GAIN;
1495
1496 if (WebRtcAgc_set_config(stt, stt->defaultConfig) == -1)
1497 {
1498 stt->lastError = AGC_UNSPECIFIED_ERROR;
1499 return -1;
1500 }
1501 stt->Rxx160_LPw32 = stt->analogTargetLevel; // Initialize rms value
1502
1503 stt->lowLevelSignal = 0;
1504
1505 /* Only positive values are allowed that are not too large */
1506 if ((minLevel >= maxLevel) || (maxLevel & 0xFC000000))
1507 {
1508 #ifdef WEBRTC_AGC_DEBUG_DUMP
1509 fprintf(stt->fpt, "minLevel, maxLevel value(s) are invalid\n\n");
1510 #endif
1511 return -1;
1512 } else
1513 {
1514 #ifdef WEBRTC_AGC_DEBUG_DUMP
1515 fprintf(stt->fpt, "\n");
1516 #endif
1517 return 0;
1518 }
1519 }
1520