text: /*
   *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
   *
   *  Use of this source code is governed by a BSD-style license
   *  that can be found in the LICENSE file in the root of the source
   *  tree. An additional intellectual property rights grant can be found
   *  in the file PATENTS.  All contributing project authors may
   *  be found in the AUTHORS file in the root of the source tree.
   */
  
  /*
   * BwEstimator.c
   *
   * This file contains the code for the Bandwidth Estimator designed
   * for iSAC.
   *
   */
  
  #include "bandwidth_estimator.h"
  #include "settings.h"
  #include "isac.h"
  #include BOSS_WEBRTC_U_rtc_base__checks_h //original-code:"rtc_base/checks.h"
  
  #include <math.h>
  #include <string.h>
  
  /* array of quantization levels for bottle neck info; Matlab code: */
  /* sprintf('%4.1ff, ', logspace(log10(5000), log10(40000), 12)) */
  static const float kQRateTableWb[12] =
  {
    10000.0f, 11115.3f, 12355.1f, 13733.1f, 15264.8f, 16967.3f,
    18859.8f, 20963.3f, 23301.4f, 25900.3f, 28789.0f, 32000.0f};
  
  
  static const float kQRateTableSwb[24] =
  {
    10000.0f, 11115.3f, 12355.1f, 13733.1f, 15264.8f, 16967.3f,
    18859.8f, 20963.3f, 23153.1f, 25342.9f, 27532.7f, 29722.5f,
    31912.3f, 34102.1f, 36291.9f, 38481.7f, 40671.4f, 42861.2f,
    45051.0f, 47240.8f, 49430.6f, 51620.4f, 53810.2f, 56000.0f,
  };
  
  
  
  
  int32_t WebRtcIsac_InitBandwidthEstimator(
      BwEstimatorstr*              bwest_str,
      enum IsacSamplingRate encoderSampRate,
      enum IsacSamplingRate decoderSampRate)
  {
    switch(encoderSampRate)
    {
      case kIsacWideband:
        {
          bwest_str->send_bw_avg       = INIT_BN_EST_WB;
          break;
        }
      case kIsacSuperWideband:
        {
          bwest_str->send_bw_avg       = INIT_BN_EST_SWB;
          break;
        }
    }
  
    switch(decoderSampRate)
    {
      case kIsacWideband:
        {
          bwest_str->prev_frame_length = INIT_FRAME_LEN_WB;
          bwest_str->rec_bw_inv        = 1.0f /
              (INIT_BN_EST_WB + INIT_HDR_RATE_WB);
          bwest_str->rec_bw            = (int32_t)INIT_BN_EST_WB;
          bwest_str->rec_bw_avg_Q      = INIT_BN_EST_WB;
          bwest_str->rec_bw_avg        = INIT_BN_EST_WB + INIT_HDR_RATE_WB;
          bwest_str->rec_header_rate   = INIT_HDR_RATE_WB;
          break;
        }
      case kIsacSuperWideband:
        {
          bwest_str->prev_frame_length = INIT_FRAME_LEN_SWB;
          bwest_str->rec_bw_inv        = 1.0f /
              (INIT_BN_EST_SWB + INIT_HDR_RATE_SWB);
          bwest_str->rec_bw            = (int32_t)INIT_BN_EST_SWB;
          bwest_str->rec_bw_avg_Q      = INIT_BN_EST_SWB;
          bwest_str->rec_bw_avg        = INIT_BN_EST_SWB + INIT_HDR_RATE_SWB;
          bwest_str->rec_header_rate   = INIT_HDR_RATE_SWB;
          break;
        }
    }
  
    bwest_str->prev_rec_rtp_number       = 0;
    bwest_str->prev_rec_arr_ts           = 0;
    bwest_str->prev_rec_send_ts          = 0;
    bwest_str->prev_rec_rtp_rate         = 1.0f;
    bwest_str->last_update_ts            = 0;
    bwest_str->last_reduction_ts         = 0;
    bwest_str->count_tot_updates_rec     = -9;
    bwest_str->rec_jitter                = 10.0f;
    bwest_str->rec_jitter_short_term     = 0.0f;
    bwest_str->rec_jitter_short_term_abs = 5.0f;
    bwest_str->rec_max_delay             = 10.0f;
    bwest_str->rec_max_delay_avg_Q       = 10.0f;
    bwest_str->num_pkts_rec              = 0;
  
    bwest_str->send_max_delay_avg        = 10.0f;
  
    bwest_str->hsn_detect_rec = 0;
  
    bwest_str->num_consec_rec_pkts_over_30k = 0;
  
    bwest_str->hsn_detect_snd = 0;
  
    bwest_str->num_consec_snt_pkts_over_30k = 0;
  
    bwest_str->in_wait_period = 0;
  
    bwest_str->change_to_WB = 0;
  
    bwest_str->numConsecLatePkts = 0;
    bwest_str->consecLatency = 0;
    bwest_str->inWaitLatePkts = 0;
    bwest_str->senderTimestamp = 0;
    bwest_str->receiverTimestamp = 0;
  
    bwest_str->external_bw_info.in_use = 0;
  
    return 0;
  }
  
  /* This function updates both bottle neck rates                                                      */
  /* Parameters:                                                                                       */
  /* rtp_number    - value from RTP packet, from NetEq                                                 */
  /* frame length  - length of signal frame in ms, from iSAC decoder                                   */
  /* send_ts       - value in RTP header giving send time in samples                                     */
  /* arr_ts        - value given by timeGetTime() time of arrival in samples of packet from NetEq      */
  /* pksize        - size of packet in bytes, from NetEq                                               */
  /* Index         - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */
  /* returns 0 if everything went fine, -1 otherwise                                                   */
  int16_t WebRtcIsac_UpdateBandwidthEstimator(
      BwEstimatorstr* bwest_str,
      const uint16_t rtp_number,
      const int32_t frame_length,
      const uint32_t send_ts,
      const uint32_t arr_ts,
      const size_t pksize
      /*,    const uint16_t Index*/)
  {
    float weight = 0.0f;
    float curr_bw_inv = 0.0f;
    float rec_rtp_rate;
    float t_diff_proj;
    float arr_ts_diff;
    float send_ts_diff;
    float arr_time_noise;
    float arr_time_noise_abs;
  
    float delay_correction_factor = 1;
    float late_diff = 0.0f;
    int immediate_set = 0;
    int num_pkts_expected;
  
    RTC_DCHECK(!bwest_str->external_bw_info.in_use);
  
    // We have to adjust the header-rate if the first packet has a
    // frame-size different than the initialized value.
    if ( frame_length != bwest_str->prev_frame_length )
    {
      bwest_str->rec_header_rate = (float)HEADER_SIZE * 8.0f *
          1000.0f / (float)frame_length;     /* bits/s */
    }
  
    /* UPDATE ESTIMATES ON THIS SIDE */
    /* compute far-side transmission rate */
    rec_rtp_rate = ((float)pksize * 8.0f * 1000.0f / (float)frame_length) +
        bwest_str->rec_header_rate;
    // rec_rtp_rate packet bits/s + header bits/s
  
    /* check for timer wrap-around */
    if (arr_ts < bwest_str->prev_rec_arr_ts)
    {
      bwest_str->prev_rec_arr_ts   = arr_ts;
      bwest_str->last_update_ts    = arr_ts;
      bwest_str->last_reduction_ts = arr_ts + 3*FS;
      bwest_str->num_pkts_rec      = 0;
  
      /* store frame length */
      bwest_str->prev_frame_length = frame_length;
  
      /* store far-side transmission rate */
      bwest_str->prev_rec_rtp_rate = rec_rtp_rate;
  
      /* store far-side RTP time stamp */
      bwest_str->prev_rec_rtp_number = rtp_number;
  
      return 0;
    }
  
    bwest_str->num_pkts_rec++;
  
    /* check that it's not one of the first 9 packets */
    if ( bwest_str->count_tot_updates_rec > 0 )
    {
      if(bwest_str->in_wait_period > 0 )
      {
        bwest_str->in_wait_period--;
      }
  
      bwest_str->inWaitLatePkts -= ((bwest_str->inWaitLatePkts > 0)? 1:0);
      send_ts_diff = (float)(send_ts - bwest_str->prev_rec_send_ts);
  
      if (send_ts_diff <= (16 * frame_length)*2)
        //doesn't allow for a dropped packet, not sure necessary to be
        // that strict -DH
      {
        /* if not been updated for a long time, reduce the BN estimate */
        if((uint32_t)(arr_ts - bwest_str->last_update_ts) *
           1000.0f / FS > 3000)
        {
          //how many frames should have been received since the last
          // update if too many have been dropped or there have been
          // big delays won't allow this reduction may no longer need
          // the send_ts_diff here
          num_pkts_expected = (int)(((float)(arr_ts -
                                             bwest_str->last_update_ts) * 1000.0f /(float) FS) /
                                    (float)frame_length);
  
          if(((float)bwest_str->num_pkts_rec/(float)num_pkts_expected) >
             0.9)
          {
            float inv_bitrate = (float) pow( 0.99995,
                                             (double)((uint32_t)(arr_ts -
                                                                       bwest_str->last_reduction_ts)*1000.0f/FS) );
  
            if ( inv_bitrate )
            {
              bwest_str->rec_bw_inv /= inv_bitrate;
  
              //precautionary, likely never necessary
              if (bwest_str->hsn_detect_snd &&
                  bwest_str->hsn_detect_rec)
              {
                if (bwest_str->rec_bw_inv > 0.000066f)
                {
                  bwest_str->rec_bw_inv = 0.000066f;
                }
              }
            }
            else
            {
              bwest_str->rec_bw_inv = 1.0f /
                  (INIT_BN_EST_WB + INIT_HDR_RATE_WB);
            }
            /* reset time-since-update counter */
            bwest_str->last_reduction_ts = arr_ts;
          }
          else
            //reset here?
          {
            bwest_str->last_reduction_ts = arr_ts + 3*FS;
            bwest_str->last_update_ts = arr_ts;
            bwest_str->num_pkts_rec = 0;
          }
        }
      }
      else
      {
        bwest_str->last_reduction_ts = arr_ts + 3*FS;
        bwest_str->last_update_ts = arr_ts;
        bwest_str->num_pkts_rec = 0;
      }
  
  
      /* temporarily speed up adaptation if frame length has changed */
      if ( frame_length != bwest_str->prev_frame_length )
      {
        bwest_str->count_tot_updates_rec = 10;
        bwest_str->rec_header_rate = (float)HEADER_SIZE * 8.0f *
            1000.0f / (float)frame_length;     /* bits/s */
  
        bwest_str->rec_bw_inv = 1.0f /((float)bwest_str->rec_bw +
                                       bwest_str->rec_header_rate);
      }
  
      ////////////////////////
      arr_ts_diff = (float)(arr_ts - bwest_str->prev_rec_arr_ts);
  
      if (send_ts_diff > 0 )
      {
        late_diff = arr_ts_diff - send_ts_diff;
      }
      else
      {
        late_diff = arr_ts_diff - (float)(16 * frame_length);
      }
  
      if((late_diff > 0) && !bwest_str->inWaitLatePkts)
      {
        bwest_str->numConsecLatePkts++;
        bwest_str->consecLatency += late_diff;
      }
      else
      {
        bwest_str->numConsecLatePkts = 0;
        bwest_str->consecLatency = 0;
      }
      if(bwest_str->numConsecLatePkts > 50)
      {
        float latencyMs = bwest_str->consecLatency/(FS/1000);
        float averageLatencyMs = latencyMs / bwest_str->numConsecLatePkts;
        delay_correction_factor = frame_length / (frame_length + averageLatencyMs);
        immediate_set = 1;
        bwest_str->inWaitLatePkts = (int16_t)((bwest_str->consecLatency/(FS/1000)) / 30);// + 150;
        bwest_str->start_wait_period = arr_ts;
      }
      ///////////////////////////////////////////////
  
  
  
      /*   update only if previous packet was not lost */
      if ( rtp_number == bwest_str->prev_rec_rtp_number + 1 )
      {
  
  
        if (!(bwest_str->hsn_detect_snd && bwest_str->hsn_detect_rec))
        {
          if ((arr_ts_diff > (float)(16 * frame_length)))
          {
            //1/2 second
            if ((late_diff > 8000.0f) && !bwest_str->in_wait_period)
            {
              delay_correction_factor = 0.7f;
              bwest_str->in_wait_period = 55;
              bwest_str->start_wait_period = arr_ts;
              immediate_set = 1;
            }
            //320 ms
            else if (late_diff > 5120.0f && !bwest_str->in_wait_period)
            {
              delay_correction_factor = 0.8f;
              immediate_set = 1;
              bwest_str->in_wait_period = 44;
              bwest_str->start_wait_period = arr_ts;
            }
          }
        }
  
  
        if ((bwest_str->prev_rec_rtp_rate > bwest_str->rec_bw_avg) &&
            (rec_rtp_rate > bwest_str->rec_bw_avg)                 &&
            !bwest_str->in_wait_period)
        {
          /* test if still in initiation period and increment counter */
          if (bwest_str->count_tot_updates_rec++ > 99)
          {
            /* constant weight after initiation part */
            weight = 0.01f;
          }
          else
          {
            /* weight decreases with number of updates */
            weight = 1.0f / (float) bwest_str->count_tot_updates_rec;
          }
          /* Bottle Neck Estimation */
  
          /* limit outliers */
          /* if more than 25 ms too much */
          if (arr_ts_diff > frame_length * FS/1000 + 400.0f)
          {
            // in samples,  why 25ms??
            arr_ts_diff = frame_length * FS/1000 + 400.0f;
          }
          if(arr_ts_diff < (frame_length * FS/1000) - 160.0f)
          {
            /* don't allow it to be less than frame rate - 10 ms */
            arr_ts_diff = (float)frame_length * FS/1000 - 160.0f;
          }
  
          /* compute inverse receiving rate for last packet */
          curr_bw_inv = arr_ts_diff / ((float)(pksize + HEADER_SIZE) *
                                       8.0f * FS); // (180+35)*8*16000 = 27.5 Mbit....
  
  
          if(curr_bw_inv <
             (1.0f / (MAX_ISAC_BW + bwest_str->rec_header_rate)))
          {
            // don't allow inv rate to be larger than MAX
            curr_bw_inv = (1.0f /
                           (MAX_ISAC_BW + bwest_str->rec_header_rate));
          }
  
          /* update bottle neck rate estimate */
          bwest_str->rec_bw_inv = weight * curr_bw_inv +
              (1.0f - weight) * bwest_str->rec_bw_inv;
  
          /* reset time-since-update counter */
          bwest_str->last_update_ts    = arr_ts;
          bwest_str->last_reduction_ts = arr_ts + 3 * FS;
          bwest_str->num_pkts_rec = 0;
  
          /* Jitter Estimation */
          /* projected difference between arrival times */
          t_diff_proj = ((float)(pksize + HEADER_SIZE) * 8.0f *
                         1000.0f) / bwest_str->rec_bw_avg;
  
  
          // difference between projected and actual
          //   arrival time differences
          arr_time_noise = (float)(arr_ts_diff*1000.0f/FS) -
              t_diff_proj;
          arr_time_noise_abs = (float) fabs( arr_time_noise );
  
          /* long term averaged absolute jitter */
          bwest_str->rec_jitter = weight * arr_time_noise_abs +
              (1.0f - weight) * bwest_str->rec_jitter;
          if (bwest_str->rec_jitter > 10.0f)
          {
            bwest_str->rec_jitter = 10.0f;
          }
          /* short term averaged absolute jitter */
          bwest_str->rec_jitter_short_term_abs = 0.05f *
              arr_time_noise_abs + 0.95f *
              bwest_str->rec_jitter_short_term_abs;
  
          /* short term averaged jitter */
          bwest_str->rec_jitter_short_term = 0.05f * arr_time_noise +
              0.95f * bwest_str->rec_jitter_short_term;
        }
      }
    }
    else
    {
      // reset time-since-update counter when
      // receiving the first 9 packets
      bwest_str->last_update_ts    = arr_ts;
      bwest_str->last_reduction_ts = arr_ts + 3*FS;
      bwest_str->num_pkts_rec = 0;
  
      bwest_str->count_tot_updates_rec++;
    }
  
    /* limit minimum bottle neck rate */
    if (bwest_str->rec_bw_inv > 1.0f / ((float)MIN_ISAC_BW +
                                        bwest_str->rec_header_rate))
    {
      bwest_str->rec_bw_inv = 1.0f / ((float)MIN_ISAC_BW +
                                      bwest_str->rec_header_rate);
    }
  
    // limit maximum bitrate
    if (bwest_str->rec_bw_inv < 1.0f / ((float)MAX_ISAC_BW +
                                        bwest_str->rec_header_rate))
    {
      bwest_str->rec_bw_inv = 1.0f / ((float)MAX_ISAC_BW +
                                      bwest_str->rec_header_rate);
    }
  
    /* store frame length */
    bwest_str->prev_frame_length = frame_length;
  
    /* store far-side transmission rate */
    bwest_str->prev_rec_rtp_rate = rec_rtp_rate;
  
    /* store far-side RTP time stamp */
    bwest_str->prev_rec_rtp_number = rtp_number;
  
    // Replace bwest_str->rec_max_delay by the new
    // value (atomic operation)
    bwest_str->rec_max_delay = 3.0f * bwest_str->rec_jitter;
  
    /* store send and arrival time stamp */
    bwest_str->prev_rec_arr_ts = arr_ts ;
    bwest_str->prev_rec_send_ts = send_ts;
  
    /* Replace bwest_str->rec_bw by the new value (atomic operation) */
    bwest_str->rec_bw = (int32_t)(1.0f / bwest_str->rec_bw_inv -
                                        bwest_str->rec_header_rate);
  
    if (immediate_set)
    {
      bwest_str->rec_bw = (int32_t) (delay_correction_factor *
                                           (float) bwest_str->rec_bw);
  
      if (bwest_str->rec_bw < (int32_t) MIN_ISAC_BW)
      {
        bwest_str->rec_bw = (int32_t) MIN_ISAC_BW;
      }
  
      bwest_str->rec_bw_avg = bwest_str->rec_bw +
          bwest_str->rec_header_rate;
  
      bwest_str->rec_bw_avg_Q = (float) bwest_str->rec_bw;
  
      bwest_str->rec_jitter_short_term = 0.0f;
  
      bwest_str->rec_bw_inv = 1.0f / (bwest_str->rec_bw +
                                      bwest_str->rec_header_rate);
  
      bwest_str->count_tot_updates_rec = 1;
  
      immediate_set = 0;
      bwest_str->consecLatency = 0;
      bwest_str->numConsecLatePkts = 0;
    }
  
    return 0;
  }
  
  
  /* This function updates the send bottle neck rate                                                   */
  /* Index         - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */
  /* returns 0 if everything went fine, -1 otherwise                                                   */
  int16_t WebRtcIsac_UpdateUplinkBwImpl(
      BwEstimatorstr*           bwest_str,
      int16_t               index,
      enum IsacSamplingRate encoderSamplingFreq)
  {
    RTC_DCHECK(!bwest_str->external_bw_info.in_use);
  
    if((index < 0) || (index > 23))
    {
      return -ISAC_RANGE_ERROR_BW_ESTIMATOR;
    }
  
    /* UPDATE ESTIMATES FROM OTHER SIDE */
    if(encoderSamplingFreq == kIsacWideband)
    {
      if(index > 11)
      {
        index -= 12;   
        /* compute the jitter estimate as decoded on the other side */
        bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg +
            0.1f * (float)MAX_ISAC_MD;
      }
      else
      {
        /* compute the jitter estimate as decoded on the other side */
        bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg +
            0.1f * (float)MIN_ISAC_MD;
      }
  
      /* compute the BN estimate as decoded on the other side */
      bwest_str->send_bw_avg = 0.9f * bwest_str->send_bw_avg +
          0.1f * kQRateTableWb[index];
    }
    else
    {
      /* compute the BN estimate as decoded on the other side */
      bwest_str->send_bw_avg = 0.9f * bwest_str->send_bw_avg +
          0.1f * kQRateTableSwb[index];
    }
  
    if (bwest_str->send_bw_avg > (float) 28000 && !bwest_str->hsn_detect_snd)
    {
      bwest_str->num_consec_snt_pkts_over_30k++;
  
      if (bwest_str->num_consec_snt_pkts_over_30k >= 66)
      {
        //approx 2 seconds with 30ms frames
        bwest_str->hsn_detect_snd = 1;
      }
    }
    else if (!bwest_str->hsn_detect_snd)
    {
      bwest_str->num_consec_snt_pkts_over_30k = 0;
    }
    return 0;
  }
  
  // called when there is upper-band bit-stream to update jitter
  // statistics.
  int16_t WebRtcIsac_UpdateUplinkJitter(
      BwEstimatorstr*              bwest_str,
      int32_t                  index)
  {
    RTC_DCHECK(!bwest_str->external_bw_info.in_use);
  
    if((index < 0) || (index > 23))
    {
      return -ISAC_RANGE_ERROR_BW_ESTIMATOR;
    }
  
    if(index > 0)
    {
      /* compute the jitter estimate as decoded on the other side */
      bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg +
          0.1f * (float)MAX_ISAC_MD;
    }
    else
    {
      /* compute the jitter estimate as decoded on the other side */
      bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg +
          0.1f * (float)MIN_ISAC_MD;
    }
  
    return 0;
  }
  
  
  
  // Returns the bandwidth/jitter estimation code (integer 0...23)
  // to put in the sending iSAC payload
  void
  WebRtcIsac_GetDownlinkBwJitIndexImpl(
      BwEstimatorstr*           bwest_str,
      int16_t*              bottleneckIndex,
      int16_t*              jitterInfo,
      enum IsacSamplingRate decoderSamplingFreq)
  {
    float MaxDelay;
    //uint16_t MaxDelayBit;
  
    float rate;
    float r;
    float e1, e2;
    const float weight = 0.1f;
    const float* ptrQuantizationTable;
    int16_t addJitterInfo;
    int16_t minInd;
    int16_t maxInd;
    int16_t midInd;
  
    if (bwest_str->external_bw_info.in_use) {
      *bottleneckIndex = bwest_str->external_bw_info.bottleneck_idx;
      *jitterInfo = bwest_str->external_bw_info.jitter_info;
      return;
    }
  
    /* Get Max Delay Bit */
    /* get unquantized max delay */
    MaxDelay = (float)WebRtcIsac_GetDownlinkMaxDelay(bwest_str);
  
    if ( ((1.f - weight) * bwest_str->rec_max_delay_avg_Q + weight *
          MAX_ISAC_MD - MaxDelay) > (MaxDelay - (1.f-weight) *
                                     bwest_str->rec_max_delay_avg_Q - weight * MIN_ISAC_MD) )
    {
      jitterInfo[0] = 0;
      /* update quantized average */
      bwest_str->rec_max_delay_avg_Q =
          (1.f - weight) * bwest_str->rec_max_delay_avg_Q + weight *
          (float)MIN_ISAC_MD;
    }
    else
    {
      jitterInfo[0] = 1;
      /* update quantized average */
      bwest_str->rec_max_delay_avg_Q =
          (1.f-weight) * bwest_str->rec_max_delay_avg_Q + weight *
          (float)MAX_ISAC_MD;
    }
  
    // Get unquantized rate.
    rate = (float)WebRtcIsac_GetDownlinkBandwidth(bwest_str);
  
    /* Get Rate Index */
    if(decoderSamplingFreq == kIsacWideband)
    {
      ptrQuantizationTable = kQRateTableWb;
      addJitterInfo = 1;
      maxInd = 11;
    }
    else
    {
      ptrQuantizationTable = kQRateTableSwb;
      addJitterInfo = 0;
      maxInd = 23;
    }
  
    minInd = 0;
    while(maxInd > minInd + 1)
    {
      midInd = (maxInd + minInd) >> 1;
      if(rate > ptrQuantizationTable[midInd])
      {
        minInd = midInd;
      }
      else
      {
        maxInd = midInd;
      }
    }
    // Chose the index which gives results an average which is closest
    // to rate
    r = (1 - weight) * bwest_str->rec_bw_avg_Q - rate;
    e1 = weight * ptrQuantizationTable[minInd] + r;
    e2 = weight * ptrQuantizationTable[maxInd] + r;
    e1 = (e1 > 0)? e1:-e1;
    e2 = (e2 > 0)? e2:-e2;
    if(e1 < e2)
    {
      bottleneckIndex[0] = minInd;
    }
    else
    {
      bottleneckIndex[0] = maxInd;
    }
  
    bwest_str->rec_bw_avg_Q = (1 - weight) * bwest_str->rec_bw_avg_Q +
        weight * ptrQuantizationTable[bottleneckIndex[0]];
    bottleneckIndex[0] += jitterInfo[0] * 12 * addJitterInfo;
  
    bwest_str->rec_bw_avg = (1 - weight) * bwest_str->rec_bw_avg + weight *
        (rate + bwest_str->rec_header_rate);
  }
  
  
  
  /* get the bottle neck rate from far side to here, as estimated on this side */
  int32_t WebRtcIsac_GetDownlinkBandwidth( const BwEstimatorstr *bwest_str)
  {
    int32_t  rec_bw;
    float   jitter_sign;
    float   bw_adjust;
  
    RTC_DCHECK(!bwest_str->external_bw_info.in_use);
  
    /* create a value between -1.0 and 1.0 indicating "average sign" of jitter */
    jitter_sign = bwest_str->rec_jitter_short_term /
        bwest_str->rec_jitter_short_term_abs;
  
    /* adjust bw proportionally to negative average jitter sign */
    bw_adjust = 1.0f - jitter_sign * (0.15f + 0.15f * jitter_sign * jitter_sign);
  
    /* adjust Rate if jitter sign is mostly constant */
    rec_bw = (int32_t)(bwest_str->rec_bw * bw_adjust);
  
    /* limit range of bottle neck rate */
    if (rec_bw < MIN_ISAC_BW)
    {
      rec_bw = MIN_ISAC_BW;
    }
    else if (rec_bw > MAX_ISAC_BW)
    {
      rec_bw = MAX_ISAC_BW;
    }
    return rec_bw;
  }
  
  /* Returns the max delay (in ms) */
  int32_t
  WebRtcIsac_GetDownlinkMaxDelay(const BwEstimatorstr *bwest_str)
  {
    int32_t rec_max_delay;
  
    RTC_DCHECK(!bwest_str->external_bw_info.in_use);
  
    rec_max_delay = (int32_t)(bwest_str->rec_max_delay);
  
    /* limit range of jitter estimate */
    if (rec_max_delay < MIN_ISAC_MD)
    {
      rec_max_delay = MIN_ISAC_MD;
    }
    else if (rec_max_delay > MAX_ISAC_MD)
    {
      rec_max_delay = MAX_ISAC_MD;
    }
    return rec_max_delay;
  }
  
  /* Clamp val to the closed interval [min,max]. */
  static int32_t clamp(int32_t val, int32_t min, int32_t max) {
    RTC_DCHECK_LE(min, max);
    return val < min ? min : (val > max ? max : val);
  }
  
  int32_t WebRtcIsac_GetUplinkBandwidth(const BwEstimatorstr* bwest_str) {
    return bwest_str->external_bw_info.in_use
               ? bwest_str->external_bw_info.send_bw_avg
               : clamp(bwest_str->send_bw_avg, MIN_ISAC_BW, MAX_ISAC_BW);
  }
  
  int32_t WebRtcIsac_GetUplinkMaxDelay(const BwEstimatorstr* bwest_str) {
    return bwest_str->external_bw_info.in_use
               ? bwest_str->external_bw_info.send_max_delay_avg
               : clamp(bwest_str->send_max_delay_avg, MIN_ISAC_MD, MAX_ISAC_MD);
  }
  
  void WebRtcIsacBw_GetBandwidthInfo(BwEstimatorstr* bwest_str,
                                     enum IsacSamplingRate decoder_sample_rate_hz,
                                     IsacBandwidthInfo* bwinfo) {
    RTC_DCHECK(!bwest_str->external_bw_info.in_use);
    bwinfo->in_use = 1;
    bwinfo->send_bw_avg = WebRtcIsac_GetUplinkBandwidth(bwest_str);
    bwinfo->send_max_delay_avg = WebRtcIsac_GetUplinkMaxDelay(bwest_str);
    WebRtcIsac_GetDownlinkBwJitIndexImpl(bwest_str, &bwinfo->bottleneck_idx,
                                         &bwinfo->jitter_info,
                                         decoder_sample_rate_hz);
  }
  
  void WebRtcIsacBw_SetBandwidthInfo(BwEstimatorstr* bwest_str,
                                     const IsacBandwidthInfo* bwinfo) {
    memcpy(&bwest_str->external_bw_info, bwinfo,
           sizeof bwest_str->external_bw_info);
  }
  
  /*
   * update long-term average bitrate and amount of data in buffer
   * returns minimum payload size (bytes)
   */
  int WebRtcIsac_GetMinBytes(
      RateModel*         State,
      int                StreamSize,    /* bytes in bitstream */
      const int          FrameSamples,  /* samples per frame */
      const double       BottleNeck,    /* bottle neck rate; excl headers (bps) */
      const double       DelayBuildUp,  /* max delay from bottleneck buffering (ms) */
      enum ISACBandwidth bandwidth
      /*,int16_t        frequentLargePackets*/)
  {
    double MinRate = 0.0;
    int    MinBytes;
    double TransmissionTime;
    int    burstInterval = BURST_INTERVAL;
  
    // first 10 packets @ low rate, then INIT_BURST_LEN packets @
    // fixed rate of INIT_RATE bps
    if (State->InitCounter > 0)
    {
      if (State->InitCounter-- <= INIT_BURST_LEN)
      {
        if(bandwidth == isac8kHz)
        {
          MinRate = INIT_RATE_WB;
        }
        else
        {
          MinRate = INIT_RATE_SWB;
        }
      }
      else
      {
        MinRate = 0;
      }
    }
    else
    {
      /* handle burst */
      if (State->BurstCounter)
      {
        if (State->StillBuffered < (1.0 - 1.0/BURST_LEN) * DelayBuildUp)
        {
          /* max bps derived from BottleNeck and DelayBuildUp values */
          MinRate = (1.0 + (FS/1000) * DelayBuildUp /
                     (double)(BURST_LEN * FrameSamples)) * BottleNeck;
        }
        else
        {
          // max bps derived from StillBuffered and DelayBuildUp
          // values
          MinRate = (1.0 + (FS/1000) * (DelayBuildUp -
                                        State->StillBuffered) / (double)FrameSamples) * BottleNeck;
          if (MinRate < 1.04 * BottleNeck)
          {
            MinRate = 1.04 * BottleNeck;
          }
        }
        State->BurstCounter--;
      }
    }
  
  
    /* convert rate from bits/second to bytes/packet */
    MinBytes = (int) (MinRate * FrameSamples / (8.0 * FS));
  
    /* StreamSize will be adjusted if less than MinBytes */
    if (StreamSize < MinBytes)
    {
      StreamSize = MinBytes;
    }
  
    /* keep track of when bottle neck was last exceeded by at least 1% */
    if (StreamSize * 8.0 * FS / FrameSamples > 1.01 * BottleNeck) {
      if (State->PrevExceed) {
        /* bottle_neck exceded twice in a row, decrease ExceedAgo */
        State->ExceedAgo -= /*BURST_INTERVAL*/ burstInterval / (BURST_LEN - 1);
        if (State->ExceedAgo < 0)
          State->ExceedAgo = 0;
      }
      else
      {
        State->ExceedAgo += (FrameSamples * 1000) / FS; /* ms */
        State->PrevExceed = 1;
      }
    }
    else
    {
      State->PrevExceed = 0;
      State->ExceedAgo += (FrameSamples * 1000) / FS;     /* ms */
    }
  
    /* set burst flag if bottle neck not exceeded for long time */
    if ((State->ExceedAgo > burstInterval) &&
        (State->BurstCounter == 0))
    {
      if (State->PrevExceed)
      {
        State->BurstCounter = BURST_LEN - 1;
      }
      else
      {
        State->BurstCounter = BURST_LEN;
      }
    }
  
  
    /* Update buffer delay */
    TransmissionTime = StreamSize * 8.0 * 1000.0 / BottleNeck;  /* ms */
    State->StillBuffered += TransmissionTime;
    State->StillBuffered -= (FrameSamples * 1000) / FS;     /* ms */
    if (State->StillBuffered < 0.0)
    {
      State->StillBuffered = 0.0;
    }
  
    return MinBytes;
  }
  
  
  /*
   * update long-term average bitrate and amount of data in buffer
   */
  void WebRtcIsac_UpdateRateModel(
      RateModel *State,
      int StreamSize,                    /* bytes in bitstream */
      const int FrameSamples,            /* samples per frame */
      const double BottleNeck)        /* bottle neck rate; excl headers (bps) */
  {
    double TransmissionTime;
  
    /* avoid the initial "high-rate" burst */
    State->InitCounter = 0;
  
    /* Update buffer delay */
    TransmissionTime = StreamSize * 8.0 * 1000.0 / BottleNeck;  /* ms */
    State->StillBuffered += TransmissionTime;
    State->StillBuffered -= (FrameSamples * 1000) / FS;     /* ms */
    if (State->StillBuffered < 0.0)
      State->StillBuffered = 0.0;
  
  }
  
  
  void WebRtcIsac_InitRateModel(
      RateModel *State)
  {
    State->PrevExceed      = 0;                        /* boolean */
    State->ExceedAgo       = 0;                        /* ms */
    State->BurstCounter    = 0;                        /* packets */
    State->InitCounter     = INIT_BURST_LEN + 10;    /* packets */
    State->StillBuffered   = 1.0;                    /* ms */
  }
  
  int WebRtcIsac_GetNewFrameLength(
      double bottle_neck,
      int    current_framesamples)
  {
    int new_framesamples;
  
    const int Thld_20_30 = 20000;
  
    //const int Thld_30_20 = 30000;
    const int Thld_30_20 = 1000000;   // disable 20 ms frames
  
    const int Thld_30_60 = 18000;
    //const int Thld_30_60 = 0;      // disable 60 ms frames
  
    const int Thld_60_30 = 27000;
  
  
    new_framesamples = current_framesamples;
  
    /* find new framelength */
    switch(current_framesamples) {
      case 320:
        if (bottle_neck < Thld_20_30)
          new_framesamples = 480;
        break;
      case 480:
        if (bottle_neck < Thld_30_60)
          new_framesamples = 960;
        else if (bottle_neck > Thld_30_20)
          new_framesamples = 320;
        break;
      case 960:
        if (bottle_neck >= Thld_60_30)
          new_framesamples = 480;
        break;
    }
  
    return new_framesamples;
  }
  
  double WebRtcIsac_GetSnr(
      double bottle_neck,
      int    framesamples)
  {
    double s2nr;
  
    const double a_20 = -30.0;
    const double b_20 = 0.8;
    const double c_20 = 0.0;
  
    const double a_30 = -23.0;
    const double b_30 = 0.48;
    const double c_30 = 0.0;
  
    const double a_60 = -23.0;
    const double b_60 = 0.53;
    const double c_60 = 0.0;
  
  
    /* find new SNR value */
    switch(framesamples) {
      case 320:
        s2nr = a_20 + b_20 * bottle_neck * 0.001 + c_20 * bottle_neck *
            bottle_neck * 0.000001;
        break;
      case 480:
        s2nr = a_30 + b_30 * bottle_neck * 0.001 + c_30 * bottle_neck *
            bottle_neck * 0.000001;
        break;
      case 960:
        s2nr = a_60 + b_60 * bottle_neck * 0.001 + c_60 * bottle_neck *
            bottle_neck * 0.000001;
        break;
      default:
        s2nr = 0;
    }
  
    return s2nr;
  
  }
  