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