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