Home | History | Annotate | Download | only in source
      1 /*
      2  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 /* analog_agc.c
     12  *
     13  * Using a feedback system, determines an appropriate analog volume level
     14  * given an input signal and current volume level. Targets a conservative
     15  * signal level and is intended for use with a digital AGC to apply
     16  * additional gain.
     17  *
     18  */
     19 
     20 #include <assert.h>
     21 #include <stdlib.h>
     22 #ifdef AGC_DEBUG //test log
     23 #include <stdio.h>
     24 #endif
     25 #include "analog_agc.h"
     26 
     27 /* The slope of in Q13*/
     28 static const WebRtc_Word16 kSlope1[8] = {21793, 12517, 7189, 4129, 2372, 1362, 472, 78};
     29 
     30 /* The offset in Q14 */
     31 static const WebRtc_Word16 kOffset1[8] = {25395, 23911, 22206, 20737, 19612, 18805, 17951,
     32         17367};
     33 
     34 /* The slope of in Q13*/
     35 static const WebRtc_Word16 kSlope2[8] = {2063, 1731, 1452, 1218, 1021, 857, 597, 337};
     36 
     37 /* The offset in Q14 */
     38 static const WebRtc_Word16 kOffset2[8] = {18432, 18379, 18290, 18177, 18052, 17920, 17670,
     39         17286};
     40 
     41 static const WebRtc_Word16 kMuteGuardTimeMs = 8000;
     42 static const WebRtc_Word16 kInitCheck = 42;
     43 
     44 /* Default settings if config is not used */
     45 #define AGC_DEFAULT_TARGET_LEVEL 3
     46 #define AGC_DEFAULT_COMP_GAIN 9
     47 /* This is the target level for the analog part in ENV scale. To convert to RMS scale you
     48  * have to add OFFSET_ENV_TO_RMS.
     49  */
     50 #define ANALOG_TARGET_LEVEL 11
     51 #define ANALOG_TARGET_LEVEL_2 5 // ANALOG_TARGET_LEVEL / 2
     52 /* Offset between RMS scale (analog part) and ENV scale (digital part). This value actually
     53  * varies with the FIXED_ANALOG_TARGET_LEVEL, hence we should in the future replace it with
     54  * a table.
     55  */
     56 #define OFFSET_ENV_TO_RMS 9
     57 /* The reference input level at which the digital part gives an output of targetLevelDbfs
     58  * (desired level) if we have no compression gain. This level should be set high enough not
     59  * to compress the peaks due to the dynamics.
     60  */
     61 #define DIGITAL_REF_AT_0_COMP_GAIN 4
     62 /* Speed of reference level decrease.
     63  */
     64 #define DIFF_REF_TO_ANALOG 5
     65 
     66 #ifdef MIC_LEVEL_FEEDBACK
     67 #define NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET 7
     68 #endif
     69 /* Size of analog gain table */
     70 #define GAIN_TBL_LEN 32
     71 /* Matlab code:
     72  * fprintf(1, '\t%i, %i, %i, %i,\n', round(10.^(linspace(0,10,32)/20) * 2^12));
     73  */
     74 /* Q12 */
     75 static const WebRtc_UWord16 kGainTableAnalog[GAIN_TBL_LEN] = {4096, 4251, 4412, 4579, 4752,
     76         4932, 5118, 5312, 5513, 5722, 5938, 6163, 6396, 6638, 6889, 7150, 7420, 7701, 7992,
     77         8295, 8609, 8934, 9273, 9623, 9987, 10365, 10758, 11165, 11587, 12025, 12480, 12953};
     78 
     79 /* Gain/Suppression tables for virtual Mic (in Q10) */
     80 static const WebRtc_UWord16 kGainTableVirtualMic[128] = {1052, 1081, 1110, 1141, 1172, 1204,
     81         1237, 1271, 1305, 1341, 1378, 1416, 1454, 1494, 1535, 1577, 1620, 1664, 1710, 1757,
     82         1805, 1854, 1905, 1957, 2010, 2065, 2122, 2180, 2239, 2301, 2364, 2428, 2495, 2563,
     83         2633, 2705, 2779, 2855, 2933, 3013, 3096, 3180, 3267, 3357, 3449, 3543, 3640, 3739,
     84         3842, 3947, 4055, 4166, 4280, 4397, 4517, 4640, 4767, 4898, 5032, 5169, 5311, 5456,
     85         5605, 5758, 5916, 6078, 6244, 6415, 6590, 6770, 6956, 7146, 7341, 7542, 7748, 7960,
     86         8178, 8402, 8631, 8867, 9110, 9359, 9615, 9878, 10148, 10426, 10711, 11004, 11305,
     87         11614, 11932, 12258, 12593, 12938, 13292, 13655, 14029, 14412, 14807, 15212, 15628,
     88         16055, 16494, 16945, 17409, 17885, 18374, 18877, 19393, 19923, 20468, 21028, 21603,
     89         22194, 22801, 23425, 24065, 24724, 25400, 26095, 26808, 27541, 28295, 29069, 29864,
     90         30681, 31520, 32382};
     91 static const WebRtc_UWord16 kSuppressionTableVirtualMic[128] = {1024, 1006, 988, 970, 952,
     92         935, 918, 902, 886, 870, 854, 839, 824, 809, 794, 780, 766, 752, 739, 726, 713, 700,
     93         687, 675, 663, 651, 639, 628, 616, 605, 594, 584, 573, 563, 553, 543, 533, 524, 514,
     94         505, 496, 487, 478, 470, 461, 453, 445, 437, 429, 421, 414, 406, 399, 392, 385, 378,
     95         371, 364, 358, 351, 345, 339, 333, 327, 321, 315, 309, 304, 298, 293, 288, 283, 278,
     96         273, 268, 263, 258, 254, 249, 244, 240, 236, 232, 227, 223, 219, 215, 211, 208, 204,
     97         200, 197, 193, 190, 186, 183, 180, 176, 173, 170, 167, 164, 161, 158, 155, 153, 150,
     98         147, 145, 142, 139, 137, 134, 132, 130, 127, 125, 123, 121, 118, 116, 114, 112, 110,
     99         108, 106, 104, 102};
    100 
    101 /* Table for target energy levels. Values in Q(-7)
    102  * Matlab code
    103  * targetLevelTable = fprintf('%d,\t%d,\t%d,\t%d,\n', round((32767*10.^(-(0:63)'/20)).^2*16/2^7) */
    104 
    105 static const WebRtc_Word32 kTargetLevelTable[64] = {134209536, 106606424, 84680493, 67264106,
    106         53429779, 42440782, 33711911, 26778323, 21270778, 16895980, 13420954, 10660642,
    107         8468049, 6726411, 5342978, 4244078, 3371191, 2677832, 2127078, 1689598, 1342095,
    108         1066064, 846805, 672641, 534298, 424408, 337119, 267783, 212708, 168960, 134210,
    109         106606, 84680, 67264, 53430, 42441, 33712, 26778, 21271, 16896, 13421, 10661, 8468,
    110         6726, 5343, 4244, 3371, 2678, 2127, 1690, 1342, 1066, 847, 673, 534, 424, 337, 268,
    111         213, 169, 134, 107, 85, 67};
    112 
    113 int WebRtcAgc_AddMic(void *state, WebRtc_Word16 *in_mic, WebRtc_Word16 *in_mic_H,
    114                      WebRtc_Word16 samples)
    115 {
    116     WebRtc_Word32 nrg, max_nrg, sample, tmp32;
    117     WebRtc_Word32 *ptr;
    118     WebRtc_UWord16 targetGainIdx, gain;
    119     WebRtc_Word16 i, n, L, M, subFrames, tmp16, tmp_speech[16];
    120     Agc_t *stt;
    121     stt = (Agc_t *)state;
    122 
    123     //default/initial values corresponding to 10ms for wb and swb
    124     M = 10;
    125     L = 16;
    126     subFrames = 160;
    127 
    128     if (stt->fs == 8000)
    129     {
    130         if (samples == 80)
    131         {
    132             subFrames = 80;
    133             M = 10;
    134             L = 8;
    135         } else if (samples == 160)
    136         {
    137             subFrames = 80;
    138             M = 20;
    139             L = 8;
    140         } else
    141         {
    142 #ifdef AGC_DEBUG //test log
    143             fprintf(stt->fpt,
    144                     "AGC->add_mic, frame %d: Invalid number of samples\n\n",
    145                     (stt->fcount + 1));
    146 #endif
    147             return -1;
    148         }
    149     } else if (stt->fs == 16000)
    150     {
    151         if (samples == 160)
    152         {
    153             subFrames = 160;
    154             M = 10;
    155             L = 16;
    156         } else if (samples == 320)
    157         {
    158             subFrames = 160;
    159             M = 20;
    160             L = 16;
    161         } else
    162         {
    163 #ifdef AGC_DEBUG //test log
    164             fprintf(stt->fpt,
    165                     "AGC->add_mic, frame %d: Invalid number of samples\n\n",
    166                     (stt->fcount + 1));
    167 #endif
    168             return -1;
    169         }
    170     } else if (stt->fs == 32000)
    171     {
    172         /* SWB is processed as 160 sample for L and H bands */
    173         if (samples == 160)
    174         {
    175             subFrames = 160;
    176             M = 10;
    177             L = 16;
    178         } else
    179         {
    180 #ifdef AGC_DEBUG
    181             fprintf(stt->fpt,
    182                     "AGC->add_mic, frame %d: Invalid sample rate\n\n",
    183                     (stt->fcount + 1));
    184 #endif
    185             return -1;
    186         }
    187     }
    188 
    189     /* Check for valid pointers based on sampling rate */
    190     if ((stt->fs == 32000) && (in_mic_H == NULL))
    191     {
    192         return -1;
    193     }
    194     /* Check for valid pointer for low band */
    195     if (in_mic == NULL)
    196     {
    197         return -1;
    198     }
    199 
    200     /* apply slowly varying digital gain */
    201     if (stt->micVol > stt->maxAnalog)
    202     {
    203         /* 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 
    326 int 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 
    392 int 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 
    534 void 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 
    586 void 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 
    611 void 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 
    672 void 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 
    703 void 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 
    753 WebRtc_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 
   1240 int 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 
   1382 int 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 
   1438 int 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 
   1467 int 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 
   1494 int 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  */
   1512 int 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 
   1682 int 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