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