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