Merge "configs: msm8953: set default IIR volume to 53 for internal codec" into audio-userspace.lnx.2.1-dev
diff --git a/configs/msm8937/audio_policy_configuration.xml b/configs/msm8937/audio_policy_configuration.xml
index 2443d13..44abe28 100644
--- a/configs/msm8937/audio_policy_configuration.xml
+++ b/configs/msm8937/audio_policy_configuration.xml
@@ -81,13 +81,13 @@
                 <mixPort name="direct_pcm" role="source"
                         flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_DIRECT_PCM">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
-                             samplingRates="8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,128000,176400,192000"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000"
                              channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
                     <profile name="" format="AUDIO_FORMAT_PCM_8_24_BIT"
-                             samplingRates="8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,128000,176400,192000"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000"
                              channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
                     <profile name="" format="AUDIO_FORMAT_PCM_24_BIT_PACKED"
-                             samplingRates="8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,128000,176400,192000"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000"
                              channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
                 </mixPort>
                 <mixPort name="compressed_offload" role="source"
diff --git a/configs/msm8953/audio_policy_configuration.xml b/configs/msm8953/audio_policy_configuration.xml
index 2443d13..44abe28 100644
--- a/configs/msm8953/audio_policy_configuration.xml
+++ b/configs/msm8953/audio_policy_configuration.xml
@@ -81,13 +81,13 @@
                 <mixPort name="direct_pcm" role="source"
                         flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_DIRECT_PCM">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
-                             samplingRates="8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,128000,176400,192000"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000"
                              channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
                     <profile name="" format="AUDIO_FORMAT_PCM_8_24_BIT"
-                             samplingRates="8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,128000,176400,192000"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000"
                              channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
                     <profile name="" format="AUDIO_FORMAT_PCM_24_BIT_PACKED"
-                             samplingRates="8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,128000,176400,192000"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000"
                              channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
                 </mixPort>
                 <mixPort name="compressed_offload" role="source"
diff --git a/configs/msm8996/audio_policy_configuration.xml b/configs/msm8996/audio_policy_configuration.xml
index 6f36be5..e8d4cd0 100644
--- a/configs/msm8996/audio_policy_configuration.xml
+++ b/configs/msm8996/audio_policy_configuration.xml
@@ -81,13 +81,13 @@
                 <mixPort name="direct_pcm" role="source"
                         flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_DIRECT_PCM">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
-                             samplingRates="8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,128000,176400,192000"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000"
                              channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
                     <profile name="" format="AUDIO_FORMAT_PCM_8_24_BIT"
-                             samplingRates="8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,128000,176400,192000"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000"
                              channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
                     <profile name="" format="AUDIO_FORMAT_PCM_24_BIT_PACKED"
-                             samplingRates="8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,128000,176400,192000"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000"
                              channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
                 </mixPort>
                 <mixPort name="compressed_offload" role="source"
diff --git a/configs/msmcobalt/audio_policy_configuration.xml b/configs/msmcobalt/audio_policy_configuration.xml
index 2503bd2..66b7d17 100644
--- a/configs/msmcobalt/audio_policy_configuration.xml
+++ b/configs/msmcobalt/audio_policy_configuration.xml
@@ -86,13 +86,13 @@
                 <mixPort name="direct_pcm" role="source"
                         flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_DIRECT_PCM">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
-                             samplingRates="8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,128000,176400,192000"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000"
                              channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
                     <profile name="" format="AUDIO_FORMAT_PCM_8_24_BIT"
-                             samplingRates="8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,128000,176400,192000,352800"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000,352800"
                              channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
                     <profile name="" format="AUDIO_FORMAT_PCM_24_BIT_PACKED"
-                             samplingRates="8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,128000,176400,192000,352800"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000,352800"
                              channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
                 </mixPort>
                 <mixPort name="compressed_offload" role="source"
diff --git a/configs/msmcobalt/mixer_paths_tasha.xml b/configs/msmcobalt/mixer_paths_tasha.xml
index 038408c..efd275d 100644
--- a/configs/msmcobalt/mixer_paths_tasha.xml
+++ b/configs/msmcobalt/mixer_paths_tasha.xml
@@ -205,12 +205,6 @@
     <ctl name="MultiMedia1 Mixer USB_AUDIO_TX" value="0" />
     <ctl name="MultiMedia5 Mixer USB_AUDIO_TX" value="0" />
     <ctl name="MultiMedia8 Mixer USB_AUDIO_TX" value="0" />
-    <ctl name="USB_AUDIO_RX Channels" value="One" />
-    <ctl name="USB_AUDIO_RX SampleRate" value="KHZ_48" />
-    <ctl name="USB_AUDIO_RX Format" value="S16_LE" />
-    <ctl name="USB_AUDIO_TX Channels" value="One" />
-    <ctl name="USB_AUDIO_TX SampleRate" value="KHZ_48" />
-    <ctl name="USB_AUDIO_TX Format" value="S16_LE" />
     <ctl name="MultiMedia6 Mixer SLIM_0_TX" value="0" />
     <ctl name="IIR0 INP0 MUX" value="ZERO" />
     <ctl name="IIR0 INP1 MUX" value="ZERO" />
@@ -399,7 +393,7 @@
     <ctl name="AFE_PCM_RX Audio Mixer MultiMedia5" value="0" />
     <!-- usb headset end -->
     <!-- fm -->
-    <ctl name="SLIMBUS_8 LOOPBACK Volume" value="1" />
+    <ctl name="SLIMBUS_8 LOOPBACK Volume" value="0" />
     <ctl name="SLIMBUS_0_RX Port Mixer SLIM_8_TX" value="0" />
     <ctl name="SLIMBUS_DL_HL Switch" value="0" />
     <ctl name="SLIMBUS_6_RX Port Mixer SLIM_8_TX" value="0" />
diff --git a/configs/msmcobalt/mixer_paths_tavil.xml b/configs/msmcobalt/mixer_paths_tavil.xml
index 4baaa52..34543f5 100644
--- a/configs/msmcobalt/mixer_paths_tavil.xml
+++ b/configs/msmcobalt/mixer_paths_tavil.xml
@@ -166,12 +166,6 @@
     <ctl name="MultiMedia1 Mixer USB_AUDIO_TX" value="0" />
     <ctl name="MultiMedia5 Mixer USB_AUDIO_TX" value="0" />
     <ctl name="MultiMedia8 Mixer USB_AUDIO_TX" value="0" />
-    <ctl name="USB_AUDIO_RX Channels" value="One" />
-    <ctl name="USB_AUDIO_RX SampleRate" value="KHZ_48" />
-    <ctl name="USB_AUDIO_RX Format" value="S16_LE" />
-    <ctl name="USB_AUDIO_TX Channels" value="One" />
-    <ctl name="USB_AUDIO_TX SampleRate" value="KHZ_48" />
-    <ctl name="USB_AUDIO_TX Format" value="S16_LE" />
     <ctl name="MultiMedia6 Mixer SLIM_0_TX" value="0" />
     <ctl name="SLIM_2_RX Format" value="UNPACKED" />
     <ctl name="SLIM_2_RX SampleRate" value="KHZ_48" />
@@ -222,7 +216,7 @@
     <ctl name="AFE_PCM_RX Audio Mixer MultiMedia5" value="0" />
     <!-- usb headset end -->
     <!-- fm -->
-    <ctl name="SLIMBUS_8 LOOPBACK Volume" value="1" />
+    <ctl name="SLIMBUS_8 LOOPBACK Volume" value="0" />
     <ctl name="SLIMBUS_0_RX Port Mixer SLIM_8_TX" value="0" />
     <ctl name="SLIMBUS_DL_HL Switch" value="0" />
     <ctl name="SLIMBUS_6_RX Port Mixer SLIM_8_TX" value="0" />
diff --git a/configs/msmcobalt/sound_trigger_mixer_paths_wcd9340.xml b/configs/msmcobalt/sound_trigger_mixer_paths_wcd9340.xml
index d12b62f..be77fee 100755
--- a/configs/msmcobalt/sound_trigger_mixer_paths_wcd9340.xml
+++ b/configs/msmcobalt/sound_trigger_mixer_paths_wcd9340.xml
@@ -106,10 +106,12 @@
     </path>
 
     <path name="listen-ape-handset-mic">
-        <ctl name="MAD_BROADCAST Switch" value="1" />
-        <ctl name="TX13 INP MUX" value="MAD_BRDCST" />
-        <ctl name="AIF4_MAD Mixer SLIM TX13" value="1" />
         <ctl name="MAD Input" value="DMIC0" />
+        <ctl name="MAD_SEL MUX" value="MSM" />
+        <ctl name="MAD_INP MUX" value="MAD" />
+        <ctl name="MAD_BROADCAST Switch" value="1" />
+        <ctl name="CDC_IF TX13 MUX" value="MAD_BRDCST" />
+        <ctl name="AIF4_MAD Mixer SLIM TX13" value="1" />
     </path>
 
 </mixer>
diff --git a/configs/msmfalcon/audio_policy_configuration.xml b/configs/msmfalcon/audio_policy_configuration.xml
index ea4b140..b1ea1b9 100644
--- a/configs/msmfalcon/audio_policy_configuration.xml
+++ b/configs/msmfalcon/audio_policy_configuration.xml
@@ -81,13 +81,13 @@
                 <mixPort name="direct_pcm" role="source"
                         flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_DIRECT_PCM">
                     <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
-                             samplingRates="8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,128000,176400,192000"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000"
                              channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
                     <profile name="" format="AUDIO_FORMAT_PCM_8_24_BIT"
-                             samplingRates="8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,128000,176400,192000"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000"
                              channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
                     <profile name="" format="AUDIO_FORMAT_PCM_24_BIT_PACKED"
-                             samplingRates="8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,128000,176400,192000"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000"
                              channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/>
                 </mixPort>
                 <mixPort name="compressed_offload" role="source"
diff --git a/hal/Android.mk b/hal/Android.mk
index f457c7b..daf7397 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -248,6 +248,12 @@
     LOCAL_SRC_FILES += audio_extn/a2dp.c
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_QAF)),true)
+    LOCAL_CFLAGS += -DQAF_EXTN_ENABLED
+    LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/qaf/
+    LOCAL_SRC_FILES += audio_extn/qaf.c
+endif
+
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
 	libcutils \
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index ccf3d64..b57bb81 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -459,9 +459,11 @@
 #ifndef HFP_ENABLED
 #define audio_extn_hfp_is_active(adev)                  (0)
 #define audio_extn_hfp_get_usecase()                    (-1)
+#define hfp_set_mic_mute(dev, state)                    (0)
 #else
 bool audio_extn_hfp_is_active(struct audio_device *adev);
 audio_usecase_t audio_extn_hfp_get_usecase();
+int hfp_set_mic_mute(struct audio_device *dev, bool state);
 #endif
 
 #ifndef DEV_ARBI_ENABLED
@@ -581,6 +583,29 @@
 void audio_utils_set_hdmi_channel_status(struct stream_out *out, char * buffer, size_t bytes);
 #endif
 
+#ifdef QAF_EXTN_ENABLED
+bool audio_extn_qaf_is_enabled();
+void audio_extn_qaf_deinit();
+void audio_extn_qaf_close_output_stream(struct audio_hw_device *dev __unused,
+                                        struct audio_stream_out *stream);
+int audio_extn_qaf_open_output_stream(struct audio_hw_device *dev,
+                                   audio_io_handle_t handle,
+                                   audio_devices_t devices,
+                                   audio_output_flags_t flags,
+                                   struct audio_config *config,
+                                   struct audio_stream_out **stream_out,
+                                   const char *address __unused);
+int audio_extn_qaf_init(struct audio_device *adev);
+int audio_extn_qaf_set_parameters(struct audio_device *adev, struct str_parms *parms);
+#else
+#define audio_extn_qaf_is_enabled()                                     (0)
+#define audio_extn_qaf_deinit()                                         (0)
+#define audio_extn_qaf_close_output_stream         adev_close_output_stream
+#define audio_extn_qaf_open_output_stream           adev_open_output_stream
+#define audio_extn_qaf_init(adev)                                       (0)
+#define audio_extn_qaf_set_parameters(adev, parms)                      (0)
+#endif
+
 #ifndef KEEP_ALIVE_ENABLED
 #define audio_extn_keep_alive_init(a) do {} while(0)
 #define audio_extn_keep_alive_start() do {} while(0)
diff --git a/hal/audio_extn/dev_arbi.c b/hal/audio_extn/dev_arbi.c
index d7ab5ff..69d8568 100644
--- a/hal/audio_extn/dev_arbi.c
+++ b/hal/audio_extn/dev_arbi.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 2016 The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -131,6 +131,7 @@
         {SND_DEVICE_OUT_VOICE_HANDSET, AUDIO_DEVICE_OUT_EARPIECE},
         {SND_DEVICE_OUT_SPEAKER, AUDIO_DEVICE_OUT_SPEAKER},
         {SND_DEVICE_OUT_VOICE_SPEAKER, AUDIO_DEVICE_OUT_SPEAKER},
+        {SND_DEVICE_OUT_VOICE_SPEAKER_2, AUDIO_DEVICE_OUT_SPEAKER},
         {SND_DEVICE_OUT_HEADPHONES, AUDIO_DEVICE_OUT_WIRED_HEADPHONE},
         {SND_DEVICE_OUT_VOICE_HEADPHONES, AUDIO_DEVICE_OUT_WIRED_HEADPHONE},
         {SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c
index 5a45b80..243d48d 100644
--- a/hal/audio_extn/hfp.c
+++ b/hal/audio_extn/hfp.c
@@ -302,6 +302,26 @@
         return false;
 }
 
+int hfp_set_mic_mute(struct audio_device *adev, bool state)
+{
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "HFP TX Mute";
+    uint32_t set_values[ ] = {0};
+
+    ALOGI("%s: enter, state=%d", __func__, state);
+
+    set_values[0] = state;
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+               __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+    ALOGV("%s: exit", __func__);
+    return 0;
+}
+
 audio_usecase_t audio_extn_hfp_get_usecase()
 {
     return hfpmod.ucid;
diff --git a/hal/audio_extn/qaf.c b/hal/audio_extn/qaf.c
new file mode 100644
index 0000000..d631275
--- /dev/null
+++ b/hal/audio_extn/qaf.c
@@ -0,0 +1,1129 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER 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
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "audio_hw_qaf"
+/*#define LOG_NDEBUG 0*/
+/*#define VERY_VERY_VERBOSE_LOGGING*/
+#ifdef VERY_VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+#define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4
+#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
+#define QAF_DEFAULT_COMPR_AUDIO_HANDLE 1001
+#define QAF_DEFAULT_COMPR_PASSTHROUGH_HANDLE 1002
+
+#include <stdlib.h>
+#include <pthread.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
+#include <cutils/properties.h>
+#include <cutils/str_parms.h>
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include "audio_utils/primitives.h"
+#include "audio_hw.h"
+#include "platform_api.h"
+#include <platform.h>
+#include <system/thread_defs.h>
+#include <cutils/sched_policy.h>
+#include "audio_extn.h"
+#include <qti_audio.h>
+#include "sound/compress_params.h"
+
+#define QAF_OUTPUT_SAMPLING_RATE 48000
+#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 50
+#define QAF_PLAYBACK_LATENCY 30
+
+#define QAF_LATENCY (COMPRESS_OFFLOAD_PLAYBACK_LATENCY + QAF_PLAYBACK_LATENCY)
+
+#ifdef QAF_DUMP_ENABLED
+FILE *fp_output_writer_hdmi = NULL;
+#endif
+
+typedef enum {
+AUDIO_OUTPUT_FLAG_MAIN = 0x4000, // Flag for Main Input Stream
+AUDIO_OUTPUT_FLAG_ASSOCIATED = 0x8000, // Flag for Assocated Input Stream
+} qaf_audio_output_flags_t;
+
+struct qaf {
+    struct audio_device *adev;
+    audio_session_handle_t session_handle;
+    void *qaf_lib;
+    int (*qaf_audio_session_open)(audio_session_handle_t* session_handle, void *p_data, void* license_data);
+    int (*qaf_audio_session_close)(audio_session_handle_t session_handle);
+    int (*qaf_audio_stream_open)(audio_session_handle_t session_handle, audio_stream_handle_t* stream_handle,
+         audio_stream_config_t input_config, audio_devices_t devices, stream_type_t flags);
+    int (*qaf_audio_stream_close)(audio_stream_handle_t stream_handle);
+    int (*qaf_audio_stream_set_param)(audio_stream_handle_t stream_handle, const char* kv_pairs);
+    int (*qaf_audio_session_set_param)(audio_session_handle_t handle, const char* kv_pairs);
+    char* (*qaf_audio_stream_get_param)(audio_stream_handle_t stream_handle, const char* key);
+    char* (*qaf_audio_session_get_param)(audio_session_handle_t handle, const char* key);
+    int (*qaf_audio_stream_start)(audio_stream_handle_t handle);
+    int (*qaf_audio_stream_stop)(audio_stream_handle_t stream_handle);
+    int (*qaf_audio_stream_pause)(audio_stream_handle_t stream_handle);
+    int (*qaf_audio_stream_flush)(audio_stream_handle_t stream_handle);
+    int (*qaf_audio_stream_write)(audio_stream_handle_t stream_handle, const void* buf, int size);
+    void (*qaf_register_event_callback)(audio_session_handle_t session_handle, void *priv_data,
+          notify_event_callback_t event_callback, audio_event_id_t event_id);
+    pthread_mutex_t lock;
+    struct stream_out *stream_drain_main;
+    struct stream_out *qaf_compr_offload_out;
+    struct stream_out *qaf_compr_passthrough_out;
+    int passthrough_enabled;
+    int hdmi_sink_channels;
+    bool multi_ch_out_enabled;
+    bool main_output_active;
+    bool assoc_output_active;
+};
+
+static struct qaf *qaf_mod = NULL;
+
+static void lock_output_stream(struct stream_out *out)
+{
+    pthread_mutex_lock(&out->pre_lock);
+    pthread_mutex_lock(&out->lock);
+    pthread_mutex_unlock(&out->pre_lock);
+}
+
+static int qaf_send_offload_cmd_l(struct stream_out* out, int command)
+{
+    struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd));
+
+    if (!cmd) {
+        ALOGE("failed to allocate mem for command 0x%x", command);
+        return -ENOMEM;
+    }
+
+    ALOGV("%s %d", __func__, command);
+
+    cmd->cmd = command;
+    list_add_tail(&out->qaf_offload_cmd_list, &cmd->node);
+    pthread_cond_signal(&out->qaf_offload_cond);
+    return 0;
+}
+
+static int audio_extn_qaf_stream_stop(struct stream_out *out)
+{
+    ALOGV("%s: %d start", __func__, __LINE__);
+    if (!qaf_mod->qaf_audio_stream_stop)
+        return -EINVAL;
+
+    return qaf_mod->qaf_audio_stream_stop(out->qaf_stream_handle);
+}
+
+static int qaf_out_standby(struct audio_stream *stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int status = 0;
+
+    ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
+          stream, out->usecase, use_case_table[out->usecase]);
+
+    lock_output_stream(out);
+    if (!out->standby) {
+        out->standby = true;
+        status = audio_extn_qaf_stream_stop(out);
+    }
+    pthread_mutex_unlock(&out->lock);
+    out->written = 0;
+    return status;
+}
+
+static int qaf_stream_set_param(struct stream_out *out, const char *kv_pair)
+{
+    ALOGV("%s %d kvpair: %s", __func__, __LINE__, kv_pair);
+    if (!qaf_mod->qaf_audio_stream_set_param)
+        return -EINVAL;
+
+    return qaf_mod->qaf_audio_stream_set_param(out->qaf_stream_handle, kv_pair);
+}
+
+static int qaf_out_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int ret = 0;
+
+    ALOGV("%s: enter: usecase(%d: %s) kvpairs: %s",
+          __func__, out->usecase, use_case_table[out->usecase], kvpairs);
+    lock_output_stream(out);
+    ret = qaf_stream_set_param(out, kvpairs);
+    pthread_mutex_unlock(&out->lock);
+    if ((NULL != qaf_mod->qaf_compr_offload_out)) {
+        qaf_mod->qaf_compr_offload_out->stream.common.set_parameters((struct audio_stream *) qaf_mod->qaf_compr_offload_out, kvpairs);
+    }
+    return ret;
+}
+
+static int qaf_write_input_buffer(struct stream_out *out, const void *buffer, int bytes)
+{
+    int ret = 0;
+    ALOGVV("%s bytes = %d [%p]", __func__, bytes, out->qaf_stream_handle);
+    if (!qaf_mod->qaf_audio_stream_write)
+        return -EINVAL;
+
+    if (out->qaf_stream_handle)
+        ret = qaf_mod->qaf_audio_stream_write(out->qaf_stream_handle, buffer, bytes);
+    return ret;
+}
+
+static int qaf_out_set_volume(struct audio_stream_out *stream __unused, float left,
+                          float right)
+{
+    if (qaf_mod->qaf_compr_offload_out != NULL) {
+        return qaf_mod->qaf_compr_offload_out->stream.set_volume(
+            (struct audio_stream_out *)qaf_mod->qaf_compr_offload_out, left, right);
+    }
+    return -ENOSYS;
+}
+
+static int qaf_stream_start(struct stream_out *out)
+{
+    if (!qaf_mod->qaf_audio_stream_start)
+        return -EINVAL;
+
+    return qaf_mod->qaf_audio_stream_start(out->qaf_stream_handle);
+}
+
+static int qaf_start_output_stream(struct stream_out *out)
+{
+    int ret = 0;
+    struct audio_device *adev = out->dev;
+    int snd_card_status = get_snd_card_state(adev);
+
+    if ((out->usecase < 0) || (out->usecase >= AUDIO_USECASE_MAX)) {
+        ret = -EINVAL;
+        usleep(50000);
+        return ret;
+    }
+
+    ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x)",
+          __func__, &out->stream, out->usecase, use_case_table[out->usecase],
+          out->devices);
+
+    if (SND_CARD_STATE_OFFLINE == snd_card_status) {
+        ALOGE("%s: sound card is not active/SSR returning error", __func__);
+        ret = -EIO;
+        usleep(50000);
+        return ret;
+    }
+
+    return qaf_stream_start(out);
+}
+
+static ssize_t qaf_out_write(struct audio_stream_out *stream, const void *buffer,
+                         size_t bytes)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    struct audio_device *adev = out->dev;
+    ssize_t ret = 0;
+
+    ALOGV("qaf_out_write bytes = %d, usecase[%d] and flags[%x] for handle[%p]",(int)bytes, out->usecase, out->flags, out);
+    lock_output_stream(out);
+
+    if (out->standby) {
+        out->standby = false;
+        pthread_mutex_lock(&adev->lock);
+        ret = qaf_start_output_stream(out);
+        pthread_mutex_unlock(&adev->lock);
+        /* ToDo: If use case is compress offload should return 0 */
+        if (ret != 0) {
+            out->standby = true;
+            goto exit;
+        }
+    }
+
+    if (adev->is_channel_status_set == false && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)){
+        audio_utils_set_hdmi_channel_status(out, (char *)buffer, bytes);
+        adev->is_channel_status_set = true;
+    }
+
+    ret = qaf_write_input_buffer(out, buffer, bytes);
+    ALOGV("%s, ret [%d] ", __func__, (int)ret);
+    if (ret < 0) {
+        goto exit;
+    }
+    out->written += bytes / ((popcount(out->channel_mask) * sizeof(short)));
+
+exit:
+
+    pthread_mutex_unlock(&out->lock);
+
+    if (ret < 0) {
+        if (ret == -EAGAIN) {
+            ALOGV("No space available in ms12 driver, post msg to cb thread");
+            lock_output_stream(out);
+            ret = qaf_send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
+            pthread_mutex_unlock(&out->lock);
+            bytes = 0;
+        }
+        if(ret == -ENOMEM || ret == -EPERM){
+            if (out->pcm)
+                ALOGE("%s: error %d, %s", __func__, (int)ret, pcm_get_error(out->pcm));
+            qaf_out_standby(&out->stream.common);
+            usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
+                            out->stream.common.get_sample_rate(&out->stream.common));
+        }
+    }
+    return bytes;
+}
+
+static int qaf_get_timestamp(struct stream_out *out, uint64_t *frames, struct timespec *timestamp)
+{
+    int ret = 0;
+    struct str_parms *parms;
+    int value = 0;
+    int signed_frames = 0;
+    const char* kvpairs = NULL;
+
+    ALOGV("%s out->format %d", __func__, out->format);
+    if(out->format & AUDIO_FORMAT_PCM_16_BIT) {
+       *frames = out->written;
+       signed_frames = out->written - (platform_render_latency(out->usecase) * out->sample_rate / 1000000LL);
+       // It would be unusual for this value to be negative, but check just in case ...
+       if (signed_frames >= 0) {
+           *frames = signed_frames;
+       }
+       clock_gettime(CLOCK_MONOTONIC, timestamp);
+    } else if (qaf_mod->qaf_audio_stream_get_param) {
+        kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle, "position");
+        if (kvpairs) {
+            parms = str_parms_create_str(kvpairs);
+            ret = str_parms_get_int(parms, "position", &value);
+            if (ret >= 0) {
+                *frames = value;
+                signed_frames = value - (platform_render_latency(out->usecase) * out->sample_rate / 1000000LL);
+                // It would be unusual for this value to be negative, but check just in case ...
+                if (signed_frames >= 0) {
+                    *frames = signed_frames;
+                }
+                clock_gettime(CLOCK_MONOTONIC, timestamp);
+            }
+            str_parms_destroy(parms);
+        }
+    } else {
+        ret = -EINVAL;
+    }
+    return ret;
+}
+
+static int qaf_out_get_presentation_position(const struct audio_stream_out *stream,
+                                   uint64_t *frames, struct timespec *timestamp)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int ret = -1;
+    lock_output_stream(out);
+    ret = qaf_get_timestamp(out, frames, timestamp);
+    pthread_mutex_unlock(&out->lock);
+
+    return ret;
+}
+
+static int qaf_stream_pause(struct stream_out *out)
+{
+    ALOGV("%s: %d start", __func__, __LINE__);
+    if (!qaf_mod->qaf_audio_stream_pause)
+        return -EINVAL;
+
+    return qaf_mod->qaf_audio_stream_pause(out->qaf_stream_handle);
+}
+
+static int qaf_out_pause(struct audio_stream_out* stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int status = -ENOSYS;
+    ALOGE("%s", __func__);
+    lock_output_stream(out);
+    status = qaf_stream_pause(out);
+    pthread_mutex_unlock(&out->lock);
+    return status;
+}
+
+static int qaf_out_resume(struct audio_stream_out* stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int status = -ENOSYS;
+    ALOGD("%s", __func__);
+    lock_output_stream(out);
+    status = qaf_stream_start(out);
+    pthread_mutex_unlock(&out->lock);
+    ALOGD("%s Exit", __func__);
+    return status;
+}
+
+static int qaf_out_drain(struct audio_stream_out* stream, audio_drain_type_t type __unused )
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    int status = 0;
+    ALOGV("%s stream_handle = %p , format = %x", __func__, out->qaf_stream_handle, out->format);
+    lock_output_stream(out);
+    if (out->offload_callback && out->qaf_stream_handle) {
+        /* Stream stop will trigger EOS and on EOS_EVENT received
+           from callback DRAIN_READY command is sent */
+        status = audio_extn_qaf_stream_stop(out);
+        if (out->format != AUDIO_FORMAT_PCM_16_BIT)
+            qaf_mod->stream_drain_main = out;
+    }
+    pthread_mutex_unlock(&out->lock);
+    return status;
+}
+
+static int audio_extn_qaf_stream_flush(struct stream_out *out)
+{
+    ALOGV("%s: %d exit", __func__, __LINE__);
+    if (!qaf_mod->qaf_audio_stream_flush)
+        return -EINVAL;
+
+    return qaf_mod->qaf_audio_stream_flush(out->qaf_stream_handle);
+}
+
+static int qaf_out_flush(struct audio_stream_out* stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    ALOGV("%s", __func__);
+    int status = -ENOSYS;
+    lock_output_stream(out);
+    status = audio_extn_qaf_stream_flush(out);
+    pthread_mutex_unlock(&out->lock);
+    ALOGV("%s Exit", __func__);
+    return status;
+}
+
+static uint32_t qaf_out_get_latency(const struct audio_stream_out *stream __unused)
+{
+    uint32_t latency = 0;
+
+    latency = QAF_LATENCY;
+    ALOGV("%s: Latency %d", __func__, latency);
+    return latency;
+}
+
+static void notify_event_callback(audio_session_handle_t session_handle __unused, void *prv_data, void *buf, audio_event_id_t event_id, int size, int device)
+{
+
+/*
+ For SPKR:
+ 1. Open pcm device if device_id passed to it SPKR and write the data to pcm device
+
+ For HDMI
+ 1.Open compress device for HDMI(PCM or AC3) based on current_hdmi_output_format
+ 2.create offload_callback thread to receive async events
+ 3.Write the data to compress device. If not all the data is consumed by the driver,
+   add a command to offload_callback thread.
+*/
+    int ret;
+    audio_output_flags_t flags;
+    struct qaf* qaf_module = (struct qaf* ) prv_data;
+    ALOGV("%s device 0x%X, %d in event = %d", __func__, device, __LINE__, event_id);
+
+    if (event_id == AUDIO_DATA_EVENT) {
+        ALOGVV("Device id %x %s %d, bytes to written %d", device, __func__,__LINE__, size);
+
+        pthread_mutex_lock(&qaf_module->lock);
+        if ((device == (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DD)) ||
+            (device == (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DDP))) {
+
+            if (NULL == qaf_mod->qaf_compr_passthrough_out) {
+                struct audio_config config;
+                audio_devices_t devices;
+
+                if (qaf_mod->qaf_compr_offload_out) {
+                    adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev,
+                                                 (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out));
+                    qaf_mod->qaf_compr_offload_out = NULL;
+                }
+
+                config.sample_rate = config.offload_info.sample_rate = QAF_OUTPUT_SAMPLING_RATE;
+                config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
+                config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
+
+                if (device == (AUDIO_DEVICE_OUT_AUX_DIGITAL | AUDIO_COMPRESSED_OUT_DDP))
+                    config.format = config.offload_info.format = AUDIO_FORMAT_E_AC3;
+                else
+                    config.format = config.offload_info.format = AUDIO_FORMAT_AC3;
+
+                config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+                config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
+                flags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_NON_BLOCKING;
+                devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
+
+                ret = adev_open_output_stream((struct audio_hw_device *) qaf_mod->adev, QAF_DEFAULT_COMPR_PASSTHROUGH_HANDLE, devices,
+                                           flags, &config, (struct audio_stream_out **) &(qaf_mod->qaf_compr_passthrough_out), NULL);
+                if (ret < 0) {
+                    ALOGE("%s: adev_open_output_stream failed with ret = %d!", __func__, ret);
+                    pthread_mutex_unlock(&qaf_module->lock);
+                    return;
+                }
+            }
+
+            if (!qaf_mod->passthrough_enabled)
+                qaf_mod->passthrough_enabled = 1;
+
+            ret = qaf_mod->qaf_compr_passthrough_out->stream.write((struct audio_stream_out *) qaf_mod->qaf_compr_passthrough_out, buf, size);
+        } else {
+            if (device == AUDIO_DEVICE_OUT_AUX_DIGITAL && !qaf_mod->multi_ch_out_enabled) {
+                if (qaf_mod->qaf_compr_offload_out) {
+                    adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev,
+                                                 (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out));
+                    qaf_mod->qaf_compr_offload_out = NULL;
+                }
+                qaf_mod->multi_ch_out_enabled = 1;
+            } else if (device == AUDIO_DEVICE_OUT_SPEAKER && qaf_mod->multi_ch_out_enabled) {
+                if (qaf_mod->qaf_compr_offload_out) {
+                    adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev,
+                                                 (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out));
+                    qaf_mod->qaf_compr_offload_out = NULL;
+                }
+                qaf_mod->multi_ch_out_enabled = 0;
+            }
+
+            if (NULL == qaf_mod->qaf_compr_offload_out) {
+                struct audio_config config;
+                audio_devices_t devices;
+
+                config.sample_rate = config.offload_info.sample_rate = QAF_OUTPUT_SAMPLING_RATE;
+                config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
+                config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
+                config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT_OFFLOAD;
+                config.offload_info.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+                config.format = AUDIO_FORMAT_PCM_16_BIT_OFFLOAD;
+                devices = AUDIO_DEVICE_NONE;
+
+                if (device == AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+                    if (qaf_mod->hdmi_sink_channels == 8) {
+                        config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_7POINT1;
+                    } else if (qaf_mod->hdmi_sink_channels == 6) {
+                        config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
+                    } else {
+                        config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+                    }
+                    devices = AUDIO_DEVICE_OUT_AUX_DIGITAL;
+                } else {
+                    config.offload_info.channel_mask = config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+                    qaf_mod->multi_ch_out_enabled = 0;
+                }
+                flags = AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING;
+
+                /* TODO:: Need to Propagate errors to framework */
+                ret = adev_open_output_stream((struct audio_hw_device *) qaf_mod->adev, QAF_DEFAULT_COMPR_AUDIO_HANDLE, devices,
+                                             flags, &config, (struct audio_stream_out **) &(qaf_mod->qaf_compr_offload_out), NULL);
+                if (ret < 0) {
+                    ALOGE("%s: adev_open_output_stream failed with ret = %d!", __func__, ret);
+                    pthread_mutex_unlock(&qaf_module->lock);
+                    return;
+                }
+            }
+
+            if (qaf_mod->passthrough_enabled) {
+                qaf_mod->passthrough_enabled = 0;
+                if (qaf_mod->qaf_compr_passthrough_out) {
+                    adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev,
+                                                 (struct audio_stream_out *) (qaf_mod->qaf_compr_passthrough_out));
+                    qaf_mod->qaf_compr_passthrough_out = NULL;
+                }
+            }
+
+            /*
+             * TODO:: Since this is mixed data,
+             * need to identify to which stream the error should be sent
+             */
+            ret = qaf_mod->qaf_compr_offload_out->stream.write((struct audio_stream_out *) qaf_mod->qaf_compr_offload_out, buf, size);
+        }
+
+        ALOGVV("%s:%d stream write ret = %d for out handle[%p]", __func__, __LINE__, ret, qaf_mod->qaf_compr_offload_out);
+        pthread_mutex_unlock(&qaf_module->lock);
+    } else if (event_id == AUDIO_EOS_MAIN_DD_DDP_EVENT || event_id == AUDIO_EOS_MAIN_AAC_EVENT) {
+        /* TODO:: Only MAIN Stream EOS Event is added, need to add ASSOC stream EOS Event */
+        struct stream_out *out = qaf_module->stream_drain_main;
+        if (out != NULL) {
+            lock_output_stream(out);
+            out->offload_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out->offload_cookie);
+            pthread_mutex_unlock(&out->lock);
+            qaf_module->stream_drain_main = NULL;
+            ALOGV("%s %d sent DRAIN_READY", __func__, __LINE__);
+        }
+    }
+    ALOGV("%s %d", __func__, __LINE__);
+}
+
+static int qaf_session_close()
+{
+    ALOGV("%s %d", __func__, __LINE__);
+    if (qaf_mod != NULL) {
+        if (!qaf_mod->qaf_audio_session_close)
+            return -EINVAL;
+
+        qaf_mod->qaf_audio_session_close(qaf_mod->session_handle);
+        qaf_mod->session_handle = NULL;
+        pthread_mutex_destroy(&qaf_mod->lock);
+    }
+    return 0;
+}
+
+static int qaf_stream_close(struct stream_out *out)
+{
+    int ret = 0;
+    ALOGV( "%s %d", __func__, __LINE__);
+    if (!qaf_mod->qaf_audio_stream_close)
+        return -EINVAL;
+    if (out->qaf_stream_handle) {
+        ALOGV( "%s %d output active flag is %x and stream handle %p", __func__, __LINE__, out->flags, out->qaf_stream_handle);
+        if ((out->flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) && (out->flags & AUDIO_OUTPUT_FLAG_MAIN)) { /* Close for Stream with Main and Associated Content*/
+            qaf_mod->main_output_active = false;
+            qaf_mod->assoc_output_active = false;
+        } else if (out->flags & AUDIO_OUTPUT_FLAG_MAIN) {/*Close for Main Stream*/
+            qaf_mod->main_output_active = false;
+            qaf_mod->assoc_output_active = false; /* TODO to remove resetting associated stream active flag when main stream is closed*/
+        } else if (out->flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) { /*Close for Associated Stream*/
+            qaf_mod->assoc_output_active = false;
+        } else { /*Close for Local Playback*/
+            qaf_mod->main_output_active = false;
+        }
+        ret = qaf_mod->qaf_audio_stream_close(out->qaf_stream_handle);
+        out->qaf_stream_handle = NULL;
+    }
+    ALOGV( "%s %d", __func__, __LINE__);
+    return ret;
+}
+
+static int qaf_stream_open(struct stream_out *out, struct audio_config *config, audio_output_flags_t flags, audio_devices_t devices)
+{
+    int status = 0;
+    ALOGV("%s %d", __func__, __LINE__);
+
+    if (!qaf_mod->qaf_audio_stream_open)
+        return -EINVAL;
+
+    audio_stream_config_t input_config;
+    input_config.sample_rate = config->sample_rate;
+    input_config.channel_mask = config->channel_mask;
+    input_config.format = config->format;
+
+    if ((config->format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC) {
+        input_config.format = AUDIO_FORMAT_AAC;
+    } else if((config->format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_ADTS) {
+        input_config.format = AUDIO_FORMAT_AAC_ADTS;
+    }
+
+    ALOGV("%s %d audio_stream_open sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x) format(%#x)\
+      ",__func__, __LINE__, input_config.sample_rate, input_config.channel_mask, devices, flags, input_config.format);
+
+    /* TODO to send appropriated flags when support for system tones is added */
+    if (input_config.format == AUDIO_FORMAT_PCM_16_BIT) {
+        status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_SYSTEM_TONE);
+    } else if (input_config.format == AUDIO_FORMAT_AC3 ||
+               input_config.format == AUDIO_FORMAT_E_AC3 ||
+               input_config.format == AUDIO_FORMAT_AAC ||
+               input_config.format == AUDIO_FORMAT_AAC_ADTS) {
+        if (qaf_mod->main_output_active == false) {
+            if ((flags & AUDIO_OUTPUT_FLAG_MAIN) && (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED)) {
+                status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_MAIN);
+                if (status == 0) {
+                    ALOGV("%s %d Open stream for Input with both Main and Associated stream contents with flag [%x] and stream handle [%p]", __func__, __LINE__, flags, out->qaf_stream_handle);
+                    qaf_mod->main_output_active = true;
+                    qaf_mod->assoc_output_active = true;
+                }
+            } else if (flags & AUDIO_OUTPUT_FLAG_MAIN) {
+                status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_MAIN);
+                if (status == 0) {
+                    ALOGV("%s %d Open stream for Input with only Main flag [%x] stream handle [%p]", __func__, __LINE__, flags, out->qaf_stream_handle);
+                    qaf_mod->main_output_active = true;
+                }
+            } else if (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) {
+                ALOGE("%s %d Error main input is not active", __func__, __LINE__);
+                return -EINVAL;
+            } else {
+                status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_MAIN);
+                if (status == 0) {
+                    ALOGV("%s %d Open stream for Local playback with flag [%x] stream handle [%p] ", __func__, __LINE__, flags, out->qaf_stream_handle);
+                    qaf_mod->main_output_active = true;
+                }
+            }
+        } else {
+            if (flags & AUDIO_OUTPUT_FLAG_MAIN) {
+                ALOGE("%s %d Error main input is already active", __func__, __LINE__);
+                return -EINVAL;
+            } else if (flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) {
+                if (qaf_mod->assoc_output_active) {
+                    ALOGE("%s %d Error assoc input is already active", __func__, __LINE__);
+                    return -EINVAL;
+                } else {
+                    status = qaf_mod->qaf_audio_stream_open(qaf_mod->session_handle, &out->qaf_stream_handle, input_config, devices, /*flags*/AUDIO_STREAM_ASSOCIATED);
+                    if (status == 0) {
+                        ALOGV("%s %d Open stream for Input with only Associated flag [%x] stream handle [%p]", __func__, __LINE__, flags, out->qaf_stream_handle);
+                        qaf_mod->assoc_output_active = true;
+                    }
+                }
+            } else {
+                ALOGE("%s %d Error main input is already active", __func__, __LINE__);
+                return -EINVAL;
+            }
+        }
+    }
+
+    return status;
+}
+
+static int qaf_deinit()
+{
+    ALOGV("%s %d", __func__, __LINE__);
+    if (qaf_mod != NULL) {
+        if (qaf_mod->qaf_compr_offload_out != NULL)
+            adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_compr_offload_out));
+        if (qaf_mod->qaf_compr_passthrough_out != NULL)
+            adev_close_output_stream((struct audio_hw_device *) qaf_mod->adev, (struct audio_stream_out *) (qaf_mod->qaf_compr_passthrough_out));
+
+        if (qaf_mod->qaf_lib != NULL) {
+            dlclose(qaf_mod->qaf_lib);
+            qaf_mod->qaf_lib = NULL;
+        }
+        free(qaf_mod);
+        qaf_mod = NULL;
+    }
+    return 0;
+}
+
+static void *qaf_offload_thread_loop(void *context)
+{
+    struct stream_out *out = (struct stream_out *) context;
+    struct listnode *item;
+    int ret = 0;
+    struct str_parms *parms = NULL;
+    int value = 0;
+    char* kvpairs = NULL;
+
+    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
+    set_sched_policy(0, SP_FOREGROUND);
+    prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0);
+
+    ALOGE("%s", __func__);
+    lock_output_stream(out);
+    for (;;) {
+        struct offload_cmd *cmd = NULL;
+        stream_callback_event_t event;
+        bool send_callback = false;
+
+        ALOGV("%s qaf_offload_cmd_list %d",
+              __func__, list_empty(&out->qaf_offload_cmd_list));
+        if (list_empty(&out->qaf_offload_cmd_list)) {
+            ALOGV("%s SLEEPING", __func__);
+            pthread_cond_wait(&out->qaf_offload_cond, &out->lock);
+            ALOGV("%s RUNNING", __func__);
+            continue;
+        }
+
+        item = list_head(&out->qaf_offload_cmd_list);
+        cmd = node_to_item(item, struct offload_cmd, node);
+        list_remove(item);
+
+        if (cmd->cmd == OFFLOAD_CMD_EXIT) {
+            free(cmd);
+            break;
+        }
+
+        pthread_mutex_unlock(&out->lock);
+        send_callback = false;
+        switch(cmd->cmd) {
+        case OFFLOAD_CMD_WAIT_FOR_BUFFER:
+            ALOGV("wait for ms12 buffer availability");
+            while (1) {
+                kvpairs = qaf_mod->qaf_audio_stream_get_param(out->qaf_stream_handle, "buf_available");
+                if (kvpairs) {
+                    parms = str_parms_create_str(kvpairs);
+                    ret = str_parms_get_int(parms, "buf_available", &value);
+                    if (ret >= 0) {
+                        if (value >= (int)out->compr_config.fragment_size) {
+                            ALOGV("%s buffer available", __func__);
+                            str_parms_destroy(parms);
+                            parms = NULL;
+                            break;
+                        } else {
+                            ALOGV("%s sleep", __func__);
+                            str_parms_destroy(parms);
+                            parms = NULL;
+                            usleep(10000);
+                        }
+                    }
+                    free(kvpairs);
+                    kvpairs = NULL;
+                }
+            }
+            send_callback = true;
+            event = STREAM_CBK_EVENT_WRITE_READY;
+            break;
+        default:
+            ALOGV("%s unknown command received: %d", __func__, cmd->cmd);
+            break;
+        }
+        lock_output_stream(out);
+        if (send_callback && out->offload_callback) {
+            out->offload_callback(event, NULL, out->offload_cookie);
+        }
+        free(cmd);
+    }
+
+    while (!list_empty(&out->qaf_offload_cmd_list)) {
+        item = list_head(&out->qaf_offload_cmd_list);
+        list_remove(item);
+        free(node_to_item(item, struct offload_cmd, node));
+    }
+    pthread_mutex_unlock(&out->lock);
+
+    return NULL;
+}
+
+static int qaf_create_offload_callback_thread(struct stream_out *out)
+{
+    ALOGV("%s", __func__);
+    pthread_cond_init(&out->qaf_offload_cond, (const pthread_condattr_t *) NULL);
+    list_init(&out->qaf_offload_cmd_list);
+    pthread_create(&out->qaf_offload_thread, (const pthread_attr_t *) NULL,
+                    qaf_offload_thread_loop, out);
+    return 0;
+}
+
+static int qaf_destroy_offload_callback_thread(struct stream_out *out)
+{
+    ALOGV("%s", __func__);
+    lock_output_stream(out);
+    qaf_send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);
+    pthread_mutex_unlock(&out->lock);
+
+    pthread_join(out->qaf_offload_thread, (void **) NULL);
+    pthread_cond_destroy(&out->qaf_offload_cond);
+
+    return 0;
+}
+
+int audio_extn_qaf_open_output_stream(struct audio_hw_device *dev,
+                                   audio_io_handle_t handle,
+                                   audio_devices_t devices,
+                                   audio_output_flags_t flags,
+                                   struct audio_config *config,
+                                   struct audio_stream_out **stream_out,
+                                   const char *address __unused)
+{
+    int ret = 0;
+    struct stream_out *out;
+
+    ret = adev_open_output_stream(dev, handle, devices, flags, config, stream_out, address);
+    if (*stream_out == NULL) {
+        goto error_open;
+    }
+
+    out = (struct stream_out *) *stream_out;
+
+    /* Override function pointers based on qaf definitions */
+    out->stream.set_volume = qaf_out_set_volume;
+    out->stream.pause = qaf_out_pause;
+    out->stream.resume = qaf_out_resume;
+    out->stream.drain = qaf_out_drain;
+    out->stream.flush = qaf_out_flush;
+
+    out->stream.common.standby = qaf_out_standby;
+    out->stream.common.set_parameters = qaf_out_set_parameters;
+    out->stream.get_latency = qaf_out_get_latency;
+    out->stream.write = qaf_out_write;
+    out->stream.get_presentation_position = qaf_out_get_presentation_position;
+
+    ret = qaf_stream_open(out, config, flags, devices);
+    if (ret < 0) {
+        ALOGE("%s, Error opening QAF stream err[%d]!", __func__, ret);
+        adev_close_output_stream(dev, *stream_out);
+        goto error_open;
+    }
+
+    if (out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY) {
+        out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
+        out->config.period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE;
+        out->config.period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT;
+        out->config.start_threshold = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4;
+        out->config.avail_min = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4;
+    }
+
+    *stream_out = &out->stream;
+    if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+        qaf_create_offload_callback_thread(out);
+    }
+    ALOGV("%s: exit", __func__);
+    return 0;
+error_open:
+    *stream_out = NULL;
+    ALOGD("%s: exit: ret %d", __func__, ret);
+    return ret;
+}
+
+void audio_extn_qaf_close_output_stream(struct audio_hw_device *dev,
+                                     struct audio_stream_out *stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+
+    ALOGV("%s: enter:stream_handle(%p) format = %x", __func__, out, out->format);
+    if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+        qaf_destroy_offload_callback_thread(out);
+    }
+    qaf_mod->stream_drain_main = NULL;
+    lock_output_stream(out);
+    qaf_stream_close(out);
+    pthread_mutex_unlock(&out->lock);
+
+    adev_close_output_stream(dev, stream);
+    ALOGV("%s: exit", __func__);
+}
+
+bool audio_extn_qaf_is_enabled()
+{
+    bool prop_enabled = false;
+    char value[PROPERTY_VALUE_MAX] = {0};
+    property_get("audio.qaf.enabled", value, NULL);
+    prop_enabled = atoi(value) || !strncmp("true", value, 4);
+    return (prop_enabled);
+}
+
+int audio_extn_qaf_session_open(struct qaf *qaf_mod,
+                                device_license_config_t* lic_config)
+{
+    ALOGV("%s %d", __func__, __LINE__);
+    int status = -ENOSYS;
+
+    pthread_mutex_init(&qaf_mod->lock, (const pthread_mutexattr_t *) NULL);
+
+    if (!qaf_mod->qaf_audio_session_open)
+       return -EINVAL;
+
+    status = qaf_mod->qaf_audio_session_open(&qaf_mod->session_handle,
+                                             (void *)(qaf_mod), (void *)lic_config);
+    if(status < 0)
+        return status;
+
+    if (qaf_mod->session_handle == NULL) {
+        ALOGE("%s %d QAF wrapper session handle is NULL", __func__, __LINE__);
+        return -ENOMEM;
+    }
+    if (qaf_mod->qaf_register_event_callback)
+        qaf_mod->qaf_register_event_callback(qaf_mod->session_handle,
+                                             qaf_mod, &notify_event_callback,
+                                             AUDIO_DATA_EVENT);
+    return status;
+}
+
+char* audio_extn_qaf_stream_get_param(struct stream_out *out __unused, const char *kv_pair __unused)
+{
+   return NULL;
+}
+
+int audio_extn_qaf_set_parameters(struct audio_device *adev, struct str_parms *parms)
+{
+    int status = 0, val = 0, channels = 0;
+    char *format_params, *kv_parirs;
+    struct str_parms *qaf_params;
+    char value[32];
+    bool passth_support = false;
+
+    ALOGV("%s %d ", __func__, __LINE__);
+    if (!qaf_mod || !qaf_mod->qaf_audio_session_set_param) {
+        return -EINVAL;
+    }
+
+    status = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
+    if (status >= 0) {
+        val = atoi(value);
+        if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+            if (property_get_bool("audio.offload.passthrough", false) &&
+                property_get_bool("audio.qaf.reencode", false)) {
+
+                qaf_params = str_parms_create();
+                if (platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_E_AC3)) {
+                    passth_support = true;
+                    if (qaf_params) {
+                        str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
+                                              AUDIO_QAF_PARAMETER_VALUE_REENCODE_EAC3);
+                    }
+                } else if (platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_AC3)) {
+                    passth_support = true;
+                    if (qaf_params) {
+                        str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
+                                              AUDIO_QAF_PARAMETER_VALUE_REENCODE_AC3);
+                    }
+                }
+
+                if (passth_support) {
+                    str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
+                                          AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
+                    format_params = str_parms_to_str(qaf_params);
+
+                    qaf_mod->qaf_audio_session_set_param(qaf_mod->session_handle, format_params);
+                }
+                str_parms_destroy(qaf_params);
+            }
+
+            if (!passth_support) {
+                channels = platform_edid_get_max_channels(adev->platform);
+
+                qaf_params = str_parms_create();
+                switch (channels) {
+                    case 8:
+                          ALOGV("%s: Switching Qaf output to 7.1 channels", __func__);
+                          str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_CHANNELS,
+                                                AUDIO_QAF_PARAMETER_VALUE_8_CHANNELS);
+                          str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
+                                                AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
+                          qaf_mod->hdmi_sink_channels = channels;
+                          break;
+                    case 6:
+                          ALOGV("%s: Switching Qaf output to 5.1 channels", __func__);
+                          str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_CHANNELS,
+                                                AUDIO_QAF_PARAMETER_VALUE_6_CHANNELS);
+                          str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
+                                                AUDIO_QAF_PARAMETER_VALUE_DEVICE_HDMI);
+                          qaf_mod->hdmi_sink_channels = channels;
+                          break;
+                    default:
+                          str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
+                                                AUDIO_QAF_PARAMETER_VALUE_DEVICE_SPEAKER);
+                          qaf_mod->hdmi_sink_channels = 2;
+                        break;
+                }
+
+                format_params = str_parms_to_str(qaf_params);
+                qaf_mod->qaf_audio_session_set_param(qaf_mod->session_handle, format_params);
+                str_parms_destroy(qaf_params);
+            }
+        }
+    }
+
+    status = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value, sizeof(value));
+    if (status >= 0) {
+        val = atoi(value);
+        if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+            qaf_params = str_parms_create();
+            str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_DEVICE,
+                                  AUDIO_QAF_PARAMETER_VALUE_DEVICE_SPEAKER);
+            str_parms_add_str(qaf_params, AUDIO_QAF_PARAMETER_KEY_RENDER_FORMAT,
+                                  AUDIO_QAF_PARAMETER_VALUE_PCM);
+            qaf_mod->hdmi_sink_channels = 0;
+
+            format_params = str_parms_to_str(qaf_params);
+            qaf_mod->qaf_audio_session_set_param(qaf_mod->session_handle, format_params);
+            str_parms_destroy(qaf_params);
+        }
+    }
+
+    kv_parirs = str_parms_to_str(parms);
+    qaf_mod->qaf_audio_session_set_param(qaf_mod->session_handle, kv_parirs);
+
+    return status;
+}
+
+char* audio_extn_qaf_get_param(struct audio_device *adev __unused, const char *kv_pair __unused)
+{
+    return 0;
+}
+
+int audio_extn_qaf_init(struct audio_device *adev)
+{
+    char value[PROPERTY_VALUE_MAX] = {0};
+    char lib_name[PROPERTY_VALUE_MAX] = {0};
+    unsigned char* license_data = NULL;
+    device_license_config_t* lic_config = NULL;
+    ALOGV("%s %d", __func__, __LINE__);
+    int ret = 0, size = 0;
+
+    qaf_mod = malloc(sizeof(struct qaf));
+    if(qaf_mod == NULL) {
+        ALOGE("%s, out of memory", __func__);
+        ret = -ENOMEM;
+        goto done;
+    }
+    memset(qaf_mod, 0, sizeof(struct qaf));
+    lic_config = (device_license_config_t*) calloc(1, sizeof(device_license_config_t));
+    if(lic_config == NULL) {
+        ALOGE("%s, out of memory", __func__);
+        ret = -ENOMEM;
+        goto done;
+    }
+    qaf_mod->adev = adev;
+    property_get("audio.qaf.library", value, NULL);
+    snprintf(lib_name, PROPERTY_VALUE_MAX, "%s", value);
+
+    license_data = platform_get_license((struct audio_hw_device *)(qaf_mod->adev->platform), &size);
+    if (!license_data) {
+        ALOGE("License is not present");
+        ret = -EINVAL;
+        goto done;
+    }
+    lic_config->p_license = (unsigned char* ) calloc(1, size);
+     if(lic_config->p_license == NULL) {
+        ALOGE("%s, out of memory", __func__);
+        ret = -ENOMEM;
+        goto done;
+    }
+    lic_config->l_size = size;
+    memcpy(lic_config->p_license, license_data, size);
+
+    if (property_get("audio.qaf.manufacturer", value, "") && atoi(value)) {
+        lic_config->manufacturer_id = (unsigned long) atoi (value);
+    } else {
+        ALOGE("audio.qaf.manufacturer id is not set");
+        ret = -EINVAL;
+        goto done;
+    }
+
+    ret = audio_extn_qaf_session_open(qaf_mod, lic_config);
+done:
+    if (license_data != NULL) {
+        free(license_data);
+        license_data = NULL;
+    }
+    if (lic_config->p_license != NULL) {
+        free(lic_config->p_license);
+        lic_config->p_license = NULL;
+    }
+    if (lic_config != NULL) {
+        free(lic_config);
+        lic_config = NULL;
+    }
+    if (ret != 0) {
+        if (qaf_mod != NULL) {
+            free(qaf_mod);
+            qaf_mod = NULL;
+        }
+    }
+    return ret;
+}
+
+void audio_extn_qaf_deinit()
+{
+    qaf_session_close();
+    qaf_deinit();
+}
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
index 1f88c71..008130f 100644
--- a/hal/audio_extn/spkr_protection.c
+++ b/hal/audio_extn/spkr_protection.c
@@ -117,6 +117,11 @@
     SPKR_PROTECTION_MODE_CALIBRATE = 1,
 };
 
+struct spkr_prot_r0t0 {
+    int r0[SP_V2_NUM_MAX_SPKRS];
+    int t0[SP_V2_NUM_MAX_SPKRS];
+};
+
 struct speaker_prot_session {
     int spkr_prot_mode;
     int spkr_processing_state;
@@ -142,6 +147,7 @@
     bool spkr_prot_enable;
     bool spkr_in_use;
     struct timespec spkr_last_time_used;
+    struct spkr_prot_r0t0 sp_r0t0_cal;
     bool wsa_found;
     int spkr_1_tzn;
     int spkr_2_tzn;
@@ -340,6 +346,7 @@
     int ret = 0;
     struct audio_cal_fb_spk_prot_cfg    cal_data;
     char value[PROPERTY_VALUE_MAX];
+    static int cal_done = 0;
 
     if (cal_fd < 0) {
         ALOGE("%s: Error: cal_fd = %d", __func__, cal_fd);
@@ -382,6 +389,13 @@
         ret = -ENODEV;
         goto done;
     }
+    if (protCfg->mode == MSM_SPKR_PROT_CALIBRATED  && !cal_done) {
+        handle.sp_r0t0_cal.r0[SP_V2_SPKR_1] = protCfg->r0[SP_V2_SPKR_1];
+        handle.sp_r0t0_cal.r0[SP_V2_SPKR_2] = protCfg->r0[SP_V2_SPKR_2];
+        handle.sp_r0t0_cal.t0[SP_V2_SPKR_1] = protCfg->t0[SP_V2_SPKR_1];
+        handle.sp_r0t0_cal.t0[SP_V2_SPKR_2] = protCfg->t0[SP_V2_SPKR_2];
+        cal_done = 1;
+    }
 done:
     return ret;
 }
@@ -1347,12 +1361,48 @@
     }
 }
 
+int audio_extn_select_spkr_prot_cal_data(snd_device_t snd_device)
+{
+    struct audio_cal_info_spk_prot_cfg protCfg;
+    int acdb_fd = -1;
+    int ret = 0;
+
+    acdb_fd = open("/dev/msm_audio_cal", O_RDWR | O_NONBLOCK);
+    if (acdb_fd < 0) {
+        ALOGE("%s: open msm_acdb failed", __func__);
+        return -ENODEV;
+    }
+    switch(snd_device) {
+        case SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED_VBAT:
+        case SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED:
+            protCfg.r0[SP_V2_SPKR_1] = handle.sp_r0t0_cal.r0[SP_V2_SPKR_2];
+            protCfg.r0[SP_V2_SPKR_2] = handle.sp_r0t0_cal.r0[SP_V2_SPKR_1];
+            protCfg.t0[SP_V2_SPKR_1] = handle.sp_r0t0_cal.t0[SP_V2_SPKR_2];
+            protCfg.t0[SP_V2_SPKR_2] = handle.sp_r0t0_cal.t0[SP_V2_SPKR_1];
+            break;
+        default:
+            protCfg.r0[SP_V2_SPKR_1] = handle.sp_r0t0_cal.r0[SP_V2_SPKR_1];
+            protCfg.r0[SP_V2_SPKR_2] = handle.sp_r0t0_cal.r0[SP_V2_SPKR_2];
+            protCfg.t0[SP_V2_SPKR_1] = handle.sp_r0t0_cal.t0[SP_V2_SPKR_1];
+            protCfg.t0[SP_V2_SPKR_2] = handle.sp_r0t0_cal.t0[SP_V2_SPKR_2];
+            break;
+    }
+    protCfg.mode = MSM_SPKR_PROT_CALIBRATED;
+    ret = set_spkr_prot_cal(acdb_fd, &protCfg);
+    if (ret)
+        ALOGE("%s: speaker protection cal data swap failed", __func__);
+
+    close(acdb_fd);
+    return ret;
+}
+
 int audio_extn_spkr_prot_start_processing(snd_device_t snd_device)
 {
     struct audio_usecase *uc_info_tx;
     struct audio_device *adev = handle.adev_handle;
     int32_t pcm_dev_tx_id = -1, ret = 0;
     bool disable_tx = false;
+    snd_device_t in_snd_device;
 
     ALOGV("%s: Entry", __func__);
     /* cancel speaker calibration */
@@ -1361,6 +1411,15 @@
        return -EINVAL;
     }
     snd_device = platform_get_spkr_prot_snd_device(snd_device);
+    if (handle.spkr_prot_mode == MSM_SPKR_PROT_CALIBRATED) {
+        ret = audio_extn_select_spkr_prot_cal_data(snd_device);
+        if (ret) {
+            ALOGE("%s: Setting speaker protection cal data failed", __func__);
+            return ret;
+        }
+    }
+
+    in_snd_device = platform_get_vi_feedback_snd_device(snd_device);
     spkr_prot_set_spkrstatus(true);
     uc_info_tx = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
     if (!uc_info_tx) {
@@ -1375,12 +1434,12 @@
     if (handle.spkr_processing_state == SPKR_PROCESSING_IN_IDLE) {
         uc_info_tx->id = USECASE_AUDIO_SPKR_CALIB_TX;
         uc_info_tx->type = PCM_CAPTURE;
-        uc_info_tx->in_snd_device = SND_DEVICE_IN_CAPTURE_VI_FEEDBACK;
+        uc_info_tx->in_snd_device = in_snd_device;
         uc_info_tx->out_snd_device = SND_DEVICE_NONE;
         handle.pcm_tx = NULL;
         list_add_tail(&adev->usecase_list, &uc_info_tx->list);
         disable_tx = true;
-        enable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK);
+        enable_snd_device(adev, in_snd_device);
         enable_audio_route(adev, uc_info_tx);
 
         pcm_dev_tx_id = platform_get_pcm_device_id(uc_info_tx->id, PCM_CAPTURE);
@@ -1420,9 +1479,9 @@
         list_remove(&uc_info_tx->list);
         uc_info_tx->id = USECASE_AUDIO_SPKR_CALIB_TX;
         uc_info_tx->type = PCM_CAPTURE;
-        uc_info_tx->in_snd_device = SND_DEVICE_IN_CAPTURE_VI_FEEDBACK;
+        uc_info_tx->in_snd_device = in_snd_device;
         uc_info_tx->out_snd_device = SND_DEVICE_NONE;
-        disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK);
+        disable_snd_device(adev, in_snd_device);
         disable_audio_route(adev, uc_info_tx);
         free(uc_info_tx);
     } else
@@ -1436,17 +1495,20 @@
 {
     struct audio_usecase *uc_info_tx;
     struct audio_device *adev = handle.adev_handle;
+    snd_device_t in_snd_device;
 
     ALOGV("%s: Entry", __func__);
     snd_device = platform_get_spkr_prot_snd_device(snd_device);
     spkr_prot_set_spkrstatus(false);
+    in_snd_device = platform_get_vi_feedback_snd_device(snd_device);
+
     pthread_mutex_lock(&handle.mutex_spkr_prot);
     if (adev && handle.spkr_processing_state == SPKR_PROCESSING_IN_PROGRESS) {
         uc_info_tx = get_usecase_from_list(adev, USECASE_AUDIO_SPKR_CALIB_TX);
         if (handle.pcm_tx)
             pcm_close(handle.pcm_tx);
         handle.pcm_tx = NULL;
-        disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK);
+        disable_snd_device(adev, in_snd_device);
         if (uc_info_tx) {
             list_remove(&uc_info_tx->list);
             disable_audio_route(adev, uc_info_tx);
diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c
index a7b10d9..b3bd58f 100644
--- a/hal/audio_extn/usb.c
+++ b/hal/audio_extn/usb.c
@@ -190,33 +190,6 @@
     }
 }
 
-static int usb_set_channel_mixer_ctl(int channel,
-                                     char *ch_mixer_ctl_name)
-{
-    struct mixer_ctl *ctl;
-
-    ctl = mixer_get_ctl_by_name(usbmod->adev->mixer, ch_mixer_ctl_name);
-    if (!ctl) {
-       ALOGE("%s: Could not get ctl for mixer cmd - %s",
-             __func__, ch_mixer_ctl_name);
-       return -EINVAL;
-    }
-    switch (channel) {
-       case 1:
-           mixer_ctl_set_enum_by_string(ctl, "One");
-           break;
-       case 2:
-           mixer_ctl_set_enum_by_string(ctl, "Two");
-           break;
-       default:
-           ALOGV("%s: channel(%d) not supported, set as default 2 channels",
-                 __func__, channel);
-           mixer_ctl_set_enum_by_string(ctl, "Two");
-           break;
-    }
-    return 0;
-}
-
 static int usb_set_dev_id_mixer_ctl(unsigned int usb_usecase_type, int card,
                                     char *dev_mixer_ctl_name)
 {
@@ -472,8 +445,6 @@
                                     int card)
 {
     int ret;
-    struct listnode *node_d;
-    struct usb_device_config *dev_info;
 
     /* get capabilities */
     if ((ret = usb_get_capability(USB_PLAYBACK, usb_card_info, card))) {
@@ -481,14 +452,6 @@
                __func__);
         goto exit;
     }
-    /* Currently only use the first profile using to configure channel for simplification */
-    list_for_each(node_d, &usb_card_info->usb_device_conf_list) {
-        dev_info = node_to_item(node_d, struct usb_device_config, list);
-        if (dev_info != NULL) {
-            usb_set_channel_mixer_ctl(dev_info->channels, "USB_AUDIO_RX Channels");
-            break;
-        }
-    }
     usb_set_dev_id_mixer_ctl(USB_PLAYBACK, card, "USB_AUDIO_RX dev_token");
 
 exit:
@@ -500,8 +463,6 @@
                                       int card)
 {
     int ret;
-    struct listnode *node_d;
-    struct usb_device_config *dev_info;
 
     /* get capabilities */
     if ((ret = usb_get_capability(USB_CAPTURE, usb_card_info, card))) {
@@ -509,14 +470,6 @@
                __func__);
         goto exit;
     }
-    /* Currently only use the first profile using to configure channel for simplification */
-    list_for_each(node_d, &usb_card_info->usb_device_conf_list) {
-        dev_info = node_to_item(node_d, struct usb_device_config, list);
-        if (dev_info != NULL) {
-            usb_set_channel_mixer_ctl(dev_info->channels, "USB_AUDIO_TX Channels");
-            break;
-        }
-    }
     usb_set_dev_id_mixer_ctl(USB_CAPTURE, card, "USB_AUDIO_TX dev_token");
 
 exit:
@@ -909,14 +862,8 @@
                  "%s: card_dev_type (0x%x), card_no(%d)",
                  __func__,  card_info->usb_device_type, card_info->usb_card);
         /* Currently only apply the first playback sound card configuration */
-        if (is_playback && card_info->usb_device_type == AUDIO_DEVICE_OUT_USB_DEVICE) {
-            is_usb_supported = usb_audio_backend_apply_policy(
-                                           &card_info->usb_device_conf_list,
-                                           bit_width,
-                                           sample_rate,
-                                           ch);
-            break;
-        } else if (card_info->usb_device_type == AUDIO_DEVICE_IN_USB_DEVICE ) {
+        if ((is_playback && card_info->usb_device_type == AUDIO_DEVICE_OUT_USB_DEVICE) ||
+            ((!is_playback) && card_info->usb_device_type == AUDIO_DEVICE_IN_USB_DEVICE)){
             is_usb_supported = usb_audio_backend_apply_policy(
                                            &card_info->usb_device_conf_list,
                                            bit_width,
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index df78f83..673c17e 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1234,6 +1234,7 @@
                (DSD_NATIVE_BACKEND == platform_get_backend_index(uc->out_snd_device))) {
             active = true;
             ALOGV("%s:DSD playback is active", __func__);
+            break;
         }
     }
     return active;
@@ -2617,10 +2618,13 @@
 
 static float AmpToDb(float amplification)
 {
-    if (amplification == 0) {
-        return DSD_VOLUME_MIN_DB;
+    float db = DSD_VOLUME_MIN_DB;
+    if (amplification > 0) {
+        db = 20 * log10(amplification);
+        if(db < DSD_VOLUME_MIN_DB)
+            return DSD_VOLUME_MIN_DB;
     }
-    return 20 * log10(amplification);
+    return db;
 }
 
 static int out_set_volume(struct audio_stream_out *stream, float left,
@@ -2807,8 +2811,14 @@
         if ( ret == (ssize_t)bytes && !out->non_blocking)
             out->written += bytes;
 
-        if (!out->playback_started && ret >= 0) {
-            compress_start(out->compr);
+        /* Call compr start only when non-zero bytes of data is there to be rendered */
+        if (!out->playback_started && ret > 0) {
+            int status = compress_start(out->compr);
+            if (status < 0) {
+                ret = status;
+                ALOGE("%s: compr start failed with err %d", __func__, errno);
+                goto exit;
+            }
             audio_extn_dts_eagle_fade(adev, true, out);
             out->playback_started = 1;
             out->offload_state = OFFLOAD_STATE_PLAYING;
@@ -2885,8 +2895,9 @@
             out->standby = true;
         }
         out_standby(&out->stream.common);
-        usleep((uint64_t)bytes * 1000000 / audio_stream_out_frame_size(stream) /
-                        out_get_sample_rate(&out->stream.common));
+        if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))
+            usleep((uint64_t)bytes * 1000000 / audio_stream_out_frame_size(stream) /
+                            out_get_sample_rate(&out->stream.common));
     }
     return bytes;
 }
@@ -3131,8 +3142,12 @@
     if (is_offload_usecase(out->usecase)) {
         ALOGD("copl(%p):calling compress flush", out);
         lock_output_stream(out);
-        stop_compressed_output_l(out);
-        out->written = 0;
+        if (out->offload_state == OFFLOAD_STATE_PAUSED) {
+            stop_compressed_output_l(out);
+            out->written = 0;
+        } else {
+            ALOGW("%s called in invalid state %d", __func__, out->offload_state);
+        }
         pthread_mutex_unlock(&out->lock);
         ALOGD("copl(%p):out of compress flush", out);
         return 0;
@@ -3489,7 +3504,7 @@
     return add_remove_audio_effect(stream, effect, false);
 }
 
-static int adev_open_output_stream(struct audio_hw_device *dev,
+int adev_open_output_stream(struct audio_hw_device *dev,
                                    audio_io_handle_t handle,
                                    audio_devices_t devices,
                                    audio_output_flags_t flags,
@@ -3774,13 +3789,13 @@
                 __func__, config->offload_info.version,
                 config->offload_info.bit_rate);
 
-        /*Check if DSD audio format is supported in codec
-         *and there is no active native DSD use case
+        /* Check if DSD audio format is supported in codec
+         * and there is no active native DSD use case
          */
 
         if ((config->format == AUDIO_FORMAT_DSD) &&
-               (!platform_check_codec_dsd_support(adev->platform) ||
-               audio_is_dsd_native_stream_active(adev))) {
+                (!platform_check_codec_dsd_support(adev->platform) ||
+                audio_is_dsd_native_stream_active(adev))) {
             ret = -EINVAL;
             goto error_open;
         }
@@ -3791,9 +3806,9 @@
          * Direct PCM playback
          */
         if (audio_extn_passthru_is_passthrough_stream(out) ||
-            (config->format == AUDIO_FORMAT_DSD) ||
-            config->offload_info.has_video ||
-            out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) {
+                (config->format == AUDIO_FORMAT_DSD) ||
+                config->offload_info.has_video ||
+                out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) {
             check_and_set_gapless_mode(adev, false);
         } else
             check_and_set_gapless_mode(adev, true);
@@ -3958,7 +3973,7 @@
     return ret;
 }
 
-static void adev_close_output_stream(struct audio_hw_device *dev __unused,
+void adev_close_output_stream(struct audio_hw_device *dev __unused,
                                      struct audio_stream_out *stream)
 {
     struct stream_out *out = (struct stream_out *)stream;
@@ -4574,6 +4589,8 @@
     if ((--audio_device_ref_count) == 0) {
         audio_extn_sound_trigger_deinit(adev);
         audio_extn_listen_deinit(adev);
+        if (audio_extn_qaf_is_enabled())
+            audio_extn_qaf_deinit();
         audio_extn_utils_release_streams_output_cfg_list(&adev->streams_output_cfg_list);
         audio_route_free(adev->audio_route);
         audio_extn_gef_deinit();
@@ -4610,6 +4627,8 @@
 static int adev_open(const hw_module_t *module, const char *name,
                      hw_device_t **device)
 {
+    int ret;
+
     ALOGD("%s: enter", __func__);
     if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) return -EINVAL;
 
@@ -4684,9 +4703,26 @@
         ALOGE("%s: Failed to init platform data, aborting.", __func__);
         *device = NULL;
         pthread_mutex_unlock(&adev_init_lock);
+        pthread_mutex_destroy(&adev->lock);
+        pthread_mutex_destroy(&adev->snd_card_status.lock);
         return -EINVAL;
     }
 
+    if (audio_extn_qaf_is_enabled()) {
+        ret = audio_extn_qaf_init(adev);
+        if (ret < 0) {
+            free(adev);
+            ALOGE("%s: Failed to init platform data, aborting.", __func__);
+            *device = NULL;
+            pthread_mutex_unlock(&adev_init_lock);
+            pthread_mutex_destroy(&adev->lock);
+            return ret;
+        }
+
+        adev->device.open_output_stream = audio_extn_qaf_open_output_stream;
+        adev->device.close_output_stream = audio_extn_qaf_close_output_stream;
+    }
+
     adev->snd_card_status.state = SND_CARD_STATE_ONLINE;
 
     if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) {
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index c1797bd..0633eb0 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -241,6 +241,10 @@
     bool routing_change;
 
     struct audio_device *dev;
+    void* qaf_stream_handle;
+    pthread_cond_t qaf_offload_cond;
+    pthread_t qaf_offload_thread;
+    struct listnode qaf_offload_cmd_list;
 };
 
 struct stream_in {
@@ -427,6 +431,16 @@
 audio_usecase_t get_usecase_id_from_usecase_type(const struct audio_device *adev,
                                                  usecase_type_t type);
 
+int adev_open_output_stream(struct audio_hw_device *dev,
+                            audio_io_handle_t handle,
+                            audio_devices_t devices,
+                            audio_output_flags_t flags,
+                            struct audio_config *config,
+                            struct audio_stream_out **stream_out,
+                            const char *address __unused);
+void adev_close_output_stream(struct audio_hw_device *dev __unused,
+                              struct audio_stream_out *stream);
+
 #define LITERAL_TO_STRING(x) #x
 #define CHECK(condition) LOG_ALWAYS_FATAL_IF(!(condition), "%s",\
             __FILE__ ":" LITERAL_TO_STRING(__LINE__)\
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 25f862e..47943da 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -118,6 +118,8 @@
 #define AUDIO_PARAMETER_KEY_AUD_CALDATA   "cal_data"
 #define AUDIO_PARAMETER_KEY_AUD_CALRESULT "cal_result"
 
+#define AUDIO_PARAMETER_KEY_MONO_SPEAKER "mono_speaker"
+
 /* Reload ACDB files from specified path */
 #define AUDIO_PARAMETER_KEY_RELOAD_ACDB "reload_acdb"
 
@@ -221,6 +223,7 @@
     /* Vbat monitor related flags */
     bool is_vbat_speaker;
     bool gsm_mode_enabled;
+    int mono_speaker;
     /* Audio calibration related functions */
     void                       *acdb_handle;
     int                        voice_feature_set;
@@ -244,7 +247,6 @@
     bool edid_valid;
     int ext_disp_type;
     codec_backend_cfg_t current_backend_cfg[MAX_CODEC_BACKENDS];
-    codec_backend_cfg_t current_tx_backend_cfg[MAX_CODEC_TX_BACKENDS];
     char ec_ref_mixer_path[64];
     char codec_version[CODEC_VERSION_MAX_LENGTH];
     int hw_dep_fd;
@@ -343,6 +345,9 @@
     [SND_DEVICE_OUT_VOICE_SPEAKER] = "voice-speaker",
     [SND_DEVICE_OUT_VOICE_SPEAKER_WSA] = "wsa-voice-speaker",
     [SND_DEVICE_OUT_VOICE_SPEAKER_VBAT] = "vbat-voice-speaker",
+    [SND_DEVICE_OUT_VOICE_SPEAKER_2] = "voice-speaker-2",
+    [SND_DEVICE_OUT_VOICE_SPEAKER_2_WSA] = "wsa-voice-speaker-2",
+    [SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT] = "vbat-voice-speaker-2",
     [SND_DEVICE_OUT_VOICE_HEADPHONES] = "voice-headphones",
     [SND_DEVICE_OUT_VOICE_LINE] = "voice-line",
     [SND_DEVICE_OUT_HDMI] = "hdmi",
@@ -369,8 +374,10 @@
     [SND_DEVICE_OUT_ANC_HANDSET] = "anc-handset",
     [SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected",
     [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = "voice-speaker-protected",
+    [SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED] = "voice-speaker-2-protected",
     [SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT] = "speaker-protected-vbat",
     [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT] = "voice-speaker-protected-vbat",
+    [SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED_VBAT] = "voice-speaker-2-protected-vbat",
 #ifdef RECORD_PLAY_CONCURRENCY
     [SND_DEVICE_OUT_VOIP_HANDSET] = "voip-handset",
     [SND_DEVICE_OUT_VOIP_SPEAKER] = "voip-speaker",
@@ -423,6 +430,8 @@
     [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = "handset-stereo-dmic-ef",
     [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = "speaker-stereo-dmic-ef",
     [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = "vi-feedback",
+    [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_1] = "vi-feedback-mono-1",
+    [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_2] = "vi-feedback-mono-2",
     [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE] = "voice-speaker-dmic-broadside",
     [SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE] = "speaker-dmic-broadside",
     [SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE] = "speaker-dmic-broadside",
@@ -465,8 +474,11 @@
     [SND_DEVICE_OUT_VOICE_HANDSET] = 7,
     [SND_DEVICE_OUT_VOICE_LINE] = 10,
     [SND_DEVICE_OUT_VOICE_SPEAKER] = 14,
+    [SND_DEVICE_OUT_VOICE_SPEAKER_2] = 14,
     [SND_DEVICE_OUT_VOICE_SPEAKER_WSA] = 135,
+    [SND_DEVICE_OUT_VOICE_SPEAKER_2_WSA] = 135,
     [SND_DEVICE_OUT_VOICE_SPEAKER_VBAT] = 135,
+    [SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT] = 135,
     [SND_DEVICE_OUT_VOICE_HEADPHONES] = 10,
     [SND_DEVICE_OUT_HDMI] = 18,
     [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14,
@@ -492,8 +504,10 @@
     [SND_DEVICE_OUT_ANC_HANDSET] = 103,
     [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 124,
     [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = 101,
+    [SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED] = 101,
     [SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT] = 124,
     [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT] = 101,
+    [SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED_VBAT] = 101,
 #ifdef RECORD_PLAY_CONCURRENCY
     [SND_DEVICE_OUT_VOIP_HANDSET] = 133,
     [SND_DEVICE_OUT_VOIP_SPEAKER] = 132,
@@ -545,6 +559,8 @@
     [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = 34,
     [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = 35,
     [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = 102,
+    [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_1] = 102,
+    [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_2] = 102,
     [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE] = 12,
     [SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE] = 12,
     [SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE] = 119,
@@ -591,6 +607,9 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_WSA)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_VBAT)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_2)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_2_WSA)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HEADPHONES)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_LINE)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_HDMI)},
@@ -617,8 +636,10 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_ANC_HANDSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED_VBAT)},
 #ifdef RECORD_PLAY_CONCURRENCY
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_HANDSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_SPEAKER)},
@@ -669,6 +690,8 @@
     {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_STEREO_DMIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_STEREO_DMIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_VI_FEEDBACK)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_1)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_2)},
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_FLUENCE_DMIC_AANC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE)},
     {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE)},
@@ -1224,6 +1247,7 @@
     backend_tag_table[SND_DEVICE_OUT_TRANSMISSION_FM] = strdup("transmission-fm");
     backend_tag_table[SND_DEVICE_OUT_HEADPHONES_44_1] = strdup("headphones-44.1");
     backend_tag_table[SND_DEVICE_OUT_VOICE_SPEAKER_VBAT] = strdup("vbat-voice-speaker");
+    backend_tag_table[SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT] = strdup("vbat-voice-speaker-2");
     backend_tag_table[SND_DEVICE_OUT_BT_A2DP] = strdup("bt-a2dp");
     backend_tag_table[SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP] = strdup("speaker-and-bt-a2dp");
 
@@ -1689,6 +1713,7 @@
     my_data->ext_disp_type = EXT_DISPLAY_TYPE_NONE;
     my_data->is_wsa_speaker = false;
     my_data->hw_dep_fd = -1;
+    my_data->mono_speaker = SPKR_1;
 
     property_get("ro.qc.sdk.audio.fluencetype", my_data->fluence_cap, "");
     if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro"))) {
@@ -1897,16 +1922,13 @@
             my_data->current_backend_cfg[idx].sample_rate = OUTPUT_SAMPLING_RATE_44100;
         my_data->current_backend_cfg[idx].bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
         my_data->current_backend_cfg[idx].channels = CODEC_BACKEND_DEFAULT_CHANNELS;
+        if (idx > MAX_RX_CODEC_BACKENDS)
+            my_data->current_backend_cfg[idx].channels = CODEC_BACKEND_DEFAULT_TX_CHANNELS;
         my_data->current_backend_cfg[idx].bitwidth_mixer_ctl = NULL;
         my_data->current_backend_cfg[idx].samplerate_mixer_ctl = NULL;
         my_data->current_backend_cfg[idx].channels_mixer_ctl = NULL;
     }
 
-    my_data->current_tx_backend_cfg[DEFAULT_CODEC_BACKEND].sample_rate =
-                                               CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
-    my_data->current_tx_backend_cfg[DEFAULT_CODEC_BACKEND].bit_width =
-                                               CODEC_BACKEND_DEFAULT_BIT_WIDTH;
-
     if (is_external_codec) {
         my_data->current_backend_cfg[DEFAULT_CODEC_BACKEND].bitwidth_mixer_ctl =
             strdup("SLIM_0_RX Format");
@@ -1923,9 +1945,9 @@
         my_data->current_backend_cfg[HEADPHONE_BACKEND].samplerate_mixer_ctl =
             strdup("SLIM_6_RX SampleRate");
 
-        my_data->current_tx_backend_cfg[DEFAULT_CODEC_BACKEND].bitwidth_mixer_ctl =
+        my_data->current_backend_cfg[SLIMBUS_0_TX].bitwidth_mixer_ctl =
             strdup("SLIM_0_TX Format");
-        my_data->current_tx_backend_cfg[DEFAULT_CODEC_BACKEND].samplerate_mixer_ctl =
+        my_data->current_backend_cfg[SLIMBUS_0_TX].samplerate_mixer_ctl =
             strdup("SLIM_0_TX SampleRate");
     } else {
         my_data->current_backend_cfg[DEFAULT_CODEC_BACKEND].bitwidth_mixer_ctl =
@@ -1933,16 +1955,17 @@
         my_data->current_backend_cfg[DEFAULT_CODEC_BACKEND].samplerate_mixer_ctl =
             strdup("MI2S_RX SampleRate");
 
-        my_data->current_tx_backend_cfg[DEFAULT_CODEC_TX_BACKEND].bitwidth_mixer_ctl =
+        my_data->current_backend_cfg[DEFAULT_CODEC_TX_BACKEND].bitwidth_mixer_ctl =
             strdup("MI2S_TX Format");
-        my_data->current_tx_backend_cfg[DEFAULT_CODEC_TX_BACKEND].samplerate_mixer_ctl =
+        my_data->current_backend_cfg[DEFAULT_CODEC_TX_BACKEND].samplerate_mixer_ctl =
             strdup("MI2S_TX SampleRate");
-
-        my_data->current_tx_backend_cfg[USB_AUDIO_TX_BACKEND].bitwidth_mixer_ctl =
-            strdup("USB_AUDIO_TX Format");
-        my_data->current_tx_backend_cfg[USB_AUDIO_TX_BACKEND].samplerate_mixer_ctl =
-            strdup("USB_AUDIO_TX SampleRate");
     }
+    my_data->current_backend_cfg[USB_AUDIO_TX_BACKEND].bitwidth_mixer_ctl =
+        strdup("USB_AUDIO_TX Format");
+    my_data->current_backend_cfg[USB_AUDIO_TX_BACKEND].samplerate_mixer_ctl =
+        strdup("USB_AUDIO_TX SampleRate");
+    my_data->current_backend_cfg[USB_AUDIO_TX_BACKEND].channels_mixer_ctl =
+            strdup("USB_AUDIO_TX Channels");
 
     my_data->current_backend_cfg[USB_AUDIO_RX_BACKEND].bitwidth_mixer_ctl =
         strdup("USB_AUDIO_RX Format");
@@ -2081,7 +2104,8 @@
         return;
     }
 
-    if((snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT) &&
+    if ((snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT) &&
         !(usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)) {
         ALOGI("%s: Not adding vbat speaker device to non voice use cases", __func__);
         return;
@@ -2485,7 +2509,7 @@
 {
     int32_t port = DEFAULT_CODEC_BACKEND;
 
-    if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) {
+    if (snd_device >= SND_DEVICE_OUT_BEGIN && snd_device < SND_DEVICE_OUT_END) {
         if (backend_tag_table[snd_device] != NULL) {
                 if (strncmp(backend_tag_table[snd_device], "headphones-44.1",
                             sizeof("headphones-44.1")) == 0)
@@ -2500,29 +2524,17 @@
                 else if (strcmp(backend_tag_table[snd_device], "usb-headphones") == 0)
                         port = USB_AUDIO_RX_BACKEND;
         }
-    } else {
-        ALOGV("%s:napb: Invalid device - %d ", __func__, snd_device);
-    }
-
-    ALOGV("%s:napb: backend port - %d device - %d ", __func__, port,
-        snd_device);
-    return port;
-}
-
-static int platform_get_capture_backend_index(snd_device_t snd_device)
-{
-    int32_t port = DEFAULT_CODEC_TX_BACKEND;
-
-    if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) {
+    } else if (snd_device >= SND_DEVICE_IN_BEGIN && snd_device < SND_DEVICE_IN_END) {
+        port = DEFAULT_CODEC_TX_BACKEND;
         if (backend_tag_table[snd_device] != NULL) {
                 if (strcmp(backend_tag_table[snd_device], "usb-headset-mic") == 0)
                         port = USB_AUDIO_TX_BACKEND;
         }
     } else {
-        ALOGW("%s: Invalid device - %d ", __func__, snd_device);
+        ALOGW("%s:napb: Invalid device - %d ", __func__, snd_device);
     }
 
-    ALOGV("%s: backend port - %d snd_device %d", __func__, port, snd_device);
+    ALOGV("%s:napb: backend port - %d device - %d ", __func__, port, snd_device);
     return port;
 }
 
@@ -2605,7 +2617,9 @@
         return ret;
 
     if ((out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER ||
-         out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT) &&
+         out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2 ||
+         out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT ||
+         out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT) &&
          audio_extn_spkr_prot_is_enabled()) {
         if (my_data->is_vbat_speaker)
             acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT];
@@ -2640,9 +2654,18 @@
     if (my_data->acdb_send_voice_cal == NULL) {
         ALOGE("%s: dlsym error for acdb_send_voice_call", __func__);
     } else {
-        if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER &&
-            audio_extn_spkr_prot_is_enabled())
-            out_snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED;
+        if (audio_extn_spkr_prot_is_enabled()) {
+            if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER ||
+                out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_WSA)
+                out_snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED;
+            else if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2 ||
+                out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2_WSA)
+                out_snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED;
+            else if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT)
+                out_snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT;
+            else if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT)
+                out_snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED_VBAT;
+        }
 
         acdb_rx_id = acdb_device_table[out_snd_device];
         acdb_tx_id = acdb_device_table[in_snd_device];
@@ -2669,7 +2692,9 @@
         return ret;
 
     if ((out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER ||
-         out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT) &&
+         out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2 ||
+         out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT ||
+         out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT) &&
          audio_extn_spkr_prot_is_enabled()) {
         if (my_data->is_vbat_speaker)
             acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT];
@@ -3073,12 +3098,22 @@
         } else if (devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
                 snd_device = SND_DEVICE_OUT_BT_A2DP;
         } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
-                if (my_data->is_vbat_speaker)
-                    snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_VBAT;
-                else if (my_data->is_wsa_speaker)
-                    snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_WSA;
-                else
-                    snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
+                if (my_data->is_vbat_speaker) {
+                    if (my_data->mono_speaker == SPKR_1)
+                        snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_VBAT;
+                    else
+                        snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT;
+                } else if (my_data->is_wsa_speaker) {
+                    if (my_data->mono_speaker == SPKR_1)
+                        snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_WSA;
+                    else
+                        snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_2_WSA;
+                } else {
+                    if (my_data->mono_speaker == SPKR_1)
+                        snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
+                    else
+                        snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_2;
+                }
         } else if (devices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ||
                    devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
             snd_device = SND_DEVICE_OUT_USB_HEADSET;
@@ -3784,6 +3819,16 @@
 
     }
 
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_MONO_SPEAKER, value, len);
+    if (err >= 0) {
+        if (!strncmp("left", value, sizeof("left")))
+            my_data->mono_speaker = SPKR_1;
+        else if (!strncmp("right", value, sizeof("right")))
+            my_data->mono_speaker = SPKR_2;
+
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_MONO_SPEAKER);
+    }
+
 #ifdef RECORD_PLAY_CONCURRENCY
     err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_REC_PLAY_CONC, value, sizeof(value));
     if (err >= 0) {
@@ -3987,6 +4032,13 @@
     free(kv_pairs);
 }
 
+unsigned char* platform_get_license(void *platform __unused, int *size __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return NULL;
+}
+
+
 /* Delay in Us, only to be used for PCM formats */
 int64_t platform_render_latency(audio_usecase_t usecase)
 {
@@ -4020,7 +4072,9 @@
     if ((snd_device >= SND_DEVICE_IN_BEGIN) &&
         (snd_device < SND_DEVICE_IN_END) &&
         (snd_device != SND_DEVICE_IN_CAPTURE_FM) &&
-        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK))
+        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK) &&
+        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_1) &&
+        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_2))
         needs_event = true;
 
     return needs_event;
@@ -4083,7 +4137,9 @@
     if ((snd_device >= SND_DEVICE_IN_BEGIN) &&
         (snd_device < SND_DEVICE_IN_END) &&
         (snd_device != SND_DEVICE_IN_CAPTURE_FM) &&
-        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK))
+        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK) &&
+        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_1) &&
+        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_2))
         needs_event = true;
 
     return needs_event;
@@ -4232,7 +4288,7 @@
     if (bit_width !=
         my_data->current_backend_cfg[backend_idx].bit_width) {
 
-        struct  mixer_ctl *ctl;
+        struct  mixer_ctl *ctl = NULL;
         ctl = mixer_get_ctl_by_name(adev->mixer,
                         my_data->current_backend_cfg[backend_idx].bitwidth_mixer_ctl);
         if (!ctl) {
@@ -4289,14 +4345,24 @@
                 rate_str = "KHZ_44P1";
                 break;
             case 64000:
-            case 88200:
             case 96000:
                 rate_str = "KHZ_96";
                 break;
+            case 88200:
+                rate_str = "KHZ_88P2";
+            break;
             case 176400:
+                rate_str = "KHZ_176P4";
+                break;
             case 192000:
                 rate_str = "KHZ_192";
                 break;
+            case 352800:
+                rate_str = "KHZ_352P8";
+                break;
+            case 384000:
+                rate_str = "KHZ_384";
+                break;
             default:
                 rate_str = "KHZ_48";
                 break;
@@ -4336,6 +4402,9 @@
             channel_cnt_str = "Four"; break;
         case 3:
             channel_cnt_str = "Three"; break;
+        case 1:
+            channel_cnt_str = "One"; break;
+        case 2:
         default:
             channel_cnt_str = "Two"; break;
         }
@@ -4688,127 +4757,6 @@
 }
 
 /*
- * configures afe with bit width and Sample Rate
- */
-
-static int platform_set_capture_codec_backend_cfg(struct audio_device* adev,
-                         snd_device_t snd_device,
-                         struct audio_backend_cfg backend_cfg)
-{
-    int ret = 0;
-    int backend_idx = platform_get_capture_backend_index(snd_device);
-    struct platform_data *my_data = (struct platform_data *)adev->platform;
-
-    ALOGI("%s:txbecf: afe: bitwidth %d, samplerate %d, backend_idx %d device (%s)",
-          __func__, backend_cfg.bit_width, backend_cfg.sample_rate, backend_idx,
-          platform_get_snd_device_name(snd_device));
-
-    if (backend_cfg.bit_width !=
-        my_data->current_tx_backend_cfg[backend_idx].bit_width) {
-
-        struct  mixer_ctl *ctl = NULL;
-        ctl = mixer_get_ctl_by_name(adev->mixer,
-                        my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl);
-        if (!ctl) {
-            ALOGE("%s:txbecf: afe: Could not get ctl for mixer command - %s",
-                  __func__,
-                  my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl);
-            return -EINVAL;
-        }
-
-        if (backend_cfg.bit_width == 24) {
-            if (backend_cfg.format == AUDIO_FORMAT_PCM_24_BIT_PACKED)
-                ret = mixer_ctl_set_enum_by_string(ctl, "S24_3LE");
-            else
-                ret = mixer_ctl_set_enum_by_string(ctl, "S24_LE");
-        } else {
-            ret = mixer_ctl_set_enum_by_string(ctl, "S16_LE");
-        }
-
-        if (ret < 0) {
-            ALOGE("%s:txbecf: afe: Could not set ctl for mixer command - %s",
-                  __func__,
-                  my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl);
-            return -EINVAL;
-        }
-
-        my_data->current_tx_backend_cfg[backend_idx].bit_width = backend_cfg.bit_width;
-        ALOGD("%s:txbecf: afe: %s mixer set to %d bit", __func__,
-              my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl,
-              backend_cfg.bit_width);
-    }
-
-    /*
-     * Backend sample rate configuration follows:
-     * 16 bit record - 48khz for streams at any valid sample rate
-     * 24 bit record - 48khz for stream sample rate less than 48khz
-     * 24 bit record - 96khz for sample rate range of 48khz to 96khz
-     * 24 bit record - 192khz for sample rate range of 96khz to 192 khz
-     * Upper limit is inclusive in the sample rate range.
-     */
-    // TODO: This has to be more dynamic based on policy file
-
-    if (backend_cfg.sample_rate !=
-        my_data->current_tx_backend_cfg[(int)backend_idx].sample_rate) {
-            /*
-             * sample rate update is needed only for hifi audio enabled platforms
-             */
-            char *rate_str = NULL;
-            struct  mixer_ctl *ctl = NULL;
-
-            switch (backend_cfg.sample_rate) {
-            case 8000:
-            case 11025:
-            case 16000:
-            case 22050:
-            case 32000:
-            case 44100:
-            case 48000:
-                rate_str = "KHZ_48";
-                break;
-            case 64000:
-            case 88200:
-            case 96000:
-                rate_str = "KHZ_96";
-                break;
-            case 176400:
-            case 192000:
-                rate_str = "KHZ_192";
-                break;
-            default:
-                rate_str = "KHZ_48";
-                break;
-            }
-
-            ctl = mixer_get_ctl_by_name(adev->mixer,
-                my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl);
-
-            if (ctl < 0) {
-                ALOGE("%s:txbecf: afe: Could not get ctl to set the Sample Rate for mixer command - %s",
-                      __func__,
-                      my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl);
-                return -EINVAL;
-            }
-
-            ALOGD("%s:txbecf: afe: %s set to %s", __func__,
-                  my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl,
-                  rate_str);
-            ret = mixer_ctl_set_enum_by_string(ctl, rate_str);
-            if (ret < 0) {
-                ALOGE("%s:txbecf: afe: Could not set ctl for mixer command - %s",
-                      __func__,
-                      my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl);
-                return -EINVAL;
-            }
-
-            my_data->current_tx_backend_cfg[backend_idx].sample_rate =
-                                        backend_cfg.sample_rate;
-    }
-
-    return ret;
-}
-
-/*
  * goes through all the current usecases and picks the highest
  * bitwidth & samplerate
  */
@@ -4827,7 +4775,8 @@
     channels = backend_cfg->channels;
 
     ALOGI("%s:txbecf: afe: Codec selected backend: %d current bit width: %d and "
-          "sample rate: %d",__func__,backend_idx, bit_width, sample_rate);
+          "sample rate: %d, channels %d",__func__,backend_idx, bit_width,
+          sample_rate, channels);
 
     // For voice calls use default configuration i.e. 16b/48K, only applicable to
     // default backend
@@ -4849,14 +4798,17 @@
           "sample rate: %d", __func__, backend_idx, bit_width, sample_rate);
     // Force routing if the expected bitwdith or samplerate
     // is not same as current backend comfiguration
-    if ((bit_width != my_data->current_tx_backend_cfg[backend_idx].bit_width) ||
-        (sample_rate != my_data->current_tx_backend_cfg[backend_idx].sample_rate)) {
+    if ((bit_width != my_data->current_backend_cfg[backend_idx].bit_width) ||
+        (sample_rate != my_data->current_backend_cfg[backend_idx].sample_rate) ||
+        (channels != my_data->current_backend_cfg[backend_idx].channels)) {
         backend_cfg->bit_width = bit_width;
         backend_cfg->sample_rate= sample_rate;
+        backend_cfg->channels = channels;
         backend_change = true;
         ALOGI("%s:txbecf: afe: Codec backend needs to be updated. new bit width: %d "
-              "new sample rate: %d", __func__, backend_cfg->bit_width,
-              backend_cfg->sample_rate);
+              "new sample rate: %d new channel: %d",
+              __func__, backend_cfg->bit_width,
+              backend_cfg->sample_rate, backend_cfg->channels);
     }
 
     return backend_change;
@@ -4865,7 +4817,7 @@
 bool platform_check_and_set_capture_codec_backend_cfg(struct audio_device* adev,
     struct audio_usecase *usecase, snd_device_t snd_device)
 {
-    int backend_idx = platform_get_capture_backend_index(snd_device);
+    int backend_idx = platform_get_backend_index(snd_device);
     int ret = 0;
     struct audio_backend_cfg backend_cfg;
 
@@ -4891,8 +4843,8 @@
           platform_get_snd_device_name(snd_device));
     if (platform_check_capture_codec_backend_cfg(adev, backend_idx,
                                                  &backend_cfg)) {
-        ret = platform_set_capture_codec_backend_cfg(adev, snd_device,
-                                                     backend_cfg);
+        ret = platform_set_codec_backend_cfg(adev, snd_device,
+                                             backend_cfg);
         if(!ret)
             return true;
     }
@@ -5546,8 +5498,11 @@
         snd_device == SND_DEVICE_OUT_SPEAKER_WSA ||
         snd_device == SND_DEVICE_OUT_SPEAKER_VBAT ||
         snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT ||
         snd_device == SND_DEVICE_OUT_VOICE_SPEAKER ||
-        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_WSA) {
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2 ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_WSA ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2_WSA) {
         ret = true;
     }
 
@@ -5567,12 +5522,19 @@
         case SND_DEVICE_OUT_VOICE_SPEAKER_WSA:
              acdb_id = platform_get_snd_device_acdb_id(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED);
              break;
+        case SND_DEVICE_OUT_VOICE_SPEAKER_2:
+        case SND_DEVICE_OUT_VOICE_SPEAKER_2_WSA:
+             acdb_id = platform_get_snd_device_acdb_id(SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED);
+             break;
         case SND_DEVICE_OUT_SPEAKER_VBAT:
              acdb_id = platform_get_snd_device_acdb_id(SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT);
              break;
         case SND_DEVICE_OUT_VOICE_SPEAKER_VBAT:
              acdb_id = platform_get_snd_device_acdb_id(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT);
              break;
+        case SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT:
+             acdb_id = platform_get_snd_device_acdb_id(SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED_VBAT);
+             break;
         default:
              acdb_id = -EINVAL;
              break;
@@ -5592,15 +5554,37 @@
         case SND_DEVICE_OUT_VOICE_SPEAKER:
         case SND_DEVICE_OUT_VOICE_SPEAKER_WSA:
              return SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED;
+        case SND_DEVICE_OUT_VOICE_SPEAKER_2:
+        case SND_DEVICE_OUT_VOICE_SPEAKER_2_WSA:
+             return SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED;
         case SND_DEVICE_OUT_SPEAKER_VBAT:
              return SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT;
         case SND_DEVICE_OUT_VOICE_SPEAKER_VBAT:
              return SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT;
+        case SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT:
+             return SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED_VBAT;
         default:
              return snd_device;
     }
 }
 
+int platform_get_vi_feedback_snd_device(snd_device_t snd_device)
+{
+    switch(snd_device) {
+        case SND_DEVICE_OUT_SPEAKER_PROTECTED:
+        case SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT:
+             return SND_DEVICE_IN_CAPTURE_VI_FEEDBACK;
+        case SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED:
+        case SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT:
+             return SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_1;
+        case SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED:
+        case SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED_VBAT:
+             return SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_2;
+        default:
+             return SND_DEVICE_IN_CAPTURE_VI_FEEDBACK;
+    }
+}
+
 int platform_set_sidetone(struct audio_device *adev,
                           snd_device_t out_snd_device,
                           bool enable,
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index 1e54ee1..33be141 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -39,6 +39,11 @@
     SOURCE_QUAD_MIC  = 0x8,            /* Target contains 4 mics */
 };
 
+enum {
+    SPKR_1,
+    SPKR_2
+};
+
 #define PLATFORM_IMAGE_NAME "modem"
 
 /*
@@ -92,6 +97,9 @@
     SND_DEVICE_OUT_VOICE_SPEAKER,
     SND_DEVICE_OUT_VOICE_SPEAKER_WSA,
     SND_DEVICE_OUT_VOICE_SPEAKER_VBAT,
+    SND_DEVICE_OUT_VOICE_SPEAKER_2,
+    SND_DEVICE_OUT_VOICE_SPEAKER_2_WSA,
+    SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT,
     SND_DEVICE_OUT_VOICE_HEADPHONES,
     SND_DEVICE_OUT_VOICE_LINE,
     SND_DEVICE_OUT_HDMI,
@@ -118,8 +126,10 @@
     SND_DEVICE_OUT_ANC_HANDSET,
     SND_DEVICE_OUT_SPEAKER_PROTECTED,
     SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED,
+    SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED,
     SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT,
     SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT,
+    SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED_VBAT,
 #ifdef RECORD_PLAY_CONCURRENCY
     SND_DEVICE_OUT_VOIP_HANDSET,
     SND_DEVICE_OUT_VOIP_SPEAKER,
@@ -178,6 +188,8 @@
     SND_DEVICE_IN_HANDSET_STEREO_DMIC,
     SND_DEVICE_IN_SPEAKER_STEREO_DMIC,
     SND_DEVICE_IN_CAPTURE_VI_FEEDBACK,
+    SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_1,
+    SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_2,
     SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE,
     SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE,
     SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE,
@@ -221,14 +233,14 @@
     HDMI_RX_BACKEND,
     DISP_PORT_RX_BACKEND,
     USB_AUDIO_RX_BACKEND,
+    MAX_RX_CODEC_BACKENDS = USB_AUDIO_RX_BACKEND,
+    /* TX BE follows RX BE */
+    SLIMBUS_0_TX,
+    DEFAULT_CODEC_TX_BACKEND = SLIMBUS_0_TX,
+    USB_AUDIO_TX_BACKEND,
     MAX_CODEC_BACKENDS
 };
-enum {
-    DEFAULT_CODEC_TX_BACKEND,
-    SLIMBUS_0_TX = DEFAULT_CODEC_TX_BACKEND,
-    USB_AUDIO_TX_BACKEND,
-    MAX_CODEC_TX_BACKENDS
-};
+
 #define AUDIO_PARAMETER_KEY_NATIVE_AUDIO "audio.nat.codec.enabled"
 #define AUDIO_PARAMETER_KEY_NATIVE_AUDIO_MODE "native_audio_mode"
 
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index c1e8e7f..b687d96 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1039,6 +1039,12 @@
     return -ENOSYS;
 }
 
+unsigned char* platform_get_license(void *platform, int *size)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return NULL;
+}
+
 /* Delay in Us */
 int64_t platform_render_latency(audio_usecase_t usecase)
 {
@@ -1223,6 +1229,11 @@
     return -ENOSYS;
 }
 
+int platform_get_vi_feedback_snd_device(snd_device_t snd_device __unused)
+{
+    return -ENOSYS;
+}
+
 int platform_spkr_prot_is_wsa_analog_mode(void *adev __unused)
 {
     return 0;
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 1f81973..6930286 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -42,6 +42,7 @@
 #include "edid.h"
 #include "sound/compress_params.h"
 #include "sound/msmcal-hwdep.h"
+#include <linux/msm_audio_calibration.h>
 
 #define SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID (100)
 #define MIXER_XML_DEFAULT_PATH "/system/etc/mixer_paths.xml"
@@ -59,7 +60,8 @@
 #define LIB_ACDB_LOADER "libacdbloader.so"
 #define CVD_VERSION_MIXER_CTL "CVD Version"
 
-#define MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE (256 * 1024)
+#define FLAC_COMPRESS_OFFLOAD_FRAGMENT_SIZE (256 * 1024)
+#define MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE (2 * 1024 * 1024)
 #define MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE (2 * 1024)
 #define COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING (2 * 1024)
 #define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024)
@@ -107,6 +109,8 @@
 #define AUDIO_PARAMETER_KEY_AUD_CALDATA   "cal_data"
 #define AUDIO_PARAMETER_KEY_AUD_CALRESULT "cal_result"
 
+#define AUDIO_PARAMETER_KEY_MONO_SPEAKER "mono_speaker"
+
 #define AUDIO_PARAMETER_KEY_PERF_LOCK_OPTS "perf_lock_opts"
 
 /* Reload ACDB files from specified path */
@@ -217,6 +221,7 @@
     /* Vbat monitor related flags */
     bool is_vbat_speaker;
     bool gsm_mode_enabled;
+    int mono_speaker;
     /* Audio calibration related functions */
     void                       *acdb_handle;
     int                        voice_feature_set;
@@ -239,7 +244,6 @@
     int ext_disp_type;
     char ec_ref_mixer_path[64];
     codec_backend_cfg_t current_backend_cfg[MAX_CODEC_BACKENDS];
-    codec_backend_cfg_t current_tx_backend_cfg[MAX_CODEC_TX_BACKENDS];
     char codec_version[CODEC_VERSION_MAX_LENGTH];
     int hw_dep_fd;
     char cvd_version[MAX_CVD_VERSION_STRING_SIZE];
@@ -347,6 +351,8 @@
     [SND_DEVICE_OUT_VOICE_HANDSET] = "voice-handset",
     [SND_DEVICE_OUT_VOICE_SPEAKER] = "voice-speaker",
     [SND_DEVICE_OUT_VOICE_SPEAKER_VBAT] = "voice-speaker-vbat",
+    [SND_DEVICE_OUT_VOICE_SPEAKER_2] = "voice-speaker-2",
+    [SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT] = "voice-speaker-2-vbat",
     [SND_DEVICE_OUT_VOICE_HEADPHONES] = "voice-headphones",
     [SND_DEVICE_OUT_VOICE_LINE] = "voice-line",
     [SND_DEVICE_OUT_HDMI] = "hdmi",
@@ -373,8 +379,10 @@
     [SND_DEVICE_OUT_ANC_HANDSET] = "anc-handset",
     [SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected",
     [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = "voice-speaker-protected",
+    [SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED] = "voice-speaker-2-protected",
     [SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT] = "speaker-protected-vbat",
     [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT] = "voice-speaker-protected-vbat",
+    [SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED_VBAT] = "voice-speaker-2-protected-vbat",
 
     /* Capture sound devices */
     [SND_DEVICE_IN_HANDSET_MIC] = "handset-mic",
@@ -424,6 +432,8 @@
     [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = "handset-stereo-dmic-ef",
     [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = "speaker-stereo-dmic-ef",
     [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = "vi-feedback",
+    [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_1] = "vi-feedback-mono-1",
+    [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_2] = "vi-feedback-mono-2",
     [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE] = "voice-speaker-dmic-broadside",
     [SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE] = "speaker-dmic-broadside",
     [SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE] = "speaker-dmic-broadside",
@@ -466,6 +476,8 @@
     [SND_DEVICE_OUT_VOICE_HANDSET] = 7,
     [SND_DEVICE_OUT_VOICE_SPEAKER] = 14,
     [SND_DEVICE_OUT_VOICE_SPEAKER_VBAT] = 14,
+    [SND_DEVICE_OUT_VOICE_SPEAKER_2] = 14,
+    [SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT] = 14,
     [SND_DEVICE_OUT_VOICE_HEADPHONES] = 10,
     [SND_DEVICE_OUT_VOICE_LINE] = 10,
     [SND_DEVICE_OUT_HDMI] = 18,
@@ -492,8 +504,10 @@
     [SND_DEVICE_OUT_ANC_HANDSET] = 103,
     [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 124,
     [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = 101,
+    [SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED] = 101,
     [SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT] = 124,
     [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT] = 101,
+    [SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED_VBAT] = 101,
 
     [SND_DEVICE_IN_HANDSET_MIC] = 4,
     [SND_DEVICE_IN_HANDSET_MIC_EXTERNAL] = 4,
@@ -542,6 +556,8 @@
     [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = 34,
     [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = 35,
     [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = 102,
+    [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_1] = 102,
+    [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_2] = 102,
     [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE] = 12,
     [SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE] = 12,
     [SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE] = 119,
@@ -587,6 +603,8 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HANDSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_VBAT)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_2)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HEADPHONES)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_LINE)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_HDMI)},
@@ -612,8 +630,10 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_ANC_HANDSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED_VBAT)},
     {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_EXTERNAL)},
     {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_AEC)},
@@ -659,6 +679,8 @@
     {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_STEREO_DMIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_STEREO_DMIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_VI_FEEDBACK)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_1)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_2)},
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE)},
     {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE)},
     {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE)},
@@ -1120,6 +1142,7 @@
     backend_tag_table[SND_DEVICE_OUT_HEADPHONES_DSD] = strdup("headphones-dsd");
     backend_tag_table[SND_DEVICE_OUT_HEADPHONES_44_1] = strdup("headphones-44.1");
     backend_tag_table[SND_DEVICE_OUT_VOICE_SPEAKER_VBAT] = strdup("voice-speaker-vbat");
+    backend_tag_table[SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT] = strdup("voice-speaker-2-vbat");
     backend_tag_table[SND_DEVICE_OUT_BT_A2DP] = strdup("bt-a2dp");
     backend_tag_table[SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP] = strdup("speaker-and-bt-a2dp");
 
@@ -1543,6 +1566,7 @@
     my_data->edid_info = NULL;
     my_data->ext_disp_type = EXT_DISPLAY_TYPE_NONE;
     my_data->hw_dep_fd = -1;
+    my_data->mono_speaker = SPKR_1;
 
     property_get("ro.qc.sdk.audio.fluencetype", my_data->fluence_cap, "");
     if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro"))) {
@@ -1731,6 +1755,8 @@
             my_data->current_backend_cfg[idx].sample_rate = OUTPUT_SAMPLING_RATE_44100;
         my_data->current_backend_cfg[idx].bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
         my_data->current_backend_cfg[idx].channels = CODEC_BACKEND_DEFAULT_CHANNELS;
+        if (idx > MAX_RX_CODEC_BACKENDS)
+            my_data->current_backend_cfg[idx].channels = CODEC_BACKEND_DEFAULT_TX_CHANNELS;
         my_data->current_backend_cfg[idx].bitwidth_mixer_ctl = NULL;
         my_data->current_backend_cfg[idx].samplerate_mixer_ctl = NULL;
         my_data->current_backend_cfg[idx].channels_mixer_ctl = NULL;
@@ -1751,15 +1777,17 @@
     my_data->current_backend_cfg[HEADPHONE_44_1_BACKEND].samplerate_mixer_ctl =
         strdup("SLIM_5_RX SampleRate");
 
-    my_data->current_tx_backend_cfg[DEFAULT_CODEC_TX_BACKEND].bitwidth_mixer_ctl =
+    my_data->current_backend_cfg[DEFAULT_CODEC_TX_BACKEND].bitwidth_mixer_ctl =
         strdup("SLIM_0_TX Format");
-    my_data->current_tx_backend_cfg[DEFAULT_CODEC_TX_BACKEND].samplerate_mixer_ctl =
+    my_data->current_backend_cfg[DEFAULT_CODEC_TX_BACKEND].samplerate_mixer_ctl =
         strdup("SLIM_0_TX SampleRate");
 
-    my_data->current_tx_backend_cfg[USB_AUDIO_TX_BACKEND].bitwidth_mixer_ctl =
+    my_data->current_backend_cfg[USB_AUDIO_TX_BACKEND].bitwidth_mixer_ctl =
         strdup("USB_AUDIO_TX Format");
-    my_data->current_tx_backend_cfg[USB_AUDIO_TX_BACKEND].samplerate_mixer_ctl =
+    my_data->current_backend_cfg[USB_AUDIO_TX_BACKEND].samplerate_mixer_ctl =
         strdup("USB_AUDIO_TX SampleRate");
+    my_data->current_backend_cfg[USB_AUDIO_TX_BACKEND].channels_mixer_ctl =
+        strdup("USB_AUDIO_TX Channels");
 
     ret = audio_extn_utils_get_codec_version(snd_card_name,
                                              my_data->adev->snd_card,
@@ -1910,7 +1938,8 @@
         return;
     }
 
-    if ((snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT) &&
+    if ((snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT) &&
         !(usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)) {
         ALOGI("%s: Not adding vbat speaker device to non voice use cases", __func__);
         return;
@@ -2334,7 +2363,7 @@
 {
     int32_t port = DEFAULT_CODEC_BACKEND;
 
-    if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) {
+    if (snd_device >= SND_DEVICE_OUT_BEGIN && snd_device < SND_DEVICE_OUT_END) {
         if (backend_tag_table[snd_device] != NULL) {
                 if (strncmp(backend_tag_table[snd_device], "headphones-44.1",
                             sizeof("headphones-44.1")) == 0)
@@ -2352,28 +2381,17 @@
                 else if (strcmp(backend_tag_table[snd_device], "usb-headphones") == 0)
                         port = USB_AUDIO_RX_BACKEND;
         }
-    } else {
-        ALOGV("%s:napb: Invalid device - %d ", __func__, snd_device);
-    }
-
-    ALOGV("%s:napb: backend port - %d snd_device %d", __func__, port, snd_device);
-    return port;
-}
-
-static int platform_get_capture_backend_index(snd_device_t snd_device)
-{
-    int32_t port = DEFAULT_CODEC_TX_BACKEND;
-
-    if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) {
+    } else if (snd_device >= SND_DEVICE_IN_BEGIN && snd_device < SND_DEVICE_IN_END) {
+        port = DEFAULT_CODEC_TX_BACKEND;
         if (backend_tag_table[snd_device] != NULL) {
                 if (strcmp(backend_tag_table[snd_device], "usb-headset-mic") == 0)
                         port = USB_AUDIO_TX_BACKEND;
         }
     } else {
-        ALOGW("%s: Invalid device - %d ", __func__, snd_device);
+        ALOGW("%s:napb: Invalid device - %d ", __func__, snd_device);
     }
 
-    ALOGV("%s: backend port - %d snd_device %d", __func__, port, snd_device);
+    ALOGV("%s:napb: backend port - %d device - %d ", __func__, port, snd_device);
     return port;
 }
 
@@ -2458,7 +2476,9 @@
         return ret;
 
     if ((out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER ||
-         out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT) &&
+         out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2 ||
+         out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT ||
+         out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT) &&
          audio_extn_spkr_prot_is_enabled()) {
         if (my_data->is_vbat_speaker)
             acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT];
@@ -2493,9 +2513,16 @@
     if (my_data->acdb_send_voice_cal == NULL) {
         ALOGE("%s: dlsym error for acdb_send_voice_call", __func__);
     } else {
-        if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER &&
-            audio_extn_spkr_prot_is_enabled())
-            out_snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED;
+        if (audio_extn_spkr_prot_is_enabled()) {
+            if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER)
+                out_snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED;
+            else if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT)
+                out_snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT;
+            else if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER)
+                out_snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED;
+            else if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT)
+                out_snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED_VBAT;
+        }
 
         acdb_rx_id = acdb_device_table[out_snd_device];
         acdb_tx_id = acdb_device_table[in_snd_device];
@@ -2522,7 +2549,9 @@
         return ret;
 
     if ((out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER ||
-         out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT) &&
+         out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2 ||
+         out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT ||
+         out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT) &&
          audio_extn_spkr_prot_is_enabled()) {
         if (my_data->is_vbat_speaker)
             acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT];
@@ -2901,10 +2930,17 @@
             else
                 snd_device = SND_DEVICE_OUT_BT_SCO;
         } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
-                if (my_data->is_vbat_speaker)
-                    snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_VBAT;
-                else
-                    snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
+                if (my_data->is_vbat_speaker) {
+                    if (my_data->mono_speaker == SPKR_1)
+                        snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_VBAT;
+                    else
+                        snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT;
+                } else {
+                    if (my_data->mono_speaker == SPKR_1)
+                        snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
+                    else
+                        snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_2;
+                }
         } else if (devices & AUDIO_DEVICE_OUT_ALL_A2DP) {
             snd_device = SND_DEVICE_OUT_BT_A2DP;
         } else if (devices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ||
@@ -2926,7 +2962,8 @@
     }
 
     if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
-        devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+        devices & AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+        devices & AUDIO_DEVICE_OUT_LINE) {
         if (devices & AUDIO_DEVICE_OUT_WIRED_HEADSET
             && audio_extn_get_anc_enabled()) {
             if (audio_extn_should_use_fb_anc())
@@ -3799,6 +3836,16 @@
 
     }
 
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_MONO_SPEAKER, value, len);
+    if (err >= 0) {
+        if (!strncmp("left", value, sizeof("left")))
+            my_data->mono_speaker = SPKR_1;
+        else if (!strncmp("right", value, sizeof("right")))
+            my_data->mono_speaker = SPKR_2;
+
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_MONO_SPEAKER);
+    }
+
     err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_EXT_AUDIO_DEVICE,
                             value, len);
     if (err >= 0) {
@@ -4116,6 +4163,54 @@
     free(kv_pairs);
 }
 
+unsigned char* platform_get_license(void *platform, int *size)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    char value[PROPERTY_VALUE_MAX] = {0};
+    acdb_audio_cal_cfg_t cal;
+    unsigned char *dptr = NULL;
+    int ret=0;
+    uint32_t param_len;
+
+    if (platform == NULL) {
+        ALOGE("[%s] received null pointer %d ",__func__, __LINE__);
+        ret = -EINVAL;
+        goto done;
+    }
+    memset(&cal, 0, sizeof(cal));
+    cal.persist = 1;
+    cal.cal_type = AUDIO_CORE_METAINFO_CAL_TYPE;
+    if (!property_get("audio.qaf.acdbid", value , "") && !atoi(value)) {
+        ALOGE("[%s] audio.qaf.acdbid is not set %d ",__func__, __LINE__);
+        ret = -EINVAL;
+        goto done;
+    }
+    cal.acdb_dev_id = (uint32_t) atoi (value);
+    param_len = MAX_SET_CAL_BYTE_SIZE;
+    dptr = (unsigned char*) calloc(param_len, sizeof(unsigned char*));
+    if (dptr == NULL) {
+        ALOGE("[%s] Memory allocation failed for length %d",__func__,param_len);
+        ret = -ENOMEM;
+        goto done;
+    }
+    if (my_data->acdb_get_audio_cal != NULL) {
+        ret = my_data->acdb_get_audio_cal((void*)&cal, (void*)dptr, &param_len);
+        ALOGE("%s, ret[%d], param_len[%d] line %d", __func__, ret, param_len, __LINE__);
+        if (ret == 0) {
+            *size = param_len;
+            return dptr;
+        } else {
+            *size = 0;
+        }
+    }
+done:
+    if (dptr != NULL)
+        free(dptr);
+
+    return NULL;
+}
+
+/* Delay in Us */
 /* Delay in Us, only to be used for PCM formats */
 int64_t platform_render_latency(audio_usecase_t usecase)
 {
@@ -4149,7 +4244,9 @@
     if ((snd_device >= SND_DEVICE_IN_BEGIN) &&
         (snd_device < SND_DEVICE_IN_END) &&
         (snd_device != SND_DEVICE_IN_CAPTURE_FM) &&
-        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK))
+        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK) &&
+        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_1) &&
+        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_2))
         needs_event = true;
 
     return needs_event;
@@ -4167,7 +4264,9 @@
     if ((snd_device >= SND_DEVICE_IN_BEGIN) &&
         (snd_device < SND_DEVICE_IN_END) &&
         (snd_device != SND_DEVICE_IN_CAPTURE_FM) &&
-        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK))
+        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK) &&
+        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_1) &&
+        (snd_device != SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_2))
         needs_event = true;
 
     return needs_event;
@@ -4199,18 +4298,21 @@
         fragment_size = info->offload_buffer_size;
     }
 
-    // For FLAC use max size since it is loss less, and has sampling rates
-    // upto 192kHZ
-    if (info != NULL && !info->has_video &&
-        info->format == AUDIO_FORMAT_FLAC) {
-       fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE;
-       ALOGV("FLAC fragment size %d", fragment_size);
-    }
-
-    if (info != NULL && info->has_video && info->is_streaming) {
-        fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING;
-        ALOGV("%s: offload fragment size reduced for AV streaming to %d",
-               __func__, fragment_size);
+    if (info != NULL && !info->has_video) {
+        if (info->is_streaming) {
+            fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING;
+            ALOGV("%s: offload fragment size reduced for AV streaming to %d",
+                   __func__, fragment_size);
+        } else if (info->format == AUDIO_FORMAT_FLAC) {
+            fragment_size = FLAC_COMPRESS_OFFLOAD_FRAGMENT_SIZE;
+            ALOGV("FLAC fragment size %d", fragment_size);
+        } else if (info->format == AUDIO_FORMAT_DSD) {
+            fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE;
+            if((property_get("audio.native.dsd.buffer.size.kb", value, "")) &&
+                    atoi(value))
+                fragment_size =  atoi(value) * 1024;
+            ALOGV("DSD fragment size %d", fragment_size);
+        }
     }
 
     fragment_size = ALIGN( fragment_size, 1024);
@@ -4254,7 +4356,7 @@
                          snd_device_t snd_device, struct audio_backend_cfg backend_cfg)
 {
     int ret = 0;
-    int backend_idx = DEFAULT_CODEC_BACKEND;
+    int backend_idx = platform_get_backend_index(snd_device);
     struct platform_data *my_data = (struct platform_data *)adev->platform;
     backend_idx = platform_get_backend_index(snd_device);
     unsigned int bit_width = backend_cfg.bit_width;
@@ -4264,13 +4366,14 @@
     bool passthrough_enabled = backend_cfg.passthrough_enabled;
 
     ALOGI("%s:becf: afe: bitwidth %d, samplerate %d channels %d"
-          ", backend_idx %d device (%s)", __func__,  bit_width, sample_rate, channels, backend_idx,
+          ", backend_idx %d device (%s)", __func__,  bit_width,
+          sample_rate, channels, backend_idx,
           platform_get_snd_device_name(snd_device));
 
     if (bit_width !=
         my_data->current_backend_cfg[backend_idx].bit_width) {
 
-        struct  mixer_ctl *ctl;
+        struct  mixer_ctl *ctl = NULL;
         ctl = mixer_get_ctl_by_name(adev->mixer,
                     my_data->current_backend_cfg[backend_idx].bitwidth_mixer_ctl);
         if (!ctl) {
@@ -4282,23 +4385,30 @@
 
         if (bit_width == 24) {
             if (format == AUDIO_FORMAT_PCM_24_BIT_PACKED)
-                 mixer_ctl_set_enum_by_string(ctl, "S24_3LE");
+                 ret = mixer_ctl_set_enum_by_string(ctl, "S24_3LE");
             else
-                 mixer_ctl_set_enum_by_string(ctl, "S24_LE");
+                 ret = mixer_ctl_set_enum_by_string(ctl, "S24_LE");
         } else if (bit_width == 32) {
-            mixer_ctl_set_enum_by_string(ctl, "S24_LE");
+            ret = mixer_ctl_set_enum_by_string(ctl, "S24_LE");
         } else {
-            mixer_ctl_set_enum_by_string(ctl, "S16_LE");
+            ret = mixer_ctl_set_enum_by_string(ctl, "S16_LE");
         }
-        my_data->current_backend_cfg[backend_idx].bit_width = bit_width;
-        ALOGD("%s:becf: afe: %s mixer set to %d bit for %x format", __func__,
-              my_data->current_backend_cfg[backend_idx].bitwidth_mixer_ctl, bit_width, format);
+        if ( ret < 0) {
+            ALOGE("%s:becf: afe: fail for %s mixer set to %d bit for %x format", __func__,
+                  my_data->current_backend_cfg[backend_idx].bitwidth_mixer_ctl, bit_width, format);
+        } else {
+            my_data->current_backend_cfg[backend_idx].bit_width = bit_width;
+            ALOGD("%s:becf: afe: %s mixer set to %d bit for %x format", __func__,
+                  my_data->current_backend_cfg[backend_idx].bitwidth_mixer_ctl, bit_width, format);
+        }
+        /* set the ret as 0 and not pass back to upper layer */
+        ret = 0;
     }
 
     if (sample_rate !=
        my_data->current_backend_cfg[backend_idx].sample_rate) {
             char *rate_str = NULL;
-            struct  mixer_ctl *ctl;
+            struct  mixer_ctl *ctl = NULL;
 
             switch (sample_rate) {
             case 8000:
@@ -4352,7 +4462,7 @@
     }
     if ((my_data->current_backend_cfg[backend_idx].channels_mixer_ctl) &&
         (channels != my_data->current_backend_cfg[backend_idx].channels)) {
-        struct  mixer_ctl *ctl;
+        struct  mixer_ctl *ctl = NULL;
         char *channel_cnt_str = NULL;
 
         switch (channels) {
@@ -4368,6 +4478,9 @@
             channel_cnt_str = "Four"; break;
         case 3:
             channel_cnt_str = "Three"; break;
+        case 1:
+            channel_cnt_str = "One"; break;
+        case 2:
         default:
             channel_cnt_str = "Two"; break;
         }
@@ -4387,7 +4500,8 @@
             platform_set_edid_channels_configuration(adev->platform, channels);
 
         ALOGD("%s:becf: afe: %s set to %s", __func__,
-               my_data->current_backend_cfg[backend_idx].channels_mixer_ctl, channel_cnt_str);
+               my_data->current_backend_cfg[backend_idx].channels_mixer_ctl,
+               channel_cnt_str);
     }
 
     bool set_ext_disp_format = false;
@@ -4737,126 +4851,6 @@
 }
 
 /*
- * configures afe with bit width and Sample Rate
- */
-
-static int platform_set_capture_codec_backend_cfg(struct audio_device* adev,
-                         snd_device_t snd_device,
-                         struct audio_backend_cfg backend_cfg)
-{
-    int ret = 0;
-    int backend_idx = platform_get_capture_backend_index(snd_device);
-    struct platform_data *my_data = (struct platform_data *)adev->platform;
-
-    ALOGI("%s:txbecf: afe: bitwidth %d, samplerate %d, backend_idx %d device (%s)",
-          __func__, backend_cfg.bit_width, backend_cfg.sample_rate, backend_idx,
-          platform_get_snd_device_name(snd_device));
-
-    if (backend_cfg.bit_width!=
-        my_data->current_tx_backend_cfg[backend_idx].bit_width) {
-
-        struct  mixer_ctl *ctl = NULL;
-        ctl = mixer_get_ctl_by_name(adev->mixer,
-                        my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl);
-        if (!ctl) {
-            ALOGE("%s:txbecf: afe: Could not get ctl for mixer command - %s",
-                  __func__,
-                  my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl);
-            return -EINVAL;
-        }
-        if (backend_cfg.bit_width == 24) {
-            if (backend_cfg.format == AUDIO_FORMAT_PCM_24_BIT_PACKED)
-                ret = mixer_ctl_set_enum_by_string(ctl, "S24_3LE");
-            else
-                ret = mixer_ctl_set_enum_by_string(ctl, "S24_LE");
-        } else {
-            ret = mixer_ctl_set_enum_by_string(ctl, "S16_LE");
-        }
-
-        if (ret < 0) {
-            ALOGE("%s:txbecf: afe: Could not set ctl for mixer command - %s",
-                  __func__,
-                  my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl);
-            return -EINVAL;
-        }
-
-        my_data->current_tx_backend_cfg[backend_idx].bit_width = backend_cfg.bit_width;
-        ALOGD("%s:txbecf: afe: %s mixer set to %d bit", __func__,
-              my_data->current_tx_backend_cfg[backend_idx].bitwidth_mixer_ctl,
-              backend_cfg.bit_width);
-    }
-
-    /*
-     * Backend sample rate configuration follows:
-     * 16 bit record - 48khz for streams at any valid sample rate
-     * 24 bit record - 48khz for stream sample rate less than 48khz
-     * 24 bit record - 96khz for sample rate range of 48khz to 96khz
-     * 24 bit record - 192khz for sample rate range of 96khz to 192 khz
-     * Upper limit is inclusive in the sample rate range.
-     */
-    // TODO: This has to be more dynamic based on policy file
-
-    if (backend_cfg.sample_rate !=
-        my_data->current_tx_backend_cfg[(int)backend_idx].sample_rate) {
-            /*
-             * sample rate update is needed only for hifi audio enabled platforms
-             */
-            char *rate_str = NULL;
-            struct  mixer_ctl *ctl = NULL;
-
-            switch (backend_cfg.sample_rate) {
-            case 8000:
-            case 11025:
-            case 16000:
-            case 22050:
-            case 32000:
-            case 44100:
-            case 48000:
-                rate_str = "KHZ_48";
-                break;
-            case 64000:
-            case 88200:
-            case 96000:
-                rate_str = "KHZ_96";
-                break;
-            case 176400:
-            case 192000:
-                rate_str = "KHZ_192";
-                break;
-            default:
-                rate_str = "KHZ_48";
-                break;
-            }
-
-            ctl = mixer_get_ctl_by_name(adev->mixer,
-                my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl);
-
-            if (!ctl) {
-                ALOGE("%s:txbecf: afe: Could not get ctl to set the Sample Rate for mixer command - %s",
-                      __func__,
-                      my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl);
-                return -EINVAL;
-            }
-
-            ALOGD("%s:txbecf: afe: %s set to %s", __func__,
-                  my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl,
-                  rate_str);
-            ret = mixer_ctl_set_enum_by_string(ctl, rate_str);
-            if (ret < 0) {
-                ALOGE("%s:txbecf: afe: Could not set ctl for mixer command - %s",
-                      __func__,
-                      my_data->current_tx_backend_cfg[backend_idx].samplerate_mixer_ctl);
-                return -EINVAL;
-            }
-
-            my_data->current_tx_backend_cfg[backend_idx].sample_rate =
-                                        backend_cfg.sample_rate;
-    }
-
-    return ret;
-}
-
-/*
  * goes through all the current usecases and picks the highest
  * bitwidth & samplerate
  */
@@ -4875,20 +4869,21 @@
     channels = backend_cfg->channels;
 
     ALOGI("%s:txbecf: afe: Codec selected backend: %d current bit width: %d and "
-          "sample rate: %d",__func__,backend_idx, bit_width, sample_rate);
+          "sample rate: %d, channels %d",__func__,backend_idx, bit_width,
+          sample_rate, channels);
 
     // For voice calls use default configuration i.e. 16b/48K, only applicable to
     // default backend
     // force routing is not required here, caller will do it anyway
     if (voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
-        ALOGW("%s:txbecf: afe:Use default bw and sr for voice/voip calls and "
+        ALOGW("%s:txbecf: afe: Use default bw and sr for voice/voip calls and "
               "for unprocessed/camera source", __func__);
         bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
         sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
     }
     if (backend_idx == USB_AUDIO_TX_BACKEND) {
         audio_extn_usb_is_config_supported(&bit_width, &sample_rate, &channels, false);
-        ALOGV("%s: USB BE configured as bit_width(%d)sample_rate(%d)channels(%d)",
+        ALOGV("%s:txbecf: afe: USB BE configured as bit_width(%d)sample_rate(%d)channels(%d)",
               __func__, bit_width, sample_rate, channels);
     }
 
@@ -4896,14 +4891,17 @@
           "sample rate: %d", __func__, backend_idx, bit_width, sample_rate);
     // Force routing if the expected bitwdith or samplerate
     // is not same as current backend comfiguration
-    if ((bit_width != my_data->current_tx_backend_cfg[backend_idx].bit_width) ||
-        (sample_rate != my_data->current_tx_backend_cfg[backend_idx].sample_rate)) {
+    if ((bit_width != my_data->current_backend_cfg[backend_idx].bit_width) ||
+        (sample_rate != my_data->current_backend_cfg[backend_idx].sample_rate) ||
+        (channels != my_data->current_backend_cfg[backend_idx].channels)) {
         backend_cfg->bit_width = bit_width;
         backend_cfg->sample_rate= sample_rate;
+        backend_cfg->channels = channels;
         backend_change = true;
         ALOGI("%s:txbecf: afe: Codec backend needs to be updated. new bit width: %d "
-              "new sample rate: %d", __func__, backend_cfg->bit_width,
-              backend_cfg->sample_rate);
+              "new sample rate: %d new channel: %d",
+              __func__, backend_cfg->bit_width,
+              backend_cfg->sample_rate, backend_cfg->channels);
     }
 
     return backend_change;
@@ -4912,7 +4910,7 @@
 bool platform_check_and_set_capture_codec_backend_cfg(struct audio_device* adev,
     struct audio_usecase *usecase, snd_device_t snd_device)
 {
-    int backend_idx = platform_get_capture_backend_index(snd_device);
+    int backend_idx = platform_get_backend_index(snd_device);
     int ret = 0;
     struct audio_backend_cfg backend_cfg;
 
@@ -4938,8 +4936,8 @@
           platform_get_snd_device_name(snd_device));
     if (platform_check_capture_codec_backend_cfg(adev, backend_idx,
                                                  &backend_cfg)) {
-        ret = platform_set_capture_codec_backend_cfg(adev, snd_device,
-                                                     backend_cfg);
+        ret = platform_set_codec_backend_cfg(adev, snd_device,
+                                             backend_cfg);
         if(!ret)
             return true;
     }
@@ -5497,7 +5495,9 @@
     if (snd_device == SND_DEVICE_OUT_SPEAKER ||
         snd_device == SND_DEVICE_OUT_SPEAKER_VBAT ||
         snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT ||
-        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER) {
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER ||
+        snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_2) {
         ret = true;
     }
 
@@ -5515,12 +5515,18 @@
         case SND_DEVICE_OUT_VOICE_SPEAKER:
              acdb_id = platform_get_snd_device_acdb_id(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED);
              break;
+        case SND_DEVICE_OUT_VOICE_SPEAKER_2:
+             acdb_id = platform_get_snd_device_acdb_id(SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED);
+             break;
         case SND_DEVICE_OUT_SPEAKER_VBAT:
              acdb_id = platform_get_snd_device_acdb_id(SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT);
              break;
         case SND_DEVICE_OUT_VOICE_SPEAKER_VBAT:
              acdb_id = platform_get_snd_device_acdb_id(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT);
              break;
+        case SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT:
+             acdb_id = platform_get_snd_device_acdb_id(SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED_VBAT);
+             break;
         default:
              acdb_id = -EINVAL;
              break;
@@ -5538,14 +5544,34 @@
              return SND_DEVICE_OUT_SPEAKER_PROTECTED;
         case SND_DEVICE_OUT_VOICE_SPEAKER:
              return SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED;
+        case SND_DEVICE_OUT_VOICE_SPEAKER_2:
+             return SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED;
         case SND_DEVICE_OUT_SPEAKER_VBAT:
              return SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT;
         case SND_DEVICE_OUT_VOICE_SPEAKER_VBAT:
              return SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT;
+        case SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT:
+             return SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED_VBAT;
         default:
              return snd_device;
     }
 }
+int platform_get_vi_feedback_snd_device(snd_device_t snd_device)
+{
+    switch(snd_device) {
+        case SND_DEVICE_OUT_SPEAKER_PROTECTED:
+        case SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT:
+             return SND_DEVICE_IN_CAPTURE_VI_FEEDBACK;
+        case SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED:
+        case SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT:
+             return SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_1;
+        case SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED:
+        case SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED_VBAT:
+             return SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_2;
+        default:
+             return SND_DEVICE_IN_CAPTURE_VI_FEEDBACK;
+    }
+}
 
 int platform_spkr_prot_is_wsa_analog_mode(void *adev __unused)
 {
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index bcf5d93..2b65950 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -39,6 +39,11 @@
     SOURCE_QUAD_MIC  = 0x8,            /* Target contains 4 mics */
 };
 
+enum {
+    SPKR_1,
+    SPKR_2
+};
+
 /*
  * Below are the devices for which is back end is same, SLIMBUS_0_RX.
  * All these devices are handled by the internal HW codec. We can
@@ -89,6 +94,8 @@
     SND_DEVICE_OUT_VOICE_HANDSET,
     SND_DEVICE_OUT_VOICE_SPEAKER,
     SND_DEVICE_OUT_VOICE_SPEAKER_VBAT,
+    SND_DEVICE_OUT_VOICE_SPEAKER_2,
+    SND_DEVICE_OUT_VOICE_SPEAKER_2_VBAT,
     SND_DEVICE_OUT_VOICE_HEADPHONES,
     SND_DEVICE_OUT_VOICE_LINE,
     SND_DEVICE_OUT_HDMI,
@@ -115,10 +122,13 @@
     SND_DEVICE_OUT_ANC_HANDSET,
     SND_DEVICE_OUT_SPEAKER_PROTECTED,
     SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED,
+    SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED,
     SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT,
     SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT,
+    SND_DEVICE_OUT_VOICE_SPEAKER_2_PROTECTED_VBAT,
     SND_DEVICE_OUT_SPEAKER_WSA,
     SND_DEVICE_OUT_VOICE_SPEAKER_WSA,
+    SND_DEVICE_OUT_VOICE_SPEAKER_2_WSA,
     SND_DEVICE_OUT_END,
 
     /*
@@ -172,6 +182,8 @@
     SND_DEVICE_IN_HANDSET_STEREO_DMIC,
     SND_DEVICE_IN_SPEAKER_STEREO_DMIC,
     SND_DEVICE_IN_CAPTURE_VI_FEEDBACK,
+    SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_1,
+    SND_DEVICE_IN_CAPTURE_VI_FEEDBACK_MONO_2,
     SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE,
     SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE,
     SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE,
@@ -213,14 +225,12 @@
     HDMI_RX_BACKEND,
     DISP_PORT_RX_BACKEND,
     USB_AUDIO_RX_BACKEND,
-    MAX_CODEC_BACKENDS
-};
-
-enum {
-    DEFAULT_CODEC_TX_BACKEND,
-    SLIMBUS_0_TX = DEFAULT_CODEC_TX_BACKEND,
+    MAX_RX_CODEC_BACKENDS = USB_AUDIO_RX_BACKEND,
+    /* TX BE follows RX BE */
+    SLIMBUS_0_TX,
+    DEFAULT_CODEC_TX_BACKEND = SLIMBUS_0_TX,
     USB_AUDIO_TX_BACKEND,
-    MAX_CODEC_TX_BACKENDS
+    MAX_CODEC_BACKENDS
 };
 
 #define AUDIO_PARAMETER_KEY_NATIVE_AUDIO "audio.nat.codec.enabled"
diff --git a/hal/platform_api.h b/hal/platform_api.h
index e5f8f8a..7dcd1b6 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -24,6 +24,8 @@
 #define CODEC_BACKEND_DEFAULT_BIT_WIDTH 16
 #define CODEC_BACKEND_DEFAULT_SAMPLE_RATE 48000
 #define CODEC_BACKEND_DEFAULT_CHANNELS 2
+#define CODEC_BACKEND_DEFAULT_TX_CHANNELS 1
+
 
 enum {
     NATIVE_AUDIO_MODE_SRC = 1,
@@ -143,6 +145,7 @@
 bool platform_can_enable_spkr_prot_on_device(snd_device_t snd_device);
 int platform_get_spkr_prot_acdb_id(snd_device_t snd_device);
 int platform_get_spkr_prot_snd_device(snd_device_t snd_device);
+int platform_get_vi_feedback_snd_device(snd_device_t snd_device);
 int platform_spkr_prot_is_wsa_analog_mode(void *adev);
 bool platform_can_split_snd_device(void *platform,
                                    snd_device_t snd_device,
@@ -177,4 +180,5 @@
     int app_type, int topology_id, int sample_rate, uint32_t module_id, uint32_t param_id,
     void* data, int* length);
 
+unsigned char* platform_get_license(void* platform, int* size);
 #endif // AUDIO_PLATFORM_API_H
diff --git a/hal/voice.c b/hal/voice.c
index f86483e..b84c7b7 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -417,11 +417,13 @@
     int err = 0;
 
     adev->voice.mic_mute = state;
-    if (adev->mode == AUDIO_MODE_IN_CALL)
+    if (audio_extn_hfp_is_active(adev)) {
+        err = hfp_set_mic_mute(adev, state);
+    } else if (adev->mode == AUDIO_MODE_IN_CALL) {
         err = platform_set_mic_mute(adev->platform, state);
-    if (adev->mode == AUDIO_MODE_IN_COMMUNICATION)
+    } else if (adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
         err = voice_extn_compress_voip_set_mic_mute(adev, state);
-
+    }
     return err;
 }
 
diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp
index 9b950d9..022a3c0 100644
--- a/policy_hal/AudioPolicyManager.cpp
+++ b/policy_hal/AudioPolicyManager.cpp
@@ -464,6 +464,11 @@
          }
     }
 #endif
+    if (property_get_bool("voice.dsd.playback.conc.disabled", true) &&
+        isInCall() &&  (offloadInfo.format == AUDIO_FORMAT_DSD)) {
+        ALOGD("blocking DSD compress offload on call mode");
+        return false;
+    }
 #ifdef RECORD_PLAY_CONCURRENCY
     char recConcPropValue[PROPERTY_VALUE_MAX];
     bool prop_rec_play_enabled = false;
@@ -846,6 +851,26 @@
     }
 
 #endif
+
+    sp<SwAudioOutputDescriptor> outputDesc = NULL;
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        outputDesc = mOutputs.valueAt(i);
+        if ((outputDesc == NULL) || (outputDesc->mProfile == NULL)) {
+            ALOGD("voice_conc:ouput desc / profile is NULL");
+            continue;
+        }
+
+        if (property_get_bool("voice.dsd.playback.conc.disabled", true) &&
+            (outputDesc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
+            (outputDesc->mFormat == AUDIO_FORMAT_DSD)) {
+            ALOGD("voice_conc:calling closeOutput on call mode for DSD COMPRESS output");
+            closeOutput(mOutputs.keyAt(i));
+            // call invalidate for music, so that DSD compress will fallback to deep-buffer.
+            mpClientInterface->invalidateStream(AUDIO_STREAM_MUSIC);
+        }
+
+    }
+
 #ifdef RECORD_PLAY_CONCURRENCY
     char recConcPropValue[PROPERTY_VALUE_MAX];
     bool prop_rec_play_enabled = false;