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