• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   LegacyAgc* stt = (LegacyAgc*)state;
255 
256     int err =  WebRtcAgc_GetAddFarendError(state, samples);
257 
258     if (err != 0)
259       return err;
260 
261     return WebRtcAgc_AddFarendToDigital(&stt->digitalAgc, in_far, samples);
262 }
263 
WebRtcAgc_GetAddFarendError(void * state,size_t samples)264 int WebRtcAgc_GetAddFarendError(void *state, size_t samples) {
265   LegacyAgc* stt;
266   stt = (LegacyAgc*)state;
267 
268   if (stt == NULL)
269     return -1;
270 
271   if (stt->fs == 8000) {
272     if (samples != 80)
273       return -1;
274   } else if (stt->fs == 16000 || stt->fs == 32000 || stt->fs == 48000) {
275     if (samples != 160)
276       return -1;
277   } else {
278     return -1;
279   }
280 
281   return 0;
282 }
283 
WebRtcAgc_VirtualMic(void * agcInst,int16_t * const * in_near,size_t num_bands,size_t samples,int32_t micLevelIn,int32_t * micLevelOut)284 int WebRtcAgc_VirtualMic(void *agcInst, int16_t* const* in_near,
285                          size_t num_bands, size_t samples, int32_t micLevelIn,
286                          int32_t *micLevelOut)
287 {
288     int32_t tmpFlt, micLevelTmp, gainIdx;
289     uint16_t gain;
290     size_t ii, j;
291     LegacyAgc* stt;
292 
293     uint32_t nrg;
294     size_t sampleCntr;
295     uint32_t frameNrg = 0;
296     uint32_t frameNrgLimit = 5500;
297     int16_t numZeroCrossing = 0;
298     const int16_t kZeroCrossingLowLim = 15;
299     const int16_t kZeroCrossingHighLim = 20;
300 
301     stt = (LegacyAgc*)agcInst;
302 
303     /*
304      *  Before applying gain decide if this is a low-level signal.
305      *  The idea is that digital AGC will not adapt to low-level
306      *  signals.
307      */
308     if (stt->fs != 8000)
309     {
310         frameNrgLimit = frameNrgLimit << 1;
311     }
312 
313     frameNrg = (uint32_t)(in_near[0][0] * in_near[0][0]);
314     for (sampleCntr = 1; sampleCntr < samples; sampleCntr++)
315     {
316 
317         // increment frame energy if it is less than the limit
318         // the correct value of the energy is not important
319         if (frameNrg < frameNrgLimit)
320         {
321           nrg = (uint32_t)(in_near[0][sampleCntr] * in_near[0][sampleCntr]);
322           frameNrg += nrg;
323         }
324 
325         // Count the zero crossings
326         numZeroCrossing +=
327                 ((in_near[0][sampleCntr] ^ in_near[0][sampleCntr - 1]) < 0);
328     }
329 
330     if ((frameNrg < 500) || (numZeroCrossing <= 5))
331     {
332         stt->lowLevelSignal = 1;
333     } else if (numZeroCrossing <= kZeroCrossingLowLim)
334     {
335         stt->lowLevelSignal = 0;
336     } else if (frameNrg <= frameNrgLimit)
337     {
338         stt->lowLevelSignal = 1;
339     } else if (numZeroCrossing >= kZeroCrossingHighLim)
340     {
341         stt->lowLevelSignal = 1;
342     } else
343     {
344         stt->lowLevelSignal = 0;
345     }
346 
347     micLevelTmp = micLevelIn << stt->scale;
348     /* Set desired level */
349     gainIdx = stt->micVol;
350     if (stt->micVol > stt->maxAnalog)
351     {
352         gainIdx = stt->maxAnalog;
353     }
354     if (micLevelTmp != stt->micRef)
355     {
356         /* Something has happened with the physical level, restart. */
357         stt->micRef = micLevelTmp;
358         stt->micVol = 127;
359         *micLevelOut = 127;
360         stt->micGainIdx = 127;
361         gainIdx = 127;
362     }
363     /* Pre-process the signal to emulate the microphone level. */
364     /* Take one step at a time in the gain table. */
365     if (gainIdx > 127)
366     {
367         gain = kGainTableVirtualMic[gainIdx - 128];
368     } else
369     {
370         gain = kSuppressionTableVirtualMic[127 - gainIdx];
371     }
372     for (ii = 0; ii < samples; ii++)
373     {
374         tmpFlt = (in_near[0][ii] * gain) >> 10;
375         if (tmpFlt > 32767)
376         {
377             tmpFlt = 32767;
378             gainIdx--;
379             if (gainIdx >= 127)
380             {
381                 gain = kGainTableVirtualMic[gainIdx - 127];
382             } else
383             {
384                 gain = kSuppressionTableVirtualMic[127 - gainIdx];
385             }
386         }
387         if (tmpFlt < -32768)
388         {
389             tmpFlt = -32768;
390             gainIdx--;
391             if (gainIdx >= 127)
392             {
393                 gain = kGainTableVirtualMic[gainIdx - 127];
394             } else
395             {
396                 gain = kSuppressionTableVirtualMic[127 - gainIdx];
397             }
398         }
399         in_near[0][ii] = (int16_t)tmpFlt;
400         for (j = 1; j < num_bands; ++j)
401         {
402             tmpFlt = (in_near[j][ii] * gain) >> 10;
403             if (tmpFlt > 32767)
404             {
405                 tmpFlt = 32767;
406             }
407             if (tmpFlt < -32768)
408             {
409                 tmpFlt = -32768;
410             }
411             in_near[j][ii] = (int16_t)tmpFlt;
412         }
413     }
414     /* Set the level we (finally) used */
415     stt->micGainIdx = gainIdx;
416 //    *micLevelOut = stt->micGainIdx;
417     *micLevelOut = stt->micGainIdx >> stt->scale;
418     /* Add to Mic as if it was the output from a true microphone */
419     if (WebRtcAgc_AddMic(agcInst, in_near, num_bands, samples) != 0)
420     {
421         return -1;
422     }
423     return 0;
424 }
425 
WebRtcAgc_UpdateAgcThresholds(LegacyAgc * stt)426 void WebRtcAgc_UpdateAgcThresholds(LegacyAgc* stt) {
427     int16_t tmp16;
428 #ifdef MIC_LEVEL_FEEDBACK
429     int zeros;
430 
431     if (stt->micLvlSat)
432     {
433         /* Lower the analog target level since we have reached its maximum */
434         zeros = WebRtcSpl_NormW32(stt->Rxx160_LPw32);
435         stt->targetIdxOffset = (3 * zeros - stt->targetIdx - 2) / 4;
436     }
437 #endif
438 
439     /* Set analog target level in envelope dBOv scale */
440     tmp16 = (DIFF_REF_TO_ANALOG * stt->compressionGaindB) + ANALOG_TARGET_LEVEL_2;
441     tmp16 = WebRtcSpl_DivW32W16ResW16((int32_t)tmp16, ANALOG_TARGET_LEVEL);
442     stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN + tmp16;
443     if (stt->analogTarget < DIGITAL_REF_AT_0_COMP_GAIN)
444     {
445         stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN;
446     }
447     if (stt->agcMode == kAgcModeFixedDigital)
448     {
449         /* Adjust for different parameter interpretation in FixedDigital mode */
450         stt->analogTarget = stt->compressionGaindB;
451     }
452 #ifdef MIC_LEVEL_FEEDBACK
453     stt->analogTarget += stt->targetIdxOffset;
454 #endif
455     /* Since the offset between RMS and ENV is not constant, we should make this into a
456      * table, but for now, we'll stick with a constant, tuned for the chosen analog
457      * target level.
458      */
459     stt->targetIdx = ANALOG_TARGET_LEVEL + OFFSET_ENV_TO_RMS;
460 #ifdef MIC_LEVEL_FEEDBACK
461     stt->targetIdx += stt->targetIdxOffset;
462 #endif
463     /* Analog adaptation limits */
464     /* analogTargetLevel = round((32767*10^(-targetIdx/20))^2*16/2^7) */
465     stt->analogTargetLevel = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx]; /* ex. -20 dBov */
466     stt->startUpperLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 1];/* -19 dBov */
467     stt->startLowerLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 1];/* -21 dBov */
468     stt->upperPrimaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 2];/* -18 dBov */
469     stt->lowerPrimaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 2];/* -22 dBov */
470     stt->upperSecondaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 5];/* -15 dBov */
471     stt->lowerSecondaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 5];/* -25 dBov */
472     stt->upperLimit = stt->startUpperLimit;
473     stt->lowerLimit = stt->startLowerLimit;
474 }
475 
WebRtcAgc_SaturationCtrl(LegacyAgc * stt,uint8_t * saturated,int32_t * env)476 void WebRtcAgc_SaturationCtrl(LegacyAgc* stt,
477                               uint8_t* saturated,
478                               int32_t* env) {
479     int16_t i, tmpW16;
480 
481     /* Check if the signal is saturated */
482     for (i = 0; i < 10; i++)
483     {
484         tmpW16 = (int16_t)(env[i] >> 20);
485         if (tmpW16 > 875)
486         {
487             stt->envSum += tmpW16;
488         }
489     }
490 
491     if (stt->envSum > 25000)
492     {
493         *saturated = 1;
494         stt->envSum = 0;
495     }
496 
497     /* stt->envSum *= 0.99; */
498     stt->envSum = (int16_t)((stt->envSum * 32440) >> 15);
499 }
500 
WebRtcAgc_ZeroCtrl(LegacyAgc * stt,int32_t * inMicLevel,int32_t * env)501 void WebRtcAgc_ZeroCtrl(LegacyAgc* stt, int32_t* inMicLevel, int32_t* env) {
502     int16_t i;
503     int32_t tmp32 = 0;
504     int32_t midVal;
505 
506     /* Is the input signal zero? */
507     for (i = 0; i < 10; i++)
508     {
509         tmp32 += env[i];
510     }
511 
512     /* Each block is allowed to have a few non-zero
513      * samples.
514      */
515     if (tmp32 < 500)
516     {
517         stt->msZero += 10;
518     } else
519     {
520         stt->msZero = 0;
521     }
522 
523     if (stt->muteGuardMs > 0)
524     {
525         stt->muteGuardMs -= 10;
526     }
527 
528     if (stt->msZero > 500)
529     {
530         stt->msZero = 0;
531 
532         /* Increase microphone level only if it's less than 50% */
533         midVal = (stt->maxAnalog + stt->minLevel + 1) / 2;
534         if (*inMicLevel < midVal)
535         {
536             /* *inMicLevel *= 1.1; */
537             *inMicLevel = (1126 * *inMicLevel) >> 10;
538             /* Reduces risk of a muted mic repeatedly triggering excessive levels due
539              * to zero signal detection. */
540             *inMicLevel = WEBRTC_SPL_MIN(*inMicLevel, stt->zeroCtrlMax);
541             stt->micVol = *inMicLevel;
542         }
543 
544 #ifdef WEBRTC_AGC_DEBUG_DUMP
545         fprintf(stt->fpt,
546                 "\t\tAGC->zeroCntrl, frame %d: 500 ms under threshold,"
547                 " micVol: %d\n",
548                 stt->fcount,
549                 stt->micVol);
550 #endif
551 
552         stt->activeSpeech = 0;
553         stt->Rxx16_LPw32Max = 0;
554 
555         /* The AGC has a tendency (due to problems with the VAD parameters), to
556          * vastly increase the volume after a muting event. This timer prevents
557          * upwards adaptation for a short period. */
558         stt->muteGuardMs = kMuteGuardTimeMs;
559     }
560 }
561 
WebRtcAgc_SpeakerInactiveCtrl(LegacyAgc * stt)562 void WebRtcAgc_SpeakerInactiveCtrl(LegacyAgc* stt) {
563     /* Check if the near end speaker is inactive.
564      * If that is the case the VAD threshold is
565      * increased since the VAD speech model gets
566      * more sensitive to any sound after a long
567      * silence.
568      */
569 
570     int32_t tmp32;
571     int16_t vadThresh;
572 
573     if (stt->vadMic.stdLongTerm < 2500)
574     {
575         stt->vadThreshold = 1500;
576     } else
577     {
578         vadThresh = kNormalVadThreshold;
579         if (stt->vadMic.stdLongTerm < 4500)
580         {
581             /* Scale between min and max threshold */
582             vadThresh += (4500 - stt->vadMic.stdLongTerm) / 2;
583         }
584 
585         /* stt->vadThreshold = (31 * stt->vadThreshold + vadThresh) / 32; */
586         tmp32 = vadThresh + 31 * stt->vadThreshold;
587         stt->vadThreshold = (int16_t)(tmp32 >> 5);
588     }
589 }
590 
WebRtcAgc_ExpCurve(int16_t volume,int16_t * index)591 void WebRtcAgc_ExpCurve(int16_t volume, int16_t *index)
592 {
593     // volume in Q14
594     // index in [0-7]
595     /* 8 different curves */
596     if (volume > 5243)
597     {
598         if (volume > 7864)
599         {
600             if (volume > 12124)
601             {
602                 *index = 7;
603             } else
604             {
605                 *index = 6;
606             }
607         } else
608         {
609             if (volume > 6554)
610             {
611                 *index = 5;
612             } else
613             {
614                 *index = 4;
615             }
616         }
617     } else
618     {
619         if (volume > 2621)
620         {
621             if (volume > 3932)
622             {
623                 *index = 3;
624             } else
625             {
626                 *index = 2;
627             }
628         } else
629         {
630             if (volume > 1311)
631             {
632                 *index = 1;
633             } else
634             {
635                 *index = 0;
636             }
637         }
638     }
639 }
640 
WebRtcAgc_ProcessAnalog(void * state,int32_t inMicLevel,int32_t * outMicLevel,int16_t vadLogRatio,int16_t echo,uint8_t * saturationWarning)641 int32_t WebRtcAgc_ProcessAnalog(void *state, int32_t inMicLevel,
642                                 int32_t *outMicLevel,
643                                 int16_t vadLogRatio,
644                                 int16_t echo, uint8_t *saturationWarning)
645 {
646     uint32_t tmpU32;
647     int32_t Rxx16w32, tmp32;
648     int32_t inMicLevelTmp, lastMicVol;
649     int16_t i;
650     uint8_t saturated = 0;
651     LegacyAgc* stt;
652 
653     stt = (LegacyAgc*)state;
654     inMicLevelTmp = inMicLevel << stt->scale;
655 
656     if (inMicLevelTmp > stt->maxAnalog)
657     {
658 #ifdef WEBRTC_AGC_DEBUG_DUMP
659         fprintf(stt->fpt,
660                 "\tAGC->ProcessAnalog, frame %d: micLvl > maxAnalog\n",
661                 stt->fcount);
662 #endif
663         return -1;
664     } else if (inMicLevelTmp < stt->minLevel)
665     {
666 #ifdef WEBRTC_AGC_DEBUG_DUMP
667         fprintf(stt->fpt,
668                 "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel\n",
669                 stt->fcount);
670 #endif
671         return -1;
672     }
673 
674     if (stt->firstCall == 0)
675     {
676         int32_t tmpVol;
677         stt->firstCall = 1;
678         tmp32 = ((stt->maxLevel - stt->minLevel) * 51) >> 9;
679         tmpVol = (stt->minLevel + tmp32);
680 
681         /* If the mic level is very low at start, increase it! */
682         if ((inMicLevelTmp < tmpVol) && (stt->agcMode == kAgcModeAdaptiveAnalog))
683         {
684             inMicLevelTmp = tmpVol;
685         }
686         stt->micVol = inMicLevelTmp;
687     }
688 
689     /* Set the mic level to the previous output value if there is digital input gain */
690     if ((inMicLevelTmp == stt->maxAnalog) && (stt->micVol > stt->maxAnalog))
691     {
692         inMicLevelTmp = stt->micVol;
693     }
694 
695     /* If the mic level was manually changed to a very low value raise it! */
696     if ((inMicLevelTmp != stt->micVol) && (inMicLevelTmp < stt->minOutput))
697     {
698         tmp32 = ((stt->maxLevel - stt->minLevel) * 51) >> 9;
699         inMicLevelTmp = (stt->minLevel + tmp32);
700         stt->micVol = inMicLevelTmp;
701 #ifdef MIC_LEVEL_FEEDBACK
702         //stt->numBlocksMicLvlSat = 0;
703 #endif
704 #ifdef WEBRTC_AGC_DEBUG_DUMP
705         fprintf(stt->fpt,
706                 "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel by manual"
707                 " decrease, raise vol\n",
708                 stt->fcount);
709 #endif
710     }
711 
712     if (inMicLevelTmp != stt->micVol)
713     {
714         if (inMicLevel == stt->lastInMicLevel) {
715             // We requested a volume adjustment, but it didn't occur. This is
716             // probably due to a coarse quantization of the volume slider.
717             // Restore the requested value to prevent getting stuck.
718             inMicLevelTmp = stt->micVol;
719         }
720         else {
721             // As long as the value changed, update to match.
722             stt->micVol = inMicLevelTmp;
723         }
724     }
725 
726     if (inMicLevelTmp > stt->maxLevel)
727     {
728         // Always allow the user to raise the volume above the maxLevel.
729         stt->maxLevel = inMicLevelTmp;
730     }
731 
732     // Store last value here, after we've taken care of manual updates etc.
733     stt->lastInMicLevel = inMicLevel;
734     lastMicVol = stt->micVol;
735 
736     /* Checks if the signal is saturated. Also a check if individual samples
737      * are larger than 12000 is done. If they are the counter for increasing
738      * the volume level is set to -100ms
739      */
740     WebRtcAgc_SaturationCtrl(stt, &saturated, stt->env[0]);
741 
742     /* The AGC is always allowed to lower the level if the signal is saturated */
743     if (saturated == 1)
744     {
745         /* Lower the recording level
746          * Rxx160_LP is adjusted down because it is so slow it could
747          * cause the AGC to make wrong decisions. */
748         /* stt->Rxx160_LPw32 *= 0.875; */
749         stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 8) * 7;
750 
751         stt->zeroCtrlMax = stt->micVol;
752 
753         /* stt->micVol *= 0.903; */
754         tmp32 = inMicLevelTmp - stt->minLevel;
755         tmpU32 = WEBRTC_SPL_UMUL(29591, (uint32_t)(tmp32));
756         stt->micVol = (tmpU32 >> 15) + stt->minLevel;
757         if (stt->micVol > lastMicVol - 2)
758         {
759             stt->micVol = lastMicVol - 2;
760         }
761         inMicLevelTmp = stt->micVol;
762 
763 #ifdef WEBRTC_AGC_DEBUG_DUMP
764         fprintf(stt->fpt,
765                 "\tAGC->ProcessAnalog, frame %d: saturated, micVol = %d\n",
766                 stt->fcount,
767                 stt->micVol);
768 #endif
769 
770         if (stt->micVol < stt->minOutput)
771         {
772             *saturationWarning = 1;
773         }
774 
775         /* Reset counter for decrease of volume level to avoid
776          * decreasing too much. The saturation control can still
777          * lower the level if needed. */
778         stt->msTooHigh = -100;
779 
780         /* Enable the control mechanism to ensure that our measure,
781          * Rxx160_LP, is in the correct range. This must be done since
782          * the measure is very slow. */
783         stt->activeSpeech = 0;
784         stt->Rxx16_LPw32Max = 0;
785 
786         /* Reset to initial values */
787         stt->msecSpeechInnerChange = kMsecSpeechInner;
788         stt->msecSpeechOuterChange = kMsecSpeechOuter;
789         stt->changeToSlowMode = 0;
790 
791         stt->muteGuardMs = 0;
792 
793         stt->upperLimit = stt->startUpperLimit;
794         stt->lowerLimit = stt->startLowerLimit;
795 #ifdef MIC_LEVEL_FEEDBACK
796         //stt->numBlocksMicLvlSat = 0;
797 #endif
798     }
799 
800     /* Check if the input speech is zero. If so the mic volume
801      * is increased. On some computers the input is zero up as high
802      * level as 17% */
803     WebRtcAgc_ZeroCtrl(stt, &inMicLevelTmp, stt->env[0]);
804 
805     /* Check if the near end speaker is inactive.
806      * If that is the case the VAD threshold is
807      * increased since the VAD speech model gets
808      * more sensitive to any sound after a long
809      * silence.
810      */
811     WebRtcAgc_SpeakerInactiveCtrl(stt);
812 
813     for (i = 0; i < 5; i++)
814     {
815         /* Computed on blocks of 16 samples */
816 
817         Rxx16w32 = stt->Rxx16w32_array[0][i];
818 
819         /* Rxx160w32 in Q(-7) */
820         tmp32 = (Rxx16w32 - stt->Rxx16_vectorw32[stt->Rxx16pos]) >> 3;
821         stt->Rxx160w32 = stt->Rxx160w32 + tmp32;
822         stt->Rxx16_vectorw32[stt->Rxx16pos] = Rxx16w32;
823 
824         /* Circular buffer */
825         stt->Rxx16pos++;
826         if (stt->Rxx16pos == RXX_BUFFER_LEN)
827         {
828             stt->Rxx16pos = 0;
829         }
830 
831         /* Rxx16_LPw32 in Q(-4) */
832         tmp32 = (Rxx16w32 - stt->Rxx16_LPw32) >> kAlphaShortTerm;
833         stt->Rxx16_LPw32 = (stt->Rxx16_LPw32) + tmp32;
834 
835         if (vadLogRatio > stt->vadThreshold)
836         {
837             /* Speech detected! */
838 
839             /* Check if Rxx160_LP is in the correct range. If
840              * it is too high/low then we set it to the maximum of
841              * Rxx16_LPw32 during the first 200ms of speech.
842              */
843             if (stt->activeSpeech < 250)
844             {
845                 stt->activeSpeech += 2;
846 
847                 if (stt->Rxx16_LPw32 > stt->Rxx16_LPw32Max)
848                 {
849                     stt->Rxx16_LPw32Max = stt->Rxx16_LPw32;
850                 }
851             } else if (stt->activeSpeech == 250)
852             {
853                 stt->activeSpeech += 2;
854                 tmp32 = stt->Rxx16_LPw32Max >> 3;
855                 stt->Rxx160_LPw32 = tmp32 * RXX_BUFFER_LEN;
856             }
857 
858             tmp32 = (stt->Rxx160w32 - stt->Rxx160_LPw32) >> kAlphaLongTerm;
859             stt->Rxx160_LPw32 = stt->Rxx160_LPw32 + tmp32;
860 
861             if (stt->Rxx160_LPw32 > stt->upperSecondaryLimit)
862             {
863                 stt->msTooHigh += 2;
864                 stt->msTooLow = 0;
865                 stt->changeToSlowMode = 0;
866 
867                 if (stt->msTooHigh > stt->msecSpeechOuterChange)
868                 {
869                     stt->msTooHigh = 0;
870 
871                     /* Lower the recording level */
872                     /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
873                     tmp32 = stt->Rxx160_LPw32 >> 6;
874                     stt->Rxx160_LPw32 = tmp32 * 53;
875 
876                     /* Reduce the max gain to avoid excessive oscillation
877                      * (but never drop below the maximum analog level).
878                      */
879                     stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
880                     stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
881 
882                     stt->zeroCtrlMax = stt->micVol;
883 
884                     /* 0.95 in Q15 */
885                     tmp32 = inMicLevelTmp - stt->minLevel;
886                     tmpU32 = WEBRTC_SPL_UMUL(31130, (uint32_t)(tmp32));
887                     stt->micVol = (tmpU32 >> 15) + stt->minLevel;
888                     if (stt->micVol > lastMicVol - 1)
889                     {
890                         stt->micVol = lastMicVol - 1;
891                     }
892                     inMicLevelTmp = stt->micVol;
893 
894                     /* Enable the control mechanism to ensure that our measure,
895                      * Rxx160_LP, is in the correct range.
896                      */
897                     stt->activeSpeech = 0;
898                     stt->Rxx16_LPw32Max = 0;
899 #ifdef MIC_LEVEL_FEEDBACK
900                     //stt->numBlocksMicLvlSat = 0;
901 #endif
902 #ifdef WEBRTC_AGC_DEBUG_DUMP
903                     fprintf(stt->fpt,
904                             "\tAGC->ProcessAnalog, frame %d: measure >"
905                             " 2ndUpperLim, micVol = %d, maxLevel = %d\n",
906                             stt->fcount,
907                             stt->micVol,
908                             stt->maxLevel);
909 #endif
910                 }
911             } else if (stt->Rxx160_LPw32 > stt->upperLimit)
912             {
913                 stt->msTooHigh += 2;
914                 stt->msTooLow = 0;
915                 stt->changeToSlowMode = 0;
916 
917                 if (stt->msTooHigh > stt->msecSpeechInnerChange)
918                 {
919                     /* Lower the recording level */
920                     stt->msTooHigh = 0;
921                     /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
922                     stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 53;
923 
924                     /* Reduce the max gain to avoid excessive oscillation
925                      * (but never drop below the maximum analog level).
926                      */
927                     stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
928                     stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
929 
930                     stt->zeroCtrlMax = stt->micVol;
931 
932                     /* 0.965 in Q15 */
933                     tmp32 = inMicLevelTmp - stt->minLevel;
934                     tmpU32 = WEBRTC_SPL_UMUL(31621, (uint32_t)(inMicLevelTmp - stt->minLevel));
935                     stt->micVol = (tmpU32 >> 15) + stt->minLevel;
936                     if (stt->micVol > lastMicVol - 1)
937                     {
938                         stt->micVol = lastMicVol - 1;
939                     }
940                     inMicLevelTmp = stt->micVol;
941 
942 #ifdef MIC_LEVEL_FEEDBACK
943                     //stt->numBlocksMicLvlSat = 0;
944 #endif
945 #ifdef WEBRTC_AGC_DEBUG_DUMP
946                     fprintf(stt->fpt,
947                             "\tAGC->ProcessAnalog, frame %d: measure >"
948                             " UpperLim, micVol = %d, maxLevel = %d\n",
949                             stt->fcount,
950                             stt->micVol,
951                             stt->maxLevel);
952 #endif
953                 }
954             } else if (stt->Rxx160_LPw32 < stt->lowerSecondaryLimit)
955             {
956                 stt->msTooHigh = 0;
957                 stt->changeToSlowMode = 0;
958                 stt->msTooLow += 2;
959 
960                 if (stt->msTooLow > stt->msecSpeechOuterChange)
961                 {
962                     /* Raise the recording level */
963                     int16_t index, weightFIX;
964                     int16_t volNormFIX = 16384; // =1 in Q14.
965 
966                     stt->msTooLow = 0;
967 
968                     /* Normalize the volume level */
969                     tmp32 = (inMicLevelTmp - stt->minLevel) << 14;
970                     if (stt->maxInit != stt->minLevel)
971                     {
972                         volNormFIX = tmp32 / (stt->maxInit - stt->minLevel);
973                     }
974 
975                     /* Find correct curve */
976                     WebRtcAgc_ExpCurve(volNormFIX, &index);
977 
978                     /* Compute weighting factor for the volume increase, 32^(-2*X)/2+1.05 */
979                     weightFIX = kOffset1[index] -
980                         (int16_t)((kSlope1[index] * volNormFIX) >> 13);
981 
982                     /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
983                     stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 67;
984 
985                     tmp32 = inMicLevelTmp - stt->minLevel;
986                     tmpU32 = ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
987                     stt->micVol = (tmpU32 >> 14) + stt->minLevel;
988                     if (stt->micVol < lastMicVol + 2)
989                     {
990                         stt->micVol = lastMicVol + 2;
991                     }
992 
993                     inMicLevelTmp = stt->micVol;
994 
995 #ifdef MIC_LEVEL_FEEDBACK
996                     /* Count ms in level saturation */
997                     //if (stt->micVol > stt->maxAnalog) {
998                     if (stt->micVol > 150)
999                     {
1000                         /* mic level is saturated */
1001                         stt->numBlocksMicLvlSat++;
1002                         fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
1003                     }
1004 #endif
1005 #ifdef WEBRTC_AGC_DEBUG_DUMP
1006                     fprintf(stt->fpt,
1007                             "\tAGC->ProcessAnalog, frame %d: measure <"
1008                             " 2ndLowerLim, micVol = %d\n",
1009                             stt->fcount,
1010                             stt->micVol);
1011 #endif
1012                 }
1013             } else if (stt->Rxx160_LPw32 < stt->lowerLimit)
1014             {
1015                 stt->msTooHigh = 0;
1016                 stt->changeToSlowMode = 0;
1017                 stt->msTooLow += 2;
1018 
1019                 if (stt->msTooLow > stt->msecSpeechInnerChange)
1020                 {
1021                     /* Raise the recording level */
1022                     int16_t index, weightFIX;
1023                     int16_t volNormFIX = 16384; // =1 in Q14.
1024 
1025                     stt->msTooLow = 0;
1026 
1027                     /* Normalize the volume level */
1028                     tmp32 = (inMicLevelTmp - stt->minLevel) << 14;
1029                     if (stt->maxInit != stt->minLevel)
1030                     {
1031                         volNormFIX = tmp32 / (stt->maxInit - stt->minLevel);
1032                     }
1033 
1034                     /* Find correct curve */
1035                     WebRtcAgc_ExpCurve(volNormFIX, &index);
1036 
1037                     /* Compute weighting factor for the volume increase, (3.^(-2.*X))/8+1 */
1038                     weightFIX = kOffset2[index] -
1039                         (int16_t)((kSlope2[index] * volNormFIX) >> 13);
1040 
1041                     /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
1042                     stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 67;
1043 
1044                     tmp32 = inMicLevelTmp - stt->minLevel;
1045                     tmpU32 = ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
1046                     stt->micVol = (tmpU32 >> 14) + stt->minLevel;
1047                     if (stt->micVol < lastMicVol + 1)
1048                     {
1049                         stt->micVol = lastMicVol + 1;
1050                     }
1051 
1052                     inMicLevelTmp = stt->micVol;
1053 
1054 #ifdef MIC_LEVEL_FEEDBACK
1055                     /* Count ms in level saturation */
1056                     //if (stt->micVol > stt->maxAnalog) {
1057                     if (stt->micVol > 150)
1058                     {
1059                         /* mic level is saturated */
1060                         stt->numBlocksMicLvlSat++;
1061                         fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
1062                     }
1063 #endif
1064 #ifdef WEBRTC_AGC_DEBUG_DUMP
1065                     fprintf(stt->fpt,
1066                             "\tAGC->ProcessAnalog, frame %d: measure < LowerLim, micVol = %d\n",
1067                             stt->fcount,
1068                             stt->micVol);
1069 #endif
1070 
1071                 }
1072             } else
1073             {
1074                 /* The signal is inside the desired range which is:
1075                  * lowerLimit < Rxx160_LP/640 < upperLimit
1076                  */
1077                 if (stt->changeToSlowMode > 4000)
1078                 {
1079                     stt->msecSpeechInnerChange = 1000;
1080                     stt->msecSpeechOuterChange = 500;
1081                     stt->upperLimit = stt->upperPrimaryLimit;
1082                     stt->lowerLimit = stt->lowerPrimaryLimit;
1083                 } else
1084                 {
1085                     stt->changeToSlowMode += 2; // in milliseconds
1086                 }
1087                 stt->msTooLow = 0;
1088                 stt->msTooHigh = 0;
1089 
1090                 stt->micVol = inMicLevelTmp;
1091 
1092             }
1093 #ifdef MIC_LEVEL_FEEDBACK
1094             if (stt->numBlocksMicLvlSat > NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET)
1095             {
1096                 stt->micLvlSat = 1;
1097                 fprintf(stderr, "target before = %d (%d)\n", stt->analogTargetLevel, stt->targetIdx);
1098                 WebRtcAgc_UpdateAgcThresholds(stt);
1099                 WebRtcAgc_CalculateGainTable(&(stt->digitalAgc.gainTable[0]),
1100                         stt->compressionGaindB, stt->targetLevelDbfs, stt->limiterEnable,
1101                         stt->analogTarget);
1102                 stt->numBlocksMicLvlSat = 0;
1103                 stt->micLvlSat = 0;
1104                 fprintf(stderr, "target offset = %d\n", stt->targetIdxOffset);
1105                 fprintf(stderr, "target after  = %d (%d)\n", stt->analogTargetLevel, stt->targetIdx);
1106             }
1107 #endif
1108         }
1109     }
1110 
1111     /* Ensure gain is not increased in presence of echo or after a mute event
1112      * (but allow the zeroCtrl() increase on the frame of a mute detection).
1113      */
1114     if (echo == 1 || (stt->muteGuardMs > 0 && stt->muteGuardMs < kMuteGuardTimeMs))
1115     {
1116         if (stt->micVol > lastMicVol)
1117         {
1118             stt->micVol = lastMicVol;
1119         }
1120     }
1121 
1122     /* limit the gain */
1123     if (stt->micVol > stt->maxLevel)
1124     {
1125         stt->micVol = stt->maxLevel;
1126     } else if (stt->micVol < stt->minOutput)
1127     {
1128         stt->micVol = stt->minOutput;
1129     }
1130 
1131     *outMicLevel = WEBRTC_SPL_MIN(stt->micVol, stt->maxAnalog) >> stt->scale;
1132 
1133     return 0;
1134 }
1135 
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)1136 int WebRtcAgc_Process(void *agcInst, const int16_t* const* in_near,
1137                       size_t num_bands, size_t samples,
1138                       int16_t* const* out, int32_t inMicLevel,
1139                       int32_t *outMicLevel, int16_t echo,
1140                       uint8_t *saturationWarning)
1141 {
1142   LegacyAgc* stt;
1143 
1144   stt = (LegacyAgc*)agcInst;
1145 
1146     //
1147     if (stt == NULL)
1148     {
1149         return -1;
1150     }
1151     //
1152 
1153 
1154     if (stt->fs == 8000)
1155     {
1156         if (samples != 80)
1157         {
1158             return -1;
1159         }
1160     } else if (stt->fs == 16000 || stt->fs == 32000 || stt->fs == 48000)
1161     {
1162         if (samples != 160)
1163         {
1164             return -1;
1165         }
1166     } else
1167     {
1168         return -1;
1169     }
1170 
1171     *saturationWarning = 0;
1172     //TODO: PUT IN RANGE CHECKING FOR INPUT LEVELS
1173     *outMicLevel = inMicLevel;
1174 
1175 #ifdef WEBRTC_AGC_DEBUG_DUMP
1176     stt->fcount++;
1177 #endif
1178 
1179     if (WebRtcAgc_ProcessDigital(&stt->digitalAgc,
1180                                  in_near,
1181                                  num_bands,
1182                                  out,
1183                                  stt->fs,
1184                                  stt->lowLevelSignal) == -1)
1185     {
1186 #ifdef WEBRTC_AGC_DEBUG_DUMP
1187         fprintf(stt->fpt,
1188                 "AGC->Process, frame %d: Error from DigAGC\n\n",
1189                 stt->fcount);
1190 #endif
1191         return -1;
1192     }
1193     if (stt->agcMode < kAgcModeFixedDigital &&
1194         (stt->lowLevelSignal == 0 || stt->agcMode != kAgcModeAdaptiveDigital))
1195     {
1196         if (WebRtcAgc_ProcessAnalog(agcInst,
1197                                     inMicLevel,
1198                                     outMicLevel,
1199                                     stt->vadMic.logRatio,
1200                                     echo,
1201                                     saturationWarning) == -1)
1202         {
1203             return -1;
1204         }
1205     }
1206 #ifdef WEBRTC_AGC_DEBUG_DUMP
1207     fprintf(stt->agcLog,
1208             "%5d\t%d\t%d\t%d\t%d\n",
1209             stt->fcount,
1210             inMicLevel,
1211             *outMicLevel,
1212             stt->maxLevel,
1213             stt->micVol);
1214 #endif
1215 
1216     /* update queue */
1217     if (stt->inQueue > 1)
1218     {
1219         memcpy(stt->env[0], stt->env[1], 10 * sizeof(int32_t));
1220         memcpy(stt->Rxx16w32_array[0],
1221                stt->Rxx16w32_array[1],
1222                5 * sizeof(int32_t));
1223     }
1224 
1225     if (stt->inQueue > 0)
1226     {
1227         stt->inQueue--;
1228     }
1229 
1230     return 0;
1231 }
1232 
WebRtcAgc_set_config(void * agcInst,WebRtcAgcConfig agcConfig)1233 int WebRtcAgc_set_config(void* agcInst, WebRtcAgcConfig agcConfig) {
1234   LegacyAgc* stt;
1235   stt = (LegacyAgc*)agcInst;
1236 
1237     if (stt == NULL)
1238     {
1239         return -1;
1240     }
1241 
1242     if (stt->initFlag != kInitCheck)
1243     {
1244         stt->lastError = AGC_UNINITIALIZED_ERROR;
1245         return -1;
1246     }
1247 
1248     if (agcConfig.limiterEnable != kAgcFalse && agcConfig.limiterEnable != kAgcTrue)
1249     {
1250         stt->lastError = AGC_BAD_PARAMETER_ERROR;
1251         return -1;
1252     }
1253     stt->limiterEnable = agcConfig.limiterEnable;
1254     stt->compressionGaindB = agcConfig.compressionGaindB;
1255     if ((agcConfig.targetLevelDbfs < 0) || (agcConfig.targetLevelDbfs > 31))
1256     {
1257         stt->lastError = AGC_BAD_PARAMETER_ERROR;
1258         return -1;
1259     }
1260     stt->targetLevelDbfs = agcConfig.targetLevelDbfs;
1261 
1262     if (stt->agcMode == kAgcModeFixedDigital)
1263     {
1264         /* Adjust for different parameter interpretation in FixedDigital mode */
1265         stt->compressionGaindB += agcConfig.targetLevelDbfs;
1266     }
1267 
1268     /* Update threshold levels for analog adaptation */
1269     WebRtcAgc_UpdateAgcThresholds(stt);
1270 
1271     /* Recalculate gain table */
1272     if (WebRtcAgc_CalculateGainTable(&(stt->digitalAgc.gainTable[0]), stt->compressionGaindB,
1273                            stt->targetLevelDbfs, stt->limiterEnable, stt->analogTarget) == -1)
1274     {
1275 #ifdef WEBRTC_AGC_DEBUG_DUMP
1276         fprintf(stt->fpt,
1277                 "AGC->set_config, frame %d: Error from calcGainTable\n\n",
1278                 stt->fcount);
1279 #endif
1280         return -1;
1281     }
1282     /* Store the config in a WebRtcAgcConfig */
1283     stt->usedConfig.compressionGaindB = agcConfig.compressionGaindB;
1284     stt->usedConfig.limiterEnable = agcConfig.limiterEnable;
1285     stt->usedConfig.targetLevelDbfs = agcConfig.targetLevelDbfs;
1286 
1287     return 0;
1288 }
1289 
WebRtcAgc_get_config(void * agcInst,WebRtcAgcConfig * config)1290 int WebRtcAgc_get_config(void* agcInst, WebRtcAgcConfig* config) {
1291   LegacyAgc* stt;
1292   stt = (LegacyAgc*)agcInst;
1293 
1294     if (stt == NULL)
1295     {
1296         return -1;
1297     }
1298 
1299     if (config == NULL)
1300     {
1301         stt->lastError = AGC_NULL_POINTER_ERROR;
1302         return -1;
1303     }
1304 
1305     if (stt->initFlag != kInitCheck)
1306     {
1307         stt->lastError = AGC_UNINITIALIZED_ERROR;
1308         return -1;
1309     }
1310 
1311     config->limiterEnable = stt->usedConfig.limiterEnable;
1312     config->targetLevelDbfs = stt->usedConfig.targetLevelDbfs;
1313     config->compressionGaindB = stt->usedConfig.compressionGaindB;
1314 
1315     return 0;
1316 }
1317 
WebRtcAgc_Create()1318 void* WebRtcAgc_Create() {
1319   LegacyAgc* stt = malloc(sizeof(LegacyAgc));
1320 
1321 #ifdef WEBRTC_AGC_DEBUG_DUMP
1322   stt->fpt = fopen("./agc_test_log.txt", "wt");
1323   stt->agcLog = fopen("./agc_debug_log.txt", "wt");
1324   stt->digitalAgc.logFile = fopen("./agc_log.txt", "wt");
1325 #endif
1326 
1327   stt->initFlag = 0;
1328   stt->lastError = 0;
1329 
1330   return stt;
1331 }
1332 
WebRtcAgc_Free(void * state)1333 void WebRtcAgc_Free(void *state) {
1334   LegacyAgc* stt;
1335 
1336   stt = (LegacyAgc*)state;
1337 #ifdef WEBRTC_AGC_DEBUG_DUMP
1338   fclose(stt->fpt);
1339   fclose(stt->agcLog);
1340   fclose(stt->digitalAgc.logFile);
1341 #endif
1342   free(stt);
1343 }
1344 
1345 /* minLevel     - Minimum volume level
1346  * maxLevel     - Maximum volume level
1347  */
WebRtcAgc_Init(void * agcInst,int32_t minLevel,int32_t maxLevel,int16_t agcMode,uint32_t fs)1348 int WebRtcAgc_Init(void *agcInst, int32_t minLevel, int32_t maxLevel,
1349                    int16_t agcMode, uint32_t fs)
1350 {
1351     int32_t max_add, tmp32;
1352     int16_t i;
1353     int tmpNorm;
1354     LegacyAgc* stt;
1355 
1356     /* typecast state pointer */
1357     stt = (LegacyAgc*)agcInst;
1358 
1359     if (WebRtcAgc_InitDigital(&stt->digitalAgc, agcMode) != 0)
1360     {
1361         stt->lastError = AGC_UNINITIALIZED_ERROR;
1362         return -1;
1363     }
1364 
1365     /* Analog AGC variables */
1366     stt->envSum = 0;
1367 
1368     /* mode     = 0 - Only saturation protection
1369      *            1 - Analog Automatic Gain Control [-targetLevelDbfs (default -3 dBOv)]
1370      *            2 - Digital Automatic Gain Control [-targetLevelDbfs (default -3 dBOv)]
1371      *            3 - Fixed Digital Gain [compressionGaindB (default 8 dB)]
1372      */
1373 #ifdef WEBRTC_AGC_DEBUG_DUMP
1374     stt->fcount = 0;
1375     fprintf(stt->fpt, "AGC->Init\n");
1376 #endif
1377     if (agcMode < kAgcModeUnchanged || agcMode > kAgcModeFixedDigital)
1378     {
1379 #ifdef WEBRTC_AGC_DEBUG_DUMP
1380         fprintf(stt->fpt, "AGC->Init: error, incorrect mode\n\n");
1381 #endif
1382         return -1;
1383     }
1384     stt->agcMode = agcMode;
1385     stt->fs = fs;
1386 
1387     /* initialize input VAD */
1388     WebRtcAgc_InitVad(&stt->vadMic);
1389 
1390     /* If the volume range is smaller than 0-256 then
1391      * the levels are shifted up to Q8-domain */
1392     tmpNorm = WebRtcSpl_NormU32((uint32_t)maxLevel);
1393     stt->scale = tmpNorm - 23;
1394     if (stt->scale < 0)
1395     {
1396         stt->scale = 0;
1397     }
1398     // TODO(bjornv): Investigate if we really need to scale up a small range now when we have
1399     // a guard against zero-increments. For now, we do not support scale up (scale = 0).
1400     stt->scale = 0;
1401     maxLevel <<= stt->scale;
1402     minLevel <<= stt->scale;
1403 
1404     /* Make minLevel and maxLevel static in AdaptiveDigital */
1405     if (stt->agcMode == kAgcModeAdaptiveDigital)
1406     {
1407         minLevel = 0;
1408         maxLevel = 255;
1409         stt->scale = 0;
1410     }
1411     /* The maximum supplemental volume range is based on a vague idea
1412      * of how much lower the gain will be than the real analog gain. */
1413     max_add = (maxLevel - minLevel) / 4;
1414 
1415     /* Minimum/maximum volume level that can be set */
1416     stt->minLevel = minLevel;
1417     stt->maxAnalog = maxLevel;
1418     stt->maxLevel = maxLevel + max_add;
1419     stt->maxInit = stt->maxLevel;
1420 
1421     stt->zeroCtrlMax = stt->maxAnalog;
1422     stt->lastInMicLevel = 0;
1423 
1424     /* Initialize micVol parameter */
1425     stt->micVol = stt->maxAnalog;
1426     if (stt->agcMode == kAgcModeAdaptiveDigital)
1427     {
1428         stt->micVol = 127; /* Mid-point of mic level */
1429     }
1430     stt->micRef = stt->micVol;
1431     stt->micGainIdx = 127;
1432 #ifdef MIC_LEVEL_FEEDBACK
1433     stt->numBlocksMicLvlSat = 0;
1434     stt->micLvlSat = 0;
1435 #endif
1436 #ifdef WEBRTC_AGC_DEBUG_DUMP
1437     fprintf(stt->fpt,
1438             "AGC->Init: minLevel = %d, maxAnalog = %d, maxLevel = %d\n",
1439             stt->minLevel,
1440             stt->maxAnalog,
1441             stt->maxLevel);
1442 #endif
1443 
1444     /* Minimum output volume is 4% higher than the available lowest volume level */
1445     tmp32 = ((stt->maxLevel - stt->minLevel) * 10) >> 8;
1446     stt->minOutput = (stt->minLevel + tmp32);
1447 
1448     stt->msTooLow = 0;
1449     stt->msTooHigh = 0;
1450     stt->changeToSlowMode = 0;
1451     stt->firstCall = 0;
1452     stt->msZero = 0;
1453     stt->muteGuardMs = 0;
1454     stt->gainTableIdx = 0;
1455 
1456     stt->msecSpeechInnerChange = kMsecSpeechInner;
1457     stt->msecSpeechOuterChange = kMsecSpeechOuter;
1458 
1459     stt->activeSpeech = 0;
1460     stt->Rxx16_LPw32Max = 0;
1461 
1462     stt->vadThreshold = kNormalVadThreshold;
1463     stt->inActive = 0;
1464 
1465     for (i = 0; i < RXX_BUFFER_LEN; i++)
1466     {
1467         stt->Rxx16_vectorw32[i] = (int32_t)1000; /* -54dBm0 */
1468     }
1469     stt->Rxx160w32 = 125 * RXX_BUFFER_LEN; /* (stt->Rxx16_vectorw32[0]>>3) = 125 */
1470 
1471     stt->Rxx16pos = 0;
1472     stt->Rxx16_LPw32 = (int32_t)16284; /* Q(-4) */
1473 
1474     for (i = 0; i < 5; i++)
1475     {
1476         stt->Rxx16w32_array[0][i] = 0;
1477     }
1478     for (i = 0; i < 10; i++)
1479     {
1480         stt->env[0][i] = 0;
1481         stt->env[1][i] = 0;
1482     }
1483     stt->inQueue = 0;
1484 
1485 #ifdef MIC_LEVEL_FEEDBACK
1486     stt->targetIdxOffset = 0;
1487 #endif
1488 
1489     WebRtcSpl_MemSetW32(stt->filterState, 0, 8);
1490 
1491     stt->initFlag = kInitCheck;
1492     // Default config settings.
1493     stt->defaultConfig.limiterEnable = kAgcTrue;
1494     stt->defaultConfig.targetLevelDbfs = AGC_DEFAULT_TARGET_LEVEL;
1495     stt->defaultConfig.compressionGaindB = AGC_DEFAULT_COMP_GAIN;
1496 
1497     if (WebRtcAgc_set_config(stt, stt->defaultConfig) == -1)
1498     {
1499         stt->lastError = AGC_UNSPECIFIED_ERROR;
1500         return -1;
1501     }
1502     stt->Rxx160_LPw32 = stt->analogTargetLevel; // Initialize rms value
1503 
1504     stt->lowLevelSignal = 0;
1505 
1506     /* Only positive values are allowed that are not too large */
1507     if ((minLevel >= maxLevel) || (maxLevel & 0xFC000000))
1508     {
1509 #ifdef WEBRTC_AGC_DEBUG_DUMP
1510         fprintf(stt->fpt, "minLevel, maxLevel value(s) are invalid\n\n");
1511 #endif
1512         return -1;
1513     } else
1514     {
1515 #ifdef WEBRTC_AGC_DEBUG_DUMP
1516         fprintf(stt->fpt, "\n");
1517 #endif
1518         return 0;
1519     }
1520 }
1521