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