Merge "[LSC] Add LOCAL_LICENSE_KINDS to frameworks/av" into rvc-qpr-dev-plus-aosp
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index a88021a..b9ee2e6 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -492,7 +492,10 @@
     // We used to not report changes to these keys to the client.
     const static std::set<std::string> sIgnoredKeys({
             KEY_BIT_RATE,
+            KEY_FRAME_RATE,
             KEY_MAX_BIT_RATE,
+            KEY_MAX_WIDTH,
+            KEY_MAX_HEIGHT,
             "csd-0",
             "csd-1",
             "csd-2",
@@ -1201,6 +1204,8 @@
     Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
     const std::unique_ptr<Config> &config = *configLocked;
 
+    config->queryConfiguration(comp);
+
     mCallback->onComponentConfigured(config->mInputFormat, config->mOutputFormat);
 }
 
@@ -1706,7 +1711,9 @@
     {
         Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
         const std::unique_ptr<Config> &config = *configLocked;
+        sp<AMessage> outputFormat = config->mOutputFormat;
         config->queryConfiguration(comp);
+        RevertOutputFormatIfNeeded(outputFormat, config->mOutputFormat);
     }
 
     (void)mChannel->start(nullptr, nullptr, [&]{
diff --git a/media/libeffects/lvm/benchmarks/lvm_benchmark.cpp b/media/libeffects/lvm/benchmarks/lvm_benchmark.cpp
index e2e4a85..bdb66d8 100644
--- a/media/libeffects/lvm/benchmarks/lvm_benchmark.cpp
+++ b/media/libeffects/lvm/benchmarks/lvm_benchmark.cpp
@@ -53,8 +53,6 @@
 
 constexpr size_t kNumChMasks = std::size(kChMasks);
 constexpr int kSampleRate = 44100;
-// TODO(b/131240940) Remove once effects are updated to produce mono output
-constexpr size_t kMinOutputChannelCount = 2;
 
 /*******************************************************************
  * A test result running on Pixel 3 for comparison.
@@ -64,6 +62,10 @@
  * -----------------------------------------------------
  * Benchmark           Time             CPU   Iterations
  * -----------------------------------------------------
+ * BM_LVM/1/0       52123 ns        51971 ns        13437
+ * BM_LVM/1/1       75397 ns        75175 ns         9382
+ * BM_LVM/1/2       40253 ns        40140 ns        17418
+ * BM_LVM/1/3       19918 ns        19860 ns        35230
  * BM_LVM/2/0       62455 ns        62283 ns        11214
  * BM_LVM/2/1      110086 ns       109751 ns         6350
  * BM_LVM/2/2       44017 ns        43890 ns        15982
@@ -203,7 +205,7 @@
 
     // Run the test
     for (auto _ : state) {
-        std::vector<float> output(kFrameCount * std::max(channelCount, kMinOutputChannelCount));
+        std::vector<float> output(kFrameCount * channelCount);
 
         benchmark::DoNotOptimize(input.data());
         benchmark::DoNotOptimize(output.data());
@@ -224,8 +226,7 @@
 }
 
 static void LVMArgs(benchmark::internal::Benchmark* b) {
-    // TODO(b/131240940) Test single channel once effects are updated to process mono data
-    for (int i = 2; i <= kNumChMasks; i++) {
+    for (int i = FCC_1; i <= kNumChMasks; i++) {
         for (int j = 0; j < kNumEffectUuids; ++j) {
             b->Args({i, j});
         }
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.cpp b/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.cpp
index d860ad0..3fc9e95 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.cpp
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.cpp
@@ -277,8 +277,8 @@
     /*
      * Create biquad instance
      */
-    pInstance->pHPFBiquad.reset(new android::audio_utils::BiquadFilter<LVM_FLOAT>(
-            (FCC_1 == pParams->NrChannels) ? FCC_2 : pParams->NrChannels));
+    pInstance->pHPFBiquad.reset(
+            new android::audio_utils::BiquadFilter<LVM_FLOAT>(pParams->NrChannels));
 
     /*
      * Update the filters
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.cpp b/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.cpp
index 8c62e71..0969053 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.cpp
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Process.cpp
@@ -79,11 +79,7 @@
         const LVM_UINT16 NrFrames)  // updated to use samples = frames * channels.
 {
     LVDBE_Instance_t* pInstance = (LVDBE_Instance_t*)hInstance;
-
-    /*Extract number of Channels info*/
-    // Mono passed in as stereo
-    const LVM_INT32 NrChannels =
-            pInstance->Params.NrChannels == 1 ? 2 : pInstance->Params.NrChannels;
+    const LVM_INT32 NrChannels = pInstance->Params.NrChannels;
     const LVM_INT32 NrSamples = NrChannels * NrFrames;
 
     /* Space to store DBE path computation */
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.cpp b/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.cpp
index fbb0fe1..1d913d7 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.cpp
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Buffers.cpp
@@ -487,10 +487,6 @@
 void LVM_BufferUnmanagedOut(LVM_Handle_t hInstance, LVM_UINT16* pNumSamples) {
     LVM_Instance_t* pInstance = (LVM_Instance_t*)hInstance;
     LVM_INT16 NumChannels = pInstance->NrChannels;
-    if (NumChannels == 1) {
-        /* Mono input is processed as stereo by LVM module */
-        NumChannels = 2;
-    }
 #undef NrFrames
 #define NrFrames (*pNumSamples)  // alias for clarity
 
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Process.cpp b/media/libeffects/lvm/lib/Bundle/src/LVM_Process.cpp
index 82c0e68..20058a1 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Process.cpp
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Process.cpp
@@ -111,19 +111,6 @@
     }
 
     /*
-     * Convert from Mono if necessary
-     */
-    if (pInstance->Params.SourceFormat == LVM_MONO) {
-        MonoTo2I_Float(pInData,                /* Source */
-                       pOutData,               /* Destination */
-                       (LVM_INT16)NumSamples); /* Number of input samples */
-        pInput = pOutData;
-        pToProcess = pOutData;
-        NrChannels = 2;
-        ChMask = AUDIO_CHANNEL_OUT_STEREO;
-    }
-
-    /*
      * Process the data with managed buffers
      */
     while (SampleCount != 0) {
diff --git a/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h b/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h
index 281d941..18de85b 100644
--- a/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h
+++ b/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h
@@ -29,17 +29,18 @@
 void Copy_Float(const LVM_FLOAT* src, LVM_FLOAT* dst, LVM_INT16 n);
 void Copy_Float_Mc_Stereo(const LVM_FLOAT* src, LVM_FLOAT* dst, LVM_INT16 NrFrames,
                           LVM_INT32 NrChannels);
-void Copy_Float_Stereo_Mc(const LVM_FLOAT* src, LVM_FLOAT* StereoOut, LVM_FLOAT* dst,
+void Copy_Float_Stereo_Mc(const LVM_FLOAT* src, const LVM_FLOAT* StereoOut, LVM_FLOAT* dst,
                           LVM_INT16 NrFrames, LVM_INT32 NrChannels);
 
 void Mult3s_Float(const LVM_FLOAT* src, const LVM_FLOAT val, LVM_FLOAT* dst, LVM_INT16 n);
 
-void DelayMix_Float(const LVM_FLOAT* src, /* Source 1, to be delayed */
-                    LVM_FLOAT* delay,     /* Delay buffer */
-                    LVM_INT16 size,       /* Delay size */
-                    LVM_FLOAT* dst,       /* Source/destination */
-                    LVM_INT16* pOffset,   /* Delay offset */
-                    LVM_INT16 n);         /* Number of stereo samples */
+void DelayMix_Float(const LVM_FLOAT* src,  /* Source 1, to be delayed */
+                    LVM_FLOAT* delay,      /* Delay buffer */
+                    LVM_INT16 size,        /* Delay size */
+                    LVM_FLOAT* dst,        /* Source/destination */
+                    LVM_INT16* pOffset,    /* Delay offset */
+                    LVM_INT16 n,           /* Number of stereo samples */
+                    LVM_INT32 NrChannels); /* Number of channels */
 void Add2_Sat_Float(const LVM_FLOAT* src, LVM_FLOAT* dst, LVM_INT16 n);
 void Mac3s_Sat_Float(const LVM_FLOAT* src, const LVM_FLOAT val, LVM_FLOAT* dst, LVM_INT16 n);
 
diff --git a/media/libeffects/lvm/lib/Common/src/Copy_16.cpp b/media/libeffects/lvm/lib/Common/src/Copy_16.cpp
index 7046a94..1fe7470 100644
--- a/media/libeffects/lvm/lib/Common/src/Copy_16.cpp
+++ b/media/libeffects/lvm/lib/Common/src/Copy_16.cpp
@@ -51,25 +51,32 @@
 }
 
 // Merge a multichannel source with stereo contained in StereoOut, to dst.
-void Copy_Float_Stereo_Mc(const LVM_FLOAT* src, LVM_FLOAT* StereoOut, LVM_FLOAT* dst,
+void Copy_Float_Stereo_Mc(const LVM_FLOAT* src, const LVM_FLOAT* StereoOut, LVM_FLOAT* dst,
                           LVM_INT16 NrFrames, /* Number of frames*/
                           LVM_INT32 NrChannels) {
     LVM_INT16 ii, jj;
 
-    // pack dst with stereo information of StereoOut
-    // together with the upper channels of src.
-    StereoOut += 2 * (NrFrames - 1);
-    dst += NrChannels * (NrFrames - 1);
-    src += NrChannels * (NrFrames - 1);
-    for (ii = NrFrames; ii != 0; ii--) {
-        dst[1] = StereoOut[1];
-        dst[0] = StereoOut[0];  // copy 1 before 0 is required for NrChannels == 3.
-        for (jj = 2; jj < NrChannels; jj++) {
-            dst[jj] = src[jj];
+    if (NrChannels >= FCC_2) {
+        // pack dst with stereo information of StereoOut
+        // together with the upper channels of src.
+        StereoOut += 2 * (NrFrames - 1);
+        dst += NrChannels * (NrFrames - 1);
+        src += NrChannels * (NrFrames - 1);
+
+        for (ii = NrFrames; ii != 0; ii--) {
+            dst[1] = StereoOut[1];
+            dst[0] = StereoOut[0];  // copy 1 before 0 is required for NrChannels == 3.
+            for (jj = FCC_2; jj < NrChannels; jj++) {
+                dst[jj] = src[jj];
+            }
+            dst -= NrChannels;
+            src -= NrChannels;
+            StereoOut -= 2;
         }
-        dst -= NrChannels;
-        src -= NrChannels;
-        StereoOut -= 2;
+    } else {
+        Copy_Float((const LVM_FLOAT*)StereoOut, /* Source */
+                   (LVM_FLOAT*)dst,             /* Destination */
+                   (LVM_INT16)NrFrames);        /* Number of frames */
     }
 }
 /**********************************************************************************/
diff --git a/media/libeffects/lvm/lib/Common/src/DelayMix_16x16.cpp b/media/libeffects/lvm/lib/Common/src/DelayMix_16x16.cpp
index d2537eb..a346636 100644
--- a/media/libeffects/lvm/lib/Common/src/DelayMix_16x16.cpp
+++ b/media/libeffects/lvm/lib/Common/src/DelayMix_16x16.cpp
@@ -26,34 +26,50 @@
                     LVM_INT16 size,       /* Delay size */
                     LVM_FLOAT* dst,       /* Source/destination */
                     LVM_INT16* pOffset,   /* Delay offset */
-                    LVM_INT16 n)          /* Number of stereo samples */
+                    LVM_INT16 n,          /* Number of samples */
+                    LVM_INT32 NrChannels) /* Number of channels */
 {
     LVM_INT16 i;
     LVM_INT16 Offset = *pOffset;
     LVM_FLOAT temp;
 
     for (i = 0; i < n; i++) {
-        /* Left channel */
-        temp = (LVM_FLOAT)((LVM_FLOAT)(*dst + (LVM_FLOAT)delay[Offset]) / 2.0f);
-        *dst = temp;
-        dst++;
+        if (NrChannels == FCC_1) {
+            temp = (LVM_FLOAT)(*dst + (LVM_FLOAT)delay[Offset]) / 2.0f;
+            *dst = temp;
+            dst++;
 
-        delay[Offset] = *src;
-        Offset++;
-        src++;
+            delay[Offset] = *src;
+            Offset++;
+            src++;
 
-        /* Right channel */
-        temp = (LVM_FLOAT)((LVM_FLOAT)(*dst - (LVM_FLOAT)delay[Offset]) / 2.0f);
-        *dst = temp;
-        dst++;
+            /* Make the reverb delay buffer a circular buffer */
+            if (Offset >= size) {
+                Offset = 0;
+            }
+        } else {
+            /* Left channel */
+            temp = (LVM_FLOAT)(*dst + (LVM_FLOAT)delay[Offset]) / 2.0f;
+            *dst = temp;
+            dst++;
 
-        delay[Offset] = *src;
-        Offset++;
-        src++;
+            delay[Offset] = *src;
+            Offset++;
+            src++;
 
-        /* Make the reverb delay buffer a circular buffer */
-        if (Offset >= size) {
-            Offset = 0;
+            /* Right channel */
+            temp = (LVM_FLOAT)(*dst - (LVM_FLOAT)delay[Offset]) / 2.0f;
+            *dst = temp;
+            dst++;
+
+            delay[Offset] = *src;
+            Offset++;
+            src++;
+
+            /* Make the reverb delay buffer a circular buffer */
+            if (Offset >= size) {
+                Offset = 0;
+            }
         }
     }
 
diff --git a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.cpp b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.cpp
index 58bc06e..b0aa172 100644
--- a/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.cpp
+++ b/media/libeffects/lvm/lib/Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.cpp
@@ -56,10 +56,11 @@
     Mix_Private_FLOAT_st* pInstance[NrChannels];
 
     if (audio_channel_mask_get_representation(ChMask) == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
-        for (int i = 0; i < 2; i++) {
+        int loopLimit = (NrChannels == FCC_1) ? NrChannels : FCC_2;
+        for (int i = 0; i < loopLimit; i++) {
             pInstance[i] = pMixPrivInst[i];
         }
-        for (int i = 2; i < NrChannels; i++) {
+        for (int i = loopLimit; i < NrChannels; i++) {
             pInstance[i] = pMixPrivInst[2];
         }
     } else {
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Control.cpp b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Control.cpp
index 3ab6afb..7e5caed 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Control.cpp
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Control.cpp
@@ -311,9 +311,8 @@
     /*
      * Create biquad instance
      */
-    pInstance->eqBiquad.resize(
-            pParams->NBands, android::audio_utils::BiquadFilter<LVM_FLOAT>(
-                                     (FCC_1 == pParams->NrChannels) ? FCC_2 : pParams->NrChannels));
+    pInstance->eqBiquad.resize(pParams->NBands,
+                               android::audio_utils::BiquadFilter<LVM_FLOAT>(pParams->NrChannels));
     LVEQNB_ClearFilterHistory(pInstance);
 
     if (bChange || modeChange) {
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.cpp b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.cpp
index 8992803..b177dd4 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.cpp
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Process.cpp
@@ -62,10 +62,7 @@
         LVEQNB_Handle_t hInstance, const LVM_FLOAT* pInData, LVM_FLOAT* pOutData,
         const LVM_UINT16 NrFrames) {  // updated to use samples = frames * channels.
     LVEQNB_Instance_t* pInstance = (LVEQNB_Instance_t*)hInstance;
-
-    // Mono passed in as stereo
-    const LVM_INT32 NrChannels =
-            pInstance->Params.NrChannels == 1 ? 2 : pInstance->Params.NrChannels;
+    const LVM_INT32 NrChannels = pInstance->Params.NrChannels;
     const LVM_INT32 NrSamples = NrChannels * NrFrames;
 
     /* Check for NULL pointers */
@@ -104,7 +101,6 @@
                  * Check if band is non-zero dB gain
                  */
                 if (pInstance->pBandDefinitions[i].Gain != 0) {
-
                     /*
                      * Select single or double precision as required
                      */
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.cpp
index efca27d..f805fca 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_BypassMix.cpp
@@ -200,6 +200,8 @@
                                       LVM_UINT16 NumSamples) {
     LVCS_Instance_t* pInstance = (LVCS_Instance_t*)hInstance;
     LVCS_BypassMix_t* pConfig = (LVCS_BypassMix_t*)&pInstance->BypassMix;
+    LVM_UINT16 destNumSamples =
+            (pInstance->Params.NrChannels == FCC_1) ? NumSamples : FCC_2 * NumSamples;
 
     /*
      * Check if the bypass mixer is enabled
@@ -209,12 +211,12 @@
          * Apply the bypass mix
          */
         LVC_MixSoft_2St_D16C31_SAT(&pConfig->Mixer_Instance, pProcessed, (LVM_FLOAT*)pUnprocessed,
-                                   pOutData, (LVM_INT16)(2 * NumSamples));
+                                   pOutData, (LVM_INT16)destNumSamples);
         /*
          * Apply output gain correction shift
          */
         Shift_Sat_Float((LVM_INT16)pConfig->Output_Shift, (LVM_FLOAT*)pOutData,
-                        (LVM_FLOAT*)pOutData, (LVM_INT16)(2 * NumSamples)); /* Left and right*/
+                        (LVM_FLOAT*)pOutData, (LVM_INT16)destNumSamples);
     }
 
     return (LVCS_SUCCESS);
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Control.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Control.cpp
index 8f88986..89f2f3b 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Control.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Control.cpp
@@ -180,7 +180,9 @@
         if (pInstance->bInOperatingModeTransition != LVM_TRUE) {
             pInstance->bTimerDone = LVM_FALSE;
             pInstance->TimerParams.TimeInMs =
-                    (LVM_INT16)(((pInstance->Reverberation.DelaySize << 2) /
+                    (LVM_INT16)(((pInstance->Params.NrChannels == FCC_1
+                                          ? pInstance->Reverberation.DelaySize << 3
+                                          : pInstance->Reverberation.DelaySize << 2) /
                                  pInstance->TimerParams.SamplingRate) +
                                 1);
             LVM_Timer_Init(&pInstance->TimerInstance, &pInstance->TimerParams);
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp
index c8ad94e..1746786 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp
@@ -74,7 +74,8 @@
                 pEqualiserCoefTable[Offset].A0, pEqualiserCoefTable[Offset].A1,
                 pEqualiserCoefTable[Offset].A2, -(pEqualiserCoefTable[Offset].B1),
                 -(pEqualiserCoefTable[Offset].B2)};
-        pInstance->pEqBiquad.reset(new android::audio_utils::BiquadFilter<LVM_FLOAT>(FCC_2, coefs));
+        pInstance->pEqBiquad.reset(new android::audio_utils::BiquadFilter<LVM_FLOAT>(
+                (pParams->NrChannels == FCC_1) ? FCC_1 : FCC_2, coefs));
     }
 
     return (LVCS_SUCCESS);
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.cpp
index d18f2c3..6af0f75 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.cpp
@@ -75,16 +75,6 @@
     LVM_INT32 channels = pInstance->Params.NrChannels;
 #define NrFrames NumSamples  // alias for clarity
 
-    /*In case of mono processing, stereo input is created from mono
-     *and stored in pInData before applying any of the effects.
-     *However we do not update the value pInstance->Params.NrChannels
-     *at this point.
-     *So to treat the pInData as stereo we are setting channels to 2
-     */
-    if (channels == 1) {
-        channels = 2;
-    }
-
     pScratch = (LVM_FLOAT*)pInstance->pScratch;
 
     /*
@@ -97,11 +87,16 @@
      */
     pInput = pScratch + (2 * NrFrames);
     pStIn = pScratch + ((LVCS_SCRATCHBUFFERS - 2) * NrFrames);
-    /* The first two channel data is extracted from the input data and
-     * copied into pInput buffer
-     */
-    Copy_Float_Mc_Stereo((LVM_FLOAT*)pInData, (LVM_FLOAT*)pInput, NrFrames, channels);
-    Copy_Float((LVM_FLOAT*)pInput, (LVM_FLOAT*)pStIn, (LVM_INT16)(2 * NrFrames));
+    if (channels == FCC_1) {
+        Copy_Float((LVM_FLOAT*)pInData, (LVM_FLOAT*)pInput, (LVM_INT16)NrFrames);
+        Copy_Float((LVM_FLOAT*)pInput, (LVM_FLOAT*)pStIn, (LVM_INT16)NrFrames);
+    } else {
+        /* The first two channel data is extracted from the input data and
+         * copied into pInput buffer
+         */
+        Copy_Float_Mc_Stereo((LVM_FLOAT*)pInData, (LVM_FLOAT*)pInput, NrFrames, channels);
+        Copy_Float((LVM_FLOAT*)pInput, (LVM_FLOAT*)pStIn, (LVM_INT16)(FCC_2 * NrFrames));
+    }
     /*
      * Call the stereo enhancer
      */
@@ -172,10 +167,10 @@
     LVCS_ReturnStatus_en err;
     /*Extract number of Channels info*/
     LVM_INT32 channels = pInstance->Params.NrChannels;
+    LVM_UINT16 destNumSamples = (channels == FCC_1) ? NumSamples : FCC_2 * NumSamples;
+    LVM_INT32 compGainInterval =
+            (channels == FCC_1) ? LVCS_COMPGAINFRAME : FCC_2 * LVCS_COMPGAINFRAME;
 #define NrFrames NumSamples  // alias for clarity
-    if (channels == 1) {
-        channels = 2;
-    }
     /*
      * Check the number of samples is not too large
      */
@@ -227,7 +222,7 @@
 
             if (NumSamples < LVCS_COMPGAINFRAME) {
                 NonLinComp_Float(Gain, /* Compressor gain setting */
-                                 pStereoOut, pStereoOut, (LVM_INT32)(2 * NrFrames));
+                                 pStereoOut, pStereoOut, (LVM_INT32)destNumSamples);
             } else {
                 LVM_FLOAT GainStep;
                 LVM_FLOAT FinalGain;
@@ -266,12 +261,15 @@
 
                     if (SampleToProcess > LVCS_COMPGAINFRAME) {
                         NonLinComp_Float(Gain, /* Compressor gain setting */
-                                         pOutPtr, pOutPtr, (LVM_INT32)(2 * LVCS_COMPGAINFRAME));
-                        pOutPtr += (2 * LVCS_COMPGAINFRAME);
+                                         pOutPtr, pOutPtr, compGainInterval);
+                        pOutPtr += compGainInterval;
                         SampleToProcess = (LVM_INT16)(SampleToProcess - LVCS_COMPGAINFRAME);
                     } else {
                         NonLinComp_Float(Gain, /* Compressor gain setting */
-                                         pOutPtr, pOutPtr, (LVM_INT32)(2 * SampleToProcess));
+                                         pOutPtr, pOutPtr,
+                                         (channels == FCC_1)
+                                                 ? (LVM_INT32)(SampleToProcess)
+                                                 : (LVM_INT32)(FCC_2 * SampleToProcess));
                         SampleToProcess = 0;
                     }
                 }
@@ -297,7 +295,7 @@
                 LVM_Timer(&pInstance->TimerInstance, (LVM_INT16)NumSamples);
             }
         }
-        Copy_Float_Stereo_Mc(pInData, pStereoOut, pOutData, NrFrames, channels);
+        Copy_Float_Stereo_Mc(pInData, (const LVM_FLOAT*)pStereoOut, pOutData, NrFrames, channels);
     } else {
         if (pInData != pOutData) {
             /*
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp
index 15acda9..12b1dc3 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp
@@ -65,7 +65,6 @@
     LVCS_ReverbGenerator_t* pConfig = (LVCS_ReverbGenerator_t*)&pInstance->Reverberation;
     const BiquadA012B12CoefsSP_t* pReverbCoefTable;
 
-
     /*
      * Initialise the delay and filters if:
      *  - the sample rate has changed
@@ -79,7 +78,8 @@
          */
         Delay = (LVM_UINT16)LVCS_StereoDelayCS[(LVM_UINT16)pParams->SampleRate];
 
-        pConfig->DelaySize = (LVM_INT16)(2 * Delay);
+        pConfig->DelaySize =
+                (pParams->NrChannels == FCC_1) ? (LVM_INT16)Delay : (LVM_INT16)(FCC_2 * Delay);
         pConfig->DelayOffset = 0;
         LoadConst_Float(0,                                      /* Value */
                         (LVM_FLOAT*)&pConfig->StereoSamples[0], /* Destination */
@@ -95,8 +95,8 @@
                 pReverbCoefTable[Offset].A0, pReverbCoefTable[Offset].A1,
                 pReverbCoefTable[Offset].A2, -(pReverbCoefTable[Offset].B1),
                 -(pReverbCoefTable[Offset].B2)};
-        pInstance->pRevBiquad.reset(
-                new android::audio_utils::BiquadFilter<LVM_FLOAT>(FCC_2, coefs));
+        pInstance->pRevBiquad.reset(new android::audio_utils::BiquadFilter<LVM_FLOAT>(
+                (pParams->NrChannels == FCC_1) ? FCC_1 : FCC_2, coefs));
 
         /*
          * Setup the mixer
@@ -155,6 +155,9 @@
     LVCS_Instance_t* pInstance = (LVCS_Instance_t*)hInstance;
     LVCS_ReverbGenerator_t* pConfig = (LVCS_ReverbGenerator_t*)&pInstance->Reverberation;
     LVM_FLOAT* pScratch;
+    LVM_INT32 NumChannels = pInstance->Params.NrChannels;
+    LVM_UINT16 destNumSamples =
+            (pInstance->Params.NrChannels == FCC_1) ? NumSamples : FCC_2 * NumSamples;
 
     pScratch = (LVM_FLOAT*)pInstance->pScratch;
 
@@ -165,9 +168,9 @@
         /*
          * Reverb not required so just copy the data
          */
-        Copy_Float((LVM_FLOAT*)pInData,          /* Source */
-                   (LVM_FLOAT*)pOutData,         /* Destination */
-                   (LVM_INT16)(2 * NumSamples)); /* Left and right */
+        Copy_Float((LVM_FLOAT*)pInData,        /* Source */
+                   (LVM_FLOAT*)pOutData,       /* Destination */
+                   (LVM_INT16)destNumSamples); /* Number of frames */
     }
 
     /*
@@ -188,9 +191,9 @@
         /*
          * Copy the input data to the scratch memory
          */
-        Copy_Float((LVM_FLOAT*)pInData,          /* Source */
-                   (LVM_FLOAT*)pScratch,         /* Destination */
-                   (LVM_INT16)(2 * NumSamples)); /* Left and right */
+        Copy_Float((LVM_FLOAT*)pInData,        /* Source */
+                   (LVM_FLOAT*)pScratch,       /* Destination */
+                   (LVM_INT16)destNumSamples); /* Number of frames */
 
         /*
          * Filter the data
@@ -198,13 +201,13 @@
         pInstance->pRevBiquad->process(pScratch, pScratch, NumSamples);
 
         Mult3s_Float((LVM_FLOAT*)pScratch, pConfig->ReverbLevel, (LVM_FLOAT*)pScratch,
-                     (LVM_INT16)(2 * NumSamples));
+                     (LVM_INT16)destNumSamples); /* Number of frames */
 
         /*
          * Apply the delay mix
          */
         DelayMix_Float((LVM_FLOAT*)pScratch, &pConfig->StereoSamples[0], pConfig->DelaySize,
-                       pOutData, &pConfig->DelayOffset, (LVM_INT16)NumSamples);
+                       pOutData, &pConfig->DelayOffset, (LVM_INT16)NumSamples, NumChannels);
     }
 
     return (LVCS_SUCCESS);
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp
index 00bb26c..e3ff604 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp
@@ -55,7 +55,6 @@
     LVCS_Instance_t* pInstance = (LVCS_Instance_t*)hInstance;
     const BiquadA012B12CoefsSP_t* pSESideCoefs;
 
-
     /*
      * If the sample rate or speaker type has changed update the filters
      */
@@ -129,6 +128,8 @@
     LVCS_StereoEnhancer_t* pConfig = (LVCS_StereoEnhancer_t*)&pInstance->StereoEnhancer;
     LVM_FLOAT* pScratch;
     pScratch = (LVM_FLOAT*)pInstance->pScratch;
+    LVM_INT32 NumChannels = pInstance->Params.NrChannels;
+    LVM_UINT16 destNumSamples = (NumChannels == FCC_1) ? NumSamples : FCC_2 * NumSamples;
     /*
      * Check if the Stereo Enhancer is enabled
      */
@@ -136,7 +137,12 @@
         /*
          * Convert from stereo to middle and side
          */
-        From2iToMS_Float(pInData, pScratch, pScratch + NumSamples, (LVM_INT16)NumSamples);
+        if (NumChannels == 1) {
+            // Copy same input to scratch as Middle data
+            Copy_Float((LVM_FLOAT*)pInData, (LVM_FLOAT*)pScratch, (LVM_INT16)NumSamples);
+        } else {
+            From2iToMS_Float(pInData, pScratch, pScratch + NumSamples, (LVM_INT16)NumSamples);
+        }
 
         /*
          * Apply filter to the middle signal
@@ -159,18 +165,23 @@
                                               NumSamples);
         }
 
-        /*
-         * Convert from middle and side to stereo
-         */
-        MSTo2i_Sat_Float(pScratch, pScratch + NumSamples, pOutData, (LVM_INT16)NumSamples);
+        if (NumChannels == 1) {
+            // Copy processed Middle data from scratch to pOutData
+            Copy_Float((LVM_FLOAT*)pScratch, (LVM_FLOAT*)pOutData, (LVM_INT16)NumSamples);
+        } else {
+            /*
+             * Convert from middle and side to stereo
+             */
+            MSTo2i_Sat_Float(pScratch, pScratch + NumSamples, pOutData, (LVM_INT16)NumSamples);
+        }
 
     } else {
         /*
          * The stereo enhancer is disabled so just copy the data
          */
-        Copy_Float((LVM_FLOAT*)pInData,          /* Source */
-                   (LVM_FLOAT*)pOutData,         /* Destination */
-                   (LVM_INT16)(2 * NumSamples)); /* Left and right */
+        Copy_Float((LVM_FLOAT*)pInData,        /* Source */
+                   (LVM_FLOAT*)pOutData,       /* Destination */
+                   (LVM_INT16)destNumSamples); /* Number of frames */
     }
 
     return (LVCS_SUCCESS);
diff --git a/media/libeffects/lvm/tests/Android.bp b/media/libeffects/lvm/tests/Android.bp
index f5ff597..639af4d 100644
--- a/media/libeffects/lvm/tests/Android.bp
+++ b/media/libeffects/lvm/tests/Android.bp
@@ -10,6 +10,26 @@
 }
 
 cc_test {
+    name: "EffectBundleTest",
+    vendor: true,
+    gtest: true,
+    host_supported: true,
+    test_suites: ["device-tests"],
+    srcs: ["EffectBundleTest.cpp"],
+    static_libs: [
+        "libaudioutils",
+        "libbundlewrapper",
+        "libmusicbundle",
+    ],
+    shared_libs: [
+        "liblog",
+    ],
+    header_libs: [
+        "libhardware_headers",
+    ],
+}
+
+cc_test {
     name: "lvmtest",
     host_supported: false,
     proprietary: true,
diff --git a/media/libeffects/lvm/tests/EffectBundleTest.cpp b/media/libeffects/lvm/tests/EffectBundleTest.cpp
new file mode 100644
index 0000000..aae09de
--- /dev/null
+++ b/media/libeffects/lvm/tests/EffectBundleTest.cpp
@@ -0,0 +1,335 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <array>
+#include <audio_utils/channels.h>
+#include <audio_utils/primitives.h>
+#include <climits>
+#include <cstdlib>
+#include <gtest/gtest.h>
+#include <hardware/audio_effect.h>
+#include <log/log.h>
+#include <random>
+#include <system/audio.h>
+#include <vector>
+
+extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
+
+// Corresponds to SNR for 1 bit difference between two int16_t signals
+constexpr float kSNRThreshold = 90.308998;
+
+// Update isBassBoost, if the order of effects is updated
+constexpr effect_uuid_t kEffectUuids[] = {
+        // NXP SW BassBoost
+        {0x8631f300, 0x72e2, 0x11df, 0xb57e, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        // NXP SW Virtualizer
+        {0x1d4033c0, 0x8557, 0x11df, 0x9f2d, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        // NXP SW Equalizer
+        {0xce772f20, 0x847d, 0x11df, 0xbb17, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        // NXP SW Volume
+        {0x119341a0, 0x8469, 0x11df, 0x81f9, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+};
+
+static bool isBassBoost(const effect_uuid_t* uuid) {
+    // Update this, if the order of effects in kEffectUuids is updated
+    return uuid == &kEffectUuids[0];
+}
+
+constexpr size_t kNumEffectUuids = std::size(kEffectUuids);
+
+constexpr audio_channel_mask_t kChMasks[] = {
+        AUDIO_CHANNEL_OUT_MONO,          AUDIO_CHANNEL_OUT_STEREO,
+        AUDIO_CHANNEL_OUT_2POINT1,       AUDIO_CHANNEL_OUT_2POINT0POINT2,
+        AUDIO_CHANNEL_OUT_QUAD,          AUDIO_CHANNEL_OUT_QUAD_BACK,
+        AUDIO_CHANNEL_OUT_QUAD_SIDE,     AUDIO_CHANNEL_OUT_SURROUND,
+        AUDIO_CHANNEL_INDEX_MASK_4,      AUDIO_CHANNEL_OUT_2POINT1POINT2,
+        AUDIO_CHANNEL_OUT_3POINT0POINT2, AUDIO_CHANNEL_OUT_PENTA,
+        AUDIO_CHANNEL_INDEX_MASK_5,      AUDIO_CHANNEL_OUT_3POINT1POINT2,
+        AUDIO_CHANNEL_OUT_5POINT1,       AUDIO_CHANNEL_OUT_5POINT1_BACK,
+        AUDIO_CHANNEL_OUT_5POINT1_SIDE,  AUDIO_CHANNEL_INDEX_MASK_6,
+        AUDIO_CHANNEL_OUT_6POINT1,       AUDIO_CHANNEL_INDEX_MASK_7,
+        AUDIO_CHANNEL_OUT_5POINT1POINT2, AUDIO_CHANNEL_OUT_7POINT1,
+        AUDIO_CHANNEL_INDEX_MASK_8,      AUDIO_CHANNEL_INDEX_MASK_9,
+        AUDIO_CHANNEL_INDEX_MASK_10,     AUDIO_CHANNEL_INDEX_MASK_11,
+        AUDIO_CHANNEL_INDEX_MASK_12,     AUDIO_CHANNEL_INDEX_MASK_13,
+        AUDIO_CHANNEL_INDEX_MASK_14,     AUDIO_CHANNEL_INDEX_MASK_15,
+        AUDIO_CHANNEL_INDEX_MASK_16,     AUDIO_CHANNEL_INDEX_MASK_17,
+        AUDIO_CHANNEL_INDEX_MASK_18,     AUDIO_CHANNEL_INDEX_MASK_19,
+        AUDIO_CHANNEL_INDEX_MASK_20,     AUDIO_CHANNEL_INDEX_MASK_21,
+        AUDIO_CHANNEL_INDEX_MASK_22,     AUDIO_CHANNEL_INDEX_MASK_23,
+        AUDIO_CHANNEL_INDEX_MASK_24,
+};
+
+constexpr size_t kNumChMasks = std::size(kChMasks);
+
+constexpr size_t kSampleRates[] = {8000,  11025, 12000, 16000, 22050,  24000, 32000,
+                                   44100, 48000, 88200, 96000, 176400, 192000};
+
+constexpr size_t kNumSampleRates = std::size(kSampleRates);
+
+constexpr size_t kFrameCounts[] = {4, 2048};
+
+constexpr size_t kNumFrameCounts = std::size(kFrameCounts);
+
+constexpr size_t kLoopCounts[] = {1, 4};
+
+constexpr size_t kNumLoopCounts = std::size(kLoopCounts);
+
+class EffectBundleHelper {
+  public:
+    EffectBundleHelper(const effect_uuid_t* uuid, size_t chMask, size_t sampleRate,
+                       size_t frameCount, size_t loopCount)
+        : mUuid(uuid),
+          mChMask(chMask),
+          mChannelCount(audio_channel_count_from_out_mask(mChMask)),
+          mSampleRate(sampleRate),
+          mFrameCount(frameCount),
+          mLoopCount(loopCount) {}
+    void createEffect();
+    void releaseEffect();
+    void configEffect();
+    void process(float* input, float* output);
+
+  private:
+    const effect_uuid_t* mUuid;
+    const size_t mChMask;
+    const size_t mChannelCount;
+    const size_t mSampleRate;
+    const size_t mFrameCount;
+    const size_t mLoopCount;
+    effect_handle_t mEffectHandle{};
+};
+
+void EffectBundleHelper::createEffect() {
+    int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(mUuid, 1, 1, &mEffectHandle);
+    ASSERT_EQ(status, 0) << "create_effect returned an error " << status << "\n";
+}
+
+void EffectBundleHelper::releaseEffect() {
+    int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(mEffectHandle);
+    ASSERT_EQ(status, 0) << "release_effect returned an error " << status << "\n";
+}
+
+void EffectBundleHelper::configEffect() {
+    effect_config_t config{};
+    config.inputCfg.samplingRate = config.outputCfg.samplingRate = mSampleRate;
+    config.inputCfg.channels = config.outputCfg.channels = mChMask;
+    config.inputCfg.format = config.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
+
+    int reply = 0;
+    uint32_t replySize = sizeof(reply);
+    int status = (*mEffectHandle)
+                         ->command(mEffectHandle, EFFECT_CMD_SET_CONFIG, sizeof(effect_config_t),
+                                   &config, &replySize, &reply);
+    ASSERT_EQ(status, 0) << "command returned an error " << status << "\n";
+    ASSERT_EQ(reply, 0) << "command reply non zero " << reply << "\n";
+
+    status = (*mEffectHandle)
+                     ->command(mEffectHandle, EFFECT_CMD_ENABLE, 0, nullptr, &replySize, &reply);
+    ASSERT_EQ(status, 0) << "command enable returned an error " << status << "\n";
+    ASSERT_EQ(reply, 0) << "command reply non zero " << reply << "\n";
+}
+
+void EffectBundleHelper::process(float* input, float* output) {
+    audio_buffer_t inBuffer = {.frameCount = mFrameCount, .f32 = input};
+    audio_buffer_t outBuffer = {.frameCount = mFrameCount, .f32 = output};
+    for (size_t i = 0; i < mLoopCount; i++) {
+        int status = (*mEffectHandle)->process(mEffectHandle, &inBuffer, &outBuffer);
+        ASSERT_EQ(status, 0) << "process returned an error " << status << "\n";
+
+        inBuffer.f32 += mFrameCount * mChannelCount;
+        outBuffer.f32 += mFrameCount * mChannelCount;
+    }
+}
+
+typedef std::tuple<int, int, int, int, int> SingleEffectTestParam;
+class SingleEffectTest : public ::testing::TestWithParam<SingleEffectTestParam> {
+  public:
+    SingleEffectTest()
+        : mChMask(kChMasks[std::get<0>(GetParam())]),
+          mChannelCount(audio_channel_count_from_out_mask(mChMask)),
+          mSampleRate(kSampleRates[std::get<1>(GetParam())]),
+          mFrameCount(kFrameCounts[std::get<2>(GetParam())]),
+          mLoopCount(kLoopCounts[std::get<3>(GetParam())]),
+          mTotalFrameCount(mFrameCount * mLoopCount),
+          mUuid(&kEffectUuids[std::get<4>(GetParam())]) {}
+
+    const size_t mChMask;
+    const size_t mChannelCount;
+    const size_t mSampleRate;
+    const size_t mFrameCount;
+    const size_t mLoopCount;
+    const size_t mTotalFrameCount;
+    const effect_uuid_t* mUuid;
+};
+
+// Tests applying a single effect
+TEST_P(SingleEffectTest, SimpleProcess) {
+    SCOPED_TRACE(testing::Message()
+                 << "chMask: " << mChMask << " sampleRate: " << mSampleRate
+                 << " frameCount: " << mFrameCount << " loopCount: " << mLoopCount);
+
+    EffectBundleHelper effect(mUuid, mChMask, mSampleRate, mFrameCount, mLoopCount);
+
+    ASSERT_NO_FATAL_FAILURE(effect.createEffect());
+    ASSERT_NO_FATAL_FAILURE(effect.configEffect());
+
+    // Initialize input buffer with deterministic pseudo-random values
+    std::vector<float> input(mTotalFrameCount * mChannelCount);
+    std::vector<float> output(mTotalFrameCount * mChannelCount);
+    std::minstd_rand gen(mChMask);
+    std::uniform_real_distribution<> dis(-1.0f, 1.0f);
+    for (auto& in : input) {
+        in = dis(gen);
+    }
+    ASSERT_NO_FATAL_FAILURE(effect.process(input.data(), output.data()));
+    ASSERT_NO_FATAL_FAILURE(effect.releaseEffect());
+}
+
+INSTANTIATE_TEST_SUITE_P(EffectBundleTestAll, SingleEffectTest,
+                         ::testing::Combine(::testing::Range(0, (int)kNumChMasks),
+                                            ::testing::Range(0, (int)kNumSampleRates),
+                                            ::testing::Range(0, (int)kNumFrameCounts),
+                                            ::testing::Range(0, (int)kNumLoopCounts),
+                                            ::testing::Range(0, (int)kNumEffectUuids)));
+
+typedef std::tuple<int, int, int, int> SingleEffectComparisonTestParam;
+class SingleEffectComparisonTest
+    : public ::testing::TestWithParam<SingleEffectComparisonTestParam> {
+  public:
+    SingleEffectComparisonTest()
+        : mSampleRate(kSampleRates[std::get<0>(GetParam())]),
+          mFrameCount(kFrameCounts[std::get<1>(GetParam())]),
+          mLoopCount(kLoopCounts[std::get<2>(GetParam())]),
+          mTotalFrameCount(mFrameCount * mLoopCount),
+          mUuid(&kEffectUuids[std::get<3>(GetParam())]) {}
+
+    const size_t mSampleRate;
+    const size_t mFrameCount;
+    const size_t mLoopCount;
+    const size_t mTotalFrameCount;
+    const effect_uuid_t* mUuid;
+};
+
+template <typename T>
+float computeSnr(const T* ref, const T* tst, size_t count) {
+    double signal{};
+    double noise{};
+
+    for (size_t i = 0; i < count; ++i) {
+        const double value(ref[i]);
+        const double diff(tst[i] - value);
+        signal += value * value;
+        noise += diff * diff;
+    }
+    // Initialized to a value greater than kSNRThreshold to handle
+    // cases where ref and tst match exactly
+    float snr = kSNRThreshold + 1.0f;
+    if (signal > 0.0f && noise > 0.0f) {
+        snr = 10.f * log(signal / noise);
+    }
+    return snr;
+}
+
+// Compares first two channels in multi-channel output to stereo output when same effect is applied
+TEST_P(SingleEffectComparisonTest, SimpleProcess) {
+    SCOPED_TRACE(testing::Message() << " sampleRate: " << mSampleRate << " frameCount: "
+                                    << mFrameCount << " loopCount: " << mLoopCount);
+
+    // Initialize mono input buffer with deterministic pseudo-random values
+    std::vector<float> monoInput(mTotalFrameCount);
+
+    std::minstd_rand gen(mSampleRate);
+    std::uniform_real_distribution<> dis(-1.0f, 1.0f);
+    for (auto& in : monoInput) {
+        in = dis(gen);
+    }
+
+    // Generate stereo by repeating mono channel data
+    std::vector<float> stereoInput(mTotalFrameCount * FCC_2);
+    adjust_channels(monoInput.data(), FCC_1, stereoInput.data(), FCC_2, sizeof(float),
+                    mTotalFrameCount * sizeof(float) * FCC_1);
+
+    // Apply effect on stereo channels
+    EffectBundleHelper stereoEffect(mUuid, AUDIO_CHANNEL_OUT_STEREO, mSampleRate, mFrameCount,
+                                    mLoopCount);
+
+    ASSERT_NO_FATAL_FAILURE(stereoEffect.createEffect());
+    ASSERT_NO_FATAL_FAILURE(stereoEffect.configEffect());
+
+    std::vector<float> stereoOutput(mTotalFrameCount * FCC_2);
+    ASSERT_NO_FATAL_FAILURE(stereoEffect.process(stereoInput.data(), stereoOutput.data()));
+    ASSERT_NO_FATAL_FAILURE(stereoEffect.releaseEffect());
+
+    // Convert stereo float data to stereo int16_t to be used as reference
+    std::vector<int16_t> stereoRefI16(mTotalFrameCount * FCC_2);
+    memcpy_to_i16_from_float(stereoRefI16.data(), stereoOutput.data(), mTotalFrameCount * FCC_2);
+
+    for (size_t chMask : kChMasks) {
+        size_t channelCount = audio_channel_count_from_out_mask(chMask);
+        EffectBundleHelper testEffect(mUuid, chMask, mSampleRate, mFrameCount, mLoopCount);
+
+        ASSERT_NO_FATAL_FAILURE(testEffect.createEffect());
+        ASSERT_NO_FATAL_FAILURE(testEffect.configEffect());
+
+        std::vector<float> testInput(mTotalFrameCount * channelCount);
+
+        // Repeat mono channel data to all the channels
+        // adjust_channels() zero fills channels > 2, hence can't be used here
+        for (size_t i = 0; i < mTotalFrameCount; ++i) {
+            auto* fp = &testInput[i * channelCount];
+            std::fill(fp, fp + channelCount, monoInput[i]);
+        }
+
+        std::vector<float> testOutput(mTotalFrameCount * channelCount);
+        ASSERT_NO_FATAL_FAILURE(testEffect.process(testInput.data(), testOutput.data()));
+        ASSERT_NO_FATAL_FAILURE(testEffect.releaseEffect());
+
+        // Extract first two channels
+        std::vector<float> stereoTestOutput(mTotalFrameCount * FCC_2);
+        adjust_channels(testOutput.data(), channelCount, stereoTestOutput.data(), FCC_2,
+                        sizeof(float), mTotalFrameCount * sizeof(float) * channelCount);
+
+        // Convert the test data to int16_t
+        std::vector<int16_t> stereoTestI16(mTotalFrameCount * FCC_2);
+        memcpy_to_i16_from_float(stereoTestI16.data(), stereoTestOutput.data(),
+                                 mTotalFrameCount * FCC_2);
+
+        if (isBassBoost(mUuid)) {
+            // SNR must be above the threshold
+            float snr = computeSnr<int16_t>(stereoRefI16.data(), stereoTestI16.data(),
+                                            mTotalFrameCount * FCC_2);
+            ASSERT_GT(snr, kSNRThreshold) << "SNR " << snr << "is lower than " << kSNRThreshold;
+        } else {
+            ASSERT_EQ(0,
+                      memcmp(stereoRefI16.data(), stereoTestI16.data(), mTotalFrameCount * FCC_2))
+                    << "First two channels do not match with stereo output \n";
+        }
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(EffectBundleTestAll, SingleEffectComparisonTest,
+                         ::testing::Combine(::testing::Range(0, (int)kNumSampleRates),
+                                            ::testing::Range(0, (int)kNumFrameCounts),
+                                            ::testing::Range(0, (int)kNumLoopCounts),
+                                            ::testing::Range(0, (int)kNumEffectUuids)));
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    ALOGV("Test result = %d\n", status);
+    return status;
+}
diff --git a/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh b/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh
index 7b0ff5e..df7ca5a 100755
--- a/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh
+++ b/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh
@@ -102,6 +102,11 @@
                     ((++error_count))
                 fi
 
+                # Do not compare cases where -vcBal is in flags and chMask is 0 (due to
+                # stereo computation)
+                if [[ $flags == *"-vcBal:"* ]] && [[ $chMask -eq 0 ]]; then
+                    continue
+                fi
 
                 # two channel files should be identical to higher channel
                 # computation (first 2 channels).
diff --git a/media/libeffects/lvm/tests/lvmtest.cpp b/media/libeffects/lvm/tests/lvmtest.cpp
index b044e16..e484a1a 100644
--- a/media/libeffects/lvm/tests/lvmtest.cpp
+++ b/media/libeffects/lvm/tests/lvmtest.cpp
@@ -489,19 +489,11 @@
     const int ioChannelCount = plvmConfigParams->fChannels;
     const int ioFrameSize = ioChannelCount * sizeof(short);  // file load size
     const int maxChannelCount = std::max(channelCount, ioChannelCount);
-    /*
-     * Mono input will be converted to 2 channels internally in the process call
-     * by copying the same data into the second channel.
-     * Hence when channelCount is 1, output buffer should be allocated for
-     * 2 channels. The memAllocChCount takes care of allocation of sufficient
-     * memory for the output buffer.
-     */
-    const int memAllocChCount = (channelCount == 1 ? 2 : channelCount);
 
     std::vector<short> in(frameLength * maxChannelCount);
     std::vector<short> out(frameLength * maxChannelCount);
     std::vector<float> floatIn(frameLength * channelCount);
-    std::vector<float> floatOut(frameLength * memAllocChCount);
+    std::vector<float> floatOut(frameLength * channelCount);
 
     int frameCounter = 0;
     while (fread(in.data(), ioFrameSize, frameLength, finp) == (size_t)frameLength) {
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 8a4b17c..c89c023 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 
 #include <android/IDataSource.h>
+#include <binder/IPCThreadState.h>
 #include <binder/Parcel.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <media/AudioResamplerPublic.h>
@@ -34,59 +35,37 @@
 
 using media::VolumeShaper;
 
-enum {
-    DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
-    SET_DATA_SOURCE_URL,
-    SET_DATA_SOURCE_FD,
-    SET_DATA_SOURCE_STREAM,
-    SET_DATA_SOURCE_CALLBACK,
-    SET_DATA_SOURCE_RTP,
-    SET_BUFFERING_SETTINGS,
-    GET_BUFFERING_SETTINGS,
-    PREPARE_ASYNC,
-    START,
-    STOP,
-    IS_PLAYING,
-    SET_PLAYBACK_SETTINGS,
-    GET_PLAYBACK_SETTINGS,
-    SET_SYNC_SETTINGS,
-    GET_SYNC_SETTINGS,
-    PAUSE,
-    SEEK_TO,
-    GET_CURRENT_POSITION,
-    GET_DURATION,
-    RESET,
-    NOTIFY_AT,
-    SET_AUDIO_STREAM_TYPE,
-    SET_LOOPING,
-    SET_VOLUME,
-    INVOKE,
-    SET_METADATA_FILTER,
-    GET_METADATA,
-    SET_AUX_EFFECT_SEND_LEVEL,
-    ATTACH_AUX_EFFECT,
-    SET_VIDEO_SURFACETEXTURE,
-    SET_PARAMETER,
-    GET_PARAMETER,
-    SET_RETRANSMIT_ENDPOINT,
-    GET_RETRANSMIT_ENDPOINT,
-    SET_NEXT_PLAYER,
-    APPLY_VOLUME_SHAPER,
-    GET_VOLUME_SHAPER_STATE,
-    // Modular DRM
-    PREPARE_DRM,
-    RELEASE_DRM,
-    // AudioRouting
-    SET_OUTPUT_DEVICE,
-    GET_ROUTED_DEVICE_ID,
-    ENABLE_AUDIO_DEVICE_CALLBACK,
-};
-
 // ModDrm helpers
-static void readVector(const Parcel& reply, Vector<uint8_t>& vector) {
-    uint32_t size = reply.readUint32();
-    vector.insertAt((size_t)0, size);
-    reply.read(vector.editArray(), size);
+static status_t readVector(const Parcel& reply, Vector<uint8_t>& vector) {
+    uint32_t size = 0;
+    status_t status = reply.readUint32(&size);
+    if (status == OK) {
+        status = size <= reply.dataAvail() ? OK : BAD_VALUE;
+    }
+    if (status == OK) {
+        status = vector.insertAt((size_t) 0, size) >= 0 ? OK : NO_MEMORY;
+    }
+    if (status == OK) {
+        status = reply.read(vector.editArray(), size);
+    }
+    if (status != OK) {
+        char errorMsg[100];
+        char buganizerId[] = "173720767";
+        snprintf(errorMsg,
+                sizeof(errorMsg),
+                "%s: failed to read array. Size: %d, status: %d.",
+                __func__,
+                size,
+                status);
+        android_errorWriteWithInfoLog(
+                /* safetyNet tag= */ 0x534e4554,
+                buganizerId,
+                IPCThreadState::self()->getCallingUid(),
+                errorMsg,
+                strlen(errorMsg));
+        ALOGE("%s (b/%s)", errorMsg, buganizerId);
+    }
+    return status;
 }
 
 static void writeVector(Parcel& data, Vector<uint8_t> const& vector) {
@@ -977,8 +956,10 @@
             uint8_t uuid[16] = {};
             data.read(uuid, sizeof(uuid));
             Vector<uint8_t> drmSessionId;
-            readVector(data, drmSessionId);
-
+            status_t status = readVector(data, drmSessionId);
+            if (status != OK) {
+              return status;
+            }
             uint32_t result = prepareDrm(uuid, drmSessionId);
             reply->writeInt32(result);
             return OK;
diff --git a/media/libmedia/include/media/IMediaPlayer.h b/media/libmedia/include/media/IMediaPlayer.h
index 3548a1e..28684d1 100644
--- a/media/libmedia/include/media/IMediaPlayer.h
+++ b/media/libmedia/include/media/IMediaPlayer.h
@@ -137,6 +137,56 @@
     virtual status_t        setOutputDevice(audio_port_handle_t deviceId) = 0;
     virtual status_t        getRoutedDeviceId(audio_port_handle_t *deviceId) = 0;
     virtual status_t        enableAudioDeviceCallback(bool enabled) = 0;
+protected:
+
+    friend class IMediaPlayerTest;
+    enum {
+        DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
+        SET_DATA_SOURCE_URL,
+        SET_DATA_SOURCE_FD,
+        SET_DATA_SOURCE_STREAM,
+        SET_DATA_SOURCE_CALLBACK,
+        SET_DATA_SOURCE_RTP,
+        SET_BUFFERING_SETTINGS,
+        GET_BUFFERING_SETTINGS,
+        PREPARE_ASYNC,
+        START,
+        STOP,
+        IS_PLAYING,
+        SET_PLAYBACK_SETTINGS,
+        GET_PLAYBACK_SETTINGS,
+        SET_SYNC_SETTINGS,
+        GET_SYNC_SETTINGS,
+        PAUSE,
+        SEEK_TO,
+        GET_CURRENT_POSITION,
+        GET_DURATION,
+        RESET,
+        NOTIFY_AT,
+        SET_AUDIO_STREAM_TYPE,
+        SET_LOOPING,
+        SET_VOLUME,
+        INVOKE,
+        SET_METADATA_FILTER,
+        GET_METADATA,
+        SET_AUX_EFFECT_SEND_LEVEL,
+        ATTACH_AUX_EFFECT,
+        SET_VIDEO_SURFACETEXTURE,
+        SET_PARAMETER,
+        GET_PARAMETER,
+        SET_RETRANSMIT_ENDPOINT,
+        GET_RETRANSMIT_ENDPOINT,
+        SET_NEXT_PLAYER,
+        APPLY_VOLUME_SHAPER,
+        GET_VOLUME_SHAPER_STATE,
+        // Modular DRM
+        PREPARE_DRM,
+        RELEASE_DRM,
+        // AudioRouting
+        SET_OUTPUT_DEVICE,
+        GET_ROUTED_DEVICE_ID,
+        ENABLE_AUDIO_DEVICE_CALLBACK,
+    };
 };
 
 // ----------------------------------------------------------------------------
diff --git a/media/libmedia/tests/mediaplayer/Android.bp b/media/libmedia/tests/mediaplayer/Android.bp
new file mode 100644
index 0000000..5538ea0
--- /dev/null
+++ b/media/libmedia/tests/mediaplayer/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_test {
+    name: "IMediaPlayerTest",
+    test_suites: ["device-tests", "mts"],
+    gtest: true,
+
+    srcs: [
+        "IMediaPlayerTest.cpp",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "liblog",
+        "libmedia",
+        "libstagefright",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+    compile_multilib: "first",
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+}
diff --git a/media/libmedia/tests/mediaplayer/IMediaPlayerTest.cpp b/media/libmedia/tests/mediaplayer/IMediaPlayerTest.cpp
new file mode 100644
index 0000000..097e8ef
--- /dev/null
+++ b/media/libmedia/tests/mediaplayer/IMediaPlayerTest.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <gtest/gtest.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/IMediaPlayer.h>
+#include <media/IMediaPlayerService.h>
+#include <media/mediaplayer.h>
+
+namespace android {
+
+constexpr uint8_t kMockByteArray[16] = {};
+
+ class IMediaPlayerTest : public testing::Test {
+  protected:
+   static constexpr uint32_t PREPARE_DRM = IMediaPlayer::PREPARE_DRM;
+
+   void SetUp() override {
+    mediaPlayer_ = new MediaPlayer();
+    sp<IServiceManager> serviceManager = defaultServiceManager();
+    sp<IBinder> mediaPlayerService = serviceManager->getService(String16("media.player"));
+    sp<IMediaPlayerService> iMediaPlayerService =
+            IMediaPlayerService::asInterface(mediaPlayerService);
+    iMediaPlayer_ = iMediaPlayerService->create(mediaPlayer_);
+   }
+
+   sp<MediaPlayer> mediaPlayer_;
+   sp<IMediaPlayer> iMediaPlayer_;
+ };
+
+TEST_F(IMediaPlayerTest, PrepareDrmInvalidTransaction) {
+    Parcel data, reply;
+    data.writeInterfaceToken(iMediaPlayer_->getInterfaceDescriptor());
+    data.write(kMockByteArray, 16);
+
+    // We write a length greater than the following session id array. Should be discarded.
+    data.writeUint32(2);
+    data.writeUnpadded(kMockByteArray, 1);
+
+    status_t result = IMediaPlayer::asBinder(iMediaPlayer_)
+            ->transact(PREPARE_DRM, data, &reply);
+    ASSERT_EQ(result, BAD_VALUE);
+}
+
+TEST_F(IMediaPlayerTest, PrepareDrmValidTransaction) {
+    Parcel data, reply;
+    data.writeInterfaceToken(iMediaPlayer_->getInterfaceDescriptor());
+    data.write(kMockByteArray, 16);
+
+    // We write a length equal to the length of the following data. The transaction should be valid.
+    data.writeUint32(1);
+    data.write(kMockByteArray, 1);
+
+    status_t result = IMediaPlayer::asBinder(iMediaPlayer_)
+            ->transact(PREPARE_DRM, data, &reply);
+    ASSERT_EQ(result, OK);
+}
+}  // namespace android
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 9671112..3f35639 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -357,11 +357,24 @@
         BufferQueue::createBufferQueue(&mProducer, &mConsumer);
         mSurface = new Surface(mProducer, false /* controlledByApp */);
         struct ConsumerListener : public BnConsumerListener {
-            void onFrameAvailable(const BufferItem&) override {}
+            ConsumerListener(const sp<IGraphicBufferConsumer> &consumer) {
+                mConsumer = consumer;
+            }
+            void onFrameAvailable(const BufferItem&) override {
+                BufferItem buffer;
+                // consume buffer
+                sp<IGraphicBufferConsumer> consumer = mConsumer.promote();
+                if (consumer != nullptr && consumer->acquireBuffer(&buffer, 0) == NO_ERROR) {
+                    consumer->releaseBuffer(buffer.mSlot, buffer.mFrameNumber,
+                                            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, buffer.mFence);
+                }
+            }
+
+            wp<IGraphicBufferConsumer> mConsumer;
             void onBuffersReleased() override {}
             void onSidebandStreamChanged() override {}
         };
-        sp<ConsumerListener> listener{new ConsumerListener};
+        sp<ConsumerListener> listener{new ConsumerListener(mConsumer)};
         mConsumer->consumerConnect(listener, false);
         mConsumer->setConsumerName(String8{"MediaCodec.release"});
         mConsumer->setConsumerUsageBits(usage);
@@ -1347,6 +1360,8 @@
     // save msg for reset
     mConfigureMsg = msg;
 
+    sp<AMessage> callback = mCallback;
+
     status_t err;
     std::vector<MediaResourceParcel> resources;
     resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
@@ -1371,7 +1386,18 @@
             // the configure failure is due to wrong state.
 
             ALOGE("configure failed with err 0x%08x, resetting...", err);
-            reset();
+            status_t err2 = reset();
+            if (err2 != OK) {
+                ALOGE("retrying configure: failed to reset codec (%08x)", err2);
+                break;
+            }
+            if (callback != nullptr) {
+                err2 = setCallback(callback);
+                if (err2 != OK) {
+                    ALOGE("retrying configure: failed to set callback (%08x)", err2);
+                    break;
+                }
+            }
         }
         if (!isResourceError(err)) {
             break;
@@ -1480,6 +1506,8 @@
 status_t MediaCodec::start() {
     sp<AMessage> msg = new AMessage(kWhatStart, this);
 
+    sp<AMessage> callback;
+
     status_t err;
     std::vector<MediaResourceParcel> resources;
     resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
@@ -1504,6 +1532,20 @@
                 ALOGE("retrying start: failed to configure codec");
                 break;
             }
+            if (callback != nullptr) {
+                err = setCallback(callback);
+                if (err != OK) {
+                    ALOGE("retrying start: failed to set callback");
+                    break;
+                }
+                ALOGD("succeed to set callback for reclaim");
+            }
+        }
+
+        // Keep callback message after the first iteration if necessary.
+        if (i == 0 && mCallback != nullptr && mFlags & kFlagIsAsync) {
+            callback = mCallback;
+            ALOGD("keep callback message for reclaim");
         }
 
         sp<AMessage> response;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index c28d288..bda1997 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -65,11 +65,11 @@
 constexpr float IN_CALL_EARPIECE_HEADROOM_DB = 3.f;
 
 // Compressed formats for MSD module, ordered from most preferred to least preferred.
-static const std::vector<audio_format_t> compressedFormatsOrder = {{
-        AUDIO_FORMAT_MAT_2_1, AUDIO_FORMAT_MAT_2_0, AUDIO_FORMAT_E_AC3,
+static const std::vector<audio_format_t> msdCompressedFormatsOrder = {{
+        AUDIO_FORMAT_IEC60958, AUDIO_FORMAT_MAT_2_1, AUDIO_FORMAT_MAT_2_0, AUDIO_FORMAT_E_AC3,
         AUDIO_FORMAT_AC3, AUDIO_FORMAT_PCM_16_BIT }};
 // Channel masks for MSD module, 3D > 2D > 1D ordering (most preferred to least preferred).
-static const std::vector<audio_channel_mask_t> surroundChannelMasksOrder = {{
+static const std::vector<audio_channel_mask_t> msdSurroundChannelMasksOrder = {{
         AUDIO_CHANNEL_OUT_3POINT1POINT2, AUDIO_CHANNEL_OUT_3POINT0POINT2,
         AUDIO_CHANNEL_OUT_2POINT1POINT2, AUDIO_CHANNEL_OUT_2POINT0POINT2,
         AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_STEREO }};
@@ -1037,7 +1037,7 @@
     *output = AUDIO_IO_HANDLE_NONE;
     if (!msdDevices.isEmpty()) {
         *output = getOutputForDevices(msdDevices, session, *stream, config, flags);
-        if (*output != AUDIO_IO_HANDLE_NONE && setMsdPatches(&outputDevices) == NO_ERROR) {
+        if (*output != AUDIO_IO_HANDLE_NONE && setMsdOutputPatches(&outputDevices) == NO_ERROR) {
             ALOGV("%s() Using MSD devices %s instead of devices %s",
                   __func__, msdDevices.toString().c_str(), outputDevices.toString().c_str());
         } else {
@@ -1203,7 +1203,7 @@
 
     // An MSD patch may be using the only output stream that can service this request. Release
     // all MSD patches to prioritize this request over any active output on MSD.
-    releaseMsdPatches(devices);
+    releaseMsdOutputPatches(devices);
 
     status_t status = outputDesc->open(config, devices, stream, flags, output);
 
@@ -1326,7 +1326,7 @@
                                                         mAvailableOutputDevices);
 }
 
-const AudioPatchCollection AudioPolicyManager::getMsdPatches() const {
+const AudioPatchCollection AudioPolicyManager::getMsdOutputPatches() const {
     AudioPatchCollection msdPatches;
     sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
     if (msdModule != 0) {
@@ -1344,50 +1344,47 @@
     return msdPatches;
 }
 
-status_t AudioPolicyManager::getBestMsdAudioProfileFor(const sp<DeviceDescriptor> &outputDevice,
-        bool hwAvSync, audio_port_config *sourceConfig, audio_port_config *sinkConfig) const
-{
-    sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
-    if (msdModule == nullptr) {
-        ALOGE("%s() unable to get MSD module", __func__);
-        return NO_INIT;
-    }
-    sp<HwModule> deviceModule = mHwModules.getModuleForDevice(outputDevice, AUDIO_FORMAT_DEFAULT);
-    if (deviceModule == nullptr) {
-        ALOGE("%s() unable to get module for %s", __func__, outputDevice->toString().c_str());
-        return NO_INIT;
-    }
-    const InputProfileCollection &inputProfiles = msdModule->getInputProfiles();
+status_t AudioPolicyManager::getMsdProfiles(bool hwAvSync,
+                                            const InputProfileCollection &inputProfiles,
+                                            const OutputProfileCollection &outputProfiles,
+                                            const sp<DeviceDescriptor> &sourceDevice,
+                                            const sp<DeviceDescriptor> &sinkDevice,
+                                            AudioProfileVector& sourceProfiles,
+                                            AudioProfileVector& sinkProfiles) const {
     if (inputProfiles.isEmpty()) {
-        ALOGE("%s() no input profiles for MSD module", __func__);
+        ALOGE("%s() no input profiles for source module", __func__);
         return NO_INIT;
     }
-    const OutputProfileCollection &outputProfiles = deviceModule->getOutputProfiles();
     if (outputProfiles.isEmpty()) {
-        ALOGE("%s() no output profiles for device %s", __func__, outputDevice->toString().c_str());
+        ALOGE("%s() no output profiles for sink module", __func__);
         return NO_INIT;
     }
-    AudioProfileVector msdProfiles;
-    // Each IOProfile represents a MixPort from audio_policy_configuration.xml
     for (const auto &inProfile : inputProfiles) {
-        if (hwAvSync == ((inProfile->getFlags() & AUDIO_INPUT_FLAG_HW_AV_SYNC) != 0)) {
-            appendAudioProfiles(msdProfiles, inProfile->getAudioProfiles());
+        if (hwAvSync == ((inProfile->getFlags() & AUDIO_INPUT_FLAG_HW_AV_SYNC) != 0) &&
+                inProfile->supportsDevice(sourceDevice)) {
+            appendAudioProfiles(sourceProfiles, inProfile->getAudioProfiles());
         }
     }
-    AudioProfileVector deviceProfiles;
     for (const auto &outProfile : outputProfiles) {
         if (hwAvSync == ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0) &&
-                outProfile->supportsDevice(outputDevice)) {
-            appendAudioProfiles(deviceProfiles, outProfile->getAudioProfiles());
+                outProfile->supportsDevice(sinkDevice)) {
+            appendAudioProfiles(sinkProfiles, outProfile->getAudioProfiles());
         }
     }
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::getBestMsdConfig(bool hwAvSync,
+        const AudioProfileVector &sourceProfiles, const AudioProfileVector &sinkProfiles,
+        audio_port_config *sourceConfig, audio_port_config *sinkConfig) const
+{
     struct audio_config_base bestSinkConfig;
-    status_t result = findBestMatchingOutputConfig(msdProfiles, deviceProfiles,
-            compressedFormatsOrder, surroundChannelMasksOrder, true /*preferHigherSamplingRates*/,
-            bestSinkConfig);
+    status_t result = findBestMatchingOutputConfig(sourceProfiles, sinkProfiles,
+            msdCompressedFormatsOrder, msdSurroundChannelMasksOrder,
+            true /*preferHigherSamplingRates*/, bestSinkConfig);
     if (result != NO_ERROR) {
-        ALOGD("%s() no matching profiles found for device: %s, hwAvSync: %d",
-                __func__, outputDevice->toString().c_str(), hwAvSync);
+        ALOGD("%s() no matching config found for sink, hwAvSync: %d",
+                __func__, hwAvSync);
         return result;
     }
     sinkConfig->sample_rate = bestSinkConfig.sample_rate;
@@ -1398,7 +1395,7 @@
             sinkConfig->flags.output | AUDIO_OUTPUT_FLAG_DIRECT);
     if (audio_is_iec61937_compatible(sinkConfig->format)) {
         // For formats compatible with IEC61937 encapsulation, assume that
-        // the record thread input from MSD is IEC61937 framed (for proportional buffer sizing).
+        // the input is IEC61937 framed (for proportional buffer sizing).
         // Add the AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO flag so downstream HAL can distinguish between
         // raw and IEC61937 framed streams.
         sinkConfig->flags.output = static_cast<audio_output_flags_t>(
@@ -1424,28 +1421,50 @@
     return NO_ERROR;
 }
 
-PatchBuilder AudioPolicyManager::buildMsdPatch(const sp<DeviceDescriptor> &outputDevice) const
+PatchBuilder AudioPolicyManager::buildMsdPatch(bool msdIsSource,
+                                               const sp<DeviceDescriptor> &device) const
 {
     PatchBuilder patchBuilder;
-    patchBuilder.addSource(getMsdAudioInDevice()).addSink(outputDevice);
+    sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
+    ALOG_ASSERT(msdModule != nullptr, "MSD module not available");
+    sp<HwModule> deviceModule = mHwModules.getModuleForDevice(device, AUDIO_FORMAT_DEFAULT);
+    if (deviceModule == nullptr) {
+        ALOGE("%s() unable to get module for %s", __func__, device->toString().c_str());
+        return patchBuilder;
+    }
+    const InputProfileCollection inputProfiles = msdIsSource ?
+            msdModule->getInputProfiles() : deviceModule->getInputProfiles();
+    const OutputProfileCollection outputProfiles = msdIsSource ?
+            deviceModule->getOutputProfiles() : msdModule->getOutputProfiles();
+
+    const sp<DeviceDescriptor> sourceDevice = msdIsSource ? getMsdAudioInDevice() : device;
+    const sp<DeviceDescriptor> sinkDevice = msdIsSource ?
+            device : getMsdAudioOutDevices().itemAt(0);
+    patchBuilder.addSource(sourceDevice).addSink(sinkDevice);
+
     audio_port_config sourceConfig = patchBuilder.patch()->sources[0];
     audio_port_config sinkConfig = patchBuilder.patch()->sinks[0];
+    AudioProfileVector sourceProfiles;
+    AudioProfileVector sinkProfiles;
     // TODO: Figure out whether MSD module has HW_AV_SYNC flag set in the AP config file.
     // For now, we just forcefully try with HwAvSync first.
-    status_t res = getBestMsdAudioProfileFor(outputDevice, true /*hwAvSync*/,
-            &sourceConfig, &sinkConfig) == NO_ERROR ? NO_ERROR :
-            getBestMsdAudioProfileFor(
-                    outputDevice, false /*hwAvSync*/, &sourceConfig, &sinkConfig);
-    if (res == NO_ERROR) {
-        // Found a matching profile for encoded audio. Re-create PatchBuilder with this config.
-        return (PatchBuilder()).addSource(sourceConfig).addSink(sinkConfig);
+    for (auto hwAvSync : { true, false }) {
+        if (getMsdProfiles(hwAvSync, inputProfiles, outputProfiles, sourceDevice, sinkDevice,
+                sourceProfiles, sinkProfiles) != NO_ERROR) {
+            continue;
+        }
+        if (getBestMsdConfig(hwAvSync, sourceProfiles, sinkProfiles, &sourceConfig,
+                &sinkConfig) == NO_ERROR) {
+            // Found a matching config. Re-create PatchBuilder with this config.
+            return (PatchBuilder()).addSource(sourceConfig).addSink(sinkConfig);
+        }
     }
-    ALOGV("%s() no matching profile found. Fall through to default PCM patch"
+    ALOGV("%s() no matching config found. Fall through to default PCM patch"
             " supporting PCM format conversion.", __func__);
     return patchBuilder;
 }
 
-status_t AudioPolicyManager::setMsdPatches(const DeviceVector *outputDevices) {
+status_t AudioPolicyManager::setMsdOutputPatches(const DeviceVector *outputDevices) {
     DeviceVector devices;
     if (outputDevices != nullptr && outputDevices->size() > 0) {
         devices.add(*outputDevices);
@@ -1460,11 +1479,11 @@
     std::vector<PatchBuilder> patchesToCreate;
     for (auto i = 0u; i < devices.size(); ++i) {
         ALOGV("%s() for device %s", __func__, devices[i]->toString().c_str());
-        patchesToCreate.push_back(buildMsdPatch(devices[i]));
+        patchesToCreate.push_back(buildMsdPatch(true /*msdIsSource*/, devices[i]));
     }
     // Retain only the MSD patches associated with outputDevices request.
     // Tear down the others, and create new ones as needed.
-    AudioPatchCollection patchesToRemove = getMsdPatches();
+    AudioPatchCollection patchesToRemove = getMsdOutputPatches();
     for (auto it = patchesToCreate.begin(); it != patchesToCreate.end(); ) {
         auto retainedPatch = false;
         for (auto i = 0u; i < patchesToRemove.size(); ++i) {
@@ -1509,8 +1528,8 @@
     return status;
 }
 
-void AudioPolicyManager::releaseMsdPatches(const DeviceVector& devices) {
-    AudioPatchCollection msdPatches = getMsdPatches();
+void AudioPolicyManager::releaseMsdOutputPatches(const DeviceVector& devices) {
+    AudioPatchCollection msdPatches = getMsdOutputPatches();
     for (size_t i = 0; i < msdPatches.size(); i++) {
         const auto& patch = msdPatches[i];
         for (size_t j = 0; j < patch->mPatch.num_sinks; ++j) {
@@ -3829,6 +3848,15 @@
             // be incomplete.
             PatchBuilder patchBuilder;
             audio_port_config sourcePortConfig = {};
+
+            // if first sink is to MSD, establish single MSD patch
+            if (getMsdAudioOutDevices().contains(
+                        mAvailableOutputDevices.getDeviceFromId(patch->sinks[0].id))) {
+                ALOGV("%s patching to MSD", __FUNCTION__);
+                patchBuilder = buildMsdPatch(false /*msdIsSource*/, srcDevice);
+                goto installPatch;
+            }
+
             srcDevice->toAudioPortConfig(&sourcePortConfig, &patch->sources[0]);
             patchBuilder.addSource(sourcePortConfig);
 
@@ -3924,6 +3952,7 @@
             }
             // TODO: check from routing capabilities in config file and other conflicting patches
 
+installPatch:
             status_t status = installPatch(
                         __func__, index, handle, patchBuilder.patch(), delayMs, uid, &patchDesc);
             if (status != NO_ERROR) {
@@ -5351,7 +5380,7 @@
             // arguments to mEngine->getOutputDevicesForAttributes() when resolving which output
             // devices to patch to. This may be complicated by the fact that devices may become
             // unavailable.
-            setMsdPatches();
+            setMsdOutputPatches();
         }
     }
 }
@@ -5424,7 +5453,7 @@
         // unnecessary rerouting by caching and reusing the arguments to
         // mEngine->getOutputDevicesForAttributes() when resolving which output devices to patch to.
         // This may be complicated by the fact that devices may become unavailable.
-        setMsdPatches();
+        setMsdOutputPatches();
     }
 }
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index c1c483c..ed5be5e 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -847,14 +847,22 @@
         // Support for Multi-Stream Decoder (MSD) module
         sp<DeviceDescriptor> getMsdAudioInDevice() const;
         DeviceVector getMsdAudioOutDevices() const;
-        const AudioPatchCollection getMsdPatches() const;
-        status_t getBestMsdAudioProfileFor(const sp<DeviceDescriptor> &outputDevice,
-                                           bool hwAvSync,
-                                           audio_port_config *sourceConfig,
-                                           audio_port_config *sinkConfig) const;
-        PatchBuilder buildMsdPatch(const sp<DeviceDescriptor> &outputDevice) const;
-        status_t setMsdPatches(const DeviceVector *outputDevices = nullptr);
-        void releaseMsdPatches(const DeviceVector& devices);
+        const AudioPatchCollection getMsdOutputPatches() const;
+        status_t getMsdProfiles(bool hwAvSync,
+                const InputProfileCollection &inputProfiles,
+                const OutputProfileCollection &outputProfiles,
+                const sp<DeviceDescriptor> &sourceDevice,
+                const sp<DeviceDescriptor> &sinkDevice,
+                AudioProfileVector &sourceProfiles,
+                AudioProfileVector &sinkProfiles) const;
+        status_t getBestMsdConfig(bool hwAvSync,
+                const AudioProfileVector &sourceProfiles,
+                const AudioProfileVector &sinkProfiles,
+                audio_port_config *sourceConfig,
+                audio_port_config *sinkConfig) const;
+        PatchBuilder buildMsdPatch(bool msdIsSource, const sp<DeviceDescriptor> &device) const;
+        status_t setMsdOutputPatches(const DeviceVector *outputDevices = nullptr);
+        void releaseMsdOutputPatches(const DeviceVector& devices);
 private:
         void onNewAudioModulesAvailableInt(DeviceVector *newDevices);
 
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index c096427..6150206 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -29,8 +29,9 @@
     using AudioPolicyManager::getOutputs;
     using AudioPolicyManager::getAvailableOutputDevices;
     using AudioPolicyManager::getAvailableInputDevices;
-    using AudioPolicyManager::releaseMsdPatches;
-    using AudioPolicyManager::setMsdPatches;
+    using AudioPolicyManager::releaseMsdOutputPatches;
+    using AudioPolicyManager::setMsdOutputPatches;
+    using AudioPolicyManager::getAudioPatches;
     uint32_t getAudioPortGeneration() const { return mAudioPortGeneration; }
 };
 
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index f391606..5b6b3e7 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -340,6 +340,8 @@
 
     const size_t mExpectedAudioPatchCount;
     sp<DeviceDescriptor> mSpdifDevice;
+
+    sp<DeviceDescriptor> mHdmiInputDevice;
 };
 
 AudioPolicyManagerTestMsd::AudioPolicyManagerTestMsd()
@@ -366,8 +368,11 @@
             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
     sp<AudioProfile> ac3OutputProfile = new AudioProfile(
             AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000);
+    sp<AudioProfile> iec958OutputProfile = new AudioProfile(
+            AUDIO_FORMAT_IEC60958, AUDIO_CHANNEL_OUT_STEREO, 48000);
     mMsdOutputDevice->addAudioProfile(pcmOutputProfile);
     mMsdOutputDevice->addAudioProfile(ac3OutputProfile);
+    mMsdOutputDevice->addAudioProfile(iec958OutputProfile);
     mMsdInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUS);
     // Match output profile from AudioPolicyConfig::setDefault.
     sp<AudioProfile> pcmInputProfile = new AudioProfile(
@@ -405,6 +410,11 @@
             AUDIO_OUTPUT_FLAG_NON_BLOCKING);
     msdCompressedOutputProfile->addSupportedDevice(mMsdOutputDevice);
     msdModule->addOutputProfile(msdCompressedOutputProfile);
+    sp<OutputProfile> msdIec958OutputProfile = new OutputProfile("msd iec958 input");
+    msdIec958OutputProfile->addAudioProfile(iec958OutputProfile);
+    msdIec958OutputProfile->setFlags(AUDIO_OUTPUT_FLAG_DIRECT);
+    msdIec958OutputProfile->addSupportedDevice(mMsdOutputDevice);
+    msdModule->addOutputProfile(msdIec958OutputProfile);
 
     sp<InputProfile> msdInputProfile = new InputProfile("msd output");
     msdInputProfile->addAudioProfile(pcmInputProfile);
@@ -428,6 +438,19 @@
         mSpdifDevice->addAudioProfile(dtsOutputProfile);
         primaryEncodedOutputProfile->addSupportedDevice(mSpdifDevice);
     }
+
+    // Add HDMI input device with IEC60958 profile for HDMI in -> MSD patching.
+    mHdmiInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_HDMI);
+    sp<AudioProfile> iec958InputProfile = new AudioProfile(
+            AUDIO_FORMAT_IEC60958, AUDIO_CHANNEL_IN_STEREO, 48000);
+    mHdmiInputDevice->addAudioProfile(iec958InputProfile);
+    config.addDevice(mHdmiInputDevice);
+    sp<InputProfile> hdmiInputProfile = new InputProfile("hdmi input");
+    hdmiInputProfile->addAudioProfile(iec958InputProfile);
+    hdmiInputProfile->setFlags(AUDIO_INPUT_FLAG_DIRECT);
+    hdmiInputProfile->addSupportedDevice(mHdmiInputDevice);
+    config.getHwModules().getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)->
+            addInputProfile(hdmiInputProfile);
 }
 
 void AudioPolicyManagerTestMsd::TearDown() {
@@ -435,6 +458,7 @@
     mMsdInputDevice.clear();
     mDefaultOutputDevice.clear();
     mSpdifDevice.clear();
+    mHdmiInputDevice.clear();
     AudioPolicyManagerTest::TearDown();
 }
 
@@ -455,21 +479,21 @@
     ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot());
 }
 
-TEST_P(AudioPolicyManagerTestMsd, PatchCreationSetReleaseMsdPatches) {
+TEST_P(AudioPolicyManagerTestMsd, PatchCreationSetReleaseMsdOutputPatches) {
     const PatchCountCheck patchCount = snapshotPatchCount();
     DeviceVector devices = mManager->getAvailableOutputDevices();
     // Remove MSD output device to avoid patching to itself
     devices.remove(mMsdOutputDevice);
     ASSERT_EQ(mExpectedAudioPatchCount, devices.size());
-    mManager->setMsdPatches(&devices);
+    mManager->setMsdOutputPatches(&devices);
     ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot());
     // Dual patch: exercise creating one new audio patch and reusing another existing audio patch.
     DeviceVector singleDevice(devices[0]);
-    mManager->releaseMsdPatches(singleDevice);
+    mManager->releaseMsdOutputPatches(singleDevice);
     ASSERT_EQ(mExpectedAudioPatchCount - 1, patchCount.deltaFromSnapshot());
-    mManager->setMsdPatches(&devices);
+    mManager->setMsdOutputPatches(&devices);
     ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot());
-    mManager->releaseMsdPatches(devices);
+    mManager->releaseMsdOutputPatches(devices);
     ASSERT_EQ(0, patchCount.deltaFromSnapshot());
 }
 
@@ -550,6 +574,34 @@
     }
 }
 
+TEST_P(AudioPolicyManagerTestMsd, PatchCreationFromHdmiInToMsd) {
+    audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
+    uid_t uid = 42;
+    const PatchCountCheck patchCount = snapshotPatchCount();
+    ASSERT_FALSE(mManager->getAvailableInputDevices().isEmpty());
+    PatchBuilder patchBuilder;
+    patchBuilder.
+            addSource(mManager->getAvailableInputDevices().
+                    getDevice(AUDIO_DEVICE_IN_HDMI, String8(""), AUDIO_FORMAT_DEFAULT)).
+            addSink(mManager->getAvailableOutputDevices().
+                    getDevice(AUDIO_DEVICE_OUT_BUS, String8(""), AUDIO_FORMAT_DEFAULT));
+    ASSERT_EQ(NO_ERROR, mManager->createAudioPatch(patchBuilder.patch(), &handle, uid));
+    ASSERT_NE(AUDIO_PATCH_HANDLE_NONE, handle);
+    AudioPatchCollection patches = mManager->getAudioPatches();
+    sp<AudioPatch> patch = patches.valueFor(handle);
+    ASSERT_EQ(1, patch->mPatch.num_sources);
+    ASSERT_EQ(1, patch->mPatch.num_sinks);
+    ASSERT_EQ(AUDIO_PORT_ROLE_SOURCE, patch->mPatch.sources[0].role);
+    ASSERT_EQ(AUDIO_PORT_ROLE_SINK, patch->mPatch.sinks[0].role);
+    ASSERT_EQ(AUDIO_FORMAT_IEC60958, patch->mPatch.sources[0].format);
+    ASSERT_EQ(AUDIO_FORMAT_IEC60958, patch->mPatch.sinks[0].format);
+    ASSERT_EQ(AUDIO_CHANNEL_IN_STEREO, patch->mPatch.sources[0].channel_mask);
+    ASSERT_EQ(AUDIO_CHANNEL_OUT_STEREO, patch->mPatch.sinks[0].channel_mask);
+    ASSERT_EQ(48000, patch->mPatch.sources[0].sample_rate);
+    ASSERT_EQ(48000, patch->mPatch.sinks[0].sample_rate);
+    ASSERT_EQ(1, patchCount.deltaFromSnapshot());
+}
+
 class AudioPolicyManagerTestWithConfigurationFile : public AudioPolicyManagerTest {
 protected:
     void SetUpManagerConfig() override;
diff --git a/services/mediametrics/Android.bp b/services/mediametrics/Android.bp
index 3797164..b2a0cda 100644
--- a/services/mediametrics/Android.bp
+++ b/services/mediametrics/Android.bp
@@ -30,7 +30,7 @@
     "modernize-loop-convert",
     "modernize-make-shared",
     "modernize-make-unique",
-    "modernize-pass-by-value",
+    // "modernize-pass-by-value", // found in TimeMachine.h
     "modernize-raw-string-literal",
     "modernize-redundant-void-arg",
     "modernize-replace-auto-ptr",
@@ -38,13 +38,13 @@
     "modernize-return-braced-init-list",
     "modernize-shrink-to-fit",
     "modernize-unary-static-assert",
-    "modernize-use-auto",  // debatable - auto can obscure type
+    // "modernize-use-auto",  // found in MediaMetricsService.h, debatable - auto can obscure type
     "modernize-use-bool-literals",
     "modernize-use-default-member-init",
     "modernize-use-emplace",
     "modernize-use-equals-default",
     "modernize-use-equals-delete",
-    "modernize-use-nodiscard",
+    // "modernize-use-nodiscard", // found in TimeMachine.h
     "modernize-use-noexcept",
     "modernize-use-nullptr",
     "modernize-use-override",
@@ -57,6 +57,10 @@
     // Remove some pedantic stylistic requirements.
     "-google-readability-casting", // C++ casts not always necessary and may be verbose
     "-google-readability-todo",    // do not require TODO(info)
+
+    "-bugprone-unhandled-self-assignment", // found in TimeMachine.h
+    "-bugprone-suspicious-string-compare", // found in TimeMachine.h
+    "-cert-oop54-cpp", // found in TransactionLog.h
 ]
 
 cc_defaults {
@@ -88,8 +92,7 @@
     tidy_checks: tidy_errors,
     tidy_checks_as_errors: tidy_errors,
     tidy_flags: [
-      "-format-style='file'",
-      "--header-filter='frameworks/av/services/mediametrics/'",
+      "-format-style=file",
     ],
 }