text: /*
   *  Copyright (c) 2011 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.
   */
  
  /*
   * encode.c
   *
   * This file contains definition of funtions for encoding.
   * Decoding of upper-band, including 8-12 kHz, when the bandwidth is
   * 0-12 kHz, and 8-16 kHz, when the bandwidth is 0-16 kHz.
   *
   */
  
  #include <stdlib.h>
  #include <string.h>
  
  #include "structs.h"
  #include "codec.h"
  #include "pitch_estimator.h"
  #include "entropy_coding.h"
  #include "arith_routines.h"
  #include "pitch_gain_tables.h"
  #include "pitch_lag_tables.h"
  #include "spectrum_ar_model_tables.h"
  #include "lpc_tables.h"
  #include "lpc_analysis.h"
  #include "bandwidth_estimator.h"
  #include "lpc_shape_swb12_tables.h"
  #include "lpc_shape_swb16_tables.h"
  #include "lpc_gain_swb_tables.h"
  
  
  #define UB_LOOKAHEAD 24
  
  /*
    Rate allocation tables of lower and upper-band bottleneck for
    12kHz & 16kHz bandwidth.
  
    12 kHz bandwidth
    -----------------
    The overall bottleneck of the coder is between 38 kbps and 45 kbps. We have
    considered 7 enteries, uniformly distributed in this interval, i.e. 38,
    39.17, 40.33, 41.5, 42.67, 43.83 and 45. For every entery, the lower-band
    and the upper-band bottlenecks are specified in
    'kLowerBandBitRate12' and 'kUpperBandBitRate12'
    tables, respectively. E.g. the overall rate of 41.5 kbps corresponts to a
    bottleneck of 31 kbps for lower-band and 27 kbps for upper-band. Given an
    overall bottleneck of the codec, we use linear interpolation to get
    lower-band and upper-band bottlenecks.
  
    16 kHz bandwidth
    -----------------
    The overall bottleneck of the coder is between 50 kbps and 56 kbps. We have
    considered 7 enteries, uniformly distributed in this interval, i.e. 50, 51.2,
    52.4, 53.6, 54.8 and 56. For every entery, the lower-band and the upper-band
    bottlenecks are specified in 'kLowerBandBitRate16' and
    'kUpperBandBitRate16' tables, respectively. E.g. the overall rate
    of 53.6 kbps corresponts to a bottleneck of 32 kbps for lower-band and 30
    kbps for upper-band. Given an overall bottleneck of the codec, we use linear
    interpolation to get lower-band and upper-band bottlenecks.
  
  */
  
  //     38  39.17  40.33   41.5  42.67  43.83     45
  static const WebRtc_Word16 kLowerBandBitRate12[7] = {
    29000, 30000, 30000, 31000, 31000, 32000, 32000};
  static const WebRtc_Word16 kUpperBandBitRate12[7] = {
    25000, 25000, 27000, 27000, 29000, 29000, 32000};
  
  //    50     51.2  52.4   53.6   54.8    56
  static const WebRtc_Word16 kLowerBandBitRate16[6] = {
    31000, 31000, 32000, 32000, 32000, 32000};
  static const WebRtc_Word16 kUpperBandBitRate16[6] = {
    28000, 29000, 29000, 30000, 31000, 32000};
  
  /******************************************************************************
   * WebRtcIsac_RateAllocation()
   * Internal function to perform a rate-allocation for upper and lower-band,
   * given a total rate.
   *
   * Input:
   *   - inRateBitPerSec           : a total bottleneck in bits/sec.
   *
   * Output:
   *   - rateLBBitPerSec           : a bottleneck allocated to the lower-band
   *                                 in bits/sec.
   *   - rateUBBitPerSec           : a bottleneck allocated to the upper-band
   *                                 in bits/sec.
   *
   * Return value                  : 0 if rate allocation has been successful.
   *                                -1 if failed to allocate rates.
   */
  
  WebRtc_Word16
  WebRtcIsac_RateAllocation(
      WebRtc_Word32         inRateBitPerSec,
      double*             rateLBBitPerSec,
      double*             rateUBBitPerSec,
      enum ISACBandwidth* bandwidthKHz)
  {
    WebRtc_Word16 idx;
    double idxD;
    double idxErr;
    if(inRateBitPerSec < 38000)
    {
      // If the given overall bottleneck is less than 38000 then
      // then codec has to operate in wideband mode, i.e. 8 kHz
      // bandwidth.
      *rateLBBitPerSec = (WebRtc_Word16)((inRateBitPerSec > 32000)?
                                         32000:inRateBitPerSec);
      *rateUBBitPerSec = 0;
      *bandwidthKHz = isac8kHz;
    }
    else if((inRateBitPerSec >= 38000) && (inRateBitPerSec < 50000))
    {
      // At a bottleneck between 38 and 50 kbps the codec is operating
      // at 12 kHz bandwidth. Using xxxBandBitRate12[] to calculates
      // upper/lower bottleneck
  
      // find the bottlenecks by linear interpolation
      // step is (45000 - 38000)/6.0 we use the inverse of it.
      const double stepSizeInv = 8.5714286e-4;
      idxD = (inRateBitPerSec - 38000) * stepSizeInv;
      idx = (idxD >= 6)? 6:((WebRtc_Word16)idxD);
      idxErr = idxD - idx;
      *rateLBBitPerSec = kLowerBandBitRate12[idx];
      *rateUBBitPerSec = kUpperBandBitRate12[idx];
  
      if(idx < 6)
      {
        *rateLBBitPerSec += (WebRtc_Word16)(idxErr *
                                            (kLowerBandBitRate12[idx + 1] -
                                             kLowerBandBitRate12[idx]));
        *rateUBBitPerSec += (WebRtc_Word16)(idxErr *
                                            (kUpperBandBitRate12[idx + 1] -
                                             kUpperBandBitRate12[idx]));
      }
  
      *bandwidthKHz = isac12kHz;
    }
    else if((inRateBitPerSec >= 50000) && (inRateBitPerSec <= 56000))
    {
      // A bottleneck between 50 and 56 kbps corresponds to bandwidth
      // of 16 kHz. Using xxxBandBitRate16[] to calculates
      // upper/lower bottleneck
  
      // find the bottlenecks by linear interpolation
      // step is (56000 - 50000)/5 we use the inverse of it
      const double stepSizeInv = 8.3333333e-4;
      idxD = (inRateBitPerSec - 50000) * stepSizeInv;
      idx = (idxD >= 5)? 5:((WebRtc_Word16)idxD);
      idxErr = idxD - idx;
      *rateLBBitPerSec = kLowerBandBitRate16[idx];
      *rateUBBitPerSec  = kUpperBandBitRate16[idx];
  
      if(idx < 5)
      {
        *rateLBBitPerSec += (WebRtc_Word16)(idxErr *
                                            (kLowerBandBitRate16[idx + 1] -
                                             kLowerBandBitRate16[idx]));
  
        *rateUBBitPerSec += (WebRtc_Word16)(idxErr *
                                            (kUpperBandBitRate16[idx + 1] -
                                             kUpperBandBitRate16[idx]));
      }
  
      *bandwidthKHz = isac16kHz;
    }
    else
    {
      // Out-of-range botlteneck value.
      return -1;
    }
  
    // limit the values.
    *rateLBBitPerSec = (*rateLBBitPerSec > 32000)? 32000:*rateLBBitPerSec;
    *rateUBBitPerSec = (*rateUBBitPerSec > 32000)? 32000:*rateUBBitPerSec;
  
    return 0;
  }
  
  
  
  int
  WebRtcIsac_EncodeLb(
      float*           in,
      ISACLBEncStruct* ISACencLB_obj,
      WebRtc_Word16      codingMode,
      WebRtc_Word16      bottleneckIndex)
  {
    int stream_length = 0;
    int err;
    int k;
    int iterCntr;
  
    double lofilt_coef[(ORDERLO+1)*SUBFRAMES];
    double hifilt_coef[(ORDERHI+1)*SUBFRAMES];
    float LP[FRAMESAMPLES_HALF];
    float HP[FRAMESAMPLES_HALF];
  
    double LP_lookahead[FRAMESAMPLES_HALF];
    double HP_lookahead[FRAMESAMPLES_HALF];
    double LP_lookahead_pf[FRAMESAMPLES_HALF + QLOOKAHEAD];
    double LPw[FRAMESAMPLES_HALF];
  
    double HPw[FRAMESAMPLES_HALF];
    double LPw_pf[FRAMESAMPLES_HALF];
    WebRtc_Word16 fre[FRAMESAMPLES_HALF];   /* Q7 */
    WebRtc_Word16 fim[FRAMESAMPLES_HALF];   /* Q7 */
  
    double PitchLags[4];
    double PitchGains[4];
    WebRtc_Word16 PitchGains_Q12[4];
    WebRtc_Word16 AvgPitchGain_Q12;
  
    int frame_mode; /* 0 for 30ms, 1 for 60ms */
    int processed_samples, status = 0;
  
    double bits_gains;
    int bmodel;
  
    transcode_obj transcodingParam;
    double bytesLeftSpecCoding;
    WebRtc_UWord16 payloadLimitBytes;
  
    /* copy new frame length and bottle neck rate only for the first
       10 ms data */
    if (ISACencLB_obj->buffer_index == 0) {
      /* set the framelength for the next packet */
      ISACencLB_obj->current_framesamples = ISACencLB_obj->new_framelength;
    }
    /* frame_mode is 0 (30 ms) or 1 (60 ms)  */
    frame_mode = ISACencLB_obj->current_framesamples/MAX_FRAMESAMPLES;
    /* processed_samples: 480 (30, 60 ms) */
    processed_samples = ISACencLB_obj->current_framesamples/(frame_mode+1);
  
    /* buffer speech samples (by 10ms packet) until the framelength */
    /* is reached (30 or 60 ms)                                     */
    /****************************************************************/
  
    /* fill the buffer with 10ms input data */
    for (k = 0; k < FRAMESAMPLES_10ms; k++) {
      ISACencLB_obj->data_buffer_float[k + ISACencLB_obj->buffer_index] =
          in[k];
    }
  
    /* if buffersize is not equal to current framesize then increase index
       and return. We do no encoding untill we have enough audio.  */
    if (ISACencLB_obj->buffer_index + FRAMESAMPLES_10ms != processed_samples) {
      ISACencLB_obj->buffer_index += FRAMESAMPLES_10ms;
      return 0;
    }
    /* if buffer reached the right size, reset index and continue with
       encoding the frame */
    ISACencLB_obj->buffer_index = 0;
  
    /* end of buffer function */
    /**************************/
  
    /* encoding */
    /************/
  
    if (frame_mode == 0 || ISACencLB_obj->frame_nb == 0 ) {
      // This is to avoid Linux warnings until we change 'int' to 'Word32'
      // at all places.
      int intVar;
      /* reset bitstream */
      ISACencLB_obj->bitstr_obj.W_upper = 0xFFFFFFFF;
      ISACencLB_obj->bitstr_obj.streamval = 0;
      ISACencLB_obj->bitstr_obj.stream_index = 0;
  
      if((codingMode == 0) && (frame_mode == 0) &&
         (ISACencLB_obj->enforceFrameSize == 0)) {
        ISACencLB_obj->new_framelength =
            WebRtcIsac_GetNewFrameLength(ISACencLB_obj->bottleneck,
                                         ISACencLB_obj->current_framesamples);
      }
  
      ISACencLB_obj->s2nr = WebRtcIsac_GetSnr(
          ISACencLB_obj->bottleneck, ISACencLB_obj->current_framesamples);
  
      /* encode frame length */
      status = WebRtcIsac_EncodeFrameLen(
          ISACencLB_obj->current_framesamples, &ISACencLB_obj->bitstr_obj);
      if (status < 0) {
        /* Wrong frame size */
        return status;
      }
      /* Save framelength for multiple packets memory */
      ISACencLB_obj->SaveEnc_obj.framelength =
          ISACencLB_obj->current_framesamples;
  
      /* To be used for Redundant Coding */
      ISACencLB_obj->lastBWIdx = bottleneckIndex;
      intVar = (int)bottleneckIndex;
      WebRtcIsac_EncodeReceiveBw(&intVar, &ISACencLB_obj->bitstr_obj);
    }
  
    /* split signal in two bands */
    WebRtcIsac_SplitAndFilterFloat(ISACencLB_obj->data_buffer_float, LP, HP,
                                   LP_lookahead, HP_lookahead,    &ISACencLB_obj->prefiltbankstr_obj );
  
    /* estimate pitch parameters and pitch-filter lookahead signal */
    WebRtcIsac_PitchAnalysis(LP_lookahead, LP_lookahead_pf,
                             &ISACencLB_obj->pitchanalysisstr_obj, PitchLags, PitchGains);
  
    /* encode in FIX Q12 */
  
    /* convert PitchGain to Fixed point */
    for (k=0;k<PITCH_SUBFRAMES;k++) {
      PitchGains_Q12[k] = (WebRtc_Word16)(PitchGains[k] * 4096.0);
    }
  
    /* Set where to store data in multiple packets memory */
    if (frame_mode == 0 || ISACencLB_obj->frame_nb == 0)
    {
      ISACencLB_obj->SaveEnc_obj.startIdx = 0;
    } else {
      ISACencLB_obj->SaveEnc_obj.startIdx = 1;
    }
  
    /* quantize & encode pitch parameters */
    WebRtcIsac_EncodePitchGain(PitchGains_Q12, &ISACencLB_obj->bitstr_obj,
                               &ISACencLB_obj->SaveEnc_obj);
    WebRtcIsac_EncodePitchLag(PitchLags, PitchGains_Q12,
                              &ISACencLB_obj->bitstr_obj, &ISACencLB_obj->SaveEnc_obj);
  
    AvgPitchGain_Q12 = (PitchGains_Q12[0] + PitchGains_Q12[1] +
                        PitchGains_Q12[2] + PitchGains_Q12[3])>>2;
  
    /* find coefficients for perceptual pre-filters */
    WebRtcIsac_GetLpcCoefLb(LP_lookahead_pf, HP_lookahead,
                            &ISACencLB_obj->maskfiltstr_obj, ISACencLB_obj->s2nr,
                            PitchGains_Q12, lofilt_coef, hifilt_coef);
  
    /* code LPC model and shape - gains not quantized yet */
    WebRtcIsac_EncodeLpcLb(lofilt_coef, hifilt_coef,  &bmodel, &bits_gains,
                           &ISACencLB_obj->bitstr_obj, &ISACencLB_obj->SaveEnc_obj);
  
    /* convert PitchGains back to FLOAT for pitchfilter_pre */
    for (k = 0; k < 4; k++) {
      PitchGains[k] = ((float)PitchGains_Q12[k])/4096;
    }
  
    /* Store the state of arithmetic coder before coding LPC gains */
    transcodingParam.W_upper      = ISACencLB_obj->bitstr_obj.W_upper;
    transcodingParam.stream_index = ISACencLB_obj->bitstr_obj.stream_index;
    transcodingParam.streamval    = ISACencLB_obj->bitstr_obj.streamval;
    transcodingParam.stream[0]    = ISACencLB_obj->bitstr_obj.stream[
        ISACencLB_obj->bitstr_obj.stream_index - 2];
    transcodingParam.stream[1]    = ISACencLB_obj->bitstr_obj.stream[
        ISACencLB_obj->bitstr_obj.stream_index - 1];
    transcodingParam.stream[2]    = ISACencLB_obj->bitstr_obj.stream[
        ISACencLB_obj->bitstr_obj.stream_index];
  
    /* Store LPC Gains before encoding them */
    for(k = 0; k < SUBFRAMES; k++) {
      transcodingParam.loFiltGain[k] = lofilt_coef[(LPC_LOBAND_ORDER+1)*k];
      transcodingParam.hiFiltGain[k] = hifilt_coef[(LPC_HIBAND_ORDER+1)*k];
    }
  
    /* Code gains */
    WebRtcIsac_EncodeLpcGainLb(lofilt_coef, hifilt_coef,  bmodel,
                               &ISACencLB_obj->bitstr_obj, &ISACencLB_obj->SaveEnc_obj);
  
    /* Get the correct value for the payload limit and calculate the
       number of bytes left for coding the spectrum.*/
    if((frame_mode == 1) && (ISACencLB_obj->frame_nb == 0)) {
      /* It is a 60ms and we are in the first 30ms then the limit at
         this point should be half of the assigned value */
      payloadLimitBytes = ISACencLB_obj->payloadLimitBytes60 >> 1;
    }
    else if (frame_mode == 0) {
      /* It is a 30ms frame */
      /* Subract 3 because termination process may add 3 bytes */
      payloadLimitBytes = ISACencLB_obj->payloadLimitBytes30 - 3;
    } else {
      /* This is the second half of a 60ms frame. */
      /* Subract 3 because termination process may add 3 bytes */
      payloadLimitBytes = ISACencLB_obj->payloadLimitBytes60 - 3;
    }
    bytesLeftSpecCoding = payloadLimitBytes - transcodingParam.stream_index;
  
    /* perceptual pre-filtering (using normalized lattice filter) */
    /* low-band filtering */
    WebRtcIsac_NormLatticeFilterMa(ORDERLO,
                                    ISACencLB_obj->maskfiltstr_obj.PreStateLoF,
                                    ISACencLB_obj->maskfiltstr_obj.PreStateLoG, LP, lofilt_coef, LPw);
    /* high-band filtering */
    WebRtcIsac_NormLatticeFilterMa(ORDERHI,
                                    ISACencLB_obj->maskfiltstr_obj.PreStateHiF,
                                    ISACencLB_obj->maskfiltstr_obj.PreStateHiG, HP, hifilt_coef, HPw);
  
  
    /* pitch filter */
    WebRtcIsac_PitchfilterPre(LPw, LPw_pf, &ISACencLB_obj->pitchfiltstr_obj,
                               PitchLags, PitchGains);
  
    /* transform */
    WebRtcIsac_Time2Spec(LPw_pf, HPw, fre, fim, &ISACencLB_obj->fftstr_obj);
  
  
    /* Save data for multiple packets memory */
    for (k = 0; k < FRAMESAMPLES_HALF; k++) {
      ISACencLB_obj->SaveEnc_obj.fre[k +
                                     ISACencLB_obj->SaveEnc_obj.startIdx*FRAMESAMPLES_HALF] = fre[k];
      ISACencLB_obj->SaveEnc_obj.fim[k +
                                     ISACencLB_obj->SaveEnc_obj.startIdx*FRAMESAMPLES_HALF] = fim[k];
    }
    ISACencLB_obj->SaveEnc_obj.AvgPitchGain[
        ISACencLB_obj->SaveEnc_obj.startIdx] = AvgPitchGain_Q12;
  
    /* quantization and lossless coding */
    err = WebRtcIsac_EncodeSpecLb(fre, fim, &ISACencLB_obj->bitstr_obj,
                                  AvgPitchGain_Q12);
    if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
      /* There has been an error but it was not too large payload
         (we can cure too large payload) */
      if (frame_mode == 1 && ISACencLB_obj->frame_nb == 1) {
        /* If this is the second 30ms of a 60ms frame reset
           this such that in the next call encoder starts fresh. */
        ISACencLB_obj->frame_nb = 0;
      }
      return err;
    }
    iterCntr = 0;
    while((ISACencLB_obj->bitstr_obj.stream_index > payloadLimitBytes) ||
          (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
      double bytesSpecCoderUsed;
      double transcodeScale;
  
      if(iterCntr >= MAX_PAYLOAD_LIMIT_ITERATION) {
        /* We were not able to limit the payload size */
        if((frame_mode == 1) && (ISACencLB_obj->frame_nb == 0)) {
          /* This was the first 30ms of a 60ms frame. Although
             the payload is larger than it should be but we let
             the second 30ms be encoded. Maybe together we
             won't exceed the limit. */
          ISACencLB_obj->frame_nb = 1;
          return 0;
        } else if((frame_mode == 1) && (ISACencLB_obj->frame_nb == 1)) {
          ISACencLB_obj->frame_nb = 0;
        }
  
        if(err != -ISAC_DISALLOWED_BITSTREAM_LENGTH) {
          return -ISAC_PAYLOAD_LARGER_THAN_LIMIT;
        } else {
          return status;
        }
      }
  
      if(err == -ISAC_DISALLOWED_BITSTREAM_LENGTH) {
        bytesSpecCoderUsed = STREAM_SIZE_MAX;
        // being coservative
        transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed * 0.5;
      } else {
        bytesSpecCoderUsed = ISACencLB_obj->bitstr_obj.stream_index -
            transcodingParam.stream_index;
        transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed;
      }
  
      /* To be safe, we reduce the scale depending on
         the number of iterations. */
      transcodeScale *= (1.0 - (0.9 * (double)iterCntr /
                                (double)MAX_PAYLOAD_LIMIT_ITERATION));
  
      /* Scale the LPC Gains */
      for (k = 0; k < SUBFRAMES; k++) {
        lofilt_coef[(LPC_LOBAND_ORDER+1) * k] =
            transcodingParam.loFiltGain[k] * transcodeScale;
        hifilt_coef[(LPC_HIBAND_ORDER+1) * k] =
            transcodingParam.hiFiltGain[k] * transcodeScale;
        transcodingParam.loFiltGain[k] =
            lofilt_coef[(LPC_LOBAND_ORDER+1) * k];
        transcodingParam.hiFiltGain[k] =
            hifilt_coef[(LPC_HIBAND_ORDER+1) * k];
      }
  
      /* Scale DFT coefficients */
      for (k = 0; k < FRAMESAMPLES_HALF; k++) {
        fre[k] = (WebRtc_Word16)(fre[k] * transcodeScale);
        fim[k] = (WebRtc_Word16)(fim[k] * transcodeScale);
      }
  
      /* Save data for multiple packets memory */
      for (k = 0; k < FRAMESAMPLES_HALF; k++) {
        ISACencLB_obj->SaveEnc_obj.fre[k +
                                       ISACencLB_obj->SaveEnc_obj.startIdx * FRAMESAMPLES_HALF] =
            fre[k];
        ISACencLB_obj->SaveEnc_obj.fim[k +
                                       ISACencLB_obj->SaveEnc_obj.startIdx * FRAMESAMPLES_HALF] =
            fim[k];
      }
  
      /* Re-store the state of arithmetic coder before coding LPC gains */
      ISACencLB_obj->bitstr_obj.W_upper = transcodingParam.W_upper;
      ISACencLB_obj->bitstr_obj.stream_index = transcodingParam.stream_index;
      ISACencLB_obj->bitstr_obj.streamval = transcodingParam.streamval;
      ISACencLB_obj->bitstr_obj.stream[transcodingParam.stream_index - 2] =
          transcodingParam.stream[0];
      ISACencLB_obj->bitstr_obj.stream[transcodingParam.stream_index - 1] =
          transcodingParam.stream[1];
      ISACencLB_obj->bitstr_obj.stream[transcodingParam.stream_index] =
          transcodingParam.stream[2];
  
      /* Code gains */
      WebRtcIsac_EncodeLpcGainLb(lofilt_coef, hifilt_coef,  bmodel,
                                 &ISACencLB_obj->bitstr_obj, &ISACencLB_obj->SaveEnc_obj);
  
      /* Update the number of bytes left for encoding the spectrum */
      bytesLeftSpecCoding = payloadLimitBytes -
          transcodingParam.stream_index;
  
      /* Encode the spectrum */
      err = WebRtcIsac_EncodeSpecLb(fre, fim, &ISACencLB_obj->bitstr_obj,
                                    AvgPitchGain_Q12);
      if((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
        /* There has been an error but it was not too large
           payload (we can cure too large payload) */
        if (frame_mode == 1 && ISACencLB_obj->frame_nb == 1) {
          /* If this is the second 30ms of a 60ms frame reset
             this such that in the next call encoder starts fresh. */
          ISACencLB_obj->frame_nb = 0;
        }
        return err;
      }
      iterCntr++;
    }
  
    /* i.e. 60 ms framesize and just processed the first 30ms, */
    /* go back to main function to buffer the other 30ms speech frame */
    if (frame_mode == 1)
    {
      if(ISACencLB_obj->frame_nb == 0)
      {
        ISACencLB_obj->frame_nb = 1;
        return 0;
      }
      else if(ISACencLB_obj->frame_nb == 1)
      {
        ISACencLB_obj->frame_nb = 0;
        /* also update the framelength for next packet,
           in Adaptive mode only */
        if (codingMode == 0 && (ISACencLB_obj->enforceFrameSize == 0))
        {
          ISACencLB_obj->new_framelength =
              WebRtcIsac_GetNewFrameLength(ISACencLB_obj->bottleneck,
                                           ISACencLB_obj->current_framesamples);
        }
      }
    }
    else
    {
      ISACencLB_obj->frame_nb = 0;
    }
  
    /* complete arithmetic coding */
    stream_length = WebRtcIsac_EncTerminate(&ISACencLB_obj->bitstr_obj);
  
    return stream_length;
  }
  
  int
  WebRtcIsac_EncodeUb16(
      float*           in,
      ISACUBEncStruct* ISACencUB_obj,
      WebRtc_Word32      jitterInfo)
  {
    int err;
    int k;
  
    double lpcVecs[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
    double percepFilterParams[(1 + UB_LPC_ORDER) * (SUBFRAMES<<1) +
                              (1 + UB_LPC_ORDER)];
  
    double LP_lookahead[FRAMESAMPLES];
    WebRtc_Word16 fre[FRAMESAMPLES_HALF];   /* Q7 */
    WebRtc_Word16 fim[FRAMESAMPLES_HALF];   /* Q7 */
  
    int status = 0;
  
    double varscale[2];
    double corr[SUBFRAMES<<1][UB_LPC_ORDER + 1];
    double lpcGains[SUBFRAMES<<1];
    transcode_obj transcodingParam;
    double bytesLeftSpecCoding;
    WebRtc_UWord16 payloadLimitBytes;
    WebRtc_UWord16 iterCntr;
    double s2nr;
  
    /* buffer speech samples (by 10ms packet) until the framelength is   */
    /* reached (30 or 60 ms)                                             */
    /*********************************************************************/
  
    /* fill the buffer with 10ms input data */
    for (k = 0; k < FRAMESAMPLES_10ms; k++) {
      ISACencUB_obj->data_buffer_float[k + ISACencUB_obj->buffer_index] =
          in[k];
    }
  
    /* if buffersize is not equal to current framesize, and end of file is
       not reached yet, we don't do encoding unless we have the whole frame */
    if (ISACencUB_obj->buffer_index + FRAMESAMPLES_10ms < FRAMESAMPLES) {
      ISACencUB_obj->buffer_index += FRAMESAMPLES_10ms;
      return 0;
    }
  
    /* end of buffer function */
    /**************************/
  
    /* encoding */
    /************/
  
    /* reset bitstream */
    ISACencUB_obj->bitstr_obj.W_upper = 0xFFFFFFFF;
    ISACencUB_obj->bitstr_obj.streamval = 0;
    ISACencUB_obj->bitstr_obj.stream_index = 0;
  
    /* bandwidth estimation and coding */
    /* To be used for Redundant Coding */
    WebRtcIsac_EncodeJitterInfo(jitterInfo, &ISACencUB_obj->bitstr_obj);
  
    status = WebRtcIsac_EncodeBandwidth(isac16kHz,
                                        &ISACencUB_obj->bitstr_obj);
    if (status < 0) {
      return status;
    }
  
    s2nr = WebRtcIsac_GetSnr(ISACencUB_obj->bottleneck,
                                   FRAMESAMPLES);
  
    memcpy(lpcVecs, ISACencUB_obj->lastLPCVec, UB_LPC_ORDER * sizeof(double));
  
    for (k = 0; k < FRAMESAMPLES; k++) {
      LP_lookahead[k] = ISACencUB_obj->data_buffer_float[UB_LOOKAHEAD + k];
    }
  
    /* find coefficients for perceptual pre-filters */
    WebRtcIsac_GetLpcCoefUb(LP_lookahead, &ISACencUB_obj->maskfiltstr_obj,
                              &lpcVecs[UB_LPC_ORDER], corr, varscale, isac16kHz);
  
    memcpy(ISACencUB_obj->lastLPCVec,
           &lpcVecs[(UB16_LPC_VEC_PER_FRAME - 1) * (UB_LPC_ORDER)],
           sizeof(double) * UB_LPC_ORDER);
  
    /* code LPC model and shape - gains not quantized yet */
    WebRtcIsac_EncodeLpcUB(lpcVecs, &ISACencUB_obj->bitstr_obj,
                             percepFilterParams, isac16kHz, &ISACencUB_obj->SaveEnc_obj);
  
  
    // the first set of lpc parameters are from the last sub-frame of
    // the previous frame. so we don't care about them
    WebRtcIsac_GetLpcGain(s2nr, &percepFilterParams[UB_LPC_ORDER + 1],
                         (SUBFRAMES<<1), lpcGains, corr, varscale);
  
    /* Store the state of arithmetic coder before coding LPC gains */
    transcodingParam.stream_index = ISACencUB_obj->bitstr_obj.stream_index;
    transcodingParam.W_upper      = ISACencUB_obj->bitstr_obj.W_upper;
    transcodingParam.streamval    = ISACencUB_obj->bitstr_obj.streamval;
    transcodingParam.stream[0]    = ISACencUB_obj->bitstr_obj.stream[
        ISACencUB_obj->bitstr_obj.stream_index - 2];
    transcodingParam.stream[1]    = ISACencUB_obj->bitstr_obj.stream[
        ISACencUB_obj->bitstr_obj.stream_index - 1];
    transcodingParam.stream[2]    = ISACencUB_obj->bitstr_obj.stream[
        ISACencUB_obj->bitstr_obj.stream_index];
  
    /* Store LPC Gains before encoding them */
    for(k = 0; k < SUBFRAMES; k++) {
      transcodingParam.loFiltGain[k] = lpcGains[k];
      transcodingParam.hiFiltGain[k] = lpcGains[SUBFRAMES + k];
    }
  
    // Store the gains for multiple encoding
    memcpy(ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains, (SUBFRAMES << 1) * sizeof(double));
  
    WebRtcIsac_EncodeLpcGainUb(lpcGains, &ISACencUB_obj->bitstr_obj,
                               ISACencUB_obj->SaveEnc_obj.lpcGainIndex);
    WebRtcIsac_EncodeLpcGainUb(&lpcGains[SUBFRAMES], &ISACencUB_obj->bitstr_obj,
                               &ISACencUB_obj->SaveEnc_obj.lpcGainIndex[SUBFRAMES]);
  
    /* Get the correct value for the payload limit and calculate the number of
       bytes left for coding the spectrum. It is a 30ms frame
       Subract 3 because termination process may add 3 bytes */
    payloadLimitBytes = ISACencUB_obj->maxPayloadSizeBytes -
        ISACencUB_obj->numBytesUsed - 3;
    bytesLeftSpecCoding = payloadLimitBytes -
        ISACencUB_obj->bitstr_obj.stream_index;
  
    for (k = 0; k < (SUBFRAMES<<1); k++) {
      percepFilterParams[k*(UB_LPC_ORDER + 1) + (UB_LPC_ORDER + 1)] =
          lpcGains[k];
    }
  
    /* perceptual pre-filtering (using normalized lattice filter) */
    /* first half-frame filtering */
    WebRtcIsac_NormLatticeFilterMa(UB_LPC_ORDER,
                                    ISACencUB_obj->maskfiltstr_obj.PreStateLoF,
                                    ISACencUB_obj->maskfiltstr_obj.PreStateLoG,
                                    &ISACencUB_obj->data_buffer_float[0],
                                    &percepFilterParams[UB_LPC_ORDER + 1],
                                    &LP_lookahead[0]);
  
    /* Second half-frame filtering */
    WebRtcIsac_NormLatticeFilterMa(UB_LPC_ORDER,
                                    ISACencUB_obj->maskfiltstr_obj.PreStateLoF,
                                    ISACencUB_obj->maskfiltstr_obj.PreStateLoG,
                                    &ISACencUB_obj->data_buffer_float[FRAMESAMPLES_HALF],
                                    &percepFilterParams[(UB_LPC_ORDER + 1) + SUBFRAMES *
                                                        (UB_LPC_ORDER + 1)], &LP_lookahead[FRAMESAMPLES_HALF]);
  
    WebRtcIsac_Time2Spec(&LP_lookahead[0], &LP_lookahead[FRAMESAMPLES_HALF],
                        fre, fim, &ISACencUB_obj->fftstr_obj);
  
    //Store FFT coefficients for multiple encoding
    memcpy(&ISACencUB_obj->SaveEnc_obj.realFFT, fre,
           FRAMESAMPLES_HALF * sizeof(WebRtc_Word16));
  
    memcpy(&ISACencUB_obj->SaveEnc_obj.imagFFT, fim,
           FRAMESAMPLES_HALF * sizeof(WebRtc_Word16));
  
    // Prepare the audio buffer for the next packet
    // move the last 3 ms to the beginning of the buffer
    memcpy(ISACencUB_obj->data_buffer_float,
           &ISACencUB_obj->data_buffer_float[FRAMESAMPLES],
           LB_TOTAL_DELAY_SAMPLES * sizeof(float));
    // start writing with 3 ms delay to compensate for the delay
    // of the lower-band.
    ISACencUB_obj->buffer_index = LB_TOTAL_DELAY_SAMPLES;
  
    // Save the bit-stream object at this point for FEC.
    memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj,
           &ISACencUB_obj->bitstr_obj, sizeof(Bitstr));
  
    /* quantization and lossless coding */
    err = WebRtcIsac_EncodeSpecUB16(fre, fim, &ISACencUB_obj->bitstr_obj);
    if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
      return err;
    }
  
    iterCntr = 0;
    while((ISACencUB_obj->bitstr_obj.stream_index > payloadLimitBytes) ||
          (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
      double bytesSpecCoderUsed;
      double transcodeScale;
  
      if (iterCntr >= MAX_PAYLOAD_LIMIT_ITERATION) {
        /* We were not able to limit the payload size */
        return -ISAC_PAYLOAD_LARGER_THAN_LIMIT;
      }
  
      if (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH) {
        bytesSpecCoderUsed = STREAM_SIZE_MAX;
        // being conservative
        transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed * 0.5;
      } else {
        bytesSpecCoderUsed = ISACencUB_obj->bitstr_obj.stream_index -
            transcodingParam.stream_index;
        transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed;
      }
  
      /* To be safe, we reduce the scale depending on the
         number of iterations. */
      transcodeScale *= (1.0 - (0.9 * (double)iterCntr/
                                (double)MAX_PAYLOAD_LIMIT_ITERATION));
  
      /* Scale the LPC Gains */
      for (k = 0; k < SUBFRAMES; k++) {
        transcodingParam.loFiltGain[k] *= transcodeScale;
        transcodingParam.hiFiltGain[k] *= transcodeScale;
      }
  
      /* Scale DFT coefficients */
      for (k = 0; k < FRAMESAMPLES_HALF; k++) {
        fre[k] = (WebRtc_Word16)(fre[k] * transcodeScale + 0.5);
        fim[k] = (WebRtc_Word16)(fim[k] * transcodeScale + 0.5);
      }
  
      //Store FFT coefficients for multiple encoding
      memcpy(&ISACencUB_obj->SaveEnc_obj.realFFT, fre,
             FRAMESAMPLES_HALF * sizeof(WebRtc_Word16));
  
      memcpy(&ISACencUB_obj->SaveEnc_obj.imagFFT, fim,
             FRAMESAMPLES_HALF * sizeof(WebRtc_Word16));
  
  
      /* Store the state of arithmetic coder before coding LPC gains */
      ISACencUB_obj->bitstr_obj.W_upper = transcodingParam.W_upper;
  
      ISACencUB_obj->bitstr_obj.stream_index = transcodingParam.stream_index;
  
      ISACencUB_obj->bitstr_obj.streamval = transcodingParam.streamval;
  
      ISACencUB_obj->bitstr_obj.stream[transcodingParam.stream_index - 2] =
          transcodingParam.stream[0];
  
      ISACencUB_obj->bitstr_obj.stream[transcodingParam.stream_index - 1] =
          transcodingParam.stream[1];
  
      ISACencUB_obj->bitstr_obj.stream[transcodingParam.stream_index] =
          transcodingParam.stream[2];
  
      // Store the gains for multiple encoding
      memcpy(ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains,
             (SUBFRAMES << 1) * sizeof(double));
  
      WebRtcIsac_EncodeLpcGainUb(transcodingParam.loFiltGain,
                                 &ISACencUB_obj->bitstr_obj,
                                 ISACencUB_obj->SaveEnc_obj.lpcGainIndex);
      WebRtcIsac_EncodeLpcGainUb(transcodingParam.hiFiltGain,
                                 &ISACencUB_obj->bitstr_obj,
                                 &ISACencUB_obj->SaveEnc_obj.lpcGainIndex[SUBFRAMES]);
  
      /* Update the number of bytes left for encoding the spectrum */
      bytesLeftSpecCoding = payloadLimitBytes -
          ISACencUB_obj->bitstr_obj.stream_index;
  
      // Save the bit-stream object at this point for FEC.
      memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj,
             &ISACencUB_obj->bitstr_obj, sizeof(Bitstr));
  
      /* Encode the spectrum */
      err = WebRtcIsac_EncodeSpecUB16(fre, fim, &ISACencUB_obj->bitstr_obj);
      if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
        /* There has been an error but it was not too large payload
           (we can cure too large payload) */
        return err;
      }
      iterCntr++;
    }
  
    /* complete arithmetic coding */
    return WebRtcIsac_EncTerminate(&ISACencUB_obj->bitstr_obj);
  }
  
  
  int
  WebRtcIsac_EncodeUb12(
      float*           in,
      ISACUBEncStruct* ISACencUB_obj,
      WebRtc_Word32      jitterInfo)
  {
    int err;
    int k;
    int iterCntr;
  
    double lpcVecs[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
  
    double percepFilterParams[(1 + UB_LPC_ORDER) * SUBFRAMES];
    float LP[FRAMESAMPLES_HALF];
    float HP[FRAMESAMPLES_HALF];
  
    double LP_lookahead[FRAMESAMPLES_HALF];
    double HP_lookahead[FRAMESAMPLES_HALF];
    double LPw[FRAMESAMPLES_HALF];
  
    double HPw[FRAMESAMPLES_HALF];
    WebRtc_Word16 fre[FRAMESAMPLES_HALF];   /* Q7 */
    WebRtc_Word16 fim[FRAMESAMPLES_HALF];   /* Q7 */
  
    int status = 0;
  
    double varscale[1];
  
    double corr[UB_LPC_GAIN_DIM][UB_LPC_ORDER + 1];
    double lpcGains[SUBFRAMES];
    transcode_obj transcodingParam;
    double bytesLeftSpecCoding;
    WebRtc_UWord16 payloadLimitBytes;
    double s2nr;
  
    /* buffer speech samples (by 10ms packet) until the framelength is  */
    /* reached (30 or 60 ms)                                            */
    /********************************************************************/
  
    /* fill the buffer with 10ms input data */
    for (k=0; k<FRAMESAMPLES_10ms; k++) {
      ISACencUB_obj->data_buffer_float[k + ISACencUB_obj->buffer_index] =
          in[k];
    }
  
    /* if buffer-size is not equal to current frame-size then increase the
       index and return. We do the encoding when we have enough audio.     */
    if (ISACencUB_obj->buffer_index + FRAMESAMPLES_10ms < FRAMESAMPLES) {
      ISACencUB_obj->buffer_index += FRAMESAMPLES_10ms;
      return 0;
    }
    /* if buffer reached the right size, reset index and continue
       with encoding the frame */
    ISACencUB_obj->buffer_index = 0;
  
    /* end of buffer function */
    /**************************/
  
    /* encoding */
    /************/
  
    /* reset bitstream */
    ISACencUB_obj->bitstr_obj.W_upper = 0xFFFFFFFF;
    ISACencUB_obj->bitstr_obj.streamval = 0;
    ISACencUB_obj->bitstr_obj.stream_index = 0;
  
    /* bandwidth estimation and coding */
    /* To be used for Redundant Coding */
    WebRtcIsac_EncodeJitterInfo(jitterInfo, &ISACencUB_obj->bitstr_obj);
  
    status = WebRtcIsac_EncodeBandwidth(isac12kHz,
                                        &ISACencUB_obj->bitstr_obj);
    if (status < 0) {
      return status;
    }
  
  
    s2nr = WebRtcIsac_GetSnr(ISACencUB_obj->bottleneck,
                                   FRAMESAMPLES);
  
    /* split signal in two bands */
    WebRtcIsac_SplitAndFilterFloat(ISACencUB_obj->data_buffer_float, HP, LP,
                                   HP_lookahead, LP_lookahead, &ISACencUB_obj->prefiltbankstr_obj);
  
    /* find coefficients for perceptual pre-filters */
    WebRtcIsac_GetLpcCoefUb(LP_lookahead, &ISACencUB_obj->maskfiltstr_obj,
                              lpcVecs, corr, varscale, isac12kHz);
  
    /* code LPC model and shape - gains not quantized yet */
    WebRtcIsac_EncodeLpcUB(lpcVecs, &ISACencUB_obj->bitstr_obj,
                             percepFilterParams, isac12kHz, &ISACencUB_obj->SaveEnc_obj);
  
    WebRtcIsac_GetLpcGain(s2nr, percepFilterParams, SUBFRAMES, lpcGains,
                         corr, varscale);
  
    /* Store the state of arithmetic coder before coding LPC gains */
    transcodingParam.W_upper = ISACencUB_obj->bitstr_obj.W_upper;
  
    transcodingParam.stream_index = ISACencUB_obj->bitstr_obj.stream_index;
  
    transcodingParam.streamval = ISACencUB_obj->bitstr_obj.streamval;
  
    transcodingParam.stream[0] = ISACencUB_obj->bitstr_obj.stream[
        ISACencUB_obj->bitstr_obj.stream_index - 2];
  
    transcodingParam.stream[1] = ISACencUB_obj->bitstr_obj.stream[
        ISACencUB_obj->bitstr_obj.stream_index - 1];
  
    transcodingParam.stream[2] = ISACencUB_obj->bitstr_obj.stream[
        ISACencUB_obj->bitstr_obj.stream_index];
  
    /* Store LPC Gains before encoding them */
    for(k = 0; k < SUBFRAMES; k++) {
      transcodingParam.loFiltGain[k] = lpcGains[k];
    }
  
    // Store the gains for multiple encoding
    memcpy(ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains, SUBFRAMES *
           sizeof(double));
  
    WebRtcIsac_EncodeLpcGainUb(lpcGains, &ISACencUB_obj->bitstr_obj,
                               ISACencUB_obj->SaveEnc_obj.lpcGainIndex);
  
    for(k = 0; k < SUBFRAMES; k++) {
      percepFilterParams[k*(UB_LPC_ORDER + 1)] = lpcGains[k];
    }
  
    /* perceptual pre-filtering (using normalized lattice filter) */
    /* low-band filtering */
    WebRtcIsac_NormLatticeFilterMa(UB_LPC_ORDER,
                                    ISACencUB_obj->maskfiltstr_obj.PreStateLoF,
                                    ISACencUB_obj->maskfiltstr_obj.PreStateLoG, LP, percepFilterParams,
                                    LPw);
  
    /* Get the correct value for the payload limit and calculate the number
       of bytes left for coding the spectrum. It is a 30ms frame Subract 3
       because termination process may add 3 bytes */
    payloadLimitBytes = ISACencUB_obj->maxPayloadSizeBytes -
        ISACencUB_obj->numBytesUsed - 3;
    bytesLeftSpecCoding = payloadLimitBytes -
        ISACencUB_obj->bitstr_obj.stream_index;
  
    memset(HPw, 0, sizeof(double) * FRAMESAMPLES_HALF);
  
    /* transform */
    WebRtcIsac_Time2Spec(LPw, HPw, fre, fim, &ISACencUB_obj->fftstr_obj);
  
    //Store real FFT coefficients for multiple encoding
    memcpy(&ISACencUB_obj->SaveEnc_obj.realFFT, fre,
           FRAMESAMPLES_HALF * sizeof(WebRtc_Word16));
  
    //Store imaginary FFT coefficients for multiple encoding
    memcpy(&ISACencUB_obj->SaveEnc_obj.imagFFT, fim,
           FRAMESAMPLES_HALF * sizeof(WebRtc_Word16));
  
    // Save the bit-stream object at this point for FEC.
    memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj,
           &ISACencUB_obj->bitstr_obj, sizeof(Bitstr));
  
    /* quantization and lossless coding */
    err = WebRtcIsac_EncodeSpecUB12(fre, fim, &ISACencUB_obj->bitstr_obj);
    if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
      /* There has been an error but it was not too large
         payload (we can cure too large payload) */
      return err;
    }
    iterCntr = 0;
    while((ISACencUB_obj->bitstr_obj.stream_index > payloadLimitBytes) ||
          (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
      double bytesSpecCoderUsed;
      double transcodeScale;
  
      if (iterCntr >= MAX_PAYLOAD_LIMIT_ITERATION) {
        /* We were not able to limit the payload size */
        return -ISAC_PAYLOAD_LARGER_THAN_LIMIT;
      }
  
      if (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH) {
        bytesSpecCoderUsed = STREAM_SIZE_MAX;
        // being coservative
        transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed * 0.5;
      } else {
        bytesSpecCoderUsed = ISACencUB_obj->bitstr_obj.stream_index -
            transcodingParam.stream_index;
        transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed;
      }
  
      /* To be safe, we reduce the scale depending on the
         number of iterations. */
      transcodeScale *= (1.0 - (0.9 * (double)iterCntr/
                                (double)MAX_PAYLOAD_LIMIT_ITERATION));
  
      /* Scale the LPC Gains */
      for (k = 0; k < SUBFRAMES; k++) {
        transcodingParam.loFiltGain[k] *= transcodeScale;
      }
  
      /* Scale DFT coefficients */
      for (k = 0; k < FRAMESAMPLES_HALF; k++) {
        fre[k] = (WebRtc_Word16)(fre[k] * transcodeScale + 0.5);
        fim[k] = (WebRtc_Word16)(fim[k] * transcodeScale + 0.5);
      }
  
      //Store real FFT coefficients for multiple encoding
      memcpy(&ISACencUB_obj->SaveEnc_obj.realFFT, fre,
             FRAMESAMPLES_HALF * sizeof(WebRtc_Word16));
  
      //Store imaginary FFT coefficients for multiple encoding
      memcpy(&ISACencUB_obj->SaveEnc_obj.imagFFT, fim,
             FRAMESAMPLES_HALF * sizeof(WebRtc_Word16));
  
  
      /* Re-store the state of arithmetic coder before coding LPC gains */
      ISACencUB_obj->bitstr_obj.W_upper = transcodingParam.W_upper;
  
      ISACencUB_obj->bitstr_obj.stream_index = transcodingParam.stream_index;
  
      ISACencUB_obj->bitstr_obj.streamval = transcodingParam.streamval;
  
      ISACencUB_obj->bitstr_obj.stream[transcodingParam.stream_index - 2] =
          transcodingParam.stream[0];
  
      ISACencUB_obj->bitstr_obj.stream[transcodingParam.stream_index - 1] =
          transcodingParam.stream[1];
  
      ISACencUB_obj->bitstr_obj.stream[transcodingParam.stream_index] =
          transcodingParam.stream[2];
  
      // Store the gains for multiple encoding
      memcpy(&ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains, SUBFRAMES *
             sizeof(double));
  
      // encode LPC gain and store quantization indices. HAving quantization
      // indices reduces transcoding complexity if 'scale factor' is 1.
      WebRtcIsac_EncodeLpcGainUb(transcodingParam.loFiltGain,
                                 &ISACencUB_obj->bitstr_obj,
                                 ISACencUB_obj->SaveEnc_obj.lpcGainIndex);
  
      // Save the bit-stream object at this point for FEC.
      memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj,
             &ISACencUB_obj->bitstr_obj, sizeof(Bitstr));
  
      /* Update the number of bytes left for encoding the spectrum */
      bytesLeftSpecCoding = payloadLimitBytes -
          ISACencUB_obj->bitstr_obj.stream_index;
  
      /* Encode the spectrum */
      err = WebRtcIsac_EncodeSpecUB12(fre, fim,
                                        &ISACencUB_obj->bitstr_obj);
      if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
        /* There has been an error but it was not too large payload
           (we can cure too large payload) */
        return err;
      }
      iterCntr++;
    }
  
    /* complete arithmetic coding */
    return WebRtcIsac_EncTerminate(&ISACencUB_obj->bitstr_obj);
  }
  
  
  
  
  
  
  /* This function is used to create a new bitstream with new BWE.
     The same data as previously encoded with the function WebRtcIsac_Encoder().
     The data needed is taken from the struct, where it was stored
     when calling the encoder. */
  
  int WebRtcIsac_EncodeStoredDataLb(
      const ISAC_SaveEncData_t* ISACSavedEnc_obj,
      Bitstr*                   ISACBitStr_obj,
      int                       BWnumber,
      float                     scale)
  {
    int ii;
    int status;
    int BWno = BWnumber;
  
    const WebRtc_UWord16 *WebRtcIsac_kQPitchGainCdf_ptr[1];
    const WebRtc_UWord16 **cdf;
  
    double tmpLPCcoeffs_lo[(ORDERLO+1)*SUBFRAMES*2];
    double tmpLPCcoeffs_hi[(ORDERHI+1)*SUBFRAMES*2];
    int tmpLPCindex_g[12*2];
    WebRtc_Word16 tmp_fre[FRAMESAMPLES], tmp_fim[FRAMESAMPLES];
  
    /* Sanity Check - possible values for BWnumber is 0 - 23 */
    if ((BWnumber < 0) || (BWnumber > 23)) {
      return -ISAC_RANGE_ERROR_BW_ESTIMATOR;
    }
  
    /* reset bitstream */
    ISACBitStr_obj->W_upper = 0xFFFFFFFF;
    ISACBitStr_obj->streamval = 0;
    ISACBitStr_obj->stream_index = 0;
  
    /* encode frame length */
    status = WebRtcIsac_EncodeFrameLen(ISACSavedEnc_obj->framelength,
                                       ISACBitStr_obj);
    if (status < 0) {
      /* Wrong frame size */
      return status;
    }
  
    /* Transcoding                                                 */
    if ((scale > 0.0) && (scale < 1.0)) {
      /* Compensate LPC gain */
      for (ii = 0;
           ii < ((ORDERLO + 1)* SUBFRAMES * (1 + ISACSavedEnc_obj->startIdx));
           ii++) {
        tmpLPCcoeffs_lo[ii] = scale *  ISACSavedEnc_obj->LPCcoeffs_lo[ii];
      }
      for (ii = 0;
           ii < ((ORDERHI + 1) * SUBFRAMES *(1 + ISACSavedEnc_obj->startIdx));
           ii++) {
        tmpLPCcoeffs_hi[ii] = scale *  ISACSavedEnc_obj->LPCcoeffs_hi[ii];
      }
      /* Scale DFT */
      for (ii = 0;
           ii < (FRAMESAMPLES_HALF * (1 + ISACSavedEnc_obj->startIdx));
           ii++) {
        tmp_fre[ii] = (WebRtc_Word16)((scale) *
                                      (float)ISACSavedEnc_obj->fre[ii]) ;
        tmp_fim[ii] = (WebRtc_Word16)((scale) *
                                      (float)ISACSavedEnc_obj->fim[ii]) ;
      }
    } else {
      for (ii = 0;
           ii < (KLT_ORDER_GAIN * (1 + ISACSavedEnc_obj->startIdx));
           ii++) {
        tmpLPCindex_g[ii] =  ISACSavedEnc_obj->LPCindex_g[ii];
      }
      for (ii = 0;
           ii < (FRAMESAMPLES_HALF * (1 + ISACSavedEnc_obj->startIdx));
           ii++) {
        tmp_fre[ii] = ISACSavedEnc_obj->fre[ii];
        tmp_fim[ii] = ISACSavedEnc_obj->fim[ii];
      }
    }
  
    /* encode bandwidth estimate */
    WebRtcIsac_EncodeReceiveBw(&BWno, ISACBitStr_obj);
  
    /* Loop over number of 30 msec */
    for (ii = 0; ii <= ISACSavedEnc_obj->startIdx; ii++) {
      /* encode pitch gains */
      *WebRtcIsac_kQPitchGainCdf_ptr = WebRtcIsac_kQPitchGainCdf;
      WebRtcIsac_EncHistMulti(ISACBitStr_obj,
                              &ISACSavedEnc_obj->pitchGain_index[ii], WebRtcIsac_kQPitchGainCdf_ptr, 1);
  
      /* entropy coding of quantization pitch lags */
      /* voicing classificiation */
      if (ISACSavedEnc_obj->meanGain[ii] < 0.2) {
        cdf = WebRtcIsac_kQPitchLagCdfPtrLo;
      } else if (ISACSavedEnc_obj->meanGain[ii] < 0.4) {
        cdf = WebRtcIsac_kQPitchLagCdfPtrMid;
      } else {
        cdf = WebRtcIsac_kQPitchLagCdfPtrHi;
      }
      WebRtcIsac_EncHistMulti(ISACBitStr_obj,
                              &ISACSavedEnc_obj->pitchIndex[PITCH_SUBFRAMES*ii], cdf,
                              PITCH_SUBFRAMES);
  
      /* LPC */
      /* entropy coding of model number */
      WebRtcIsac_EncHistMulti(ISACBitStr_obj,
                              &ISACSavedEnc_obj->LPCmodel[ii], WebRtcIsac_kQKltModelCdfPtr, 1);
  
      /* entropy coding of quantization indices - LPC shape only */
      WebRtcIsac_EncHistMulti(ISACBitStr_obj,
                              &ISACSavedEnc_obj->LPCindex_s[KLT_ORDER_SHAPE*ii],
                              WebRtcIsac_kQKltCdfPtrShape[ISACSavedEnc_obj->LPCmodel[ii]],
                              KLT_ORDER_SHAPE);
  
      /* If transcoding, get new LPC gain indices */
      if (scale < 1.0) {
        WebRtcIsac_TranscodeLPCCoef(&tmpLPCcoeffs_lo[(ORDERLO+1) *
                                                     SUBFRAMES*ii], &tmpLPCcoeffs_hi[(ORDERHI+1)*SUBFRAMES*ii],
                                    ISACSavedEnc_obj->LPCmodel[ii],
                                    &tmpLPCindex_g[KLT_ORDER_GAIN * ii]);
      }
  
      /* entropy coding of quantization indices - LPC gain */
      WebRtcIsac_EncHistMulti(ISACBitStr_obj,
                              &tmpLPCindex_g[KLT_ORDER_GAIN*ii], WebRtcIsac_kQKltCdfPtrGain[
                                  ISACSavedEnc_obj->LPCmodel[ii]], KLT_ORDER_GAIN);
  
      /* quantization and lossless coding */
      status = WebRtcIsac_EncodeSpecLb(&tmp_fre[ii*FRAMESAMPLES_HALF],
                                       &tmp_fim[ii*FRAMESAMPLES_HALF], ISACBitStr_obj,
                                       ISACSavedEnc_obj->AvgPitchGain[ii]);
      if (status < 0) {
        return status;
      }
    }
  
    /* complete arithmetic coding */
    return WebRtcIsac_EncTerminate(ISACBitStr_obj);
  }
  
  
  
  
  int WebRtcIsac_EncodeStoredDataUb12(
      const ISACUBSaveEncDataStruct* ISACSavedEnc_obj,
      Bitstr*                        bitStream,
      WebRtc_Word32                    jitterInfo,
      float                          scale)
  {
    int n;
    int err;
    double lpcGain[SUBFRAMES];
    WebRtc_Word16 realFFT[FRAMESAMPLES_HALF];
    WebRtc_Word16 imagFFT[FRAMESAMPLES_HALF];
  
    /* reset bitstream */
    bitStream->W_upper = 0xFFFFFFFF;
    bitStream->streamval = 0;
    bitStream->stream_index = 0;
  
    // Encode jitter index
    WebRtcIsac_EncodeJitterInfo(jitterInfo, bitStream);
  
    err = WebRtcIsac_EncodeBandwidth(isac12kHz, bitStream);
    if(err < 0)
    {
      return err;
    }
  
    // Encode LPC-shape
    WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->indexLPCShape,
                            WebRtcIsac_kLpcShapeCdfMatUb12, UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME);
  
  
    // we only consider scales between zero and one.
    if((scale <= 0.0) || (scale > 1.0))
    {
      scale = 1.0f;
    }
  
    if(scale == 1.0f)
    {
      //memcpy(lpcGain, ISACSavedEnc_obj->lpcGain, SUBFRAMES * sizeof(double));
      WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->lpcGainIndex,
                              WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM);
      // store FFT coefficients
      err = WebRtcIsac_EncodeSpecUB12(ISACSavedEnc_obj->realFFT,
                                        ISACSavedEnc_obj->imagFFT, bitStream);
    }
    else
    {
      /* scale lpc gain and FFT coefficients */
      for(n = 0; n < SUBFRAMES; n++)
      {
        lpcGain[n] = scale * ISACSavedEnc_obj->lpcGain[n];
      }
      // store lpc gain
      WebRtcIsac_StoreLpcGainUb(lpcGain, bitStream);
      for(n = 0; n < FRAMESAMPLES_HALF; n++)
      {
        realFFT[n] = (WebRtc_Word16)(scale * (float)ISACSavedEnc_obj->realFFT[n] + 0.5f);
        imagFFT[n] = (WebRtc_Word16)(scale * (float)ISACSavedEnc_obj->imagFFT[n] + 0.5f);
      }
      // store FFT coefficients
      err = WebRtcIsac_EncodeSpecUB12(realFFT, imagFFT, bitStream);
    }
    if(err < 0)
    {
      // error happened while encoding FFT coefficients.
      return err;
    }
  
    /* complete arithmetic coding */
    return WebRtcIsac_EncTerminate(bitStream);
  }
  
  
  int
  WebRtcIsac_EncodeStoredDataUb16(
      const ISACUBSaveEncDataStruct* ISACSavedEnc_obj,
      Bitstr*                        bitStream,
      WebRtc_Word32                    jitterInfo,
      float                          scale)
  {
    int n;
    int err;
    double lpcGain[SUBFRAMES << 1];
    WebRtc_Word16 realFFT[FRAMESAMPLES_HALF];
    WebRtc_Word16 imagFFT[FRAMESAMPLES_HALF];
  
    /* reset bitstream */
    bitStream->W_upper = 0xFFFFFFFF;
    bitStream->streamval = 0;
    bitStream->stream_index = 0;
  
    // Encode jitter index
    WebRtcIsac_EncodeJitterInfo(jitterInfo, bitStream);
  
    err = WebRtcIsac_EncodeBandwidth(isac16kHz, bitStream);
    if(err < 0)
    {
      return err;
    }
  
    WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->indexLPCShape,
                            WebRtcIsac_kLpcShapeCdfMatUb16, UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME);
  
    // we only consider scales between zero and one.
    if((scale <= 0.0) || (scale > 1.0))
    {
      scale = 1.0f;
    }
  
    if(scale == 1.0f)
    {
      // store gains
      WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->lpcGainIndex,
                              WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM);
      WebRtcIsac_EncHistMulti(bitStream, &ISACSavedEnc_obj->lpcGainIndex[SUBFRAMES],
                              WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM);
      // store FFT coefficients
      err = WebRtcIsac_EncodeSpecUB16(ISACSavedEnc_obj->realFFT,
                                        ISACSavedEnc_obj->imagFFT, bitStream);
  
    }
    else
    {
      /* Scale Gain */
      for(n = 0; n < SUBFRAMES; n++)
      {
        lpcGain[n] = scale * ISACSavedEnc_obj->lpcGain[n];
        lpcGain[n + SUBFRAMES] = scale * ISACSavedEnc_obj->lpcGain[n + SUBFRAMES];
      }
      // store lpc gain
      WebRtcIsac_StoreLpcGainUb(lpcGain, bitStream);
      WebRtcIsac_StoreLpcGainUb(&lpcGain[SUBFRAMES], bitStream);
      /* scale FFT coefficients */
      for(n = 0; n < FRAMESAMPLES_HALF; n++)
      {
        realFFT[n] = (WebRtc_Word16)(scale * (float)ISACSavedEnc_obj->realFFT[n] + 0.5f);
        imagFFT[n] = (WebRtc_Word16)(scale * (float)ISACSavedEnc_obj->imagFFT[n] + 0.5f);
      }
      // store FFT coefficients
      err = WebRtcIsac_EncodeSpecUB16(realFFT, imagFFT, bitStream);
    }
  
    if(err < 0)
    {
      // error happened while encoding FFT coefficients.
      return err;
    }
  
    /* complete arithmetic coding */
    return WebRtcIsac_EncTerminate(bitStream);
  }
  
  
  WebRtc_Word16
  WebRtcIsac_GetRedPayloadUb(
      const ISACUBSaveEncDataStruct* ISACSavedEncObj,
      Bitstr*                        bitStreamObj,
      enum ISACBandwidth             bandwidth)
  {
    int n;
    WebRtc_Word16 status;
    WebRtc_Word16 realFFT[FRAMESAMPLES_HALF];
    WebRtc_Word16 imagFFT[FRAMESAMPLES_HALF];
  
    // store bit-stream object.
    memcpy(bitStreamObj, &ISACSavedEncObj->bitStreamObj, sizeof(Bitstr));
  
    // Scale FFT coefficients.
    for(n = 0; n < FRAMESAMPLES_HALF; n++)
    {
      realFFT[n] = (WebRtc_Word16)((float)ISACSavedEncObj->realFFT[n] *
                                   RCU_TRANSCODING_SCALE_UB + 0.5);
      imagFFT[n] = (WebRtc_Word16)((float)ISACSavedEncObj->imagFFT[n] *
                                   RCU_TRANSCODING_SCALE_UB + 0.5);
    }
  
    switch(bandwidth)
    {
      case isac12kHz:
        {
          status = WebRtcIsac_EncodeSpecUB12(realFFT, imagFFT, bitStreamObj);
          break;
        }
      case isac16kHz:
        {
          status = WebRtcIsac_EncodeSpecUB16(realFFT, imagFFT, bitStreamObj);
          break;
        }
      default:
        return -1;
    }
  
    if(status < 0)
    {
      // error happened
      return status;
    }
    else
    {
      // terminate entropy coding
      return WebRtcIsac_EncTerminate(bitStreamObj);
    }
  }
  