Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / audio_processing / agc / analog_agc.c
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 "webrtc/modules/audio_processing/agc/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
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
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
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
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
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
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
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
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
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
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
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
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
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
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  */
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 }