Merge "Merge Android 12"
diff --git a/documentation/aacDecoder.pdf b/documentation/aacDecoder.pdf
index cc7cf41..3d4699e 100644
--- a/documentation/aacDecoder.pdf
+++ b/documentation/aacDecoder.pdf
Binary files differ
diff --git a/documentation/aacEncoder.pdf b/documentation/aacEncoder.pdf
index 77b8f4c..a47708a 100644
--- a/documentation/aacEncoder.pdf
+++ b/documentation/aacEncoder.pdf
Binary files differ
diff --git a/fuzzer/aac_dec_fuzzer.cpp b/fuzzer/aac_dec_fuzzer.cpp
index b5545fc..c970197 100644
--- a/fuzzer/aac_dec_fuzzer.cpp
+++ b/fuzzer/aac_dec_fuzzer.cpp
@@ -118,7 +118,8 @@
       INT_PCM outputBuf[kMaxOutBufferSize];
       do {
         mErrorCode =
-            aacDecoder_DecodeFrame(mAacDecoderHandle, outputBuf, sizeof(outputBuf), 0);
+            aacDecoder_DecodeFrame(mAacDecoderHandle, outputBuf,
+                    kMaxOutBufferSize /*size in number of INT_PCM, not bytes*/, 0);
       } while (mErrorCode == AAC_DEC_OK);
       UINT offset = inputSize - valid;
       data += offset;
diff --git a/libAACdec/include/aacdecoder_lib.h b/libAACdec/include/aacdecoder_lib.h
index 56f4ec1..d7928c0 100644
--- a/libAACdec/include/aacdecoder_lib.h
+++ b/libAACdec/include/aacdecoder_lib.h
@@ -1032,7 +1032,7 @@
  * \param self          AAC decoder handle.
  * \param pTimeData     Pointer to external output buffer where the decoded PCM
  * samples will be stored into.
- * \param timeDataSize  Size of external output buffer.
+ * \param timeDataSize  Size of external output buffer in PCM samples.
  * \param flags         Bit field with flags for the decoder: \n
  *                      (flags & AACDEC_CONCEAL) == 1: Do concealment. \n
  *                      (flags & AACDEC_FLUSH) == 2: Discard input data. Flush
diff --git a/libAACdec/src/aac_ram.cpp b/libAACdec/src/aac_ram.cpp
index aa8f6a6..fac1540 100644
--- a/libAACdec/src/aac_ram.cpp
+++ b/libAACdec/src/aac_ram.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -148,7 +148,7 @@
 /*! The buffer holds time samples for the crossfade in case of an USAC DASH IPF
    config change Dimension: (8)
  */
-C_ALLOC_MEM2(TimeDataFlush, INT_PCM, TIME_DATA_FLUSH_SIZE, (8))
+C_ALLOC_MEM2(TimeDataFlush, PCM_DEC, TIME_DATA_FLUSH_SIZE, (8))
 
 /* @} */
 
diff --git a/libAACdec/src/aac_ram.h b/libAACdec/src/aac_ram.h
index b9b95b7..395b2b2 100644
--- a/libAACdec/src/aac_ram.h
+++ b/libAACdec/src/aac_ram.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -132,7 +132,7 @@
 H_ALLOC_MEM(SpectralCoeffs, FIXP_DBL)
 H_ALLOC_MEM(SpecScale, SHORT)
 
-H_ALLOC_MEM(TimeDataFlush, INT_PCM)
+H_ALLOC_MEM(TimeDataFlush, PCM_DEC)
 
 H_ALLOC_MEM_OVERLAY(WorkBufferCore1, CWorkBufferCore1)
 H_ALLOC_MEM_OVERLAY(WorkBufferCore2, FIXP_DBL)
diff --git a/libAACdec/src/aacdec_drc.cpp b/libAACdec/src/aacdec_drc.cpp
index b6f5b49..760a9ba 100644
--- a/libAACdec/src/aacdec_drc.cpp
+++ b/libAACdec/src/aacdec_drc.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -150,6 +150,19 @@
 }
 
 /*!
+\brief  Disable DRC
+
+\self Handle of DRC info
+
+\return none
+*/
+void aacDecoder_drcDisable(HANDLE_AAC_DRC self) {
+  self->enable = 0;
+  self->applyExtGain = 0;
+  self->progRefLevelPresent = 0;
+}
+
+/*!
 \brief Reset DRC information
 
 \self Handle of DRC info
diff --git a/libAACdec/src/aacdec_drc.h b/libAACdec/src/aacdec_drc.h
index 76a44d6..2bb945d 100644
--- a/libAACdec/src/aacdec_drc.h
+++ b/libAACdec/src/aacdec_drc.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -140,6 +140,8 @@
 /**
  * \brief DRC module interface functions
  */
+void aacDecoder_drcDisable(HANDLE_AAC_DRC self);
+
 void aacDecoder_drcReset(HANDLE_AAC_DRC self);
 
 void aacDecoder_drcInit(HANDLE_AAC_DRC self);
diff --git a/libAACdec/src/aacdec_hcrs.cpp b/libAACdec/src/aacdec_hcrs.cpp
index 44b32a5..5e3f9ac 100644
--- a/libAACdec/src/aacdec_hcrs.cpp
+++ b/libAACdec/src/aacdec_hcrs.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -173,7 +173,9 @@
     pHcr->segmentInfo.readDirection = FROM_RIGHT_TO_LEFT;
 
     /* Process sets subsequently */
+    numSet = fMin(numSet, (UCHAR)MAX_HCR_SETS);
     for (currentSet = 1; currentSet < numSet; currentSet++) {
+
       /* step 1 */
       numCodeword -=
           *pNumSegment; /* number of remaining non PCWs [for all sets] */
diff --git a/libAACdec/src/aacdecoder.cpp b/libAACdec/src/aacdecoder.cpp
index 965631b..d5f0cea 100644
--- a/libAACdec/src/aacdecoder.cpp
+++ b/libAACdec/src/aacdecoder.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -494,6 +494,75 @@
   return error;
 }
 
+static INT findElementInstanceTag(
+    INT elementTag, MP4_ELEMENT_ID elementId,
+    CAacDecoderChannelInfo **pAacDecoderChannelInfo, INT nChannels,
+    MP4_ELEMENT_ID *pElementIdTab, INT nElements) {
+  int el, chCnt = 0;
+
+  for (el = 0; el < nElements; el++) {
+    switch (pElementIdTab[el]) {
+      case ID_CPE:
+      case ID_SCE:
+      case ID_LFE:
+        if ((elementTag == pAacDecoderChannelInfo[chCnt]->ElementInstanceTag) &&
+            (elementId == pElementIdTab[el])) {
+          return 1; /* element instance tag found */
+        }
+        chCnt += (pElementIdTab[el] == ID_CPE) ? 2 : 1;
+        break;
+      default:
+        break;
+    }
+    if (chCnt >= nChannels) break;
+    if (pElementIdTab[el] == ID_END) break;
+  }
+
+  return 0; /* element instance tag not found */
+}
+
+static INT validateElementInstanceTags(
+    CProgramConfig *pce, CAacDecoderChannelInfo **pAacDecoderChannelInfo,
+    INT nChannels, MP4_ELEMENT_ID *pElementIdTab, INT nElements) {
+  if (nChannels >= pce->NumChannels) {
+    for (int el = 0; el < pce->NumFrontChannelElements; el++) {
+      if (!findElementInstanceTag(pce->FrontElementTagSelect[el],
+                                  pce->FrontElementIsCpe[el] ? ID_CPE : ID_SCE,
+                                  pAacDecoderChannelInfo, nChannels,
+                                  pElementIdTab, nElements)) {
+        return 0; /* element instance tag not in raw_data_block() */
+      }
+    }
+    for (int el = 0; el < pce->NumSideChannelElements; el++) {
+      if (!findElementInstanceTag(pce->SideElementTagSelect[el],
+                                  pce->SideElementIsCpe[el] ? ID_CPE : ID_SCE,
+                                  pAacDecoderChannelInfo, nChannels,
+                                  pElementIdTab, nElements)) {
+        return 0; /* element instance tag not in raw_data_block() */
+      }
+    }
+    for (int el = 0; el < pce->NumBackChannelElements; el++) {
+      if (!findElementInstanceTag(pce->BackElementTagSelect[el],
+                                  pce->BackElementIsCpe[el] ? ID_CPE : ID_SCE,
+                                  pAacDecoderChannelInfo, nChannels,
+                                  pElementIdTab, nElements)) {
+        return 0; /* element instance tag not in raw_data_block() */
+      }
+    }
+    for (int el = 0; el < pce->NumLfeChannelElements; el++) {
+      if (!findElementInstanceTag(pce->LfeElementTagSelect[el], ID_LFE,
+                                  pAacDecoderChannelInfo, nChannels,
+                                  pElementIdTab, nElements)) {
+        return 0; /* element instance tag not in raw_data_block() */
+      }
+    }
+  } else {
+    return 0; /* too less decoded audio channels */
+  }
+
+  return 1; /* all element instance tags found in raw_data_block() */
+}
+
 /*!
   \brief Read Program Config Element
 
@@ -568,7 +637,7 @@
   \return  Error code
 */
 LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_PrepareCrossFade(
-    const INT_PCM *pTimeData, INT_PCM **pTimeDataFlush, const INT numChannels,
+    const PCM_DEC *pTimeData, PCM_DEC **pTimeDataFlush, const INT numChannels,
     const INT frameSize, const INT interleaved) {
   int i, ch, s1, s2;
   AAC_DECODER_ERROR ErrorStatus;
@@ -584,7 +653,7 @@
   }
 
   for (ch = 0; ch < numChannels; ch++) {
-    const INT_PCM *pIn = &pTimeData[ch * s1];
+    const PCM_DEC *pIn = &pTimeData[ch * s1];
     for (i = 0; i < TIME_DATA_FLUSH_SIZE; i++) {
       pTimeDataFlush[ch][i] = *pIn;
       pIn += s2;
@@ -606,7 +675,7 @@
   \return  Error code
 */
 LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_ApplyCrossFade(
-    INT_PCM *pTimeData, INT_PCM **pTimeDataFlush, const INT numChannels,
+    PCM_DEC *pTimeData, PCM_DEC **pTimeDataFlush, const INT numChannels,
     const INT frameSize, const INT interleaved) {
   int i, ch, s1, s2;
   AAC_DECODER_ERROR ErrorStatus;
@@ -622,15 +691,15 @@
   }
 
   for (ch = 0; ch < numChannels; ch++) {
-    INT_PCM *pIn = &pTimeData[ch * s1];
+    PCM_DEC *pIn = &pTimeData[ch * s1];
     for (i = 0; i < TIME_DATA_FLUSH_SIZE; i++) {
       FIXP_SGL alpha = (FIXP_SGL)i
                        << (FRACT_BITS - 1 - TIME_DATA_FLUSH_SIZE_SF);
-      FIXP_DBL time = FX_PCM2FX_DBL(*pIn);
-      FIXP_DBL timeFlush = FX_PCM2FX_DBL(pTimeDataFlush[ch][i]);
+      FIXP_DBL time = PCM_DEC2FIXP_DBL(*pIn);
+      FIXP_DBL timeFlush = PCM_DEC2FIXP_DBL(pTimeDataFlush[ch][i]);
 
-      *pIn = (INT_PCM)(FIXP_PCM)FX_DBL2FX_PCM(
-          timeFlush - fMult(timeFlush, alpha) + fMult(time, alpha));
+      *pIn = FIXP_DBL2PCM_DEC(timeFlush - fMult(timeFlush, alpha) +
+                              fMult(time, alpha));
       pIn += s2;
     }
   }
@@ -753,7 +822,12 @@
     /* We are interested in preroll AUs if an explicit or an implicit config
      * change is signalized in other words if the build up status is set. */
     if (self->buildUpStatus == AACDEC_USAC_BUILD_UP_ON) {
-      self->applyCrossfade |= FDKreadBit(hBs);
+      UCHAR applyCrossfade = FDKreadBit(hBs);
+      if (applyCrossfade) {
+        self->applyCrossfade |= AACDEC_CROSSFADE_BITMASK_PREROLL;
+      } else {
+        self->applyCrossfade &= ~AACDEC_CROSSFADE_BITMASK_PREROLL;
+      }
       FDKreadBit(hBs); /* reserved */
       /* Read num preroll AU's */
       *numPrerollAU = escapedValue(hBs, 2, 4, 0);
@@ -1397,6 +1471,27 @@
 }
 
 /*!
+ * \brief CAacDecoder_AcceptFlags Accept flags and element flags
+ *
+ * \param self          [o]   handle to AACDECODER structure
+ * \param asc           [i]   handle to ASC structure
+ * \param flags         [i]   flags
+ * \param elFlags       [i]   pointer to element flags
+ * \param streamIndex   [i]   stream index
+ * \param elementOffset [i]   element offset
+ *
+ * \return void
+ */
+static void CAacDecoder_AcceptFlags(HANDLE_AACDECODER self,
+                                    const CSAudioSpecificConfig *asc,
+                                    UINT flags, UINT *elFlags, int streamIndex,
+                                    int elementOffset) {
+  FDKmemcpy(self->elFlags, elFlags, sizeof(self->elFlags));
+
+  self->flags[streamIndex] = flags;
+}
+
+/*!
  * \brief CAacDecoder_CtrlCFGChange Set config change parameters.
  *
  * \param self           [i]   handle to AACDECODER structure
@@ -1493,6 +1588,15 @@
   const int streamIndex = 0;
   INT flushChannels = 0;
 
+  UINT flags;
+  /* elFlags[(3*MAX_CHANNELS + (MAX_CHANNELS)/2 + 4 * (MAX_TRACKS) + 1]
+     where MAX_CHANNELS is (8*2) and MAX_TRACKS is 1 */
+  UINT elFlags[(3 * ((8) * 2) + (((8) * 2)) / 2 + 4 * (1) + 1)];
+
+  UCHAR sbrEnabled = self->sbrEnabled;
+  UCHAR sbrEnabledPrev = self->sbrEnabledPrev;
+  UCHAR mpsEnableCurr = self->mpsEnableCurr;
+
   if (!self) return AAC_DEC_INVALID_HANDLE;
 
   UCHAR downscaleFactor = self->downscaleFactor;
@@ -1649,8 +1753,8 @@
   }
 
   /* Set syntax flags */
-  self->flags[streamIndex] = 0;
-  { FDKmemclear(self->elFlags, sizeof(self->elFlags)); }
+  flags = 0;
+  { FDKmemclear(elFlags, sizeof(elFlags)); }
 
   if ((asc->m_channelConfiguration > 0) || IS_USAC(asc->m_aot)) {
     if (IS_USAC(asc->m_aot)) {
@@ -1676,7 +1780,7 @@
             asc->m_sc.m_usacConfig.m_usacNumElements;
       }
 
-      self->mpsEnableCurr = 0;
+      mpsEnableCurr = 0;
       for (int _el = 0;
            _el < (int)self->pUsacConfig[streamIndex]->m_usacNumElements;
            _el++) {
@@ -1696,35 +1800,34 @@
           self->usacStereoConfigIndex[el] =
               asc->m_sc.m_usacConfig.element[_el].m_stereoConfigIndex;
           if (self->elements[el] == ID_USAC_CPE) {
-            self->mpsEnableCurr |= self->usacStereoConfigIndex[el] ? 1 : 0;
+            mpsEnableCurr |= self->usacStereoConfigIndex[el] ? 1 : 0;
           }
         }
 
-        self->elFlags[el] |=
-            (asc->m_sc.m_usacConfig.element[_el].m_noiseFilling)
-                ? AC_EL_USAC_NOISE
-                : 0;
-        self->elFlags[el] |=
+        elFlags[el] |= (asc->m_sc.m_usacConfig.element[_el].m_noiseFilling)
+                           ? AC_EL_USAC_NOISE
+                           : 0;
+        elFlags[el] |=
             (asc->m_sc.m_usacConfig.element[_el].m_stereoConfigIndex > 0)
                 ? AC_EL_USAC_MPS212
                 : 0;
-        self->elFlags[el] |= (asc->m_sc.m_usacConfig.element[_el].m_interTes)
-                                 ? AC_EL_USAC_ITES
-                                 : 0;
-        self->elFlags[el] |=
+        elFlags[el] |= (asc->m_sc.m_usacConfig.element[_el].m_interTes)
+                           ? AC_EL_USAC_ITES
+                           : 0;
+        elFlags[el] |=
             (asc->m_sc.m_usacConfig.element[_el].m_pvc) ? AC_EL_USAC_PVC : 0;
-        self->elFlags[el] |=
+        elFlags[el] |=
             (asc->m_sc.m_usacConfig.element[_el].usacElementType == ID_USAC_LFE)
                 ? AC_EL_USAC_LFE
                 : 0;
-        self->elFlags[el] |=
+        elFlags[el] |=
             (asc->m_sc.m_usacConfig.element[_el].usacElementType == ID_USAC_LFE)
                 ? AC_EL_LFE
                 : 0;
         if ((asc->m_sc.m_usacConfig.element[_el].usacElementType ==
              ID_USAC_CPE) &&
             ((self->usacStereoConfigIndex[el] == 0))) {
-          self->elFlags[el] |= AC_EL_USAC_CP_POSSIBLE;
+          elFlags[el] |= AC_EL_USAC_CP_POSSIBLE;
         }
       }
 
@@ -1791,9 +1894,17 @@
       downscaleFactorInBS =
           asc->m_samplingFrequency /
           asc->m_sc.m_eldSpecificConfig.m_downscaledSamplingFrequency;
-      if (downscaleFactorInBS == 1 || downscaleFactorInBS == 2 ||
-          downscaleFactorInBS == 3 || downscaleFactorInBS == 4) {
+      if ((downscaleFactorInBS == 1 || downscaleFactorInBS == 2 ||
+           (downscaleFactorInBS == 3 &&
+            asc->m_sc.m_eldSpecificConfig.m_frameLengthFlag) ||
+           downscaleFactorInBS == 4) &&
+          ((asc->m_samplingFrequency %
+            asc->m_sc.m_eldSpecificConfig.m_downscaledSamplingFrequency) ==
+           0)) {
         downscaleFactor = downscaleFactorInBS;
+      } else {
+        downscaleFactorInBS = 1;
+        downscaleFactor = 1;
       }
     }
   } else {
@@ -1825,7 +1936,7 @@
       self->useLdQmfTimeAlign =
           asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign;
     }
-    if (self->sbrEnabled != asc->m_sbrPresentFlag) {
+    if (sbrEnabled != asc->m_sbrPresentFlag) {
       ascChanged = 1;
     }
   }
@@ -1838,16 +1949,16 @@
   if (configMode & AC_CM_ALLOC_MEM) {
     self->streamInfo.extSamplingRate = asc->m_extensionSamplingFrequency;
   }
-  self->flags[streamIndex] |= (asc->m_sbrPresentFlag) ? AC_SBR_PRESENT : 0;
-  self->flags[streamIndex] |= (asc->m_psPresentFlag) ? AC_PS_PRESENT : 0;
+  flags |= (asc->m_sbrPresentFlag) ? AC_SBR_PRESENT : 0;
+  flags |= (asc->m_psPresentFlag) ? AC_PS_PRESENT : 0;
   if (asc->m_sbrPresentFlag) {
-    self->sbrEnabled = 1;
-    self->sbrEnabledPrev = 1;
+    sbrEnabled = 1;
+    sbrEnabledPrev = 1;
   } else {
-    self->sbrEnabled = 0;
-    self->sbrEnabledPrev = 0;
+    sbrEnabled = 0;
+    sbrEnabledPrev = 0;
   }
-  if (self->sbrEnabled && asc->m_extensionSamplingFrequency) {
+  if (sbrEnabled && asc->m_extensionSamplingFrequency) {
     if (downscaleFactor != 1 && (downscaleFactor)&1) {
       return AAC_DEC_UNSUPPORTED_SAMPLINGRATE; /* SBR needs an even downscale
                                                   factor */
@@ -1865,51 +1976,47 @@
   }
 
   /* --------- vcb11 ------------ */
-  self->flags[streamIndex] |= (asc->m_vcb11Flag) ? AC_ER_VCB11 : 0;
+  flags |= (asc->m_vcb11Flag) ? AC_ER_VCB11 : 0;
 
   /* ---------- rvlc ------------ */
-  self->flags[streamIndex] |= (asc->m_rvlcFlag) ? AC_ER_RVLC : 0;
+  flags |= (asc->m_rvlcFlag) ? AC_ER_RVLC : 0;
 
   /* ----------- hcr ------------ */
-  self->flags[streamIndex] |= (asc->m_hcrFlag) ? AC_ER_HCR : 0;
+  flags |= (asc->m_hcrFlag) ? AC_ER_HCR : 0;
 
   if (asc->m_aot == AOT_ER_AAC_ELD) {
-    self->mpsEnableCurr = 0;
-    self->flags[streamIndex] |= AC_ELD;
-    self->flags[streamIndex] |=
-        (asc->m_sbrPresentFlag)
-            ? AC_SBR_PRESENT
-            : 0; /* Need to set the SBR flag for backward-compatibility
-       reasons. Even if SBR is not supported. */
-    self->flags[streamIndex] |=
-        (asc->m_sc.m_eldSpecificConfig.m_sbrCrcFlag) ? AC_SBRCRC : 0;
-    self->flags[streamIndex] |=
-        (asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign) ? AC_MPS_PRESENT
-                                                            : 0;
+    mpsEnableCurr = 0;
+    flags |= AC_ELD;
+    flags |= (asc->m_sbrPresentFlag)
+                 ? AC_SBR_PRESENT
+                 : 0; /* Need to set the SBR flag for backward-compatibility
+                               reasons. Even if SBR is not supported. */
+    flags |= (asc->m_sc.m_eldSpecificConfig.m_sbrCrcFlag) ? AC_SBRCRC : 0;
+    flags |= (asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign)
+                 ? AC_MPS_PRESENT
+                 : 0;
     if (self->mpsApplicable) {
-      self->mpsEnableCurr = asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign;
+      mpsEnableCurr = asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign;
     }
   }
-  self->flags[streamIndex] |= (asc->m_aot == AOT_ER_AAC_LD) ? AC_LD : 0;
-  self->flags[streamIndex] |= (asc->m_epConfig >= 0) ? AC_ER : 0;
+  flags |= (asc->m_aot == AOT_ER_AAC_LD) ? AC_LD : 0;
+  flags |= (asc->m_epConfig >= 0) ? AC_ER : 0;
 
   if (asc->m_aot == AOT_USAC) {
-    self->flags[streamIndex] |= AC_USAC;
-    self->flags[streamIndex] |=
-        (asc->m_sc.m_usacConfig.element[0].m_stereoConfigIndex > 0)
-            ? AC_MPS_PRESENT
-            : 0;
+    flags |= AC_USAC;
+    flags |= (asc->m_sc.m_usacConfig.element[0].m_stereoConfigIndex > 0)
+                 ? AC_MPS_PRESENT
+                 : 0;
   }
   if (asc->m_aot == AOT_DRM_AAC) {
-    self->flags[streamIndex] |= AC_DRM | AC_SBRCRC | AC_SCALABLE;
+    flags |= AC_DRM | AC_SBRCRC | AC_SCALABLE;
   }
   if (asc->m_aot == AOT_DRM_SURROUND) {
-    self->flags[streamIndex] |=
-        AC_DRM | AC_SBRCRC | AC_SCALABLE | AC_MPS_PRESENT;
+    flags |= AC_DRM | AC_SBRCRC | AC_SCALABLE | AC_MPS_PRESENT;
     FDK_ASSERT(!asc->m_psPresentFlag);
   }
   if ((asc->m_aot == AOT_AAC_SCAL) || (asc->m_aot == AOT_ER_AAC_SCAL)) {
-    self->flags[streamIndex] |= AC_SCALABLE;
+    flags |= AC_SCALABLE;
   }
 
   if ((asc->m_epConfig >= 0) && (asc->m_channelConfiguration <= 0)) {
@@ -1960,13 +2067,17 @@
     if (ascChanged != 0) {
       *configChanged = 1;
     }
+
+    CAacDecoder_AcceptFlags(self, asc, flags, elFlags, streamIndex,
+                            elementOffset);
+
     return err;
   }
 
   /* set AC_USAC_SCFGI3 globally if any usac element uses */
   switch (asc->m_aot) {
     case AOT_USAC:
-      if (self->sbrEnabled) {
+      if (sbrEnabled) {
         for (int _el = 0;
              _el < (int)self->pUsacConfig[streamIndex]->m_usacNumElements;
              _el++) {
@@ -1988,7 +2099,7 @@
         }
 
         if (usacStereoConfigIndex == 3) {
-          self->flags[streamIndex] |= AC_USAC_SCFGI3;
+          flags |= AC_USAC_SCFGI3;
         }
       }
       break;
@@ -2003,7 +2114,7 @@
     */
     switch (asc->m_aot) {
       case AOT_USAC:
-        if (self->sbrEnabled) {
+        if (sbrEnabled) {
           const UCHAR map_sbrRatio_2_nAnaBands[] = {16, 24, 32};
 
           FDK_ASSERT(asc->m_sc.m_usacConfig.m_sbrRatioIndex > 0);
@@ -2031,11 +2142,11 @@
         }
         break;
       case AOT_ER_AAC_ELD:
-        if (self->mpsEnableCurr &&
+        if (mpsEnableCurr &&
             asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign) {
-          SAC_INPUT_CONFIG sac_interface =
-              (self->sbrEnabled && self->hSbrDecoder) ? SAC_INTERFACE_QMF
-                                                      : SAC_INTERFACE_TIME;
+          SAC_INPUT_CONFIG sac_interface = (sbrEnabled && self->hSbrDecoder)
+                                               ? SAC_INTERFACE_QMF
+                                               : SAC_INTERFACE_TIME;
           mpegSurroundDecoder_ConfigureQmfDomain(
               (CMpegSurroundDecoder *)self->pMpegSurroundDecoder, sac_interface,
               (UINT)self->streamInfo.aacSampleRate, asc->m_aot);
@@ -2069,14 +2180,14 @@
       ch = aacChannelsOffset;
       int _numElements;
       _numElements = (((8)) + (8));
-      if (self->flags[streamIndex] & (AC_RSV603DA | AC_USAC)) {
+      if (flags & (AC_RSV603DA | AC_USAC)) {
         _numElements = (int)asc->m_sc.m_usacConfig.m_usacNumElements;
       }
       for (int _el = 0; _el < _numElements; _el++) {
         int el_channels = 0;
         int el = elementOffset + _el;
 
-        if (self->flags[streamIndex] &
+        if (flags &
             (AC_ER | AC_LD | AC_ELD | AC_RSV603DA | AC_USAC | AC_RSVD50)) {
           if (ch >= ascChannels) {
             break;
@@ -2176,15 +2287,14 @@
           if (self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer == NULL) {
             goto bail;
           }
-          if (self->flags[streamIndex] &
-              (AC_USAC | AC_RSVD50 | AC_RSV603DA /*|AC_BSAC*/)) {
+          if (flags & (AC_USAC | AC_RSVD50 | AC_RSV603DA /*|AC_BSAC*/)) {
             self->pAacDecoderStaticChannelInfo[ch]->hArCo = CArco_Create();
             if (self->pAacDecoderStaticChannelInfo[ch]->hArCo == NULL) {
               goto bail;
             }
           }
 
-          if (!(self->flags[streamIndex] & (AC_USAC | AC_RSV603DA))) {
+          if (!(flags & (AC_USAC | AC_RSV603DA))) {
             CPns_UpdateNoiseState(
                 &self->pAacDecoderChannelInfo[ch]->data.aac.PnsData,
                 &self->pAacDecoderStaticChannelInfo[ch]->pnsCurrentSeed,
@@ -2195,7 +2305,7 @@
         chIdx++;
       }
 
-      if (self->flags[streamIndex] & AC_USAC) {
+      if (flags & AC_USAC) {
         for (int _ch = 0; _ch < flushChannels; _ch++) {
           ch = aacChannelsOffset + _ch;
           if (self->pTimeDataFlush[ch] == NULL) {
@@ -2207,7 +2317,7 @@
         }
       }
 
-      if (self->flags[streamIndex] & (AC_USAC | AC_RSV603DA)) {
+      if (flags & (AC_USAC | AC_RSV603DA)) {
         int complexStereoPredPossible = 0;
         ch = aacChannelsOffset;
         chIdx = aacChannelsOffsetIdx;
@@ -2223,7 +2333,7 @@
             elCh = 1;
           }
 
-          if (self->elFlags[el2] & AC_EL_USAC_CP_POSSIBLE) {
+          if (elFlags[el2] & AC_EL_USAC_CP_POSSIBLE) {
             complexStereoPredPossible = 1;
             if (self->cpeStaticData[el2] == NULL) {
               self->cpeStaticData[el2] = GetCpePersistentData();
@@ -2360,9 +2470,6 @@
     }
   }
 
-  /* Update externally visible copy of flags */
-  self->streamInfo.flags = self->flags[0];
-
   if (*configChanged) {
     int drcDecSampleRate, drcDecFrameSize;
 
@@ -2383,8 +2490,7 @@
 
   if (*configChanged) {
     if (asc->m_aot == AOT_USAC) {
-      self->hDrcInfo->enable = 0;
-      self->hDrcInfo->progRefLevelPresent = 0;
+      aacDecoder_drcDisable(self->hDrcInfo);
     }
   }
 
@@ -2393,6 +2499,15 @@
     pcmLimiter_SetThreshold(self->hLimiter, FL2FXCONST_DBL(0.89125094f));
   }
 
+  CAacDecoder_AcceptFlags(self, asc, flags, elFlags, streamIndex,
+                          elementOffset);
+  self->sbrEnabled = sbrEnabled;
+  self->sbrEnabledPrev = sbrEnabledPrev;
+  self->mpsEnableCurr = mpsEnableCurr;
+
+  /* Update externally visible copy of flags */
+  self->streamInfo.flags = self->flags[0];
+
   return err;
 
 bail:
@@ -2927,6 +3042,24 @@
 
   } /* while ( (type != ID_END) ... ) */
 
+  if (!(self->flags[streamIndex] &
+        (AC_USAC | AC_RSVD50 | AC_RSV603DA | AC_BSAC | AC_LD | AC_ELD | AC_ER |
+         AC_SCALABLE)) &&
+      (self->streamInfo.channelConfig == 0) && pce->isValid &&
+      (ErrorStatus == AAC_DEC_OK) && self->frameOK &&
+      !(flags & (AACDEC_CONCEAL | AACDEC_FLUSH))) {
+    /* Check whether all PCE listed element instance tags are present in
+     * raw_data_block() */
+    if (!validateElementInstanceTags(
+            &self->pce, self->pAacDecoderChannelInfo, aacChannels,
+            channel_elements,
+            fMin(channel_element_count, (int)(sizeof(channel_elements) /
+                                              sizeof(*channel_elements))))) {
+      ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR;
+      self->frameOK = 0;
+    }
+  }
+
   if (!(flags & (AACDEC_CONCEAL | AACDEC_FLUSH))) {
     /* float decoder checks if bitsLeft is in range 0-7; only prerollAUs are
      * byteAligned with respect to the first bit */
@@ -3194,11 +3327,12 @@
          * data in the bitstream. */
         self->flags[streamIndex] |= AC_DRC_PRESENT;
       } else {
-        self->hDrcInfo->enable = 0;
-        self->hDrcInfo->progRefLevelPresent = 0;
         ErrorStatus = AAC_DEC_UNSUPPORTED_FORMAT;
       }
     }
+    if (self->flags[streamIndex] & (AC_USAC | AC_RSV603DA)) {
+      aacDecoder_drcDisable(self->hDrcInfo);
+    }
 
     /* Create a reverse mapping table */
     UCHAR Reverse_chMapping[((8) * 2)];
@@ -3441,11 +3575,12 @@
          * data in the bitstream. */
         self->flags[streamIndex] |= AC_DRC_PRESENT;
       } else {
-        self->hDrcInfo->enable = 0;
-        self->hDrcInfo->progRefLevelPresent = 0;
         ErrorStatus = AAC_DEC_UNSUPPORTED_FORMAT;
       }
     }
+    if (self->flags[streamIndex] & (AC_USAC | AC_RSV603DA)) {
+      aacDecoder_drcDisable(self->hDrcInfo);
+    }
   }
 
   /* Add additional concealment delay */
diff --git a/libAACdec/src/aacdecoder.h b/libAACdec/src/aacdecoder.h
index bd1f38f..002807f 100644
--- a/libAACdec/src/aacdecoder.h
+++ b/libAACdec/src/aacdecoder.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -172,6 +172,12 @@
   AACDEC_RSV60_BUILD_UP_IDLE_IN_BAND = 5
 };
 
+#define AACDEC_CROSSFADE_BITMASK_OFF                                    \
+  ((UCHAR)0) /*!< No cross-fade between frames shall be applied at next \
+                config change. */
+#define AACDEC_CROSSFADE_BITMASK_PREROLL \
+  ((UCHAR)1 << 1) /*!< applyCrossfade is signaled in AudioPreRoll */
+
 typedef struct {
   /* Usac Extension Elements */
   USAC_EXT_ELEMENT_TYPE usacExtElementType[(3)];
@@ -325,7 +331,7 @@
   UINT loudnessInfoSetPosition[3];
   SCHAR defaultTargetLoudness;
 
-  INT_PCM
+  PCM_DEC
   *pTimeDataFlush[((8) * 2)]; /*!< Pointer to the flushed time data which
                                  will be used for the crossfade in case of
                                  an USAC DASH IPF config change */
@@ -341,8 +347,8 @@
                                                           start position in the
                                                           bitstream */
   INT accessUnit; /*!< Number of the actual processed preroll accessUnit */
-  UCHAR applyCrossfade; /*!< if set crossfade for seamless stream switching is
-                           applied */
+  UCHAR applyCrossfade; /*!< If any bit is set, cross-fade for seamless stream
+                           switching is applied */
 
   FDK_SignalDelay usacResidualDelay; /*!< Delay residual signal to compensate
                                         for eSBR delay of DMX signal in case of
@@ -439,12 +445,12 @@
 
 /* Prepare crossfade for USAC DASH IPF config change */
 LINKSPEC_H AAC_DECODER_ERROR CAacDecoder_PrepareCrossFade(
-    const INT_PCM *pTimeData, INT_PCM **pTimeDataFlush, const INT numChannels,
+    const PCM_DEC *pTimeData, PCM_DEC **pTimeDataFlush, const INT numChannels,
     const INT frameSize, const INT interleaved);
 
 /* Apply crossfade for USAC DASH IPF config change */
 LINKSPEC_H AAC_DECODER_ERROR CAacDecoder_ApplyCrossFade(
-    INT_PCM *pTimeData, INT_PCM **pTimeDataFlush, const INT numChannels,
+    PCM_DEC *pTimeData, PCM_DEC **pTimeDataFlush, const INT numChannels,
     const INT frameSize, const INT interleaved);
 
 /* Set flush and build up mode */
diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp
index 0f281eb..0c83191 100644
--- a/libAACdec/src/aacdecoder_lib.cpp
+++ b/libAACdec/src/aacdecoder_lib.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -385,21 +385,19 @@
   return errTp;
 }
 
-static INT aacDecoder_SscCallback(void *handle, HANDLE_FDK_BITSTREAM hBs,
-                                  const AUDIO_OBJECT_TYPE coreCodec,
-                                  const INT samplingRate, const INT frameSize,
-                                  const INT stereoConfigIndex,
-                                  const INT coreSbrFrameLengthIndex,
-                                  const INT configBytes, const UCHAR configMode,
-                                  UCHAR *configChanged) {
+static INT aacDecoder_SscCallback(
+    void *handle, HANDLE_FDK_BITSTREAM hBs, const AUDIO_OBJECT_TYPE coreCodec,
+    const INT samplingRate, const INT frameSize, const INT numChannels,
+    const INT stereoConfigIndex, const INT coreSbrFrameLengthIndex,
+    const INT configBytes, const UCHAR configMode, UCHAR *configChanged) {
   SACDEC_ERROR err;
   TRANSPORTDEC_ERROR errTp;
   HANDLE_AACDECODER hAacDecoder = (HANDLE_AACDECODER)handle;
 
   err = mpegSurroundDecoder_Config(
       (CMpegSurroundDecoder *)hAacDecoder->pMpegSurroundDecoder, hBs, coreCodec,
-      samplingRate, frameSize, stereoConfigIndex, coreSbrFrameLengthIndex,
-      configBytes, configMode, configChanged);
+      samplingRate, frameSize, numChannels, stereoConfigIndex,
+      coreSbrFrameLengthIndex, configBytes, configMode, configChanged);
 
   switch (err) {
     case MPS_UNSUPPORTED_CONFIG:
@@ -443,12 +441,23 @@
   TRANSPORTDEC_ERROR errTp;
   HANDLE_AACDECODER hAacDecoder = (HANDLE_AACDECODER)handle;
   DRC_DEC_CODEC_MODE drcDecCodecMode = DRC_DEC_CODEC_MODE_UNDEFINED;
+  UCHAR dummyBuffer[4] = {0};
+  FDK_BITSTREAM dummyBs;
+  HANDLE_FDK_BITSTREAM hReadBs;
 
   if (subStreamIndex != 0) {
     return TRANSPORTDEC_OK;
   }
 
-  else if (aot == AOT_USAC) {
+  if (hBs == NULL) {
+    /* use dummy zero payload to clear memory */
+    hReadBs = &dummyBs;
+    FDKinitBitStream(hReadBs, dummyBuffer, 4, 24);
+  } else {
+    hReadBs = hBs;
+  }
+
+  if (aot == AOT_USAC) {
     drcDecCodecMode = DRC_DEC_MPEG_D_USAC;
   }
 
@@ -457,10 +466,10 @@
 
   if (payloadType == 0) /* uniDrcConfig */
   {
-    err = FDK_drcDec_ReadUniDrcConfig(hAacDecoder->hUniDrcDecoder, hBs);
+    err = FDK_drcDec_ReadUniDrcConfig(hAacDecoder->hUniDrcDecoder, hReadBs);
   } else /* loudnessInfoSet */
   {
-    err = FDK_drcDec_ReadLoudnessInfoSet(hAacDecoder->hUniDrcDecoder, hBs);
+    err = FDK_drcDec_ReadLoudnessInfoSet(hAacDecoder->hUniDrcDecoder, hReadBs);
     hAacDecoder->loudnessInfoSetPosition[1] = payloadStart;
     hAacDecoder->loudnessInfoSetPosition[2] = fullPayloadLength;
   }
@@ -822,6 +831,9 @@
 
     case AAC_DRC_ATTENUATION_FACTOR:
       /* DRC compression factor (where 0 is no and 127 is max compression) */
+      if ((value < 0) || (value > 127)) {
+        return AAC_DEC_SET_PARAM_FAIL;
+      }
       errorStatus = aacDecoder_drcSetParam(hDrcInfo, DRC_CUT_SCALE, value);
       uniDrcErr = FDK_drcDec_SetParam(self->hUniDrcDecoder, DRC_DEC_COMPRESS,
                                       value * (FL2FXCONST_DBL(0.5f / 127.0f)));
@@ -829,6 +841,9 @@
 
     case AAC_DRC_BOOST_FACTOR:
       /* DRC boost factor (where 0 is no and 127 is max boost) */
+      if ((value < 0) || (value > 127)) {
+        return AAC_DEC_SET_PARAM_FAIL;
+      }
       errorStatus = aacDecoder_drcSetParam(hDrcInfo, DRC_BOOST_SCALE, value);
       uniDrcErr = FDK_drcDec_SetParam(self->hUniDrcDecoder, DRC_DEC_BOOST,
                                       value * (FL2FXCONST_DBL(0.5f / 127.0f)));
@@ -1151,6 +1166,8 @@
   int applyCrossfade = 1;    /* flag indicates if flushing was possible */
   PCM_DEC *pTimeData2;
   PCM_AAC *pTimeData3;
+  INT pcmLimiterScale = 0;
+  INT interleaved = 0;
 
   if (self == NULL) {
     return AAC_DEC_INVALID_HANDLE;
@@ -1173,8 +1190,10 @@
       aacDecoder_FreeMemCallback(self, &asc);
       self->streamInfo.numChannels = 0;
       /* 3) restore AudioSpecificConfig */
-      transportDec_OutOfBandConfig(self->hInput, asc.config,
-                                   (asc.configBits + 7) >> 3, 0);
+      if (asc.configBits <= (TP_USAC_MAX_CONFIG_LEN << 3)) {
+        transportDec_OutOfBandConfig(self->hInput, asc.config,
+                                     (asc.configBits + 7) >> 3, 0);
+      }
     }
   }
 
@@ -1607,6 +1626,11 @@
         /* set params */
         sbrDecoder_SetParam(self->hSbrDecoder, SBR_SYSTEM_BITSTREAM_DELAY,
                             self->sbrParams.bsDelay);
+        sbrDecoder_SetParam(
+            self->hSbrDecoder, SBR_FLUSH_DATA,
+            (flags & AACDEC_FLUSH) |
+                ((self->flushStatus && !(flags & AACDEC_CONCEAL)) ? AACDEC_FLUSH
+                                                                  : 0));
 
         sbrDecoder_SetParam(self->hSbrDecoder, SBR_SKIP_QMF, 1);
 
@@ -1794,8 +1818,7 @@
       }
 
       if (self->streamInfo.extAot != AOT_AAC_SLS) {
-        INT pcmLimiterScale = 0;
-        INT interleaved = 0;
+        interleaved = 0;
         interleaved |= (self->sbrEnabled) ? 1 : 0;
         interleaved |= (self->mpsEnableCurr) ? 1 : 0;
         PCMDMX_ERROR dmxErr = PCMDMX_OK;
@@ -1826,145 +1849,38 @@
            * predictable behavior and thus maybe produce strange output. */
           ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR;
         }
-
-        pcmLimiterScale += PCM_OUT_HEADROOM;
-
-        if (flags & AACDEC_CLRHIST) {
-          if (!(self->flags[0] & AC_USAC)) {
-            /* Reset DRC data */
-            aacDecoder_drcReset(self->hDrcInfo);
-            /* Delete the delayed signal. */
-            pcmLimiter_Reset(self->hLimiter);
-          }
-        }
-
-        /* Set applyExtGain if DRC processing is enabled and if
-           progRefLevelPresent is present for the first time. Consequences: The
-           headroom of the output signal can be set to AACDEC_DRC_GAIN_SCALING
-           only for audio formats which support legacy DRC Level Normalization.
-                         For all other audio formats the headroom of the output
-           signal is set to PCM_OUT_HEADROOM. */
-        if (self->hDrcInfo->enable &&
-            (self->hDrcInfo->progRefLevelPresent == 1)) {
-          self->hDrcInfo->applyExtGain |= 1;
-        }
-
-        /* Check whether time data buffer is large enough. */
-        if (timeDataSize <
-            (self->streamInfo.numChannels * self->streamInfo.frameSize)) {
-          ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL;
-          goto bail;
-        }
-
-        if (self->limiterEnableCurr) {
-          /* use workBufferCore2 buffer for interleaving */
-          PCM_LIM *pInterleaveBuffer;
-          int blockLength = self->streamInfo.frameSize;
-
-          /* Set actual signal parameters */
-          pcmLimiter_SetNChannels(self->hLimiter, self->streamInfo.numChannels);
-          pcmLimiter_SetSampleRate(self->hLimiter, self->streamInfo.sampleRate);
-
-          if ((self->streamInfo.numChannels == 1) || (self->sbrEnabled) ||
-              (self->mpsEnableCurr)) {
-            pInterleaveBuffer = (PCM_LIM *)pTimeData2;
-          } else {
-            pInterleaveBuffer = (PCM_LIM *)self->workBufferCore2;
-
-            /* applyLimiter requests for interleaved data */
-            /* Interleave ouput buffer */
-            FDK_interleave(pTimeData2, pInterleaveBuffer,
-                           self->streamInfo.numChannels, blockLength,
-                           self->streamInfo.frameSize);
-          }
-
-          FIXP_DBL *pGainPerSample = NULL;
-
-          if (self->hDrcInfo->enable && self->hDrcInfo->applyExtGain) {
-            pGainPerSample = self->workBufferCore1;
-
-            if ((INT)GetRequiredMemWorkBufferCore1() <
-                (INT)(self->streamInfo.frameSize * sizeof(FIXP_DBL))) {
-              ErrorStatus = AAC_DEC_UNKNOWN;
-              goto bail;
-            }
-
-            pcmLimiterScale = applyDrcLevelNormalization(
-                self->hDrcInfo, (PCM_DEC *)pInterleaveBuffer, self->extGain,
-                pGainPerSample, pcmLimiterScale, self->extGainDelay,
-                self->streamInfo.frameSize, self->streamInfo.numChannels, 1, 1);
-          }
-
-          pcmLimiter_Apply(self->hLimiter, pInterleaveBuffer, pTimeData,
-                           pGainPerSample, pcmLimiterScale,
-                           self->streamInfo.frameSize);
-
-          {
-            /* Announce the additional limiter output delay */
-            self->streamInfo.outputDelay += pcmLimiter_GetDelay(self->hLimiter);
-          }
-        } else {
-          if (self->hDrcInfo->enable && self->hDrcInfo->applyExtGain) {
-            pcmLimiterScale = applyDrcLevelNormalization(
-                self->hDrcInfo, pTimeData2, self->extGain, NULL,
-                pcmLimiterScale, self->extGainDelay, self->streamInfo.frameSize,
-                self->streamInfo.numChannels,
-                (interleaved || (self->streamInfo.numChannels == 1))
-                    ? 1
-                    : self->streamInfo.frameSize,
-                0);
-          }
-
-          /* If numChannels = 1 we do not need interleaving. The same applies if
-          SBR or MPS are used, since their output is interleaved already
-          (resampled or not) */
-          if ((self->streamInfo.numChannels == 1) || (self->sbrEnabled) ||
-              (self->mpsEnableCurr)) {
-            scaleValuesSaturate(
-                pTimeData, pTimeData2,
-                self->streamInfo.frameSize * self->streamInfo.numChannels,
-                pcmLimiterScale);
-
-          } else {
-            scaleValuesSaturate(
-                (INT_PCM *)self->workBufferCore2, pTimeData2,
-                self->streamInfo.frameSize * self->streamInfo.numChannels,
-                pcmLimiterScale);
-            /* Interleave ouput buffer */
-            FDK_interleave((INT_PCM *)self->workBufferCore2, pTimeData,
-                           self->streamInfo.numChannels,
-                           self->streamInfo.frameSize,
-                           self->streamInfo.frameSize);
-          }
-        }
-      } /* if (self->streamInfo.extAot != AOT_AAC_SLS)*/
+      }
 
       if (self->flags[0] & AC_USAC) {
         if (self->flushStatus == AACDEC_USAC_DASH_IPF_FLUSH_ON &&
             !(flags & AACDEC_CONCEAL)) {
-          CAacDecoder_PrepareCrossFade(pTimeData, self->pTimeDataFlush,
+          CAacDecoder_PrepareCrossFade(pTimeData2, self->pTimeDataFlush,
                                        self->streamInfo.numChannels,
-                                       self->streamInfo.frameSize, 1);
+                                       self->streamInfo.frameSize, interleaved);
         }
 
         /* prepare crossfade buffer for fade in */
-        if (!applyCrossfade && self->applyCrossfade &&
+        if (!applyCrossfade &&
+            (self->applyCrossfade != AACDEC_CROSSFADE_BITMASK_OFF) &&
             !(flags & AACDEC_CONCEAL)) {
           for (int ch = 0; ch < self->streamInfo.numChannels; ch++) {
             for (int i = 0; i < TIME_DATA_FLUSH_SIZE; i++) {
-              self->pTimeDataFlush[ch][i] = 0;
+              self->pTimeDataFlush[ch][i] = (PCM_DEC)0;
             }
           }
           applyCrossfade = 1;
         }
 
-        if (applyCrossfade && self->applyCrossfade &&
+        if (applyCrossfade &&
+            (self->applyCrossfade != AACDEC_CROSSFADE_BITMASK_OFF) &&
             !(accessUnit < numPrerollAU) &&
             (self->buildUpStatus == AACDEC_USAC_BUILD_UP_ON)) {
-          CAacDecoder_ApplyCrossFade(pTimeData, self->pTimeDataFlush,
+          CAacDecoder_ApplyCrossFade(pTimeData2, self->pTimeDataFlush,
                                      self->streamInfo.numChannels,
-                                     self->streamInfo.frameSize, 1);
-          self->applyCrossfade = 0;
+                                     self->streamInfo.frameSize, interleaved);
+          self->applyCrossfade =
+              AACDEC_CROSSFADE_BITMASK_OFF; /* disable cross-fade between frames
+                                               at nect config change */
         }
       }
 
@@ -2006,6 +1922,116 @@
            ((self->flushStatus == AACDEC_USAC_DASH_IPF_FLUSH_ON) &&
             !(flags & AACDEC_CONCEAL)));
 
+  if (self->streamInfo.extAot != AOT_AAC_SLS) {
+    pcmLimiterScale += PCM_OUT_HEADROOM;
+
+    if (flags & AACDEC_CLRHIST) {
+      if (!(self->flags[0] & AC_USAC)) {
+        /* Reset DRC data */
+        aacDecoder_drcReset(self->hDrcInfo);
+        /* Delete the delayed signal. */
+        pcmLimiter_Reset(self->hLimiter);
+      }
+    }
+
+    /* Set applyExtGain if DRC processing is enabled and if progRefLevelPresent
+       is present for the first time. Consequences: The headroom of the output
+       signal can be set to AACDEC_DRC_GAIN_SCALING only for audio formats which
+       support legacy DRC Level Normalization. For all other audio formats the
+       headroom of the output signal is set to PCM_OUT_HEADROOM. */
+    if (self->hDrcInfo->enable && (self->hDrcInfo->progRefLevelPresent == 1)) {
+      self->hDrcInfo->applyExtGain |= 1;
+    }
+
+    /* Check whether time data buffer is large enough. */
+    if (timeDataSize <
+        (self->streamInfo.numChannels * self->streamInfo.frameSize)) {
+      ErrorStatus = AAC_DEC_OUTPUT_BUFFER_TOO_SMALL;
+      goto bail;
+    }
+
+    if (self->limiterEnableCurr) {
+      /* use workBufferCore2 buffer for interleaving */
+      PCM_LIM *pInterleaveBuffer;
+      int blockLength = self->streamInfo.frameSize;
+
+      /* Set actual signal parameters */
+      pcmLimiter_SetNChannels(self->hLimiter, self->streamInfo.numChannels);
+      pcmLimiter_SetSampleRate(self->hLimiter, self->streamInfo.sampleRate);
+
+      if ((self->streamInfo.numChannels == 1) || (self->sbrEnabled) ||
+          (self->mpsEnableCurr)) {
+        pInterleaveBuffer = (PCM_LIM *)pTimeData2;
+      } else {
+        pInterleaveBuffer = (PCM_LIM *)self->workBufferCore2;
+
+        /* applyLimiter requests for interleaved data */
+        /* Interleave ouput buffer */
+        FDK_interleave(pTimeData2, pInterleaveBuffer,
+                       self->streamInfo.numChannels, blockLength,
+                       self->streamInfo.frameSize);
+      }
+
+      FIXP_DBL *pGainPerSample = NULL;
+
+      if (self->hDrcInfo->enable && self->hDrcInfo->applyExtGain) {
+        pGainPerSample = self->workBufferCore1;
+
+        if ((INT)GetRequiredMemWorkBufferCore1() <
+            (INT)(self->streamInfo.frameSize * sizeof(FIXP_DBL))) {
+          ErrorStatus = AAC_DEC_UNKNOWN;
+          goto bail;
+        }
+
+        pcmLimiterScale = applyDrcLevelNormalization(
+            self->hDrcInfo, (PCM_DEC *)pInterleaveBuffer, self->extGain,
+            pGainPerSample, pcmLimiterScale, self->extGainDelay,
+            self->streamInfo.frameSize, self->streamInfo.numChannels, 1, 1);
+      }
+
+      pcmLimiter_Apply(self->hLimiter, pInterleaveBuffer, pTimeData,
+                       pGainPerSample, pcmLimiterScale,
+                       self->streamInfo.frameSize);
+
+      {
+        /* Announce the additional limiter output delay */
+        self->streamInfo.outputDelay += pcmLimiter_GetDelay(self->hLimiter);
+      }
+    } else {
+      if (self->hDrcInfo->enable && self->hDrcInfo->applyExtGain) {
+        pcmLimiterScale = applyDrcLevelNormalization(
+            self->hDrcInfo, pTimeData2, self->extGain, NULL, pcmLimiterScale,
+            self->extGainDelay, self->streamInfo.frameSize,
+            self->streamInfo.numChannels,
+            (interleaved || (self->streamInfo.numChannels == 1))
+                ? 1
+                : self->streamInfo.frameSize,
+            0);
+      }
+
+      /* If numChannels = 1 we do not need interleaving. The same applies if SBR
+      or MPS are used, since their output is interleaved already (resampled or
+      not) */
+      if ((self->streamInfo.numChannels == 1) || (self->sbrEnabled) ||
+          (self->mpsEnableCurr)) {
+        scaleValuesSaturate(
+            pTimeData, pTimeData2,
+            self->streamInfo.frameSize * self->streamInfo.numChannels,
+            pcmLimiterScale);
+
+      } else {
+        scaleValuesSaturate(
+            (INT_PCM *)self->workBufferCore2, pTimeData2,
+            self->streamInfo.frameSize * self->streamInfo.numChannels,
+            pcmLimiterScale);
+        /* Interleave ouput buffer */
+        FDK_interleave((INT_PCM *)self->workBufferCore2, pTimeData,
+                       self->streamInfo.numChannels, self->streamInfo.frameSize,
+                       self->streamInfo.frameSize);
+      }
+    }
+  } /* if (self->streamInfo.extAot != AOT_AAC_SLS)*/
+
 bail:
 
   /* error in renderer part occurred, ErrorStatus was set to invalid output */
diff --git a/libAACdec/src/channel.cpp b/libAACdec/src/channel.cpp
index a020034..7e62bfb 100644
--- a/libAACdec/src/channel.cpp
+++ b/libAACdec/src/channel.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -265,7 +265,9 @@
          stereo prediction since scaling has already been carried out. */
       int max_sfb_ste = (INT)(pAacDecoderChannelInfo[L]->icsInfo.max_sfb_ste);
 
-      if ((!CP_active) || (CP_active && (max_sfb_ste < noSfbs)) ||
+      if (!(CP_active && (max_sfb_ste == noSfbs)) ||
+          !(CP_active &&
+            !(pAacDecoderChannelInfo[ch]->pDynData->TnsData.Active)) ||
           ((flags & (AC_USAC | AC_RSVD50 | AC_RSV603DA)) &&
            (pAacDecoderChannelInfo[L]->pDynData->specificTo.usac.tns_on_lr ==
             0))) {
diff --git a/libAACdec/src/rvlc.cpp b/libAACdec/src/rvlc.cpp
index b7a9be1..0b80364 100644
--- a/libAACdec/src/rvlc.cpp
+++ b/libAACdec/src/rvlc.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -628,7 +628,7 @@
 
   SHORT *pScfBwd = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd;
   SHORT *pScfEsc = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfEsc;
-  UCHAR *pEscEscCnt = &(pRvlc->numDecodedEscapeWordsEsc);
+  UCHAR escEscCnt = pRvlc->numDecodedEscapeWordsEsc;
   UCHAR *pEscBwdCnt = &(pRvlc->numDecodedEscapeWordsBwd);
 
   pRvlc->pRvlBitCnt_RVL = &(pRvlc->length_of_rvlc_sf_bwd);
@@ -636,7 +636,7 @@
 
   *pEscBwdCnt = 0;
   pRvlc->direction = BWD;
-  pScfEsc += *pEscEscCnt - 1; /* set pScfEsc to last entry */
+  pScfEsc += escEscCnt - 1; /* set pScfEsc to last entry */
   pRvlc->firstScf = 0;
   pRvlc->firstNrg = 0;
   pRvlc->firstIs = 0;
@@ -651,7 +651,7 @@
     }
     dpcm -= TABLE_OFFSET;
     if ((dpcm == MIN_RVL) || (dpcm == MAX_RVL)) {
-      if (pRvlc->length_of_rvlc_escapes) {
+      if ((pRvlc->length_of_rvlc_escapes) || (*pEscBwdCnt >= escEscCnt)) {
         pRvlc->conceal_min = bnds;
         return;
       } else {
@@ -694,7 +694,7 @@
           }
           dpcm -= TABLE_OFFSET;
           if ((dpcm == MIN_RVL) || (dpcm == MAX_RVL)) {
-            if (pRvlc->length_of_rvlc_escapes) {
+            if ((pRvlc->length_of_rvlc_escapes) || (*pEscBwdCnt >= escEscCnt)) {
               pScfBwd[bnds] = position;
               pRvlc->conceal_min = fMax(0, bnds - offset);
               return;
@@ -731,7 +731,8 @@
             }
             dpcm -= TABLE_OFFSET;
             if ((dpcm == MIN_RVL) || (dpcm == MAX_RVL)) {
-              if (pRvlc->length_of_rvlc_escapes) {
+              if ((pRvlc->length_of_rvlc_escapes) ||
+                  (*pEscBwdCnt >= escEscCnt)) {
                 pScfBwd[bnds] = noisenrg;
                 pRvlc->conceal_min = fMax(0, bnds - offset);
                 return;
@@ -762,7 +763,7 @@
           }
           dpcm -= TABLE_OFFSET;
           if ((dpcm == MIN_RVL) || (dpcm == MAX_RVL)) {
-            if (pRvlc->length_of_rvlc_escapes) {
+            if ((pRvlc->length_of_rvlc_escapes) || (*pEscBwdCnt >= escEscCnt)) {
               pScfBwd[bnds] = factor;
               pRvlc->conceal_min = fMax(0, bnds - offset);
               return;
diff --git a/libAACdec/src/usacdec_acelp.cpp b/libAACdec/src/usacdec_acelp.cpp
index a8dadc0..ca1a6a2 100644
--- a/libAACdec/src/usacdec_acelp.cpp
+++ b/libAACdec/src/usacdec_acelp.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -719,7 +719,7 @@
   UCHAR *pold_T0_frac = &acelp_mem->old_T0_frac;
 
   if ((int)*pold_T0 >= PIT_MAX) {
-    *pold_T0 = (UCHAR)(PIT_MAX - 5);
+    *pold_T0 = (USHORT)(PIT_MAX - 5);
   }
   *pT0 = (int)*pold_T0;
   *pT0_frac = (int)*pold_T0_frac;
diff --git a/libAACenc/include/aacenc_lib.h b/libAACenc/include/aacenc_lib.h
index 71f7556..f0f23b4 100644
--- a/libAACenc/include/aacenc_lib.h
+++ b/libAACenc/include/aacenc_lib.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -1643,7 +1643,7 @@
  *
  * \return
  *          - AACENC_OK, on succes.
- *          - AACENC_INIT_ERROR, on failure.
+ *          - AACENC_INVALID_HANDLE, AACENC_INIT_ERROR, on failure.
  */
 AACENC_ERROR aacEncInfo(const HANDLE_AACENCODER hAacEncoder,
                         AACENC_InfoStruct *pInfo);
diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp
index 0ae329b..c11db27 100644
--- a/libAACenc/src/aacenc_lib.cpp
+++ b/libAACenc/src/aacenc_lib.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -1242,7 +1242,7 @@
 INT aacenc_SscCallback(void *self, HANDLE_FDK_BITSTREAM hBs,
                        const AUDIO_OBJECT_TYPE coreCodec,
                        const INT samplingRate, const INT frameSize,
-                       const INT stereoConfigIndex,
+                       const INT numChannels, const INT stereoConfigIndex,
                        const INT coreSbrFrameLengthIndex, const INT configBytes,
                        const UCHAR configMode, UCHAR *configChanged) {
   HANDLE_AACENCODER hAacEncoder = (HANDLE_AACENCODER)self;
@@ -1784,8 +1784,8 @@
                                                    hAacEncoder->nSamplesRead));
     INT_PCM *pIn =
         hAacEncoder->inputBuffer +
-        (hAacEncoder->inputBufferOffset + hAacEncoder->nSamplesRead) /
-            hAacEncoder->aacConfig.nChannels;
+        hAacEncoder->inputBufferOffset / hAacEncoder->aacConfig.nChannels +
+        hAacEncoder->nSamplesRead / hAacEncoder->extParam.nChannels;
     newSamples -=
         (newSamples %
          hAacEncoder->extParam
@@ -1827,12 +1827,13 @@
 
         /* clear out until end-of-buffer */
         if (nZeros) {
+          INT_PCM *pIn =
+              hAacEncoder->inputBuffer +
+              hAacEncoder->inputBufferOffset /
+                  hAacEncoder->aacConfig.nChannels +
+              hAacEncoder->nSamplesRead / hAacEncoder->extParam.nChannels;
           for (i = 0; i < (int)hAacEncoder->extParam.nChannels; i++) {
-            FDKmemclear(hAacEncoder->inputBuffer +
-                            i * hAacEncoder->inputBufferSizePerChannel +
-                            (hAacEncoder->inputBufferOffset +
-                             hAacEncoder->nSamplesRead) /
-                                hAacEncoder->extParam.nChannels,
+            FDKmemclear(pIn + i * hAacEncoder->inputBufferSizePerChannel,
                         sizeof(INT_PCM) * nZeros);
           }
           hAacEncoder->nZerosAppended += nZeros;
@@ -2520,6 +2521,11 @@
                         AACENC_InfoStruct *pInfo) {
   AACENC_ERROR err = AACENC_OK;
 
+  if ((hAacEncoder == NULL) || (pInfo == NULL)) {
+    err = AACENC_INVALID_HANDLE;
+    goto bail;
+  }
+
   FDKmemclear(pInfo, sizeof(AACENC_InfoStruct));
   pInfo->confSize = 64; /* pre-initialize */
 
diff --git a/libDRCdec/src/drcDec_reader.cpp b/libDRCdec/src/drcDec_reader.cpp
index 367a352..b080f50 100644
--- a/libDRCdec/src/drcDec_reader.cpp
+++ b/libDRCdec/src/drcDec_reader.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -512,10 +512,13 @@
               fMin(tmpNNodes, (UCHAR)16) * sizeof(GAIN_NODE));
   }
 
-  hUniDrcGain->uniDrcGainExtPresent = FDKreadBits(hBs, 1);
-  if (hUniDrcGain->uniDrcGainExtPresent == 1) {
-    err = _readUniDrcGainExtension(hBs, &(hUniDrcGain->uniDrcGainExtension));
-    if (err) return err;
+  if (pCoef && (gainSequenceCount ==
+                pCoef->gainSequenceCount)) { /* all sequences have been read */
+    hUniDrcGain->uniDrcGainExtPresent = FDKreadBits(hBs, 1);
+    if (hUniDrcGain->uniDrcGainExtPresent == 1) {
+      err = _readUniDrcGainExtension(hBs, &(hUniDrcGain->uniDrcGainExtension));
+      if (err) return err;
+    }
   }
 
   if (err == DE_OK && gainSequenceCount > 0) {
@@ -914,7 +917,7 @@
       firFilterOrder;
   int uniqueEqSubbandGainsCount, eqSubbandGainRepresentation,
       eqSubbandGainCount;
-  EQ_SUBBAND_GAIN_FORMAT eqSubbandGainFormat;
+  int eqSubbandGainFormat;
 
   eqDelayMaxPresent = FDKreadBits(hBs, 1);
   if (eqDelayMaxPresent) {
@@ -955,7 +958,7 @@
   uniqueEqSubbandGainsCount = FDKreadBits(hBs, 6);
   if (uniqueEqSubbandGainsCount > 0) {
     eqSubbandGainRepresentation = FDKreadBits(hBs, 1);
-    eqSubbandGainFormat = (EQ_SUBBAND_GAIN_FORMAT)FDKreadBits(hBs, 4);
+    eqSubbandGainFormat = FDKreadBits(hBs, 4);
     switch (eqSubbandGainFormat) {
       case GF_QMF32:
         eqSubbandGainCount = 32;
diff --git a/libFDK/include/nlc_dec.h b/libFDK/include/nlc_dec.h
index cca97f1..aded569 100644
--- a/libFDK/include/nlc_dec.h
+++ b/libFDK/include/nlc_dec.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -159,9 +159,6 @@
 #ifndef HUFFDEC_PARAMS
 #define HUFFDEC_PARMS
 
-#define PAIR_SHIFT 4
-#define PAIR_MASK 0xf
-
 #define MAX_ENTRIES 168
 #define HANDLE_HUFF_NODE const SHORT(*)[MAX_ENTRIES][2]
 
diff --git a/libFDK/src/FDK_hybrid.cpp b/libFDK/src/FDK_hybrid.cpp
index 08d32a8..d208abd 100644
--- a/libFDK/src/FDK_hybrid.cpp
+++ b/libFDK/src/FDK_hybrid.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -539,11 +539,11 @@
   i6 = pQmfImag[pReadIdx[6]] >> 2;
 
   FDK_ASSERT((invert == 0) || (invert == 1));
-  mHybridReal[0 + invert] = (r6 + r1) << 1;
-  mHybridImag[0 + invert] = (i6 + i1) << 1;
+  mHybridReal[0 + invert] = SATURATE_LEFT_SHIFT((r6 + r1), 1, DFRACT_BITS);
+  mHybridImag[0 + invert] = SATURATE_LEFT_SHIFT((i6 + i1), 1, DFRACT_BITS);
 
-  mHybridReal[1 - invert] = (r6 - r1) << 1;
-  mHybridImag[1 - invert] = (i6 - i1) << 1;
+  mHybridReal[1 - invert] = SATURATE_LEFT_SHIFT((r6 - r1), 1, DFRACT_BITS);
+  mHybridImag[1 - invert] = SATURATE_LEFT_SHIFT((i6 - i1), 1, DFRACT_BITS);
 }
 
 static void fourChannelFiltering(const FIXP_DBL *const pQmfReal,
@@ -766,15 +766,15 @@
     mHybridReal[3] = pfft[FFT_IDX_R(1)] << sc;
     mHybridImag[3] = pfft[FFT_IDX_I(1)] << sc;
 
-    mHybridReal[4] = pfft[FFT_IDX_R(2)] << sc;
-    mHybridReal[4] += pfft[FFT_IDX_R(5)] << sc;
-    mHybridImag[4] = pfft[FFT_IDX_I(2)] << sc;
-    mHybridImag[4] += pfft[FFT_IDX_I(5)] << sc;
+    mHybridReal[4] = SATURATE_LEFT_SHIFT(
+        (pfft[FFT_IDX_R(2)] + pfft[FFT_IDX_R(5)]), sc, DFRACT_BITS);
+    mHybridImag[4] = SATURATE_LEFT_SHIFT(
+        (pfft[FFT_IDX_I(2)] + pfft[FFT_IDX_I(5)]), sc, DFRACT_BITS);
 
-    mHybridReal[5] = pfft[FFT_IDX_R(3)] << sc;
-    mHybridReal[5] += pfft[FFT_IDX_R(4)] << sc;
-    mHybridImag[5] = pfft[FFT_IDX_I(3)] << sc;
-    mHybridImag[5] += pfft[FFT_IDX_I(4)] << sc;
+    mHybridReal[5] = SATURATE_LEFT_SHIFT(
+        (pfft[FFT_IDX_R(3)] + pfft[FFT_IDX_R(4)]), sc, DFRACT_BITS);
+    mHybridImag[5] = SATURATE_LEFT_SHIFT(
+        (pfft[FFT_IDX_I(3)] + pfft[FFT_IDX_I(4)]), sc, DFRACT_BITS);
   } else {
     for (k = 0; k < 8; k++) {
       mHybridReal[k] = pfft[FFT_IDX_R(k)] << sc;
diff --git a/libFDK/src/autocorr2nd.cpp b/libFDK/src/autocorr2nd.cpp
index 718a555..8c5673c 100644
--- a/libFDK/src/autocorr2nd.cpp
+++ b/libFDK/src/autocorr2nd.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -102,11 +102,6 @@
 
 #include "autocorr2nd.h"
 
-/*  If the accumulator does not provide enough overflow bits,
-    products have to be shifted down in the autocorrelation below. */
-#define SHIFT_FACTOR (5)
-#define SHIFT >> (SHIFT_FACTOR)
-
 /*!
  *
  * \brief Calculate second order autocorrelation using 2 accumulators
@@ -126,45 +121,49 @@
 
   const FIXP_DBL *realBuf = reBuffer;
 
+  const int len_scale = fMax(DFRACT_BITS - fNormz((FIXP_DBL)(len / 2)), 1);
   /*
     r11r,r22r
     r01r,r12r
     r02r
   */
   pReBuf = realBuf - 2;
-  accu5 = ((fMultDiv2(pReBuf[0], pReBuf[2]) + fMultDiv2(pReBuf[1], pReBuf[3]))
-               SHIFT);
+  accu5 =
+      ((fMultDiv2(pReBuf[0], pReBuf[2]) + fMultDiv2(pReBuf[1], pReBuf[3])) >>
+       len_scale);
   pReBuf++;
 
   /* len must be even */
-  accu1 = fPow2Div2(pReBuf[0]) SHIFT;
-  accu3 = fMultDiv2(pReBuf[0], pReBuf[1]) SHIFT;
+  accu1 = fPow2Div2(pReBuf[0]) >> len_scale;
+  accu3 = fMultDiv2(pReBuf[0], pReBuf[1]) >> len_scale;
   pReBuf++;
 
   for (j = (len - 2) >> 1; j != 0; j--, pReBuf += 2) {
-    accu1 += ((fPow2Div2(pReBuf[0]) + fPow2Div2(pReBuf[1])) SHIFT);
+    accu1 += ((fPow2Div2(pReBuf[0]) + fPow2Div2(pReBuf[1])) >> len_scale);
 
-    accu3 += ((fMultDiv2(pReBuf[0], pReBuf[1]) +
-               fMultDiv2(pReBuf[1], pReBuf[2])) SHIFT);
+    accu3 +=
+        ((fMultDiv2(pReBuf[0], pReBuf[1]) + fMultDiv2(pReBuf[1], pReBuf[2])) >>
+         len_scale);
 
-    accu5 += ((fMultDiv2(pReBuf[0], pReBuf[2]) +
-               fMultDiv2(pReBuf[1], pReBuf[3])) SHIFT);
+    accu5 +=
+        ((fMultDiv2(pReBuf[0], pReBuf[2]) + fMultDiv2(pReBuf[1], pReBuf[3])) >>
+         len_scale);
   }
 
-  accu2 = (fPow2Div2(realBuf[-2]) SHIFT);
+  accu2 = (fPow2Div2(realBuf[-2]) >> len_scale);
   accu2 += accu1;
 
-  accu1 += (fPow2Div2(realBuf[len - 2]) SHIFT);
+  accu1 += (fPow2Div2(realBuf[len - 2]) >> len_scale);
 
-  accu4 = (fMultDiv2(realBuf[-1], realBuf[-2]) SHIFT);
+  accu4 = (fMultDiv2(realBuf[-1], realBuf[-2]) >> len_scale);
   accu4 += accu3;
 
-  accu3 += (fMultDiv2(realBuf[len - 1], realBuf[len - 2]) SHIFT);
+  accu3 += (fMultDiv2(realBuf[len - 1], realBuf[len - 2]) >> len_scale);
 
   mScale = CntLeadingZeros(
                (accu1 | accu2 | fAbs(accu3) | fAbs(accu4) | fAbs(accu5))) -
            1;
-  autoCorrScaling = mScale - 1 - SHIFT_FACTOR; /* -1 because of fMultDiv2*/
+  autoCorrScaling = mScale - 1 - len_scale; /* -1 because of fMultDiv2*/
 
   /* Scale to common scale factor */
   ac->r11r = accu1 << mScale;
@@ -190,7 +189,7 @@
     const FIXP_DBL *imBuffer, /*!< Pointer to imag part of input samples */
     const int len /*!< Number of input samples (should be smaller than 128) */
 ) {
-  int j, autoCorrScaling, mScale, len_scale;
+  int j, autoCorrScaling, mScale;
 
   FIXP_DBL accu0, accu1, accu2, accu3, accu4, accu5, accu6, accu7, accu8;
 
@@ -199,7 +198,7 @@
   const FIXP_DBL *realBuf = reBuffer;
   const FIXP_DBL *imagBuf = imBuffer;
 
-  (len > 64) ? (len_scale = 6) : (len_scale = 5);
+  const int len_scale = fMax(DFRACT_BITS - fNormz((FIXP_DBL)len), 1);
   /*
     r00r,
     r11r,r22r
diff --git a/libFDK/src/dct.cpp b/libFDK/src/dct.cpp
index bd26736..35507b5 100644
--- a/libFDK/src/dct.cpp
+++ b/libFDK/src/dct.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -305,9 +305,8 @@
 
   {
     for (i = 0; i < M; i++) {
-      tmp[i] = pDat[2 * i] >> 1; /* dit_fft expects 1 bit scaled input values */
-      tmp[L - 1 - i] =
-          pDat[2 * i + 1] >> 1; /* dit_fft expects 1 bit scaled input values */
+      tmp[i] = pDat[2 * i] >> 2;
+      tmp[L - 1 - i] = pDat[2 * i + 1] >> 2;
     }
   }
 
@@ -337,15 +336,14 @@
     a1 = ((pTmp_0[0] >> 1) + (pTmp_1[0] >> 1));
     a2 = ((pTmp_0[1] >> 1) - (pTmp_1[1] >> 1));
 
-    cplxMultDiv2(&accu3, &accu4, (a1 + accu2), -(accu1 + a2),
-                 sin_twiddle[i * inc]);
-    pDat[L - i] = accu4;
-    pDat[i] = accu3;
+    cplxMult(&accu3, &accu4, (accu1 + a2), (a1 + accu2), sin_twiddle[i * inc]);
+    pDat[L - i] = -accu3;
+    pDat[i] = accu4;
 
-    cplxMultDiv2(&accu3, &accu4, (a1 - accu2), -(accu1 - a2),
-                 sin_twiddle[(M - i) * inc]);
-    pDat[M + i] = accu4;
-    pDat[M - i] = accu3;
+    cplxMult(&accu3, &accu4, (accu1 - a2), (a1 - accu2),
+             sin_twiddle[(M - i) * inc]);
+    pDat[M + i] = -accu3;
+    pDat[M - i] = accu4;
 
     /* Create index helper variables for (4*i)*inc indexed equivalent values of
      * short tables. */
@@ -356,12 +354,12 @@
     }
   }
 
-  cplxMultDiv2(&accu1, &accu2, tmp[M], tmp[M + 1], sin_twiddle[(M / 2) * inc]);
+  cplxMult(&accu1, &accu2, tmp[M], tmp[M + 1], sin_twiddle[(M / 2) * inc]);
   pDat[L - (M / 2)] = accu2;
   pDat[M / 2] = accu1;
 
-  pDat[0] = (tmp[0] >> 1) + (tmp[1] >> 1);
-  pDat[M] = fMult(((tmp[0] >> 1) - (tmp[1] >> 1)),
+  pDat[0] = tmp[0] + tmp[1];
+  pDat[M] = fMult(tmp[0] - tmp[1],
                   sin_twiddle[M * inc].v.re); /* cos((PI/(2*L))*M); */
 
   *pDat_e += 2;
diff --git a/libFDK/src/nlc_dec.cpp b/libFDK/src/nlc_dec.cpp
index 6e98ce0..3733d98 100644
--- a/libFDK/src/nlc_dec.cpp
+++ b/libFDK/src/nlc_dec.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -568,12 +568,12 @@
 static ERROR_t huff_decode(HANDLE_FDK_BITSTREAM strm, SCHAR* out_data_1,
                            SCHAR* out_data_2, DATA_TYPE data_type,
                            DIFF_TYPE diff_type_1, DIFF_TYPE diff_type_2,
-                           int num_val, CODING_SCHEME* cdg_scheme, int ldMode) {
+                           int num_val, PAIRING* pairing_scheme, int ldMode) {
   ERROR_t err = HUFFDEC_OK;
+  CODING_SCHEME coding_scheme = HUFF_1D;
   DIFF_TYPE diff_type;
 
   int i = 0;
-  ULONG data = 0;
 
   SCHAR pair_vec[28][2];
 
@@ -596,15 +596,13 @@
   int hufYY;
 
   /* Coding scheme */
-  data = FDKreadBits(strm, 1);
-  *cdg_scheme = (CODING_SCHEME)(data << PAIR_SHIFT);
+  coding_scheme = (CODING_SCHEME)FDKreadBits(strm, 1);
 
-  if (*cdg_scheme >> PAIR_SHIFT == HUFF_2D) {
+  if (coding_scheme == HUFF_2D) {
     if ((out_data_1 != NULL) && (out_data_2 != NULL) && (ldMode == 0)) {
-      data = FDKreadBits(strm, 1);
-      *cdg_scheme = (CODING_SCHEME)(*cdg_scheme | data);
+      *pairing_scheme = (PAIRING)FDKreadBits(strm, 1);
     } else {
-      *cdg_scheme = (CODING_SCHEME)(*cdg_scheme | FREQ_PAIR);
+      *pairing_scheme = FREQ_PAIR;
     }
   }
 
@@ -613,7 +611,7 @@
     hufYY2 = diff_type_2;
   }
 
-  switch (*cdg_scheme >> PAIR_SHIFT) {
+  switch (coding_scheme) {
     case HUFF_1D:
       p0_flag[0] = (diff_type_1 == DIFF_FREQ);
       p0_flag[1] = (diff_type_2 == DIFF_FREQ);
@@ -634,7 +632,7 @@
 
     case HUFF_2D:
 
-      switch (*cdg_scheme & PAIR_MASK) {
+      switch (*pairing_scheme) {
         case FREQ_PAIR:
 
           if (out_data_1 != NULL) {
@@ -843,7 +841,7 @@
   SCHAR* pDataVec[2] = {NULL, NULL};
 
   DIFF_TYPE diff_type[2] = {DIFF_FREQ, DIFF_FREQ};
-  CODING_SCHEME cdg_scheme = HUFF_1D;
+  PAIRING pairing = FREQ_PAIR;
   DIRECTION direction = BACKWARDS;
 
   switch (data_type) {
@@ -959,7 +957,7 @@
     }
     /* Huffman decoding */
     err = huff_decode(strm, pDataVec[0], pDataVec[1], data_type, diff_type[0],
-                      diff_type[1], dataBands, &cdg_scheme,
+                      diff_type[1], dataBands, &pairing,
                       (DECODER == SAOC_DECODER));
     if (err != HUFFDEC_OK) {
       return HUFFDEC_NOTOK;
@@ -986,8 +984,8 @@
         }
       }
 
-      mixed_time_pair = (diff_type[0] != diff_type[1]) &&
-                        ((cdg_scheme & PAIR_MASK) == TIME_PAIR);
+      mixed_time_pair =
+          (diff_type[0] != diff_type[1]) && (pairing == TIME_PAIR);
 
       if (direction == BACKWARDS) {
         if (diff_type[0] == DIFF_FREQ) {
diff --git a/libMpegTPDec/include/tp_data.h b/libMpegTPDec/include/tp_data.h
index b015332..b63087a 100644
--- a/libMpegTPDec/include/tp_data.h
+++ b/libMpegTPDec/include/tp_data.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -368,7 +368,7 @@
 typedef INT (*cbSsc_t)(void *, HANDLE_FDK_BITSTREAM,
                        const AUDIO_OBJECT_TYPE coreCodec,
                        const INT samplingRate, const INT frameSize,
-                       const INT stereoConfigIndex,
+                       const INT numChannels, const INT stereoConfigIndex,
                        const INT coreSbrFrameLengthIndex, const INT configBytes,
                        const UCHAR configMode, UCHAR *configChanged);
 
diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp
index 82f840e..8f77017 100644
--- a/libMpegTPDec/src/tpdec_asc.cpp
+++ b/libMpegTPDec/src/tpdec_asc.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -266,11 +266,118 @@
   return (err);
 }
 
+/**
+ * \brief Sanity checks for program config element.
+ *        Check order of elements according to ISO/IEC 13818-7:2003(E),
+ * chapter 8.5.1
+ *
+ * \param pPce  pointer to program config element.
+ *
+ * \return  0 if successful, otherwise 1.
+ */
+static int CProgramConfig_Check(CProgramConfig *pPce) {
+  INT i;
+  INT err = 0;
+  INT numBackChannels[3] = {0};
+  INT numSideChannels[3] = {0};
+  INT numFrontChannels[3] = {0};
+  UCHAR *pCpeFront = pPce->FrontElementIsCpe;
+  UCHAR *pCpeSide = pPce->SideElementIsCpe;
+  UCHAR *pCpeBack = pPce->BackElementIsCpe;
+  UCHAR *pHeight;
+
+  pHeight = pPce->BackElementHeightInfo;
+  for (i = 0; i < pPce->NumBackChannelElements; i++) {
+    numBackChannels[*pHeight] += pPce->BackElementIsCpe[i] ? 2 : 1;
+    pHeight++;
+  }
+  pHeight = pPce->SideElementHeightInfo;
+  for (i = 0; i < pPce->NumSideChannelElements; i++) {
+    numSideChannels[*pHeight] += pPce->SideElementIsCpe[i] ? 2 : 1;
+    pHeight++;
+  }
+  pHeight = pPce->FrontElementHeightInfo;
+  for (i = 0; i < pPce->NumFrontChannelElements; i++) {
+    numFrontChannels[*pHeight] += pPce->FrontElementIsCpe[i] ? 2 : 1;
+    pHeight++;
+  }
+
+  /* 0 = normal height channels, 1 = top height channels, 2 = bottom height
+   * channels */
+  for (i = 0; i < 3; i++) {
+    /* if number of channels is odd => first element must be a SCE (front center
+     * channel) */
+    if (numFrontChannels[i] & 1) {
+      if (*pCpeFront++ == ID_CPE) {
+        err = 1;
+        goto bail;
+      }
+      numFrontChannels[i]--;
+    }
+    while (numFrontChannels[i] > 0) {
+      /* must be CPE or paired SCE */
+      if (*pCpeFront++ == ID_SCE) {
+        if (*pCpeFront++ == ID_CPE) {
+          err = 1;
+          goto bail;
+        }
+      }
+      numFrontChannels[i] -= 2;
+    };
+
+    /* in case that a top center surround channel (Ts) is transmitted the number
+     * of channels can be odd */
+    if (i != 1) {
+      /* number of channels must be even */
+      if (numSideChannels[i] & 1) {
+        err = 1;
+        goto bail;
+      }
+      while (numSideChannels[i] > 0) {
+        /* must be CPE or paired SCE */
+        if (*pCpeSide++ == ID_SCE) {
+          if (*pCpeSide++ == ID_CPE) {
+            err = 1;
+            goto bail;
+          }
+        }
+        numSideChannels[i] -= 2;
+      };
+    }
+
+    while (numBackChannels[i] > 1) {
+      /* must be CPE or paired SCE */
+      if (*pCpeBack++ == ID_SCE) {
+        if (*pCpeBack++ == ID_CPE) {
+          err = 1;
+          goto bail;
+        }
+      }
+      numBackChannels[i] -= 2;
+    };
+    /* if number of channels is odd => last element must be a SCE (back center
+     * channel) */
+    if (numBackChannels[i]) {
+      if (*pCpeBack++ == ID_CPE) {
+        err = 1;
+        goto bail;
+      }
+    }
+  }
+
+bail:
+
+  return err;
+}
+
 void CProgramConfig_Read(CProgramConfig *pPce, HANDLE_FDK_BITSTREAM bs,
                          UINT alignmentAnchor) {
-  int i, err = 0;
+  int i;
   int commentBytes;
+  UCHAR tag, isCpe;
+  UCHAR checkElementTagSelect[3][PC_FSB_CHANNELS_MAX] = {{0}};
 
+  pPce->isValid = 1;
   pPce->NumEffectiveChannels = 0;
   pPce->NumChannels = 0;
   pPce->ElementInstanceTag = (UCHAR)FDKreadBits(bs, 4);
@@ -297,28 +404,60 @@
   }
 
   for (i = 0; i < pPce->NumFrontChannelElements; i++) {
-    pPce->FrontElementIsCpe[i] = (UCHAR)FDKreadBits(bs, 1);
-    pPce->FrontElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4);
+    pPce->FrontElementIsCpe[i] = isCpe = (UCHAR)FDKreadBits(bs, 1);
+    pPce->FrontElementTagSelect[i] = tag = (UCHAR)FDKreadBits(bs, 4);
     pPce->NumChannels += pPce->FrontElementIsCpe[i] ? 2 : 1;
+
+    /* Check element instance tag according to ISO/IEC 13818-7:2003(E),
+     * chapter 8.2.1.1 */
+    if (checkElementTagSelect[isCpe][tag] == 0) {
+      checkElementTagSelect[isCpe][tag] = 1;
+    } else {
+      pPce->isValid = 0;
+    }
   }
 
   for (i = 0; i < pPce->NumSideChannelElements; i++) {
-    pPce->SideElementIsCpe[i] = (UCHAR)FDKreadBits(bs, 1);
-    pPce->SideElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4);
+    pPce->SideElementIsCpe[i] = isCpe = (UCHAR)FDKreadBits(bs, 1);
+    pPce->SideElementTagSelect[i] = tag = (UCHAR)FDKreadBits(bs, 4);
     pPce->NumChannels += pPce->SideElementIsCpe[i] ? 2 : 1;
+
+    /* Check element instance tag according to ISO/IEC 13818-7:2003(E),
+     * chapter 8.2.1.1 */
+    if (checkElementTagSelect[isCpe][tag] == 0) {
+      checkElementTagSelect[isCpe][tag] = 1;
+    } else {
+      pPce->isValid = 0;
+    }
   }
 
   for (i = 0; i < pPce->NumBackChannelElements; i++) {
-    pPce->BackElementIsCpe[i] = (UCHAR)FDKreadBits(bs, 1);
-    pPce->BackElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4);
+    pPce->BackElementIsCpe[i] = isCpe = (UCHAR)FDKreadBits(bs, 1);
+    pPce->BackElementTagSelect[i] = tag = (UCHAR)FDKreadBits(bs, 4);
     pPce->NumChannels += pPce->BackElementIsCpe[i] ? 2 : 1;
+
+    /* Check element instance tag according to ISO/IEC 13818-7:2003(E),
+     * chapter 8.2.1.1 */
+    if (checkElementTagSelect[isCpe][tag] == 0) {
+      checkElementTagSelect[isCpe][tag] = 1;
+    } else {
+      pPce->isValid = 0;
+    }
   }
 
   pPce->NumEffectiveChannels = pPce->NumChannels;
 
   for (i = 0; i < pPce->NumLfeChannelElements; i++) {
-    pPce->LfeElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4);
+    pPce->LfeElementTagSelect[i] = tag = (UCHAR)FDKreadBits(bs, 4);
     pPce->NumChannels += 1;
+
+    /* Check element instance tag according to ISO/IEC 13818-7:2003(E),
+     * chapter 8.2.1.1 */
+    if (checkElementTagSelect[2][tag] == 0) {
+      checkElementTagSelect[2][tag] = 1;
+    } else {
+      pPce->isValid = 0;
+    }
   }
 
   for (i = 0; i < pPce->NumAssocDataElements; i++) {
@@ -336,7 +475,15 @@
   commentBytes = pPce->CommentFieldBytes;
 
   /* Search for height info extension and read it if available */
-  err = CProgramConfig_ReadHeightExt(pPce, bs, &commentBytes, alignmentAnchor);
+  if (CProgramConfig_ReadHeightExt(pPce, bs, &commentBytes, alignmentAnchor)) {
+    pPce->isValid = 0;
+  }
+
+  /* Check order of elements according to ISO / IEC 13818 - 7:2003(E),
+   * chapter 8.5.1 */
+  if (CProgramConfig_Check(pPce)) {
+    pPce->isValid = 0;
+  }
 
   for (i = 0; i < commentBytes; i++) {
     UCHAR text;
@@ -347,8 +494,6 @@
       pPce->Comment[i] = text;
     }
   }
-
-  pPce->isValid = (err) ? 0 : 1;
 }
 
 /*
@@ -1415,7 +1560,7 @@
               cb->cbSscData, hBs, asc->m_aot,
               asc->m_samplingFrequency << esc->m_sbrSamplingRate,
               asc->m_samplesPerFrame << esc->m_sbrSamplingRate,
-              1,  /* stereoConfigIndex */
+              asc->m_channelConfiguration, 1, /* stereoConfigIndex */
               -1, /* nTimeSlots: read from bitstream */
               eldExtLen, asc->configMode, &asc->SacConfigChanged);
           if (ErrorStatus != TRANSPORTDEC_OK) {
@@ -1549,8 +1694,7 @@
                                            const AUDIO_OBJECT_TYPE aot) {
   TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
 
-  USAC_EXT_ELEMENT_TYPE usacExtElementType =
-      (USAC_EXT_ELEMENT_TYPE)escapedValue(hBs, 4, 8, 16);
+  UINT usacExtElementType = escapedValue(hBs, 4, 8, 16);
 
   /* recurve extension elements which are invalid for USAC */
   if (aot == AOT_USAC) {
@@ -1567,7 +1711,6 @@
     }
   }
 
-  extElement->usacExtElementType = usacExtElementType;
   int usacExtElementConfigLength = escapedValue(hBs, 4, 8, 16);
   extElement->usacExtElementConfigLength = (USHORT)usacExtElementConfigLength;
   INT bsAnchor;
@@ -1601,8 +1744,10 @@
       }
     } break;
     default:
+      usacExtElementType = ID_EXT_ELE_UNKNOWN;
       break;
   }
+  extElement->usacExtElementType = (USAC_EXT_ELEMENT_TYPE)usacExtElementType;
 
   /* Adjust bit stream position. This is required because of byte alignment and
    * unhandled extensions. */
@@ -1631,14 +1776,18 @@
   TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
 
   int numConfigExtensions;
-  CONFIG_EXT_ID usacConfigExtType;
+  UINT usacConfigExtType;
   int usacConfigExtLength;
+  int loudnessInfoSetIndex =
+      -1; /* index of loudnessInfoSet config extension. -1 if not contained. */
+  int tmp_subStreamIndex = 0;
+  AUDIO_OBJECT_TYPE tmp_aot = AOT_USAC;
 
   numConfigExtensions = (int)escapedValue(hBs, 2, 4, 8) + 1;
   for (int confExtIdx = 0; confExtIdx < numConfigExtensions; confExtIdx++) {
     INT nbits;
     int loudnessInfoSetConfigExtensionPosition = FDKgetValidBits(hBs);
-    usacConfigExtType = (CONFIG_EXT_ID)escapedValue(hBs, 4, 8, 16);
+    usacConfigExtType = escapedValue(hBs, 4, 8, 16);
     usacConfigExtLength = (int)escapedValue(hBs, 4, 8, 16);
 
     /* Start bit position of config extension */
@@ -1662,10 +1811,12 @@
           ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbUniDrc(
               cb->cbUniDrcData, hBs, usacConfigExtLength,
               1, /* loudnessInfoSet */
-              0, loudnessInfoSetConfigExtensionPosition, AOT_USAC);
+              tmp_subStreamIndex, loudnessInfoSetConfigExtensionPosition,
+              tmp_aot);
           if (ErrorStatus != TRANSPORTDEC_OK) {
             return ErrorStatus;
           }
+          loudnessInfoSetIndex = confExtIdx;
         }
       } break;
       default:
@@ -1681,6 +1832,17 @@
     FDKpushFor(hBs, usacConfigExtLength);
   }
 
+  if (loudnessInfoSetIndex == -1 && cb->cbUniDrc != NULL) {
+    /* no loudnessInfoSet contained. Clear the loudnessInfoSet struct by feeding
+     * an empty config extension */
+    ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbUniDrc(
+        cb->cbUniDrcData, NULL, 0, 1 /* loudnessInfoSet */, tmp_subStreamIndex,
+        0, tmp_aot);
+    if (ErrorStatus != TRANSPORTDEC_OK) {
+      return ErrorStatus;
+    }
+  }
+
   return ErrorStatus;
 }
 
@@ -1697,6 +1859,8 @@
   int channelElementIdx =
       0; /* index for elements which contain audio channels (sce, cpe, lfe) */
   SC_CHANNEL_CONFIG sc_chan_config = {0, 0, 0, 0};
+  int uniDrcElement =
+      -1; /* index of uniDrc extension element. -1 if not contained. */
 
   numberOfElements = (int)escapedValue(hBs, 4, 8, 16) + 1;
   usc->m_usacNumElements = numberOfElements;
@@ -1827,6 +1991,8 @@
               /* Mps212Config() ISO/IEC FDIS 23003-3 */
               if (cb->cbSsc(cb->cbSscData, hBs, asc->m_aot,
                             asc->m_extensionSamplingFrequency, samplesPerFrame,
+                            1, /* only downmix channels (residual channels are
+                                  not counted) */
                             usc->element[i].m_stereoConfigIndex,
                             usc->m_coreSbrFrameLengthIndex,
                             0, /* don't know the length */
@@ -1870,6 +2036,10 @@
       case ID_USAC_EXT:
         ErrorStatus = extElementConfig(&usc->element[i].extElement, hBs, cb, 0,
                                        asc->m_samplesPerFrame, 0, asc->m_aot);
+        if (usc->element[i].extElement.usacExtElementType ==
+            ID_EXT_ELE_UNI_DRC) {
+          uniDrcElement = i;
+        }
 
         if (ErrorStatus) {
           return ErrorStatus;
@@ -1898,6 +2068,18 @@
     }
   }
 
+  if (uniDrcElement == -1 && cb->cbUniDrc != NULL) {
+    /* no uniDrcConfig contained. Clear the uniDrcConfig struct by feeding an
+     * empty extension element */
+    int subStreamIndex = 0;
+    ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbUniDrc(
+        cb->cbUniDrcData, NULL, 0, 0 /* uniDrcConfig */, subStreamIndex, 0,
+        asc->m_aot);
+    if (ErrorStatus != TRANSPORTDEC_OK) {
+      return ErrorStatus;
+    }
+  }
+
   return ErrorStatus;
 }
 
@@ -1984,6 +2166,14 @@
     if (err != TRANSPORTDEC_OK) {
       return err;
     }
+  } else if (cb->cbUniDrc != NULL) {
+    /* no loudnessInfoSet contained. Clear the loudnessInfoSet struct by feeding
+     * an empty config extension */
+    err = (TRANSPORTDEC_ERROR)cb->cbUniDrc(
+        cb->cbUniDrcData, NULL, 0, 1 /* loudnessInfoSet */, 0, 0, asc->m_aot);
+    if (err != TRANSPORTDEC_OK) {
+      return err;
+    }
   }
 
   /* sanity check whether number of channels signaled in UsacDecoderConfig()
@@ -1996,9 +2186,11 @@
 
   /* Copy UsacConfig() to asc->m_sc.m_usacConfig.UsacConfig[] buffer. */
   INT configSize_bits = (INT)FDKgetValidBits(hBs) - nbits;
-  StoreConfigAsBitstream(hBs, configSize_bits,
-                         asc->m_sc.m_usacConfig.UsacConfig,
-                         TP_USAC_MAX_CONFIG_LEN);
+  if (StoreConfigAsBitstream(hBs, configSize_bits,
+                             asc->m_sc.m_usacConfig.UsacConfig,
+                             TP_USAC_MAX_CONFIG_LEN)) {
+    return TRANSPORTDEC_PARSE_ERROR;
+  }
   asc->m_sc.m_usacConfig.UsacConfigBits = fAbs(configSize_bits);
 
   return err;
@@ -2219,7 +2411,7 @@
     case AOT_MPEGS:
       if (cb->cbSsc != NULL) {
         if (cb->cbSsc(cb->cbSscData, bs, self->m_aot, self->m_samplingFrequency,
-                      self->m_samplesPerFrame, 1,
+                      self->m_samplesPerFrame, self->m_channelConfiguration, 1,
                       -1, /* nTimeSlots: read from bitstream */
                       0,  /* don't know the length */
                       self->configMode, &self->SacConfigChanged)) {
@@ -2300,8 +2492,10 @@
   /* Copy config() to asc->config[] buffer. */
   if ((ErrorStatus == TRANSPORTDEC_OK) && (self->m_aot == AOT_USAC)) {
     INT configSize_bits = (INT)FDKgetValidBits(bs) - (INT)ascStartAnchor;
-    StoreConfigAsBitstream(bs, configSize_bits, self->config,
-                           TP_USAC_MAX_CONFIG_LEN);
+    if (StoreConfigAsBitstream(bs, configSize_bits, self->config,
+                               TP_USAC_MAX_CONFIG_LEN)) {
+      return TRANSPORTDEC_PARSE_ERROR;
+    }
     self->configBits = fAbs(configSize_bits);
   }
 
@@ -2415,6 +2609,8 @@
                 cb->cbSscData, hBs,
                 AOT_DRM_USAC, /* syntax differs from MPEG Mps212Config() */
                 asc->m_extensionSamplingFrequency, samplesPerFrame,
+                1, /* only downmix channels (residual channels are not
+                      counted) */
                 usc->element[elemIdx].m_stereoConfigIndex,
                 usc->m_coreSbrFrameLengthIndex, 0, /* don't know the length */
                 asc->configMode, &asc->SacConfigChanged);
diff --git a/libMpegTPDec/src/tpdec_latm.cpp b/libMpegTPDec/src/tpdec_latm.cpp
index 3b71db8..c32be54 100644
--- a/libMpegTPDec/src/tpdec_latm.cpp
+++ b/libMpegTPDec/src/tpdec_latm.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -591,6 +591,18 @@
   return (ErrorStatus);
 }
 
+static int CLatmDemux_ReadAuChunkLengthInfo(HANDLE_FDK_BITSTREAM bs) {
+  int len = 0, tmp = 255;
+  int validBytes = (int)FDKgetValidBits(bs) >> 3;
+
+  while (tmp == 255 && validBytes-- > 0) {
+    tmp = (int)FDKreadBits(bs, 8);
+    len += tmp;
+  }
+
+  return ((tmp == 255) ? -1 : (len << 3));
+}
+
 TRANSPORTDEC_ERROR CLatmDemux_ReadPayloadLengthInfo(HANDLE_FDK_BITSTREAM bs,
                                                     CLatmDemux *pLatmDemux) {
   TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
@@ -602,11 +614,17 @@
       FDK_ASSERT(pLatmDemux->m_numLayer[prog] <= LATM_MAX_LAYER);
       for (UINT lay = 0; lay < pLatmDemux->m_numLayer[prog]; lay++) {
         LATM_LAYER_INFO *p_linfo = &pLatmDemux->m_linfo[prog][lay];
+        int auChunkLengthInfo = 0;
 
         switch (p_linfo->m_frameLengthType) {
           case 0:
-            p_linfo->m_frameLengthInBits = CLatmDemux_ReadAuChunkLengthInfo(bs);
-            totalPayloadBits += p_linfo->m_frameLengthInBits;
+            auChunkLengthInfo = CLatmDemux_ReadAuChunkLengthInfo(bs);
+            if (auChunkLengthInfo >= 0) {
+              p_linfo->m_frameLengthInBits = (UINT)auChunkLengthInfo;
+              totalPayloadBits += p_linfo->m_frameLengthInBits;
+            } else {
+              return TRANSPORTDEC_PARSE_ERROR;
+            }
             break;
           case 3:
           case 5:
@@ -627,23 +645,6 @@
   return (ErrorStatus);
 }
 
-int CLatmDemux_ReadAuChunkLengthInfo(HANDLE_FDK_BITSTREAM bs) {
-  UCHAR endFlag;
-  int len = 0;
-
-  do {
-    UCHAR tmp = (UCHAR)FDKreadBits(bs, 8);
-    endFlag = (tmp < 255);
-
-    len += tmp;
-
-  } while (endFlag == 0);
-
-  len <<= 3; /* convert from bytes to bits */
-
-  return len;
-}
-
 UINT CLatmDemux_GetFrameLengthInBits(CLatmDemux *pLatmDemux, const UINT prog,
                                      const UINT layer) {
   UINT nFrameLenBits = 0;
diff --git a/libMpegTPDec/src/tpdec_latm.h b/libMpegTPDec/src/tpdec_latm.h
index 6af553d..8b8c971 100644
--- a/libMpegTPDec/src/tpdec_latm.h
+++ b/libMpegTPDec/src/tpdec_latm.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -151,8 +151,6 @@
                                   AudioPreRoll */
 } CLatmDemux;
 
-int CLatmDemux_ReadAuChunkLengthInfo(HANDLE_FDK_BITSTREAM bs);
-
 TRANSPORTDEC_ERROR CLatmDemux_Read(HANDLE_FDK_BITSTREAM bs,
                                    CLatmDemux *pLatmDemux, TRANSPORT_TYPE tt,
                                    CSTpCallBacks *pTpDecCallbacks,
diff --git a/libMpegTPEnc/include/tp_data.h b/libMpegTPEnc/include/tp_data.h
index 00de356..464c485 100644
--- a/libMpegTPEnc/include/tp_data.h
+++ b/libMpegTPEnc/include/tp_data.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -368,7 +368,7 @@
 typedef INT (*cbSsc_t)(void *, HANDLE_FDK_BITSTREAM,
                        const AUDIO_OBJECT_TYPE coreCodec,
                        const INT samplingRate, const INT frameSize,
-                       const INT stereoConfigIndex,
+                       const INT numChannels, const INT stereoConfigIndex,
                        const INT coreSbrFrameLengthIndex, const INT configBytes,
                        const UCHAR configMode, UCHAR *configChanged);
 
diff --git a/libMpegTPEnc/src/tpenc_asc.cpp b/libMpegTPEnc/src/tpenc_asc.cpp
index 0b484a0..9591ba8 100644
--- a/libMpegTPEnc/src/tpenc_asc.cpp
+++ b/libMpegTPEnc/src/tpenc_asc.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -795,7 +795,7 @@
 
     const INT eldExtLen =
         (cb->cbSsc(cb->cbSscData, NULL, config->aot, config->extSamplingRate, 0,
-                   0, 0, 0, 0, NULL) +
+                   0, 0, 0, 0, 0, NULL) +
          7) >>
         3;
     INT cnt = eldExtLen;
@@ -818,7 +818,7 @@
     }
 
     cb->cbSsc(cb->cbSscData, hBs, config->aot, config->extSamplingRate, 0, 0, 0,
-              0, 0, NULL);
+              0, 0, 0, NULL);
   }
 
   if (config->downscaleSamplingRate != 0 &&
diff --git a/libPCMutils/src/limiter.cpp b/libPCMutils/src/limiter.cpp
index 598dc0c..c6b8687 100644
--- a/libPCMutils/src/limiter.cpp
+++ b/libPCMutils/src/limiter.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -322,7 +322,8 @@
               (FIXP_DBL)SATURATE_LEFT_SHIFT(tmp, scaling, DFRACT_BITS));
 #else
           samplesOut[j] = (INT_PCM)FX_DBL2FX_PCM((FIXP_DBL)SATURATE_LEFT_SHIFT(
-              tmp + ((FIXP_DBL)0x8000 >> scaling), scaling, DFRACT_BITS));
+              (tmp >> 1) + ((FIXP_DBL)0x8000 >> (scaling + 1)), scaling + 1,
+              DFRACT_BITS));
 #endif
         }
       }
diff --git a/libPCMutils/src/pcmdmx_lib.cpp b/libPCMutils/src/pcmdmx_lib.cpp
index 2070dbc..fca12ce 100644
--- a/libPCMutils/src/pcmdmx_lib.cpp
+++ b/libPCMutils/src/pcmdmx_lib.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -494,13 +494,40 @@
   return plainChMode;
 }
 
-static inline UINT getIdxSum(UCHAR numCh) {
-  UINT result = 0;
-  int i;
-  for (i = 1; i < numCh; i += 1) {
-    result += i;
+/** Validates the channel indices of all channels present in the bitstream.
+ * The channel indices have to be consecutive and unique for each audio channel
+ *type.
+ * @param [in] The total number of channels of the given configuration.
+ * @param [in] The total number of channels of the current audio channel type of
+ *the given configuration.
+ * @param [in] Audio channel type to be examined.
+ * @param [in] Array holding the corresponding channel types for each channel.
+ * @param [in] Array holding the corresponding channel type indices for each
+ *channel.
+ * @returns Returns 1 on success, returns 0 on error.
+ **/
+static UINT validateIndices(UINT numChannels, UINT numChannelsPlaneAndGrp,
+                            AUDIO_CHANNEL_TYPE aChType,
+                            const AUDIO_CHANNEL_TYPE channelType[],
+                            const UCHAR channelIndices[]) {
+  for (UINT reqValue = 0; reqValue < numChannelsPlaneAndGrp; reqValue++) {
+    int found = FALSE;
+    for (UINT i = 0; i < numChannels; i++) {
+      if (channelType[i] == aChType) {
+        if (channelIndices[i] == reqValue) {
+          if (found == TRUE) {
+            return 0; /* Found channel index a second time */
+          } else {
+            found = TRUE; /* Found channel index */
+          }
+        }
+      }
+    }
+    if (found == FALSE) {
+      return 0; /* Did not find channel index */
+    }
   }
-  return result;
+  return 1; /* Successfully validated channel indices */
 }
 
 /** Evaluate a given channel configuration and extract a packed channel mode. In
@@ -523,7 +550,6 @@
     UCHAR offsetTable[(8)],                 /* out */
     PCM_DMX_CHANNEL_MODE *chMode            /* out */
 ) {
-  UINT idxSum[(3)][(4)];
   UCHAR numCh[(3)][(4)];
   UCHAR mapped[(8)];
   PCM_DMX_SPEAKER_POSITION spkrPos[(8)];
@@ -538,7 +564,6 @@
   FDK_ASSERT(chMode != NULL);
 
   /* For details see ISO/IEC 13818-7:2005(E), 8.5.3 Channel configuration */
-  FDKmemclear(idxSum, (3) * (4) * sizeof(UINT));
   FDKmemclear(numCh, (3) * (4) * sizeof(UCHAR));
   FDKmemclear(mapped, (8) * sizeof(UCHAR));
   FDKmemclear(spkrPos, (8) * sizeof(PCM_DMX_SPEAKER_POSITION));
@@ -552,19 +577,22 @@
         (channelType[ch] & 0x0F) - 1,
         0); /* Assign all undefined channels (ACT_NONE) to front channels. */
     numCh[channelType[ch] >> 4][chGrp] += 1;
-    idxSum[channelType[ch] >> 4][chGrp] += channelIndices[ch];
   }
-  if (numChannels > TWO_CHANNEL) {
+
+  {
     int chGrp;
     /* Sanity check on the indices */
     for (chGrp = 0; chGrp < (4); chGrp += 1) {
       int plane;
       for (plane = 0; plane < (3); plane += 1) {
-        if (idxSum[plane][chGrp] != getIdxSum(numCh[plane][chGrp])) {
+        if (numCh[plane][chGrp] == 0) continue;
+        AUDIO_CHANNEL_TYPE aChType =
+            (AUDIO_CHANNEL_TYPE)((plane << 4) | ((chGrp + 1) & 0xF));
+        if (!validateIndices(numChannels, numCh[plane][chGrp], aChType,
+                             channelType, channelIndices)) {
           unsigned idxCnt = 0;
           for (ch = 0; ch < numChannels; ch += 1) {
-            if (channelType[ch] ==
-                (AUDIO_CHANNEL_TYPE)((plane << 4) | ((chGrp + 1) & 0xF))) {
+            if (channelType[ch] == aChType) {
               channelIndices[ch] = idxCnt++;
             }
           }
diff --git a/libSACdec/include/sac_dec_lib.h b/libSACdec/include/sac_dec_lib.h
index 1827504..5aad4e0 100644
--- a/libSACdec/include/sac_dec_lib.h
+++ b/libSACdec/include/sac_dec_lib.h
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -316,8 +316,8 @@
 SACDEC_ERROR mpegSurroundDecoder_Config(
     CMpegSurroundDecoder *pMpegSurroundDecoder, HANDLE_FDK_BITSTREAM hBs,
     AUDIO_OBJECT_TYPE coreCodec, INT samplingRate, INT frameSize,
-    INT stereoConfigIndex, INT coreSbrFrameLengthIndex, INT configBytes,
-    const UCHAR configMode, UCHAR *configChanged);
+    INT numChannels, INT stereoConfigIndex, INT coreSbrFrameLengthIndex,
+    INT configBytes, const UCHAR configMode, UCHAR *configChanged);
 
 SACDEC_ERROR
 mpegSurroundDecoder_ConfigureQmfDomain(
diff --git a/libSACdec/src/sac_bitdec.cpp b/libSACdec/src/sac_bitdec.cpp
index 4485ccf..25b3d9e 100644
--- a/libSACdec/src/sac_bitdec.cpp
+++ b/libSACdec/src/sac_bitdec.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -488,12 +488,17 @@
   pSpatialSpecificConfig->freqRes =
       (SPATIALDEC_FREQ_RES)freqResTable_LD[bsFreqRes];
 
-  pSpatialSpecificConfig->treeConfig =
-      (SPATIALDEC_TREE_CONFIG)FDKreadBits(bitstream, 4);
+  {
+    UINT treeConfig = FDKreadBits(bitstream, 4);
 
-  if (pSpatialSpecificConfig->treeConfig != SPATIALDEC_MODE_RSVD7) {
-    err = MPS_UNSUPPORTED_CONFIG;
-    goto bail;
+    switch (treeConfig) {
+      case SPATIALDEC_MODE_RSVD7:
+        pSpatialSpecificConfig->treeConfig = (SPATIALDEC_TREE_CONFIG)treeConfig;
+        break;
+      default:
+        err = MPS_UNSUPPORTED_CONFIG;
+        goto bail;
+    }
   }
 
   {
diff --git a/libSACdec/src/sac_dec.cpp b/libSACdec/src/sac_dec.cpp
index a7b50df..a26e251 100644
--- a/libSACdec/src/sac_dec.cpp
+++ b/libSACdec/src/sac_dec.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -1098,6 +1098,28 @@
   }
 }
 
+/**
+ * \brief Set internal error and reset error status
+ *
+ * \param self         spatialDec handle.
+ * \param bypassMode   pointer to bypassMode.
+ * \param err          error status.
+ *
+ * \return  error status.
+ */
+static SACDEC_ERROR SpatialDecSetInternalError(spatialDec *self,
+                                               int *bypassMode,
+                                               SACDEC_ERROR err) {
+  *bypassMode = 1;
+
+  if (self->errInt == MPS_OK) {
+    /* store internal error before it gets overwritten */
+    self->errInt = err;
+  }
+
+  return MPS_OK;
+}
+
 /*******************************************************************************
  Functionname: SpatialDecApplyParameterSets
  *******************************************************************************
@@ -1118,7 +1140,7 @@
     const FDK_channelMapDescr *const mapDescr) {
   SACDEC_ERROR err = MPS_OK;
 
-  FIXP_SGL alpha;
+  FIXP_SGL alpha = FL2FXCONST_SGL(0.0);
 
   int ts;
   int ch;
@@ -1141,20 +1163,22 @@
        ts++, ts_io++) {
     int currSlot = frame->paramSlot[ps];
 
+    err = (currSlot < ts) ? MPS_WRONG_PARAMETERSETS : MPS_OK;
+    if (err != MPS_OK) {
+      err = SpatialDecSetInternalError(self, &bypassMode, err);
+    }
+
     /*
      * Get new parameter set
      */
     if (ts == prevSlot + 1) {
-      err = SpatialDecCalculateM1andM2(self, ps,
-                                       frame); /* input: ottCLD, ottICC, ... */
-      /* output: M1param(Real/Imag), M2(Real/Imag) */
-      if (err != MPS_OK) {
-        bypassMode = 1;
-        if (self->errInt == MPS_OK) {
-          /* store internal error befor it gets overwritten */
-          self->errInt = err;
+      if (bypassMode == 0) {
+        err = SpatialDecCalculateM1andM2(
+            self, ps, frame); /* input: ottCLD, ottICC, ... */
+                              /* output: M1param(Real/Imag), M2(Real/Imag) */
+        if (err != MPS_OK) {
+          err = SpatialDecSetInternalError(self, &bypassMode, err);
         }
-        err = MPS_OK;
       }
 
       if ((ps == 0) && (self->bOverwriteM1M2prev != 0)) {
@@ -1168,13 +1192,16 @@
         self->bOverwriteM1M2prev = 0;
       }
 
-      SpatialDecSmoothM1andM2(
-          self, frame,
-          ps); /* input: M1param(Real/Imag)(Prev), M2(Real/Imag)(Prev) */
-               /* output: M1param(Real/Imag), M2(Real/Imag) */
+      if (bypassMode == 0) {
+        SpatialDecSmoothM1andM2(
+            self, frame,
+            ps); /* input: M1param(Real/Imag)(Prev), M2(Real/Imag)(Prev) */
+      }          /* output: M1param(Real/Imag), M2(Real/Imag) */
     }
 
-    alpha = FX_DBL2FX_SGL(fDivNorm(ts - prevSlot, currSlot - prevSlot));
+    if (bypassMode == 0) {
+      alpha = FX_DBL2FX_SGL(fDivNorm(ts - prevSlot, currSlot - prevSlot));
+    }
 
     switch (mode) {
       case INPUTMODE_QMF_SBR:
@@ -1182,15 +1209,17 @@
           self->bShareDelayWithSBR = 0; /* We got no hybrid delay */
         else
           self->bShareDelayWithSBR = 1;
-        SpatialDecFeedQMF(self, qmfInDataReal, qmfInDataImag, ts_io, bypassMode,
-                          self->qmfInputReal__FDK, self->qmfInputImag__FDK,
-                          self->numInputChannels);
+        SpatialDecFeedQMF(
+            self, qmfInDataReal, qmfInDataImag, ts_io, bypassMode,
+            self->qmfInputReal__FDK, self->qmfInputImag__FDK,
+            (bypassMode) ? numInputChannels : self->numInputChannels);
         break;
       case INPUTMODE_TIME:
         self->bShareDelayWithSBR = 0;
-        SpatialDecQMFAnalysis(self, inData, ts_io, bypassMode,
-                              self->qmfInputReal__FDK, self->qmfInputImag__FDK,
-                              self->numInputChannels);
+        SpatialDecQMFAnalysis(
+            self, inData, ts_io, bypassMode, self->qmfInputReal__FDK,
+            self->qmfInputImag__FDK,
+            (bypassMode) ? numInputChannels : self->numInputChannels);
         break;
       default:
         break;
@@ -1360,7 +1389,7 @@
       }   /* !self->tempShapeConfig == 1 */
     }     /*  !bypassMode */
 
-    if (self->phaseCoding == 1) {
+    if ((self->phaseCoding == 1) && (bypassMode == 0)) {
       /* only if bsPhaseCoding == 1 and bsResidualCoding == 0 */
 
       SpatialDecApplyPhase(
diff --git a/libSACdec/src/sac_dec_lib.cpp b/libSACdec/src/sac_dec_lib.cpp
index 57446f8..d30131f 100644
--- a/libSACdec/src/sac_dec_lib.cpp
+++ b/libSACdec/src/sac_dec_lib.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -700,9 +700,10 @@
 SACDEC_ERROR mpegSurroundDecoder_Config(
     CMpegSurroundDecoder *pMpegSurroundDecoder, HANDLE_FDK_BITSTREAM hBs,
     AUDIO_OBJECT_TYPE coreCodec, INT samplingRate, INT frameSize,
-    INT stereoConfigIndex, INT coreSbrFrameLengthIndex, INT configBytes,
-    const UCHAR configMode, UCHAR *configChanged) {
+    INT numChannels, INT stereoConfigIndex, INT coreSbrFrameLengthIndex,
+    INT configBytes, const UCHAR configMode, UCHAR *configChanged) {
   SACDEC_ERROR err = MPS_OK;
+  INT nInputChannels;
   SPATIAL_SPECIFIC_CONFIG spatialSpecificConfig;
   SPATIAL_SPECIFIC_CONFIG *pSsc =
       &pMpegSurroundDecoder->spatialSpecificConfigBackup;
@@ -716,12 +717,18 @@
         err = SpatialDecParseMps212Config(
             hBs, &spatialSpecificConfig, samplingRate, coreCodec,
             stereoConfigIndex, coreSbrFrameLengthIndex);
+        nInputChannels = spatialSpecificConfig.nInputChannels;
         pSsc = &spatialSpecificConfig;
       } else {
         err = SpatialDecParseMps212Config(
             hBs, &pMpegSurroundDecoder->spatialSpecificConfigBackup,
             samplingRate, coreCodec, stereoConfigIndex,
             coreSbrFrameLengthIndex);
+        nInputChannels =
+            pMpegSurroundDecoder->spatialSpecificConfigBackup.nInputChannels;
+      }
+      if ((err == MPS_OK) && (numChannels != nInputChannels)) {
+        err = MPS_PARSE_ERROR;
       }
       break;
     case AOT_ER_AAC_ELD:
@@ -731,11 +738,19 @@
          * into temporarily allocated structure */
         err = SpatialDecParseSpecificConfig(hBs, &spatialSpecificConfig,
                                             configBytes, coreCodec);
+        nInputChannels = spatialSpecificConfig.nInputChannels;
         pSsc = &spatialSpecificConfig;
       } else {
         err = SpatialDecParseSpecificConfig(
             hBs, &pMpegSurroundDecoder->spatialSpecificConfigBackup,
             configBytes, coreCodec);
+        nInputChannels =
+            pMpegSurroundDecoder->spatialSpecificConfigBackup.nInputChannels;
+      }
+      /* check number of channels for channel_configuration > 0  */
+      if ((err == MPS_OK) && (numChannels > 0) &&
+          (numChannels != nInputChannels)) {
+        err = MPS_PARSE_ERROR;
       }
       break;
     default:
diff --git a/libSACdec/src/sac_process.cpp b/libSACdec/src/sac_process.cpp
index 22091a9..33a1647 100644
--- a/libSACdec/src/sac_process.cpp
+++ b/libSACdec/src/sac_process.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -517,12 +517,11 @@
       maxVal = fAbs(iReal0) | fAbs(iImag0);
       maxVal |= fAbs(iReal1);
 
-      s = fMax(CntLeadingZeros(maxVal) - 1, 0);
-      s = fMin(s, scale_param_m2);
+      s = fMin(CntLeadingZeros(maxVal) - 2, scale_param_m2);
 
-      mReal0 = iReal0 << s;
-      mImag0 = iImag0 << s;
-      mReal1 = iReal1 << s;
+      mReal0 = scaleValue(iReal0, s);
+      mImag0 = scaleValue(iImag0, s);
+      mReal1 = scaleValue(iReal1, s);
 
       s = scale_param_m2 - s;
 
@@ -562,12 +561,11 @@
       maxVal = fAbs(iReal0) | fAbs(iImag0);
       maxVal |= fAbs(iReal1);
 
-      s = fMax(CntLeadingZeros(maxVal) - 1, 0);
-      s = fMin(s, scale_param_m2);
+      s = fMin(CntLeadingZeros(maxVal) - 2, scale_param_m2);
 
-      mReal0 = FX_DBL2FX_SGL(iReal0 << s);
-      mImag0 = FX_DBL2FX_SGL(iImag0 << s);
-      mReal1 = FX_DBL2FX_SGL(iReal1 << s);
+      mReal0 = FX_DBL2FX_SGL(scaleValue(iReal0, s));
+      mImag0 = FX_DBL2FX_SGL(scaleValue(iImag0, s));
+      mReal1 = FX_DBL2FX_SGL(scaleValue(iReal1, s));
 
       s = scale_param_m2 - s;
 
diff --git a/libSACdec/src/sac_reshapeBBEnv.cpp b/libSACdec/src/sac_reshapeBBEnv.cpp
index 272d009..72f4e58 100644
--- a/libSACdec/src/sac_reshapeBBEnv.cpp
+++ b/libSACdec/src/sac_reshapeBBEnv.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -241,29 +241,56 @@
   }
 }
 
-static inline void slotAmp(FIXP_DBL *RESTRICT slotAmp_dry,
-                           FIXP_DBL *RESTRICT slotAmp_wet,
-                           FIXP_DBL *RESTRICT pHybOutputRealDry,
-                           FIXP_DBL *RESTRICT pHybOutputImagDry,
-                           FIXP_DBL *RESTRICT pHybOutputRealWet,
-                           FIXP_DBL *RESTRICT pHybOutputImagWet, INT cplxBands,
-                           INT hybBands) {
-  INT qs;
+static inline void slotAmp(
+    FIXP_DBL *RESTRICT slotAmp_dry, INT *RESTRICT slotAmp_dry_e,
+    FIXP_DBL *RESTRICT slotAmp_wet, INT *RESTRICT slotAmp_wet_e,
+    FIXP_DBL *RESTRICT pHybOutputRealDry, FIXP_DBL *RESTRICT pHybOutputImagDry,
+    FIXP_DBL *RESTRICT pHybOutputRealWet, FIXP_DBL *RESTRICT pHybOutputImagWet,
+    INT cplxBands, INT hybBands) {
+  INT qs, s1, s2, headroom_dry, headroom_wet;
   FIXP_DBL dry, wet;
 
+  /* headroom can be reduced by 1 bit due to use of fPow2Div2 */
+  s1 = DFRACT_BITS - 1 - CntLeadingZeros(hybBands + cplxBands);
+  headroom_dry = fMin(getScalefactor(pHybOutputRealDry, hybBands),
+                      getScalefactor(pHybOutputImagDry, cplxBands));
+  headroom_wet = fMin(getScalefactor(pHybOutputRealWet, hybBands),
+                      getScalefactor(pHybOutputImagWet, cplxBands));
+
   dry = wet = FL2FXCONST_DBL(0.0f);
   for (qs = 0; qs < cplxBands; qs++) {
-    dry = fAddSaturate(dry, fPow2Div2(pHybOutputRealDry[qs] << (1)) +
-                                fPow2Div2(pHybOutputImagDry[qs] << (1)));
-    wet = fAddSaturate(wet, fPow2Div2(pHybOutputRealWet[qs] << (1)) +
-                                fPow2Div2(pHybOutputImagWet[qs] << (1)));
+    /* sum up dry part */
+    dry += (fPow2Div2(pHybOutputRealDry[qs] << headroom_dry) >> s1);
+    dry += (fPow2Div2(pHybOutputImagDry[qs] << headroom_dry) >> s1);
+    /* sum up wet part */
+    wet += (fPow2Div2(pHybOutputRealWet[qs] << headroom_wet) >> s1);
+    wet += (fPow2Div2(pHybOutputImagWet[qs] << headroom_wet) >> s1);
   }
   for (; qs < hybBands; qs++) {
-    dry = fAddSaturate(dry, fPow2Div2(pHybOutputRealDry[qs] << (1)));
-    wet = fAddSaturate(wet, fPow2Div2(pHybOutputRealWet[qs] << (1)));
+    dry += (fPow2Div2(pHybOutputRealDry[qs] << headroom_dry) >> s1);
+    wet += (fPow2Div2(pHybOutputRealWet[qs] << headroom_wet) >> s1);
   }
-  *slotAmp_dry = dry >> (2 * (1));
-  *slotAmp_wet = wet >> (2 * (1));
+
+  /* consider fPow2Div2() */
+  s1 += 1;
+
+  /* normalize dry part, ensure that exponent is even */
+  s2 = fixMax(0, CntLeadingZeros(dry) - 1);
+  *slotAmp_dry = dry << s2;
+  *slotAmp_dry_e = s1 - s2 - 2 * headroom_dry;
+  if (*slotAmp_dry_e & 1) {
+    *slotAmp_dry = *slotAmp_dry >> 1;
+    *slotAmp_dry_e += 1;
+  }
+
+  /* normalize wet part, ensure that exponent is even */
+  s2 = fixMax(0, CntLeadingZeros(wet) - 1);
+  *slotAmp_wet = wet << s2;
+  *slotAmp_wet_e = s1 - s2 - 2 * headroom_wet;
+  if (*slotAmp_wet_e & 1) {
+    *slotAmp_wet = *slotAmp_wet >> 1;
+    *slotAmp_wet_e += 1;
+  }
 }
 
 #if defined(__aarch64__)
@@ -533,6 +560,7 @@
                             INT ts) {
   INT ch, scale;
   INT dryFacSF, slotAmpSF;
+  INT slotAmp_dry_e, slotAmp_wet_e;
   FIXP_DBL tmp, dryFac, envShape;
   FIXP_DBL slotAmp_dry, slotAmp_wet, slotAmp_ratio;
   FIXP_DBL envDry[MAX_OUTPUT_CHANNELS], envDmx[2];
@@ -594,22 +622,25 @@
         dryFacSF = SF_SHAPE + 2 * dryFacSF;
       }
 
+      slotAmp_dry_e = slotAmp_wet_e = 0;
+
       /* calculate slotAmp_dry and slotAmp_wet */
-      slotAmp(&slotAmp_dry, &slotAmp_wet, &self->hybOutputRealDry__FDK[ch][6],
+      slotAmp(&slotAmp_dry, &slotAmp_dry_e, &slotAmp_wet, &slotAmp_wet_e,
+              &self->hybOutputRealDry__FDK[ch][6],
               &self->hybOutputImagDry__FDK[ch][6],
               &self->hybOutputRealWet__FDK[ch][6],
               &self->hybOutputImagWet__FDK[ch][6], cplxBands, hybBands);
 
+      /* exponents must be even due to subsequent square root calculation */
+      FDK_ASSERT(((slotAmp_dry_e & 1) == 0) && ((slotAmp_wet_e & 1) == 0));
+
       /* slotAmp_ratio will be scaled by slotAmpSF bits */
       if (slotAmp_dry != FL2FXCONST_DBL(0.0f)) {
-        sc = fixMax(0, CntLeadingZeros(slotAmp_wet) - 1);
-        sc = sc - (sc & 1);
-
-        slotAmp_wet = sqrtFixp(slotAmp_wet << sc);
+        slotAmp_wet = sqrtFixp(slotAmp_wet);
         slotAmp_dry = invSqrtNorm2(slotAmp_dry, &slotAmpSF);
 
         slotAmp_ratio = fMult(slotAmp_wet, slotAmp_dry);
-        slotAmpSF = slotAmpSF - (sc >> 1);
+        slotAmpSF = slotAmpSF + (slotAmp_wet_e >> 1) - (slotAmp_dry_e >> 1);
       }
 
       /* calculate common scale factor */
diff --git a/libSACdec/src/sac_stp.cpp b/libSACdec/src/sac_stp.cpp
index bb66277..0e6affa 100644
--- a/libSACdec/src/sac_stp.cpp
+++ b/libSACdec/src/sac_stp.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -229,15 +229,13 @@
   int n;
   FIXP_DBL scaleY;
   for (n = bands - 1; n >= 0; n--) {
-    scaleY = fMultDiv2(scaleX, *pBP);
+    scaleY = fMult(scaleX, *pBP);
     *hybOutputRealDry = SATURATE_LEFT_SHIFT(
-        (*hybOutputRealDry >> 1) +
-            (fMultDiv2(*hybOutputRealWet, scaleY) << (SF_SCALE + 1)),
-        1, DFRACT_BITS);
+        (*hybOutputRealDry >> SF_SCALE) + fMult(*hybOutputRealWet, scaleY),
+        SF_SCALE, DFRACT_BITS);
     *hybOutputImagDry = SATURATE_LEFT_SHIFT(
-        (*hybOutputImagDry >> 1) +
-            (fMultDiv2(*hybOutputImagWet, scaleY) << (SF_SCALE + 1)),
-        1, DFRACT_BITS);
+        (*hybOutputImagDry >> SF_SCALE) + fMult(*hybOutputImagWet, scaleY),
+        SF_SCALE, DFRACT_BITS);
     hybOutputRealDry++, hybOutputRealWet++;
     hybOutputImagDry++, hybOutputImagWet++;
     pBP++;
@@ -252,12 +250,12 @@
   int n;
 
   for (n = bands - 1; n >= 0; n--) {
-    *hybOutputRealDry =
-        *hybOutputRealDry +
-        (fMultDiv2(*hybOutputRealWet, scaleX) << (SF_SCALE + 1));
-    *hybOutputImagDry =
-        *hybOutputImagDry +
-        (fMultDiv2(*hybOutputImagWet, scaleX) << (SF_SCALE + 1));
+    *hybOutputRealDry = SATURATE_LEFT_SHIFT(
+        (*hybOutputRealDry >> SF_SCALE) + fMult(*hybOutputRealWet, scaleX),
+        SF_SCALE, DFRACT_BITS);
+    *hybOutputImagDry = SATURATE_LEFT_SHIFT(
+        (*hybOutputImagDry >> SF_SCALE) + fMult(*hybOutputImagWet, scaleX),
+        SF_SCALE, DFRACT_BITS);
     hybOutputRealDry++, hybOutputRealWet++;
     hybOutputImagDry++, hybOutputImagWet++;
   }
@@ -369,15 +367,15 @@
     hStpDec->update_old_ener = 1;
     for (ch = 0; ch < self->numInputChannels; ch++) {
       hStpDec->oldDryEnerLD64[ch] =
-          CalcLdData(hStpDec->runDryEner[ch] + ABS_THR__FDK);
+          CalcLdData(fAddSaturate(hStpDec->runDryEner[ch], ABS_THR__FDK));
     }
     for (ch = 0; ch < self->numOutputChannels; ch++) {
       if (self->treeConfig == TREE_212)
         hStpDec->oldWetEnerLD64[ch] =
-            CalcLdData(hStpDec->runWetEner[ch] + ABS_THR__FDK);
+            CalcLdData(fAddSaturate(hStpDec->runWetEner[ch], ABS_THR__FDK));
       else
         hStpDec->oldWetEnerLD64[ch] =
-            CalcLdData(hStpDec->runWetEner[ch] + ABS_THR2__FDK);
+            CalcLdData(fAddSaturate(hStpDec->runWetEner[ch], ABS_THR2__FDK));
     }
   } else {
     hStpDec->update_old_ener++;
diff --git a/libSBRdec/src/arm/lpp_tran_arm.cpp b/libSBRdec/src/arm/lpp_tran_arm.cpp
deleted file mode 100644
index db1948f..0000000
--- a/libSBRdec/src/arm/lpp_tran_arm.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-/* -----------------------------------------------------------------------------
-Software License for The Fraunhofer FDK AAC Codec Library for Android
-
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
-Forschung e.V. All rights reserved.
-
- 1.    INTRODUCTION
-The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
-that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
-scheme for digital audio. This FDK AAC Codec software is intended to be used on
-a wide variety of Android devices.
-
-AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
-general perceptual audio codecs. AAC-ELD is considered the best-performing
-full-bandwidth communications codec by independent studies and is widely
-deployed. AAC has been standardized by ISO and IEC as part of the MPEG
-specifications.
-
-Patent licenses for necessary patent claims for the FDK AAC Codec (including
-those of Fraunhofer) may be obtained through Via Licensing
-(www.vialicensing.com) or through the respective patent owners individually for
-the purpose of encoding or decoding bit streams in products that are compliant
-with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
-Android devices already license these patent claims through Via Licensing or
-directly from the patent owners, and therefore FDK AAC Codec software may
-already be covered under those patent licenses when it is used for those
-licensed purposes only.
-
-Commercially-licensed AAC software libraries, including floating-point versions
-with enhanced sound quality, are also available from Fraunhofer. Users are
-encouraged to check the Fraunhofer website for additional applications
-information and documentation.
-
-2.    COPYRIGHT LICENSE
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted without payment of copyright license fees provided that you
-satisfy the following conditions:
-
-You must retain the complete text of this software license in redistributions of
-the FDK AAC Codec or your modifications thereto in source code form.
-
-You must retain the complete text of this software license in the documentation
-and/or other materials provided with redistributions of the FDK AAC Codec or
-your modifications thereto in binary form. You must make available free of
-charge copies of the complete source code of the FDK AAC Codec and your
-modifications thereto to recipients of copies in binary form.
-
-The name of Fraunhofer may not be used to endorse or promote products derived
-from this library without prior written permission.
-
-You may not charge copyright license fees for anyone to use, copy or distribute
-the FDK AAC Codec software or your modifications thereto.
-
-Your modified versions of the FDK AAC Codec must carry prominent notices stating
-that you changed the software and the date of any change. For modified versions
-of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
-must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
-AAC Codec Library for Android."
-
-3.    NO PATENT LICENSE
-
-NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
-limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
-Fraunhofer provides no warranty of patent non-infringement with respect to this
-software.
-
-You may use this FDK AAC Codec software or modifications thereto only for
-purposes that are authorized by appropriate patent licenses.
-
-4.    DISCLAIMER
-
-This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
-holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
-including but not limited to the implied warranties of merchantability and
-fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
-CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
-or consequential damages, including but not limited to procurement of substitute
-goods or services; loss of use, data, or profits, or business interruption,
-however caused and on any theory of liability, whether in contract, strict
-liability, or tort (including negligence), arising in any way out of the use of
-this software, even if advised of the possibility of such damage.
-
-5.    CONTACT INFORMATION
-
-Fraunhofer Institute for Integrated Circuits IIS
-Attention: Audio and Multimedia Departments - FDK AAC LL
-Am Wolfsmantel 33
-91058 Erlangen, Germany
-
-www.iis.fraunhofer.de/amm
-amm-info@iis.fraunhofer.de
------------------------------------------------------------------------------ */
-
-/**************************** SBR decoder library ******************************
-
-   Author(s):   Arthur Tritthart
-
-   Description: (ARM optimised) LPP transposer subroutines
-
-*******************************************************************************/
-
-#if defined(__arm__)
-
-#define FUNCTION_LPPTRANSPOSER_func1
-
-#ifdef FUNCTION_LPPTRANSPOSER_func1
-
-/* Note: This code requires only 43 cycles per iteration instead of 61 on
- * ARM926EJ-S */
-static void lppTransposer_func1(FIXP_DBL *lowBandReal, FIXP_DBL *lowBandImag,
-                                FIXP_DBL **qmfBufferReal,
-                                FIXP_DBL **qmfBufferImag, int loops, int hiBand,
-                                int dynamicScale, int descale, FIXP_SGL a0r,
-                                FIXP_SGL a0i, FIXP_SGL a1r, FIXP_SGL a1i,
-                                const int fPreWhitening,
-                                FIXP_DBL preWhiteningGain,
-                                int preWhiteningGains_sf) {
-  FIXP_DBL real1, real2, imag1, imag2, accu1, accu2;
-
-  real2 = lowBandReal[-2];
-  real1 = lowBandReal[-1];
-  imag2 = lowBandImag[-2];
-  imag1 = lowBandImag[-1];
-  for (int i = 0; i < loops; i++) {
-    accu1 = fMultDiv2(a0r, real1);
-    accu2 = fMultDiv2(a0i, imag1);
-    accu1 = fMultAddDiv2(accu1, a1r, real2);
-    accu2 = fMultAddDiv2(accu2, a1i, imag2);
-    real2 = fMultDiv2(a1i, real2);
-    accu1 = accu1 - accu2;
-    accu1 = accu1 >> dynamicScale;
-
-    accu2 = fMultAddDiv2(real2, a1r, imag2);
-    real2 = real1;
-    imag2 = imag1;
-    accu2 = fMultAddDiv2(accu2, a0i, real1);
-    real1 = lowBandReal[i];
-    accu2 = fMultAddDiv2(accu2, a0r, imag1);
-    imag1 = lowBandImag[i];
-    accu2 = accu2 >> dynamicScale;
-
-    accu1 <<= 1;
-    accu2 <<= 1;
-    accu1 += (real1 >> descale);
-    accu2 += (imag1 >> descale);
-    if (fPreWhitening) {
-      accu1 = scaleValueSaturate(fMultDiv2(accu1, preWhiteningGain),
-                                 preWhiteningGains_sf);
-      accu2 = scaleValueSaturate(fMultDiv2(accu2, preWhiteningGain),
-                                 preWhiteningGains_sf);
-    }
-    qmfBufferReal[i][hiBand] = accu1;
-    qmfBufferImag[i][hiBand] = accu2;
-  }
-}
-#endif /* #ifdef FUNCTION_LPPTRANSPOSER_func1 */
-
-#endif /* __arm__ */
diff --git a/libSBRdec/src/env_calc.cpp b/libSBRdec/src/env_calc.cpp
index 0b2f651..cefa612 100644
--- a/libSBRdec/src/env_calc.cpp
+++ b/libSBRdec/src/env_calc.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -664,7 +664,7 @@
         gain_sf[i] = mult_sf - total_power_low_sf + sf2;
         gain[i] = sqrtFixp_lookup(gain[i], &gain_sf[i]);
         if (gain_sf[i] < 0) {
-          gain[i] >>= -gain_sf[i];
+          gain[i] >>= fMin(DFRACT_BITS - 1, -gain_sf[i]);
           gain_sf[i] = 0;
         }
       } else {
@@ -683,11 +683,6 @@
 
     /* gain[i] = g_inter[i] */
     for (i = 0; i < nbSubsample; ++i) {
-      if (gain_sf[i] < 0) {
-        gain[i] >>= -gain_sf[i];
-        gain_sf[i] = 0;
-      }
-
       /* calculate: gain[i] = 1.0f + gamma * (gain[i] - 1.0f); */
       FIXP_DBL one = (FIXP_DBL)MAXVAL_DBL >>
                      gain_sf[i]; /* to substract this from gain[i] */
@@ -755,23 +750,15 @@
     int gain_adj_sf = gain_adj_2_sf;
 
     for (i = 0; i < nbSubsample; ++i) {
-      gain[i] = fMult(gain[i], gain_adj);
-      gain_sf[i] += gain_adj_sf;
-
-      /* limit gain */
-      if (gain_sf[i] > INTER_TES_SF_CHANGE) {
-        gain[i] = (FIXP_DBL)MAXVAL_DBL;
-        gain_sf[i] = INTER_TES_SF_CHANGE;
-      }
-    }
-
-    for (i = 0; i < nbSubsample; ++i) {
-      /* equalize gain[]'s scale factors */
-      gain[i] >>= INTER_TES_SF_CHANGE - gain_sf[i];
+      int gain_e = fMax(
+          fMin(gain_sf[i] + gain_adj_sf - INTER_TES_SF_CHANGE, DFRACT_BITS - 1),
+          -(DFRACT_BITS - 1));
+      FIXP_DBL gain_final = fMult(gain[i], gain_adj);
+      gain_final = scaleValueSaturate(gain_final, gain_e);
 
       for (j = lowSubband; j < highSubband; j++) {
-        qmfReal[startPos + i][j] = fMult(qmfReal[startPos + i][j], gain[i]);
-        qmfImag[startPos + i][j] = fMult(qmfImag[startPos + i][j], gain[i]);
+        qmfReal[startPos + i][j] = fMult(qmfReal[startPos + i][j], gain_final);
+        qmfImag[startPos + i][j] = fMult(qmfImag[startPos + i][j], gain_final);
       }
     }
   } else { /* gamma_idx == 0 */
@@ -1398,6 +1385,17 @@
     */
     noise_e = (start_pos < no_cols) ? adj_e : final_e;
 
+    if (start_pos >= no_cols) {
+      int diff = h_sbr_cal_env->filtBufferNoise_e - noise_e;
+      if (diff > 0) {
+        int s = getScalefactor(h_sbr_cal_env->filtBufferNoise, noSubbands);
+        if (diff > s) {
+          final_e += diff - s;
+          noise_e = final_e;
+        }
+      }
+    }
+
     /*
       Convert energies to amplitude levels
     */
@@ -2741,6 +2739,9 @@
             fMult(direct_ratio, noiseLevel[k]);
       }
 
+      smoothedNoise = fMax(fMin(smoothedNoise, (FIXP_DBL)(MAXVAL_DBL / 2)),
+                           (FIXP_DBL)(MINVAL_DBL / 2));
+
       /*
         The next 2 multiplications constitute the actual envelope adjustment
         of the signal and should be carried out with full accuracy
@@ -2930,6 +2931,9 @@
             fMult(direct_ratio, noiseLevel[k]);
       }
 
+      smoothedNoise = fMax(fMin(smoothedNoise, (FIXP_DBL)(MAXVAL_DBL / 2)),
+                           (FIXP_DBL)(MINVAL_DBL / 2));
+
       /*
         The next 2 multiplications constitute the actual envelope adjustment
         of the signal and should be carried out with full accuracy
diff --git a/libSBRdec/src/hbe.cpp b/libSBRdec/src/hbe.cpp
index d210bb6..f2452ea 100644
--- a/libSBRdec/src/hbe.cpp
+++ b/libSBRdec/src/hbe.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -1400,42 +1400,27 @@
 
   if (shift_ov != 0) {
     for (i = 0; i < HBE_MAX_OUT_SLOTS; i++) {
-      for (band = 0; band < QMF_SYNTH_CHANNELS; band++) {
-        if (shift_ov >= 0) {
-          hQmfTransposer->qmfHBEBufReal_F[i][band] <<= shift_ov;
-          hQmfTransposer->qmfHBEBufImag_F[i][band] <<= shift_ov;
-        } else {
-          hQmfTransposer->qmfHBEBufReal_F[i][band] >>= (-shift_ov);
-          hQmfTransposer->qmfHBEBufImag_F[i][band] >>= (-shift_ov);
-        }
-      }
-    }
-  }
-
-  if ((keepStatesSyncedMode == KEEP_STATES_SYNCED_OFF) && shift_ov != 0) {
-    for (i = timeStep * firstSlotOffsset; i < ov_len; i++) {
-      for (band = hQmfTransposer->startBand; band < hQmfTransposer->stopBand;
-           band++) {
-        if (shift_ov >= 0) {
-          ppQmfBufferOutReal_F[i][band] <<= shift_ov;
-          ppQmfBufferOutImag_F[i][band] <<= shift_ov;
-        } else {
-          ppQmfBufferOutReal_F[i][band] >>= (-shift_ov);
-          ppQmfBufferOutImag_F[i][band] >>= (-shift_ov);
-        }
-      }
+      scaleValuesSaturate(&hQmfTransposer->qmfHBEBufReal_F[i][0],
+                          QMF_SYNTH_CHANNELS, shift_ov);
+      scaleValuesSaturate(&hQmfTransposer->qmfHBEBufImag_F[i][0],
+                          QMF_SYNTH_CHANNELS, shift_ov);
     }
 
-    /* shift lpc filterstates */
-    for (i = 0; i < timeStep * firstSlotOffsset + LPC_ORDER; i++) {
-      for (band = 0; band < (64); band++) {
-        if (shift_ov >= 0) {
-          lpcFilterStatesReal[i][band] <<= shift_ov;
-          lpcFilterStatesImag[i][band] <<= shift_ov;
-        } else {
-          lpcFilterStatesReal[i][band] >>= (-shift_ov);
-          lpcFilterStatesImag[i][band] >>= (-shift_ov);
-        }
+    if (keepStatesSyncedMode == KEEP_STATES_SYNCED_OFF) {
+      int nBands =
+          fMax(0, hQmfTransposer->stopBand - hQmfTransposer->startBand);
+
+      for (i = timeStep * firstSlotOffsset; i < ov_len; i++) {
+        scaleValuesSaturate(&ppQmfBufferOutReal_F[i][hQmfTransposer->startBand],
+                            nBands, shift_ov);
+        scaleValuesSaturate(&ppQmfBufferOutImag_F[i][hQmfTransposer->startBand],
+                            nBands, shift_ov);
+      }
+
+      /* shift lpc filterstates */
+      for (i = 0; i < timeStep * firstSlotOffsset + LPC_ORDER; i++) {
+        scaleValuesSaturate(&lpcFilterStatesReal[i][0], (64), shift_ov);
+        scaleValuesSaturate(&lpcFilterStatesImag[i][0], (64), shift_ov);
       }
     }
   }
diff --git a/libSBRdec/src/lpp_tran.cpp b/libSBRdec/src/lpp_tran.cpp
index 93e1158..68a25bf 100644
--- a/libSBRdec/src/lpp_tran.cpp
+++ b/libSBRdec/src/lpp_tran.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -132,10 +132,6 @@
 
 #include "HFgen_preFlat.h"
 
-#if defined(__arm__)
-#include "arm/lpp_tran_arm.cpp"
-#endif
-
 #define LPC_SCALE_FACTOR 2
 
 /*!
@@ -220,19 +216,21 @@
                                       const FIXP_DBL *const lowBandReal,
                                       const int startSample,
                                       const int stopSample, const UCHAR hiBand,
-                                      const int dynamicScale, const int descale,
+                                      const int dynamicScale,
                                       const FIXP_SGL a0r, const FIXP_SGL a1r) {
-  FIXP_DBL accu1, accu2;
-  int i;
+  const int dynscale = fixMax(0, dynamicScale - 1) + 1;
+  const int rescale = -fixMin(0, dynamicScale - 1) + 1;
+  const int descale =
+      fixMin(DFRACT_BITS - 1, LPC_SCALE_FACTOR + dynamicScale + rescale);
 
-  for (i = 0; i < stopSample - startSample; i++) {
-    accu1 = fMultDiv2(a1r, lowBandReal[i]);
-    accu1 = (fMultDiv2(a0r, lowBandReal[i + 1]) + accu1);
-    accu1 = accu1 >> dynamicScale;
+  for (int i = 0; i < stopSample - startSample; i++) {
+    FIXP_DBL accu;
 
-    accu1 <<= 1;
-    accu2 = (lowBandReal[i + 2] >> descale);
-    qmfBufferReal[i + startSample][hiBand] = accu1 + accu2;
+    accu = fMultDiv2(a1r, lowBandReal[i]) + fMultDiv2(a0r, lowBandReal[i + 1]);
+    accu = (lowBandReal[i + 2] >> descale) + (accu >> dynscale);
+
+    qmfBufferReal[i + startSample][hiBand] =
+        SATURATE_LEFT_SHIFT(accu, rescale, DFRACT_BITS);
   }
 }
 
@@ -529,7 +527,7 @@
         if ((scale > 0) && (result >= (FIXP_DBL)MAXVAL_DBL >> scale)) {
           resetLPCCoeffs = 1;
         } else {
-          alphar[1] = FX_DBL2FX_SGL(scaleValue(result, scale));
+          alphar[1] = FX_DBL2FX_SGL(scaleValueSaturate(result, scale));
           if ((tmp < FL2FX_DBL(0.0f)) ^ (ac.det < FL2FX_DBL(0.0f))) {
             alphar[1] = -alphar[1];
           }
@@ -557,7 +555,7 @@
                scale)) {
             resetLPCCoeffs = 1;
           } else {
-            alphai[1] = FX_DBL2FX_SGL(scaleValue(result, scale));
+            alphai[1] = FX_DBL2FX_SGL(scaleValueSaturate(result, scale));
             if ((tmp < FL2FX_DBL(0.0f)) ^ (ac.det < FL2FX_DBL(0.0f))) {
               alphai[1] = -alphai[1];
             }
@@ -596,7 +594,7 @@
       } else {
         INT scale;
         FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale);
-        alphar[0] = FX_DBL2FX_SGL(scaleValue(result, scale + 1));
+        alphar[0] = FX_DBL2FX_SGL(scaleValueSaturate(result, scale + 1));
 
         if ((tmp > FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f)))
           alphar[0] = -alphar[0];
@@ -616,7 +614,7 @@
         } else {
           INT scale;
           FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale);
-          alphai[0] = FX_DBL2FX_SGL(scaleValue(result, scale + 1));
+          alphai[0] = FX_DBL2FX_SGL(scaleValueSaturate(result, scale + 1));
           if ((tmp > FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f)))
             alphai[0] = -alphai[0];
         }
@@ -659,7 +657,7 @@
           INT scale;
           FIXP_DBL result =
               fDivNorm(fixp_abs(ac.r01r), fixp_abs(ac.r11r), &scale);
-          k1 = scaleValue(result, scale);
+          k1 = scaleValueSaturate(result, scale);
 
           if (!((ac.r01r < FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f)))) {
             k1 = -k1;
@@ -771,52 +769,50 @@
       } else { /* bw <= 0 */
 
         if (!useLP) {
-          int descale =
-              fixMin(DFRACT_BITS - 1, (LPC_SCALE_FACTOR + dynamicScale));
-#ifdef FUNCTION_LPPTRANSPOSER_func1
-          lppTransposer_func1(
-              lowBandReal + LPC_ORDER + startSample,
-              lowBandImag + LPC_ORDER + startSample,
-              qmfBufferReal + startSample, qmfBufferImag + startSample,
-              stopSample - startSample, (int)hiBand, dynamicScale, descale, a0r,
-              a0i, a1r, a1i, fPreWhitening, preWhiteningGains[loBand],
-              preWhiteningGains_exp[loBand] + 1);
-#else
+          const int dynscale = fixMax(0, dynamicScale - 2) + 1;
+          const int rescale = -fixMin(0, dynamicScale - 2) + 1;
+          const int descale = fixMin(DFRACT_BITS - 1,
+                                     LPC_SCALE_FACTOR + dynamicScale + rescale);
+
           for (i = startSample; i < stopSample; i++) {
             FIXP_DBL accu1, accu2;
 
-            accu1 = (fMultDiv2(a0r, lowBandReal[LPC_ORDER + i - 1]) -
-                     fMultDiv2(a0i, lowBandImag[LPC_ORDER + i - 1]) +
-                     fMultDiv2(a1r, lowBandReal[LPC_ORDER + i - 2]) -
-                     fMultDiv2(a1i, lowBandImag[LPC_ORDER + i - 2])) >>
-                    dynamicScale;
-            accu2 = (fMultDiv2(a0i, lowBandReal[LPC_ORDER + i - 1]) +
-                     fMultDiv2(a0r, lowBandImag[LPC_ORDER + i - 1]) +
-                     fMultDiv2(a1i, lowBandReal[LPC_ORDER + i - 2]) +
-                     fMultDiv2(a1r, lowBandImag[LPC_ORDER + i - 2])) >>
-                    dynamicScale;
+            accu1 = ((fMultDiv2(a0r, lowBandReal[LPC_ORDER + i - 1]) -
+                      fMultDiv2(a0i, lowBandImag[LPC_ORDER + i - 1])) >>
+                     1) +
+                    ((fMultDiv2(a1r, lowBandReal[LPC_ORDER + i - 2]) -
+                      fMultDiv2(a1i, lowBandImag[LPC_ORDER + i - 2])) >>
+                     1);
+            accu2 = ((fMultDiv2(a0i, lowBandReal[LPC_ORDER + i - 1]) +
+                      fMultDiv2(a0r, lowBandImag[LPC_ORDER + i - 1])) >>
+                     1) +
+                    ((fMultDiv2(a1i, lowBandReal[LPC_ORDER + i - 2]) +
+                      fMultDiv2(a1r, lowBandImag[LPC_ORDER + i - 2])) >>
+                     1);
 
-            accu1 = (lowBandReal[LPC_ORDER + i] >> descale) + (accu1 << 1);
-            accu2 = (lowBandImag[LPC_ORDER + i] >> descale) + (accu2 << 1);
+            accu1 =
+                (lowBandReal[LPC_ORDER + i] >> descale) + (accu1 >> dynscale);
+            accu2 =
+                (lowBandImag[LPC_ORDER + i] >> descale) + (accu2 >> dynscale);
             if (fPreWhitening) {
-              accu1 = scaleValueSaturate(
+              qmfBufferReal[i][hiBand] = scaleValueSaturate(
                   fMultDiv2(accu1, preWhiteningGains[loBand]),
-                  preWhiteningGains_exp[loBand] + 1);
-              accu2 = scaleValueSaturate(
+                  preWhiteningGains_exp[loBand] + 1 + rescale);
+              qmfBufferImag[i][hiBand] = scaleValueSaturate(
                   fMultDiv2(accu2, preWhiteningGains[loBand]),
-                  preWhiteningGains_exp[loBand] + 1);
+                  preWhiteningGains_exp[loBand] + 1 + rescale);
+            } else {
+              qmfBufferReal[i][hiBand] =
+                  SATURATE_LEFT_SHIFT(accu1, rescale, DFRACT_BITS);
+              qmfBufferImag[i][hiBand] =
+                  SATURATE_LEFT_SHIFT(accu2, rescale, DFRACT_BITS);
             }
-            qmfBufferReal[i][hiBand] = accu1;
-            qmfBufferImag[i][hiBand] = accu2;
           }
-#endif
         } else {
           FDK_ASSERT(dynamicScale >= 0);
           calc_qmfBufferReal(
               qmfBufferReal, &(lowBandReal[LPC_ORDER + startSample - 2]),
-              startSample, stopSample, hiBand, dynamicScale,
-              fMin(DFRACT_BITS - 1, (LPC_SCALE_FACTOR + dynamicScale)), a0r,
-              a1r);
+              startSample, stopSample, hiBand, dynamicScale, a0r, a1r);
         }
       } /* bw <= 0 */
 
@@ -1066,7 +1062,7 @@
         if ((scale > 0) && (result >= (FIXP_DBL)MAXVAL_DBL >> scale)) {
           resetLPCCoeffs = 1;
         } else {
-          alphar[1] = FX_DBL2FX_SGL(scaleValue(result, scale));
+          alphar[1] = FX_DBL2FX_SGL(scaleValueSaturate(result, scale));
           if ((tmp < FL2FX_DBL(0.0f)) ^ (ac.det < FL2FX_DBL(0.0f))) {
             alphar[1] = -alphar[1];
           }
@@ -1092,7 +1088,7 @@
             (result >= /*FL2FXCONST_DBL(1.f)*/ (FIXP_DBL)MAXVAL_DBL >> scale)) {
           resetLPCCoeffs = 1;
         } else {
-          alphai[1] = FX_DBL2FX_SGL(scaleValue(result, scale));
+          alphai[1] = FX_DBL2FX_SGL(scaleValueSaturate(result, scale));
           if ((tmp < FL2FX_DBL(0.0f)) ^ (ac.det < FL2FX_DBL(0.0f))) {
             alphai[1] = -alphai[1];
           }
@@ -1121,7 +1117,7 @@
       } else {
         INT scale;
         FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale);
-        alphar[0] = FX_DBL2FX_SGL(scaleValue(result, scale + 1));
+        alphar[0] = FX_DBL2FX_SGL(scaleValueSaturate(result, scale + 1));
 
         if ((tmp > FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f)))
           alphar[0] = -alphar[0];
@@ -1140,7 +1136,7 @@
       } else {
         INT scale;
         FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale);
-        alphai[0] = FX_DBL2FX_SGL(scaleValue(result, scale + 1));
+        alphai[0] = FX_DBL2FX_SGL(scaleValueSaturate(result, scale + 1));
         if ((tmp > FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f))) {
           alphai[0] = -alphai[0];
         }
diff --git a/libSBRdec/src/sbr_dec.cpp b/libSBRdec/src/sbr_dec.cpp
index b1fb0da..919e9bb 100644
--- a/libSBRdec/src/sbr_dec.cpp
+++ b/libSBRdec/src/sbr_dec.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -713,7 +713,8 @@
 
   } else { /* (flags & SBRDEC_PS_DECODED) */
     INT sdiff;
-    INT scaleFactorHighBand, scaleFactorLowBand_ov, scaleFactorLowBand_no_ov;
+    INT scaleFactorHighBand, scaleFactorLowBand_ov, scaleFactorLowBand_no_ov,
+        outScalefactor, outScalefactorR, outScalefactorL;
 
     HANDLE_QMF_FILTER_BANK synQmf = &hSbrDec->qmfDomainOutCh->fb;
     HANDLE_QMF_FILTER_BANK synQmfRight = &hSbrDecRight->qmfDomainOutCh->fb;
@@ -744,7 +745,7 @@
       */
       FDK_ASSERT(hSbrDec->qmfDomainInCh->pGlobalConf->nBandsSynthesis <=
                  QMF_MAX_SYNTHESIS_BANDS);
-      qmfChangeOutScalefactor(synQmfRight, -(8));
+      synQmfRight->outScalefactor = synQmf->outScalefactor;
       FDKmemcpy(synQmfRight->FilterStates, synQmf->FilterStates,
                 9 * hSbrDec->qmfDomainInCh->pGlobalConf->nBandsSynthesis *
                     sizeof(FIXP_QSS));
@@ -788,9 +789,11 @@
       FDKmemcpy(&hSbrDecRight->sbrDrcChannel, &hSbrDec->sbrDrcChannel,
                 sizeof(SBRDEC_DRC_CHANNEL));
 
-      for (i = 0; i < synQmf->no_col; i++) { /* ----- no_col loop ----- */
+      outScalefactor = maxShift - (8);
+      outScalefactorL = outScalefactorR =
+          sbrInDataHeadroom + 1; /* +1: psDiffScale! (MPEG-PS) */
 
-        INT outScalefactorR, outScalefactorL;
+      for (i = 0; i < synQmf->no_col; i++) { /* ----- no_col loop ----- */
 
         /* qmf timeslot of right channel */
         FIXP_DBL *rQmfReal = pWorkBuffer;
@@ -815,27 +818,20 @@
                   ? scaleFactorLowBand_ov
                   : scaleFactorLowBand_no_ov,
               scaleFactorHighBand, synQmf->lsb, synQmf->usb);
-
-          outScalefactorL = outScalefactorR =
-              1 + sbrInDataHeadroom; /* psDiffScale! (MPEG-PS) */
         }
 
         sbrDecoder_drcApplySlot(/* right channel */
                                 &hSbrDecRight->sbrDrcChannel, rQmfReal,
                                 rQmfImag, i, synQmfRight->no_col, maxShift);
 
-        outScalefactorR += maxShift;
-
         sbrDecoder_drcApplySlot(/* left channel */
                                 &hSbrDec->sbrDrcChannel, *(pLowBandReal + i),
                                 *(pLowBandImag + i), i, synQmf->no_col,
                                 maxShift);
 
-        outScalefactorL += maxShift;
-
         if (!(flags & SBRDEC_SKIP_QMF_SYN)) {
-          qmfChangeOutScalefactor(synQmf, -(8));
-          qmfChangeOutScalefactor(synQmfRight, -(8));
+          qmfChangeOutScalefactor(synQmf, outScalefactor);
+          qmfChangeOutScalefactor(synQmfRight, outScalefactor);
 
           qmfSynthesisFilteringSlot(
               synQmfRight, rQmfReal, /* QMF real buffer */
diff --git a/libSBRdec/src/sbrdec_drc.cpp b/libSBRdec/src/sbrdec_drc.cpp
index 2d73f32..089d046 100644
--- a/libSBRdec/src/sbrdec_drc.cpp
+++ b/libSBRdec/src/sbrdec_drc.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -233,14 +233,19 @@
     if (hDrcData->winSequenceCurr != 2) { /* long window */
       int j = col + (numQmfSubSamples >> 1);
 
-      if (hDrcData->drcInterpolationSchemeCurr == 0) {
-        INT k = (frameLenFlag) ? 0x4444445 : 0x4000000;
+      if (j < winBorderToColMap[15]) {
+        if (hDrcData->drcInterpolationSchemeCurr == 0) {
+          INT k = (frameLenFlag) ? 0x4444445 : 0x4000000;
 
-        alphaValue = (FIXP_DBL)(j * k);
-      } else {
-        if (j >= (int)winBorderToColMap[hDrcData->drcInterpolationSchemeCurr]) {
-          alphaValue = (FIXP_DBL)MAXVAL_DBL;
+          alphaValue = (FIXP_DBL)(j * k);
+        } else {
+          if (j >=
+              (int)winBorderToColMap[hDrcData->drcInterpolationSchemeCurr]) {
+            alphaValue = (FIXP_DBL)MAXVAL_DBL;
+          }
         }
+      } else {
+        alphaValue = (FIXP_DBL)MAXVAL_DBL;
       }
     } else { /* short windows */
       shortDrc = 1;
@@ -254,14 +259,19 @@
     if (hDrcData->winSequenceNext != 2) { /* next: long window */
       int j = col - (numQmfSubSamples >> 1);
 
-      if (hDrcData->drcInterpolationSchemeNext == 0) {
-        INT k = (frameLenFlag) ? 0x4444445 : 0x4000000;
+      if (j < winBorderToColMap[15]) {
+        if (hDrcData->drcInterpolationSchemeNext == 0) {
+          INT k = (frameLenFlag) ? 0x4444445 : 0x4000000;
 
-        alphaValue = (FIXP_DBL)(j * k);
-      } else {
-        if (j >= (int)winBorderToColMap[hDrcData->drcInterpolationSchemeNext]) {
-          alphaValue = (FIXP_DBL)MAXVAL_DBL;
+          alphaValue = (FIXP_DBL)(j * k);
+        } else {
+          if (j >=
+              (int)winBorderToColMap[hDrcData->drcInterpolationSchemeNext]) {
+            alphaValue = (FIXP_DBL)MAXVAL_DBL;
+          }
         }
+      } else {
+        alphaValue = (FIXP_DBL)MAXVAL_DBL;
       }
 
       fact_mag = hDrcData->nextFact_mag;
@@ -289,14 +299,19 @@
     if (hDrcData->winSequenceNext != 2) { /* long window */
       int j = col - (numQmfSubSamples >> 1);
 
-      if (hDrcData->drcInterpolationSchemeNext == 0) {
-        INT k = (frameLenFlag) ? 0x4444445 : 0x4000000;
+      if (j < winBorderToColMap[15]) {
+        if (hDrcData->drcInterpolationSchemeNext == 0) {
+          INT k = (frameLenFlag) ? 0x4444445 : 0x4000000;
 
-        alphaValue = (FIXP_DBL)(j * k);
-      } else {
-        if (j >= (int)winBorderToColMap[hDrcData->drcInterpolationSchemeNext]) {
-          alphaValue = (FIXP_DBL)MAXVAL_DBL;
+          alphaValue = (FIXP_DBL)(j * k);
+        } else {
+          if (j >=
+              (int)winBorderToColMap[hDrcData->drcInterpolationSchemeNext]) {
+            alphaValue = (FIXP_DBL)MAXVAL_DBL;
+          }
         }
+      } else {
+        alphaValue = (FIXP_DBL)MAXVAL_DBL;
       }
     } else { /* short windows */
       shortDrc = 1;
diff --git a/libSBRdec/src/sbrdec_freq_sca.cpp b/libSBRdec/src/sbrdec_freq_sca.cpp
index e187656..daa3554 100644
--- a/libSBRdec/src/sbrdec_freq_sca.cpp
+++ b/libSBRdec/src/sbrdec_freq_sca.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -765,9 +765,6 @@
   sbrdecUpdateLoRes(hFreq->freqBandTable[0], &nBandsLo, hFreq->freqBandTable[1],
                     nBandsHi);
 
-  hFreq->nSfb[0] = nBandsLo;
-  hFreq->nSfb[1] = nBandsHi;
-
   /* Check index to freqBandTable[0] */
   if (!(nBandsLo > 0) ||
       (nBandsLo > (((hHeaderData->numberOfAnalysisBands == 16)
@@ -777,6 +774,9 @@
     return SBRDEC_UNSUPPORTED_CONFIG;
   }
 
+  hFreq->nSfb[0] = nBandsLo;
+  hFreq->nSfb[1] = nBandsHi;
+
   lsb = hFreq->freqBandTable[0][0];
   usb = hFreq->freqBandTable[0][nBandsLo];
 
@@ -814,15 +814,15 @@
 
     if (intTemp == 0) intTemp = 1;
 
+    if (intTemp > MAX_NOISE_COEFFS) {
+      return SBRDEC_UNSUPPORTED_CONFIG;
+    }
+
     hFreq->nNfb = intTemp;
   }
 
   hFreq->nInvfBands = hFreq->nNfb;
 
-  if (hFreq->nNfb > MAX_NOISE_COEFFS) {
-    return SBRDEC_UNSUPPORTED_CONFIG;
-  }
-
   /* Get noise bands */
   sbrdecDownSampleLoRes(hFreq->freqBandTableNoise, hFreq->nNfb,
                         hFreq->freqBandTable[0], nBandsLo);
diff --git a/libSBRdec/src/sbrdecoder.cpp b/libSBRdec/src/sbrdecoder.cpp
index b101a4a..7718695 100644
--- a/libSBRdec/src/sbrdecoder.cpp
+++ b/libSBRdec/src/sbrdecoder.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -961,8 +961,10 @@
 
           /* Set sync state UPSAMPLING for the corresponding slot.
              This switches off bitstream parsing until a new header arrives. */
-          hSbrHeader->syncState = UPSAMPLING;
-          hSbrHeader->status |= SBRDEC_HDR_STAT_UPDATE;
+          if (hSbrHeader->syncState != SBR_NOT_INITIALIZED) {
+            hSbrHeader->syncState = UPSAMPLING;
+            hSbrHeader->status |= SBRDEC_HDR_STAT_UPDATE;
+          }
         }
       }
     } break;
@@ -1371,7 +1373,9 @@
       }
       if (headerStatus == HEADER_ERROR) {
         /* Corrupt SBR info data, do not decode and switch to UPSAMPLING */
-        hSbrHeader->syncState = UPSAMPLING;
+        hSbrHeader->syncState = hSbrHeader->syncState > UPSAMPLING
+                                    ? UPSAMPLING
+                                    : hSbrHeader->syncState;
         fDoDecodeSbrData = 0;
         sbrHeaderPresent = 0;
       }
@@ -1610,7 +1614,9 @@
       /* No valid SBR payload available, hence switch to upsampling (in all
        * headers) */
       for (hdrIdx = 0; hdrIdx < ((1) + 1); hdrIdx += 1) {
-        self->sbrHeader[elementIndex][hdrIdx].syncState = UPSAMPLING;
+        if (self->sbrHeader[elementIndex][hdrIdx].syncState > UPSAMPLING) {
+          self->sbrHeader[elementIndex][hdrIdx].syncState = UPSAMPLING;
+        }
       }
     } else {
       /* Move frame pointer to the next slot which is up to be decoded/applied
diff --git a/libSBRenc/src/env_est.cpp b/libSBRenc/src/env_est.cpp
index 0eb8425..cc8780a 100644
--- a/libSBRenc/src/env_est.cpp
+++ b/libSBRenc/src/env_est.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -1267,6 +1267,7 @@
     sbrExtrEnv->pre_transient_info[1] = ed->transient_info[1]; /* tran_flag */
     hEnvChan->encEnvData.noOfEnvelopes = ed->nEnvelopes =
         ed->frame_info->nEnvelopes; /* number of envelopes of current frame */
+    hEnvChan->encEnvData.currentAmpResFF = (AMP_RES)h_con->initAmpResFF;
 
     /*
       Check if the current frame is divided into one envelope only. If so, set
@@ -1274,8 +1275,9 @@
     */
     if ((hEnvChan->encEnvData.hSbrBSGrid->frameClass == FIXFIX) &&
         (ed->nEnvelopes == 1)) {
+      AMP_RES currentAmpResFF = SBR_AMP_RES_1_5;
       if (h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) {
-        /* Note: global_tonaliy_float_value ==
+        /* Note: global_tonality_float_value ==
            ((float)hEnvChan->encEnvData.global_tonality/((INT64)(1)<<(31-(19+2)))/0.524288*(2.0/3.0)));
                  threshold_float_value ==
            ((float)h_con->thresholdAmpResFF_m/((INT64)(1)<<(31-(h_con->thresholdAmpResFF_e)))/0.524288*(2.0/3.0)));
@@ -1289,14 +1291,13 @@
         } else {
           hEnvChan->encEnvData.currentAmpResFF = SBR_AMP_RES_3_0;
         }
-      } else
-        hEnvChan->encEnvData.currentAmpResFF = SBR_AMP_RES_1_5;
+        currentAmpResFF = hEnvChan->encEnvData.currentAmpResFF;
+      }
 
-      if (hEnvChan->encEnvData.currentAmpResFF !=
-          hEnvChan->encEnvData.init_sbr_amp_res) {
+      if (currentAmpResFF != hEnvChan->encEnvData.init_sbr_amp_res) {
         FDKsbrEnc_InitSbrHuffmanTables(
             &hEnvChan->encEnvData, &hEnvChan->sbrCodeEnvelope,
-            &hEnvChan->sbrCodeNoiseFloor, hEnvChan->encEnvData.currentAmpResFF);
+            &hEnvChan->sbrCodeNoiseFloor, currentAmpResFF);
       }
     } else {
       if (sbrHeaderData->sbr_amp_res != hEnvChan->encEnvData.init_sbr_amp_res) {
@@ -1355,6 +1356,13 @@
     }
   }
 
+  if (h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY &&
+      stereoMode == SBR_SWITCH_LRC &&
+      h_envChan[0]->encEnvData.currentAmpResFF !=
+          h_envChan[1]->encEnvData.currentAmpResFF) {
+    stereoMode = SBR_LEFT_RIGHT;
+  }
+
   /*
     Extract envelope of current frame.
   */
diff --git a/libSBRenc/src/sbr_encoder.cpp b/libSBRenc/src/sbr_encoder.cpp
index c1e083f..c3da072 100644
--- a/libSBRenc/src/sbr_encoder.cpp
+++ b/libSBRenc/src/sbr_encoder.cpp
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
 Software License for The Fraunhofer FDK AAC Codec Library for Android
 
-© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+© Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
 Forschung e.V. All rights reserved.
 
  1.    INTRODUCTION
@@ -1450,8 +1450,6 @@
                                     params->deltaTAcrossFrames, 0, 0))
     return (1);
 
-  sbrConfigData->initAmpResFF = params->init_amp_res_FF;
-
   if (FDKsbrEnc_InitSbrHuffmanTables(&hEnv->encEnvData, &hEnv->sbrCodeEnvelope,
                                      &hEnv->sbrCodeNoiseFloor,
                                      sbrHeaderData->sbr_amp_res))
@@ -1749,6 +1747,7 @@
     hSbrElement->sbrHeaderData.sbr_data_extra = 1;
 
   hSbrElement->sbrHeaderData.sbr_amp_res = (AMP_RES)params->amp_res;
+  hSbrElement->sbrConfigData.initAmpResFF = params->init_amp_res_FF;
 
   /* header_extra_1 */
   hSbrElement->sbrHeaderData.freqScale = params->freqScale;