48 kHz extension to iSAC.

Test:
-manual test with voe_cmd_test.
-manual test with RTPEncode & NetEqRTPPlay.
-manual test with simpleKenny.
-Bit-exact test of iSAC-swb and iSAC-wb with head revision of trunk. The bit-exactness is confirmed on all files generated by running webrtc/modules/audio_coding/codecs/isac/main/test/QA/runiSACLongtest.txt
Review URL: https://webrtc-codereview.appspot.com/937025

git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@3226 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/modules/audio_coding/codecs/isac/main/interface/isac.h b/modules/audio_coding/codecs/isac/main/interface/isac.h
index 03c260b..6ae6c1a 100644
--- a/modules/audio_coding/codecs/isac/main/interface/isac.h
+++ b/modules/audio_coding/codecs/isac/main/interface/isac.h
@@ -18,9 +18,6 @@
 
 typedef struct WebRtcISACStruct    ISACStruct;
 
-enum IsacSamplingRate {kIsacWideband = 16,  kIsacSuperWideband = 32};
-
-
 #if defined(__cplusplus)
 extern "C" {
 #endif
@@ -478,14 +475,11 @@
    * 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.
+   * Return value               : sampling frequency in Hertz.
    *
    */
 
-  enum IsacSamplingRate WebRtcIsac_DecSampRate(
-      ISACStruct*                ISAC_main_inst);
+  WebRtc_UWord16 WebRtcIsac_DecSampRate(ISACStruct* ISAC_main_inst);
 
 
   /******************************************************************************
@@ -494,14 +488,11 @@
    * 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.
+   * Return value               : sampling rate in Hertz.
    *
    */
 
-  enum IsacSamplingRate WebRtcIsac_EncSampRate(
-      ISACStruct*                ISAC_main_inst);
+  WebRtc_UWord16 WebRtcIsac_EncSampRate(ISACStruct* ISAC_main_inst);
 
 
   /******************************************************************************
@@ -512,15 +503,14 @@
    *
    * Input:
    *        - ISAC_main_inst    : iSAC instance
-   *        - sampRate          : enumerator specifying the sampling rate.
+   *        - sampRate          : sampling rate in Hertz.
    *
    * Return value               : 0 if successful
    *                             -1 if failed.
    */
 
-  WebRtc_Word16 WebRtcIsac_SetDecSampRate(
-      ISACStruct*           ISAC_main_inst,
-      enum IsacSamplingRate sampRate);
+  WebRtc_Word16 WebRtcIsac_SetDecSampRate(ISACStruct* ISAC_main_inst,
+                                          WebRtc_UWord16 samp_rate_hz);
 
 
   /******************************************************************************
@@ -533,15 +523,14 @@
    *
    * Input:
    *        - ISAC_main_inst    : iSAC instance
-   *        - sampRate          : enumerator specifying the sampling rate.
+   *        - sampRate          : sampling rate in Hertz.
    *
    * Return value               : 0 if successful
    *                             -1 if failed.
    */
 
-  WebRtc_Word16 WebRtcIsac_SetEncSampRate(
-      ISACStruct*           ISAC_main_inst,
-      enum IsacSamplingRate sampRate);
+  WebRtc_Word16 WebRtcIsac_SetEncSampRate(ISACStruct* ISAC_main_inst,
+                                          WebRtc_UWord16 sample_rate_hz);
 
 
 
diff --git a/modules/audio_coding/codecs/isac/main/source/decode_bwe.c b/modules/audio_coding/codecs/isac/main/source/decode_bwe.c
index cdac7fa..a92b9b9 100644
--- a/modules/audio_coding/codecs/isac/main/source/decode_bwe.c
+++ b/modules/audio_coding/codecs/isac/main/source/decode_bwe.c
@@ -68,6 +68,7 @@
     diffArrivalTime = (WebRtc_UWord32)diffArrivalTime >> 1;
     diffSendTime = (WebRtc_UWord32)diffSendTime >> 1;
   }
+
   // arrival timestamp in 16 kHz
   arrivalTimestampIn16kHz = (WebRtc_UWord32)((WebRtc_UWord32)
                                              bwest_str->prev_rec_arr_ts + (WebRtc_UWord32)diffArrivalTime);
diff --git a/modules/audio_coding/codecs/isac/main/source/isac.c b/modules/audio_coding/codecs/isac/main/source/isac.c
index 7c90334..428fda8 100644
--- a/modules/audio_coding/codecs/isac/main/source/isac.c
+++ b/modules/audio_coding/codecs/isac/main/source/isac.c
@@ -249,6 +249,7 @@
     instISAC->encoderSamplingRateKHz = kIsacWideband;
     instISAC->decoderSamplingRateKHz = kIsacWideband;
     instISAC->bandwidthKHz           = isac8kHz;
+    instISAC->in_sample_rate_hz = 16000;
     return 0;
   } else {
     return -1;
@@ -280,6 +281,7 @@
     instISAC->bandwidthKHz = isac8kHz;
     instISAC->encoderSamplingRateKHz = kIsacWideband;
     instISAC->decoderSamplingRateKHz = kIsacWideband;
+    instISAC->in_sample_rate_hz = 16000;
     return 0;
   } else {
     return -1;
@@ -458,6 +460,7 @@
       return -1;
     }
   }
+  memset(instISAC->state_in_resampler, 0, sizeof(instISAC->state_in_resampler));
   /* Initialization is successful, set the flag. */
   instISAC->initFlag |= BIT_MASK_ENC_INIT;
   return 0;
@@ -505,6 +508,8 @@
   ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
   ISACLBStruct* instLB = &(instISAC->instLB);
   ISACUBStruct* instUB = &(instISAC->instUB);
+  const int16_t* speech_in_ptr = speechIn;
+  int16_t resampled_buff[FRAMESAMPLES_10ms * 2];
 
   /* Check if encoder initiated. */
   if ((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
@@ -513,8 +518,37 @@
     return -1;
   }
 
+  if (instISAC->in_sample_rate_hz == 48000) {
+    /* Samples in 10 ms @ 48 kHz. */
+    const int kNumInputSamples = FRAMESAMPLES_10ms * 3;
+    /* Samples 10 ms @ 32 kHz. */
+    const int kNumOutputSamples = FRAMESAMPLES_10ms * 2;
+    /* Resampler divide the input into blocks of 3 samples, i.e.
+     * kNumInputSamples / 3. */
+    const int kNumResamplerBlocks = FRAMESAMPLES_10ms;
+    int32_t buffer32[FRAMESAMPLES_10ms * 3 + SIZE_RESAMPLER_STATE];
+
+    /* Restore last samples from the past to the beginning of the buffer
+     * and store the last samples of current frame for the next resampling. */
+    for (k = 0; k < SIZE_RESAMPLER_STATE; k++) {
+      buffer32[k] = instISAC->state_in_resampler[k];
+      instISAC->state_in_resampler[k] = speechIn[kNumInputSamples -
+                                                 SIZE_RESAMPLER_STATE + k];
+    }
+    for (k = 0; k < kNumInputSamples; k++) {
+      buffer32[SIZE_RESAMPLER_STATE + k] = speechIn[k];
+    }
+    /* Resampling 3 samples to 2. Function divides the input in
+     * |kNumResamplerBlocks| number of 3-sample groups, and output is
+     * |kNumResamplerBlocks| number of 2-sample groups. */
+    WebRtcSpl_Resample48khzTo32khz(buffer32, buffer32, kNumResamplerBlocks);
+    WebRtcSpl_VectorBitShiftW32ToW16(resampled_buff, kNumOutputSamples,
+                                     buffer32, 15);
+    speech_in_ptr = resampled_buff;
+  }
+
   if (instISAC->encoderSamplingRateKHz == kIsacSuperWideband) {
-    WebRtcSpl_AnalysisQMF(speechIn, speechInLB, speechInUB,
+    WebRtcSpl_AnalysisQMF(speech_in_ptr, speechInLB, speechInUB,
                           instISAC->analysisFBState1,
                           instISAC->analysisFBState2);
 
@@ -728,7 +762,7 @@
  * 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
+ * NOTE 2! Rates larger than the bottleneck of the codec will be limited
  *         to the current bottleneck.
  *
  * Input:
@@ -946,6 +980,11 @@
  *
  * This function updates the estimate of the bandwidth.
  *
+ * NOTE:
+ * The estimates of bandwidth is not valid if the sample rate of the far-end
+ * encoder is set to 48 kHz and send timestamps are increamented according to
+ * 48 kHz sampling rate.
+ *
  * Input:
  *        - ISAC_main_inst    : ISAC instance.
  *        - encoded           : encoded ISAC frame(s).
@@ -1731,7 +1770,8 @@
 /****************************************************************************
  * WebRtcIsac_ReadFrameLen(...)
  *
- * This function returns the length of the frame represented in the packet.
+ * This function returns the number of samples the decoder will generate if
+ * the given payload is decoded.
  *
  * Input:
  *        - encoded           : Encoded bitstream
@@ -1798,11 +1838,12 @@
   ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
 
   /* Return new frame length. */
-  if (instISAC->encoderSamplingRateKHz == kIsacWideband) {
+  if (instISAC->in_sample_rate_hz == 16000)
     return (instISAC->instLB.ISACencLB_obj.new_framelength);
-  } else {
-    return ((instISAC->instLB.ISACencLB_obj.new_framelength) << 1);
-  }
+  else if (instISAC->in_sample_rate_hz == 32000)
+    return ((instISAC->instLB.ISACencLB_obj.new_framelength) * 2);
+  else
+    return ((instISAC->instLB.ISACencLB_obj.new_framelength) * 3);
 }
 
 
@@ -2015,7 +2056,7 @@
   } else {
     if (maxRateInBytesPer30Ms < 120) {
       /* 'maxRate' is out of valid range
-       * Sset to the acceptable value and return -1. */
+       * Set to the acceptable value and return -1. */
       maxRateInBytesPer30Ms = 120;
       status = -1;
     }
@@ -2153,31 +2194,45 @@
  * and the bottleneck remain unchanged by this call, however, the maximum rate
  * and maximum payload-size will be reset to their default values.
  *
+ * NOTE:
+ * The maximum internal sampling rate is 32 kHz. If the encoder sample rate is
+ * set to 48 kHz the input is expected to be at 48 kHz but will be resampled to
+ * 32 kHz before any further processing.
+ * This mode is created for compatibility with full-band codecs if iSAC is used
+ * in dual-streaming. See SetDecSampleRate() for sampling rates at the decoder.
+ *
  * Input:
  *        - ISAC_main_inst    : iSAC instance
- *        - sampRate          : enumerator specifying the sampling rate.
+ *        - sample_rate_hz    : sampling rate in Hertz, valid values are 16000,
+ *                              32000 and 48000.
  *
  * Return value               : 0 if successful
  *                             -1 if failed.
  */
 WebRtc_Word16 WebRtcIsac_SetEncSampRate(ISACStruct* ISAC_main_inst,
-                                        enum IsacSamplingRate sampRate) {
+                                        WebRtc_UWord16 sample_rate_hz) {
   ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+  enum IsacSamplingRate encoder_operational_rate;
 
-  if ((sampRate != kIsacWideband) &&
-      (sampRate != kIsacSuperWideband)) {
+  if ((sample_rate_hz != 16000) && (sample_rate_hz != 32000) &&
+      (sample_rate_hz != 48000)) {
     /* 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) {
+  }
+  if (sample_rate_hz == 16000) {
+    encoder_operational_rate = kIsacWideband;
+  } else {
+    encoder_operational_rate = kIsacSuperWideband;
+  }
+
+  if ((instISAC->initFlag & BIT_MASK_ENC_INIT) !=
+      BIT_MASK_ENC_INIT) {
+    if (encoder_operational_rate == kIsacWideband) {
       instISAC->bandwidthKHz = isac8kHz;
     } else {
       instISAC->bandwidthKHz = isac16kHz;
     }
-    instISAC->encoderSamplingRateKHz = sampRate;
-    return 0;
   } else {
     ISACUBStruct* instUB = &(instISAC->instUB);
     ISACLBStruct* instLB = &(instISAC->instLB);
@@ -2188,7 +2243,7 @@
     WebRtc_Word16 frameSizeMs = instLB->ISACencLB_obj.new_framelength /
         (FS / 1000);
 
-    if ((sampRate == kIsacWideband) &&
+    if ((encoder_operational_rate == kIsacWideband) &&
         (instISAC->encoderSamplingRateKHz == kIsacSuperWideband)) {
       /* Changing from super-wideband to wideband.
        * we don't need to re-initialize the encoder of the lower-band. */
@@ -2199,7 +2254,7 @@
       }
       instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX_60;
       instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX_30;
-    } else if ((sampRate == kIsacSuperWideband) &&
+    } else if ((encoder_operational_rate == kIsacSuperWideband) &&
                (instISAC->encoderSamplingRateKHz == kIsacWideband)) {
       if (codingMode == 1) {
         WebRtcIsac_RateAllocation(bottleneck, &bottleneckLB, &bottleneckUB,
@@ -2210,7 +2265,7 @@
       instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX;
       instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX;
 
-      EncoderInitLb(instLB, codingMode, sampRate);
+      EncoderInitLb(instLB, codingMode, encoder_operational_rate);
       EncoderInitUb(instUB, instISAC->bandwidthKHz);
 
       memset(instISAC->analysisFBState1, 0,
@@ -2230,9 +2285,10 @@
         instLB->ISACencLB_obj.new_framelength = FRAMESAMPLES;
       }
     }
-    instISAC->encoderSamplingRateKHz = sampRate;
-    return 0;
   }
+  instISAC->encoderSamplingRateKHz = encoder_operational_rate;
+  instISAC->in_sample_rate_hz = sample_rate_hz;
+  return 0;
 }
 
 
@@ -2244,23 +2300,29 @@
  *
  * Input:
  *        - ISAC_main_inst    : iSAC instance
- *        - sampRate          : enumerator specifying the sampling rate.
+ *        - sample_rate_hz    : sampling rate in Hertz, valid values are 16000
+ *                              and 32000.
  *
  * Return value               : 0 if successful
  *                             -1 if failed.
  */
 WebRtc_Word16 WebRtcIsac_SetDecSampRate(ISACStruct* ISAC_main_inst,
-                                        enum IsacSamplingRate sampRate) {
+                                        WebRtc_UWord16 sample_rate_hz) {
   ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
+  enum IsacSamplingRate decoder_operational_rate;
 
-  if ((sampRate != kIsacWideband) &&
-      (sampRate != kIsacSuperWideband)) {
+  if (sample_rate_hz == 16000) {
+    decoder_operational_rate = kIsacWideband;
+  } else if (sample_rate_hz == 32000) {
+    decoder_operational_rate = kIsacSuperWideband;
+  } else {
     /* Sampling Frequency is not supported. */
     instISAC->errorCode = ISAC_UNSUPPORTED_SAMPLING_FREQUENCY;
     return -1;
-  } else {
-    if ((instISAC->decoderSamplingRateKHz == kIsacWideband) &&
-        (sampRate == kIsacSuperWideband)) {
+  }
+
+  if ((instISAC->decoderSamplingRateKHz == kIsacWideband) &&
+        (decoder_operational_rate == 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,
@@ -2271,10 +2333,9 @@
       if (DecoderInitUb(&(instISAC->instUB)) < 0) {
         return -1;
       }
-    }
-    instISAC->decoderSamplingRateKHz = sampRate;
-    return 0;
   }
+  instISAC->decoderSamplingRateKHz = decoder_operational_rate;
+  return 0;
 }
 
 
@@ -2284,14 +2345,13 @@
  * 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.
+ * Return value               : sampling rate in Hertz. The input to encoder
+ *                              is expected to be sampled in this rate.
  *
  */
-enum IsacSamplingRate WebRtcIsac_EncSampRate(ISACStruct* ISAC_main_inst) {
+WebRtc_UWord16 WebRtcIsac_EncSampRate(ISACStruct* ISAC_main_inst) {
   ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
-  return instISAC->encoderSamplingRateKHz;
+  return instISAC->in_sample_rate_hz;
 }
 
 
@@ -2302,12 +2362,11 @@
  * 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.
+ * Return value               : sampling rate in Hertz. Decoder output is
+ *                              sampled at this rate.
  *
  */
-enum IsacSamplingRate WebRtcIsac_DecSampRate(ISACStruct* ISAC_main_inst) {
+WebRtc_UWord16 WebRtcIsac_DecSampRate(ISACStruct* ISAC_main_inst) {
   ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
-  return instISAC->decoderSamplingRateKHz;
+  return instISAC->decoderSamplingRateKHz == kIsacWideband ? 16000 : 32000;
 }
diff --git a/modules/audio_coding/codecs/isac/main/source/settings.h b/modules/audio_coding/codecs/isac/main/source/settings.h
index 9c1ec1e..5562c35 100644
--- a/modules/audio_coding/codecs/isac/main/source/settings.h
+++ b/modules/audio_coding/codecs/isac/main/source/settings.h
@@ -82,6 +82,7 @@
 #define LB_TOTAL_DELAY_SAMPLES                 48
 enum ISACBandwidth {isac8kHz = 8, isac12kHz = 12, isac16kHz = 16};
 enum ISACBand {kIsacLowerBand = 0, kIsacUpperBand12 = 1, kIsacUpperBand16 = 2};
+enum IsacSamplingRate {kIsacWideband = 16,  kIsacSuperWideband = 32};
 #define UB_LPC_GAIN_DIM                 SUBFRAMES
 #define FB_STATE_SIZE_WORD32                    6
 
@@ -167,6 +168,7 @@
 #define RCU_TRANSCODING_SCALE_UB                0.50f
 #define RCU_TRANSCODING_SCALE_UB_INVERSE        2.0f
 
+#define SIZE_RESAMPLER_STATE  6
 
 /* Define Error codes */
 /* 6000 General */
diff --git a/modules/audio_coding/codecs/isac/main/source/structs.h b/modules/audio_coding/codecs/isac/main/source/structs.h
index 96cef30..39a86d2 100644
--- a/modules/audio_coding/codecs/isac/main/source/structs.h
+++ b/modules/audio_coding/codecs/isac/main/source/structs.h
@@ -472,6 +472,12 @@
   WebRtc_Word16               maxRateBytesPer30Ms;
   // Maximum allowed payload-size, measured in Bytes.
   WebRtc_Word16               maxPayloadSizeBytes;
+  /* The expected sampling rate of the input signal. Valid values are 16000,
+   * 32000 and 48000. This is not the operation sampling rate of the codec.
+   * Input signals at 48 kHz are resampled to 32 kHz, then encoded. */
+  WebRtc_UWord16 in_sample_rate_hz;
+  /* State for the input-resampler. It is only used for 48 kHz input signals. */
+  int16_t state_in_resampler[SIZE_RESAMPLER_STATE];
 } ISACMainStruct;
 
 #endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_ */
diff --git a/modules/audio_coding/codecs/isac/main/test/ReleaseTest-API/ReleaseTest-API.cc b/modules/audio_coding/codecs/isac/main/test/ReleaseTest-API/ReleaseTest-API.cc
index 04c5367..ca05c2c 100644
--- a/modules/audio_coding/codecs/isac/main/test/ReleaseTest-API/ReleaseTest-API.cc
+++ b/modules/audio_coding/codecs/isac/main/test/ReleaseTest-API/ReleaseTest-API.cc
@@ -477,8 +477,9 @@
         if(!useAssign)
         {
             err =WebRtcIsac_Create(&ISAC_main_inst);
-            WebRtcIsac_SetEncSampRate(ISAC_main_inst, (sampFreqKHz == 16)? kIsacWideband:kIsacSuperWideband);
-            WebRtcIsac_SetDecSampRate(ISAC_main_inst, (sampFreqKHz == 16)? kIsacWideband:kIsacSuperWideband);
+            WebRtcIsac_SetEncSampRate(ISAC_main_inst, sampFreqKHz * 1000);
+            WebRtcIsac_SetDecSampRate(ISAC_main_inst, sampFreqKHz >= 32 ?
+                32000 : 16000);
         }
         else
         {
@@ -488,8 +489,9 @@
             err = WebRtcIsac_AssignSize(&sss);
             ppp = malloc(sss);
             err = WebRtcIsac_Assign(&ISAC_main_inst, ppp);
-            WebRtcIsac_SetEncSampRate(ISAC_main_inst, (sampFreqKHz == 16)? kIsacWideband:kIsacSuperWideband);
-            WebRtcIsac_SetDecSampRate(ISAC_main_inst, (sampFreqKHz == 16)? kIsacWideband:kIsacSuperWideband);
+            WebRtcIsac_SetEncSampRate(ISAC_main_inst, sampFreqKHz * 1000);
+            WebRtcIsac_SetDecSampRate(ISAC_main_inst, sampFreqKHz >= 32 ?
+                32000 : 16000);
         }
         /* Error check */
         if(err < 0)
@@ -510,8 +512,9 @@
     if(doTransCoding)
     {
         WebRtcIsac_Create(&decoderTransCoding);
-        WebRtcIsac_SetEncSampRate(decoderTransCoding, (sampFreqKHz == 16)? kIsacWideband:kIsacSuperWideband);
-        WebRtcIsac_SetDecSampRate(decoderTransCoding, (sampFreqKHz == 16)? kIsacWideband:kIsacSuperWideband);
+        WebRtcIsac_SetEncSampRate(decoderTransCoding, sampFreqKHz * 1000);
+        WebRtcIsac_SetDecSampRate(decoderTransCoding, sampFreqKHz >= 32 ?
+            32000 : 16000);
         WebRtcIsac_DecoderInit(decoderTransCoding);
         transCodingFile = fopen(transCodingFileName, "wb");
         if(transCodingFile == NULL)
diff --git a/modules/audio_coding/codecs/isac/main/test/SwitchingSampRate/SwitchingSampRate.cc b/modules/audio_coding/codecs/isac/main/test/SwitchingSampRate/SwitchingSampRate.cc
index cccae28..196eb11 100644
--- a/modules/audio_coding/codecs/isac/main/test/SwitchingSampRate/SwitchingSampRate.cc
+++ b/modules/audio_coding/codecs/isac/main/test/SwitchingSampRate/SwitchingSampRate.cc
@@ -38,7 +38,7 @@
   ISACStruct* codecInstance[MAX_NUM_CLIENTS];
   WebRtc_Word32 resamplerState[MAX_NUM_CLIENTS][8];
 
-  enum IsacSamplingRate encoderSampRate[MAX_NUM_CLIENTS];
+  int encoderSampRate[MAX_NUM_CLIENTS];
 
   int minBn = 16000;
   int maxBn = 56000;
@@ -86,11 +86,11 @@
   }
 
   // THE FIRST CLIENT STARTS IN WIDEBAND
-  encoderSampRate[0] = kIsacWideband;
+  encoderSampRate[0] = 16000;
   OPEN_FILE_RB(inFile[0], fileNameWB);
 
   // THE SECOND CLIENT STARTS IN SUPER-WIDEBAND
-  encoderSampRate[1] = kIsacSuperWideband;
+  encoderSampRate[1] = 32000;
   OPEN_FILE_RB(inFile[1], fileNameSWB);
 
   strcpy(myFlag, "-I");
@@ -104,7 +104,7 @@
     printf("Client %d\n", clientCntr + 1);
     printf("---------\n");
     printf("Starting %s",
-           (encoderSampRate[clientCntr] == kIsacWideband)
+           (encoderSampRate[clientCntr] == 16000)
            ? "wideband":"super-wideband");
 
     // Open output File Name
@@ -242,17 +242,17 @@
         printf("Changing Encoder Sampling frequency in client %d to ", senderIdx+1);
         fclose(inFile[senderIdx]);
         numSampFreqChanged++;
-        if(encoderSampRate[senderIdx] == kIsacWideband)
+        if(encoderSampRate[senderIdx] == 16000)
         {
           printf("super-wideband.\n");
           OPEN_FILE_RB(inFile[senderIdx], fileNameSWB);
-          encoderSampRate[senderIdx] = kIsacSuperWideband;
+          encoderSampRate[senderIdx] = 32000;
         }
         else
         {
           printf("wideband.\n");
           OPEN_FILE_RB(inFile[senderIdx], fileNameWB);
-          encoderSampRate[senderIdx] = kIsacWideband;
+          encoderSampRate[senderIdx] = 16000;
         }
         WebRtcIsac_SetEncSampRate(codecInstance[senderIdx], encoderSampRate[senderIdx]);
         WebRtcIsac_SetDecSampRate(codecInstance[receiverIdx], encoderSampRate[senderIdx]);
@@ -264,7 +264,7 @@
         if(numSamplesRead != samplesIn10ms[senderIdx])
         {
           printf(" File %s for client %d has not enough audio\n",
-                 (encoderSampRate[senderIdx]==kIsacWideband)? "wideband":"super-wideband",
+                 (encoderSampRate[senderIdx]==16000)? "wideband":"super-wideband",
                  senderIdx + 1);
           return -1;
         }
@@ -428,7 +428,7 @@
         }
 
 
-        if(encoderSampRate[senderIdx] == kIsacWideband)
+        if(encoderSampRate[senderIdx] == 16000)
         {
           WebRtcSpl_UpsampleBy2(audioBuff60ms, lenDecodedAudio, resampledAudio60ms,
                                 resamplerState[receiverIdx]);
diff --git a/modules/audio_coding/codecs/isac/main/test/simpleKenny.c b/modules/audio_coding/codecs/isac/main/test/simpleKenny.c
index be1588c..f1b78c2 100644
--- a/modules/audio_coding/codecs/isac/main/test/simpleKenny.c
+++ b/modules/audio_coding/codecs/isac/main/test/simpleKenny.c
@@ -254,8 +254,9 @@
     /* Initialize the ISAC and BN structs */
     err = WebRtcIsac_Create(&ISAC_main_inst);
 
-    WebRtcIsac_SetEncSampRate(ISAC_main_inst, (sampFreqKHz == 16)? kIsacWideband: kIsacSuperWideband);
-    WebRtcIsac_SetDecSampRate(ISAC_main_inst, (sampFreqKHz == 16)? kIsacWideband: kIsacSuperWideband);
+    WebRtcIsac_SetEncSampRate(ISAC_main_inst, sampFreqKHz * 1000);
+    WebRtcIsac_SetDecSampRate(ISAC_main_inst, sampFreqKHz >= 32 ? 32000 :
+        16000);
     /* Error check */
     if (err < 0) {
         fprintf(stderr,"\n\n Error in create.\n\n");
diff --git a/modules/audio_coding/main/source/acm_codec_database.cc b/modules/audio_coding/main/source/acm_codec_database.cc
index 1c9a409..b860b8a 100644
--- a/modules/audio_coding/main/source/acm_codec_database.cc
+++ b/modules/audio_coding/main/source/acm_codec_database.cc
@@ -107,10 +107,10 @@
 // codecs. Note! There are a limited number of payload types. If more codecs
 // are defined they will receive reserved fixed payload types (values 69-95).
 const int kDynamicPayloadtypes[ACMCodecDB::kMaxNumCodecs] = {
-  105, 107, 108, 109, 111, 112, 113, 114, 115, 116, 117, 92,
+  107, 108, 109, 111, 112, 113, 114, 115, 116, 117, 92,
    91,  90,  89,  88,  87,  86,  85,  84,  83,  82,  81, 80,
    79,  78,  77,  76,  75,  74,  73,  72,  71,  70,  69, 68,
-   67, 66
+   67, 66, 65
 };
 
 // Creates database with all supported codecs at compile time.
@@ -129,6 +129,7 @@
   {103, "ISAC", 16000, kIsacPacSize480, 1, kIsacWbDefaultRate},
 # if (defined(WEBRTC_CODEC_ISAC))
   {104, "ISAC", 32000, kIsacPacSize960, 1, kIsacSwbDefaultRate},
+  {105, "ISAC", 48000, kIsacPacSize1440, 1, kIsacSwbDefaultRate},
 # endif
 #endif
 #ifdef WEBRTC_CODEC_PCM16
@@ -221,6 +222,7 @@
   {2, {kIsacPacSize480, kIsacPacSize960}, 0, 1},
 # if (defined(WEBRTC_CODEC_ISAC))
   {1, {kIsacPacSize960}, 0, 1},
+  {1, {kIsacPacSize1440}, 0, 1},
 # endif
 #endif
 #ifdef WEBRTC_CODEC_PCM16
@@ -311,6 +313,7 @@
   kDecoderISAC,
 # if (defined(WEBRTC_CODEC_ISAC))
   kDecoderISACswb,
+  kDecoderISACfb,
 # endif
 #endif
 #ifdef WEBRTC_CODEC_PCM16
diff --git a/modules/audio_coding/main/source/acm_codec_database.h b/modules/audio_coding/main/source/acm_codec_database.h
index 4822153..30d0462 100644
--- a/modules/audio_coding/main/source/acm_codec_database.h
+++ b/modules/audio_coding/main/source/acm_codec_database.h
@@ -33,6 +33,7 @@
     , kISAC
 # if (defined(WEBRTC_CODEC_ISAC))
     , kISACSWB
+    , kISACFB
 # endif
 #endif
 #ifdef WEBRTC_CODEC_PCM16
@@ -115,6 +116,7 @@
   // Set unsupported codecs to -1
 #ifndef WEBRTC_CODEC_ISAC
   enum {kISACSWB = -1};
+  enum {kISACFB = -1};
 # ifndef WEBRTC_CODEC_ISACFX
   enum {kISAC = -1};
 # endif
diff --git a/modules/audio_coding/main/source/acm_common_defs.h b/modules/audio_coding/main/source/acm_common_defs.h
index cdff1c1..06d17f3 100644
--- a/modules/audio_coding/main/source/acm_common_defs.h
+++ b/modules/audio_coding/main/source/acm_common_defs.h
@@ -54,6 +54,7 @@
 const int kIsacSwbDefaultRate = 56000;
 const int kIsacPacSize480 = 480;
 const int kIsacPacSize960 = 960;
+const int kIsacPacSize1440 = 1440;
 
 // An encoded bit-stream is labeled by one of the following enumerators.
 //
diff --git a/modules/audio_coding/main/source/acm_isac.cc b/modules/audio_coding/main/source/acm_isac.cc
index 0e88bc6..5f734a0 100644
--- a/modules/audio_coding/main/source/acm_isac.cc
+++ b/modules/audio_coding/main/source/acm_isac.cc
@@ -465,7 +465,8 @@
   }
 
   // set decoder sampling frequency.
-  if (codecParams->codecInstant.plfreq == 32000) {
+  if (codecParams->codecInstant.plfreq == 32000 ||
+      codecParams->codecInstant.plfreq == 48000) {
     UpdateDecoderSampFreq(ACMCodecDB::kISACSWB);
   } else {
     UpdateDecoderSampFreq(ACMCodecDB::kISAC);
@@ -556,9 +557,17 @@
 #endif
   } else {
 #ifdef WEBRTC_CODEC_ISAC
-    SET_CODEC_PAR((codecDef), kDecoderISACswb, codecInst.pltype,
-        _codecInstPtr->inst, 32000);
-    SET_ISACSWB_FUNCTIONS((codecDef));
+    // Decoder is either @ 16 kHz or 32 kHz. Even if encoder is set @ 48 kHz
+    // decoding is @ 32 kHz.
+    if (codecInst.plfreq == 32000) {
+      SET_CODEC_PAR((codecDef), kDecoderISACswb, codecInst.pltype,
+                    _codecInstPtr->inst, 32000);
+      SET_ISACSWB_FUNCTIONS((codecDef));
+    } else {
+      SET_CODEC_PAR((codecDef), kDecoderISACfb, codecInst.pltype,
+                    _codecInstPtr->inst, 32000);
+      SET_ISACFB_FUNCTIONS((codecDef));
+    }
 #else
     return -1;
 #endif
@@ -659,7 +668,7 @@
 WebRtc_Word32 ACMISAC::GetEstimatedBandwidthSafe() {
   WebRtc_Word16 bandwidthIndex = 0;
   WebRtc_Word16 delayIndex = 0;
-  IsacSamplingRate sampRate;
+  int sampRate;
 
   // Get bandwidth information
   ACM_ISAC_GETSENDBWE(_codecInstPtr->inst, &bandwidthIndex, &delayIndex);
@@ -671,7 +680,7 @@
 
   // Check sample frequency
   sampRate = ACM_ISAC_GETDECSAMPRATE(_codecInstPtr->inst);
-  if (sampRate == kIsacWideband) {
+  if (sampRate == 16000) {
     return isacRatesWB[bandwidthIndex];
   } else {
     return isacRatesSWB[bandwidthIndex];
@@ -680,13 +689,13 @@
 
 WebRtc_Word32 ACMISAC::SetEstimatedBandwidthSafe(
     WebRtc_Word32 estimatedBandwidth) {
-  IsacSamplingRate sampRate;
+  int sampRate;
   WebRtc_Word16 bandwidthIndex;
 
   // Check sample frequency and choose appropriate table
   sampRate = ACM_ISAC_GETENCSAMPRATE(_codecInstPtr->inst);
 
-  if (sampRate == kIsacWideband) {
+  if (sampRate == 16000) {
     // Search through the WB rate table to find the index
     bandwidthIndex = NR_ISAC_BANDWIDTHS / 2 - 1;
     for (int i = 0; i < (NR_ISAC_BANDWIDTHS / 2); i++) {
@@ -738,10 +747,12 @@
 WebRtc_Word16 ACMISAC::UpdateDecoderSampFreq(
 #ifdef WEBRTC_CODEC_ISAC
     WebRtc_Word16 codecId) {
+  // The decoder supports only wideband and super-wideband.
   if (ACMCodecDB::kISAC == codecId) {
-    return WebRtcIsac_SetDecSampRate(_codecInstPtr->inst, kIsacWideband);
-  } else if (ACMCodecDB::kISACSWB == codecId) {
-    return WebRtcIsac_SetDecSampRate(_codecInstPtr->inst, kIsacSuperWideband);
+    return WebRtcIsac_SetDecSampRate(_codecInstPtr->inst, 16000);
+  } else if (ACMCodecDB::kISACSWB == codecId ||
+      ACMCodecDB::kISACFB == codecId) {
+    return WebRtcIsac_SetDecSampRate(_codecInstPtr->inst, 32000);
   } else {
     return -1;
   }
@@ -758,24 +769,18 @@
   EncoderSampFreq(currentSampRateHz);
 
   if (currentSampRateHz != encoderSampFreqHz) {
-    if ((encoderSampFreqHz != 16000) && (encoderSampFreqHz != 32000)) {
+    if ((encoderSampFreqHz != 16000) && (encoderSampFreqHz != 32000) &&
+        (encoderSampFreqHz != 48000)) {
       return -1;
     } else {
       _inAudioIxRead = 0;
       _inAudioIxWrite = 0;
       _inTimestampIxWrite = 0;
-      if (encoderSampFreqHz == 16000) {
-        if (WebRtcIsac_SetEncSampRate(_codecInstPtr->inst, kIsacWideband) < 0) {
-          return -1;
-        }
-        _samplesIn10MsAudio = 160;
-      } else {
-        if (WebRtcIsac_SetEncSampRate(_codecInstPtr->inst, kIsacSuperWideband)
-            < 0) {
-          return -1;
-        }
-        _samplesIn10MsAudio = 320;
+      if (WebRtcIsac_SetEncSampRate(_codecInstPtr->inst,
+                                    encoderSampFreqHz) < 0) {
+        return -1;
       }
+      _samplesIn10MsAudio = encoderSampFreqHz / 100;
       _frameLenSmpl = ACM_ISAC_GETNEWFRAMELEN(_codecInstPtr->inst);
       _encoderParams.codecInstant.pacsize = _frameLenSmpl;
       _encoderParams.codecInstant.plfreq = encoderSampFreqHz;
@@ -789,13 +794,7 @@
 }
 
 WebRtc_Word16 ACMISAC::EncoderSampFreq(WebRtc_UWord16& sampFreqHz) {
-  IsacSamplingRate sampRate;
-  sampRate = ACM_ISAC_GETENCSAMPRATE(_codecInstPtr->inst);
-  if (sampRate == kIsacSuperWideband) {
-    sampFreqHz = 32000;
-  } else {
-    sampFreqHz = 16000;
-  }
+  sampFreqHz = ACM_ISAC_GETENCSAMPRATE(_codecInstPtr->inst);
   return 0;
 }
 
@@ -809,7 +808,7 @@
     // TODO(turajs): at 32kHz we hardcode calling with 30ms and enforce
     // the frame-size otherwise we might get error. Revise if
     // control-bwe is changed.
-    if (sampFreqHz == 32000) {
+    if (sampFreqHz == 32000 || sampFreqHz == 48000) {
       status = ACM_ISAC_CONTROL_BWE(_codecInstPtr->inst, initRateBitPerSec, 30,
                                     1);
     } else {
diff --git a/modules/audio_coding/neteq/codec_db.c b/modules/audio_coding/neteq/codec_db.c
index 10277d5..3464ad7 100644
--- a/modules/audio_coding/neteq/codec_db.c
+++ b/modules/audio_coding/neteq/codec_db.c
@@ -115,6 +115,9 @@
 #ifdef NETEQ_ISAC_SWB_CODEC
         case kDecoderISACswb :
 #endif
+#ifdef NETEQ_ISAC_FB_CODEC
+        case kDecoderISACfb :
+#endif
 #ifdef NETEQ_OPUS_CODEC
         case kDecoderOpus :
 #endif
@@ -463,6 +466,9 @@
 #ifdef NETEQ_ISAC_SWB_CODEC
         case kDecoderISACswb:
 #endif
+#ifdef NETEQ_ISAC_FB_CODEC
+        case kDecoderISACfb:
+#endif
 #ifdef NETEQ_OPUS_CODEC
         case kDecoderOpus:
 #endif
diff --git a/modules/audio_coding/neteq/interface/webrtc_neteq.h b/modules/audio_coding/neteq/interface/webrtc_neteq.h
index 9621036..3d5181e 100644
--- a/modules/audio_coding/neteq/interface/webrtc_neteq.h
+++ b/modules/audio_coding/neteq/interface/webrtc_neteq.h
@@ -37,6 +37,7 @@
     kDecoderILBC,
     kDecoderISAC,
     kDecoderISACswb,
+    kDecoderISACfb,
     kDecoderPCM16B,
     kDecoderPCM16Bwb,
     kDecoderPCM16Bswb32kHz,
diff --git a/modules/audio_coding/neteq/interface/webrtc_neteq_help_macros.h b/modules/audio_coding/neteq/interface/webrtc_neteq_help_macros.h
index 325fcc4..58822f1 100644
--- a/modules/audio_coding/neteq/interface/webrtc_neteq_help_macros.h
+++ b/modules/audio_coding/neteq/interface/webrtc_neteq_help_macros.h
@@ -102,6 +102,18 @@
                     inst.funcDurationEst=NULL; \
                     inst.funcGetErrorCode=(WebRtcNetEQ_FuncGetErrorCode)WebRtcIsac_GetErrorCode;
 
+#define SET_ISACFB_FUNCTIONS(inst) \
+                    inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcIsac_Decode; \
+                    inst.funcDecodeRCU=(WebRtcNetEQ_FuncDecode)WebRtcIsac_DecodeRcu; \
+                    inst.funcDecodePLC=NULL; \
+                    inst.funcDecodeInit=(WebRtcNetEQ_FuncDecodeInit)WebRtcIsac_DecoderInit; \
+                    inst.funcAddLatePkt=NULL; \
+                    inst.funcGetMDinfo=NULL; \
+                    inst.funcGetPitch=NULL; \
+                    inst.funcUpdBWEst=(WebRtcNetEQ_FuncUpdBWEst)WebRtcIsac_UpdateBwEstimate; \
+                    inst.funcDurationEst=NULL; \
+                    inst.funcGetErrorCode=(WebRtcNetEQ_FuncGetErrorCode)WebRtcIsac_GetErrorCode;
+
 #define SET_G729_FUNCTIONS(inst) \
                     inst.funcDecode=(WebRtcNetEQ_FuncDecode)WebRtcG729_Decode; \
                     inst.funcDecodeRCU=NULL; \
diff --git a/modules/audio_coding/neteq/neteq.gypi b/modules/audio_coding/neteq/neteq.gypi
index 0d19c89..8bc35d0 100644
--- a/modules/audio_coding/neteq/neteq.gypi
+++ b/modules/audio_coding/neteq/neteq.gypi
@@ -122,6 +122,7 @@
             'CODEC_ISAC',
             'CODEC_PCM16B_WB',
             'CODEC_ISAC_SWB',
+            'CODEC_ISAC_FB',
             'CODEC_PCM16B_32KHZ',
             'CODEC_CNGCODEC8',
             'CODEC_CNGCODEC16',
@@ -159,6 +160,7 @@
             'CODEC_ISAC',
             'CODEC_PCM16B_WB',
             'CODEC_ISAC_SWB',
+            'CODEC_ISAC_FB',
             'CODEC_PCM16B_32KHZ',
             'CODEC_CNGCODEC8',
             'CODEC_CNGCODEC16',
@@ -271,6 +273,7 @@
             'CODEC_ISAC',
             'CODEC_PCM16B_WB',
             'CODEC_ISAC_SWB',
+            'CODEC_ISAC_FB',
             'CODEC_PCM16B_32KHZ',
             'CODEC_CNGCODEC8',
             'CODEC_CNGCODEC16',
diff --git a/modules/audio_coding/neteq/neteq_defines.h b/modules/audio_coding/neteq/neteq_defines.h
index 79cb144..1f092df 100644
--- a/modules/audio_coding/neteq/neteq_defines.h
+++ b/modules/audio_coding/neteq/neteq_defines.h
@@ -65,6 +65,10 @@
  *
  * NETEQ_ISAC_SWB_CODEC           Enable iSAC-SWB
  *
+ * Note that the decoder of iSAC full-band operates at 32 kHz, that is the
+ * decoded signal is at 32 kHz.
+ * NETEQ_ISAC_FB_CODEC            Enable iSAC-FB
+ *
  * NETEQ_G722_CODEC               Enable G.722
  *
  * NETEQ_G729_CODEC               Enable G.729
@@ -302,6 +306,7 @@
 
     /* Fullband 48 kHz codecs */
     #define NETEQ_OPUS_CODEC
+    #define NETEQ_ISAC_FB_CODEC
 #endif 
 
 #if (defined(NETEQ_ALL_CODECS))
@@ -339,6 +344,7 @@
     /* Super wideband 48kHz codecs */
     #define NETEQ_48KHZ_WIDEBAND
     #define NETEQ_OPUS_CODEC
+    #define NETEQ_ISAC_FB
 #endif
 
 /* Max output size from decoding one frame */
diff --git a/modules/audio_coding/neteq/packet_buffer.c b/modules/audio_coding/neteq/packet_buffer.c
index 60e5198..bb2d08e 100644
--- a/modules/audio_coding/neteq/packet_buffer.c
+++ b/modules/audio_coding/neteq/packet_buffer.c
@@ -615,7 +615,8 @@
             codecBytes = 960; /* 240ms @ 32kbps (60ms frames) */
             codecBuffers = 8;
         }
-        else if (codecID[i] == kDecoderISACswb)
+        else if ((codecID[i] == kDecoderISACswb) ||
+            (codecID[i] == kDecoderISACfb))
         {
             codecBytes = 1560; /* 240ms @ 52kbps (30ms frames) */
             codecBuffers = 8;
diff --git a/modules/audio_coding/neteq/recin.c b/modules/audio_coding/neteq/recin.c
index 00c8f81..c2f0d2d 100644
--- a/modules/audio_coding/neteq/recin.c
+++ b/modules/audio_coding/neteq/recin.c
@@ -380,11 +380,12 @@
             MCU_inst->scalingFactor = kTSscalingTwo;
             break;
         }
+        case kDecoderISACfb:
         case kDecoderOpus:
         {
-            /* We resample Opus internally to 32 kHz, but timestamps
-             * are counted at 48 kHz. So there are two output samples
-             * per three RTP timestamp ticks. */
+            /* We resample Opus internally to 32 kHz, and isac-fb decodes at
+             * 32 kHz, but timestamps are counted at 48 kHz. So there are two
+             * output samples per three RTP timestamp ticks. */
             MCU_inst->scalingFactor = kTSscalingTwoThirds;
             break;
         }
diff --git a/modules/audio_coding/neteq/test/NETEQTEST_CodecClass.cc b/modules/audio_coding/neteq/test/NETEQTEST_CodecClass.cc
index 0056ddc..25f10b0 100644
--- a/modules/audio_coding/neteq/test/NETEQTEST_CodecClass.cc
+++ b/modules/audio_coding/neteq/test/NETEQTEST_CodecClass.cc
@@ -53,7 +53,7 @@
     }
 
     WebRtcIsac_EncoderInit((ISACStruct *) _decoder, 0);
-    WebRtcIsac_SetDecSampRate((ISACStruct *) _decoder, kIsacWideband);
+    WebRtcIsac_SetDecSampRate((ISACStruct *) _decoder, 16000);
 }
 
 
@@ -90,7 +90,7 @@
     }
 
     WebRtcIsac_EncoderInit((ISACStruct *) _decoder, 0);
-    WebRtcIsac_SetDecSampRate((ISACStruct *) _decoder, kIsacSuperWideband);
+    WebRtcIsac_SetDecSampRate((ISACStruct *) _decoder, 32000);
 }
 
 decoder_iSACSWB::~decoder_iSACSWB()
@@ -113,6 +113,32 @@
 }
 #endif
 
+#ifdef CODEC_ISAC_FB
+decoder_iSACFB::decoder_iSACFB(WebRtc_UWord8 pt)
+    : NETEQTEST_Decoder(kDecoderISACfb, 32000, "iSAC fb", pt) {
+  WebRtc_Word16 err = WebRtcIsac_Create((ISACStruct **) &_decoder);
+  if (err) {
+    exit(EXIT_FAILURE);
+  }
+
+  WebRtcIsac_EncoderInit((ISACStruct *) _decoder, 0);
+  WebRtcIsac_SetDecSampRate((ISACStruct *) _decoder, 32000);
+}
+
+decoder_iSACFB::~decoder_iSACFB() {
+  if (_decoder) {
+    WebRtcIsac_Free((ISACStruct *) _decoder);
+    _decoder = NULL;
+  }
+}
+
+int decoder_iSACFB::loadToNetEQ(NETEQTEST_NetEQClass & neteq){
+  WebRtcNetEQ_CodecDef codecInst;
+  SET_ISACFB_FUNCTIONS(codecInst);
+  return(NETEQTEST_Decoder::loadToNetEQ(neteq, codecInst));
+}
+#endif
+
 // PCM u/A
 #ifdef CODEC_G711
 #include "g711_interface.h"
diff --git a/modules/audio_coding/neteq/test/NETEQTEST_CodecClass.h b/modules/audio_coding/neteq/test/NETEQTEST_CodecClass.h
index 6990794..43f16a5 100644
--- a/modules/audio_coding/neteq/test/NETEQTEST_CodecClass.h
+++ b/modules/audio_coding/neteq/test/NETEQTEST_CodecClass.h
@@ -64,6 +64,14 @@
 };
 
 
+class decoder_iSACFB : public NETEQTEST_Decoder {
+ public:
+  decoder_iSACFB(WebRtc_UWord8 pt = 0);
+  virtual ~decoder_iSACFB();
+  int loadToNetEQ(NETEQTEST_NetEQClass & neteq);
+};
+
+
 class decoder_PCMU : public NETEQTEST_Decoder
 {
 public:
diff --git a/modules/audio_coding/neteq/test/NetEqRTPplay.cc b/modules/audio_coding/neteq/test/NetEqRTPplay.cc
index 8aa88d8..83fcbfa 100644
--- a/modules/audio_coding/neteq/test/NetEqRTPplay.cc
+++ b/modules/audio_coding/neteq/test/NetEqRTPplay.cc
@@ -955,6 +955,12 @@
                 tempDecoder.fs = 32000;
             }
 #endif
+#ifdef CODEC_ISAC_FB
+            else if(strcmp(codec, "isacfb") == 0) {
+                tempDecoder.codec = kDecoderISACfb;
+                tempDecoder.fs = 32000;
+            }
+#endif
 #ifdef CODEC_IPCMWB
             else if(strcmp(codec, "ipcmwb") == 0) {
                 tempDecoder.codec = kDecoderIPCMwb;
@@ -1358,6 +1364,11 @@
                 *dec = new decoder_iSACSWB( pt );
                 break;
 #endif
+#ifdef CODEC_ISAC_FB
+            case kDecoderISACfb:
+                *dec = new decoder_iSACFB(pt);
+                break;
+#endif
 #ifdef CODEC_G729
             case kDecoderG729:
                 *dec = new decoder_G729( pt );
diff --git a/modules/audio_coding/neteq/test/PayloadTypes.h b/modules/audio_coding/neteq/test/PayloadTypes.h
index f6cc3da..f74e245 100644
--- a/modules/audio_coding/neteq/test/PayloadTypes.h
+++ b/modules/audio_coding/neteq/test/PayloadTypes.h
@@ -35,6 +35,7 @@
 #define NETEQ_CODEC_ISAC_PT				103
 #define NETEQ_CODEC_ISACLC_PT			119
 #define NETEQ_CODEC_ISACSWB_PT			104
+#define NETEQ_CODEC_ISACFB_PT      124
 #define NETEQ_CODEC_AVT_PT				106
 #define NETEQ_CODEC_G722_1_16_PT		108
 #define NETEQ_CODEC_G722_1_24_PT		109
@@ -53,7 +54,7 @@
 #define NETEQ_CODEC_CN_SWB_PT           126
 #define NETEQ_CODEC_G729_1_PT			107
 #define NETEQ_CODEC_G729D_PT			123
-#define NETEQ_CODEC_MELPE_PT			124
+//#define NETEQ_CODEC_MELPE_PT    124
 #define NETEQ_CODEC_CELT32_PT     114
 
 /* Extra dynamic codepoints */
diff --git a/modules/audio_coding/neteq/test/RTPencode.cc b/modules/audio_coding/neteq/test/RTPencode.cc
index 3aaaf6c..32b0bcc 100644
--- a/modules/audio_coding/neteq/test/RTPencode.cc
+++ b/modules/audio_coding/neteq/test/RTPencode.cc
@@ -110,7 +110,7 @@
 #ifdef CODEC_ILBC
 	#include "ilbc.h"
 #endif
-#if (defined CODEC_ISAC || defined CODEC_ISAC_SWB) 
+#if (defined CODEC_ISAC || defined CODEC_ISAC_SWB || defined CODEC_ISAC_FB)
 	#include "isac.h"
 #endif
 #ifdef NETEQ_ISACFIX_CODEC
@@ -217,6 +217,9 @@
 #ifdef CODEC_ISAC_SWB
 	ISACStruct *ISACSWB_inst[2];
 #endif
+#ifdef CODEC_ISAC_FB
+  ISACStruct *ISACFB_inst[2];
+#endif
 #ifdef CODEC_GSMFR
 	GSMFR_encinst_t *GSMFRenc_inst[2];
 #endif
@@ -362,6 +365,9 @@
 #ifdef CODEC_ISAC_SWB
 		printf("             : isacswb       iSAC SWB (32kHz and 32.0-52.0 kbps). To set rate specify a rate parameter as last parameter\n");
 #endif
+#ifdef CODEC_ISAC_FB
+    printf("             : isacfb       iSAC FB (48kHz encoder 32kHz decoder and 32.0-52.0 kbps). To set rate specify a rate parameter as last parameter\n");
+#endif
 #ifdef CODEC_GSMFR
 		printf("             : gsmfr        GSM FR codec (8kHz and 13kbps)\n");
 #endif
@@ -482,7 +488,8 @@
         }
     }
 
-	if ((usedCodec == kDecoderISAC) || (usedCodec == kDecoderISACswb))
+    if ((usedCodec == kDecoderISAC) || (usedCodec == kDecoderISACswb) ||
+        (usedCodec == kDecoderISACfb))
     {
         if (argc != 7)
         {
@@ -492,7 +499,7 @@
                 printf(
                     "Running iSAC at default bitrate of 32000 bps (to specify explicitly add the bps as last parameter)\n");
             }
-            else // (usedCodec==kDecoderISACswb)
+            else // usedCodec == kDecoderISACswb || usedCodec == kDecoderISACfb
             {
                 bitrate = 56000;
                 printf(
@@ -513,12 +520,12 @@
                 }
                 printf("Running iSAC at bitrate of %i bps\n", bitrate);
             }
-            else // (usedCodec==kDecoderISACswb)
+            else // usedCodec == kDecoderISACswb || usedCodec == kDecoderISACfb
             {
                 if ((bitrate < 32000) || (bitrate > 56000))
                 {
                     printf(
-                        "Error: iSAC SWB bitrate must be between 32000 and 56000 bps (%i is invalid)\n",
+                        "Error: iSAC SWB/FB bitrate must be between 32000 and 56000 bps (%i is invalid)\n",
                         bitrate);
                     exit(0);
                 }
@@ -970,11 +977,16 @@
 		*codec=kDecoderISAC;
 		*PT=NETEQ_CODEC_ISAC_PT;
 	}
-    else if(!strcmp(name,"isacswb")){
-		*fs=32000;
-		*codec=kDecoderISACswb;
-		*PT=NETEQ_CODEC_ISACSWB_PT;
+  else if(!strcmp(name,"isacswb")){
+    *fs=32000;
+    *codec=kDecoderISACswb;
+    *PT=NETEQ_CODEC_ISACSWB_PT;
 	}
+  else if(!strcmp(name,"isacfb")){
+    *fs=48000;
+    *codec=kDecoderISACfb;
+    *PT=NETEQ_CODEC_ISACFB_PT;
+  }
 	else if(!strcmp(name,"g729")){
 		*fs=8000;
 		*codec=kDecoderG729;
@@ -1481,7 +1493,7 @@
                 printf("\nError - iSAC SWB only supports frameSize 30 ms\n");
                 exit(0);
             }
-            ok = WebRtcIsac_SetEncSampRate(ISACSWB_inst[k], kIsacSuperWideband);
+            ok = WebRtcIsac_SetEncSampRate(ISACSWB_inst[k], 32000);
             if (ok!=0) {
                 printf("Error: Couldn't set sample rate for iSAC SWB instance\n");
                 exit(0);
@@ -1498,6 +1510,38 @@
         }
         break;
 #endif
+#ifdef CODEC_ISAC_FB
+    case kDecoderISACfb:
+        if (sampfreq == 48000) {
+            ok = WebRtcIsac_Create(&ISACFB_inst[k]);
+            if (ok != 0) {
+                printf("Error: Couldn't allocate memory for iSAC FB "
+                    "instance\n");
+                exit(0);
+            }
+            if (enc_frameSize != 1440) {
+                printf("\nError - iSAC FB only supports frameSize 30 ms\n");
+                exit(0);
+            }
+            ok = WebRtcIsac_SetEncSampRate(ISACFB_inst[k], 48000);
+            if (ok != 0) {
+                printf("Error: Couldn't set sample rate for iSAC FB "
+                    "instance\n");
+                exit(0);
+            }
+            WebRtcIsac_EncoderInit(ISACFB_inst[k], 1);
+            if ((bitrate < 32000) || (bitrate > 56000)) {
+                printf("\nError - iSAC FB bitrate has to be between 32000 and"
+                    "56000 bps (not %i)\n", bitrate);
+                exit(0);
+            }
+            WebRtcIsac_Control(ISACFB_inst[k], bitrate, 30);
+        } else {
+            printf("\nError - iSAC FB only support 48 kHz sampling rate.\n");
+            exit(0);
+        }
+        break;
+#endif
 #ifdef CODEC_GSMFR
     case kDecoderGSMFR:
         if (sampfreq==8000) {
@@ -1657,6 +1701,11 @@
             WebRtcIsac_Free(ISACSWB_inst[k]);
             break;
 #endif
+#ifdef CODEC_ISAC_FB
+        case kDecoderISACfb:
+            WebRtcIsac_Free(ISACFB_inst[k]);
+            break;
+#endif
 #ifdef CODEC_GSMFR
         case kDecoderGSMFR:
             WebRtcGSMFR_FreeEnc(GSMFRenc_inst[k]);
@@ -1859,6 +1908,18 @@
             }
         }
 #endif
+#ifdef CODEC_ISAC_FB
+        else if (coder == kDecoderISACfb) { /* iSAC FB */
+            int noOfCalls = 0;
+            cdlen = 0;
+            while (cdlen <= 0) {
+                cdlen = WebRtcIsac_Encode(ISACFB_inst[k],
+                                          &indata[noOfCalls * 480],
+                                          (WebRtc_Word16*)encoded);
+                noOfCalls++;
+            }
+        }
+#endif
 #ifdef CODEC_GSMFR
         else if (coder==kDecoderGSMFR) { /* GSM FR */
             cdlen=WebRtcGSMFR_Encode(GSMFRenc_inst[k], indata, frameLen, (WebRtc_Word16*)encoded);
diff --git a/modules/audio_coding/neteq/test/ptypes.txt b/modules/audio_coding/neteq/test/ptypes.txt
index c3d4e25..04d35a6 100644
--- a/modules/audio_coding/neteq/test/ptypes.txt
+++ b/modules/audio_coding/neteq/test/ptypes.txt
@@ -7,6 +7,7 @@
 ilbc 102
 isac 103
 isacswb 104
+isacfb 124
 avt 106
 red 117
 cn_wb 98
diff --git a/modules/audio_coding/neteq/webrtc_neteq_unittest.cc b/modules/audio_coding/neteq/webrtc_neteq_unittest.cc
index 77e7569..ebb96aa 100644
--- a/modules/audio_coding/neteq/webrtc_neteq_unittest.cc
+++ b/modules/audio_coding/neteq/webrtc_neteq_unittest.cc
@@ -239,6 +239,8 @@
   dec_.push_back(new decoder_iSAC(103));
   *used_codec++ = kDecoderISACswb;
   dec_.push_back(new decoder_iSACSWB(104));
+  *used_codec++ = kDecoderISACfb;
+  dec_.push_back(new decoder_iSACFB(105));
   *used_codec++ = kDecoderPCM16B;
   dec_.push_back(new decoder_PCM16B_NB(93));
   *used_codec++ = kDecoderPCM16Bwb;
diff --git a/voice_engine/test/cmd_test/voe_cmd_test.cc b/voice_engine/test/cmd_test/voe_cmd_test.cc
index bf60946..2035e4e 100644
--- a/voice_engine/test/cmd_test/voe_cmd_test.cc
+++ b/voice_engine/test/cmd_test/voe_cmd_test.cc
@@ -340,8 +340,10 @@
     if (strncmp(cinst.plname, "ISAC", 4) == 0 && cinst.plfreq == 32000) {
       printf("%i. ISAC-swb pltype:%i plfreq:%i channels:%i\n", i, cinst.pltype,
              cinst.plfreq, cinst.channels);
-    }
-    else {
+    } else if (strncmp(cinst.plname, "ISAC", 4) == 0 && cinst.plfreq == 48000) {
+      printf("%i. ISAC-fb pltype:%i plfreq:%i channels:%i\n", i, cinst.pltype,
+                   cinst.plfreq, cinst.channels);
+    } else {
       printf("%i. %s pltype:%i plfreq:%i channels:%i\n", i, cinst.plname,
              cinst.pltype, cinst.plfreq, cinst.channels);
     }