LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/audio_processing/agc/legacy - analog_agc.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 540 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : /* analog_agc.c
      12             :  *
      13             :  * Using a feedback system, determines an appropriate analog volume level
      14             :  * given an input signal and current volume level. Targets a conservative
      15             :  * signal level and is intended for use with a digital AGC to apply
      16             :  * additional gain.
      17             :  *
      18             :  */
      19             : 
      20             : #include "webrtc/modules/audio_processing/agc/legacy/analog_agc.h"
      21             : 
      22             : #include <stdlib.h>
      23             : #ifdef WEBRTC_AGC_DEBUG_DUMP
      24             : #include <stdio.h>
      25             : #endif
      26             : 
      27             : #include "webrtc/base/checks.h"
      28             : 
      29             : /* The slope of in Q13*/
      30             : static const int16_t kSlope1[8] = {21793, 12517, 7189, 4129,
      31             :                                    2372,  1362,  472,  78};
      32             : 
      33             : /* The offset in Q14 */
      34             : static const int16_t kOffset1[8] = {25395, 23911, 22206, 20737,
      35             :                                     19612, 18805, 17951, 17367};
      36             : 
      37             : /* The slope of in Q13*/
      38             : static const int16_t kSlope2[8] = {2063, 1731, 1452, 1218, 1021, 857, 597, 337};
      39             : 
      40             : /* The offset in Q14 */
      41             : static const int16_t kOffset2[8] = {18432, 18379, 18290, 18177,
      42             :                                     18052, 17920, 17670, 17286};
      43             : 
      44             : static const int16_t kMuteGuardTimeMs = 8000;
      45             : static const int16_t kInitCheck = 42;
      46             : static const size_t kNumSubframes = 10;
      47             : 
      48             : /* Default settings if config is not used */
      49             : #define AGC_DEFAULT_TARGET_LEVEL 3
      50             : #define AGC_DEFAULT_COMP_GAIN 9
      51             : /* This is the target level for the analog part in ENV scale. To convert to RMS
      52             :  * scale you
      53             :  * have to add OFFSET_ENV_TO_RMS.
      54             :  */
      55             : #define ANALOG_TARGET_LEVEL 11
      56             : #define ANALOG_TARGET_LEVEL_2 5  // ANALOG_TARGET_LEVEL / 2
      57             : /* Offset between RMS scale (analog part) and ENV scale (digital part). This
      58             :  * value actually
      59             :  * varies with the FIXED_ANALOG_TARGET_LEVEL, hence we should in the future
      60             :  * replace it with
      61             :  * a table.
      62             :  */
      63             : #define OFFSET_ENV_TO_RMS 9
      64             : /* The reference input level at which the digital part gives an output of
      65             :  * targetLevelDbfs
      66             :  * (desired level) if we have no compression gain. This level should be set high
      67             :  * enough not
      68             :  * to compress the peaks due to the dynamics.
      69             :  */
      70             : #define DIGITAL_REF_AT_0_COMP_GAIN 4
      71             : /* Speed of reference level decrease.
      72             :  */
      73             : #define DIFF_REF_TO_ANALOG 5
      74             : 
      75             : #ifdef MIC_LEVEL_FEEDBACK
      76             : #define NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET 7
      77             : #endif
      78             : /* Size of analog gain table */
      79             : #define GAIN_TBL_LEN 32
      80             : /* Matlab code:
      81             :  * fprintf(1, '\t%i, %i, %i, %i,\n', round(10.^(linspace(0,10,32)/20) * 2^12));
      82             :  */
      83             : /* Q12 */
      84             : static const uint16_t kGainTableAnalog[GAIN_TBL_LEN] = {
      85             :     4096, 4251, 4412, 4579,  4752,  4932,  5118,  5312,  5513,  5722, 5938,
      86             :     6163, 6396, 6638, 6889,  7150,  7420,  7701,  7992,  8295,  8609, 8934,
      87             :     9273, 9623, 9987, 10365, 10758, 11165, 11587, 12025, 12480, 12953};
      88             : 
      89             : /* Gain/Suppression tables for virtual Mic (in Q10) */
      90             : static const uint16_t kGainTableVirtualMic[128] = {
      91             :     1052,  1081,  1110,  1141,  1172,  1204,  1237,  1271,  1305,  1341,  1378,
      92             :     1416,  1454,  1494,  1535,  1577,  1620,  1664,  1710,  1757,  1805,  1854,
      93             :     1905,  1957,  2010,  2065,  2122,  2180,  2239,  2301,  2364,  2428,  2495,
      94             :     2563,  2633,  2705,  2779,  2855,  2933,  3013,  3096,  3180,  3267,  3357,
      95             :     3449,  3543,  3640,  3739,  3842,  3947,  4055,  4166,  4280,  4397,  4517,
      96             :     4640,  4767,  4898,  5032,  5169,  5311,  5456,  5605,  5758,  5916,  6078,
      97             :     6244,  6415,  6590,  6770,  6956,  7146,  7341,  7542,  7748,  7960,  8178,
      98             :     8402,  8631,  8867,  9110,  9359,  9615,  9878,  10148, 10426, 10711, 11004,
      99             :     11305, 11614, 11932, 12258, 12593, 12938, 13292, 13655, 14029, 14412, 14807,
     100             :     15212, 15628, 16055, 16494, 16945, 17409, 17885, 18374, 18877, 19393, 19923,
     101             :     20468, 21028, 21603, 22194, 22801, 23425, 24065, 24724, 25400, 26095, 26808,
     102             :     27541, 28295, 29069, 29864, 30681, 31520, 32382};
     103             : static const uint16_t kSuppressionTableVirtualMic[128] = {
     104             :     1024, 1006, 988, 970, 952, 935, 918, 902, 886, 870, 854, 839, 824, 809, 794,
     105             :     780,  766,  752, 739, 726, 713, 700, 687, 675, 663, 651, 639, 628, 616, 605,
     106             :     594,  584,  573, 563, 553, 543, 533, 524, 514, 505, 496, 487, 478, 470, 461,
     107             :     453,  445,  437, 429, 421, 414, 406, 399, 392, 385, 378, 371, 364, 358, 351,
     108             :     345,  339,  333, 327, 321, 315, 309, 304, 298, 293, 288, 283, 278, 273, 268,
     109             :     263,  258,  254, 249, 244, 240, 236, 232, 227, 223, 219, 215, 211, 208, 204,
     110             :     200,  197,  193, 190, 186, 183, 180, 176, 173, 170, 167, 164, 161, 158, 155,
     111             :     153,  150,  147, 145, 142, 139, 137, 134, 132, 130, 127, 125, 123, 121, 118,
     112             :     116,  114,  112, 110, 108, 106, 104, 102};
     113             : 
     114             : /* Table for target energy levels. Values in Q(-7)
     115             :  * Matlab code
     116             :  * targetLevelTable = fprintf('%d,\t%d,\t%d,\t%d,\n',
     117             :  * round((32767*10.^(-(0:63)'/20)).^2*16/2^7) */
     118             : 
     119             : static const int32_t kTargetLevelTable[64] = {
     120             :     134209536, 106606424, 84680493, 67264106, 53429779, 42440782, 33711911,
     121             :     26778323,  21270778,  16895980, 13420954, 10660642, 8468049,  6726411,
     122             :     5342978,   4244078,   3371191,  2677832,  2127078,  1689598,  1342095,
     123             :     1066064,   846805,    672641,   534298,   424408,   337119,   267783,
     124             :     212708,    168960,    134210,   106606,   84680,    67264,    53430,
     125             :     42441,     33712,     26778,    21271,    16896,    13421,    10661,
     126             :     8468,      6726,      5343,     4244,     3371,     2678,     2127,
     127             :     1690,      1342,      1066,     847,      673,      534,      424,
     128             :     337,       268,       213,      169,      134,      107,      85,
     129             :     67};
     130             : 
     131           0 : int WebRtcAgc_AddMic(void* state,
     132             :                      int16_t* const* in_mic,
     133             :                      size_t num_bands,
     134             :                      size_t samples) {
     135             :   int32_t nrg, max_nrg, sample, tmp32;
     136             :   int32_t* ptr;
     137             :   uint16_t targetGainIdx, gain;
     138             :   size_t i;
     139             :   int16_t n, L, tmp16, tmp_speech[16];
     140             :   LegacyAgc* stt;
     141           0 :   stt = (LegacyAgc*)state;
     142             : 
     143           0 :   if (stt->fs == 8000) {
     144           0 :     L = 8;
     145           0 :     if (samples != 80) {
     146           0 :       return -1;
     147             :     }
     148             :   } else {
     149           0 :     L = 16;
     150           0 :     if (samples != 160) {
     151           0 :       return -1;
     152             :     }
     153             :   }
     154             : 
     155             :   /* apply slowly varying digital gain */
     156           0 :   if (stt->micVol > stt->maxAnalog) {
     157             :     /* |maxLevel| is strictly >= |micVol|, so this condition should be
     158             :      * satisfied here, ensuring there is no divide-by-zero. */
     159           0 :     RTC_DCHECK_GT(stt->maxLevel, stt->maxAnalog);
     160             : 
     161             :     /* Q1 */
     162           0 :     tmp16 = (int16_t)(stt->micVol - stt->maxAnalog);
     163           0 :     tmp32 = (GAIN_TBL_LEN - 1) * tmp16;
     164           0 :     tmp16 = (int16_t)(stt->maxLevel - stt->maxAnalog);
     165           0 :     targetGainIdx = tmp32 / tmp16;
     166           0 :     RTC_DCHECK_LT(targetGainIdx, GAIN_TBL_LEN);
     167             : 
     168             :     /* Increment through the table towards the target gain.
     169             :      * If micVol drops below maxAnalog, we allow the gain
     170             :      * to be dropped immediately. */
     171           0 :     if (stt->gainTableIdx < targetGainIdx) {
     172           0 :       stt->gainTableIdx++;
     173           0 :     } else if (stt->gainTableIdx > targetGainIdx) {
     174           0 :       stt->gainTableIdx--;
     175             :     }
     176             : 
     177             :     /* Q12 */
     178           0 :     gain = kGainTableAnalog[stt->gainTableIdx];
     179             : 
     180           0 :     for (i = 0; i < samples; i++) {
     181             :       size_t j;
     182           0 :       for (j = 0; j < num_bands; ++j) {
     183           0 :         sample = (in_mic[j][i] * gain) >> 12;
     184           0 :         if (sample > 32767) {
     185           0 :           in_mic[j][i] = 32767;
     186           0 :         } else if (sample < -32768) {
     187           0 :           in_mic[j][i] = -32768;
     188             :         } else {
     189           0 :           in_mic[j][i] = (int16_t)sample;
     190             :         }
     191             :       }
     192             :     }
     193             :   } else {
     194           0 :     stt->gainTableIdx = 0;
     195             :   }
     196             : 
     197             :   /* compute envelope */
     198           0 :   if (stt->inQueue > 0) {
     199           0 :     ptr = stt->env[1];
     200             :   } else {
     201           0 :     ptr = stt->env[0];
     202             :   }
     203             : 
     204           0 :   for (i = 0; i < kNumSubframes; i++) {
     205             :     /* iterate over samples */
     206           0 :     max_nrg = 0;
     207           0 :     for (n = 0; n < L; n++) {
     208           0 :       nrg = in_mic[0][i * L + n] * in_mic[0][i * L + n];
     209           0 :       if (nrg > max_nrg) {
     210           0 :         max_nrg = nrg;
     211             :       }
     212             :     }
     213           0 :     ptr[i] = max_nrg;
     214             :   }
     215             : 
     216             :   /* compute energy */
     217           0 :   if (stt->inQueue > 0) {
     218           0 :     ptr = stt->Rxx16w32_array[1];
     219             :   } else {
     220           0 :     ptr = stt->Rxx16w32_array[0];
     221             :   }
     222             : 
     223           0 :   for (i = 0; i < kNumSubframes / 2; i++) {
     224           0 :     if (stt->fs == 16000) {
     225           0 :       WebRtcSpl_DownsampleBy2(&in_mic[0][i * 32], 32, tmp_speech,
     226           0 :                               stt->filterState);
     227             :     } else {
     228           0 :       memcpy(tmp_speech, &in_mic[0][i * 16], 16 * sizeof(short));
     229             :     }
     230             :     /* Compute energy in blocks of 16 samples */
     231           0 :     ptr[i] = WebRtcSpl_DotProductWithScale(tmp_speech, tmp_speech, 16, 4);
     232             :   }
     233             : 
     234             :   /* update queue information */
     235           0 :   if (stt->inQueue == 0) {
     236           0 :     stt->inQueue = 1;
     237             :   } else {
     238           0 :     stt->inQueue = 2;
     239             :   }
     240             : 
     241             :   /* call VAD (use low band only) */
     242           0 :   WebRtcAgc_ProcessVad(&stt->vadMic, in_mic[0], samples);
     243             : 
     244           0 :   return 0;
     245             : }
     246             : 
     247           0 : int WebRtcAgc_AddFarend(void* state, const int16_t* in_far, size_t samples) {
     248           0 :   LegacyAgc* stt = (LegacyAgc*)state;
     249             : 
     250           0 :   int err = WebRtcAgc_GetAddFarendError(state, samples);
     251             : 
     252           0 :   if (err != 0)
     253           0 :     return err;
     254             : 
     255           0 :   return WebRtcAgc_AddFarendToDigital(&stt->digitalAgc, in_far, samples);
     256             : }
     257             : 
     258           0 : int WebRtcAgc_GetAddFarendError(void* state, size_t samples) {
     259             :   LegacyAgc* stt;
     260           0 :   stt = (LegacyAgc*)state;
     261             : 
     262           0 :   if (stt == NULL)
     263           0 :     return -1;
     264             : 
     265           0 :   if (stt->fs == 8000) {
     266           0 :     if (samples != 80)
     267           0 :       return -1;
     268           0 :   } else if (stt->fs == 16000 || stt->fs == 32000 || stt->fs == 48000) {
     269           0 :     if (samples != 160)
     270           0 :       return -1;
     271             :   } else {
     272           0 :     return -1;
     273             :   }
     274             : 
     275           0 :   return 0;
     276             : }
     277             : 
     278           0 : int WebRtcAgc_VirtualMic(void* agcInst,
     279             :                          int16_t* const* in_near,
     280             :                          size_t num_bands,
     281             :                          size_t samples,
     282             :                          int32_t micLevelIn,
     283             :                          int32_t* micLevelOut) {
     284             :   int32_t tmpFlt, micLevelTmp, gainIdx;
     285             :   uint16_t gain;
     286             :   size_t ii, j;
     287             :   LegacyAgc* stt;
     288             : 
     289             :   uint32_t nrg;
     290             :   size_t sampleCntr;
     291           0 :   uint32_t frameNrg = 0;
     292           0 :   uint32_t frameNrgLimit = 5500;
     293           0 :   int16_t numZeroCrossing = 0;
     294           0 :   const int16_t kZeroCrossingLowLim = 15;
     295           0 :   const int16_t kZeroCrossingHighLim = 20;
     296             : 
     297           0 :   stt = (LegacyAgc*)agcInst;
     298             : 
     299             :   /*
     300             :    *  Before applying gain decide if this is a low-level signal.
     301             :    *  The idea is that digital AGC will not adapt to low-level
     302             :    *  signals.
     303             :    */
     304           0 :   if (stt->fs != 8000) {
     305           0 :     frameNrgLimit = frameNrgLimit << 1;
     306             :   }
     307             : 
     308           0 :   frameNrg = (uint32_t)(in_near[0][0] * in_near[0][0]);
     309           0 :   for (sampleCntr = 1; sampleCntr < samples; sampleCntr++) {
     310             :     // increment frame energy if it is less than the limit
     311             :     // the correct value of the energy is not important
     312           0 :     if (frameNrg < frameNrgLimit) {
     313           0 :       nrg = (uint32_t)(in_near[0][sampleCntr] * in_near[0][sampleCntr]);
     314           0 :       frameNrg += nrg;
     315             :     }
     316             : 
     317             :     // Count the zero crossings
     318           0 :     numZeroCrossing +=
     319           0 :         ((in_near[0][sampleCntr] ^ in_near[0][sampleCntr - 1]) < 0);
     320             :   }
     321             : 
     322           0 :   if ((frameNrg < 500) || (numZeroCrossing <= 5)) {
     323           0 :     stt->lowLevelSignal = 1;
     324           0 :   } else if (numZeroCrossing <= kZeroCrossingLowLim) {
     325           0 :     stt->lowLevelSignal = 0;
     326           0 :   } else if (frameNrg <= frameNrgLimit) {
     327           0 :     stt->lowLevelSignal = 1;
     328           0 :   } else if (numZeroCrossing >= kZeroCrossingHighLim) {
     329           0 :     stt->lowLevelSignal = 1;
     330             :   } else {
     331           0 :     stt->lowLevelSignal = 0;
     332             :   }
     333             : 
     334           0 :   micLevelTmp = micLevelIn << stt->scale;
     335             :   /* Set desired level */
     336           0 :   gainIdx = stt->micVol;
     337           0 :   if (stt->micVol > stt->maxAnalog) {
     338           0 :     gainIdx = stt->maxAnalog;
     339             :   }
     340           0 :   if (micLevelTmp != stt->micRef) {
     341             :     /* Something has happened with the physical level, restart. */
     342           0 :     stt->micRef = micLevelTmp;
     343           0 :     stt->micVol = 127;
     344           0 :     *micLevelOut = 127;
     345           0 :     stt->micGainIdx = 127;
     346           0 :     gainIdx = 127;
     347             :   }
     348             :   /* Pre-process the signal to emulate the microphone level. */
     349             :   /* Take one step at a time in the gain table. */
     350           0 :   if (gainIdx > 127) {
     351           0 :     gain = kGainTableVirtualMic[gainIdx - 128];
     352             :   } else {
     353           0 :     gain = kSuppressionTableVirtualMic[127 - gainIdx];
     354             :   }
     355           0 :   for (ii = 0; ii < samples; ii++) {
     356           0 :     tmpFlt = (in_near[0][ii] * gain) >> 10;
     357           0 :     if (tmpFlt > 32767) {
     358           0 :       tmpFlt = 32767;
     359           0 :       gainIdx--;
     360           0 :       if (gainIdx >= 127) {
     361           0 :         gain = kGainTableVirtualMic[gainIdx - 127];
     362             :       } else {
     363           0 :         gain = kSuppressionTableVirtualMic[127 - gainIdx];
     364             :       }
     365             :     }
     366           0 :     if (tmpFlt < -32768) {
     367           0 :       tmpFlt = -32768;
     368           0 :       gainIdx--;
     369           0 :       if (gainIdx >= 127) {
     370           0 :         gain = kGainTableVirtualMic[gainIdx - 127];
     371             :       } else {
     372           0 :         gain = kSuppressionTableVirtualMic[127 - gainIdx];
     373             :       }
     374             :     }
     375           0 :     in_near[0][ii] = (int16_t)tmpFlt;
     376           0 :     for (j = 1; j < num_bands; ++j) {
     377           0 :       tmpFlt = (in_near[j][ii] * gain) >> 10;
     378           0 :       if (tmpFlt > 32767) {
     379           0 :         tmpFlt = 32767;
     380             :       }
     381           0 :       if (tmpFlt < -32768) {
     382           0 :         tmpFlt = -32768;
     383             :       }
     384           0 :       in_near[j][ii] = (int16_t)tmpFlt;
     385             :     }
     386             :   }
     387             :   /* Set the level we (finally) used */
     388           0 :   stt->micGainIdx = gainIdx;
     389             :   //    *micLevelOut = stt->micGainIdx;
     390           0 :   *micLevelOut = stt->micGainIdx >> stt->scale;
     391             :   /* Add to Mic as if it was the output from a true microphone */
     392           0 :   if (WebRtcAgc_AddMic(agcInst, in_near, num_bands, samples) != 0) {
     393           0 :     return -1;
     394             :   }
     395           0 :   return 0;
     396             : }
     397             : 
     398           0 : void WebRtcAgc_UpdateAgcThresholds(LegacyAgc* stt) {
     399             :   int16_t tmp16;
     400             : #ifdef MIC_LEVEL_FEEDBACK
     401             :   int zeros;
     402             : 
     403             :   if (stt->micLvlSat) {
     404             :     /* Lower the analog target level since we have reached its maximum */
     405             :     zeros = WebRtcSpl_NormW32(stt->Rxx160_LPw32);
     406             :     stt->targetIdxOffset = (3 * zeros - stt->targetIdx - 2) / 4;
     407             :   }
     408             : #endif
     409             : 
     410             :   /* Set analog target level in envelope dBOv scale */
     411           0 :   tmp16 = (DIFF_REF_TO_ANALOG * stt->compressionGaindB) + ANALOG_TARGET_LEVEL_2;
     412           0 :   tmp16 = WebRtcSpl_DivW32W16ResW16((int32_t)tmp16, ANALOG_TARGET_LEVEL);
     413           0 :   stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN + tmp16;
     414           0 :   if (stt->analogTarget < DIGITAL_REF_AT_0_COMP_GAIN) {
     415           0 :     stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN;
     416             :   }
     417           0 :   if (stt->agcMode == kAgcModeFixedDigital) {
     418             :     /* Adjust for different parameter interpretation in FixedDigital mode */
     419           0 :     stt->analogTarget = stt->compressionGaindB;
     420             :   }
     421             : #ifdef MIC_LEVEL_FEEDBACK
     422             :   stt->analogTarget += stt->targetIdxOffset;
     423             : #endif
     424             :   /* Since the offset between RMS and ENV is not constant, we should make this
     425             :    * into a
     426             :    * table, but for now, we'll stick with a constant, tuned for the chosen
     427             :    * analog
     428             :    * target level.
     429             :    */
     430           0 :   stt->targetIdx = ANALOG_TARGET_LEVEL + OFFSET_ENV_TO_RMS;
     431             : #ifdef MIC_LEVEL_FEEDBACK
     432             :   stt->targetIdx += stt->targetIdxOffset;
     433             : #endif
     434             :   /* Analog adaptation limits */
     435             :   /* analogTargetLevel = round((32767*10^(-targetIdx/20))^2*16/2^7) */
     436           0 :   stt->analogTargetLevel =
     437           0 :       RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx]; /* ex. -20 dBov */
     438           0 :   stt->startUpperLimit =
     439           0 :       RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 1]; /* -19 dBov */
     440           0 :   stt->startLowerLimit =
     441           0 :       RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 1]; /* -21 dBov */
     442           0 :   stt->upperPrimaryLimit =
     443           0 :       RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 2]; /* -18 dBov */
     444           0 :   stt->lowerPrimaryLimit =
     445           0 :       RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 2]; /* -22 dBov */
     446           0 :   stt->upperSecondaryLimit =
     447           0 :       RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 5]; /* -15 dBov */
     448           0 :   stt->lowerSecondaryLimit =
     449           0 :       RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 5]; /* -25 dBov */
     450           0 :   stt->upperLimit = stt->startUpperLimit;
     451           0 :   stt->lowerLimit = stt->startLowerLimit;
     452           0 : }
     453             : 
     454           0 : void WebRtcAgc_SaturationCtrl(LegacyAgc* stt,
     455             :                               uint8_t* saturated,
     456             :                               int32_t* env) {
     457             :   int16_t i, tmpW16;
     458             : 
     459             :   /* Check if the signal is saturated */
     460           0 :   for (i = 0; i < 10; i++) {
     461           0 :     tmpW16 = (int16_t)(env[i] >> 20);
     462           0 :     if (tmpW16 > 875) {
     463           0 :       stt->envSum += tmpW16;
     464             :     }
     465             :   }
     466             : 
     467           0 :   if (stt->envSum > 25000) {
     468           0 :     *saturated = 1;
     469           0 :     stt->envSum = 0;
     470             :   }
     471             : 
     472             :   /* stt->envSum *= 0.99; */
     473           0 :   stt->envSum = (int16_t)((stt->envSum * 32440) >> 15);
     474           0 : }
     475             : 
     476           0 : void WebRtcAgc_ZeroCtrl(LegacyAgc* stt, int32_t* inMicLevel, int32_t* env) {
     477             :   int16_t i;
     478           0 :   int64_t tmp = 0;
     479             :   int32_t midVal;
     480             : 
     481             :   /* Is the input signal zero? */
     482           0 :   for (i = 0; i < 10; i++) {
     483           0 :     tmp += env[i];
     484             :   }
     485             : 
     486             :   /* Each block is allowed to have a few non-zero
     487             :    * samples.
     488             :    */
     489           0 :   if (tmp < 500) {
     490           0 :     stt->msZero += 10;
     491             :   } else {
     492           0 :     stt->msZero = 0;
     493             :   }
     494             : 
     495           0 :   if (stt->muteGuardMs > 0) {
     496           0 :     stt->muteGuardMs -= 10;
     497             :   }
     498             : 
     499           0 :   if (stt->msZero > 500) {
     500           0 :     stt->msZero = 0;
     501             : 
     502             :     /* Increase microphone level only if it's less than 50% */
     503           0 :     midVal = (stt->maxAnalog + stt->minLevel + 1) / 2;
     504           0 :     if (*inMicLevel < midVal) {
     505             :       /* *inMicLevel *= 1.1; */
     506           0 :       *inMicLevel = (1126 * *inMicLevel) >> 10;
     507             :       /* Reduces risk of a muted mic repeatedly triggering excessive levels due
     508             :        * to zero signal detection. */
     509           0 :       *inMicLevel = WEBRTC_SPL_MIN(*inMicLevel, stt->zeroCtrlMax);
     510           0 :       stt->micVol = *inMicLevel;
     511             :     }
     512             : 
     513             : #ifdef WEBRTC_AGC_DEBUG_DUMP
     514             :     fprintf(stt->fpt,
     515             :             "\t\tAGC->zeroCntrl, frame %d: 500 ms under threshold,"
     516             :             " micVol: %d\n",
     517             :             stt->fcount, stt->micVol);
     518             : #endif
     519             : 
     520           0 :     stt->activeSpeech = 0;
     521           0 :     stt->Rxx16_LPw32Max = 0;
     522             : 
     523             :     /* The AGC has a tendency (due to problems with the VAD parameters), to
     524             :      * vastly increase the volume after a muting event. This timer prevents
     525             :      * upwards adaptation for a short period. */
     526           0 :     stt->muteGuardMs = kMuteGuardTimeMs;
     527             :   }
     528           0 : }
     529             : 
     530           0 : void WebRtcAgc_SpeakerInactiveCtrl(LegacyAgc* stt) {
     531             :   /* Check if the near end speaker is inactive.
     532             :    * If that is the case the VAD threshold is
     533             :    * increased since the VAD speech model gets
     534             :    * more sensitive to any sound after a long
     535             :    * silence.
     536             :    */
     537             : 
     538             :   int32_t tmp32;
     539             :   int16_t vadThresh;
     540             : 
     541           0 :   if (stt->vadMic.stdLongTerm < 2500) {
     542           0 :     stt->vadThreshold = 1500;
     543             :   } else {
     544           0 :     vadThresh = kNormalVadThreshold;
     545           0 :     if (stt->vadMic.stdLongTerm < 4500) {
     546             :       /* Scale between min and max threshold */
     547           0 :       vadThresh += (4500 - stt->vadMic.stdLongTerm) / 2;
     548             :     }
     549             : 
     550             :     /* stt->vadThreshold = (31 * stt->vadThreshold + vadThresh) / 32; */
     551           0 :     tmp32 = vadThresh + 31 * stt->vadThreshold;
     552           0 :     stt->vadThreshold = (int16_t)(tmp32 >> 5);
     553             :   }
     554           0 : }
     555             : 
     556           0 : void WebRtcAgc_ExpCurve(int16_t volume, int16_t* index) {
     557             :   // volume in Q14
     558             :   // index in [0-7]
     559             :   /* 8 different curves */
     560           0 :   if (volume > 5243) {
     561           0 :     if (volume > 7864) {
     562           0 :       if (volume > 12124) {
     563           0 :         *index = 7;
     564             :       } else {
     565           0 :         *index = 6;
     566             :       }
     567             :     } else {
     568           0 :       if (volume > 6554) {
     569           0 :         *index = 5;
     570             :       } else {
     571           0 :         *index = 4;
     572             :       }
     573             :     }
     574             :   } else {
     575           0 :     if (volume > 2621) {
     576           0 :       if (volume > 3932) {
     577           0 :         *index = 3;
     578             :       } else {
     579           0 :         *index = 2;
     580             :       }
     581             :     } else {
     582           0 :       if (volume > 1311) {
     583           0 :         *index = 1;
     584             :       } else {
     585           0 :         *index = 0;
     586             :       }
     587             :     }
     588             :   }
     589           0 : }
     590             : 
     591           0 : int32_t WebRtcAgc_ProcessAnalog(void* state,
     592             :                                 int32_t inMicLevel,
     593             :                                 int32_t* outMicLevel,
     594             :                                 int16_t vadLogRatio,
     595             :                                 int16_t echo,
     596             :                                 uint8_t* saturationWarning) {
     597             :   uint32_t tmpU32;
     598             :   int32_t Rxx16w32, tmp32;
     599             :   int32_t inMicLevelTmp, lastMicVol;
     600             :   int16_t i;
     601           0 :   uint8_t saturated = 0;
     602             :   LegacyAgc* stt;
     603             : 
     604           0 :   stt = (LegacyAgc*)state;
     605           0 :   inMicLevelTmp = inMicLevel << stt->scale;
     606             : 
     607           0 :   if (inMicLevelTmp > stt->maxAnalog) {
     608             : #ifdef WEBRTC_AGC_DEBUG_DUMP
     609             :     fprintf(stt->fpt, "\tAGC->ProcessAnalog, frame %d: micLvl > maxAnalog\n",
     610             :             stt->fcount);
     611             : #endif
     612           0 :     return -1;
     613           0 :   } else if (inMicLevelTmp < stt->minLevel) {
     614             : #ifdef WEBRTC_AGC_DEBUG_DUMP
     615             :     fprintf(stt->fpt, "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel\n",
     616             :             stt->fcount);
     617             : #endif
     618           0 :     return -1;
     619             :   }
     620             : 
     621           0 :   if (stt->firstCall == 0) {
     622             :     int32_t tmpVol;
     623           0 :     stt->firstCall = 1;
     624           0 :     tmp32 = ((stt->maxLevel - stt->minLevel) * 51) >> 9;
     625           0 :     tmpVol = (stt->minLevel + tmp32);
     626             : 
     627             :     /* If the mic level is very low at start, increase it! */
     628           0 :     if ((inMicLevelTmp < tmpVol) && (stt->agcMode == kAgcModeAdaptiveAnalog)) {
     629           0 :       inMicLevelTmp = tmpVol;
     630             :     }
     631           0 :     stt->micVol = inMicLevelTmp;
     632             :   }
     633             : 
     634             :   /* Set the mic level to the previous output value if there is digital input
     635             :    * gain */
     636           0 :   if ((inMicLevelTmp == stt->maxAnalog) && (stt->micVol > stt->maxAnalog)) {
     637           0 :     inMicLevelTmp = stt->micVol;
     638             :   }
     639             : 
     640             :   /* If the mic level was manually changed to a very low value raise it! */
     641           0 :   if ((inMicLevelTmp != stt->micVol) && (inMicLevelTmp < stt->minOutput)) {
     642           0 :     tmp32 = ((stt->maxLevel - stt->minLevel) * 51) >> 9;
     643           0 :     inMicLevelTmp = (stt->minLevel + tmp32);
     644           0 :     stt->micVol = inMicLevelTmp;
     645             : #ifdef MIC_LEVEL_FEEDBACK
     646             : // stt->numBlocksMicLvlSat = 0;
     647             : #endif
     648             : #ifdef WEBRTC_AGC_DEBUG_DUMP
     649             :     fprintf(stt->fpt,
     650             :             "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel by manual"
     651             :             " decrease, raise vol\n",
     652             :             stt->fcount);
     653             : #endif
     654             :   }
     655             : 
     656           0 :   if (inMicLevelTmp != stt->micVol) {
     657           0 :     if (inMicLevel == stt->lastInMicLevel) {
     658             :       // We requested a volume adjustment, but it didn't occur. This is
     659             :       // probably due to a coarse quantization of the volume slider.
     660             :       // Restore the requested value to prevent getting stuck.
     661           0 :       inMicLevelTmp = stt->micVol;
     662             :     } else {
     663             :       // As long as the value changed, update to match.
     664           0 :       stt->micVol = inMicLevelTmp;
     665             :     }
     666             :   }
     667             : 
     668           0 :   if (inMicLevelTmp > stt->maxLevel) {
     669             :     // Always allow the user to raise the volume above the maxLevel.
     670           0 :     stt->maxLevel = inMicLevelTmp;
     671             :   }
     672             : 
     673             :   // Store last value here, after we've taken care of manual updates etc.
     674           0 :   stt->lastInMicLevel = inMicLevel;
     675           0 :   lastMicVol = stt->micVol;
     676             : 
     677             :   /* Checks if the signal is saturated. Also a check if individual samples
     678             :    * are larger than 12000 is done. If they are the counter for increasing
     679             :    * the volume level is set to -100ms
     680             :    */
     681           0 :   WebRtcAgc_SaturationCtrl(stt, &saturated, stt->env[0]);
     682             : 
     683             :   /* The AGC is always allowed to lower the level if the signal is saturated */
     684           0 :   if (saturated == 1) {
     685             :     /* Lower the recording level
     686             :      * Rxx160_LP is adjusted down because it is so slow it could
     687             :      * cause the AGC to make wrong decisions. */
     688             :     /* stt->Rxx160_LPw32 *= 0.875; */
     689           0 :     stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 8) * 7;
     690             : 
     691           0 :     stt->zeroCtrlMax = stt->micVol;
     692             : 
     693             :     /* stt->micVol *= 0.903; */
     694           0 :     tmp32 = inMicLevelTmp - stt->minLevel;
     695           0 :     tmpU32 = WEBRTC_SPL_UMUL(29591, (uint32_t)(tmp32));
     696           0 :     stt->micVol = (tmpU32 >> 15) + stt->minLevel;
     697           0 :     if (stt->micVol > lastMicVol - 2) {
     698           0 :       stt->micVol = lastMicVol - 2;
     699             :     }
     700           0 :     inMicLevelTmp = stt->micVol;
     701             : 
     702             : #ifdef WEBRTC_AGC_DEBUG_DUMP
     703             :     fprintf(stt->fpt,
     704             :             "\tAGC->ProcessAnalog, frame %d: saturated, micVol = %d\n",
     705             :             stt->fcount, stt->micVol);
     706             : #endif
     707             : 
     708           0 :     if (stt->micVol < stt->minOutput) {
     709           0 :       *saturationWarning = 1;
     710             :     }
     711             : 
     712             :     /* Reset counter for decrease of volume level to avoid
     713             :      * decreasing too much. The saturation control can still
     714             :      * lower the level if needed. */
     715           0 :     stt->msTooHigh = -100;
     716             : 
     717             :     /* Enable the control mechanism to ensure that our measure,
     718             :      * Rxx160_LP, is in the correct range. This must be done since
     719             :      * the measure is very slow. */
     720           0 :     stt->activeSpeech = 0;
     721           0 :     stt->Rxx16_LPw32Max = 0;
     722             : 
     723             :     /* Reset to initial values */
     724           0 :     stt->msecSpeechInnerChange = kMsecSpeechInner;
     725           0 :     stt->msecSpeechOuterChange = kMsecSpeechOuter;
     726           0 :     stt->changeToSlowMode = 0;
     727             : 
     728           0 :     stt->muteGuardMs = 0;
     729             : 
     730           0 :     stt->upperLimit = stt->startUpperLimit;
     731           0 :     stt->lowerLimit = stt->startLowerLimit;
     732             : #ifdef MIC_LEVEL_FEEDBACK
     733             : // stt->numBlocksMicLvlSat = 0;
     734             : #endif
     735             :   }
     736             : 
     737             :   /* Check if the input speech is zero. If so the mic volume
     738             :    * is increased. On some computers the input is zero up as high
     739             :    * level as 17% */
     740           0 :   WebRtcAgc_ZeroCtrl(stt, &inMicLevelTmp, stt->env[0]);
     741             : 
     742             :   /* Check if the near end speaker is inactive.
     743             :    * If that is the case the VAD threshold is
     744             :    * increased since the VAD speech model gets
     745             :    * more sensitive to any sound after a long
     746             :    * silence.
     747             :    */
     748           0 :   WebRtcAgc_SpeakerInactiveCtrl(stt);
     749             : 
     750           0 :   for (i = 0; i < 5; i++) {
     751             :     /* Computed on blocks of 16 samples */
     752             : 
     753           0 :     Rxx16w32 = stt->Rxx16w32_array[0][i];
     754             : 
     755             :     /* Rxx160w32 in Q(-7) */
     756           0 :     tmp32 = (Rxx16w32 - stt->Rxx16_vectorw32[stt->Rxx16pos]) >> 3;
     757           0 :     stt->Rxx160w32 = stt->Rxx160w32 + tmp32;
     758           0 :     stt->Rxx16_vectorw32[stt->Rxx16pos] = Rxx16w32;
     759             : 
     760             :     /* Circular buffer */
     761           0 :     stt->Rxx16pos++;
     762           0 :     if (stt->Rxx16pos == RXX_BUFFER_LEN) {
     763           0 :       stt->Rxx16pos = 0;
     764             :     }
     765             : 
     766             :     /* Rxx16_LPw32 in Q(-4) */
     767           0 :     tmp32 = (Rxx16w32 - stt->Rxx16_LPw32) >> kAlphaShortTerm;
     768           0 :     stt->Rxx16_LPw32 = (stt->Rxx16_LPw32) + tmp32;
     769             : 
     770           0 :     if (vadLogRatio > stt->vadThreshold) {
     771             :       /* Speech detected! */
     772             : 
     773             :       /* Check if Rxx160_LP is in the correct range. If
     774             :        * it is too high/low then we set it to the maximum of
     775             :        * Rxx16_LPw32 during the first 200ms of speech.
     776             :        */
     777           0 :       if (stt->activeSpeech < 250) {
     778           0 :         stt->activeSpeech += 2;
     779             : 
     780           0 :         if (stt->Rxx16_LPw32 > stt->Rxx16_LPw32Max) {
     781           0 :           stt->Rxx16_LPw32Max = stt->Rxx16_LPw32;
     782             :         }
     783           0 :       } else if (stt->activeSpeech == 250) {
     784           0 :         stt->activeSpeech += 2;
     785           0 :         tmp32 = stt->Rxx16_LPw32Max >> 3;
     786           0 :         stt->Rxx160_LPw32 = tmp32 * RXX_BUFFER_LEN;
     787             :       }
     788             : 
     789           0 :       tmp32 = (stt->Rxx160w32 - stt->Rxx160_LPw32) >> kAlphaLongTerm;
     790           0 :       stt->Rxx160_LPw32 = stt->Rxx160_LPw32 + tmp32;
     791             : 
     792           0 :       if (stt->Rxx160_LPw32 > stt->upperSecondaryLimit) {
     793           0 :         stt->msTooHigh += 2;
     794           0 :         stt->msTooLow = 0;
     795           0 :         stt->changeToSlowMode = 0;
     796             : 
     797           0 :         if (stt->msTooHigh > stt->msecSpeechOuterChange) {
     798           0 :           stt->msTooHigh = 0;
     799             : 
     800             :           /* Lower the recording level */
     801             :           /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
     802           0 :           tmp32 = stt->Rxx160_LPw32 >> 6;
     803           0 :           stt->Rxx160_LPw32 = tmp32 * 53;
     804             : 
     805             :           /* Reduce the max gain to avoid excessive oscillation
     806             :            * (but never drop below the maximum analog level).
     807             :            */
     808           0 :           stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
     809           0 :           stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
     810             : 
     811           0 :           stt->zeroCtrlMax = stt->micVol;
     812             : 
     813             :           /* 0.95 in Q15 */
     814           0 :           tmp32 = inMicLevelTmp - stt->minLevel;
     815           0 :           tmpU32 = WEBRTC_SPL_UMUL(31130, (uint32_t)(tmp32));
     816           0 :           stt->micVol = (tmpU32 >> 15) + stt->minLevel;
     817           0 :           if (stt->micVol > lastMicVol - 1) {
     818           0 :             stt->micVol = lastMicVol - 1;
     819             :           }
     820           0 :           inMicLevelTmp = stt->micVol;
     821             : 
     822             :           /* Enable the control mechanism to ensure that our measure,
     823             :            * Rxx160_LP, is in the correct range.
     824             :            */
     825           0 :           stt->activeSpeech = 0;
     826           0 :           stt->Rxx16_LPw32Max = 0;
     827             : #ifdef MIC_LEVEL_FEEDBACK
     828             : // stt->numBlocksMicLvlSat = 0;
     829             : #endif
     830             : #ifdef WEBRTC_AGC_DEBUG_DUMP
     831             :           fprintf(stt->fpt,
     832             :                   "\tAGC->ProcessAnalog, frame %d: measure >"
     833             :                   " 2ndUpperLim, micVol = %d, maxLevel = %d\n",
     834             :                   stt->fcount, stt->micVol, stt->maxLevel);
     835             : #endif
     836             :         }
     837           0 :       } else if (stt->Rxx160_LPw32 > stt->upperLimit) {
     838           0 :         stt->msTooHigh += 2;
     839           0 :         stt->msTooLow = 0;
     840           0 :         stt->changeToSlowMode = 0;
     841             : 
     842           0 :         if (stt->msTooHigh > stt->msecSpeechInnerChange) {
     843             :           /* Lower the recording level */
     844           0 :           stt->msTooHigh = 0;
     845             :           /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
     846           0 :           stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 53;
     847             : 
     848             :           /* Reduce the max gain to avoid excessive oscillation
     849             :            * (but never drop below the maximum analog level).
     850             :            */
     851           0 :           stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
     852           0 :           stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
     853             : 
     854           0 :           stt->zeroCtrlMax = stt->micVol;
     855             : 
     856             :           /* 0.965 in Q15 */
     857           0 :           tmp32 = inMicLevelTmp - stt->minLevel;
     858           0 :           tmpU32 =
     859           0 :               WEBRTC_SPL_UMUL(31621, (uint32_t)(inMicLevelTmp - stt->minLevel));
     860           0 :           stt->micVol = (tmpU32 >> 15) + stt->minLevel;
     861           0 :           if (stt->micVol > lastMicVol - 1) {
     862           0 :             stt->micVol = lastMicVol - 1;
     863             :           }
     864           0 :           inMicLevelTmp = stt->micVol;
     865             : 
     866             : #ifdef MIC_LEVEL_FEEDBACK
     867             : // stt->numBlocksMicLvlSat = 0;
     868             : #endif
     869             : #ifdef WEBRTC_AGC_DEBUG_DUMP
     870             :           fprintf(stt->fpt,
     871             :                   "\tAGC->ProcessAnalog, frame %d: measure >"
     872             :                   " UpperLim, micVol = %d, maxLevel = %d\n",
     873             :                   stt->fcount, stt->micVol, stt->maxLevel);
     874             : #endif
     875             :         }
     876           0 :       } else if (stt->Rxx160_LPw32 < stt->lowerSecondaryLimit) {
     877           0 :         stt->msTooHigh = 0;
     878           0 :         stt->changeToSlowMode = 0;
     879           0 :         stt->msTooLow += 2;
     880             : 
     881           0 :         if (stt->msTooLow > stt->msecSpeechOuterChange) {
     882             :           /* Raise the recording level */
     883             :           int16_t index, weightFIX;
     884           0 :           int16_t volNormFIX = 16384;  // =1 in Q14.
     885             : 
     886           0 :           stt->msTooLow = 0;
     887             : 
     888             :           /* Normalize the volume level */
     889           0 :           tmp32 = (inMicLevelTmp - stt->minLevel) << 14;
     890           0 :           if (stt->maxInit != stt->minLevel) {
     891           0 :             volNormFIX = tmp32 / (stt->maxInit - stt->minLevel);
     892             :           }
     893             : 
     894             :           /* Find correct curve */
     895           0 :           WebRtcAgc_ExpCurve(volNormFIX, &index);
     896             : 
     897             :           /* Compute weighting factor for the volume increase, 32^(-2*X)/2+1.05
     898             :            */
     899           0 :           weightFIX =
     900           0 :               kOffset1[index] - (int16_t)((kSlope1[index] * volNormFIX) >> 13);
     901             : 
     902             :           /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
     903           0 :           stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 67;
     904             : 
     905           0 :           tmp32 = inMicLevelTmp - stt->minLevel;
     906           0 :           tmpU32 =
     907           0 :               ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
     908           0 :           stt->micVol = (tmpU32 >> 14) + stt->minLevel;
     909           0 :           if (stt->micVol < lastMicVol + 2) {
     910           0 :             stt->micVol = lastMicVol + 2;
     911             :           }
     912             : 
     913           0 :           inMicLevelTmp = stt->micVol;
     914             : 
     915             : #ifdef MIC_LEVEL_FEEDBACK
     916             :           /* Count ms in level saturation */
     917             :           // if (stt->micVol > stt->maxAnalog) {
     918             :           if (stt->micVol > 150) {
     919             :             /* mic level is saturated */
     920             :             stt->numBlocksMicLvlSat++;
     921             :             fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
     922             :           }
     923             : #endif
     924             : #ifdef WEBRTC_AGC_DEBUG_DUMP
     925             :           fprintf(stt->fpt,
     926             :                   "\tAGC->ProcessAnalog, frame %d: measure <"
     927             :                   " 2ndLowerLim, micVol = %d\n",
     928             :                   stt->fcount, stt->micVol);
     929             : #endif
     930             :         }
     931           0 :       } else if (stt->Rxx160_LPw32 < stt->lowerLimit) {
     932           0 :         stt->msTooHigh = 0;
     933           0 :         stt->changeToSlowMode = 0;
     934           0 :         stt->msTooLow += 2;
     935             : 
     936           0 :         if (stt->msTooLow > stt->msecSpeechInnerChange) {
     937             :           /* Raise the recording level */
     938             :           int16_t index, weightFIX;
     939           0 :           int16_t volNormFIX = 16384;  // =1 in Q14.
     940             : 
     941           0 :           stt->msTooLow = 0;
     942             : 
     943             :           /* Normalize the volume level */
     944           0 :           tmp32 = (inMicLevelTmp - stt->minLevel) << 14;
     945           0 :           if (stt->maxInit != stt->minLevel) {
     946           0 :             volNormFIX = tmp32 / (stt->maxInit - stt->minLevel);
     947             :           }
     948             : 
     949             :           /* Find correct curve */
     950           0 :           WebRtcAgc_ExpCurve(volNormFIX, &index);
     951             : 
     952             :           /* Compute weighting factor for the volume increase, (3.^(-2.*X))/8+1
     953             :            */
     954           0 :           weightFIX =
     955           0 :               kOffset2[index] - (int16_t)((kSlope2[index] * volNormFIX) >> 13);
     956             : 
     957             :           /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
     958           0 :           stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 67;
     959             : 
     960           0 :           tmp32 = inMicLevelTmp - stt->minLevel;
     961           0 :           tmpU32 =
     962           0 :               ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
     963           0 :           stt->micVol = (tmpU32 >> 14) + stt->minLevel;
     964           0 :           if (stt->micVol < lastMicVol + 1) {
     965           0 :             stt->micVol = lastMicVol + 1;
     966             :           }
     967             : 
     968           0 :           inMicLevelTmp = stt->micVol;
     969             : 
     970             : #ifdef MIC_LEVEL_FEEDBACK
     971             :           /* Count ms in level saturation */
     972             :           // if (stt->micVol > stt->maxAnalog) {
     973             :           if (stt->micVol > 150) {
     974             :             /* mic level is saturated */
     975             :             stt->numBlocksMicLvlSat++;
     976             :             fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
     977             :           }
     978             : #endif
     979             : #ifdef WEBRTC_AGC_DEBUG_DUMP
     980             :           fprintf(stt->fpt,
     981             :                   "\tAGC->ProcessAnalog, frame %d: measure < LowerLim, micVol "
     982             :                   "= %d\n",
     983             :                   stt->fcount, stt->micVol);
     984             : #endif
     985             :         }
     986             :       } else {
     987             :         /* The signal is inside the desired range which is:
     988             :          * lowerLimit < Rxx160_LP/640 < upperLimit
     989             :          */
     990           0 :         if (stt->changeToSlowMode > 4000) {
     991           0 :           stt->msecSpeechInnerChange = 1000;
     992           0 :           stt->msecSpeechOuterChange = 500;
     993           0 :           stt->upperLimit = stt->upperPrimaryLimit;
     994           0 :           stt->lowerLimit = stt->lowerPrimaryLimit;
     995             :         } else {
     996           0 :           stt->changeToSlowMode += 2;  // in milliseconds
     997             :         }
     998           0 :         stt->msTooLow = 0;
     999           0 :         stt->msTooHigh = 0;
    1000             : 
    1001           0 :         stt->micVol = inMicLevelTmp;
    1002             :       }
    1003             : #ifdef MIC_LEVEL_FEEDBACK
    1004             :       if (stt->numBlocksMicLvlSat > NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET) {
    1005             :         stt->micLvlSat = 1;
    1006             :         fprintf(stderr, "target before = %d (%d)\n", stt->analogTargetLevel,
    1007             :                 stt->targetIdx);
    1008             :         WebRtcAgc_UpdateAgcThresholds(stt);
    1009             :         WebRtcAgc_CalculateGainTable(
    1010             :             &(stt->digitalAgc.gainTable[0]), stt->compressionGaindB,
    1011             :             stt->targetLevelDbfs, stt->limiterEnable, stt->analogTarget);
    1012             :         stt->numBlocksMicLvlSat = 0;
    1013             :         stt->micLvlSat = 0;
    1014             :         fprintf(stderr, "target offset = %d\n", stt->targetIdxOffset);
    1015             :         fprintf(stderr, "target after  = %d (%d)\n", stt->analogTargetLevel,
    1016             :                 stt->targetIdx);
    1017             :       }
    1018             : #endif
    1019             :     }
    1020             :   }
    1021             : 
    1022             :   /* Ensure gain is not increased in presence of echo or after a mute event
    1023             :    * (but allow the zeroCtrl() increase on the frame of a mute detection).
    1024             :    */
    1025           0 :   if (echo == 1 ||
    1026           0 :       (stt->muteGuardMs > 0 && stt->muteGuardMs < kMuteGuardTimeMs)) {
    1027           0 :     if (stt->micVol > lastMicVol) {
    1028           0 :       stt->micVol = lastMicVol;
    1029             :     }
    1030             :   }
    1031             : 
    1032             :   /* limit the gain */
    1033           0 :   if (stt->micVol > stt->maxLevel) {
    1034           0 :     stt->micVol = stt->maxLevel;
    1035           0 :   } else if (stt->micVol < stt->minOutput) {
    1036           0 :     stt->micVol = stt->minOutput;
    1037             :   }
    1038             : 
    1039           0 :   *outMicLevel = WEBRTC_SPL_MIN(stt->micVol, stt->maxAnalog) >> stt->scale;
    1040             : 
    1041           0 :   return 0;
    1042             : }
    1043             : 
    1044           0 : int WebRtcAgc_Process(void* agcInst,
    1045             :                       const int16_t* const* in_near,
    1046             :                       size_t num_bands,
    1047             :                       size_t samples,
    1048             :                       int16_t* const* out,
    1049             :                       int32_t inMicLevel,
    1050             :                       int32_t* outMicLevel,
    1051             :                       int16_t echo,
    1052             :                       uint8_t* saturationWarning) {
    1053             :   LegacyAgc* stt;
    1054             : 
    1055           0 :   stt = (LegacyAgc*)agcInst;
    1056             : 
    1057             :   //
    1058           0 :   if (stt == NULL) {
    1059           0 :     return -1;
    1060             :   }
    1061             :   //
    1062             : 
    1063           0 :   if (stt->fs == 8000) {
    1064           0 :     if (samples != 80) {
    1065           0 :       return -1;
    1066             :     }
    1067           0 :   } else if (stt->fs == 16000 || stt->fs == 32000 || stt->fs == 48000) {
    1068           0 :     if (samples != 160) {
    1069           0 :       return -1;
    1070             :     }
    1071             :   } else {
    1072           0 :     return -1;
    1073             :   }
    1074             : 
    1075           0 :   *saturationWarning = 0;
    1076             :   // TODO(minyue): PUT IN RANGE CHECKING FOR INPUT LEVELS
    1077           0 :   *outMicLevel = inMicLevel;
    1078             : 
    1079             : #ifdef WEBRTC_AGC_DEBUG_DUMP
    1080             :   stt->fcount++;
    1081             : #endif
    1082             : 
    1083           0 :   if (WebRtcAgc_ProcessDigital(&stt->digitalAgc, in_near, num_bands, out,
    1084           0 :                                stt->fs, stt->lowLevelSignal) == -1) {
    1085             : #ifdef WEBRTC_AGC_DEBUG_DUMP
    1086             :     fprintf(stt->fpt, "AGC->Process, frame %d: Error from DigAGC\n\n",
    1087             :             stt->fcount);
    1088             : #endif
    1089           0 :     return -1;
    1090             :   }
    1091           0 :   if (stt->agcMode < kAgcModeFixedDigital &&
    1092           0 :       (stt->lowLevelSignal == 0 || stt->agcMode != kAgcModeAdaptiveDigital)) {
    1093           0 :     if (WebRtcAgc_ProcessAnalog(agcInst, inMicLevel, outMicLevel,
    1094           0 :                                 stt->vadMic.logRatio, echo,
    1095             :                                 saturationWarning) == -1) {
    1096           0 :       return -1;
    1097             :     }
    1098             :   }
    1099             : #ifdef WEBRTC_AGC_DEBUG_DUMP
    1100             :   fprintf(stt->agcLog, "%5d\t%d\t%d\t%d\t%d\n", stt->fcount, inMicLevel,
    1101             :           *outMicLevel, stt->maxLevel, stt->micVol);
    1102             : #endif
    1103             : 
    1104             :   /* update queue */
    1105           0 :   if (stt->inQueue > 1) {
    1106           0 :     memcpy(stt->env[0], stt->env[1], 10 * sizeof(int32_t));
    1107           0 :     memcpy(stt->Rxx16w32_array[0], stt->Rxx16w32_array[1], 5 * sizeof(int32_t));
    1108             :   }
    1109             : 
    1110           0 :   if (stt->inQueue > 0) {
    1111           0 :     stt->inQueue--;
    1112             :   }
    1113             : 
    1114           0 :   return 0;
    1115             : }
    1116             : 
    1117           0 : int WebRtcAgc_set_config(void* agcInst, WebRtcAgcConfig agcConfig) {
    1118             :   LegacyAgc* stt;
    1119           0 :   stt = (LegacyAgc*)agcInst;
    1120             : 
    1121           0 :   if (stt == NULL) {
    1122           0 :     return -1;
    1123             :   }
    1124             : 
    1125           0 :   if (stt->initFlag != kInitCheck) {
    1126           0 :     stt->lastError = AGC_UNINITIALIZED_ERROR;
    1127           0 :     return -1;
    1128             :   }
    1129             : 
    1130           0 :   if (agcConfig.limiterEnable != kAgcFalse &&
    1131           0 :       agcConfig.limiterEnable != kAgcTrue) {
    1132           0 :     stt->lastError = AGC_BAD_PARAMETER_ERROR;
    1133           0 :     return -1;
    1134             :   }
    1135           0 :   stt->limiterEnable = agcConfig.limiterEnable;
    1136           0 :   stt->compressionGaindB = agcConfig.compressionGaindB;
    1137           0 :   if ((agcConfig.targetLevelDbfs < 0) || (agcConfig.targetLevelDbfs > 31)) {
    1138           0 :     stt->lastError = AGC_BAD_PARAMETER_ERROR;
    1139           0 :     return -1;
    1140             :   }
    1141           0 :   stt->targetLevelDbfs = agcConfig.targetLevelDbfs;
    1142             : 
    1143           0 :   if (stt->agcMode == kAgcModeFixedDigital) {
    1144             :     /* Adjust for different parameter interpretation in FixedDigital mode */
    1145           0 :     stt->compressionGaindB += agcConfig.targetLevelDbfs;
    1146             :   }
    1147             : 
    1148             :   /* Update threshold levels for analog adaptation */
    1149           0 :   WebRtcAgc_UpdateAgcThresholds(stt);
    1150             : 
    1151             :   /* Recalculate gain table */
    1152           0 :   if (WebRtcAgc_CalculateGainTable(
    1153           0 :           &(stt->digitalAgc.gainTable[0]), stt->compressionGaindB,
    1154           0 :           stt->targetLevelDbfs, stt->limiterEnable, stt->analogTarget) == -1) {
    1155             : #ifdef WEBRTC_AGC_DEBUG_DUMP
    1156             :     fprintf(stt->fpt, "AGC->set_config, frame %d: Error from calcGainTable\n\n",
    1157             :             stt->fcount);
    1158             : #endif
    1159           0 :     return -1;
    1160             :   }
    1161             :   /* Store the config in a WebRtcAgcConfig */
    1162           0 :   stt->usedConfig.compressionGaindB = agcConfig.compressionGaindB;
    1163           0 :   stt->usedConfig.limiterEnable = agcConfig.limiterEnable;
    1164           0 :   stt->usedConfig.targetLevelDbfs = agcConfig.targetLevelDbfs;
    1165             : 
    1166           0 :   return 0;
    1167             : }
    1168             : 
    1169           0 : int WebRtcAgc_get_config(void* agcInst, WebRtcAgcConfig* config) {
    1170             :   LegacyAgc* stt;
    1171           0 :   stt = (LegacyAgc*)agcInst;
    1172             : 
    1173           0 :   if (stt == NULL) {
    1174           0 :     return -1;
    1175             :   }
    1176             : 
    1177           0 :   if (config == NULL) {
    1178           0 :     stt->lastError = AGC_NULL_POINTER_ERROR;
    1179           0 :     return -1;
    1180             :   }
    1181             : 
    1182           0 :   if (stt->initFlag != kInitCheck) {
    1183           0 :     stt->lastError = AGC_UNINITIALIZED_ERROR;
    1184           0 :     return -1;
    1185             :   }
    1186             : 
    1187           0 :   config->limiterEnable = stt->usedConfig.limiterEnable;
    1188           0 :   config->targetLevelDbfs = stt->usedConfig.targetLevelDbfs;
    1189           0 :   config->compressionGaindB = stt->usedConfig.compressionGaindB;
    1190             : 
    1191           0 :   return 0;
    1192             : }
    1193             : 
    1194           0 : void* WebRtcAgc_Create() {
    1195           0 :   LegacyAgc* stt = malloc(sizeof(LegacyAgc));
    1196             : 
    1197             : #ifdef WEBRTC_AGC_DEBUG_DUMP
    1198             :   stt->fpt = fopen("./agc_test_log.txt", "wt");
    1199             :   stt->agcLog = fopen("./agc_debug_log.txt", "wt");
    1200             :   stt->digitalAgc.logFile = fopen("./agc_log.txt", "wt");
    1201             : #endif
    1202             : 
    1203           0 :   stt->initFlag = 0;
    1204           0 :   stt->lastError = 0;
    1205             : 
    1206           0 :   return stt;
    1207             : }
    1208             : 
    1209           0 : void WebRtcAgc_Free(void* state) {
    1210             :   LegacyAgc* stt;
    1211             : 
    1212           0 :   stt = (LegacyAgc*)state;
    1213             : #ifdef WEBRTC_AGC_DEBUG_DUMP
    1214             :   fclose(stt->fpt);
    1215             :   fclose(stt->agcLog);
    1216             :   fclose(stt->digitalAgc.logFile);
    1217             : #endif
    1218           0 :   free(stt);
    1219           0 : }
    1220             : 
    1221             : /* minLevel     - Minimum volume level
    1222             :  * maxLevel     - Maximum volume level
    1223             :  */
    1224           0 : int WebRtcAgc_Init(void* agcInst,
    1225             :                    int32_t minLevel,
    1226             :                    int32_t maxLevel,
    1227             :                    int16_t agcMode,
    1228             :                    uint32_t fs) {
    1229             :   int32_t max_add, tmp32;
    1230             :   int16_t i;
    1231             :   int tmpNorm;
    1232             :   LegacyAgc* stt;
    1233             : 
    1234             :   /* typecast state pointer */
    1235           0 :   stt = (LegacyAgc*)agcInst;
    1236             : 
    1237           0 :   if (WebRtcAgc_InitDigital(&stt->digitalAgc, agcMode) != 0) {
    1238           0 :     stt->lastError = AGC_UNINITIALIZED_ERROR;
    1239           0 :     return -1;
    1240             :   }
    1241             : 
    1242             :   /* Analog AGC variables */
    1243           0 :   stt->envSum = 0;
    1244             : 
    1245             : /* mode     = 0 - Only saturation protection
    1246             :  *            1 - Analog Automatic Gain Control [-targetLevelDbfs (default -3
    1247             :  * dBOv)]
    1248             :  *            2 - Digital Automatic Gain Control [-targetLevelDbfs (default -3
    1249             :  * dBOv)]
    1250             :  *            3 - Fixed Digital Gain [compressionGaindB (default 8 dB)]
    1251             :  */
    1252             : #ifdef WEBRTC_AGC_DEBUG_DUMP
    1253             :   stt->fcount = 0;
    1254             :   fprintf(stt->fpt, "AGC->Init\n");
    1255             : #endif
    1256           0 :   if (agcMode < kAgcModeUnchanged || agcMode > kAgcModeFixedDigital) {
    1257             : #ifdef WEBRTC_AGC_DEBUG_DUMP
    1258             :     fprintf(stt->fpt, "AGC->Init: error, incorrect mode\n\n");
    1259             : #endif
    1260           0 :     return -1;
    1261             :   }
    1262           0 :   stt->agcMode = agcMode;
    1263           0 :   stt->fs = fs;
    1264             : 
    1265             :   /* initialize input VAD */
    1266           0 :   WebRtcAgc_InitVad(&stt->vadMic);
    1267             : 
    1268             :   /* If the volume range is smaller than 0-256 then
    1269             :    * the levels are shifted up to Q8-domain */
    1270           0 :   tmpNorm = WebRtcSpl_NormU32((uint32_t)maxLevel);
    1271           0 :   stt->scale = tmpNorm - 23;
    1272           0 :   if (stt->scale < 0) {
    1273           0 :     stt->scale = 0;
    1274             :   }
    1275             :   // TODO(bjornv): Investigate if we really need to scale up a small range now
    1276             :   // when we have
    1277             :   // a guard against zero-increments. For now, we do not support scale up (scale
    1278             :   // = 0).
    1279           0 :   stt->scale = 0;
    1280           0 :   maxLevel <<= stt->scale;
    1281           0 :   minLevel <<= stt->scale;
    1282             : 
    1283             :   /* Make minLevel and maxLevel static in AdaptiveDigital */
    1284           0 :   if (stt->agcMode == kAgcModeAdaptiveDigital) {
    1285           0 :     minLevel = 0;
    1286           0 :     maxLevel = 255;
    1287           0 :     stt->scale = 0;
    1288             :   }
    1289             :   /* The maximum supplemental volume range is based on a vague idea
    1290             :    * of how much lower the gain will be than the real analog gain. */
    1291           0 :   max_add = (maxLevel - minLevel) / 4;
    1292             : 
    1293             :   /* Minimum/maximum volume level that can be set */
    1294           0 :   stt->minLevel = minLevel;
    1295           0 :   stt->maxAnalog = maxLevel;
    1296           0 :   stt->maxLevel = maxLevel + max_add;
    1297           0 :   stt->maxInit = stt->maxLevel;
    1298             : 
    1299           0 :   stt->zeroCtrlMax = stt->maxAnalog;
    1300           0 :   stt->lastInMicLevel = 0;
    1301             : 
    1302             :   /* Initialize micVol parameter */
    1303           0 :   stt->micVol = stt->maxAnalog;
    1304           0 :   if (stt->agcMode == kAgcModeAdaptiveDigital) {
    1305           0 :     stt->micVol = 127; /* Mid-point of mic level */
    1306             :   }
    1307           0 :   stt->micRef = stt->micVol;
    1308           0 :   stt->micGainIdx = 127;
    1309             : #ifdef MIC_LEVEL_FEEDBACK
    1310             :   stt->numBlocksMicLvlSat = 0;
    1311             :   stt->micLvlSat = 0;
    1312             : #endif
    1313             : #ifdef WEBRTC_AGC_DEBUG_DUMP
    1314             :   fprintf(stt->fpt, "AGC->Init: minLevel = %d, maxAnalog = %d, maxLevel = %d\n",
    1315             :           stt->minLevel, stt->maxAnalog, stt->maxLevel);
    1316             : #endif
    1317             : 
    1318             :   /* Minimum output volume is 4% higher than the available lowest volume level
    1319             :    */
    1320           0 :   tmp32 = ((stt->maxLevel - stt->minLevel) * 10) >> 8;
    1321           0 :   stt->minOutput = (stt->minLevel + tmp32);
    1322             : 
    1323           0 :   stt->msTooLow = 0;
    1324           0 :   stt->msTooHigh = 0;
    1325           0 :   stt->changeToSlowMode = 0;
    1326           0 :   stt->firstCall = 0;
    1327           0 :   stt->msZero = 0;
    1328           0 :   stt->muteGuardMs = 0;
    1329           0 :   stt->gainTableIdx = 0;
    1330             : 
    1331           0 :   stt->msecSpeechInnerChange = kMsecSpeechInner;
    1332           0 :   stt->msecSpeechOuterChange = kMsecSpeechOuter;
    1333             : 
    1334           0 :   stt->activeSpeech = 0;
    1335           0 :   stt->Rxx16_LPw32Max = 0;
    1336             : 
    1337           0 :   stt->vadThreshold = kNormalVadThreshold;
    1338           0 :   stt->inActive = 0;
    1339             : 
    1340           0 :   for (i = 0; i < RXX_BUFFER_LEN; i++) {
    1341           0 :     stt->Rxx16_vectorw32[i] = (int32_t)1000; /* -54dBm0 */
    1342             :   }
    1343           0 :   stt->Rxx160w32 =
    1344             :       125 * RXX_BUFFER_LEN; /* (stt->Rxx16_vectorw32[0]>>3) = 125 */
    1345             : 
    1346           0 :   stt->Rxx16pos = 0;
    1347           0 :   stt->Rxx16_LPw32 = (int32_t)16284; /* Q(-4) */
    1348             : 
    1349           0 :   for (i = 0; i < 5; i++) {
    1350           0 :     stt->Rxx16w32_array[0][i] = 0;
    1351             :   }
    1352           0 :   for (i = 0; i < 10; i++) {
    1353           0 :     stt->env[0][i] = 0;
    1354           0 :     stt->env[1][i] = 0;
    1355             :   }
    1356           0 :   stt->inQueue = 0;
    1357             : 
    1358             : #ifdef MIC_LEVEL_FEEDBACK
    1359             :   stt->targetIdxOffset = 0;
    1360             : #endif
    1361             : 
    1362           0 :   WebRtcSpl_MemSetW32(stt->filterState, 0, 8);
    1363             : 
    1364           0 :   stt->initFlag = kInitCheck;
    1365             :   // Default config settings.
    1366           0 :   stt->defaultConfig.limiterEnable = kAgcTrue;
    1367           0 :   stt->defaultConfig.targetLevelDbfs = AGC_DEFAULT_TARGET_LEVEL;
    1368           0 :   stt->defaultConfig.compressionGaindB = AGC_DEFAULT_COMP_GAIN;
    1369             : 
    1370           0 :   if (WebRtcAgc_set_config(stt, stt->defaultConfig) == -1) {
    1371           0 :     stt->lastError = AGC_UNSPECIFIED_ERROR;
    1372           0 :     return -1;
    1373             :   }
    1374           0 :   stt->Rxx160_LPw32 = stt->analogTargetLevel;  // Initialize rms value
    1375             : 
    1376           0 :   stt->lowLevelSignal = 0;
    1377             : 
    1378             :   /* Only positive values are allowed that are not too large */
    1379           0 :   if ((minLevel >= maxLevel) || (maxLevel & 0xFC000000)) {
    1380             : #ifdef WEBRTC_AGC_DEBUG_DUMP
    1381             :     fprintf(stt->fpt, "minLevel, maxLevel value(s) are invalid\n\n");
    1382             : #endif
    1383           0 :     return -1;
    1384             :   } else {
    1385             : #ifdef WEBRTC_AGC_DEBUG_DUMP
    1386             :     fprintf(stt->fpt, "\n");
    1387             : #endif
    1388           0 :     return 0;
    1389             :   }
    1390             : }

Generated by: LCOV version 1.13