/*
 *  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.
 */

/*
 * isac.c
 *
 * This C file contains the functions for the ISAC API
 *
 */

#include "isac.h"
#include "bandwidth_estimator.h"
#include "crc.h"
#include "entropy_coding.h"
#include "codec.h"
#include "structs.h"
#include "signal_processing_library.h"
#include "lpc_shape_swb16_tables.h"
#include "os_specific_inline.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

#define BIT_MASK_DEC_INIT 0x0001
#define BIT_MASK_ENC_INIT 0x0002

#define LEN_CHECK_SUM_WORD8     4
#define MAX_NUM_LAYERS         10


/****************************************************************************
 * UpdatePayloadSizeLimit()
 *
 * Call this function to update the limit on the payload size. The limit on
 * payload size might change i) if a user ''directly changes the limit by
 * calling xxx_setMaxPayloadSize() or xxx_setMaxRate(), or ii) indirectly
 * when bandwidth is changing. The latter might be the result of bandwidth
 * adaptation, or direct change of the bottleneck in instantaneous mode.
 *
 * This function takes the current overall limit on payload, and translate it
 * to the limits on lower and upper-band. If the codec is in wideband mode
 * then the overall limit and the limit on the lower-band is the same.
 * Otherwise, a fraction of the limit should be allocated to lower-band
 * leaving some room for the upper-band bit-stream. That is why an update
 * of limit is required every time that the bandwidth is changing.
 *
 */
static void UpdatePayloadSizeLimit(
				   ISACMainStruct *instISAC)
{
  WebRtc_Word16 lim30MsPayloadBytes;
  WebRtc_Word16 lim60MsPayloadBytes;

  lim30MsPayloadBytes = WEBRTC_SPL_MIN(
				       (instISAC->maxPayloadSizeBytes),
				       (instISAC->maxRateBytesPer30Ms));

  lim60MsPayloadBytes = WEBRTC_SPL_MIN(
				       (instISAC->maxPayloadSizeBytes),
				       (instISAC->maxRateBytesPer30Ms << 1));

  // The only time that iSAC will have 60 ms
  // frame-size is when operating in wideband so
  // there is no upper-band bit-stream

  if(instISAC->bandwidthKHz == isac8kHz)
    {
      // at 8 kHz there is no upper-band bit-stream
      // therefore the lower-band limit is as the overall
      // limit.
      instISAC->instLB.ISACencLB_obj.payloadLimitBytes60 =
        lim60MsPayloadBytes;
      instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 =
        lim30MsPayloadBytes;
    }
  else
    {
      // when in super-wideband, we only have 30 ms frames
      // Do a rate allocation for the given limit.
      if(lim30MsPayloadBytes > 250)
	{
	  // 4/5 to lower-band the rest for upper-band
	  instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 =
	    (lim30MsPayloadBytes << 2) / 5;
	}
      else if(lim30MsPayloadBytes > 200)
	{
	  // for the interval of 200 to 250 the share of
	  // upper-band linearly grows from 20 to 50;
	  instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 =
	    (lim30MsPayloadBytes << 1) / 5 + 100;
	}
      else
	{
	  // allocate only 20 for upper-band
	  instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 =
	    lim30MsPayloadBytes - 20;
	}
      instISAC->instUB.ISACencUB_obj.maxPayloadSizeBytes =
        lim30MsPayloadBytes;
    }
}


/****************************************************************************
 * UpdateBottleneck()
 *
 * This function updates the bottleneck only if the codec is operating in
 * channel-adaptive mode. Furthermore, as the update of bottleneck might
 * result in an update of bandwidth, therefore, the bottlenech should be
 * updated just right before the first 10ms of a frame is pushed into encoder.
 *
 */
static void UpdateBottleneck(
			     ISACMainStruct *instISAC)
{
  // read the bottleneck from bandwidth estimator for the
  // first 10 ms audio. This way, if there is a change
  // in bandwidth upper and lower-band will be in sync.
  if((instISAC->codingMode == 0) &&
     (instISAC->instLB.ISACencLB_obj.buffer_index == 0) &&
     (instISAC->instLB.ISACencLB_obj.frame_nb == 0))
    {
      WebRtc_Word32 bottleneck;
      WebRtcIsac_GetUplinkBandwidth(&(instISAC->bwestimator_obj),
				    &bottleneck);

      // Adding hysteresis when increasing signal bandwidth
      if((instISAC->bandwidthKHz == isac8kHz)
	 && (bottleneck > 37000)
	 && (bottleneck < 41000))
	{
	  bottleneck = 37000;
	}

      // switching from 12 kHz to 16 kHz is not allowed at this revision
      // If we let this happen, we have to take care of buffer_index and
      // the last LPC vector.
      if((instISAC->bandwidthKHz != isac16kHz) &&
	 (bottleneck > 46000))
	{
	  bottleneck = 46000;
	}

      // we might need a rate allocation.
      if(instISAC->encoderSamplingRateKHz == kIsacWideband)
	{
	  // wideband is the only choise we have here.
	  instISAC->instLB.ISACencLB_obj.bottleneck =
	    (bottleneck > 32000)? 32000:bottleneck;
	  instISAC->bandwidthKHz = isac8kHz;
	}
      else
	{
	  // do the rate-allosation and get the new bandwidth.
	  enum ISACBandwidth bandwidth;
	  WebRtcIsac_RateAllocation(bottleneck,
				    &(instISAC->instLB.ISACencLB_obj.bottleneck),
				    &(instISAC->instUB.ISACencUB_obj.bottleneck),
				    &bandwidth);
	  if(bandwidth != isac8kHz)
	    {
	      instISAC->instLB.ISACencLB_obj.new_framelength = 480;
	    }
	  if(bandwidth != instISAC->bandwidthKHz)
	    {
	      // bandwidth is changing.
	      instISAC->bandwidthKHz = bandwidth;
	      UpdatePayloadSizeLimit(instISAC);
	      if(bandwidth == isac12kHz)
		{
		  instISAC->instLB.ISACencLB_obj.buffer_index = 0;
		}
	      // currently we don't let the bandwidth to switch to 16 kHz
	      // if in adaptive mode. If we let this happen, we have to take
	      // car of buffer_index and the last LPC vector.
	    }
	}
    }
}


/****************************************************************************
 * GetSendBandwidthInfo()
 *
 * This is called to get the bandwidth info. This info is the bandwidth and
 * and the jitter of 'there-to-here' channel, estimated 'here.' These info
 * is signaled in an in-band fashion to the otherside.
 *
 * The call to the bandwidth estimator trigers a recursive averaging which
 * has to be synchronized between encoder & decoder, therefore. The call to
 * BWE should be once per packet. As the BWE info is inserted into bit-stream
 * we need a valid info right before the encodeLB function is going to
 * generating a bit-stream. That is when lower-band buffer has already 20ms
 * of audio, and the 3rd block of 10ms is going to be injected into encoder.
 *
 * Inputs:
 *         - instISAC          : iSAC instance.
 *
 * Outputs:
 *         - bandwidthIndex    : an index which has to be encoded in
 *                               lower-band bit-stream, indicating the
 *                               bandwidth of there-to-here channel.
 *         - jitterInfo        : this indicates if the jitter is high
 *                               or low and it is encoded in upper-band
 *                               bit-stream.
 *
 */
static void GetSendBandwidthInfo(
				 ISACMainStruct* instISAC,
				 WebRtc_Word16*    bandwidthIndex,
				 WebRtc_Word16*    jitterInfo)
{
  if((instISAC->instLB.ISACencLB_obj.buffer_index ==
      (FRAMESAMPLES_10ms << 1)) &&
     (instISAC->instLB.ISACencLB_obj.frame_nb == 0))
    {
      /* bandwidth estimation and coding */
      WebRtcIsac_GetDownlinkBwJitIndexImpl(&(instISAC->bwestimator_obj),
				       bandwidthIndex, jitterInfo, instISAC->decoderSamplingRateKHz);
    }
}


/****************************************************************************
 * WebRtcIsac_AssignSize(...)
 *
 * This function returns the size of the ISAC instance, so that the instance
 * can be created out side iSAC.
 *
 * Output:
 *        - sizeinbytes       : number of bytes needed to allocate for the
 *                              instance.
 *
 * Return value               : 0 - Ok
 *                             -1 - Error
 */
WebRtc_Word16 WebRtcIsac_AssignSize(
				   int *sizeInBytes)
{
  *sizeInBytes = sizeof(ISACMainStruct) * 2 / sizeof(WebRtc_Word16);
  return 0;
}


/****************************************************************************
 * WebRtcIsac_Assign(...)
 *
 * This function assignes the memory already created to the ISAC instance.
 *
 * Input:
 *        - ISAC_main_inst    : address of the pointer to the coder instance.
 *        - instISAC_Addr     : the already allocaded memeory, where we put the
 *                              iSAC struct
 *
 * Return value               : 0 - Ok
 *                             -1 - Error
 */
WebRtc_Word16 WebRtcIsac_Assign(
			       ISACStruct** ISAC_main_inst,
			       void*        instISAC_Addr)
{
  if(instISAC_Addr != NULL)
    {
      ISACMainStruct* instISAC = (ISACMainStruct*)instISAC_Addr;
      instISAC->errorCode = 0;
      instISAC->initFlag = 0;

      // Assign the address
      *ISAC_main_inst = (ISACStruct*)instISAC_Addr;

      // Default is wideband.
      instISAC->encoderSamplingRateKHz = kIsacWideband;
      instISAC->decoderSamplingRateKHz = kIsacWideband;
      instISAC->bandwidthKHz           = isac8kHz;
      return 0;
    }
  else
    {
      return -1;
    }
}


/****************************************************************************
 * WebRtcIsac_Create(...)
 *
 * This function creates an ISAC instance, which will contain the state
 * information for one coding/decoding channel.
 *
 * Input:
 *        - ISAC_main_inst    : address of the pointer to the coder instance.
 *
 * Return value               : 0 - Ok
 *                             -1 - Error
 */
WebRtc_Word16 WebRtcIsac_Create(
			       ISACStruct** ISAC_main_inst)
{
  ISACMainStruct* instISAC;

  instISAC = (ISACMainStruct*)WEBRTC_SPL_VNEW(ISACMainStruct, 1);
  *ISAC_main_inst = (ISACStruct*)instISAC;
  if(*ISAC_main_inst != NULL)
    {
      instISAC->errorCode = 0;
      instISAC->initFlag = 0;
      // Default is wideband
      instISAC->bandwidthKHz           = isac8kHz;
      instISAC->encoderSamplingRateKHz = kIsacWideband;
      instISAC->decoderSamplingRateKHz = kIsacWideband;
      return 0;
    }
  else
    {
      return -1;
    }
}


/****************************************************************************
 * WebRtcIsac_Free(...)
 *
 * This function frees the ISAC instance created at the beginning.
 *
 * Input:
 *        - ISAC_main_inst    : a ISAC instance.
 *
 * Return value               : 0 - Ok
 *                             -1 - Error
 */
WebRtc_Word16 WebRtcIsac_Free(
			     ISACStruct* ISAC_main_inst)
{
  ISACMainStruct* instISAC;

  instISAC = (ISACMainStruct*)ISAC_main_inst;
  WEBRTC_SPL_FREE(instISAC);
  return 0;
}


/****************************************************************************
 * EncoderInitLb(...) - internal function for initialization of
 *                                Lower Band
 * EncoderInitUb(...) - internal function for initialization of
 *                                Upper Band
 * WebRtcIsac_EncoderInit(...) - API function
 *
 * This function initializes a ISAC instance prior to the encoder calls.
 *
 * Input:
 *        - ISAC_main_inst    : ISAC instance.
 *        - CodingMode        : 0 -> Bit rate and frame length are automatically
 *                                 adjusted to available bandwidth on
 *                                 transmission channel, applicable just to
 *                                 wideband mode.
 *                              1 -> User sets a frame length and a target bit
 *                                 rate which is taken as the maximum
 *                                 short-term average bit rate.
 *
 * Return value               :  0 - Ok
 *                              -1 - Error
 */
static WebRtc_Word16 EncoderInitLb(
				   ISACLBStruct*             instLB,
				   WebRtc_Word16               codingMode,
				   enum IsacSamplingRate sampRate)
{
  WebRtc_Word16 statusInit = 0;
  int k;

  /* Init stream vector to zero */
  for(k=0; k < STREAM_SIZE_MAX_60; k++)
    {
      instLB->ISACencLB_obj.bitstr_obj.stream[k] = 0;
    }

  if((codingMode == 1) || (sampRate == kIsacSuperWideband))
    {
      // 30 ms frame-size if either in super-wideband or
      // instanteneous mode (I-mode)
      instLB->ISACencLB_obj.new_framelength = 480;
    }
  else
    {
      instLB->ISACencLB_obj.new_framelength = INITIAL_FRAMESAMPLES;
    }

  WebRtcIsac_InitMasking(&instLB->ISACencLB_obj.maskfiltstr_obj);
  WebRtcIsac_InitPreFilterbank(&instLB->ISACencLB_obj.prefiltbankstr_obj);
  WebRtcIsac_InitPitchFilter(&instLB->ISACencLB_obj.pitchfiltstr_obj);
  WebRtcIsac_InitPitchAnalysis(
			       &instLB->ISACencLB_obj.pitchanalysisstr_obj);


  instLB->ISACencLB_obj.buffer_index         = 0;
  instLB->ISACencLB_obj.frame_nb             = 0;
  /* default for I-mode */
  instLB->ISACencLB_obj.bottleneck           = 32000;
  instLB->ISACencLB_obj.current_framesamples = 0;
  instLB->ISACencLB_obj.s2nr                 = 0;
  instLB->ISACencLB_obj.payloadLimitBytes30  = STREAM_SIZE_MAX_30;
  instLB->ISACencLB_obj.payloadLimitBytes60  = STREAM_SIZE_MAX_60;
  instLB->ISACencLB_obj.maxPayloadBytes      = STREAM_SIZE_MAX_60;
  instLB->ISACencLB_obj.maxRateInBytes       = STREAM_SIZE_MAX_30;
  instLB->ISACencLB_obj.enforceFrameSize     = 0;
  /* invalid value prevents getRedPayload to
     run before encoder is called */
  instLB->ISACencLB_obj.lastBWIdx            = -1;
  return statusInit;
}

static WebRtc_Word16 EncoderInitUb(
				   ISACUBStruct* instUB,
				   WebRtc_Word16   bandwidth)
{
  WebRtc_Word16 statusInit = 0;
  int k;

  /* Init stream vector to zero */
  for(k = 0; k < STREAM_SIZE_MAX_60; k++)
    {
      instUB->ISACencUB_obj.bitstr_obj.stream[k] = 0;
    }

  WebRtcIsac_InitMasking(&instUB->ISACencUB_obj.maskfiltstr_obj);
  WebRtcIsac_InitPreFilterbank(&instUB->ISACencUB_obj.prefiltbankstr_obj);

  if(bandwidth == isac16kHz)
    {
      instUB->ISACencUB_obj.buffer_index = LB_TOTAL_DELAY_SAMPLES;
    }
  else
    {
      instUB->ISACencUB_obj.buffer_index        = 0;
    }
  /* default for I-mode */
  instUB->ISACencUB_obj.bottleneck            = 32000;
  // These store the limits for the wideband + super-wideband bit-stream.
  instUB->ISACencUB_obj.maxPayloadSizeBytes    = STREAM_SIZE_MAX_30 << 1;
  // This has to be updated after each lower-band encoding to guarantee
  // a correct payload-limitation.
  instUB->ISACencUB_obj.numBytesUsed         = 0;
  memset(instUB->ISACencUB_obj.data_buffer_float, 0,
         (MAX_FRAMESAMPLES + LB_TOTAL_DELAY_SAMPLES) * sizeof(float));

  memcpy(&(instUB->ISACencUB_obj.lastLPCVec),
         WebRtcIsac_kMeanLarUb16, sizeof(double) * UB_LPC_ORDER);

  return statusInit;
}


WebRtc_Word16 WebRtcIsac_EncoderInit(
				    ISACStruct* ISAC_main_inst,
				    WebRtc_Word16 codingMode)
{
  ISACMainStruct *instISAC;
  WebRtc_Word16 status;

  instISAC = (ISACMainStruct*)ISAC_main_inst;

  if((codingMode != 0) && (codingMode != 1))
    {
      instISAC->errorCode = ISAC_DISALLOWED_CODING_MODE;
      return -1;
    }
  // default bottleneck
  instISAC->bottleneck = MAX_ISAC_BW;

  if(instISAC->encoderSamplingRateKHz == kIsacWideband)
    {
      instISAC->bandwidthKHz = isac8kHz;
      instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX_60;
      instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX_30;
    }
  else
    {
      instISAC->bandwidthKHz = isac16kHz;
      instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX;
      instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX;
    }

  // Channel-adaptive = 0; Instantaneous (Channel-independent) = 1;
  instISAC->codingMode = codingMode;

  WebRtcIsac_InitBandwidthEstimator(&instISAC->bwestimator_obj,
                                    instISAC->encoderSamplingRateKHz,
                                    instISAC->decoderSamplingRateKHz);

  WebRtcIsac_InitRateModel(&instISAC->rate_data_obj);
  /* default for I-mode */
  instISAC->MaxDelay = 10.0;

  status = EncoderInitLb(&instISAC->instLB, codingMode,
			 instISAC->encoderSamplingRateKHz);
  if(status < 0)
    {
      instISAC->errorCode = -status;
      return -1;
    }

  if(instISAC->encoderSamplingRateKHz == kIsacSuperWideband)
    {
      // Initialize encoder filter-bank.
      memset(instISAC->analysisFBState1, 0,
	     FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32));
      memset(instISAC->analysisFBState2, 0,
	     FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32));

      status = EncoderInitUb(&(instISAC->instUB),
			     instISAC->bandwidthKHz);
      if(status < 0)
	{
	  instISAC->errorCode = -status;
	  return -1;
	}
    }
  // Initializtion is successful, set the flag
  instISAC->initFlag |= BIT_MASK_ENC_INIT;
  return 0;
}


/****************************************************************************
 * WebRtcIsac_Encode(...)
 *
 * This function encodes 10ms frame(s) and inserts it into a package.
 * Input speech length has to be 160 samples (10ms). The encoder buffers those
 * 10ms frames until it reaches the chosen Framesize (480 or 960 samples
 * corresponding to 30 or 60 ms frames), and then proceeds to the encoding.
 *
 * Input:
 *        - ISAC_main_inst    : ISAC instance.
 *        - speechIn          : input speech vector.
 *
 * Output:
 *        - encoded           : the encoded data vector
 *
 * Return value:
 *                            : >0 - Length (in bytes) of coded data
 *                            :  0 - The buffer didn't reach the chosen
 *                                  frameSize so it keeps buffering speech
 *                                 samples.
 *                            : -1 - Error
 */
WebRtc_Word16 WebRtcIsac_Encode(
			       ISACStruct*        ISAC_main_inst,
			       const WebRtc_Word16* speechIn,
			       WebRtc_Word16*       encoded)
{
  ISACMainStruct* instISAC;
  ISACLBStruct*   instLB;
  ISACUBStruct*   instUB;

  float        inFrame[FRAMESAMPLES_10ms];
  WebRtc_Word16  speechInLB[FRAMESAMPLES_10ms];
  WebRtc_Word16  speechInUB[FRAMESAMPLES_10ms];
  WebRtc_Word16  streamLenLB;
  WebRtc_Word16  streamLenUB;
  WebRtc_Word16  streamLen;
  WebRtc_Word16  k;
  WebRtc_UWord8* ptrEncodedUW8 = (WebRtc_UWord8*)encoded;
  int          garbageLen;
  WebRtc_Word32  bottleneck;
  WebRtc_Word16  bottleneckIdx = 0;
  WebRtc_Word16  jitterInfo = 0;

  instISAC = (ISACMainStruct*)ISAC_main_inst;
  instLB = &(instISAC->instLB);
  instUB = &(instISAC->instUB);

  /* check if encoder initiated */
  if((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
     BIT_MASK_ENC_INIT)
    {
      instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED;
      return -1;
    }

  if(instISAC->encoderSamplingRateKHz == kIsacSuperWideband)
    {
      WebRtcSpl_AnalysisQMF(speechIn, speechInLB, speechInUB,
			     instISAC->analysisFBState1, instISAC->analysisFBState2);

      /* convert from fixed to floating point */
      for(k = 0; k < FRAMESAMPLES_10ms; k++)
	{
	  inFrame[k] = (float)speechInLB[k];
	}
    }
  else
    {
      for(k = 0; k < FRAMESAMPLES_10ms; k++)
	{
	  inFrame[k] = (float) speechIn[k];
	}
    }

  /* add some noise to avoid denormal numbers */
  inFrame[0] += (float)1.23455334e-3;
  inFrame[1] -= (float)2.04324239e-3;
  inFrame[2] += (float)1.90854954e-3;
  inFrame[9] += (float)1.84854878e-3;


  // This function will update the bottleneck if required
  UpdateBottleneck(instISAC);

  // Get the bandwith information which has to be sent to the other side
  GetSendBandwidthInfo(instISAC, &bottleneckIdx, &jitterInfo);

  //
  // ENCODE LOWER-BAND
  //
  streamLenLB = WebRtcIsac_EncodeLb(inFrame, &instLB->ISACencLB_obj,
                                    instISAC->codingMode, bottleneckIdx);

  if(streamLenLB < 0)
    {
      return -1;
    }

  if(instISAC->encoderSamplingRateKHz == kIsacSuperWideband)
    {
      instUB = &(instISAC->instUB);

      // convert to float
      for(k = 0; k < FRAMESAMPLES_10ms; k++)
	{
	  inFrame[k] = (float) speechInUB[k];
	}

      /* add some noise to avoid denormal numbers */
      inFrame[0] += (float)1.23455334e-3;
      inFrame[1] -= (float)2.04324239e-3;
      inFrame[2] += (float)1.90854954e-3;
      inFrame[9] += (float)1.84854878e-3;

      // Tell to upper-band the number of bytes used so far.
      // This is for payload limitation.
      instUB->ISACencUB_obj.numBytesUsed = streamLenLB + 1 +
        LEN_CHECK_SUM_WORD8;

      //
      // ENCODE UPPER-BAND
      //
      switch(instISAC->bandwidthKHz)
	{
	case isac12kHz:
	  {
	    streamLenUB = WebRtcIsac_EncodeUb12(inFrame,
						&instUB->ISACencUB_obj,
						jitterInfo);
	    break;
	  }
	case isac16kHz:
	  {
	    streamLenUB = WebRtcIsac_EncodeUb16(inFrame,
						&instUB->ISACencUB_obj,
						jitterInfo);
	    break;
	  }
	case isac8kHz:
	  {
	    streamLenUB = 0;
	    break;
	  }
	default:
	  return -1;
	}

      if((streamLenUB < 0) &&
	 (streamLenUB != -ISAC_PAYLOAD_LARGER_THAN_LIMIT))
	{
	  // an error has happened but this is not the error due to a
	  // bit-stream larger than the limit
	  return -1;
	}

      if(streamLenLB == 0)
	{
	  return 0;
	}

      // One bite is allocated for the length. According to older decoders
      // so the length bit-stream plus one byte for size and
      // LEN_CHECK_SUM_WORD8 for the checksum should be less than or equal
      // to 255.
      if((streamLenUB > (255 - (LEN_CHECK_SUM_WORD8 + 1))) ||
	 (streamLenUB == -ISAC_PAYLOAD_LARGER_THAN_LIMIT))
	{
	  // we have got a too long bit-stream we skip the upper-band
	  // bit-stream for this frame.
	  streamLenUB = 0;
	}

      memcpy(ptrEncodedUW8, instLB->ISACencLB_obj.bitstr_obj.stream,
	     streamLenLB);
      streamLen = streamLenLB;
      if(streamLenUB > 0)
	{
	  ptrEncodedUW8[streamLenLB] = (WebRtc_UWord8)(streamLenUB + 1 +
						       LEN_CHECK_SUM_WORD8);
	  memcpy(&ptrEncodedUW8[streamLenLB + 1],
		 instUB->ISACencUB_obj.bitstr_obj.stream, streamLenUB);
	  streamLen += ptrEncodedUW8[streamLenLB];
	}
      else
	{
	  ptrEncodedUW8[streamLenLB] = 0;
	}
    }
  else
    {
      if(streamLenLB == 0)
	{
	  return 0;
	}
      memcpy(ptrEncodedUW8, instLB->ISACencLB_obj.bitstr_obj.stream,
	     streamLenLB);
      streamLenUB = 0;
      streamLen = streamLenLB;
    }

  // Add Garbage if required.
  WebRtcIsac_GetUplinkBandwidth(&instISAC->bwestimator_obj, &bottleneck);
  if(instISAC->codingMode == 0)
    {
      int          minBytes;
      int          limit;
      WebRtc_UWord8* ptrGarbage;

      instISAC->MaxDelay = (double)WebRtcIsac_GetUplinkMaxDelay(
								&instISAC->bwestimator_obj);

      /* update rate model and get minimum number of bytes in this packet */
      minBytes = WebRtcIsac_GetMinBytes(&(instISAC->rate_data_obj),
					streamLen, instISAC->instLB.ISACencLB_obj.current_framesamples,
					bottleneck, instISAC->MaxDelay, instISAC->bandwidthKHz);

      /* Make sure MinBytes does not exceed packet size limit */
      if(instISAC->bandwidthKHz == isac8kHz)
	{
	  if(instLB->ISACencLB_obj.current_framesamples == FRAMESAMPLES)
	    {
	      limit = instLB->ISACencLB_obj.payloadLimitBytes30;
	    }
	  else
	    {
	      limit = instLB->ISACencLB_obj.payloadLimitBytes60;
	    }
	}
      else
	{
	  limit = instUB->ISACencUB_obj.maxPayloadSizeBytes;
	}
      minBytes = (minBytes > limit)? limit:minBytes;

      /* Make sure we don't allow more than 255 bytes of garbage data.
	 We store the length of the garbage data in 8 bits in the bitstream,
	 255 is the max garbage length we can signal using 8 bits. */
      if((instISAC->bandwidthKHz == isac8kHz) ||
	 (streamLenUB == 0))
	{
	  ptrGarbage = &ptrEncodedUW8[streamLenLB];
	  limit = streamLen + 255;
	}
      else
	{
	  ptrGarbage = &ptrEncodedUW8[streamLenLB + 1 + streamLenUB];
	  limit = streamLen + (255 - ptrEncodedUW8[streamLenLB]);
	}
      minBytes = (minBytes > limit)? limit:minBytes;

      garbageLen = (minBytes > streamLen)? (minBytes - streamLen):0;

      /* Save data for creation of multiple bitstreams */
      //ISACencLB_obj->SaveEnc_obj.minBytes = MinBytes;

      /* if bitstream is too short, add garbage at the end */
      if(garbageLen > 0)
	{
	  for(k = 0; k < garbageLen; k++)
	    {
	      ptrGarbage[k] = (WebRtc_UWord8)(rand() & 0xFF);
	    }

	  // for a correct length of the upper-band bit-stream together
	  // with the garbage. Garbage is embeded in upper-band bit-stream.
	  //    That is the only way to preserve backward compatibility.
	  if((instISAC->bandwidthKHz == isac8kHz) ||
	     (streamLenUB == 0))
	    {
	      ptrEncodedUW8[streamLenLB] = (WebRtc_UWord8)garbageLen;
	    }
	  else
	    {
	      ptrEncodedUW8[streamLenLB] += (WebRtc_UWord8)garbageLen;
	      // write the length of the garbage at the end of the upper-band
	      // bit-stream, if exists. This helps for sanity check.
	      ptrEncodedUW8[streamLenLB + 1 + streamLenUB] = (WebRtc_UWord8)garbageLen;

	    }

	  streamLen += garbageLen;
	}
    }
  else
    {
      /* update rate model */
      WebRtcIsac_UpdateRateModel(&instISAC->rate_data_obj, streamLen,
				 instISAC->instLB.ISACencLB_obj.current_framesamples, bottleneck);
      garbageLen = 0;
    }

  // Generate CRC if required.
  if((instISAC->bandwidthKHz != isac8kHz) &&
     (streamLenUB > 0))
    {
      WebRtc_UWord32 crc;

      WebRtcIsac_GetCrc((WebRtc_Word16*)(&(ptrEncodedUW8[streamLenLB + 1])),
			streamLenUB + garbageLen, &crc);
#ifndef WEBRTC_BIG_ENDIAN
      for(k = 0; k < LEN_CHECK_SUM_WORD8; k++)
	{
	  ptrEncodedUW8[streamLen - LEN_CHECK_SUM_WORD8 + k] =
	    (WebRtc_UWord8)((crc >> (24 - k * 8)) & 0xFF);
	}
#else
      memcpy(&ptrEncodedUW8[streamLenLB + streamLenUB + 1], &crc,
	     LEN_CHECK_SUM_WORD8);
#endif
    }

  return streamLen;
}


/******************************************************************************
 * WebRtcIsac_GetNewBitStream(...)
 *
 * This function returns encoded data, with the recieved bwe-index in the
 * stream. If the rate is set to a value less than bottleneck of codec
 * the new bistream will be re-encoded with the given target rate.
 * It should always return a complete packet, i.e. only called once
 * even for 60 msec frames.
 *
 * NOTE 1! This function does not write in the ISACStruct, it is not allowed.
 * NOTE 3! Rates larger than the bottleneck of the codec will be limited
 *         to the current bottleneck.
 *
 * Input:
 *        - ISAC_main_inst    : ISAC instance.
 *        - bweIndex          : Index of bandwidth estimate to put in new
 *                              bitstream
 *        - rate              : target rate of the transcoder is bits/sec.
 *                              Valid values are the accepted rate in iSAC,
 *                              i.e. 10000 to 56000.
 *
 * Output:
 *        - encoded           : The encoded data vector
 *
 * Return value               : >0 - Length (in bytes) of coded data
 *                              -1 - Error  or called in SWB mode
 *                                 NOTE! No error code is written to
 *                                 the struct since it is only allowed to read
 *                                 the struct.
 */
WebRtc_Word16 WebRtcIsac_GetNewBitStream(
					ISACStruct*  ISAC_main_inst,
					WebRtc_Word16  bweIndex,
					WebRtc_Word16  jitterInfo,
					WebRtc_Word32  rate,
					WebRtc_Word16* encoded,
					WebRtc_Word16  isRCU)
{
  Bitstr iSACBitStreamInst;   /* Local struct for bitstream handling */
  WebRtc_Word16 streamLenLB;
  WebRtc_Word16 streamLenUB;
  WebRtc_Word16 totalStreamLen;
  double gain2;
  double gain1;
  float scale;
  enum ISACBandwidth bandwidthKHz;
  double rateLB;
  double rateUB;
  WebRtc_Word32 currentBN;
  ISACMainStruct* instISAC;
  WebRtc_UWord8* encodedPtrUW8 = (WebRtc_UWord8*)encoded;
  WebRtc_UWord32 crc;
#ifndef WEBRTC_BIG_ENDIAN
  WebRtc_Word16  k;
#endif

  instISAC = (ISACMainStruct*)ISAC_main_inst;

  if((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
     BIT_MASK_ENC_INIT)
    {
      return -1;
    }

  // Get the bottleneck of this iSAC and limit the
  // given rate to the current bottleneck.
  WebRtcIsac_GetUplinkBw(ISAC_main_inst, &currentBN);
  if(rate > currentBN)
    {
      rate = currentBN;
    }

  if(WebRtcIsac_RateAllocation(rate, &rateLB, &rateUB, &bandwidthKHz) < 0)
    {
      return -1;
    }

  // Cannot transcode from 16 kHz to 12 kHz
  if((bandwidthKHz == isac12kHz) &&
     (instISAC->bandwidthKHz == isac16kHz))
    {
      return -1;
    }

  // These gains are in dB
  // gain for the given rate.
  gain1 = WebRtcIsac_GetSnr(rateLB,
			    instISAC->instLB.ISACencLB_obj.current_framesamples);
  // gain of this iSAC
  gain2 = WebRtcIsac_GetSnr(
			    instISAC->instLB.ISACencLB_obj.bottleneck,
			    instISAC->instLB.ISACencLB_obj.current_framesamples);

  // scale is the ratio of two gains in normal domain.
  scale = (float)pow(10, (gain1 - gain2) / 20.0);
  // change the scale if this is a RCU bit-stream.
  scale = (isRCU)? (scale * RCU_TRANSCODING_SCALE):scale;

  streamLenLB = WebRtcIsac_EncodeStoredDataLb(
					      &instISAC->instLB.ISACencLB_obj.SaveEnc_obj, &iSACBitStreamInst,
					      bweIndex, scale);

  if(streamLenLB < 0)
    {
      return -1;
    }

  /* convert from bytes to WebRtc_Word16 */
  memcpy(encoded, iSACBitStreamInst.stream, streamLenLB);

  if(bandwidthKHz == isac8kHz)
    {
      return streamLenLB;
    }

  totalStreamLen = streamLenLB;
  // super-wideband is always at 30ms.
  // These gains are in dB
  // gain for the given rate.
  gain1 = WebRtcIsac_GetSnr(rateUB, FRAMESAMPLES);
  // gain of this iSAC
  gain2 = WebRtcIsac_GetSnr(
			    instISAC->instUB.ISACencUB_obj.bottleneck, FRAMESAMPLES);

  // scale is the ratio of two gains in normal domain.
  scale = (float)pow(10, (gain1 - gain2) / 20.0);

  // change the scale if this is a RCU bit-stream.
  scale = (isRCU)? (scale * RCU_TRANSCODING_SCALE_UB):scale;

  switch(instISAC->bandwidthKHz)
    {
    case isac12kHz:
      {
        streamLenUB = WebRtcIsac_EncodeStoredDataUb12(
						      &(instISAC->instUB.ISACencUB_obj.SaveEnc_obj),
						      &iSACBitStreamInst, jitterInfo, scale);
        break;
      }
    case isac16kHz:
      {
        streamLenUB = WebRtcIsac_EncodeStoredDataUb16(
						      &(instISAC->instUB.ISACencUB_obj.SaveEnc_obj),
						      &iSACBitStreamInst, jitterInfo, scale);
        break;
      }
    default:
      return -1;
    }

  if(streamLenUB < 0)
    {
      return -1;
    }

  if(streamLenUB + 1 + LEN_CHECK_SUM_WORD8 > 255)
    {
      return streamLenLB;
    }

  totalStreamLen = streamLenLB + streamLenUB + 1 + LEN_CHECK_SUM_WORD8;
  encodedPtrUW8[streamLenLB] = streamLenUB + 1 + LEN_CHECK_SUM_WORD8;

  memcpy(&encodedPtrUW8[streamLenLB+1], iSACBitStreamInst.stream,
         streamLenUB);

  WebRtcIsac_GetCrc((WebRtc_Word16*)(&(encodedPtrUW8[streamLenLB + 1])),
                    streamLenUB, &crc);
#ifndef WEBRTC_BIG_ENDIAN
  for(k = 0; k < LEN_CHECK_SUM_WORD8; k++)
    {
      encodedPtrUW8[totalStreamLen - LEN_CHECK_SUM_WORD8 + k] =
        (WebRtc_UWord8)((crc >> (24 - k * 8)) & 0xFF);
    }
#else
  memcpy(&encodedPtrUW8[streamLenLB + streamLenUB + 1], &crc,
         LEN_CHECK_SUM_WORD8);
#endif


  return totalStreamLen;
}


/****************************************************************************
 * DecoderInitLb(...) - internal function for initialization of
 *                                Lower Band
 * DecoderInitUb(...) - internal function for initialization of
 *                                Upper Band
 * WebRtcIsac_DecoderInit(...) - API function
 *
 * This function initializes a ISAC instance prior to the decoder calls.
 *
 * Input:
 *        - ISAC_main_inst    : ISAC instance.
 *
 * Return value
 *                            :  0 - Ok
 *                              -1 - Error
 */
static WebRtc_Word16 DecoderInitLb(
				   ISACLBStruct* instISAC)
{
  int i;
  /* Init stream vector to zero */
  for (i=0; i<STREAM_SIZE_MAX_60; i++)
    {
      instISAC->ISACdecLB_obj.bitstr_obj.stream[i] = 0;
    }

  WebRtcIsac_InitMasking(&instISAC->ISACdecLB_obj.maskfiltstr_obj);
  WebRtcIsac_InitPostFilterbank(
				&instISAC->ISACdecLB_obj.postfiltbankstr_obj);
  WebRtcIsac_InitPitchFilter(&instISAC->ISACdecLB_obj.pitchfiltstr_obj);

  return (0);
}

static WebRtc_Word16 DecoderInitUb(
				   ISACUBStruct* instISAC)
{
  int i;
  /* Init stream vector to zero */
  for (i = 0; i < STREAM_SIZE_MAX_60; i++)
    {
      instISAC->ISACdecUB_obj.bitstr_obj.stream[i] = 0;
    }

  WebRtcIsac_InitMasking(&instISAC->ISACdecUB_obj.maskfiltstr_obj);
  WebRtcIsac_InitPostFilterbank(
				&instISAC->ISACdecUB_obj.postfiltbankstr_obj);
  return (0);
}

WebRtc_Word16 WebRtcIsac_DecoderInit(
				    ISACStruct *ISAC_main_inst)
{
  ISACMainStruct* instISAC;

  instISAC = (ISACMainStruct*)ISAC_main_inst;

  if(DecoderInitLb(&instISAC->instLB) < 0)
    {
      return -1;
    }

  if(instISAC->decoderSamplingRateKHz == kIsacSuperWideband)
    {
      memset(instISAC->synthesisFBState1, 0,
	     FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32));
      memset(instISAC->synthesisFBState2, 0,
	     FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32));

      if(DecoderInitUb(&(instISAC->instUB)) < 0)
	{
	  return -1;
	}
    }

  if((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
     BIT_MASK_ENC_INIT)
    {
      WebRtcIsac_InitBandwidthEstimator(&instISAC->bwestimator_obj,
					instISAC->encoderSamplingRateKHz,
					instISAC->decoderSamplingRateKHz);
    }

  instISAC->initFlag |= BIT_MASK_DEC_INIT;

  instISAC->resetFlag_8kHz = 0;

  return 0;
}


/****************************************************************************
 * WebRtcIsac_UpdateBwEstimate(...)
 *
 * This function updates the estimate of the bandwidth.
 *
 * Input:
 *        - ISAC_main_inst    : ISAC instance.
 *        - encoded           : encoded ISAC frame(s).
 *        - packet_size       : size of the packet.
 *        - rtp_seq_number    : the RTP number of the packet.
 *        - arr_ts            : the arrival time of the packet (from NetEq)
 *                              in samples.
 *
 * Return value               :  0 - Ok
 *                              -1 - Error
 */
WebRtc_Word16 WebRtcIsac_UpdateBwEstimate(
				  ISACStruct*         ISAC_main_inst,
				  const WebRtc_UWord16* encoded,
				  WebRtc_Word32         packet_size,
				  WebRtc_UWord16        rtp_seq_number,
				  WebRtc_UWord32        send_ts,
				  WebRtc_UWord32        arr_ts)
{
  ISACMainStruct *instISAC;
  Bitstr streamdata;
#ifndef WEBRTC_BIG_ENDIAN
  int k;
#endif
  WebRtc_Word16 err;

  /* typecast pointer to real structure */
  instISAC = (ISACMainStruct *)ISAC_main_inst;

  /* check if decoder initiated */
  if((instISAC->initFlag & BIT_MASK_DEC_INIT) !=
     BIT_MASK_DEC_INIT)
    {
      instISAC->errorCode = ISAC_DECODER_NOT_INITIATED;
      return -1;
    }

  if(packet_size <= 0)
    {
      /* return error code if the packet length is null */
      instISAC->errorCode = ISAC_EMPTY_PACKET;
      return -1;
    }

  streamdata.W_upper = 0xFFFFFFFF;
  streamdata.streamval = 0;
  streamdata.stream_index = 0;

#ifndef WEBRTC_BIG_ENDIAN
  for(k = 0; k < 10; k++)
    {
      streamdata.stream[k] = (WebRtc_UWord8) ((encoded[k>>1] >>
					       ((k&1) << 3)) & 0xFF);
    }
#else
  memcpy(streamdata.stream, encoded, 10);
#endif

  err = WebRtcIsac_EstimateBandwidth(&instISAC->bwestimator_obj, &streamdata,
                                     packet_size, rtp_seq_number, send_ts, arr_ts,
                                     instISAC->encoderSamplingRateKHz,
                                     instISAC->decoderSamplingRateKHz);

  if(err < 0)
    {
      /* return error code if something went wrong */
      instISAC->errorCode = -err;
      return -1;
    }

  return 0;
}

static WebRtc_Word16 Decode(
			    ISACStruct*         ISAC_main_inst,
			    const WebRtc_UWord16* encoded,
			    WebRtc_Word16         lenEncodedBytes,
			    WebRtc_Word16*        decoded,
			    WebRtc_Word16*        speechType,
			    WebRtc_Word16         isRCUPayload)
{
  /* number of samples (480 or 960), output from decoder
     that were actually used in the encoder/decoder
     (determined on the fly) */
  ISACMainStruct* instISAC;
  ISACUBDecStruct* decInstUB;
  ISACLBDecStruct*    decInstLB;

  WebRtc_Word16  numSamplesLB;
  WebRtc_Word16  numSamplesUB;
  WebRtc_Word16  speechIdx;
  float        outFrame[MAX_FRAMESAMPLES];
  WebRtc_Word16  outFrameLB[MAX_FRAMESAMPLES];
  WebRtc_Word16  outFrameUB[MAX_FRAMESAMPLES];
  WebRtc_Word16  numDecodedBytesLB;
  WebRtc_Word16  numDecodedBytesUB;
  WebRtc_Word16  lenEncodedLBBytes;
  WebRtc_Word16  validChecksum = 1;
  WebRtc_Word16  k;
  WebRtc_UWord8* ptrEncodedUW8 = (WebRtc_UWord8*)encoded;
  WebRtc_UWord16 numLayer;
  WebRtc_Word16  totSizeBytes;
  WebRtc_Word16  err;

  instISAC = (ISACMainStruct*)ISAC_main_inst;
  decInstUB = &(instISAC->instUB.ISACdecUB_obj);
  decInstLB = &(instISAC->instLB.ISACdecLB_obj);

  /* check if decoder initiated */
  if((instISAC->initFlag & BIT_MASK_DEC_INIT) !=
     BIT_MASK_DEC_INIT)
    {
      instISAC->errorCode = ISAC_DECODER_NOT_INITIATED;
      return -1;
    }

  if(lenEncodedBytes <= 0)
    {
      /* return error code if the packet length is null */
      instISAC->errorCode = ISAC_EMPTY_PACKET;
      return -1;
    }

  // the size of the rncoded lower-band is bounded by
  // STREAM_SIZE_MAX,
  // If a payload with the size larger than STREAM_SIZE_MAX
  // is received, it is not considered erroneous.
  lenEncodedLBBytes = (lenEncodedBytes > STREAM_SIZE_MAX)
    ?  STREAM_SIZE_MAX:lenEncodedBytes;

  // Copy to lower-band bit-stream structure
  memcpy(instISAC->instLB.ISACdecLB_obj.bitstr_obj.stream, ptrEncodedUW8,
         lenEncodedLBBytes);

  // Regardless of that the current codec is setup to work in
  // wideband or super-wideband, the decoding of the lower-band
  // has to be performed.
  numDecodedBytesLB = WebRtcIsac_DecodeLb(outFrame, decInstLB,
                                          &numSamplesLB, isRCUPayload);

  // Check for error
  if((numDecodedBytesLB < 0) ||
     (numDecodedBytesLB > lenEncodedLBBytes) ||
     (numSamplesLB > MAX_FRAMESAMPLES))
    {
      instISAC->errorCode = ISAC_LENGTH_MISMATCH;
      return -1;
    }

  // Error Check, we accept multi-layer bit-stream
  // This will limit number of iterations of the
  // while loop. Even withouut this the number of iterations
  // is limited.
  numLayer = 1;
  totSizeBytes = numDecodedBytesLB;
  while(totSizeBytes != lenEncodedBytes)
    {
      if((totSizeBytes > lenEncodedBytes) ||
	 (ptrEncodedUW8[totSizeBytes] == 0) ||
	 (numLayer > MAX_NUM_LAYERS))
	{
	  instISAC->errorCode = ISAC_LENGTH_MISMATCH;
	  return -1;
	}
      totSizeBytes += ptrEncodedUW8[totSizeBytes];
      numLayer++;
    }

  if(instISAC->decoderSamplingRateKHz == kIsacWideband)
    {
      for(k = 0; k < numSamplesLB; k++)
	{
	  if(outFrame[k] > 32767)
	    {
	      decoded[k] = 32767;
	    }
	  else if(outFrame[k] < -32768)
	    {
	      decoded[k] = -32768;
	    }
	  else
	    {
              decoded[k] = (WebRtc_Word16)WebRtcIsac_lrint(outFrame[k]);
	    }
	}
      numSamplesUB = 0;
    }
  else
    {
      WebRtc_UWord32 crc;
      // We don't accept larger than 30ms (480 samples at lower-band)
      // frame-size.
      for(k = 0; k < numSamplesLB; k++)
	{
	  if(outFrame[k] > 32767)
	    {
	      outFrameLB[k] = 32767;
	    }
	  else if(outFrame[k] < -32768)
	    {
	      outFrameLB[k] = -32768;
	    }
	  else
	    {
              outFrameLB[k] = (WebRtc_Word16)WebRtcIsac_lrint(outFrame[k]);
	    }
	}

      //numSamplesUB = numSamplesLB;

      // Check for possible error, and if upper-band stream exist.
      if(numDecodedBytesLB == lenEncodedBytes)
	{
	  // Decoding was successful. No super-wideband bitstream
	  // exists.
	  numSamplesUB = numSamplesLB;
	  memset(outFrameUB, 0, sizeof(WebRtc_Word16) *  numSamplesUB);

	  // Prepare for the potential increase of signal bandwidth
	  instISAC->resetFlag_8kHz = 2;
	}
      else
	{
	  // this includes the check sum and the bytes that stores the
	  // length
	  WebRtc_Word16 lenNextStream = ptrEncodedUW8[numDecodedBytesLB];

	  // Is this garbage or valid super-wideband bit-stream?
	  // Check if checksum is valid
	  if(lenNextStream <= (LEN_CHECK_SUM_WORD8 + 1))
	    {
	      // such a small second layer cannot be super-wideband layer.
	      // It must be a short garbage.
	      validChecksum = 0;
	    }
	  else
	    {
	      // Run CRC to see if the checksum match.
	      WebRtcIsac_GetCrc((WebRtc_Word16*)(
						 &ptrEncodedUW8[numDecodedBytesLB + 1]),
				lenNextStream - LEN_CHECK_SUM_WORD8 - 1, &crc);

	      validChecksum = 1;
	      for(k = 0; k < LEN_CHECK_SUM_WORD8; k++)
		{
		  validChecksum &= (((crc >> (24 - k * 8)) & 0xFF) ==
				    ptrEncodedUW8[numDecodedBytesLB + lenNextStream -
						  LEN_CHECK_SUM_WORD8 + k]);
		}
	    }

	  if(!validChecksum)
	    {
	      // this is a garbage, we have received a wideband
	      // bit-stream with garbage
	      numSamplesUB = numSamplesLB;
	      memset(outFrameUB, 0, sizeof(WebRtc_Word16) * numSamplesUB);
	    }
	  else
	    {
	      // A valid super-wideband biststream exists.
	      enum ISACBandwidth bandwidthKHz;
	      WebRtc_Word32 maxDelayBit;

	      //instISAC->bwestimator_obj.incomingStreamSampFreq =
	      //    kIsacSuperWideband;
	      // If we have super-wideband bit-stream, we cannot
	      // have 60 ms frame-size.
	      if(numSamplesLB > FRAMESAMPLES)
		{
		  instISAC->errorCode = ISAC_LENGTH_MISMATCH;
		  return -1;
		}

	      // the rest of the bit-stream contains the upper-band
	      // bit-stream curently this is the only thing there,
	      // however, we might add more layers.

	      // Have to exclude one byte where the length is stored
	      // and last 'LEN_CHECK_SUM_WORD8' bytes where the
	      // checksum is stored.
	      lenNextStream -= (LEN_CHECK_SUM_WORD8 + 1);

	      memcpy(decInstUB->bitstr_obj.stream,
		     &ptrEncodedUW8[numDecodedBytesLB + 1], lenNextStream);

	      // THIS IS THE FIRST DECODING
	      decInstUB->bitstr_obj.W_upper      = 0xFFFFFFFF;
	      decInstUB->bitstr_obj.streamval    = 0;
	      decInstUB->bitstr_obj.stream_index = 0;

	      // Decode jitter infotmation
	      err = WebRtcIsac_DecodeJitterInfo(&decInstUB->bitstr_obj,
						&maxDelayBit);
	      // error check
	      if(err < 0)
		{
		  instISAC->errorCode = -err;
		  return -1;
		}

	      // Update jitter info which is in the upper-band bit-stream
	      // only if the encoder is in super-wideband. Otherwise,
	      // the jitter info is already embeded in bandwidth index
	      // and has been updated.
	      if(instISAC->encoderSamplingRateKHz == kIsacSuperWideband)
		{
		  err = WebRtcIsac_UpdateUplinkJitter(
						      &(instISAC->bwestimator_obj), maxDelayBit);
		  if(err < 0)
		    {
		      instISAC->errorCode = -err;
		      return -1;
		    }
		}

	      // decode bandwidth information
	      err = WebRtcIsac_DecodeBandwidth(&decInstUB->bitstr_obj,
					       &bandwidthKHz);
	      if(err < 0)
		{
		  instISAC->errorCode = -err;
		  return -1;
		}

	      switch(bandwidthKHz)
		{
		case isac12kHz:
		  {
		    numDecodedBytesUB = WebRtcIsac_DecodeUb12(outFrame,
							      decInstUB, isRCUPayload);

		    // Hang-over for transient alleviation -
		    // wait two frames to add the upper band going up from 8 kHz
		    if (instISAC->resetFlag_8kHz > 0)
		      {
			if (instISAC->resetFlag_8kHz == 2)
			  {
			    // Silence first and a half frame
			    memset(outFrame, 0, MAX_FRAMESAMPLES *
				   sizeof(float));
			  }
			else
			  {
			    const float rampStep = 2.0f / MAX_FRAMESAMPLES;
			    float rampVal = 0;
			    memset(outFrame, 0, (MAX_FRAMESAMPLES>>1) *
				   sizeof(float));

			    // Ramp up second half of second frame
			    for(k = MAX_FRAMESAMPLES/2; k < MAX_FRAMESAMPLES; k++)
			      {
				outFrame[k] *= rampVal;
				rampVal += rampStep;
			      }
			  }
			instISAC->resetFlag_8kHz -= 1;
		      }

		    break;
		  }
		case isac16kHz:
		  {
		    numDecodedBytesUB = WebRtcIsac_DecodeUb16(outFrame,
							      decInstUB, isRCUPayload);
		    break;
		  }
		default:
		  return -1;
		}

	      // it might be less due to garbage.
	      if((numDecodedBytesUB != lenNextStream) &&
		 (numDecodedBytesUB != (lenNextStream - ptrEncodedUW8[
								      numDecodedBytesLB + 1 + numDecodedBytesUB])))
		{
		  instISAC->errorCode = ISAC_LENGTH_MISMATCH;
		  return -1;
		}

	      // If there is no error Upper-band always decodes
	      // 30 ms (480 samples)
	      numSamplesUB = FRAMESAMPLES;

	      // Convert to W16
	      for(k = 0; k < numSamplesUB; k++)
		{
		  if(outFrame[k] > 32767)
		    {
		      outFrameUB[k] = 32767;
		    }
		  else if(outFrame[k] < -32768)
		    {
		      outFrameUB[k] = -32768;
		    }
		  else
		    {
                      outFrameUB[k] = (WebRtc_Word16)WebRtcIsac_lrint(
                          outFrame[k]);
		    }
		}
	    }
	}

      speechIdx = 0;
      while(speechIdx < numSamplesLB)
	{
	  WebRtcSpl_SynthesisQMF(&outFrameLB[speechIdx],
				  &outFrameUB[speechIdx], &decoded[(speechIdx<<1)],
				  instISAC->synthesisFBState1, instISAC->synthesisFBState2);

	  speechIdx += FRAMESAMPLES_10ms;
	}
    }
  *speechType = 0;
  return (numSamplesLB + numSamplesUB);
}







/****************************************************************************
 * WebRtcIsac_Decode(...)
 *
 * This function decodes a ISAC frame. Output speech length
 * will be a multiple of 480 samples: 480 or 960 samples,
 * depending on the  frameSize (30 or 60 ms).
 *
 * Input:
 *        - ISAC_main_inst    : ISAC instance.
 *        - encoded           : encoded ISAC frame(s)
 *        - len               : bytes in encoded vector
 *
 * Output:
 *        - decoded           : The decoded vector
 *
 * Return value               : >0 - number of samples in decoded vector
 *                              -1 - Error
 */

WebRtc_Word16 WebRtcIsac_Decode(
			       ISACStruct*         ISAC_main_inst,
			       const WebRtc_UWord16* encoded,
			       WebRtc_Word16         lenEncodedBytes,
			       WebRtc_Word16*        decoded,
			       WebRtc_Word16*        speechType)
{
  WebRtc_Word16 isRCUPayload = 0;
  return Decode(ISAC_main_inst, encoded, lenEncodedBytes, decoded,
		speechType, isRCUPayload);
}

/****************************************************************************
 * WebRtcIsac_DecodeRcu(...)
 *
 * This function decodes a redundant (RCU) iSAC frame. Function is called in
 * NetEq with a stored RCU payload i case of packet loss. Output speech length
 * will be a multiple of 480 samples: 480 or 960 samples,
 * depending on the framesize (30 or 60 ms).
 *
 * Input:
 *      - ISAC_main_inst     : ISAC instance.
 *      - encoded            : encoded ISAC RCU frame(s)
 *      - len                : bytes in encoded vector
 *
 * Output:
 *      - decoded            : The decoded vector
 *
 * Return value              : >0 - number of samples in decoded vector
 *                             -1 - Error
 */



WebRtc_Word16 WebRtcIsac_DecodeRcu(
				  ISACStruct*         ISAC_main_inst,
				  const WebRtc_UWord16* encoded,
				  WebRtc_Word16         lenEncodedBytes,
				  WebRtc_Word16*        decoded,
				  WebRtc_Word16*        speechType)
{
  WebRtc_Word16 isRCUPayload = 1;
  return Decode(ISAC_main_inst, encoded, lenEncodedBytes, decoded,
		speechType, isRCUPayload);
}


/****************************************************************************
 * WebRtcIsac_DecodePlc(...)
 *
 * This function conducts PLC for ISAC frame(s). Output speech length
 * will be a multiple of 480 samples: 480 or 960 samples,
 * depending on the  frameSize (30 or 60 ms).
 *
 * Input:
 *        - ISAC_main_inst    : ISAC instance.
 *        - noOfLostFrames    : Number of PLC frames to produce
 *
 * Output:
 *        - decoded           : The decoded vector
 *
 * Return value               : >0 - number of samples in decoded PLC vector
 *                              -1 - Error
 */
WebRtc_Word16 WebRtcIsac_DecodePlc(
				  ISACStruct*         ISAC_main_inst,
				  WebRtc_Word16*        decoded,
				  WebRtc_Word16         noOfLostFrames)
{
  WebRtc_Word16 numSamples;
  ISACMainStruct* instISAC;


  /* typecast pointer to real structure */
  instISAC = (ISACMainStruct*)ISAC_main_inst;

  /* Limit number of frames to two = 60 msec. Otherwise we exceed data vectors */
  if(noOfLostFrames > 2)
    {
      noOfLostFrames = 2;
    }

  /* Get the number of samples per frame */
  switch(instISAC->decoderSamplingRateKHz)
    {
    case kIsacWideband:
      {
        numSamples = 480 * noOfLostFrames;
        break;
      }
    case kIsacSuperWideband:
      {
        numSamples = 960 * noOfLostFrames;
        break;
      }
    default:
      return -1;
    }

  /* Set output samples to zero */
  memset(decoded, 0, numSamples * sizeof(WebRtc_Word16));
  return numSamples;
}


/****************************************************************************
 * ControlLb(...) - Internal function for controling Lower Band
 * ControlUb(...) - Internal function for controling Upper Band
 * WebRtcIsac_Control(...) - API function
 *
 * This function sets the limit on the short-term average bit rate and the
 * frame length. Should be used only in Instantaneous mode.
 *
 * Input:
 *        - ISAC_main_inst    : ISAC instance.
 *        - rate              : limit on the short-term average bit rate,
 *                              in bits/second (between 10000 and 32000)
 *        -  frameSize         : number of milliseconds per frame (30 or 60)
 *
 * Return value               : 0  - ok
 *                             -1 - Error
 */
static WebRtc_Word16 ControlLb(
					  ISACLBStruct* instISAC,
					  double        rate,
					  WebRtc_Word16   frameSize)
{
  if((rate >= 10000) && (rate <= 32000))
    {
      instISAC->ISACencLB_obj.bottleneck = rate;
    }
  else
    {
      return -ISAC_DISALLOWED_BOTTLENECK;
    }

  if((frameSize == 30) ||  (frameSize == 60))
    {
      instISAC->ISACencLB_obj.new_framelength = (FS/1000) *  frameSize;
    }
  else
    {
      return -ISAC_DISALLOWED_FRAME_LENGTH;
    }

  return 0;
}

static WebRtc_Word16 ControlUb(
					  ISACUBStruct* instISAC,
					  double        rate)
{
  if((rate >= 10000) && (rate <= 32000))
    {
      instISAC->ISACencUB_obj.bottleneck = rate;
    }
  else
    {
      return -ISAC_DISALLOWED_BOTTLENECK;
    }
  return 0;
}

WebRtc_Word16 WebRtcIsac_Control(
				ISACStruct* ISAC_main_inst,
				WebRtc_Word32 bottleneckBPS,
				WebRtc_Word16 frameSize)
{
  ISACMainStruct *instISAC;
  WebRtc_Word16 status;
  double rateLB;
  double rateUB;
  enum ISACBandwidth bandwidthKHz;


  /* Typecast pointer to real structure */
  instISAC = (ISACMainStruct*)ISAC_main_inst;

  if(instISAC->codingMode == 0)
    {
      /* in adaptive mode */
      instISAC->errorCode = ISAC_MODE_MISMATCH;
      return -1;
    }

  /* check if encoder initiated */
  if((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
     BIT_MASK_ENC_INIT)
    {
      instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED;
      return -1;
    }

  if(instISAC->encoderSamplingRateKHz == kIsacWideband)
    {
      // if the sampling rate is 16kHz then bandwith should be 8kHz,
      // regardless of bottleneck.
      bandwidthKHz = isac8kHz;
      rateLB = (bottleneckBPS > 32000)? 32000:bottleneckBPS;
      rateUB = 0;
    }
  else
    {
      if(WebRtcIsac_RateAllocation(bottleneckBPS, &rateLB, &rateUB,
				   &bandwidthKHz) < 0)
	{
	  return -1;
	}
    }

  if((instISAC->encoderSamplingRateKHz == kIsacSuperWideband) &&
     (frameSize != 30)                                      &&
     (bandwidthKHz != isac8kHz))
    {
      // Cannot have 60 ms in super-wideband
      instISAC->errorCode = ISAC_DISALLOWED_FRAME_LENGTH;
      return -1;
    }

  status = ControlLb(&instISAC->instLB, rateLB, frameSize);
  if(status < 0)
    {
      instISAC->errorCode = -status;
      return -1;
    }
  if(bandwidthKHz != isac8kHz)
    {
      status = ControlUb(&(instISAC->instUB), rateUB);
      if(status < 0)
	{
	  instISAC->errorCode = -status;
	  return -1;
	}
    }

  //
  // Check if bandwidth is changing from wideband to super-wideband
  // then we have to synch data buffer of lower & upper-band. also
  // clean up the upper-band data buffer.
  //
  if((instISAC->bandwidthKHz == isac8kHz) &&
     (bandwidthKHz != isac8kHz))
    {
      memset(instISAC->instUB.ISACencUB_obj.data_buffer_float, 0,
	     sizeof(float) * (MAX_FRAMESAMPLES + LB_TOTAL_DELAY_SAMPLES));

      if(bandwidthKHz == isac12kHz)
	{
	  instISAC->instUB.ISACencUB_obj.buffer_index =
	    instISAC->instLB.ISACencLB_obj.buffer_index;
	}
      else
	{
	  instISAC->instUB.ISACencUB_obj.buffer_index = LB_TOTAL_DELAY_SAMPLES +
	    instISAC->instLB.ISACencLB_obj.buffer_index;

	  memcpy(&(instISAC->instUB.ISACencUB_obj.lastLPCVec),
            WebRtcIsac_kMeanLarUb16, sizeof(double) * UB_LPC_ORDER);
	}
    }

  // update the payload limit it the bandwidth is changing.
  if(instISAC->bandwidthKHz != bandwidthKHz)
    {
      instISAC->bandwidthKHz = bandwidthKHz;
      UpdatePayloadSizeLimit(instISAC);
    }
  instISAC->bottleneck = bottleneckBPS;
  return 0;
}


/****************************************************************************
 * WebRtcIsac_ControlBwe(...)
 *
 * This function sets the initial values of bottleneck and frame-size if
 * iSAC is used in channel-adaptive mode. Through this API, users can
 * enforce a frame-size for all values of bottleneck. Then iSAC will not
 * automatically change the frame-size.
 *
 *
 * Input:
 *        - ISAC_main_inst    : ISAC instance.
 *        - rateBPS           : initial value of bottleneck in bits/second
 *                              10000 <= rateBPS <= 32000 is accepted
 *                              For default bottleneck set rateBPS = 0
 *        - frameSizeMs       : number of milliseconds per frame (30 or 60)
 *        - enforceFrameSize  : 1 to enforce the given frame-size through out
 *                              the adaptation process, 0 to let iSAC change
 *                              the frame-size if required.
 *
 * Return value               : 0  - ok
 *                             -1 - Error
 */
WebRtc_Word16 WebRtcIsac_ControlBwe(
				   ISACStruct* ISAC_main_inst,
				   WebRtc_Word32 bottleneckBPS,
				   WebRtc_Word16 frameSizeMs,
				   WebRtc_Word16 enforceFrameSize)
{
  ISACMainStruct *instISAC;
  enum ISACBandwidth bandwidth;

  /* Typecast pointer to real structure */
  instISAC = (ISACMainStruct *)ISAC_main_inst;

  /* check if encoder initiated */
  if((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
     BIT_MASK_ENC_INIT)
    {
      instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED;
      return -1;
    }

  /* Check that we are in channel-adaptive mode, otherwise, return (-1) */
  if(instISAC->codingMode != 0)
    {
      instISAC->errorCode = ISAC_MODE_MISMATCH;
      return -1;
    }
  if((frameSizeMs != 30) &&
     (instISAC->encoderSamplingRateKHz == kIsacSuperWideband))
    {
      return -1;
    }

  /* Set struct variable if enforceFrameSize is set. ISAC will then */
  /* keep the chosen frame size. */
  if((enforceFrameSize != 0) /*||
                               (instISAC->samplingRateKHz == kIsacSuperWideband)*/)
    {
      instISAC->instLB.ISACencLB_obj.enforceFrameSize = 1;
    }
  else
    {
      instISAC->instLB.ISACencLB_obj.enforceFrameSize = 0;
    }

  /* Set initial rate, if value between 10000 and 32000,                */
  /* if rateBPS is 0, keep the default initial bottleneck value (15000) */
  if(bottleneckBPS != 0)
    {
      double rateLB;
      double rateUB;
      if(WebRtcIsac_RateAllocation(bottleneckBPS, &rateLB, &rateUB, &bandwidth) < 0)
	{
	  return -1;
	}
      instISAC->bwestimator_obj.send_bw_avg = (float)bottleneckBPS;
      instISAC->bandwidthKHz = bandwidth;
    }

  /* Set initial  frameSize. If enforceFrameSize is set the frame size will
     not change */
  if(frameSizeMs != 0)
    {
      if((frameSizeMs  == 30) || (frameSizeMs == 60))
	{
	  instISAC->instLB.ISACencLB_obj.new_framelength = (FS/1000) *
	    frameSizeMs;
	  //instISAC->bwestimator_obj.rec_header_rate = ((float)HEADER_SIZE *
	  //    8.0f * 1000.0f / (float)frameSizeMs);
	}
      else
	{
	  instISAC->errorCode = ISAC_DISALLOWED_FRAME_LENGTH;
	  return -1;
	}
    }
  return 0;
}


/****************************************************************************
 * WebRtcIsac_GetDownLinkBwIndex(...)
 *
 * This function returns index representing the Bandwidth estimate from
 * other side to this side.
 *
 * Input:
 *        - ISAC_main_inst    : iSAC struct
 *
 * Output:
 *        - bweIndex         : Bandwidth estimate to transmit to other side.
 *
 */
WebRtc_Word16 WebRtcIsac_GetDownLinkBwIndex(
				   ISACStruct*  ISAC_main_inst,
				   WebRtc_Word16* bweIndex,
				   WebRtc_Word16* jitterInfo)
{
  ISACMainStruct *instISAC;

  /* typecast pointer to real structure */
  instISAC = (ISACMainStruct*)ISAC_main_inst;

  /* check if encoder initiated */
  if((instISAC->initFlag & BIT_MASK_DEC_INIT) !=
     BIT_MASK_DEC_INIT)
    {
      instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED;
      return -1;
    }

  /* Call function to get Bandwidth Estimate */
  WebRtcIsac_GetDownlinkBwJitIndexImpl(&(instISAC->bwestimator_obj),
                                   bweIndex, jitterInfo, instISAC->decoderSamplingRateKHz);
  return 0;
}


/****************************************************************************
 * WebRtcIsac_UpdateUplinkBw(...)
 *
 * This function takes an index representing the Bandwidth estimate from
 * this side to other side and updates BWE.
 *
 * Input:
 *        - ISAC_main_inst    : iSAC struct
 *        - rateIndex         : Bandwidth estimate from other side.
 *
 * Return value               : 0 - ok
 *                             -1 - index out of range
 */
WebRtc_Word16 WebRtcIsac_UpdateUplinkBw(
			       ISACStruct*   ISAC_main_inst,
			       WebRtc_Word16   bweIndex)
{
  ISACMainStruct *instISAC;
  WebRtc_Word16 returnVal;

  /* typecast pointer to real structure */
  instISAC = (ISACMainStruct *)ISAC_main_inst;

  /* check if encoder initiated */
  if((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
     BIT_MASK_ENC_INIT)
    {
      instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED;
      return -1;
    }

  /* Call function to get Bandwidth Estimate */
  returnVal = WebRtcIsac_UpdateUplinkBwImpl(
					&(instISAC->bwestimator_obj), bweIndex,
					instISAC->encoderSamplingRateKHz);

  if(returnVal < 0)
    {
      instISAC->errorCode = -returnVal;
      return -1;
    }
  else
    {
      return 0;
    }
}


/****************************************************************************
 * WebRtcIsac_ReadBwIndex(...)
 *
 * This function returns the index of the Bandwidth estimate from the
 * bitstream.
 *
 * Input:
 *        - encoded           : Encoded bitstream
 *
 * Output:
 *        - frameLength       : Length of frame in packet (in samples)
 *        - bweIndex         : Bandwidth estimate in bitstream
 *
 */
WebRtc_Word16 WebRtcIsac_ReadBwIndex(
			       const WebRtc_Word16* encoded,
			       WebRtc_Word16*       bweIndex)
{
  Bitstr streamdata;
#ifndef WEBRTC_BIG_ENDIAN
  int k;
#endif
  WebRtc_Word16 err;

  streamdata.W_upper = 0xFFFFFFFF;
  streamdata.streamval = 0;
  streamdata.stream_index = 0;

#ifndef WEBRTC_BIG_ENDIAN
  for(k = 0; k < 10; k++)
    {
      streamdata.stream[k] = (WebRtc_UWord8) ((encoded[k>>1] >>
					       ((k&1) << 3)) & 0xFF);
    }
#else
  memcpy(streamdata.stream, encoded, 10);
#endif

  /* decode frame length */
  err = WebRtcIsac_DecodeFrameLen(&streamdata, bweIndex);
  if(err < 0)
    {
      return err;
    }

  /* decode BW estimation */
  err = WebRtcIsac_DecodeSendBW(&streamdata, bweIndex);
  if(err < 0)
    {
      return err;
    }

  return 0;
}


/****************************************************************************
 * WebRtcIsac_ReadFrameLen(...)
 *
 * This function returns the length of the frame represented in the packet.
 *
 * Input:
 *        - encoded           : Encoded bitstream
 *
 * Output:
 *        - frameLength       : Length of frame in packet (in samples)
 *
 */
WebRtc_Word16 WebRtcIsac_ReadFrameLen(
				    ISACStruct*        ISAC_main_inst,
				    const WebRtc_Word16* encoded,
				    WebRtc_Word16*       frameLength)
{
  Bitstr streamdata;
#ifndef WEBRTC_BIG_ENDIAN
  int k;
#endif
  WebRtc_Word16 err;
  ISACMainStruct* instISAC;

  streamdata.W_upper = 0xFFFFFFFF;
  streamdata.streamval = 0;
  streamdata.stream_index = 0;

#ifndef WEBRTC_BIG_ENDIAN
  for (k=0; k<10; k++) {
    streamdata.stream[k] = (WebRtc_UWord8) ((encoded[k>>1] >>
                                             ((k&1) << 3)) & 0xFF);
  }
#else
  memcpy(streamdata.stream, encoded, 10);
#endif

  /* decode frame length */
  err = WebRtcIsac_DecodeFrameLen(&streamdata, frameLength);
  if(err < 0) {
    return -1;
  }
  instISAC = (ISACMainStruct*)ISAC_main_inst;

  if(instISAC->decoderSamplingRateKHz == kIsacSuperWideband)
    {
      // the decoded frame length indicates the number of samples in
      // lower-band in this case, multiply by 2 to get the total number
      // of samples.
      *frameLength <<= 1;
    }

  return 0;
}


/*******************************************************************************
 * WebRtcIsac_GetNewFrameLen(...)
 *
 * returns the frame lenght (in samples) of the next packet. In the case of
 * channel-adaptive mode, iSAC decides on its frame lenght based on the
 * estimated bottleneck this allows a user to prepare for the next packet
 * (at the encoder).
 *
 * The primary usage is in CE to make the iSAC works in channel-adaptive mode
 *
 * Input:
 *        - ISAC_main_inst     : iSAC struct
 *
 * Return Value                : frame lenght in samples
 *
 */
WebRtc_Word16 WebRtcIsac_GetNewFrameLen(
				       ISACStruct *ISAC_main_inst)
{
  ISACMainStruct *instISAC;

  /* typecast pointer to real structure */
  instISAC = (ISACMainStruct *)ISAC_main_inst;

  /* Return new frame length */
  if(instISAC->encoderSamplingRateKHz == kIsacWideband)
    {
      return (instISAC->instLB.ISACencLB_obj.new_framelength);
    }
  else
    {
      return ((instISAC->instLB.ISACencLB_obj.new_framelength) << 1);
    }
}


/****************************************************************************
 * WebRtcIsac_GetErrorCode(...)
 *
 * This function can be used to check the error code of an iSAC instance.
 * When a function returns -1 a error code will be set for that instance.
 * The function below extract the code of the last error that occured in
 * the specified instance.
 *
 * Input:
 *        - ISAC_main_inst    : ISAC instance
 *
 * Return value               : Error code
 */
WebRtc_Word16 WebRtcIsac_GetErrorCode(
				     ISACStruct *ISAC_main_inst)
{
  ISACMainStruct *instISAC;
  /* typecast pointer to real structure */
  instISAC = (ISACMainStruct *)ISAC_main_inst;

  return (instISAC->errorCode);
}


/****************************************************************************
 * WebRtcIsac_GetUplinkBw(...)
 *
 * This function outputs the target bottleneck of the codec. In
 * channel-adaptive mode, the target bottleneck is specified through in-band
 * signalling retreived by bandwidth estimator.
 * In channel-independent, also called instantaneous mode, the target
 * bottleneck is provided to the encoder by calling xxx_control(...) (if
 * xxx_control is never called the default values is).
 * Note that the output is the iSAC internal operating bottleneck whch might
 * differ slightly from the one provided through xxx_control().
 *
 * Input:
 *        - ISAC_main_inst    : iSAC instance
 *
 * Output:
 *        - *bottleneck       : bottleneck in bits/sec
 *
 * Return value               : -1 if error happens
 *                               0 bit-rates computed correctly.
 */
WebRtc_Word16 WebRtcIsac_GetUplinkBw(
				       ISACStruct*  ISAC_main_inst,
				       WebRtc_Word32* bottleneck)
{
  ISACMainStruct* instISAC = (ISACMainStruct *)ISAC_main_inst;

  if(instISAC->codingMode == 0)
    {
      // we are in adaptive mode then get the bottleneck from BWE
      *bottleneck = (WebRtc_Word32)instISAC->bwestimator_obj.send_bw_avg;
    }
  else
    {
      *bottleneck = instISAC->bottleneck;
    }

  if((*bottleneck > 32000) && (*bottleneck < 38000))
    {
      *bottleneck = 32000;
    }
  else if((*bottleneck > 45000) && (*bottleneck < 50000))
    {
      *bottleneck = 45000;
    }
  else if(*bottleneck > 56000)
    {
      *bottleneck = 56000;
    }

  return 0;
}


/******************************************************************************
 * WebRtcIsac_SetMaxPayloadSize(...)
 *
 * This function sets a limit for the maximum payload size of iSAC. The same
 * value is used both for 30 and 60 ms packets. If the encoder sampling rate
 * is 16 kHz the maximum payload size is between 120 and 400 bytes. If the
 * encoder sampling rate is 32 kHz the maximum payload size is between 120
 * and 600 bytes.
 *
 * ---------------
 * IMPORTANT NOTES
 * ---------------
 * The size of a packet is limited to the minimum of 'max-payload-size' and
 * 'max-rate.' For instance, let's assume the max-payload-size is set to
 * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps
 * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms
 * frame-size. Then a packet with a frame-size of 30 ms is limited to 150,
 * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to
 * 170 bytes, i.e. min(170, 300).
 *
 * Input:
 *        - ISAC_main_inst    : iSAC instance
 *        - maxPayloadBytes   : maximum size of the payload in bytes
 *                              valid values are between 100 and 400 bytes
 *                              if encoder sampling rate is 16 kHz. For
 *                              32 kHz encoder sampling rate valid values
 *                              are between 100 and 600 bytes.
 *
 * Return value               : 0 if successful
 *                             -1 if error happens
 */
WebRtc_Word16 WebRtcIsac_SetMaxPayloadSize(
					  ISACStruct* ISAC_main_inst,
					  WebRtc_Word16 maxPayloadBytes)
{
  ISACMainStruct *instISAC;
  WebRtc_Word16 status = 0;

  /* typecast pointer to real structure  */
  instISAC = (ISACMainStruct *)ISAC_main_inst;

  /* check if encoder initiated */
  if((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
     BIT_MASK_ENC_INIT)
    {
      instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED;
      return -1;
    }

  if(instISAC->encoderSamplingRateKHz == kIsacSuperWideband)
    {
      // sanity check
      if(maxPayloadBytes < 120)
	{
	  // maxRate is out of valid range
	  // set to the acceptable value and return -1.
	  maxPayloadBytes = 120;
	  status = -1;
	}

      /* sanity check */
      if(maxPayloadBytes > STREAM_SIZE_MAX)
	{
	  // maxRate is out of valid range
	  // set to the acceptable value and return -1.
	  maxPayloadBytes = STREAM_SIZE_MAX;
	  status = -1;
	}
    }
  else
    {
      if(maxPayloadBytes < 120)
	{
	  // max payload-size is out of valid range
	  // set to the acceptable value and return -1.
	  maxPayloadBytes = 120;
	  status = -1;
	}
      if(maxPayloadBytes > STREAM_SIZE_MAX_60)
	{
	  // max payload-size is out of valid range
	  // set to the acceptable value and return -1.
	  maxPayloadBytes = STREAM_SIZE_MAX_60;
	  status = -1;
	}
    }
  instISAC->maxPayloadSizeBytes = maxPayloadBytes;
  UpdatePayloadSizeLimit(instISAC);
  return status;
}


/******************************************************************************
 * WebRtcIsac_SetMaxRate(...)
 *
 * This function sets the maximum rate which the codec may not exceed for
 * any signal packet. The maximum rate is defined and payload-size per
 * frame-size in bits per second.
 *
 * The codec has a maximum rate of 53400 bits per second (200 bytes per 30
 * ms) if the encoder sampling rate is 16kHz, and 160 kbps (600 bytes/30 ms)
 * if the encoder sampling rate is 32 kHz.
 *
 * It is possible to set a maximum rate between 32000 and 53400 bits/sec
 * in wideband mode, and 32000 to 160000 bits/sec in super-wideband mode.
 *
 * ---------------
 * IMPORTANT NOTES
 * ---------------
 * The size of a packet is limited to the minimum of 'max-payload-size' and
 * 'max-rate.' For instance, let's assume the max-payload-size is set to
 * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps
 * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms
 * frame-size. Then a packet with a frame-size of 30 ms is limited to 150,
 * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to
 * 170 bytes, min(170, 300).
 *
 * Input:
 *        - ISAC_main_inst    : iSAC instance
 *        - maxRate           : maximum rate in bits per second,
 *                              valid values are 32000 to 53400 bits/sec in
 *                              wideband mode, and 32000 to 160000 bits/sec in
 *                              super-wideband mode.
 *
 * Return value               : 0 if successful
 *                             -1 if error happens
 */
WebRtc_Word16 WebRtcIsac_SetMaxRate(
				   ISACStruct* ISAC_main_inst,
				   WebRtc_Word32 maxRate)
{
  ISACMainStruct *instISAC;
  WebRtc_Word16 maxRateInBytesPer30Ms;
  WebRtc_Word16 status = 0;

  /* typecast pointer to real structure */
  instISAC = (ISACMainStruct *)ISAC_main_inst;

  /* check if encoder initiated */
  if((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
     BIT_MASK_ENC_INIT)
    {
      instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED;
      return -1;
    }
  /*
    Calculate maximum number of bytes per 30 msec packets for the
    given maximum rate. Multiply with 30/1000 to get number of
    bits per 30 ms, divide by 8 to get number of bytes per 30 ms:
    maxRateInBytes = floor((maxRate * 30/1000) / 8);
  */
  maxRateInBytesPer30Ms = (WebRtc_Word16)(maxRate*3/800);

  if(instISAC->encoderSamplingRateKHz == kIsacWideband)
    {
      if(maxRate < 32000)
	{
	  // max rate is out of valid range
	  // set to the acceptable value and return -1.
	  maxRateInBytesPer30Ms = 120;
	  status = -1;
	}

      if(maxRate > 53400)
	{
	  // max rate is out of valid range
	  // set to the acceptable value and return -1.
	  maxRateInBytesPer30Ms = 200;
	  status = -1;
	}
    }
  else
    {
      if(maxRateInBytesPer30Ms < 120)
	{
	  // maxRate is out of valid range
	  // set to the acceptable value and return -1.
	  maxRateInBytesPer30Ms = 120;
	  status = -1;
	}

      if(maxRateInBytesPer30Ms > STREAM_SIZE_MAX)
	{
	  // maxRate is out of valid range
	  // set to the acceptable value and return -1.
	  maxRateInBytesPer30Ms = STREAM_SIZE_MAX;
	  status = -1;
	}
    }
  instISAC->maxRateBytesPer30Ms = maxRateInBytesPer30Ms;
  UpdatePayloadSizeLimit(instISAC);
  return status;
}


/****************************************************************************
 * WebRtcIsac_GetRedPayload(...)
 *
 * Populates "encoded" with the redundant payload of the recently encoded
 * frame. This function has to be called once that WebRtcIsac_Encode(...)
 * returns a positive value. Regardless of the frame-size this function will
 * be called only once after encoding is completed. The bit-stream is
 * targeted for 16000 bit/sec.
 *
 * Input:
 *        - ISAC_main_inst    : iSAC struct
 *
 * Output:
 *        - encoded           : the encoded data vector
 *
 *
 * Return value               : >0 - Length (in bytes) of coded data
 *                            : -1 - Error
 *
 *
 */
WebRtc_Word16 WebRtcIsac_GetRedPayload(
				      ISACStruct*  ISAC_main_inst,
				      WebRtc_Word16* encoded)
{
  ISACMainStruct* instISAC;
  Bitstr          iSACBitStreamInst;
  WebRtc_Word16     streamLenLB;
  WebRtc_Word16     streamLenUB;
  WebRtc_Word16     streamLen;
  WebRtc_Word16     totalLenUB;
  WebRtc_UWord8*    ptrEncodedUW8 = (WebRtc_UWord8*)encoded;
#ifndef WEBRTC_BIG_ENDIAN
  int k;
#endif

  /* typecast pointer to real structure */
  instISAC = (ISACMainStruct*)ISAC_main_inst;


  if((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
     BIT_MASK_ENC_INIT)
    {
      instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED;
    }


  iSACBitStreamInst.W_upper = 0xFFFFFFFF;
  iSACBitStreamInst.streamval = 0;
  iSACBitStreamInst.stream_index = 0;


  streamLenLB = WebRtcIsac_EncodeStoredDataLb(
					      &instISAC->instLB.ISACencLB_obj.SaveEnc_obj,
					      &iSACBitStreamInst,
					      instISAC->instLB.ISACencLB_obj.lastBWIdx,
					      RCU_TRANSCODING_SCALE);

  if(streamLenLB < 0)
    {
      return -1;
    }

  /* convert from bytes to WebRtc_Word16 */
  memcpy(ptrEncodedUW8, iSACBitStreamInst.stream, streamLenLB);

  streamLen = streamLenLB;

  if(instISAC->bandwidthKHz == isac8kHz)
    {
      return streamLenLB;
    }

  streamLenUB = WebRtcIsac_GetRedPayloadUb(
					   &instISAC->instUB.ISACencUB_obj.SaveEnc_obj,
					   &iSACBitStreamInst, instISAC->bandwidthKHz);

  if(streamLenUB < 0)
    {
      // an error has happened but this is not the error due to a
      // bit-stream larger than the limit
      return -1;
    }

  // We have one byte to write the total length of the upper band
  // the length include the bitstream length, check-sum and the
  // single byte where the length is written to. This is according to
  // iSAC wideband and how the "garbage" is dealt.
  totalLenUB = streamLenUB + 1 + LEN_CHECK_SUM_WORD8;
  if(totalLenUB > 255)
    {
      streamLenUB = 0;
    }

  // Generate CRC if required.
  if((instISAC->bandwidthKHz != isac8kHz) &&
     (streamLenUB > 0))
    {
      WebRtc_UWord32 crc;
      streamLen += totalLenUB;
      ptrEncodedUW8[streamLenLB] = (WebRtc_UWord8)totalLenUB;
      memcpy(&ptrEncodedUW8[streamLenLB+1], iSACBitStreamInst.stream, streamLenUB);

      WebRtcIsac_GetCrc((WebRtc_Word16*)(&(ptrEncodedUW8[streamLenLB + 1])),
			streamLenUB, &crc);
#ifndef WEBRTC_BIG_ENDIAN
      for(k = 0; k < LEN_CHECK_SUM_WORD8; k++)
	{
	  ptrEncodedUW8[streamLen - LEN_CHECK_SUM_WORD8 + k] =
	    (WebRtc_UWord8)((crc >> (24 - k * 8)) & 0xFF);
	}
#else
      memcpy(&ptrEncodedUW8[streamLenLB + streamLenUB + 1], &crc,
	     LEN_CHECK_SUM_WORD8);
#endif
    }


  return streamLen;
}


/****************************************************************************
 * WebRtcIsac_version(...)
 *
 * This function returns the version number.
 *
 * Output:
 *        - version      : Pointer to character string
 *
 */
void WebRtcIsac_version(char *version)
{
  strcpy(version, "4.3.0");
}


/******************************************************************************
 * WebRtcIsac_SetEncSampRate()
 * Set the sampling rate of the encoder. Initialization of the encoder WILL
 * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz
 * which is set when the instance is created. The encoding-mode and the
 * bottleneck remain unchanged by this call, however, the maximum rate and
 * maximum payload-size will reset to their default value.
 *
 * Input:
 *        - ISAC_main_inst    : iSAC instance
 *        - sampRate          : enumerator specifying the sampling rate.
 *
 * Return value               : 0 if successful
 *                             -1 if failed.
 */
WebRtc_Word16 WebRtcIsac_SetEncSampRate(
				       ISACStruct*               ISAC_main_inst,
				       enum IsacSamplingRate sampRate)
{
  ISACMainStruct* instISAC;

  instISAC = (ISACMainStruct*)ISAC_main_inst;

  if((sampRate != kIsacWideband) &&
     (sampRate != kIsacSuperWideband))
    {
      // Sampling Frequency is not supported
      instISAC->errorCode = ISAC_UNSUPPORTED_SAMPLING_FREQUENCY;
      return -1;
    }
  else if((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
          BIT_MASK_ENC_INIT)
    {
      if(sampRate == kIsacWideband)
      {
        instISAC->bandwidthKHz = isac8kHz;
      }
      else
      {
        instISAC->bandwidthKHz = isac16kHz;
      }
      instISAC->encoderSamplingRateKHz = sampRate;
      return 0;
    }
  else
    {
      ISACUBStruct* instUB = &(instISAC->instUB);
      ISACLBStruct* instLB = &(instISAC->instLB);
      double bottleneckLB = 0;
      double bottleneckUB = 0;
      WebRtc_Word32 bottleneck = instISAC->bottleneck;
      WebRtc_Word16 codingMode = instISAC->codingMode;
      WebRtc_Word16 frameSizeMs = instLB->ISACencLB_obj.new_framelength / (FS / 1000);

      if((sampRate == kIsacWideband) &&
	 (instISAC->encoderSamplingRateKHz == kIsacSuperWideband))
	{
	  // changing from super-wideband to wideband.
	  // we don't need to re-initialize the encoder of the
	  // lower-band.
	  instISAC->bandwidthKHz = isac8kHz;
	  if(codingMode == 1)
	    {
	      ControlLb(instLB,
				   (bottleneck > 32000)? 32000:bottleneck, FRAMESIZE);
	    }
	  instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX_60;
	  instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX_30;
	}
      else if((sampRate == kIsacSuperWideband) &&
	      (instISAC->encoderSamplingRateKHz == kIsacWideband))
	{
	  if(codingMode == 1)
	    {
	      WebRtcIsac_RateAllocation(bottleneck, &bottleneckLB, &bottleneckUB,
					&(instISAC->bandwidthKHz));
	    }

          instISAC->bandwidthKHz = isac16kHz;
	  instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX;
	  instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX;

	  EncoderInitLb(instLB, codingMode, sampRate);
	  EncoderInitUb(instUB, instISAC->bandwidthKHz);

	  memset(instISAC->analysisFBState1, 0,
		 FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32));
	  memset(instISAC->analysisFBState2, 0,
		 FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32));

	  if(codingMode == 1)
	    {
	      instISAC->bottleneck = bottleneck;
	      ControlLb(instLB, bottleneckLB,
				   (instISAC->bandwidthKHz == isac8kHz)? frameSizeMs:FRAMESIZE);
	      if(instISAC->bandwidthKHz > isac8kHz)
		{
		  ControlUb(instUB, bottleneckUB);
		}
	    }
	  else
	    {
	      instLB->ISACencLB_obj.enforceFrameSize = 0;
	      instLB->ISACencLB_obj.new_framelength = FRAMESAMPLES;
	    }
	}
      instISAC->encoderSamplingRateKHz = sampRate;
      return 0;
    }
}


/******************************************************************************
 * WebRtcIsac_SetDecSampRate()
 * Set the sampling rate of the decoder.  Initialization of the decoder WILL
 * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz
 * which is set when the instance is created.
 *
 * Input:
 *        - ISAC_main_inst    : iSAC instance
 *        - sampRate          : enumerator specifying the sampling rate.
 *
 * Return value               : 0 if successful
 *                             -1 if failed.
 */
WebRtc_Word16 WebRtcIsac_SetDecSampRate(
				       ISACStruct*               ISAC_main_inst,
				       enum IsacSamplingRate sampRate)
{
  ISACMainStruct* instISAC;

  instISAC = (ISACMainStruct*)ISAC_main_inst;

  if((sampRate != kIsacWideband) &&
     (sampRate != kIsacSuperWideband))
    {
      // Sampling Frequency is not supported
      instISAC->errorCode = ISAC_UNSUPPORTED_SAMPLING_FREQUENCY;
      return -1;
    }
  else
    {
      if((instISAC->decoderSamplingRateKHz == kIsacWideband) &&
	 (sampRate == kIsacSuperWideband))
	{
	  // switching from wideband to super-wideband at the decoder
	  // we need to reset the filter-bank and initialize
	  // upper-band decoder.
	  memset(instISAC->synthesisFBState1, 0,
		 FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32));
	  memset(instISAC->synthesisFBState2, 0,
		 FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32));

	  if(DecoderInitUb(&(instISAC->instUB)) < 0)
	    {
	      return -1;
	    }
	}
      instISAC->decoderSamplingRateKHz = sampRate;
      return 0;
    }
}


/******************************************************************************
 * WebRtcIsac_EncSampRate()
 *
 * Input:
 *        - ISAC_main_inst    : iSAC instance
 *
 * Return value               : enumerator representing sampling frequency
 *                              associated with the encoder, the input audio
 *                              is expected to be sampled at this rate.
 *
 */
enum IsacSamplingRate WebRtcIsac_EncSampRate(
					       ISACStruct*                ISAC_main_inst)
{
  ISACMainStruct* instISAC;

  instISAC = (ISACMainStruct*)ISAC_main_inst;

  return instISAC->encoderSamplingRateKHz;
}


/******************************************************************************
 * WebRtcIsac_DecSampRate()
 * Return the sampling rate of the decoded audio.
 *
 * Input:
 *        - ISAC_main_inst    : iSAC instance
 *
 * Return value               : enumerator representing sampling frequency
 *                              associated with the decoder, i.e. the
 *                              sampling rate of the decoded audio.
 *
 */
enum IsacSamplingRate WebRtcIsac_DecSampRate(
					       ISACStruct*                ISAC_main_inst)
{
  ISACMainStruct* instISAC;

  instISAC = (ISACMainStruct*)ISAC_main_inst;

  return instISAC->decoderSamplingRateKHz;
}
