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