Merge "configs: add system property to set AudioFlinger client heap size"
diff --git a/configs/apq8098_latv/apq8098_latv.mk b/configs/apq8098_latv/apq8098_latv.mk
index e5c8978..242c6d5 100644
--- a/configs/apq8098_latv/apq8098_latv.mk
+++ b/configs/apq8098_latv/apq8098_latv.mk
@@ -123,117 +123,105 @@
 
 # Low latency audio buffer size in frames
 PRODUCT_PROPERTY_OVERRIDES += \
-    audio_hal.period_size=192
+    vendor.audio_hal.period_size=192
 
 ##fluencetype can be "fluence" or "fluencepro" or "none"
 PRODUCT_PROPERTY_OVERRIDES += \
-ro.qc.sdk.audio.fluencetype=none\
-persist.audio.fluence.voicecall=true\
-persist.audio.fluence.voicerec=false\
-persist.audio.fluence.speaker=true
+ro.vendor.audio.sdk.fluencetype=none\
+persist.vendor.audio.fluence.voicecall=true\
+persist.vendor.audio.fluence.voicerec=false\
+persist.vendor.audio.fluence.speaker=true
 
 #disable tunnel encoding
 PRODUCT_PROPERTY_OVERRIDES += \
-tunnel.audio.encode=false
+vendor.audio.tunnel.encode=false
 
 #Disable RAS Feature by default
 PRODUCT_PROPERTY_OVERRIDES += \
-persist.audio.ras.enabled=false
+persist.vendor.audio.ras.enabled=false
 
 #Buffer size in kbytes for compress offload playback
 PRODUCT_PROPERTY_OVERRIDES += \
-audio.offload.buffer.size.kb=32
+vendor.audio.offload.buffer.size.kb=32
 
 #Enable offload audio video playback by default
 PRODUCT_PROPERTY_OVERRIDES += \
 audio.offload.video=true
 
-#Enable 16 bit PCM offload by default
-PRODUCT_PROPERTY_OVERRIDES += \
-audio.offload.pcm.16bit.enable=true
-
-#Enable 24 bit PCM offload by default
-PRODUCT_PROPERTY_OVERRIDES += \
-audio.offload.pcm.24bit.enable=true
-
 #Enable audio track offload by default
 PRODUCT_PROPERTY_OVERRIDES += \
-audio.offload.track.enable=true
+vendor.audio.offload.track.enable=true
 
 #Enable music through deep buffer
 PRODUCT_PROPERTY_OVERRIDES += \
 audio.deep_buffer.media=true
 
-#QC property used when calculating client heap size in audio flinger
-PRODUCT_PROPERTY_OVERRIDES += \
-audio.heap.size.multiplier=7
-
 #enable voice path for PCM VoIP by default
 PRODUCT_PROPERTY_OVERRIDES += \
-use.voice.path.for.pcm.voip=true
+vendor.voice.path.for.pcm.voip=true
 
 #Enable multi channel aac through offload
 PRODUCT_PROPERTY_OVERRIDES += \
-audio.offload.multiaac.enable=true
+vendor.audio.offload.multiaac.enable=true
 
 #Enable DS2, Hardbypass feature for Dolby
 PRODUCT_PROPERTY_OVERRIDES += \
-audio.dolby.ds2.enabled=false\
-audio.dolby.ds2.hardbypass=false
+vendor.audio.dolby.ds2.enabled=false\
+vendor.audio.dolby.ds2.hardbypass=false
 
 #Disable Multiple offload sesison
 PRODUCT_PROPERTY_OVERRIDES += \
-audio.offload.multiple.enabled=false
+vendor.audio.offload.multiple.enabled=false
 
 #Disable Compress passthrough playback
 PRODUCT_PROPERTY_OVERRIDES += \
-audio.offload.passthrough=false
+vendor.audio.offload.passthrough=false
 
 #Disable surround sound recording
 PRODUCT_PROPERTY_OVERRIDES += \
-ro.qc.sdk.audio.ssr=false
+ro.vendor.audio.sdk.ssr=false
 
 #enable dsp gapless mode by default
 PRODUCT_PROPERTY_OVERRIDES += \
-audio.offload.gapless.enabled=true
+vendor.audio.offload.gapless.enabled=true
 
 #enable pbe effects
 PRODUCT_PROPERTY_OVERRIDES += \
-audio.safx.pbe.enabled=true
+vendor.audio.safx.pbe.enabled=true
 
 #parser input buffer size(256kb) in byte stream mode
 PRODUCT_PROPERTY_OVERRIDES += \
-audio.parser.ip.buffer.size=262144
+vendor.audio.parser.ip.buffer.size=262144
 
 #flac sw decoder 24 bit decode capability
 PRODUCT_PROPERTY_OVERRIDES += \
-flac.sw.decoder.24bit.support=true
+vendor.audio.flac.sw.decoder.24bit=true
 
 #split a2dp DSP supported encoder list
 PRODUCT_PROPERTY_OVERRIDES += \
-persist.bt.a2dp_offload_cap=sbc-aptx-aptxhd-aac
+persist.vendor.bt.a2dp_offload_cap=sbc-aptx-aptxhd-aac
 
 #enable software decoders for ALAC and APE
 PRODUCT_PROPERTY_OVERRIDES += \
-use.qti.sw.alac.decoder=true
+vendor.audio.use.sw.alac.decoder=true
 PRODUCT_PROPERTY_OVERRIDES += \
-use.qti.sw.ape.decoder=true
+vendor.audio.use.sw.ape.decoder=true
 
 #enable hw aac encoder by default
 PRODUCT_PROPERTY_OVERRIDES += \
-qcom.hw.aac.encoder=true
+vendor.audio.hw.aac.encoder=true
 
 #Disable FM a2dp concurrency
 PRODUCT_PROPERTY_OVERRIDES += \
-fm.a2dp.conc.disabled=true
+vendor.fm.a2dp.conc.disabled=true
 
 #audio becoming noisy intent broadcast delay
 PRODUCT_PROPERTY_OVERRIDES += \
-audio.noisy.broadcast.delay=600
+vendor.audio.noisy.broadcast.delay=600
 
 #offload pausetime out duration to 3 secs to inline with other outputs
 PRODUCT_PROPERTY_OVERRIDES += \
-audio.offload.pstimeout.secs=3
+vendor.audio.offload.pstimeout.secs=3
 
 #Set AudioFlinger client heap size
 PRODUCT_PROPERTY_OVERRIDES += \
diff --git a/configs/apq8098_latv/audio_policy_configuration.xml b/configs/apq8098_latv/audio_policy_configuration.xml
index fafd322..c8707e3 100644
--- a/configs/apq8098_latv/audio_policy_configuration.xml
+++ b/configs/apq8098_latv/audio_policy_configuration.xml
@@ -329,7 +329,7 @@
                 <route type="mix" sink="voice_rx"
                        sources="Telephony Rx"/>
                 <route type="mix" sink="primary input"
-                       sources="Wired Headset Mic,BT SCO Headset Mic,FM Tuner,USB Device In,Telephony Rx"/>
+                       sources="Built-In Mic,Wired Headset Mic,BT SCO Headset Mic,FM Tuner,USB Device In,Telephony Rx"/>
                 <route type="mix" sink="surround_sound"
                        sources="Built-In Mic,Built-In Back Mic"/>
                 <route type="mix" sink="record_24"
diff --git a/configs/msm8998/mixer_paths_tasha.xml b/configs/msm8998/mixer_paths_tasha.xml
index a7dfbeb..93656e6 100644
--- a/configs/msm8998/mixer_paths_tasha.xml
+++ b/configs/msm8998/mixer_paths_tasha.xml
@@ -125,6 +125,10 @@
     <ctl name="MultiMedia1 Mixer SLIM_0_TX" value="0" />
     <ctl name="MultiMedia1 Mixer SLIM_4_TX" value="0" />
     <ctl name="MultiMedia1 Mixer SLIM_7_TX" value="0" />
+    <ctl name="HDMI RX Format" value="LPCM" />
+    <ctl name="HDMI_RX Bit Format" value="S16_LE" />
+    <ctl name="HDMI_RX SampleRate" value="KHZ_48" />
+    <ctl name="HDMI_RX Channels" value="Two" />
     <ctl name="HDMI Mixer MultiMedia1" value="0" />
     <ctl name="HDMI Mixer MultiMedia2" value="0" />
     <ctl name="HDMI Mixer MultiMedia3" value="0" />
@@ -139,6 +143,10 @@
     <ctl name="HDMI Mixer MultiMedia14" value="0" />
     <ctl name="HDMI Mixer MultiMedia15" value="0" />
     <ctl name="HDMI Mixer MultiMedia16" value="0" />
+    <ctl name="Display Port RX Format" value="LPCM" />
+    <ctl name="Display Port RX Bit Format" value="S16_LE" />
+    <ctl name="Display Port RX SampleRate" value="KHZ_48" />
+    <ctl name="Display Port RX Channels" value="Two" />
     <ctl name="DISPLAY_PORT Mixer MultiMedia1" value="0" />
     <ctl name="DISPLAY_PORT Mixer MultiMedia2" value="0" />
     <ctl name="DISPLAY_PORT Mixer MultiMedia3" value="0" />
diff --git a/configs/msm8998/mixer_paths_tavil.xml b/configs/msm8998/mixer_paths_tavil.xml
index def9580..ba37799 100644
--- a/configs/msm8998/mixer_paths_tavil.xml
+++ b/configs/msm8998/mixer_paths_tavil.xml
@@ -72,6 +72,10 @@
     <ctl name="MultiMedia8 Mixer SLIM_0_TX" value="0" />
     <ctl name="MultiMedia8 Mixer SLIM_4_TX" value="0" />
     <ctl name="MultiMedia8 Mixer SLIM_7_TX" value="0" />
+    <ctl name="HDMI RX Format" value="LPCM" />
+    <ctl name="HDMI_RX Bit Format" value="S16_LE" />
+    <ctl name="HDMI_RX SampleRate" value="KHZ_48" />
+    <ctl name="HDMI_RX Channels" value="Two" />
     <ctl name="HDMI Mixer MultiMedia1" value="0" />
     <ctl name="HDMI Mixer MultiMedia2" value="0" />
     <ctl name="HDMI Mixer MultiMedia3" value="0" />
@@ -86,6 +90,10 @@
     <ctl name="HDMI Mixer MultiMedia14" value="0" />
     <ctl name="HDMI Mixer MultiMedia15" value="0" />
     <ctl name="HDMI Mixer MultiMedia16" value="0" />
+    <ctl name="Display Port RX Format" value="LPCM" />
+    <ctl name="Display Port RX Bit Format" value="S16_LE" />
+    <ctl name="Display Port RX SampleRate" value="KHZ_48" />
+    <ctl name="Display Port RX Channels" value="Two" />
     <ctl name="DISPLAY_PORT Mixer MultiMedia1" value="0" />
     <ctl name="DISPLAY_PORT Mixer MultiMedia2" value="0" />
     <ctl name="DISPLAY_PORT Mixer MultiMedia3" value="0" />
diff --git a/configure.ac b/configure.ac
index da39527..978d235 100644
--- a/configure.ac
+++ b/configure.ac
@@ -114,6 +114,7 @@
 AM_CONDITIONAL([AUDIO_HW_LOOPBACK], [test x$AUDIO_FEATURE_ENABLED_AUDIO_HW_LOOPBACK = xtrue])
 AM_CONDITIONAL([AUDIO_PARSER], [test x$AUDIO_FEATURE_ENABLED_PARSER = xtrue])
 AM_CONDITIONAL([DTSHD_PARSER], [test x$AUDIO_FEATURE_ENABLED_DTSHD_PARSER = xtrue])
+AM_CONDITIONAL([QAP], [test x$AUDIO_FEATURE_ENABLED_QAP = xtrue])
 
 AC_CONFIG_FILES([ \
         Makefile \
diff --git a/hal/audio_extn/a2dp.c b/hal/audio_extn/a2dp.c
index 2103930..9ebc0f2 100644
--- a/hal/audio_extn/a2dp.c
+++ b/hal/audio_extn/a2dp.c
@@ -1038,6 +1038,7 @@
   a2dp.enc_sampling_rate = 48000;
   a2dp.is_a2dp_offload_supported = false;
   a2dp.is_handoff_in_progress = false;
+  reset_a2dp_enc_config_params();
   update_offload_codec_capabilities();
 }
 
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index a1b1344..2726d40 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -99,16 +99,24 @@
 #define AUDIO_FORMAT_AC4  0x23000000UL
 #endif
 
-#ifndef AUDIO_OUTPUT_FLAG_TIMESTAMP
-#define AUDIO_OUTPUT_FLAG_TIMESTAMP 0x10000
+#ifndef AUDIO_OUTPUT_FLAG_MAIN
+#define AUDIO_OUTPUT_FLAG_MAIN 0x8000000
 #endif
 
-#ifndef AUDIO_OUTPUT_FLAG_BD10
-#define AUDIO_OUTPUT_FLAG_BD10 0x20000
+#ifndef AUDIO_OUTPUT_FLAG_ASSOCIATED
+#define AUDIO_OUTPUT_FLAG_ASSOCIATED 0x10000000
+#endif
+
+#ifndef AUDIO_OUTPUT_FLAG_TIMESTAMP
+#define AUDIO_OUTPUT_FLAG_TIMESTAMP 0x20000000
+#endif
+
+#ifndef AUDIO_OUTPUT_FLAG_BD
+#define AUDIO_OUTPUT_FLAG_BD 0x40000000
 #endif
 
 #ifndef AUDIO_OUTPUT_FLAG_INTERACTIVE
-#define AUDIO_OUTPUT_FLAG_INTERACTIVE 0x40000
+#define AUDIO_OUTPUT_FLAG_INTERACTIVE 0x80000000
 #endif
 
 #ifndef COMPRESS_METADATA_NEEDED
@@ -508,6 +516,8 @@
 #define audio_extn_passthru_init(a) do {} while(0)
 #define audio_extn_passthru_should_standby(o) (1)
 #define audio_extn_passthru_get_channel_count(out) (0)
+#define audio_extn_passthru_update_dts_stream_configuration(out, buffer, bytes) (-ENOSYS)
+#define audio_extn_passthru_is_direct_passthrough(out)	(0)
 #else
 bool audio_extn_passthru_is_convert_supported(struct audio_device *adev,
                                                  struct stream_out *out);
@@ -532,6 +542,9 @@
 void audio_extn_passthru_init(struct audio_device *adev);
 bool audio_extn_passthru_should_standby(struct stream_out *out);
 int audio_extn_passthru_get_channel_count(struct stream_out *out);
+int audio_extn_passthru_update_dts_stream_configuration(struct stream_out *out,
+        const void *buffer, size_t bytes);
+bool audio_extn_passthru_is_direct_passthrough(struct stream_out *out);
 #endif
 
 #ifndef HFP_ENABLED
diff --git a/hal/audio_extn/hw_loopback.c b/hal/audio_extn/hw_loopback.c
index 180e575..7c846d9 100644
--- a/hal/audio_extn/hw_loopback.c
+++ b/hal/audio_extn/hw_loopback.c
@@ -41,7 +41,10 @@
 #define PATCH_HANDLE_INVALID 0xFFFF
 #define MAX_SOURCE_PORTS_PER_PATCH 1
 #define MAX_SINK_PORTS_PER_PATCH 1
+#define HW_LOOPBACK_RX_VOLUME     "Trans Loopback RX Volume"
+#define HW_LOOPBACK_RX_UNITY_GAIN 0x2000
 
+#include <math.h>
 #include <stdlib.h>
 #include <pthread.h>
 #include <errno.h>
@@ -59,7 +62,8 @@
 #include <system/thread_defs.h>
 #include <cutils/sched_policy.h>
 #include "audio_extn.h"
-#include "sound/compress_params.h"
+#include <sound/compress_params.h>
+#include <sound/compress_offload.h>
 #include <system/audio.h>
 
 /*
@@ -131,6 +135,34 @@
     }
 }
 
+/* Set loopback volume : for mute implementation */
+static int hw_loopback_set_volume(struct audio_device *adev, int value)
+{
+    int32_t ret = 0;
+    struct mixer_ctl *ctl;
+    char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT];
+    snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+            "Transcode Loopback Rx Volume");
+
+    ALOGD("%s: (%d)\n", __func__, value);
+
+    ALOGD("%s: Setting HW loopback volume to %d \n", __func__, value);
+    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;
+    }
+
+    if(mixer_ctl_set_value(ctl, 0, value) < 0) {
+        ALOGE("%s: Couldn't set HW Loopback Volume: [%d]", __func__, value);
+        return -EINVAL;
+    }
+
+    ALOGV("%s: exit", __func__);
+    return ret;
+}
+
 /* Initialize patch database */
 int init_patch_database(patch_db_t* patch_db)
 {
@@ -147,7 +179,8 @@
 {
     if((sink_device_mask & AUDIO_DEVICE_OUT_SPEAKER) ||
        (sink_device_mask & AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
-       (sink_device_mask & AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+       (sink_device_mask & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) ||
+       (sink_device_mask & AUDIO_DEVICE_OUT_LINE)) {
            return true;
        }
     return false;
@@ -270,7 +303,7 @@
 
     adev->active_input = get_next_active_input(adev);
 
-    if (audio_extn_ip_hdlr_intf_supported(source_patch_config->format, false) && inout->ip_hdlr_handle) {
+    if (inout->ip_hdlr_handle) {
         ret = audio_extn_ip_hdlr_intf_close(inout->ip_hdlr_handle, true, inout);
         if (ret < 0)
             ALOGE("%s: audio_extn_ip_hdlr_intf_close failed %d",__func__, ret);
@@ -284,8 +317,7 @@
         inout->adsp_hdlr_stream_handle = NULL;
     }
 
-    if (audio_extn_ip_hdlr_intf_supported(source_patch_config->format, false) &&
-        inout->ip_hdlr_handle) {
+    if (inout->ip_hdlr_handle) {
         audio_extn_ip_hdlr_intf_deinit(inout->ip_hdlr_handle);
         inout->ip_hdlr_handle = NULL;
     }
@@ -306,6 +338,27 @@
     return 0;
 }
 
+#if defined SNDRV_COMPRESS_LATENCY_MODE
+static void transcode_loopback_util_set_latency_mode(
+                             loopback_patch_t *active_loopback_patch,
+                             uint32_t latency_mode)
+{
+    struct snd_compr_metadata metadata;
+
+    metadata.key = SNDRV_COMPRESS_LATENCY_MODE;
+    metadata.value[0] = latency_mode;
+    ALOGV("%s: Setting latency mode %d",__func__, latency_mode);
+    compress_set_metadata(active_loopback_patch->source_stream,&metadata);
+}
+#else
+static void transcode_loopback_util_set_latency_mode(
+                            loopback_patch_t *active_loopback_patch __unused,
+                            uint32_t latency_mode __unused)
+{
+    ALOGD("%s:: Latency mode configuration not supported", __func__);
+}
+#endif
+
 /* Create a loopback session based on active loopback patch selected */
 int create_loopback_session(loopback_patch_t *active_loopback_patch)
 {
@@ -323,6 +376,7 @@
     struct stream_inout *inout =  &active_loopback_patch->patch_stream;
     struct adsp_hdlr_stream_cfg hdlr_stream_cfg;
     struct stream_in loopback_source_stream;
+    char prop_value[PROPERTY_VALUE_MAX] = {0};
 
     ALOGD("%s: Create loopback session begin", __func__);
 
@@ -381,8 +435,9 @@
         inout->adsp_hdlr_stream_handle = NULL;
         goto exit;
     }
-    if (audio_extn_ip_hdlr_intf_supported(source_patch_config->format, false)) {
-        ret = audio_extn_ip_hdlr_intf_init(&inout->ip_hdlr_handle, NULL, NULL);
+    if (audio_extn_ip_hdlr_intf_supported(source_patch_config->format,false, true)) {
+        ret = audio_extn_ip_hdlr_intf_init(&inout->ip_hdlr_handle, NULL, NULL, adev,
+                                           USECASE_AUDIO_TRANSCODE_LOOPBACK);
         if (ret < 0) {
             ALOGE("%s: audio_extn_ip_hdlr_intf_init failed %d", __func__, ret);
             inout->ip_hdlr_handle = NULL;
@@ -434,6 +489,14 @@
     sink_config.fragments = 1;
     sink_config.codec = &codec;
 
+    /* Do not alter the location of sending latency mode property */
+    /* Mode set on any stream but before both streams are open */
+    if(property_get("audio.transcode.latency.mode", prop_value, "")) {
+        uint32_t latency_mode = atoi(prop_value);
+        transcode_loopback_util_set_latency_mode(active_loopback_patch,
+                                                 latency_mode);
+    }
+
     /* Open compress stream in playback path */
     active_loopback_patch->sink_stream = compress_open(adev->snd_card,
                          pcm_dev_asm_rx_id, COMPRESS_IN, &sink_config);
@@ -467,7 +530,7 @@
         ret = -EINVAL;
         goto exit;
     }
-    if (audio_extn_ip_hdlr_intf_supported(source_patch_config->format, false) && inout->ip_hdlr_handle) {
+    if (inout->ip_hdlr_handle) {
         ret = audio_extn_ip_hdlr_intf_open(inout->ip_hdlr_handle, true, inout,
                                            USECASE_AUDIO_TRANSCODE_LOOPBACK);
         if (ret < 0) {
@@ -662,8 +725,7 @@
                                     struct audio_port *port_in)
 {
     int status = 0, n=0, patch_num=-1;
-    loopback_patch_t *active_loopback_patch = NULL;
-    port_info_t *port_info = NULL;
+    port_info_t port_info;
     struct audio_port_config *port_out=NULL;
     ALOGV("%s %d", __func__, __LINE__);
 
@@ -675,10 +737,10 @@
 
     pthread_mutex_lock(&audio_loopback_mod->lock);
 
-    port_info->id = port_in->id;
-    port_info->role = port_in->role;              /* sink or source */
-    port_info->type = port_in->type;              /* device, mix ... */
-    port_out = get_port_from_patch_db(port_info, &audio_loopback_mod->patch_db,
+    port_info.id = port_in->id;
+    port_info.role = port_in->role;              /* sink or source */
+    port_info.type = port_in->type;              /* device, mix ... */
+    port_out = get_port_from_patch_db(&port_info, &audio_loopback_mod->patch_db,
                                       &patch_num);
     if (port_out == NULL) {
         ALOGE("%s, Unable to find a valid matching port in patch \
@@ -709,40 +771,64 @@
                                         const struct audio_port_config *config)
 {
     int status = 0, n=0, patch_num=-1;
-    loopback_patch_t *active_loopback_patch = NULL;
-    port_info_t *port_info = NULL;
+    port_info_t port_info;
     struct audio_port_config *port_out=NULL;
+    struct audio_device *adev = audio_loopback_mod->adev;
+    int loopback_gain = HW_LOOPBACK_RX_UNITY_GAIN;
+
     ALOGV("%s %d", __func__, __LINE__);
 
     if ((audio_loopback_mod == NULL) || (dev == NULL)) {
         ALOGE("%s, Invalid device", __func__);
-        status = -1;
+        status = -EINVAL;
         return status;
     }
 
     pthread_mutex_lock(&audio_loopback_mod->lock);
 
-    port_info->id = config->id;
-    port_info->role = config->role;              /* sink or source */
-    port_info->type = config->type;              /* device, mix  */
-    port_out = get_port_from_patch_db(port_info, &audio_loopback_mod->patch_db
+    port_info.id = config->id;
+    port_info.role = config->role;              /* sink or source */
+    port_info.type = config->type;              /* device, mix  */
+    port_out = get_port_from_patch_db(&port_info, &audio_loopback_mod->patch_db
                                     , &patch_num);
 
     if (port_out == NULL) {
         ALOGE("%s, Unable to find a valid matching port in patch \
         database,exiting", __func__);
-        status = -1;
-        return status;
+        status = -EINVAL;
+        goto exit_set_port_config;
     }
 
-    port_out->config_mask = config->config_mask;
-    port_out->channel_mask = config->channel_mask;
-    port_out->format = config->format;
-    port_out->gain = config->gain;
-    port_out->sample_rate = config->sample_rate;
+    port_out->config_mask |= config->config_mask;
+    if(config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK)
+        port_out->channel_mask = config->channel_mask;
+    if(config->config_mask & AUDIO_PORT_CONFIG_FORMAT)
+        port_out->format = config->format;
+    if(config->config_mask & AUDIO_PORT_CONFIG_GAIN)
+        port_out->gain = config->gain;
+    if(config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE)
+        port_out->sample_rate = config->sample_rate;
+
+    /* Convert gain in millibels to ratio and convert to Q13 */
+    loopback_gain = pow(10, (float)((float)port_out->gain.values[0]/2000)) *
+                       (1 << 13);
+    ALOGV("%s, Port config gain_in_mbells: %d, gain_in_q13 : %d", __func__,
+          port_out->gain.values[0], loopback_gain);
+    if((port_out->config_mask & AUDIO_PORT_CONFIG_GAIN) &&
+        port_out->gain.mode == AUDIO_GAIN_MODE_JOINT ) {
+        status = hw_loopback_set_volume(adev, loopback_gain);
+        if (status) {
+            ALOGE("%s, Error setting loopback gain config: status %d",
+                  __func__, status);
+        }
+    } else {
+        ALOGE("%s, Unsupported port config ,exiting", __func__);
+        status = -EINVAL;
+    }
 
     /* Currently, port config is not used for anything,
     need to restart session    */
+exit_set_port_config:
     pthread_mutex_unlock(&audio_loopback_mod->lock);
     return status;
 }
diff --git a/hal/audio_extn/ip_hdlr_intf.c b/hal/audio_extn/ip_hdlr_intf.c
index 0f31f21..a94e6de 100644
--- a/hal/audio_extn/ip_hdlr_intf.c
+++ b/hal/audio_extn/ip_hdlr_intf.c
@@ -70,6 +70,7 @@
     int (*deinit)(void *handle);
     int (*open)(void *handle, bool is_dsp_decode, void *aud_sess_handle);
     int (*shm_info)(void *handle, int *fd);
+    int (*get_lib_fd)(void *handle, int *lib_fd);
     int (*close)(void *handle);
     int (*event)(void *handle, void *payload);
     int (*reg_cb)(void *handle, void *ack_cb, void *fail_cb);
@@ -116,12 +117,20 @@
     uint8_t payload[0];
 };
 
-bool audio_extn_ip_hdlr_intf_supported(audio_format_t format,bool is_direct_passthru)
+bool audio_extn_ip_hdlr_intf_supported(audio_format_t format,
+                    bool is_direct_passthrough,
+                    bool is_transcode_loopback)
 {
-    if (((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_DOLBY_TRUEHD) ||
-        ((!is_direct_passthru) &&
-         (((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_E_AC3) ||
-         ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AC3))))
+
+    if ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_DOLBY_TRUEHD)
+        return true;
+    else if (!is_direct_passthrough && !audio_extn_qaf_is_enabled() &&
+            (((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_E_AC3) ||
+             ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AC3)))
+        return true;
+    else if (is_transcode_loopback &&
+            (((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_E_AC3) ||
+             ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AC3)))
         return true;
     else
         return false;
@@ -416,9 +425,13 @@
     return ret;
 }
 
-int audio_extn_ip_hdlr_intf_init(void **handle, char *lib_path, void **lib_handle)
+int audio_extn_ip_hdlr_intf_init(void **handle, char *lib_path, void **lib_handle,
+                                 struct audio_device *dev, audio_usecase_t usecase)
 {
-    int ret = 0;
+    int ret = 0, pcm_device_id;
+    int lib_fd;
+    struct mixer_ctl *ctl = NULL;
+    char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
 
     if (!ip_hdlr) {
         ip_hdlr = (struct ip_hdlr_intf *)calloc(1, sizeof(struct ip_hdlr_intf));
@@ -444,11 +457,13 @@
                                   void *fail_cb))dlsym(ip_hdlr->lib_hdl, "audio_ip_hdlr_reg_cb");
         ip_hdlr->shm_info =(int (*)(void *handle, int *fd))dlsym(ip_hdlr->lib_hdl,
                                                                  "audio_ip_hdlr_shm_info");
+        ip_hdlr->get_lib_fd =(int (*)(void *handle, int *fd))dlsym(ip_hdlr->lib_hdl,
+                                                                 "audio_ip_hdlr_lib_fd");
         ip_hdlr->event =(int (*)(void *handle, void *payload))dlsym(ip_hdlr->lib_hdl,
                                                                     "audio_ip_hdlr_event");
         if (!ip_hdlr->init || !ip_hdlr->deinit || !ip_hdlr->open ||
             !ip_hdlr->close || !ip_hdlr->reg_cb || !ip_hdlr->shm_info ||
-            !ip_hdlr->event) {
+            !ip_hdlr->event || !ip_hdlr->get_lib_fd) {
             ALOGE("%s: failed to get symbols", __func__);
             ret = -EINVAL;
             goto dlclose;
@@ -462,6 +477,32 @@
         ret = -EINVAL;
         goto dlclose;
     }
+    if (!lib_path) {
+        ip_hdlr->get_lib_fd(*handle, &lib_fd);
+
+        pcm_device_id = platform_get_pcm_device_id(usecase, PCM_PLAYBACK);
+        ret = snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+                       "Playback ION LIB FD %d", pcm_device_id);
+        if (ret < 0) {
+            ALOGE("%s:[%d] snprintf failed",__func__, ip_hdlr->ref_cnt, ret);
+            goto dlclose;
+        }
+        ALOGV("%s: fd = %d  pcm_id = %d", __func__, lib_fd, pcm_device_id);
+
+        ctl = mixer_get_ctl_by_name(dev->mixer, mixer_ctl_name);
+        if (!ctl) {
+            ALOGE("%s:[%d] Could not get ctl for mixer cmd - %s", __func__,
+                  ip_hdlr->ref_cnt, mixer_ctl_name);
+            ret = -EINVAL;
+            goto dlclose;
+        }
+        ret = mixer_ctl_set_array(ctl, &lib_fd, sizeof(lib_fd));
+        if (ret < 0) {
+            ALOGE("%s:[%d] Could not set ctl for mixer cmd - %s, ret %d", __func__, ip_hdlr->ref_cnt,
+                  mixer_ctl_name, ret);
+            goto dlclose;
+        }
+    }
     ip_hdlr->ref_cnt++;
     ALOGD("%s:[%d] init done", __func__, ip_hdlr->ref_cnt);
 
diff --git a/hal/audio_extn/ip_hdlr_intf.h b/hal/audio_extn/ip_hdlr_intf.h
index 1f2c304..6040620 100644
--- a/hal/audio_extn/ip_hdlr_intf.h
+++ b/hal/audio_extn/ip_hdlr_intf.h
@@ -35,17 +35,20 @@
 int audio_extn_ip_hdlr_intf_open(void *handle, bool is_dsp_decode, void *aud_sess_handle,
                                  audio_usecase_t usecase);
 int audio_extn_ip_hdlr_intf_close(void *handle, bool is_dsp_decode, void *aud_sess_handle);
-int audio_extn_ip_hdlr_intf_init(void **handle, char *lib_path, void **lib_handle);
+int audio_extn_ip_hdlr_intf_init(void **handle, char *lib_path, void **lib_handle,
+                                 struct audio_device *dev, audio_usecase_t usecase);
 int audio_extn_ip_hdlr_intf_deinit(void *handle);
-bool audio_extn_ip_hdlr_intf_supported(audio_format_t format, bool is_direct_passthru);
+bool audio_extn_ip_hdlr_intf_supported(audio_format_t format,
+                                       bool is_direct_passthru,
+                                       bool is_transcode_loopback);
 
 #else
 
 #define audio_extn_ip_hdlr_intf_open(handle, is_dsp_decode, aud_sess_handle, usecase)  (0)
-#define audio_extn_ip_hdlr_intf_close(handle, is_dsp_decode, aud_sess_handle) (0)
-#define audio_extn_ip_hdlr_intf_init(handle, lib_path, lib_handle)            (0)
+#define audio_extn_ip_hdlr_intf_close(handle, is_dsp_decode, aud_sess_handle)          (0)
+#define audio_extn_ip_hdlr_intf_init(handle, lib_path, lib_handlei, adev, usecase)     (0)
 #define audio_extn_ip_hdlr_intf_deinit(handle)                                (0)
-#define audio_extn_ip_hdlr_intf_supported(format, is_direct_passthru)                             (0)
+#define audio_extn_ip_hdlr_intf_supported(format, is_direct_passthru, is_loopback) (0)
 
 #endif
 
diff --git a/hal/audio_extn/keep_alive.c b/hal/audio_extn/keep_alive.c
index 8bd1da1..3e9a91c 100644
--- a/hal/audio_extn/keep_alive.c
+++ b/hal/audio_extn/keep_alive.c
@@ -49,6 +49,7 @@
     STATE_DEINIT = -1,
     STATE_IDLE,
     STATE_ACTIVE,
+    STATE_DISABLED,
 } state_t;
 
 typedef enum {
@@ -93,6 +94,13 @@
     ka.userdata = adev;
     ka.state = STATE_IDLE;
     ka.pcm = NULL;
+
+    if (property_get_bool("audio.keep_alive.disabled", false)) {
+        ALOGE("keep alive disabled");
+        ka.state = STATE_DISABLED;
+        return;
+    }
+
     pthread_mutex_init(&ka.lock, (const pthread_mutexattr_t *) NULL);
     pthread_cond_init(&ka.cond, (const pthread_condattr_t *) NULL);
     pthread_cond_init(&ka.wake_up_cond, (const pthread_condattr_t *) NULL);
@@ -108,7 +116,7 @@
 
 static void send_cmd_l(request_t r)
 {
-    if (ka.state == STATE_DEINIT)
+    if (ka.state == STATE_DEINIT || ka.state == STATE_DISABLED)
         return;
 
     struct keep_alive_cmd *cmd =
@@ -193,6 +201,9 @@
     struct audio_usecase *usecase;
     int32_t sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
 
+    if (ka.state == STATE_DISABLED)
+        return;
+
     pthread_mutex_lock(&ka.lock);
 
     if (ka.state == STATE_DEINIT) {
@@ -317,6 +328,9 @@
 {
     struct audio_device * adev = (struct audio_device *)ka.userdata;
 
+    if (ka.state == STATE_DISABLED)
+        return;
+
     pthread_mutex_lock(&ka.lock);
 
     if ((ka.state == STATE_DEINIT) || (ka.state == STATE_IDLE))
@@ -359,6 +373,9 @@
     char value[32];
     int ret;
 
+    if (ka.state == STATE_DISABLED)
+        return;
+
     ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
     if (ret >= 0) {
         int val = atoi(value);
diff --git a/hal/audio_extn/passthru.c b/hal/audio_extn/passthru.c
index ee9995c..701084a 100644
--- a/hal/audio_extn/passthru.c
+++ b/hal/audio_extn/passthru.c
@@ -90,7 +90,7 @@
 static volatile int32_t compress_passthru_active;
 
 #ifdef DTSHD_PARSER_ENABLED
-static void passthru_update_stream_configuration_from_dts_parser( struct stream_out *out,
+int audio_extn_passthru_update_dts_stream_configuration(struct stream_out *out,
         const void *buffer, size_t bytes)
 {
     struct audio_parser_codec_info codec_info;
@@ -100,6 +100,27 @@
     bool is_valid_transmission_rate = false;
     bool is_valid_transmission_channels = false;
 
+    if (!out) {
+        ALOGE("Invalid session");
+        return -EINVAL;
+    }
+
+    if ((out->format != AUDIO_FORMAT_DTS) &&
+        (out->format != AUDIO_FORMAT_DTS_HD)) {
+        ALOGE("Non DTS format %d", out->format);
+        return -EINVAL;
+    }
+
+    if (!buffer || bytes <= 0) {
+        ALOGD("Invalid buffer %p size %d skipping dts stream conf update",
+                buffer, bytes);
+        out->sample_rate = 48000;
+        out->compr_config.codec->sample_rate = out->sample_rate;
+        out->compr_config.codec->ch_in = 2;
+        out->channel_mask = audio_channel_out_mask_from_count(2);
+        return -EINVAL;
+    }
+
     /* codec format is AUDIO_PARSER_CODEC_DTSHD for both DTS and DTSHD as
      *  DTSHD parser can support both DTS and DTSHD
      */
@@ -135,9 +156,9 @@
     }
 
     if (!is_valid_transmission_rate) {
-        ALOGE("%s:: Invalid dts transmission rate %d\n using default sample rate 192000",
+        ALOGE("%s:: Invalid dts transmission rate %d\n using default sample rate 48000",
                dtshd_tr_info.sample_rate);
-        out->sample_rate = 192000;
+        out->sample_rate = 48000;
         out->compr_config.codec->sample_rate = out->sample_rate;
     }
 
@@ -147,14 +168,15 @@
         out->compr_config.codec->ch_in = 2;
         out->channel_mask = audio_channel_out_mask_from_count(2);
     }
+    return 0;
 }
 #else
-static void passthru_update_stream_configuration_from_dts_parser(
+int audio_extn_passthru_update_dts_stream_configuration(
                         struct stream_out *out __unused,
                         const void *buffer __unused,
                         size_t bytes __unused)
 {
-    return;
+    return -ENOSYS;
 }
 #endif
 
@@ -391,7 +413,7 @@
 
 void audio_extn_passthru_update_stream_configuration(
         struct audio_device *adev, struct stream_out *out,
-        const void *buffer, size_t bytes)
+        const void *buffer __unused, size_t bytes __unused)
 {
     if (audio_extn_passthru_is_passt_supported(adev, out)) {
         ALOGV("%s:PASSTHROUGH", __func__);
@@ -406,28 +428,6 @@
         ALOGV("%s:NO PASSTHROUGH", __func__);
         out->compr_config.codec->compr_passthr = LEGACY_PCM;
     }
-
-    /*
-     * for DTS passthrough, need to get sample rate from bitstream,
-     * based on this sample rate hdmi backend will be configured
-     */
-    if ((out->format == AUDIO_FORMAT_DTS) ||
-        (out->format == AUDIO_FORMAT_DTS_HD))
-        passthru_update_stream_configuration_from_dts_parser(out, buffer, bytes);
-
-}
-
-bool audio_extn_passthru_is_direct_passthrough(struct stream_out *out)
-{
-    //check passthrough system property
-    if (!property_get_bool("audio.offload.passthrough", false)) {
-        return false;
-    }
-
-    if ((out != NULL) && (out->compr_config.codec->compr_passthr == PASSTHROUGH || out->compr_config.codec->compr_passthr == PASSTHROUGH_IEC61937))
-        return true;
-    else
-        return false;
 }
 
 bool audio_extn_passthru_is_passthrough_stream(struct stream_out *out)
@@ -464,6 +464,15 @@
     return false;
 }
 
+bool audio_extn_passthru_is_direct_passthrough(struct stream_out *out)
+{
+    if (((out != NULL) && audio_extn_passthru_is_passthrough_stream(out)) &&
+          !audio_extn_passthru_is_convert_supported(out->dev, out))
+        return true;
+    else
+        return false;
+}
+
 int audio_extn_passthru_get_buffer_size(audio_offload_info_t* info)
 {
     uint32_t fragment_size = MIN_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE;
diff --git a/hal/audio_extn/qaf.c b/hal/audio_extn/qaf.c
index 90b054c..6320b94 100644
--- a/hal/audio_extn/qaf.c
+++ b/hal/audio_extn/qaf.c
@@ -765,8 +765,7 @@
     DEBUG_MSG_VV("ret [%d]", (int)ret);
 
     if (ret >= 0) {
-        bytes = ret;
-        out->written += bytes / ((popcount(out->channel_mask) * sizeof(short)));
+        out->written += ret / ((popcount(out->channel_mask) * sizeof(short)));
     }
 
 
@@ -786,6 +785,11 @@
                    / audio_stream_out_frame_size(stream)
                    / out->stream.common.get_sample_rate(&out->stream.common));
         }
+    } else if (ret < bytes) {
+        //partial buffer copied to the module.
+        DEBUG_MSG_VV("Not enough space available in mm module, post msg to cb thread");
+        (void)qaf_send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
+        bytes = ret;
     }
     return bytes;
 }
@@ -1665,12 +1669,14 @@
         }
         DEBUG_MSG_VV("Bytes written = %d", ret);
     }
-    else if (event_id == AUDIO_EOS_MAIN_DD_DDP_EVENT
+    else if (event_id == AUDIO_EOS_EVENT
+               || event_id == AUDIO_EOS_MAIN_DD_DDP_EVENT
                || event_id == AUDIO_EOS_MAIN_2_DD_DDP_EVENT
                || event_id == AUDIO_EOS_MAIN_AAC_EVENT
                || event_id == AUDIO_EOS_MAIN_AC4_EVENT
                || event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT) {
         struct stream_out *out = qaf_mod->stream_in[QAF_IN_MAIN];
+        struct stream_out *out_pcm = qaf_mod->stream_in[QAF_IN_PCM];
         struct stream_out *out_main2 = qaf_mod->stream_in[QAF_IN_MAIN_2];
         struct stream_out *out_assoc = qaf_mod->stream_in[QAF_IN_ASSOC];
 
@@ -1678,7 +1684,16 @@
          * TODO:: Only DD/DDP Associate Eos is handled, need to add support
          * for other formats.
          */
-        if (event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT
+        if (event_id == AUDIO_EOS_EVENT
+                && (out_pcm != NULL)
+                && (check_stream_state(out_pcm, STOPPING))) {
+
+            lock_output_stream(out_pcm);
+            out_pcm->client_callback(STREAM_CBK_EVENT_DRAIN_READY, NULL, out_pcm->client_cookie);
+            set_stream_state(out_pcm, STOPPED);
+            unlock_output_stream(out_pcm);
+            DEBUG_MSG("sent pcm DRAIN_READY");
+        } else if (event_id == AUDIO_EOS_ASSOC_DD_DDP_EVENT
                 && (out_assoc != NULL)
                 && (check_stream_state(out_assoc, STOPPING))) {
 
@@ -1915,13 +1930,16 @@
     struct qaf_module* qaf_mod = NULL;
     DEBUG_MSG("Flags 0x%x, Device 0x%x", flags, devices);
 
-    if (mmtype >= MAX_MM_MODULE_TYPE
-        || p_qaf->qaf_mod[mmtype].qaf_audio_session_open == NULL
-        || p_qaf->qaf_mod[mmtype].qaf_audio_stream_open == NULL) {
+    if (mmtype >= MAX_MM_MODULE_TYPE) {
         ERROR_MSG("Unsupported Stream");
         return -ENOTSUP;
     }
 
+    if (p_qaf->qaf_mod[mmtype].qaf_audio_session_open == NULL ||
+        p_qaf->qaf_mod[mmtype].qaf_audio_stream_open == NULL) {
+        ERROR_MSG("Session or Stream is NULL");
+        return status;
+    }
     //Open the module session, if not opened already.
     status = audio_extn_qaf_session_open(mmtype, out);
     qaf_mod = &(p_qaf->qaf_mod[mmtype]);
@@ -2136,7 +2154,7 @@
                         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) {
+                            if (value > 0) {
                                 DEBUG_MSG_VV("buffer available");
                                 str_parms_destroy(parms);
                                 parms = NULL;
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
index 3784197..a33d432 100644
--- a/hal/audio_extn/spkr_protection.c
+++ b/hal/audio_extn/spkr_protection.c
@@ -430,6 +430,20 @@
      return -EINVAL;
 }
 
+void destroy_thread_params()
+{
+    pthread_mutex_destroy(&handle.mutex_spkr_prot);
+    pthread_mutex_destroy(&handle.spkr_calib_cancelack_mutex);
+    pthread_mutex_destroy(&handle.cal_wait_cond_mutex);
+    pthread_cond_destroy(&handle.cal_wait_condition);
+    pthread_cond_destroy(&handle.spkr_calib_cancel);
+    pthread_cond_destroy(&handle.spkr_calibcancel_ack);
+    if(!handle.wsa_found) {
+        pthread_mutex_destroy(&handle.spkr_prot_thermalsync_mutex);
+        pthread_cond_destroy(&handle.spkr_prot_thermalsync);
+    }
+}
+
 static int spkr_calibrate(int t0_spk_1, int t0_spk_2)
 {
     struct audio_device *adev = handle.adev_handle;
@@ -443,6 +457,7 @@
     bool acquire_device = false;
 
     status.status = 0;
+    memset(&protCfg, 0, sizeof(protCfg));
     if (!adev) {
         ALOGE("%s: Invalid params", __func__);
         return -EINVAL;
@@ -1314,11 +1329,7 @@
             handle.init_check = true;
         } else {
             ALOGE("%s: speaker calibration thread creation failed", __func__);
-            pthread_mutex_destroy(&handle.mutex_spkr_prot);
-            pthread_mutex_destroy(&handle.spkr_calib_cancelack_mutex);
-            pthread_mutex_destroy(&handle.cal_wait_cond_mutex);
-            pthread_cond_destroy(&handle.spkr_calib_cancel);
-            pthread_cond_destroy(&handle.spkr_calibcancel_ack);
+            destroy_thread_params();
         }
     return;
     } else {
@@ -1366,13 +1377,7 @@
             handle.init_check = true;
         } else {
             ALOGE("%s: speaker calibration thread creation failed", __func__);
-            pthread_mutex_destroy(&handle.mutex_spkr_prot);
-            pthread_mutex_destroy(&handle.spkr_calib_cancelack_mutex);
-            pthread_mutex_destroy(&handle.cal_wait_cond_mutex);
-            pthread_cond_destroy(&handle.spkr_calib_cancel);
-            pthread_cond_destroy(&handle.spkr_calibcancel_ack);
-            pthread_mutex_destroy(&handle.spkr_prot_thermalsync_mutex);
-            pthread_cond_destroy(&handle.spkr_prot_thermalsync);
+            destroy_thread_params();
         }
     } else {
         ALOGE("%s: thermal_client_request failed", __func__);
@@ -1400,7 +1405,8 @@
 {
     int result = 0;
 
-    ALOGD("%s: Entering deinit init_check :%d", __func__, handle.init_check);
+    ALOGD("%s: Entering deinit init_check :%d",
+          __func__, handle.init_check);
     if(!handle.init_check)
         return -1;
 
@@ -1411,15 +1417,7 @@
         ALOGE("%s:Unable to join the calibration thread", __func__);
         return -1;
     }
-    pthread_mutex_destroy(&handle.mutex_spkr_prot);
-    pthread_mutex_destroy(&handle.spkr_calib_cancelack_mutex);
-    pthread_mutex_destroy(&handle.cal_wait_cond_mutex);
-    pthread_cond_destroy(&handle.spkr_calib_cancel);
-    pthread_cond_destroy(&handle.spkr_calibcancel_ack);
-    if(!handle.wsa_found) {
-        pthread_mutex_destroy(&handle.spkr_prot_thermalsync_mutex);
-        pthread_cond_destroy(&handle.spkr_prot_thermalsync);
-    }
+    destroy_thread_params();
     memset(&handle, 0, sizeof(handle));
     return 0;
 }
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 8c4f313..3923818 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -845,6 +845,19 @@
                                                 &usecase->stream.in->app_type_cfg);
         ALOGV("%s Selected apptype: %d", __func__, usecase->stream.in->app_type_cfg.app_type);
         break;
+    case TRANSCODE_LOOPBACK :
+        audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
+                                                &adev->streams_output_cfg_list,
+                                                usecase->stream.inout->out_config.devices,
+                                                0,
+                                                usecase->stream.inout->out_config.format,
+                                                usecase->stream.inout->out_config.sample_rate,
+                                                usecase->stream.inout->out_config.bit_width,
+                                                usecase->stream.inout->out_config.channel_mask,
+                                                usecase->stream.inout->profile,
+                                                &usecase->stream.inout->out_app_type_cfg);
+        ALOGV("%s Selected apptype: %d", __func__, usecase->stream.inout->out_app_type_cfg.app_type);
+        break;
     default:
         ALOGE("%s: app type cfg not supported for usecase type (%d)",
             __func__, usecase->type);
@@ -872,7 +885,8 @@
           platform_get_snd_device_name(usecase->in_snd_device),
           platform_get_snd_device_name(split_snd_device));
 
-    if (usecase->type != PCM_PLAYBACK && usecase->type != PCM_CAPTURE) {
+    if (usecase->type != PCM_PLAYBACK && usecase->type != PCM_CAPTURE &&
+        usecase->type != TRANSCODE_LOOPBACK) {
         ALOGE("%s: not a playback/capture path, no need to cfg app type", __func__);
         rc = 0;
         goto exit_send_app_type_cfg;
@@ -882,6 +896,7 @@
         (usecase->id != USECASE_AUDIO_PLAYBACK_MULTI_CH) &&
         (usecase->id != USECASE_AUDIO_PLAYBACK_ULL) &&
         (usecase->id != USECASE_AUDIO_PLAYBACK_VOIP) &&
+        (usecase->id != USECASE_AUDIO_TRANSCODE_LOOPBACK) &&
         (!is_interactive_usecase(usecase->id)) &&
         (!is_offload_usecase(usecase->id)) &&
         (usecase->type != PCM_CAPTURE)) {
@@ -897,7 +912,7 @@
             goto exit_send_app_type_cfg;
     }
 
-    if (usecase->type == PCM_PLAYBACK) {
+    if (usecase->type == PCM_PLAYBACK || usecase->type == TRANSCODE_LOOPBACK) {
         pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_PLAYBACK);
         snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
             "Audio Stream %d App Type Cfg", pcm_device_id);
@@ -980,7 +995,8 @@
         if (((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
             (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC) ||
             (usecase->stream.out->format == AUDIO_FORMAT_DOLBY_TRUEHD))
-            && audio_extn_passthru_is_passthrough_stream(usecase->stream.out)) {
+            && audio_extn_passthru_is_passthrough_stream(usecase->stream.out)
+            && !audio_extn_passthru_is_convert_supported(adev, usecase->stream.out)) {
 
             sample_rate = sample_rate * 4;
             if (sample_rate > HDMI_PASSTHROUGH_MAX_SAMPLE_RATE)
@@ -1006,6 +1022,10 @@
            __func__, app_type, acdb_dev_id, sample_rate, snd_device_be_idx);
     } else {
         app_type = platform_get_default_app_type_v2(adev->platform, usecase->type);
+        if(usecase->type == TRANSCODE_LOOPBACK) {
+            sample_rate = usecase->stream.inout->out_config.sample_rate;
+            app_type = usecase->stream.inout->out_app_type_cfg.app_type;
+        }
         app_type_cfg[len++] = app_type;
         app_type_cfg[len++] = acdb_dev_id;
         app_type_cfg[len++] = sample_rate;
@@ -1015,7 +1035,8 @@
               __func__, app_type, acdb_dev_id, sample_rate, snd_device_be_idx);
     }
 
-    mixer_ctl_set_array(ctl, app_type_cfg, len);
+    if(ctl)
+        mixer_ctl_set_array(ctl, app_type_cfg, len);
     rc = 0;
 exit_send_app_type_cfg:
     return rc;
@@ -1030,6 +1051,7 @@
 
     switch (usecase->type) {
     case PCM_PLAYBACK:
+    case TRANSCODE_LOOPBACK:
         ALOGD("%s: usecase->out_snd_device %s",
               __func__, platform_get_snd_device_name(usecase->out_snd_device));
         /* check for out combo device */
@@ -1222,7 +1244,8 @@
      *be multiple of (number of channels * bytes per sample)
      *For writes to succeed, the buffer must be written at address which is multiple of 32
      */
-    fragment_size = ALIGN(fragment_size, (bytes_per_sample * noOfChannels * 32));
+    fragment_size = ALIGN(fragment_size, (bytes_per_sample * noOfChannels));
+    fragment_size = ALIGN(fragment_size, 32);
 
     ALOGI("PCM offload Fragment size to %d bytes", fragment_size);
     return fragment_size;
@@ -1369,6 +1392,13 @@
         platform_send_audio_calibration(adev->platform, usecase,
                          platform_get_default_app_type_v2(adev->platform, usecase->type),
                          48000);
+    } else if (type == TRANSCODE_LOOPBACK && usecase->stream.inout != NULL) {
+        int snd_device = usecase->out_snd_device;
+        snd_device = (snd_device == SND_DEVICE_OUT_SPEAKER) ?
+                     platform_get_spkr_prot_snd_device(snd_device) : snd_device;
+        platform_send_audio_calibration(adev->platform, usecase,
+                         platform_get_default_app_type_v2(adev->platform, usecase->type),
+                         usecase->stream.inout->out_config.sample_rate);
     } else {
         /* No need to send audio calibration for voice and voip call usecases */
         if ((type != VOICE_CALL) && (type != VOIP_CALL))
@@ -2302,9 +2332,11 @@
 
     out->downmix_params.has_mixer_coeffs = mm_params->has_mixer_coeffs;
     for (i = 0; i < mm_params->num_output_channels; i++)
-        for (j = 0; j < mm_params->num_input_channels; j++)
+        for (j = 0; j < mm_params->num_input_channels; j++) {
+            //Convert the channel coefficient gains in Q14 format
             out->downmix_params.mixer_coeffs[i][j] =
-                               mm_params->mixer_coeffs[i][j];
+                               mm_params->mixer_coeffs[i][j] * (2 << 13);
+    }
 
     ret = platform_set_stream_downmix_params(out->dev->platform,
                                              out->pcm_device_id,
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 5cfc3f8..12bc76b 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1645,6 +1645,10 @@
          ret = true;
      }
 
+     if (usecase->stream.out->stream_config_changed) {
+         ALOGD("Force stream_config_changed to update iec61937 transmission config");
+         return true;
+     }
     return ret;
 }
 
@@ -2544,7 +2548,7 @@
     if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
         audio_extn_keep_alive_start();
 
-    if (audio_extn_ip_hdlr_intf_supported(out->format, audio_extn_passthru_is_direct_passthrough(out)) && out->ip_hdlr_handle) {
+    if (out->ip_hdlr_handle) {
         ret = audio_extn_ip_hdlr_intf_close(out->ip_hdlr_handle, true, out);
         if (ret < 0)
             ALOGE("%s: audio_extn_ip_hdlr_intf_close failed %d",__func__, ret);
@@ -2799,7 +2803,7 @@
     audio_extn_perf_lock_release(&adev->perf_lock_handle);
     ALOGD("%s: exit", __func__);
 
-    if (audio_extn_ip_hdlr_intf_supported(out->format, audio_extn_passthru_is_direct_passthrough(out)) && out->ip_hdlr_handle) {
+    if (out->ip_hdlr_handle) {
         ret = audio_extn_ip_hdlr_intf_open(out->ip_hdlr_handle, true, out, out->usecase);
         if (ret < 0)
             ALOGE("%s: audio_extn_ip_hdlr_intf_open failed %d",__func__, ret);
@@ -2966,7 +2970,7 @@
     struct stream_out *out = (struct stream_out *)stream;
 
     if (is_interactive_usecase(out->usecase)) {
-        return out->config.period_size;
+        return out->config.period_size * out->config.period_count;
     } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
         if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP)
             return out->compr_config.fragment_size - sizeof(struct snd_codec_metadata);
@@ -3704,6 +3708,7 @@
     struct stream_out *out = (struct stream_out *)stream;
     struct audio_device *adev = out->dev;
     ssize_t ret = 0;
+    int channels = 0;
 
     lock_output_stream(out);
 
@@ -3733,12 +3738,44 @@
     }
 
     if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
-        /*ADD audio_extn_passthru_is_passthrough_stream(out) check*/
-        if ((audio_extn_passthru_is_enabled()) &&
-                (!out->is_iec61937_info_available)) {
+        channels = platform_edid_get_max_channels(out->dev->platform);
+        if (audio_extn_passthru_is_enabled() &&
+            !out->is_iec61937_info_available &&
+            audio_extn_passthru_is_passthrough_stream(out)) {
             audio_extn_passthru_update_stream_configuration(adev, out,
                     buffer, bytes);
             out->is_iec61937_info_available = true;
+
+            if((out->format == AUDIO_FORMAT_DTS) ||
+               (out->format == AUDIO_FORMAT_DTS_HD)) {
+                ret = audio_extn_passthru_update_dts_stream_configuration(out,
+                                                                buffer, bytes);
+                if (ret) {
+                    if (ret != -ENOSYS) {
+                        out->is_iec61937_info_available = false;
+                        ALOGD("iec61937 transmission info not yet updated retry");
+                    }
+                } else {
+                    /* if stream has started and after that there is
+                     * stream config change (iec transmission config)
+                     * then trigger select_device to update backend configuration.
+                     */
+                    out->stream_config_changed = true;
+                    pthread_mutex_lock(&adev->lock);
+                    select_devices(adev, out->usecase);
+                    pthread_mutex_unlock(&adev->lock);
+                    out->stream_config_changed = false;
+                    out->is_iec61937_info_available = true;
+                }
+            }
+
+            if ((channels < (int)audio_channel_count_from_out_mask(out->channel_mask)) &&
+                (out->compr_config.codec->compr_passthr == PASSTHROUGH) &&
+                (out->is_iec61937_info_available == true)) {
+                    ALOGE("%s: ERROR: Unsupported channel config in passthrough mode", __func__);
+                    ret = -EINVAL;
+                    goto exit;
+            }
         }
     }
 
@@ -3944,6 +3981,11 @@
         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));
+
+        if (audio_extn_passthru_is_passthrough_stream(out)) {
+                ALOGE("%s: write error, ret = %ld", __func__, ret);
+                return ret;
+        }
     }
     return bytes;
 }
@@ -4459,6 +4501,7 @@
         pthread_mutex_lock(&adev->lock);
         in->standby = true;
         if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
+            do_stop = false;
             voice_extn_compress_voip_close_input_stream(stream);
             ALOGD("VOIP input entered standby");
         } else if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
@@ -4467,20 +4510,15 @@
         } else {
             if (audio_extn_cin_attached_usecase(in->usecase))
                 audio_extn_cin_stop_input_stream(in);
+        }
+
+        if (do_stop) {
             if (in->pcm) {
                 pcm_close(in->pcm);
                 in->pcm = NULL;
             }
             status = stop_input_stream(in);
         }
-        if (in->pcm) {
-            pcm_close(in->pcm);
-            in->pcm = NULL;
-        }
-
-        if (do_stop) {
-            status = stop_input_stream(in);
-        }
         pthread_mutex_unlock(&adev->lock);
     }
     pthread_mutex_unlock(&in->lock);
@@ -4958,6 +4996,7 @@
     int ret = 0;
     audio_format_t format;
     struct adsp_hdlr_stream_cfg hdlr_stream_cfg;
+    bool is_direct_passthough = false;
 
     *stream_out = NULL;
 
@@ -4998,7 +5037,7 @@
     out->a2dp_compress_mute = false;
     out->dynamic_pm_qos_enabled = 0;
 
-    if ((flags & AUDIO_OUTPUT_FLAG_BD10) &&
+    if ((flags & AUDIO_OUTPUT_FLAG_BD) &&
         (property_get_bool("audio.matrix.limiter.enable", false)))
         platform_set_device_params(out, DEVICE_PARAM_LIMITER_ID, 1);
 
@@ -5020,7 +5059,7 @@
     }
 
     /* Init use case and pcm_config */
-#ifndef COMPRESS_VOIP_ENABLED
+#ifndef COMPRES_ENABLED
     if (out->flags == (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_VOIP_RX) &&
         (out->sample_rate == 8000 || out->sample_rate == 16000 ||
          out->sample_rate == 32000 || out->sample_rate == 48000)) {
@@ -5033,7 +5072,7 @@
         out->config.rate = out->sample_rate;
 
 #else
-    if ((out->dev->mode == AUDIO_MODE_IN_COMMUNICATION || voice_extn_compress_voip_is_active(out->dev)) &&
+    } else if ((out->dev->mode == AUDIO_MODE_IN_COMMUNICATION || voice_extn_compress_voip_is_active(out->dev)) &&
                (out->flags == (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_VOIP_RX)) &&
                (voice_extn_compress_voip_is_config_supported(config))) {
         ret = voice_extn_compress_voip_open_output_stream(out);
@@ -5491,9 +5530,10 @@
         audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
                                              popcount(out->channel_mask), out->playback_started);
     /* setup a channel for client <--> adsp communication for stream events */
+    is_direct_passthough = audio_extn_passthru_is_direct_passthrough(out);
     if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) ||
             (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) ||
-            (audio_extn_ip_hdlr_intf_supported(config->format, audio_extn_passthru_is_direct_passthrough(out)))) {
+            (audio_extn_ip_hdlr_intf_supported(config->format, is_direct_passthough, false))) {
         hdlr_stream_cfg.pcm_device_id = platform_get_pcm_device_id(
                 out->usecase, PCM_PLAYBACK);
         hdlr_stream_cfg.flags = out->flags;
@@ -5505,8 +5545,8 @@
             out->adsp_hdlr_stream_handle = NULL;
         }
     }
-    if (audio_extn_ip_hdlr_intf_supported(config->format, audio_extn_passthru_is_direct_passthrough(out))) {
-        ret = audio_extn_ip_hdlr_intf_init(&out->ip_hdlr_handle, NULL, NULL);
+    if (audio_extn_ip_hdlr_intf_supported(config->format, is_direct_passthough, false)) {
+        ret = audio_extn_ip_hdlr_intf_init(&out->ip_hdlr_handle, NULL, NULL, adev, out->usecase);
         if (ret < 0) {
             ALOGE("%s: audio_extn_ip_hdlr_intf_init failed %d",__func__, ret);
             out->ip_hdlr_handle = NULL;
@@ -5545,7 +5585,7 @@
         out->adsp_hdlr_stream_handle = NULL;
     }
 
-    if (audio_extn_ip_hdlr_intf_supported(out->format, audio_extn_passthru_is_direct_passthrough(out)) && out->ip_hdlr_handle) {
+    if (out->ip_hdlr_handle) {
         audio_extn_ip_hdlr_intf_deinit(out->ip_hdlr_handle);
         out->ip_hdlr_handle = NULL;
     }
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 0a6d85b..f0b7077 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -239,6 +239,8 @@
     pthread_cond_t  cond;
     struct stream_config in_config;
     struct stream_config out_config;
+    struct stream_app_type_cfg out_app_type_cfg;
+    char profile[MAX_STREAM_PROFILE_STR_LEN];
     struct audio_device *dev;
     void *adsp_hdlr_stream_handle;
     void *ip_hdlr_handle;
@@ -321,6 +323,7 @@
 
     char pm_qos_mixer_path[MAX_MIXER_PATH_LEN];
     int dynamic_pm_qos_enabled;
+    bool stream_config_changed;
     mix_matrix_params_t pan_scale_params;
     mix_matrix_params_t downmix_params;
 };
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index fcc9ade..f8c0aba 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -3206,6 +3206,9 @@
         snd_device = voice_get_incall_rec_snd_device(usecase->in_snd_device);
     else if ((usecase->type == PCM_HFP_CALL) || (usecase->type == PCM_CAPTURE))
         snd_device = usecase->in_snd_device;
+    else if (usecase->type == TRANSCODE_LOOPBACK)
+        snd_device = usecase->out_snd_device;
+
     acdb_dev_id = acdb_device_table[platform_get_spkr_prot_snd_device(snd_device)];
 
     if (platform_split_snd_device(platform, snd_device, &num_devices,
@@ -5604,12 +5607,11 @@
                   __func__, DEFAULT_HDMI_OUT_CHANNELS);
             channels = DEFAULT_HDMI_OUT_CHANNELS;
         }
-
-        if ((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
+        if (((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
             (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC) ||
-            (usecase->stream.out->format == AUDIO_FORMAT_DOLBY_TRUEHD)) {
-            sample_rate = sample_rate * 4 ;
-
+            (usecase->stream.out->format == AUDIO_FORMAT_DOLBY_TRUEHD))
+            && (usecase->stream.out->compr_config.codec->compr_passthr == PASSTHROUGH)) {
+            sample_rate = sample_rate * 4;
             if (sample_rate > HDMI_PASSTHROUGH_MAX_SAMPLE_RATE)
                 sample_rate = HDMI_PASSTHROUGH_MAX_SAMPLE_RATE;
         }
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index f368d17..a29aa9d 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -2969,6 +2969,8 @@
         snd_device = voice_get_incall_rec_snd_device(usecase->in_snd_device);
     else if ((usecase->type == PCM_HFP_CALL) || (usecase->type == PCM_CAPTURE))
         snd_device = usecase->in_snd_device;
+    else if (usecase->type == TRANSCODE_LOOPBACK)
+        snd_device = usecase->out_snd_device;
 
     acdb_dev_id = acdb_device_table[platform_get_spkr_prot_snd_device(snd_device)];
     if (acdb_dev_id < 0) {
@@ -5474,10 +5476,10 @@
                   __func__, DEFAULT_HDMI_OUT_CHANNELS);
             channels = DEFAULT_HDMI_OUT_CHANNELS;
         }
-        if ((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
+        if (((usecase->stream.out->format == AUDIO_FORMAT_E_AC3) ||
             (usecase->stream.out->format == AUDIO_FORMAT_E_AC3_JOC) ||
-            (usecase->stream.out->format == AUDIO_FORMAT_DOLBY_TRUEHD)) {
-
+            (usecase->stream.out->format == AUDIO_FORMAT_DOLBY_TRUEHD))
+            && (usecase->stream.out->compr_config.codec->compr_passthr == PASSTHROUGH)) {
             sample_rate = sample_rate * 4;
             if (sample_rate > HDMI_PASSTHROUGH_MAX_SAMPLE_RATE)
                 sample_rate = HDMI_PASSTHROUGH_MAX_SAMPLE_RATE;
@@ -6070,12 +6072,7 @@
     int iter_i = 0;
     int iter_j = 0;
     int length = 0;
-    int pan_scale_data[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
-
-    if (sizeof(mm_params) > MAX_LENGTH_MIXER_CONTROL_IN_INT) {
-        ret = -EINVAL;
-        goto end;
-    }
+    int *pan_scale_data = NULL;
 
     snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
                           "Audio Stream %d Pan Scale Control", snd_id);
@@ -6088,6 +6085,11 @@
         ret = -EINVAL;
         goto end;
     }
+    pan_scale_data = (int* ) calloc(1, sizeof(mm_params));
+    if (!pan_scale_data) {
+        ret = -ENOMEM;
+        goto end;
+    }
     pan_scale_data[length++] = mm_params.num_output_channels;
     pan_scale_data[length++] = mm_params.num_input_channels;
 
@@ -6121,6 +6123,8 @@
 
     ret = mixer_ctl_set_array(ctl, pan_scale_data, length);
 end:
+    if (pan_scale_data)
+        free(pan_scale_data);
     return ret;
 }
 
@@ -6133,20 +6137,13 @@
     struct audio_device *adev = my_data->adev;
     struct mixer_ctl *ctl;
     char mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = {0};
-    int downmix_param_data[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
+    int *downmix_param_data = NULL;
     int ret = 0;
     int iter_i = 0;
     int iter_j = 0;
     int length = 0;
     int be_idx = 0;
 
-    if ((sizeof(mm_params) +
-         sizeof(be_idx)) >
-        MAX_LENGTH_MIXER_CONTROL_IN_INT) {
-        ret = -EINVAL;
-        goto end;
-    }
-
     snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
                           "Audio Device %d Downmix Control", snd_id);
     ALOGD("%s mixer_ctl_name:%s", __func__, mixer_ctl_name);
@@ -6158,8 +6155,13 @@
         ret = -EINVAL;
     }
 
+    downmix_param_data = (int* ) calloc(1, sizeof(mm_params) + sizeof(be_idx));
+    if (!downmix_param_data) {
+        ret = -ENOMEM;
+        goto end;
+    }
     be_idx = platform_get_snd_device_backend_index(snd_device);
-    downmix_param_data[length]   = be_idx;
+    downmix_param_data[length++] = be_idx;
     downmix_param_data[length++] = mm_params.num_output_channels;
     downmix_param_data[length++] = mm_params.num_input_channels;
 
@@ -6194,6 +6196,8 @@
 
     ret = mixer_ctl_set_array(ctl, downmix_param_data, length);
 end:
+    if (downmix_param_data)
+        free(downmix_param_data);
     return ret;
 }
 
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index a15c399..930bae0 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -298,7 +298,7 @@
 
 
 /* Used in calculating fragment size for pcm offload */
-#define PCM_OFFLOAD_BUFFER_DURATION 40 /* 40 millisecs */
+#define PCM_OFFLOAD_BUFFER_DURATION 80 /* 80 millisecs */
 
 /* MAX PCM fragment size cannot be increased  further due
  * to flinger's cblk size of 1mb,and it has to be a multiple of
diff --git a/qahw_api/Makefile.am b/qahw_api/Makefile.am
index f2c1060..ca1839a 100644
--- a/qahw_api/Makefile.am
+++ b/qahw_api/Makefile.am
@@ -17,8 +17,8 @@
 lib_LTLIBRARIES = libqahw.la
 libqahw_la_SOURCES = src/qahw.c \
                      src/qahw_effect.c
-libqahw_la_CFLAGS = $(AM_CFLAGS) -include stddef.h
+libqahw_la_CFLAGS = -Dstrlcpy=g_strlcpy $(GLIB_CFLAGS) -include glib.h $(AM_CFLAGS) -include stddef.h
 libqahw_la_CFLAGS += -D__unused=__attribute__\(\(__unused__\)\)
 libqahw_la_CFLAGS += -Wno-sign-compare -Werror
-libqahw_la_LIBADD = -llog -lcutils -lhardware
+libqahw_la_LIBADD = $(GLIB_LIBS) -llog -lcutils -lhardware
 libqahw_la_LDFLAGS = -module -shared -avoid-version
diff --git a/qahw_api/inc/qahw_defs.h b/qahw_api/inc/qahw_defs.h
index fa780bd..c13a1a4 100644
--- a/qahw_api/inc/qahw_defs.h
+++ b/qahw_api/inc/qahw_defs.h
@@ -180,6 +180,23 @@
 #define MAX_OUT_CHANNELS 8
 #define MAX_INP_CHANNELS 8
 
+#define QAHW_PCM_CHANNEL_FL    1  /* Front left channel.                           */
+#define QAHW_PCM_CHANNEL_FR    2  /* Front right channel.                          */
+#define QAHW_PCM_CHANNEL_FC    3  /* Front center channel.                         */
+#define QAHW_PCM_CHANNEL_LS    4  /* Left surround channel.                        */
+#define QAHW_PCM_CHANNEL_RS    5  /* Right surround channel.                       */
+#define QAHW_PCM_CHANNEL_LFE   6  /* Low frequency effect channel.                 */
+#define QAHW_PCM_CHANNEL_CS    7  /* Center surround channel; Rear center channel. */
+#define QAHW_PCM_CHANNEL_LB    8  /* Left back channel; Rear left channel.         */
+#define QAHW_PCM_CHANNEL_RB    9  /* Right back channel; Rear right channel.       */
+#define QAHW_PCM_CHANNEL_TS   10  /* Top surround channel.                         */
+#define QAHW_PCM_CHANNEL_CVH  11  /* Center vertical height channel.               */
+#define QAHW_PCM_CHANNEL_MS   12  /* Mono surround channel.                        */
+#define QAHW_PCM_CHANNEL_FLC  13  /* Front left of center.                         */
+#define QAHW_PCM_CHANNEL_FRC  14  /* Front right of center.                        */
+#define QAHW_PCM_CHANNEL_RLC  15  /* Rear left of center.                          */
+#define QAHW_PCM_CHANNEL_RRC  16  /* Rear right of center.                         */
+
 /* type of asynchronous write callback events. Mutually exclusive */
 typedef enum {
     QAHW_STREAM_CBK_EVENT_WRITE_READY, /* non blocking write completed */
diff --git a/qahw_api/test/Makefile.am b/qahw_api/test/Makefile.am
index d87962b..b4bbea7 100644
--- a/qahw_api/test/Makefile.am
+++ b/qahw_api/test/Makefile.am
@@ -6,9 +6,19 @@
 
 hal_play_test_SOURCES = qahw_playback_test.c \
                         qahw_effect_test.c
-hal_play_test_CPPFLAGS = $(PLAY_CPPFLAGS) $(PLAY_INCLUDES)
+
 hal_play_test_LDADD = -lutils ../libqahw.la
 
+if QAP
+AM_CFLAGS = -DQAP
+AM_CFLAGS += -I ${WORKSPACE}/audio/mm-audio/qap_wrapper/inc/
+hal_play_test_SOURCES += qap_wrapper_extn.c
+hal_play_test_LDADD += -lqap_wrapper
+endif
+
+hal_play_test_CPPFLAGS = $(PLAY_CPPFLAGS) $(PLAY_INCLUDES)
+hal_play_test_CFLAGS = $(AM_CFLAGS)
+hal_play_test_CFLAGS = -DLINUX_ENABLED
 
 bin_PROGRAMS += hal_rec_test
 
@@ -18,6 +28,7 @@
 hal_rec_test_SOURCES = qahw_multi_record_test.c
 hal_rec_test_CPPFLAGS = -Dstrlcat=g_strlcat $(GLIB_CFLAGS) -include glib.h
 hal_rec_test_CPPFLAGS += $(REC_CPPFLAGS) $(REC_INCLUDES)
+hal_play_test_CFLAGS += $(AM_CFLAGS)
 hal_rec_test_LDADD = -lutils ../libqahw.la $(GLIB_LIBS)
 
 bin_PROGRAMS += trans_loopback_test
diff --git a/qahw_api/test/qahw_playback_test.c b/qahw_api/test/qahw_playback_test.c
index c27f920..fb69d93 100644
--- a/qahw_api/test/qahw_playback_test.c
+++ b/qahw_api/test/qahw_playback_test.c
@@ -18,22 +18,7 @@
 
 /* Test app to play audio at the HAL layer */
 
-#include <getopt.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-#include <signal.h>
-#include <cutils/str_parms.h>
-#include <tinyalsa/asoundlib.h>
-#include "qahw_api.h"
-#include "qahw_defs.h"
-#include "qahw_effect_api.h"
-#include "qahw_effect_test.h"
+#include "qahw_playback_test.h"
 
 #define nullptr NULL
 
@@ -51,9 +36,9 @@
 #define KV_PAIR_MAX_LENGTH  1000
 
 #define FORMAT_PCM 1
-#define WAV_HEADER_LENGTH_MAX 46
+#define WAV_HEADER_LENGTH_MAX 128
 
-#define MAX_PLAYBACK_STREAMS   9
+#define MAX_PLAYBACK_STREAMS   105 //This value is changed to suppport 100 clips in playlist
 #define PRIMARY_STREAM_INDEX   0
 
 #define KVPAIRS_MAX 100
@@ -69,50 +54,10 @@
 #define DTSHD_CHUNK_STREAM_KEYWORD "STRMDATA"
 #define DTSHD_META_KEYWORD_SIZE 8 /*in bytes */
 
-static int get_wav_header_length (FILE* file_stream);
 static ssize_t get_bytes_to_read(FILE* file, int filetype);
 static void init_streams(void);
 int pthread_cancel(pthread_t thread);
 
-
-enum {
-    FILE_WAV = 1,
-    FILE_MP3,
-    FILE_AAC,
-    FILE_AAC_ADTS,
-    FILE_FLAC,
-    FILE_ALAC,
-    FILE_VORBIS,
-    FILE_WMA,
-    FILE_AC3,
-    FILE_AAC_LATM,
-    FILE_EAC3,
-    FILE_EAC3_JOC,
-    FILE_DTS,
-    FILE_MP2,
-    FILE_APTX,
-    FILE_TRUEHD,
-    FILE_IEC61937
-};
-
-typedef enum {
-    USB_MODE_DEVICE,
-    USB_MODE_HOST,
-    USB_MODE_NONE
-} usb_mode_type_t;
-
-typedef enum {
-    AAC_LC = 1,
-    AAC_HE_V1,
-    AAC_HE_V2
-} aac_format_type_t;
-
-typedef enum {
-    WMA = 1,
-    WMA_PRO,
-    WMA_LOSSLESS
-} wma_format_type_t;
-
 struct wav_header {
     uint32_t riff_id;
     uint32_t riff_sz;
@@ -129,18 +74,6 @@
     uint32_t data_sz;
 };
 
-struct audio_config_params {
-    qahw_module_handle_t *qahw_mod_handle;
-    audio_io_handle_t handle;
-    audio_devices_t input_device;
-    audio_config_t config;
-    audio_input_flags_t flags;
-    const char* kStreamName ;
-    audio_source_t kInputSource;
-    char *file_name;
-    volatile bool thread_exit;
-};
-
 struct proxy_data {
     struct audio_config_params acp;
     struct wav_header hdr;
@@ -162,42 +95,6 @@
     uint32_t config_mask;
 };
 
-typedef struct {
-    qahw_module_handle_t *qahw_in_hal_handle;
-    qahw_module_handle_t *qahw_out_hal_handle;
-    audio_io_handle_t handle;
-    char* filename;
-    FILE* file_stream;
-    int filetype;
-    int stream_index;
-    audio_devices_t output_device;
-    audio_devices_t input_device;
-    audio_config_t config;
-    audio_output_flags_t flags;
-    qahw_stream_handle_t* out_handle;
-    qahw_stream_handle_t* in_handle;
-    int channels;
-    aac_format_type_t aac_fmt_type;
-    wma_format_type_t wma_fmt_type;
-    char *kvpair_values;
-    bool flags_set;
-    usb_mode_type_t usb_mode;
-    int effect_index;
-    int effect_preset_strength;
-    bool drift_query;
-    bool drift_correction;
-    bool play_later;
-    char *device_url;
-    thread_func_t ethread_func;
-    thread_data_t *ethread_data;
-    cmd_data_t cmd_data;
-    pthread_cond_t write_cond;
-    pthread_mutex_t write_lock;
-    pthread_cond_t drain_cond;
-    pthread_mutex_t drain_lock;
-    bool interactive_strm;
-}stream_config;
-
 /* Lock for dual main usecase */
 pthread_cond_t dual_main_cond;
 pthread_mutex_t dual_main_lock;
@@ -211,13 +108,12 @@
 FILE * log_file = NULL;
 volatile bool stop_playback = false;
 const char *log_filename = NULL;
-float vol_level = 0.01;
 struct proxy_data proxy_params;
 pthread_t playback_thread[MAX_PLAYBACK_STREAMS];
 bool thread_active[MAX_PLAYBACK_STREAMS] = { false };
+bool qap_wrapper_session_active = false;
 
 stream_config stream_param[MAX_PLAYBACK_STREAMS];
-bool kpi_mode;
 bool event_trigger;
 
 /*
@@ -262,11 +158,11 @@
                    "music_offload_wma_format_tag=%d;"
 
 #ifndef AUDIO_OUTPUT_FLAG_ASSOCIATED
-#define AUDIO_OUTPUT_FLAG_ASSOCIATED 0x8000
+#define AUDIO_OUTPUT_FLAG_ASSOCIATED 0x10000000
 #endif
 
 #ifndef AUDIO_OUTPUT_FLAG_INTERACTIVE
-#define AUDIO_OUTPUT_FLAG_INTERACTIVE 0x40000
+#define AUDIO_OUTPUT_FLAG_INTERACTIVE 0x80000000
 #endif
 
 static bool request_wake_lock(bool wakelock_acquired, bool enable)
@@ -667,7 +563,7 @@
     size_t bytes_wanted = 0;
     size_t write_length = 0;
     size_t bytes_remaining = 0;
-    size_t bytes_written = 0;
+    ssize_t bytes_written = 0;
 
     size_t bytes_read = 0;
     char  *data_ptr = NULL;
@@ -1000,6 +896,7 @@
     case AAC_LC:
     case AAC_HE_V1:
     case AAC_HE_V2:
+    case AAC_LOAS:
         valid_format_type = true;
         break;
     default:
@@ -1067,7 +964,7 @@
     return aac_format;
 }
 
-static void get_file_format(stream_config *stream_info)
+void get_file_format(stream_config *stream_info)
 {
     int rc = 0;
 
@@ -1171,6 +1068,7 @@
            fprintf(log_file, "Does not support given filetype\n");
            fprintf(stderr, "Does not support given filetype\n");
            usage();
+           hal_test_qap_usage();
            return;
     }
     stream_info->config.sample_rate = stream_info->config.offload_info.sample_rate;
@@ -1608,10 +1506,7 @@
     printf(" -m  --mode                                - usb operating mode(Device Mode is default)\n");
     printf("                                             0:Device Mode(host drives the stream and its params and so no need to give params as input)\n");
     printf("                                             1:Host Mode(user can give stream and stream params via a stream(SD card file) or setup loopback with given params\n");
-    printf(" -O  --output-ch-map                       - output channel map");
-    printf(" -I  --input-ch-map                        - input channel map");
-    printf(" -M  --mixer-coeffs                        - mixer coefficient matrix");
-    printf(" -i  --intr-strm                           - interactive stream indicator");
+    printf(" -i  --intr-strm                           - interactive stream indicator\n");
     printf(" -C  --Device Config                       - Device Configuration params\n");
     printf("                                             Params should be in the order defined in struct qahw_device_cfg_param. Order is: \n");
     printf("                                             <sample_rate>, <channels>, <bit_width>, <format>, <device>, <channel_map[channels]>, <channel_allocation> \n");
@@ -1681,9 +1576,11 @@
     printf("                                          ->full duplex, setup both primary to usb and usb to primary loopbacks\n");
     printf("                                          ->Note:-P separates the steam params for both the loopbacks\n");
     printf("                                          ->Note:all the USB device commmands(above) should be accompanied with the host side commands\n\n");
+    printf("hal_play_test -f interactive_audio.wav -d 2 -l out.txt -k \"mixer_ctrl=pan_scale;c=1;o=6;I=fc;O=fl,fr,fc,lfe,bl,br;M=0.5,0.5,0,0,0,0\" -i 1\n");
+    printf("                                          ->kv_pair for downmix or pan_scale should folow the above sequence, one can pass downmix & pan_scale params/coeff matrices. For each control params should be sent separately \n");
 }
 
-static int get_wav_header_length (FILE* file_stream)
+int get_wav_header_length (FILE* file_stream)
 {
     int subchunk_size = 0, wav_header_len = 0;
 
@@ -1800,7 +1697,7 @@
      return file_read_size;
 }
 
-static qahw_module_handle_t * load_hal(audio_devices_t dev) {
+qahw_module_handle_t * load_hal(audio_devices_t dev) {
     qahw_module_handle_t *hal = NULL;
 
     if ((AUDIO_DEVICE_IN_USB_DEVICE == dev) ||
@@ -1844,7 +1741,7 @@
  * this function unloads all the loaded hal modules so this should be called
  * after all the stream playback are concluded.
  */
-static int unload_hals() {
+int unload_hals() {
 
     if (usb_hal_handle) {
         fprintf(log_file,"\nUnLoading usb HAL\n");
@@ -1878,41 +1775,37 @@
     if (NULL == name)
         return channel_type;
     else if (strncmp(name, "fl", 2) == 0)
-        channel_type = AUDIO_CHANNEL_OUT_FRONT_LEFT;
+        channel_type = QAHW_PCM_CHANNEL_FL;
     else if (strncmp(name, "fr", 2) == 0)
-        channel_type = AUDIO_CHANNEL_OUT_FRONT_RIGHT;
+        channel_type = QAHW_PCM_CHANNEL_FR;
     else if (strncmp(name, "fc", 2) == 0)
-        channel_type = AUDIO_CHANNEL_OUT_FRONT_CENTER;
+        channel_type = QAHW_PCM_CHANNEL_FC;
     else if (strncmp(name, "lfe", 2) == 0)
-        channel_type = AUDIO_CHANNEL_OUT_LOW_FREQUENCY;
+        channel_type = QAHW_PCM_CHANNEL_LFE;
     else if (strncmp(name, "bl", 2) == 0)
-        channel_type = AUDIO_CHANNEL_OUT_BACK_LEFT;
+        channel_type = QAHW_PCM_CHANNEL_LB;
     else if (strncmp(name, "br", 2) == 0)
-        channel_type = AUDIO_CHANNEL_OUT_BACK_RIGHT;
+        channel_type = QAHW_PCM_CHANNEL_RB;
     else if (strncmp(name, "flc", 3) == 0)
-        channel_type = AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER;
+        channel_type = QAHW_PCM_CHANNEL_FLC;
     else if (strncmp(name, "frc", 3) == 0)
-        channel_type = AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER;
-    else if (strncmp(name, "bc", 2) == 0)
-        channel_type = AUDIO_CHANNEL_OUT_BACK_CENTER;
-    else if (strncmp(name, "sl", 2) == 0)
-        channel_type = AUDIO_CHANNEL_OUT_SIDE_LEFT;
-    else if (strncmp(name, "sr", 2) == 0)
-        channel_type = AUDIO_CHANNEL_OUT_SIDE_RIGHT;
-    else if (strncmp(name, "tc", 2) == 0)
-        channel_type = AUDIO_CHANNEL_OUT_TOP_CENTER;
-    else if (strncmp(name, "tfl", 3) == 0)
-        channel_type = AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT;
-    else if (strncmp(name, "tfc", 3) == 0)
-        channel_type = AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER;
-    else if (strncmp(name, "tfr", 3) == 0)
-        channel_type = AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT;
-    else if (strncmp(name, "tbl", 3) == 0)
-        channel_type = AUDIO_CHANNEL_OUT_TOP_BACK_LEFT;
-    else if (strncmp(name, "tbc", 3) == 0)
-        channel_type = AUDIO_CHANNEL_OUT_TOP_BACK_CENTER;
-    else if (strncmp(name, "tbr", 3) == 0)
-        channel_type = AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT;
+        channel_type = QAHW_PCM_CHANNEL_FRC;
+    else if (strncmp(name, "cs", 2) == 0)
+        channel_type = QAHW_PCM_CHANNEL_CS;
+    else if (strncmp(name, "ls", 2) == 0)
+        channel_type = QAHW_PCM_CHANNEL_LS;
+    else if (strncmp(name, "rs", 2) == 0)
+        channel_type = QAHW_PCM_CHANNEL_RS;
+    else if (strncmp(name, "ts", 2) == 0)
+        channel_type = QAHW_PCM_CHANNEL_TS;
+    else if (strncmp(name, "cvh", 3) == 0)
+        channel_type = QAHW_PCM_CHANNEL_CVH;
+    else if (strncmp(name, "ms", 3) == 0)
+        channel_type = QAHW_PCM_CHANNEL_MS;
+    else if (strncmp(name, "rlc", 3) == 0)
+        channel_type = QAHW_PCM_CHANNEL_RLC;
+    else if (strncmp(name, "rrc", 3) == 0)
+        channel_type = QAHW_PCM_CHANNEL_RRC;
 
     return channel_type;
 }
@@ -1994,18 +1887,60 @@
         token_string = NULL;
     } else
         return -EINVAL;
+}
+
+#ifdef QAP
+int start_playback_through_qap(char * kvp_string, int num_of_streams,  qahw_module_handle_t *hal_handle) {
+    stream_config *stream = NULL;
+    int rc = 0;
+    int i;
+
+    fprintf(stdout, "kvp_string %s and num_of_streams %d\n", kvp_string, num_of_streams);
+    for (i = 0; i < num_of_streams; i++) {
+        stream = &stream_param[i];
+        if (stream->filename) {
+            if ((stream->file_stream = fopen(stream->filename, "r"))== NULL) {
+                fprintf(log_file, "Cannot open audio file %s\n", stream->filename);
+                fprintf(stderr, "Cannot open audio file %s\n", stream->filename);
+                return -EINVAL;
+            }
+        }
+        get_file_format(stream);
+        fprintf(stdout, "Playing from:%s\n", stream->filename);
+        qap_module_handle_t qap_module_handle = NULL;
+        if (!qap_wrapper_session_active) {
+            rc = qap_wrapper_session_open(kvp_string, stream, num_of_streams, hal_handle);
+            if (rc != 0) {
+                fprintf(stderr, "Session Open failed\n");
+                return -EINVAL;
+            }
+            qap_wrapper_session_active = true;
+        }
+
+        if (qap_wrapper_session_active) {
+            stream->qap_module_handle = qap_wrapper_stream_open(stream);
+            if (stream->qap_module_handle == NULL) {
+                fprintf(stderr, "QAP Stream open Failed\n");
+            } else {
+                fprintf(stdout, "QAP module handle is %p and file name is %s\n", stream->qap_module_handle, stream->filename);
+                rc = pthread_create(&playback_thread[i], NULL, qap_wrapper_start_stream, (void *)&stream_param[i]);
+                if (rc) {
+                    fprintf(stderr, "stream %d: failed to create thread\n", stream->stream_index);
+                    return -EINVAL;
+                }
+                thread_active[i] = true;
+            }
+        }
+    }
     return 0;
 }
+#endif
 
 int main(int argc, char* argv[]) {
     char *ba = NULL;
-    char *temp_input_channel_map = NULL;
-    char *temp_output_channel_map = NULL;
-    char *temp_mixer_coeffs = NULL;
     qahw_param_payload payload;
     qahw_param_id param_id;
     struct qahw_aptx_dec_param aptx_params;
-    qahw_mix_matrix_params_t mm_params;
     int rc = 0;
     int i = 0;
     int iter_i = 0;
@@ -2014,7 +1949,11 @@
 
     kpi_mode = false;
     char mixer_ctrl_name[64] = {0};
-    int mixer_ctrl_type = 0;
+    char input_ch[64] = {0};
+    char output_ch[64] = {0};
+    char input_ch_map[64] = {0};
+    char output_ch_map[64] = {0};
+    char mixer_coeff[64] = {0};
     event_trigger = false;
     bool wakelock_acquired = false;
 
@@ -2028,6 +1967,7 @@
     init_streams();
 
     int num_of_streams = 1;
+    char kvp_string[KV_PAIR_MAX_LENGTH] = {0};
 
     struct option long_options[] = {
         /* These options set a flag. */
@@ -2038,6 +1978,7 @@
         {"channels",      required_argument,    0, 'c'},
         {"bitwidth",      required_argument,    0, 'b'},
         {"volume",        required_argument,    0, 'v'},
+        {"enable-dump",   required_argument,    0, 'V'},
         {"log-file",      required_argument,    0, 'l'},
         {"dump-file",     required_argument,    0, 'D'},
         {"file-type",     required_argument,    0, 't'},
@@ -2056,13 +1997,12 @@
         {"mode",          required_argument,    0, 'm'},
         {"effect-preset",   required_argument,    0, 'p'},
         {"effect-strength", required_argument,    0, 'S'},
-        {"device-config", required_argument,    0, 'C'},
-        {"help",          no_argument,          0, 'h'},
-        {"output-ch-map", required_argument,    0, 'O'},
-        {"input-ch-map",  required_argument,    0, 'I'},
-        {"mixer-coeffs",  required_argument,    0, 'M'},
-        {"num-out-ch",    required_argument,    0, 'o'},
+        {"render-format", required_argument,    0, 'x'},
+        {"timestamp-file", required_argument,    0, 'y'},
         {"intr-strm",    required_argument,    0, 'i'},
+        {"device-config", required_argument,    0, 'C'},
+        {"play-list",    required_argument,    0, 'g'},
+        {"help",          no_argument,          0, 'h'},
         {0, 0, 0, 0}
     };
 
@@ -2085,7 +2025,7 @@
 
     while ((opt = getopt_long(argc,
                               argv,
-                              "-f:r:c:b:d:s:v:l:t:a:w:k:PD:KF:Ee:A:u:m:S:C:p:qQhI:O:M:o:i:",
+                              "-f:r:c:b:d:s:v:V:l:t:a:w:k:PD:KF:Ee:A:u:m:S:C:p::x:y:qQh:i:h:g:",
                               long_options,
                               &option_index)) != -1) {
 
@@ -2102,7 +2042,6 @@
         case 'c':
             stream_param[i].channels = atoi(optarg);
             stream_param[i].config.channel_mask = audio_channel_out_mask_from_count(atoi(optarg));
-            mm_params.num_input_channels = stream_param[i].channels;
             break;
         case 'b':
             stream_param[i].config.offload_info.bit_width = atoi(optarg);
@@ -2116,6 +2055,9 @@
         case 'v':
             vol_level = atof(optarg);
             break;
+        case 'V':
+            enable_dump = atof(optarg);
+            break;
         case 'l':
             log_filename = optarg;
             if (strcasecmp(log_filename, "stdout") &&
@@ -2141,12 +2083,77 @@
             break;
         case 'k':
             get_kvpairs_string(optarg, "mixer_ctrl", mixer_ctrl_name);
+            printf("%s, mixer_ctrl_name- %s\n", __func__, mixer_ctrl_name);
             if(strncmp(mixer_ctrl_name, "downmix", 7) == 0) {
-                mixer_ctrl_type = QAHW_PARAM_CH_MIX_MATRIX_PARAMS;
+                stream_param[i].mix_ctrl = QAHW_PARAM_CH_MIX_MATRIX_PARAMS;
+
+                get_kvpairs_string(optarg, "c", input_ch);
+                stream_param[i].mm_params_downmix.num_input_channels = atoi(input_ch);
+                get_kvpairs_string(optarg, "o", output_ch);
+                stream_param[i].mm_params_downmix.num_output_channels = atoi(output_ch);
+                get_kvpairs_string(optarg, "I", input_ch_map);
+                get_kvpairs_string(optarg, "O", output_ch_map);
+                get_kvpairs_string(optarg, "M", mixer_coeff);
+
+                extract_channel_mapping(stream_param[i].mm_params_downmix.input_channel_map, input_ch_map);
+                stream_param[i].mm_params_downmix.has_input_channel_map = 1;
+                fprintf(log_file, "\ndownmix Input channel mapping: ");
+                for (iter_i= 0; iter_i < stream_param[i].mm_params_downmix.num_input_channels; iter_i++) {
+                    fprintf(log_file, "0x%x, ", stream_param[i].mm_params_downmix.input_channel_map[iter_i]);
+                }
+
+                extract_channel_mapping(stream_param[i].mm_params_downmix.output_channel_map, output_ch_map);
+                stream_param[i].mm_params_downmix.has_output_channel_map = 1;
+                fprintf(log_file, "\ndownmix Output channel mapping: ");
+                for (iter_i = 0; iter_i < stream_param[i].mm_params_downmix.num_output_channels; iter_i++)
+                    fprintf(log_file, "0x%x, ", stream_param[i].mm_params_downmix.output_channel_map[iter_i]);
+
+
+                extract_mixer_coeffs(&stream_param[i].mm_params_downmix, mixer_coeff);
+                stream_param[i].mm_params_downmix.has_mixer_coeffs = 1;
+                fprintf(log_file, "\ndownmix mixer coeffs:\n");
+                for (iter_i = 0; iter_i < stream_param[i].mm_params_downmix.num_output_channels; iter_i++){
+                    for (iter_j = 0; iter_j < stream_param[i].mm_params_downmix.num_input_channels; iter_j++){
+                        fprintf(log_file, "%.2f ",stream_param[i].mm_params_downmix.mixer_coeffs[iter_i][iter_j]);
+                    }
+                    fprintf(log_file, "\n");
+                }
+
             } else if(strncmp(mixer_ctrl_name, "pan_scale", 9) == 0) {
-                mixer_ctrl_type = QAHW_PARAM_OUT_MIX_MATRIX_PARAMS;
+                stream_param[i].pan_scale_ctrl = QAHW_PARAM_OUT_MIX_MATRIX_PARAMS;
+
+                get_kvpairs_string(optarg, "c", input_ch);
+                stream_param[i].mm_params_pan_scale.num_input_channels = atoi(input_ch);
+                get_kvpairs_string(optarg, "o", output_ch);
+                stream_param[i].mm_params_pan_scale.num_output_channels = atoi(output_ch);
+                get_kvpairs_string(optarg, "I", input_ch_map);
+                get_kvpairs_string(optarg, "O", output_ch_map);
+                get_kvpairs_string(optarg, "M", mixer_coeff);
+
+                extract_channel_mapping(stream_param[i].mm_params_pan_scale.input_channel_map, input_ch_map);
+                stream_param[i].mm_params_pan_scale.has_input_channel_map = 1;
+                fprintf(log_file, "\n pan_sclae Input channel mapping: ");
+                for (iter_i= 0; iter_i < stream_param[i].mm_params_pan_scale.num_input_channels; iter_i++) {
+                    fprintf(log_file, "0x%x, ", stream_param[i].mm_params_pan_scale.input_channel_map[iter_i]);
+                }
+
+                extract_channel_mapping(stream_param[i].mm_params_pan_scale.output_channel_map, output_ch_map);
+                stream_param[i].mm_params_pan_scale.has_output_channel_map = 1;
+                fprintf(log_file, "\n pan_scale Output channel mapping: ");
+                for (iter_i = 0; iter_i < stream_param[i].mm_params_pan_scale.num_output_channels; iter_i++)
+                    fprintf(log_file, "0x%x, ", stream_param[i].mm_params_pan_scale.output_channel_map[iter_i]);
+
+                extract_mixer_coeffs(&stream_param[i].mm_params_pan_scale, mixer_coeff);
+                stream_param[i].mm_params_pan_scale.has_mixer_coeffs = 1;
+                fprintf(log_file, "\n pan_scale mixer coeffs:\n");
+                for (iter_i = 0; iter_i < stream_param[i].mm_params_pan_scale.num_output_channels; iter_i++){
+                    for (iter_j = 0; iter_j < stream_param[i].mm_params_pan_scale.num_input_channels; iter_j++){
+                        fprintf(log_file, "%.2f ",stream_param[i].mm_params_pan_scale.mixer_coeffs[iter_i][iter_j]);
+                    }
+                    fprintf(log_file, "\n");
+                }
+
             } else {
-                mixer_ctrl_type = 0;
                 stream_param[i].kvpair_values = optarg;
             }
             break;
@@ -2209,17 +2216,12 @@
         case 'm':
             stream_param[i].usb_mode = atoi(optarg);
             break;
-        case 'O':
-            temp_output_channel_map = strdup(optarg);
+        case 'x':
+            render_format = atoi(optarg);
             break;
-        case 'I':
-            temp_input_channel_map = strdup(optarg);
+        case 'y':
+            stream_param[i].timestamp_filename = optarg;
             break;
-        case 'M':
-            temp_mixer_coeffs = strdup(optarg);
-            break;
-        case 'o':
-            mm_params.num_output_channels = atoi(optarg);
         case 'C':
             fprintf(log_file, " In Device config \n");
             fprintf(stderr, " In Device config \n");
@@ -2281,57 +2283,17 @@
                  fprintf(stderr, " Device config :::: channel_allocation - %d \n", device_cfg_params.channel_allocation);
             }
             break;
+        case 'g':
+            break;
         case 'h':
             usage();
+            hal_test_qap_usage();
             return 0;
             break;
 
         }
     }
 
-    /*
-     * Process Input channel map's input
-     */
-    if (NULL != temp_input_channel_map) {
-        extract_channel_mapping(mm_params.input_channel_map, temp_input_channel_map);
-        mm_params.has_input_channel_map = 1;
-        fprintf(log_file, "\nInput channel mapping: ");
-        for (iter_i= 0; iter_i < mm_params.num_input_channels; iter_i++) {
-            fprintf(log_file, "0x%x, ", mm_params.input_channel_map[iter_i]);
-        }
-        free(temp_input_channel_map);
-        temp_input_channel_map = NULL;
-    }
-
-    /*
-     * Process Output channel map's input
-     */
-    if (NULL != temp_output_channel_map) {
-        extract_channel_mapping(mm_params.output_channel_map, temp_output_channel_map);
-        mm_params.has_output_channel_map = 1;
-        fprintf(log_file, "\nOutput channel mapping: ");
-        for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++)
-            fprintf(log_file, "0x%x, ", mm_params.output_channel_map[iter_i]);
-
-        free(temp_output_channel_map);
-        temp_output_channel_map = NULL;
-    }
-
-    /*
-     * Process mixer-coeffs input
-     */
-    if (NULL != temp_mixer_coeffs) {
-        extract_mixer_coeffs(&mm_params, temp_mixer_coeffs);
-        mm_params.has_mixer_coeffs = 1;
-        fprintf(log_file, "\nmixer coeffs:\n");
-        for (iter_i = 0; iter_i < mm_params.num_output_channels; iter_i++){
-            for (iter_j = 0; iter_j < mm_params.num_input_channels; iter_j++){
-                fprintf(log_file, "%.2f ",mm_params.mixer_coeffs[iter_i][iter_j]);
-            }
-            fprintf(log_file, "\n");
-        }
-    }
-
     wakelock_acquired = request_wake_lock(wakelock_acquired, true);
     num_of_streams = i+1;
     /* Caution: Below ADL log shouldnt be altered without notifying automation APT since it used
@@ -2373,20 +2335,59 @@
 
     }
 
+    if (is_qap_session_active(argc, argv, kvp_string)) {
+        char *file_name = NULL;
+        char *file_name_tmp = NULL;
+        char *cmd_kvp_str[100] = {NULL};
+        char *play_list_kvp_str[100] = {NULL};
+        int i = 0, j = 0;
+        qahw_module_handle_t *qap_out_hal_handle = NULL;
+
+        stream = &stream_param[i];
+        qap_out_hal_handle = load_hal(stream->output_device);
+        if (qap_out_hal_handle == NULL) {
+            fprintf(stderr, "Failed log load HAL\n");
+            goto exit;
+        }
+
+        file_name = (char*) check_for_playlist(kvp_string);
+        fprintf(stderr, "%s file_name is %s \n", __FUNCTION__, file_name);
+        if (file_name != NULL) {
+            FILE *fp = fopen(file_name, "r+");
+            if (fp != NULL) {
+                get_play_list(fp, &stream_param, &num_of_streams, cmd_kvp_str);
+                for (j = 0; j < num_of_streams; j++) {
+                     play_list_kvp_str[j] = strdup(cmd_kvp_str[j]);
+                }
+                rc = start_playback_through_qap_playlist(play_list_kvp_str, num_of_streams, kvp_string, stream_param, qap_wrapper_session_active, qap_out_hal_handle);
+                if (rc != 0) {
+                    fprintf(stderr, "QAP playback failed\n");
+                }
+            } else {
+                fprintf(stderr, "%s file open failed\nnd errno is %d", __FUNCTION__, errno);
+            }
+        } else {
+            rc = start_playback_through_qap(kvp_string, num_of_streams, qap_out_hal_handle);
+            if (rc != 0) {
+                fprintf(stderr, "QAP playback failed\n");
+            }
+        }
+        goto exit;
+    }
     for (i = 0; i < num_of_streams; i++) {
         stream = &stream_param[i];
 
         if ((kpi_mode == false) &&
             (AUDIO_DEVICE_NONE == stream->input_device)){
-            if (stream_param[PRIMARY_STREAM_INDEX].filename == nullptr) {
-                fprintf(log_file, "Primary file name is must for non kpi-mode\n");
-                fprintf(stderr, "Primary file name is must for non kpi-mode\n");
-                goto exit;
-            }
+                if (stream_param[PRIMARY_STREAM_INDEX].filename == nullptr) {
+                    fprintf(log_file, "Primary file name is must for non kpi-mode\n");
+                    fprintf(stderr, "Primary file name is must for non kpi-mode\n");
+                    goto exit;
+                }
         }
 
         if (stream->output_device != AUDIO_DEVICE_NONE)
-            if ((stream->qahw_out_hal_handle = load_hal(stream->output_device)) <= 0)
+             if ((stream->qahw_out_hal_handle = load_hal(stream->output_device)) <= 0)
                 goto exit;
 
         if (stream->input_device != AUDIO_DEVICE_NONE)
@@ -2397,8 +2398,8 @@
             (AUDIO_DEVICE_NONE != stream->input_device))
             /*
              * hal loopback at what params we need to probably detect.
-             */
-             if(detect_stream_params(stream) < 0)
+            */
+            if(detect_stream_params(stream) < 0)
                 goto exit;
 
         if (stream->filename) {
@@ -2508,29 +2509,33 @@
 
         thread_active[i] = true;
         usleep(500000); //Wait until stream is created
-        if(mixer_ctrl_type == QAHW_PARAM_OUT_MIX_MATRIX_PARAMS) {
-            payload = (qahw_param_payload) mm_params;
+        if(stream_param[i].pan_scale_ctrl == QAHW_PARAM_OUT_MIX_MATRIX_PARAMS) {
+            payload = (qahw_param_payload) stream_param[i].mm_params_pan_scale;
             param_id = QAHW_PARAM_OUT_MIX_MATRIX_PARAMS;
             rc = qahw_out_set_param_data(stream->out_handle, param_id, &payload);
             if (rc != 0) {
                 fprintf(log_file, "QAHW_PARAM_OUT_MIX_MATRIX_PARAMS could not be sent!\n");
             }
         }
-        if(mixer_ctrl_type == QAHW_PARAM_CH_MIX_MATRIX_PARAMS) {
-            payload = (qahw_param_payload) mm_params;
+        if(stream_param[i].mix_ctrl == QAHW_PARAM_CH_MIX_MATRIX_PARAMS) {
+            payload = (qahw_param_payload) stream_param[i].mm_params_downmix;
             param_id = QAHW_PARAM_CH_MIX_MATRIX_PARAMS;
             rc = qahw_out_set_param_data(stream->out_handle, param_id, &payload);
             if (rc != 0) {
                 fprintf(log_file, "QAHW_PARAM_CH_MIX_MATRIX_PARAMS could not be sent!\n");
             }
         }
+
     }
 
 exit:
-
     for (i=0; i<MAX_PLAYBACK_STREAMS; i++) {
         if(thread_active[i])
-            pthread_join(playback_thread[i], NULL);
+           pthread_join(playback_thread[i], NULL);
+    }
+
+    if(qap_wrapper_session_active) {
+        qap_wrapper_session_close();
     }
 
     /*
diff --git a/qahw_api/test/qahw_playback_test.h b/qahw_api/test/qahw_playback_test.h
new file mode 100644
index 0000000..1f524b9
--- /dev/null
+++ b/qahw_api/test/qahw_playback_test.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2015 The Android Open Source Project *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef QAHW_PLAYBACK_TEST_H
+#define QAHW_PLAYBACK_TEST_H
+
+#include <getopt.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <signal.h>
+#include <cutils/str_parms.h>
+#include <tinyalsa/asoundlib.h>
+#include "qahw_api.h"
+#include "qahw_defs.h"
+#include "qahw_effect_api.h"
+#include "qahw_effect_test.h"
+
+#define MAX_STR_LEN 256
+typedef void* qap_module_handle_t;
+bool kpi_mode;
+bool enable_dump;
+float vol_level;
+uint8_t render_format;
+
+
+enum {
+    FILE_WAV = 1,
+    FILE_MP3,
+    FILE_AAC,
+    FILE_AAC_ADTS,
+    FILE_FLAC,
+    FILE_ALAC,
+    FILE_VORBIS,
+    FILE_WMA,
+    FILE_AC3,
+    FILE_AAC_LATM,
+    FILE_EAC3,
+    FILE_EAC3_JOC,
+    FILE_DTS,
+    FILE_MP2,
+    FILE_APTX,
+    FILE_TRUEHD,
+    FILE_IEC61937
+};
+
+typedef enum {
+    USB_MODE_DEVICE,
+    USB_MODE_HOST,
+    USB_MODE_NONE
+} usb_mode_type_t;
+
+typedef enum {
+    AAC_LC = 1,
+    AAC_HE_V1,
+    AAC_HE_V2,
+    AAC_LOAS
+} aac_format_type_t;
+
+typedef enum {
+    WMA = 1,
+    WMA_PRO,
+    WMA_LOSSLESS
+} wma_format_type_t;
+
+struct audio_config_params {
+    qahw_module_handle_t *qahw_mod_handle;
+    audio_io_handle_t handle;
+    audio_devices_t input_device;
+    audio_config_t config;
+    audio_input_flags_t flags;
+    const char* kStreamName ;
+    audio_source_t kInputSource;
+    char *file_name;
+    volatile bool thread_exit;
+};
+
+typedef struct {
+    qahw_module_handle_t *qahw_in_hal_handle;
+    qahw_module_handle_t *qahw_out_hal_handle;
+    audio_io_handle_t handle;
+    char* filename;
+    FILE* file_stream;
+    char* timestamp_filename;
+    FILE* timestamp_file_ptr;
+    FILE* framesize_file_ptr;
+    int filetype;
+    int stream_index;
+    audio_devices_t output_device;
+    audio_devices_t input_device;
+    audio_config_t config;
+    audio_output_flags_t flags;
+    qahw_stream_handle_t* out_handle;
+    qahw_stream_handle_t* in_handle;
+    int channels;
+    aac_format_type_t aac_fmt_type;
+    wma_format_type_t wma_fmt_type;
+    char *kvpair_values;
+    bool flags_set;
+    usb_mode_type_t usb_mode;
+    int effect_index;
+    int effect_preset_strength;
+    bool drift_query;
+    bool drift_correction;
+    bool play_later;
+    char *device_url;
+    thread_func_t ethread_func;
+    thread_data_t *ethread_data;
+    cmd_data_t cmd_data;
+    int bytes_to_read;
+    qap_module_handle_t qap_module_handle;
+    bool sec_input;
+    bool system_input;
+    pthread_cond_t write_cond;
+    pthread_mutex_t write_lock;
+    pthread_cond_t drain_cond;
+    pthread_mutex_t drain_lock;
+    bool interactive_strm;
+    qahw_mix_matrix_params_t mm_params_pan_scale;
+    qahw_mix_matrix_params_t mm_params_downmix;
+    int mix_ctrl;
+    int pan_scale_ctrl;
+}stream_config;
+
+
+qahw_module_handle_t * load_hal(audio_devices_t dev);
+int unload_hals();
+int get_wav_header_length (FILE* file_stream);
+
+#ifndef QAP
+#define hal_test_qap_usage()                                             (0)
+#define qap_wrapper_get_single_kvp(key, kv_pairs, status)                (0)
+#define qap_wrapper_session_open(kv_pairs, stream_data, num_of_streams,\
+                              qap_out_hal_handle_t)                      (0)
+#define qap_wrapper_session_close()                                      (0)
+#define qap_wrapper_stream_open(stream_data)                             (0)
+#define qap_wrapper_get_cmd_string_from_arg_array(argc, argv, status)    (0)
+#define qap_wrapper_start_stream (stream_data)                           (0)
+#define is_qap_session_active(argc, argv, kvp_string)                    (0)
+#define get_play_list(fp, stream_param, num_of_streams, kvp_str)         (0)
+#define check_for_playlist(kvp_string)                                   (0)
+#define start_playback_through_qap(kvp_string, num_of_streams,\
+                                         qap_out_hal_handle_t)           (0)
+#define start_playback_through_qap_playlist(cmd_kvp_str, num_of_streams,\
+                   kvp_string, stream_param, qap_wrapper_session_active,\
+                   qap_out_hal_handle_t)                                 (0)
+#else
+void hal_test_qap_usage();
+char * qap_wrapper_get_single_kvp(const char *key, const char *kv_pairs, int *status);
+int qap_wrapper_session_open(char *kv_pairs, void* stream_data, int num_of_streams,\
+                              qahw_module_handle_t *qap_out_hal_handle_t);
+int qap_wrapper_session_close();
+qap_module_handle_t qap_wrapper_stream_open(void* stream_data);
+char * qap_wrapper_get_cmd_string_from_arg_array(int argc, char * argv[], int *status);
+void *qap_wrapper_start_stream (void* stream_data);
+void get_file_format(stream_config *stream_info);
+bool is_qap_session_active(int argc, char* argv[], char *kvp_string);
+void get_play_list(FILE *fp, stream_config (*stream_param)[], int *num_of_streams, char *kvp_str[]);
+char* check_for_playlist(char *kvp_string);
+int start_playback_through_qap(char * kvp_string, int num_of_streams,\
+                                qahw_module_handle_t *qap_out_hal_handle_t);
+int start_playback_through_qap_playlist(char *cmd_kvp_str[], int num_of_streams,\
+    char *kvp_string, stream_config stream_param[], bool qap_wrapper_session_active,\
+    qahw_module_handle_t *qap_out_hal_handle_t);
+#endif
+#endif /* QAHW_PLAYBACK_TEST_H */
diff --git a/qahw_api/test/qap_wrapper_extn.c b/qahw_api/test/qap_wrapper_extn.c
new file mode 100644
index 0000000..5c76d40
--- /dev/null
+++ b/qahw_api/test/qap_wrapper_extn.c
@@ -0,0 +1,1659 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2015 The Android Open Source Project *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Test app extension to exercise QAP (Non-tunnel Decode) */
+
+#include <ctype.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <cutils/properties.h>
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <system/audio.h>
+#include <qap_api.h>
+#include <qti_audio.h>
+#include "qahw_playback_test.h"
+
+#undef LOG_TAG
+#define LOG_TAG "HAL_TEST"
+#undef LOG_NDEBUG
+/*#define LOG_NDEBUG 0*/
+
+#if LINUX_ENABLED
+#define QAC_LIB_MS12 "/usr/lib/libdolby_ms12_wrapper.so"
+#define QAC_LIB_M8   "/usr/lib/libdts_m8_wrapper.so"
+#else
+#define QAC_LIB_MS12 "/system/lib/libdolby_ms12_wrapper.so"
+#define QAC_LIB_M8   "/system/lib/libdts_m8_wrapper.so"
+#endif
+
+#define SESSION_BLURAY   1
+#define SESSION_BROADCAST 2
+#define MAX_OUTPUT_CHANNELS 8
+#define FRAME_SIZE 32768 /* 32k size */
+#define MAX_BUFFER_SIZE 32768 /* 32k size */
+#define CONTIGUOUS_TIMESTAMP 0x7fffffff
+#define TIMESTAMP_ARRAY_SIZE 2048
+#define DOLBY 1
+#define DTS   2
+#define FRAME_SIZE_FOR_2CH_PCM 6144 /* For 48k samplerate, 2 ch, 2 bytes */
+
+#define MAX_QAP_MODULE_OUT 3
+
+qap_output_config_t qap_out_configs[MAX_QAP_MODULE_OUT];
+bool is_media_fmt_changed[MAX_QAP_MODULE_OUT];
+int new_output_conf_index = 0;
+
+qap_lib_handle_t ms12_lib_handle = NULL;
+qap_lib_handle_t m8_lib_handle = NULL;
+qap_session_handle_t qap_session_handle = NULL;
+qahw_module_handle_t *qap_out_hal_handle = NULL;
+qahw_module_handle_t *qap_out_spk_handle = NULL;
+qahw_module_handle_t *qap_out_hdmi_handle = NULL;
+qahw_module_handle_t *qap_out_hp_handle = NULL;
+
+audio_io_handle_t qap_stream_out_spk_handle = 0x999;
+audio_io_handle_t qap_stream_out_hdmi_handle = 0x998;
+audio_io_handle_t qap_stream_out_hp_handle = 0x997;
+audio_io_handle_t qap_stream_out_cmpr_handle = 0x996;
+
+FILE *fp_output_writer_spk = NULL;
+FILE *fp_output_writer_hp = NULL;
+FILE *fp_output_writer_hdmi = NULL;
+FILE *fp_output_timestamp_file = NULL;
+unsigned char data_buf[MAX_BUFFER_SIZE];
+uint32_t output_device_id = 0;
+uint16_t input_streams_count = 0;
+
+bool hdmi_connected = false;
+bool play_through_bt = false;
+bool encode = false;
+bool dolby_formats = false;
+bool timestamp_mode = false;
+int  data_write_count = 0;
+int data_callback_count = 0;
+bool play_list = false;
+int play_list_cnt = 0;
+uint8_t session_type = SESSION_BLURAY;
+
+pthread_t main_input_thread;
+pthread_attr_t main_input_thrd_attr;
+pthread_cond_t main_eos_cond;
+pthread_mutex_t main_eos_lock;
+pthread_cond_t sec_eos_cond;
+pthread_mutex_t sec_eos_lock;
+
+qap_session_outputs_config_t session_output_config;
+bool session_output_configured = false;
+struct timeval tcold_start, tcold_stop;
+struct timeval tcont_ts1, tcont_ts2;
+double cold_start, cold_stop;
+long int data_callback_ts_arr[TIMESTAMP_ARRAY_SIZE];
+long int data_input_ts_arr[TIMESTAMP_ARRAY_SIZE];
+double data_input_st_arr[TIMESTAMP_ARRAY_SIZE];
+double data_callback_st_arr[TIMESTAMP_ARRAY_SIZE];
+bool has_system_input = false;
+char session_kv_pairs[256];
+bool stream_close = false;
+uint32_t dsp_latency = 0;
+
+static int get_qap_out_config_index_for_id(int32_t out_id)
+{
+    int index = -1, i;
+
+    for (i = 0; i < MAX_QAP_MODULE_OUT; i++)
+        if (qap_out_configs[i].id == out_id)
+            index = i;
+
+    return index;
+}
+
+static void update_combo_dev_kvpairs()
+{
+    bool enable_spk = false;
+    bool enable_hp = false;
+    bool enable_hdmi = false;
+    bool combo_enabled = false;
+    char dev_kv_pair[16] = {0};
+
+    ALOGV("%s:%d output device id %d", __func__, __LINE__, output_device_id);
+
+    if (output_device_id & AUDIO_DEVICE_OUT_HDMI)
+        enable_hdmi = true;
+    if (output_device_id & AUDIO_DEVICE_OUT_WIRED_HEADPHONE)
+        enable_hp = true;
+    if (output_device_id & AUDIO_DEVICE_OUT_SPEAKER)
+        enable_spk = true;
+
+    // Update the kv_pair based on the output device selsction
+    // To select hdmi, spekaer and headphone: o_device=1,2,8
+    // To select hdmi, headphone: o_device=2,8
+    // To select hdmi, spekaer : o_device=1,8
+    // To select spekaer and headphone: o_device=1,2
+    if (enable_hdmi && enable_hp && enable_spk) {
+        sprintf(dev_kv_pair, "o_device=1,2,8");
+        combo_enabled = true;
+    } else if (enable_hdmi && enable_hp) {
+        sprintf(dev_kv_pair, "o_device=2,8");
+        combo_enabled = true;
+    } else if (enable_hdmi && enable_spk) {
+        sprintf(dev_kv_pair, "o_device=1,8");
+        combo_enabled = true;
+    } else if (enable_hp && enable_spk) {
+        sprintf(dev_kv_pair, "o_device=1,2");
+        combo_enabled = true;
+    }
+
+    if (combo_enabled)
+        strcat(session_kv_pairs, dev_kv_pair);
+
+    ALOGV("%s:%d session set param %s and combo_enabled %d", __func__, __LINE__, session_kv_pairs, combo_enabled);
+    return;
+}
+
+static void update_kvpairs_for_encode(int out_device_id) {
+    uint8_t device_id;
+    char command[64];
+    if (out_device_id == AUDIO_DEVICE_OUT_HDMI)
+        device_id = 8;
+    switch (render_format) {
+        case 1:
+            sprintf(command, "o_device=%d;od=;", device_id);
+            strcat(session_kv_pairs, command);
+            encode = true;
+            break;
+        case 2:
+            sprintf(command, "o_device=%d;odp=;", device_id);
+            strcat(session_kv_pairs, command);
+            encode = true;
+            break;
+        case 3:
+            sprintf(command, "o_device=%d;render_format=odts;enabletransencode;", device_id);
+            strcat(session_kv_pairs, command);
+            encode = true;
+            break;
+        default:
+            encode = false;
+            break;
+    }
+    ALOGV("%s::%d output device %d and session set params %s", __func__, __LINE__, out_device_id, session_kv_pairs);
+    return;
+}
+
+static void qap_wrapper_create_multi_channel_dump(char *path) {
+    fp_output_writer_hdmi = fopen(path,"wb");
+    if (fp_output_writer_hdmi)
+        fprintf(stdout, "output file ::%s has been generated.\n", path);
+    else
+        fprintf(stderr, "Failed open hdmi dump file\n");
+}
+
+/*
+ * cold_time_latency is the time difference between the session open
+ * and the first data output received from decoder.
+ *
+ * cont_time_latency is the avg time taken to decode the input buffers
+ * i.e. avg of the time differences between the time the input buffer feeded
+ * and the time the o/p buffer received
+ */
+static void qap_wrapper_measure_kpi_values(double cold_start, double cold_stop)
+{
+    int i=0, m=0, j=0;
+    int cnt = 0;
+    double syst_time_arr[TIMESTAMP_ARRAY_SIZE];
+    double total_lat = 0;
+    double cold_time_latency, cont_time_latency;
+    cold_time_latency = cold_stop - cold_start;
+    memset(syst_time_arr,0, sizeof(syst_time_arr));
+
+    if (data_write_count > TIMESTAMP_ARRAY_SIZE)
+        data_write_count = TIMESTAMP_ARRAY_SIZE;
+    if (data_callback_count > TIMESTAMP_ARRAY_SIZE)
+        data_callback_count = TIMESTAMP_ARRAY_SIZE;
+
+    for (i = 6; i < data_write_count; i++) {
+        for(j = 6; j < ((data_callback_count < TIMESTAMP_ARRAY_SIZE) ? data_callback_count : TIMESTAMP_ARRAY_SIZE); j++) {
+            if( abs(data_input_ts_arr[i] - data_callback_ts_arr[j]) <= 4000) {
+                syst_time_arr[cnt++] = (data_callback_st_arr[j] - data_input_st_arr[i]);
+            }
+        }
+    }
+
+    for(m = 0; m < cnt; m++) {
+        total_lat += syst_time_arr[m];
+        ALOGV("%d system time diff %lf", __LINE__, syst_time_arr[m]);
+    }
+    cont_time_latency = total_lat/(cnt);
+    fprintf(stdout, "cold time latency %lf ms, avg cont time latency %lf ms,"
+            "total cont time latency %f ms, total count %d\n",
+            cold_time_latency, cont_time_latency, total_lat, cnt);
+    if (dsp_latency)
+        fprintf(stdout, "Dsp latency = %lu ms \n", dsp_latency);
+}
+
+static void qap_wrapper_read_frame_size_from_file(qap_audio_buffer_t *buffer, FILE *fp_framesize)
+{
+    if (NULL != fp_framesize) {
+        char tempstr[100];
+        fgets(tempstr, sizeof(tempstr), fp_framesize);
+        buffer->common_params.size = atoi(tempstr);
+    }
+}
+
+static void read_bytes_timestamps_from_file(qap_audio_buffer_t *buffer, FILE *fp_timestamp, FILE *fp_input_file)
+{
+    if (NULL != fp_timestamp) {
+        char tempstr[100] = {0};
+        int seek_offset = 0;
+        fgets(tempstr, sizeof(tempstr), fp_timestamp);
+        printf("%s and tempstr is %s \n", __FUNCTION__,  tempstr);
+        char * token = strtok(tempstr, ",");
+        if (token != NULL) {
+            buffer->common_params.size = atoi(token);
+            if(token!= NULL) {
+                token = strtok(NULL, ",");
+                if (token!= NULL) {
+                    buffer->common_params.timestamp = atoi(token);
+                    ALOGV("%s and timestamp to be pushed to queue is %lld", __FUNCTION__, buffer->common_params.timestamp);
+                }
+                token = strtok(NULL, ",");
+                if (token != NULL) {
+                    seek_offset = atoi(token);
+                    if (fp_input_file && seek_offset > 0)
+                        fseek(fp_input_file, seek_offset, SEEK_CUR);
+                }
+            }
+        } else {
+            buffer->common_params.timestamp = CONTIGUOUS_TIMESTAMP;
+            buffer->common_params.size = 0;
+        }
+    }
+}
+
+bool is_qap_session_active(int argc, char* argv[], char *kvp_string) {
+    char *qap_kvp = NULL;
+    char *cmd_str = NULL;
+    char *tmp_str = NULL;
+    int status = 0;
+    cmd_str = (char *)qap_wrapper_get_cmd_string_from_arg_array(argc, argv, &status);
+    if (status > 0) {
+        qap_kvp = qap_wrapper_get_single_kvp("qap", cmd_str, &status);
+        if (qap_kvp == NULL) {
+            return false;
+        }
+        strncpy(kvp_string, cmd_str, strlen(cmd_str));
+        if (cmd_str != NULL) {
+            free(cmd_str);
+            cmd_str = NULL;
+        }
+    }
+    return true;
+}
+
+char* check_for_playlist(char *kvp_string) {
+    char *file_str = NULL;
+    char *tmp_str = NULL;
+    char *play_list = NULL;
+    int len = 0;
+
+    tmp_str = strstr(kvp_string, "g=/");
+    if (tmp_str != NULL) {
+        file_str = strstr(kvp_string, ".txt");
+        len = file_str - tmp_str;
+        play_list = (char*) malloc(sizeof(char) * (len+4));
+        memset(play_list, '\0', len+4);
+        strncpy(play_list, tmp_str+2, len+2);
+    }
+    return play_list;
+}
+
+int start_playback_through_qap_playlist(char *cmd_kvp_str[], int num_of_streams, char *kvp_string, stream_config stream_param[],
+                                     bool qap_wrapper_session_active, qahw_module_handle_t *hal_handle) {
+    stream_config *stream = NULL;
+    int rc = 0;
+    bool broad_cast = false, bd = false;
+    int i = 0, curr_clip_type = DOLBY, prev_clip_type;
+
+    if (strstr(kvp_string, "broadcast"))
+       broad_cast = true;
+    else if(strstr(kvp_string, "bd"))
+       bd = true;
+    do {
+        fprintf(stdout, "cmd_kvp_string is %s kvp_string %s and num_of_streams %d\n", cmd_kvp_str[i], kvp_string, num_of_streams);
+        stream = &stream_param[i];
+        fprintf(stdout, "stream->filename is %s\n", stream->filename);
+        if (stream->filename) {
+            prev_clip_type = curr_clip_type;
+            if ((stream->file_stream = fopen(stream->filename, "r"))== NULL) {
+                fprintf(stderr, "Cannot open audio file %s\n", stream->filename);
+                return -EINVAL;
+            }
+            if (strstr(stream->filename, ".dts")) {
+                curr_clip_type = DTS;
+            } else {
+                curr_clip_type = DOLBY;
+            }
+        }
+        get_file_format(stream);
+        fprintf(stdout, "Playing from:%s\n", stream->filename);
+        qap_module_handle_t qap_module_handle = NULL;
+        if ((bd || (prev_clip_type != curr_clip_type)) && qap_wrapper_session_active) {
+            fprintf(stdout, " prev_clip_type is %d curr_clip_type is %d\n", prev_clip_type, curr_clip_type);
+            qap_wrapper_session_close();
+            qap_wrapper_session_active = false;
+        }
+        if (!qap_wrapper_session_active) {
+            if (broad_cast) {
+                cmd_kvp_str[i] = realloc(cmd_kvp_str[i], strlen(cmd_kvp_str[i])+11);
+                strcat(strcat(cmd_kvp_str[i], ";"), "broadcast");
+            } else if (bd) {
+                cmd_kvp_str[i] = realloc(cmd_kvp_str[i], strlen(cmd_kvp_str[i])+4);
+                strcat(strcat(cmd_kvp_str[i], ";"), "bd");
+            }
+            rc = qap_wrapper_session_open(cmd_kvp_str[i], stream, num_of_streams, hal_handle);
+            if (rc != 0) {
+                fprintf(stderr, "Session Open failed\n");
+                return -EINVAL;
+            }
+            qap_wrapper_session_active = true;
+        }
+
+        if (qap_wrapper_session_active) {
+            stream->qap_module_handle = qap_wrapper_stream_open(stream);
+            if (stream->qap_module_handle == NULL) {
+                fprintf(stderr, "QAP Stream open Failed\n");
+            } else {
+                fprintf(stdout, "QAP module handle is %p and file name is %s\n", stream->qap_module_handle, stream->filename);
+                qap_wrapper_start_stream(&stream_param[i]);
+                free(stream->filename);
+                stream->filename = NULL;
+                free(cmd_kvp_str[i]);
+                cmd_kvp_str[i] = NULL;
+            }
+        }
+        i++;
+        while (!stream_close) {
+            usleep(50000);
+            fprintf(stderr, "QAP Stream not closed\n");
+        }
+        fprintf(stderr, "QAP Stream closed\n");
+    } while (i <num_of_streams);
+    if (broad_cast && qap_wrapper_session_active) {
+        qap_wrapper_session_close();
+        qap_wrapper_session_active = false;
+    }
+    return 0;
+}
+
+#ifdef QAP
+char *qap_wrapper_get_single_kvp(const char *key, const char *kv_pairs, int *status)
+{
+    char *kvp = NULL;
+    char *tempstr = NULL;
+    char *token = NULL;
+    char *context1 = NULL;
+    char *context2 = NULL;
+    char *temp_kvp = NULL;
+    char *temp_key = NULL;
+
+    if (NULL == key || NULL == kv_pairs) {
+        *status = -EINVAL;
+        return NULL;
+    }
+    tempstr = strdup(kv_pairs);
+    token = strtok_r(tempstr, ";", &context1);
+    if (token != NULL) {
+        temp_kvp = strdup(token);
+        if (temp_kvp != NULL) {
+            temp_key = strtok_r(temp_kvp, "=", &context2);
+            if (!strncmp(key, temp_key, strlen(key))) {
+                kvp = malloc((strlen(token) + 1) * sizeof(char));
+                memset(kvp, 0, strlen(token) + 1);
+                strncat(kvp, token, strlen(token));
+                return kvp;
+            }
+            free(temp_kvp);
+        }
+        while (token != NULL) {
+            token = strtok_r(NULL, ";", &context1);
+            if (token != NULL) {
+                temp_kvp = strdup(token);
+                if (temp_kvp != NULL) {
+                    temp_key = strtok_r(temp_kvp, "=", &context2);
+                    if (!strncmp(key, temp_key, strlen(key))) {
+                        kvp = malloc((strlen(token) + 1) * sizeof(char));
+                        memset(kvp, 0, strlen(token) + 1);
+                        strncat(kvp, token, strlen(token));
+                        return kvp;
+                    }
+                    free(temp_kvp);
+                    temp_kvp = NULL;
+                }
+            }
+        }
+        free(tempstr);
+    }
+    return NULL;
+}
+#endif
+
+int *qap_wrapper_get_int_value_array(const char *kvp, int *count, int *status __unused)
+{
+    char *tempstr1;
+    char *tempstr2;
+    char *l1;
+    char *l2 __unused;
+    char *ctx1;
+    char *ctx2 __unused;
+    int *val = NULL;
+    int i = 0;
+    char *s;
+    char *endstr;
+    int temp = 0;
+    char *jump;
+
+    *count = 0;
+    if (kvp == NULL) {
+        return NULL;
+    }
+    tempstr1 = strdup(kvp);
+    l1 = strtok_r(tempstr1, "=", &ctx1);
+    if (l1 != NULL) {
+        /* jump from key to value */
+        l1 = strtok_r(NULL, "=", &ctx1);
+        if (l1 != NULL) {
+            tempstr2 = strdup(l1);
+
+            s = tempstr2;
+            for (i=0; s[i]; s[i]==',' ? i++ : *s++);
+
+            temp = i;
+            val = malloc((i + 1)*sizeof(int));
+            i = 0;
+            val[i++] = strtol(tempstr2, &endstr, 0);
+
+            while (i <= temp) {
+                 jump = endstr + 1;
+                val[i++] = strtol(jump, &endstr, 0);
+            }
+            free(tempstr2);
+        }
+    }
+    free(tempstr1);
+    *count = i;
+    return val;
+}
+
+char * qap_wrapper_get_cmd_string_from_arg_array(int argc, char * argv[], int *status)
+{
+    char * kvps;
+    int idx;
+    int has_key = 0;
+    int mem = 0;
+
+    fprintf(stdout, "%s %d in", __func__, __LINE__);
+    if (argc < 2 || NULL == argv) {
+        fprintf(stdout, "%s %d returning EINVAL\n", __func__, __LINE__);
+        *status = -EINVAL;
+        return NULL;
+    }
+
+    for (idx = 0; idx < argc; idx++) {
+        mem += (strlen(argv[idx]) + 2);     /* Extra byte to insert delim ';' */
+    }
+
+    if (mem > 0)
+        kvps = calloc(1, mem * sizeof(char));
+    else {
+        *status = -EINVAL;
+        fprintf(stdout, "%s %d returning EINVAL\n", __func__, __LINE__);
+        return NULL;
+    }
+
+    if (NULL == kvps) {
+        *status = -ENOMEM;
+        fprintf(stdout, "%s %d returning EINVAL\n", __func__, __LINE__);
+        return NULL;
+    }
+
+    for (idx = 1; idx < argc; idx++) {
+        if (( argv[idx][0] == '-') &&
+                (argv[idx][1] < '0' || argv[idx][1] > '9')) {
+            if (has_key) {
+                strcat(kvps, ";");
+                has_key = 0;
+            }
+            strcat(kvps, argv[idx]+1);
+            strcat(kvps, "=");
+            has_key = 1;
+        } else if (has_key) {
+            strcat(kvps, argv[idx]);
+            strcat(kvps, ";");
+            has_key = 0;
+        } else {
+            *status = -EINVAL;
+            if (kvps != NULL) {
+                free(kvps);
+                kvps = NULL;
+            }
+            fprintf(stdout, "%s %d returning EINVAL\n", __func__, __LINE__);
+            return NULL;
+        }
+    }
+    *status = mem;
+    fprintf(stdout, "%s %d returning\n", __func__, __LINE__);
+    return kvps;
+}
+
+static int qap_wrapper_map_input_format(audio_format_t audio_format, qap_audio_format_t *format)
+{
+    if (audio_format == AUDIO_FORMAT_AC3) {
+        *format = QAP_AUDIO_FORMAT_AC3;
+        fprintf(stdout, "File Format is AC3!\n");
+    } else if (audio_format == AUDIO_FORMAT_E_AC3) {
+        *format = QAP_AUDIO_FORMAT_EAC3;
+        fprintf(stdout, "File Format is E_AC3!\n");
+    } else if ((audio_format == AUDIO_FORMAT_AAC_ADTS_LC) ||
+               (audio_format == AUDIO_FORMAT_AAC_ADTS_HE_V1) ||
+               (audio_format == AUDIO_FORMAT_AAC_ADTS_HE_V2) ||
+               (audio_format == AUDIO_FORMAT_AAC_LC) ||
+               (audio_format == AUDIO_FORMAT_AAC_HE_V1) ||
+               (audio_format == AUDIO_FORMAT_AAC_HE_V2) ||
+               (audio_format == AUDIO_FORMAT_AAC_LATM_LC) ||
+               (audio_format == AUDIO_FORMAT_AAC_LATM_HE_V1) ||
+               (audio_format == AUDIO_FORMAT_AAC_LATM_HE_V2)) {
+        *format = QAP_AUDIO_FORMAT_AAC_ADTS;
+        fprintf(stdout, "File Format is AAC!\n");
+    } else if (audio_format == AUDIO_FORMAT_DTS) {
+        *format = QAP_AUDIO_FORMAT_DTS;
+        fprintf(stdout, "File Format is DTS!\n");
+    } else if (audio_format == AUDIO_FORMAT_DTS_HD) {
+        *format = QAP_AUDIO_FORMAT_DTS_HD;
+        fprintf(stdout, "File Format is DTS_HD!\n");
+    } else if (audio_format == AUDIO_FORMAT_PCM_16_BIT) {
+        *format = QAP_AUDIO_FORMAT_PCM_16_BIT;
+        fprintf(stdout, "File Format is PCM_16!\n");
+    } else if (audio_format == AUDIO_FORMAT_PCM_32_BIT) {
+        *format = QAP_AUDIO_FORMAT_PCM_32_BIT;
+        fprintf(stdout, "File Format is PCM_32!\n");
+    } else if (audio_format == AUDIO_FORMAT_PCM_24_BIT_PACKED) {
+        *format = QAP_AUDIO_FORMAT_PCM_24_BIT_PACKED;
+        fprintf(stdout, "File Format is PCM_24!\n");
+    } else if ((audio_format == AUDIO_FORMAT_PCM_8_BIT) ||
+               (audio_format == AUDIO_FORMAT_PCM_8_24_BIT)) {
+        *format = QAP_AUDIO_FORMAT_PCM_8_24_BIT;
+        fprintf(stdout, "File Format is PCM_8_24!\n");
+    } else {
+        fprintf(stdout, "File Format not supported!\n");
+        return -EINVAL;
+    }
+    return 0;
+}
+
+char *get_string_value(const char *kvp, int *status)
+{
+    char *tempstr1 = NULL;
+    char *tempstr2 = NULL;
+    char *l1;
+    char *ctx1;
+    if (kvp == NULL)
+        return NULL;
+    tempstr1 = strdup(kvp);
+    l1 = strtok_r(tempstr1, "=", &ctx1);
+    if (l1 != NULL) {
+        /* jump from key to value */
+        l1 = strtok_r(NULL, "=", &ctx1);
+        if (l1 != NULL)
+            tempstr2 = strdup(l1);
+    }
+    free(tempstr1);
+    return tempstr2;
+}
+
+int qap_wrapper_write_to_hal(qahw_stream_handle_t* out_handle, char *data, size_t bytes)
+{
+    ssize_t ret;
+    qahw_out_buffer_t out_buf;
+
+    memset(&out_buf,0, sizeof(qahw_out_buffer_t));
+    out_buf.buffer = data;
+    out_buf.bytes = bytes;
+
+    ret = qahw_out_write(out_handle, &out_buf);
+    if (ret < 0)
+        fprintf(stderr, "%s::%d: writing data to hal failed (ret = %zd)\n", __func__, __LINE__, ret);
+    else if (ret != bytes)
+        fprintf(stdout, "%s::%d provided bytes %zd, written bytes %d\n",__func__, __LINE__, bytes, ret);
+
+    return ret;
+}
+
+static void close_output_streams()
+{
+    int ret;
+    if (qap_out_hal_handle && qap_out_spk_handle) {
+        ret = qahw_out_standby(qap_out_spk_handle);
+        if (ret)
+            fprintf(stderr, "%s::%d: out standby failed %d \n", __func__, __LINE__, ret);
+        if (play_through_bt) {
+            fprintf(stdout, "%s::%d: disconnecting BT\n", __func__, __LINE__);
+            char param[100] = {0};
+            snprintf(param, sizeof(param), "%s=%d", "disconnect", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP);
+            qahw_set_parameters(qap_out_hal_handle, param);
+        }
+        fprintf(stdout, "%s::%d: closing output stream\n", __func__, __LINE__);
+        ret = qahw_close_output_stream(qap_out_spk_handle);
+        if (ret)
+            fprintf(stderr, "%s::%d: could not close output stream, error - %d\n", __func__, __LINE__, ret);
+        qap_out_spk_handle = NULL;
+    }
+    if (qap_out_hal_handle && qap_out_hp_handle) {
+        ret = qahw_out_standby(qap_out_hp_handle);
+        if (ret)
+            fprintf(stderr, "%s::%d: out standby failed %d \n", __func__, __LINE__, ret);
+        fprintf(stdout, "%s::%d: closing output stream\n", __func__, __LINE__);
+        ret = qahw_close_output_stream(qap_out_hp_handle);
+        if (ret)
+            fprintf(stderr, "%s::%d: could not close output stream, error - %d\n", __func__, __LINE__, ret);
+        qap_out_hp_handle = NULL;
+    }
+    if (qap_out_hal_handle && qap_out_hdmi_handle) {
+        char param[100] = {0};
+        snprintf(param, sizeof(param), "%s=%d", "disconnect", AUDIO_DEVICE_OUT_HDMI);
+        ret = qahw_out_standby(qap_out_hdmi_handle);
+        if (ret)
+            fprintf(stderr, "%s::%d: out standby failed %d\n", __func__, __LINE__, ret);
+        qahw_set_parameters(qap_out_hal_handle, param);
+        fprintf(stdout, "%s::%d: closing output stream\n", __func__, __LINE__);
+        ret = qahw_close_output_stream(qap_out_hdmi_handle);
+        if (ret)
+            fprintf(stderr, "%s::%d: could not close output stream, error - %d\n", __func__, __LINE__, ret);
+        qap_out_hdmi_handle = NULL;
+    }
+    stream_close = true;
+}
+
+void qap_wrapper_session_callback(qap_session_handle_t session_handle __unused, void* priv_data __unused, qap_callback_event_t event_id, int size __unused, void *data)
+{
+    int ret = 0;
+    int bytes_written = 0;
+    int bytes_remaining = 0;
+    int offset = 0;
+    audio_output_flags_t flags;
+    flags = (AUDIO_OUTPUT_FLAG_NON_BLOCKING |
+             AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
+             AUDIO_OUTPUT_FLAG_DIRECT);
+    ALOGV("%s %d Received event id %d\n", __func__, __LINE__, event_id);
+    switch (event_id) {
+        case QAP_CALLBACK_EVENT_EOS:
+            ALOGV("%s %d Received Main Input EOS", __func__, __LINE__);
+            pthread_mutex_lock(&main_eos_lock);
+            pthread_cond_signal(&main_eos_cond);
+            pthread_mutex_unlock(&main_eos_lock);
+
+            ALOGE("%s %d Received Main Input EOS ", __func__, __LINE__);
+            if (!stream_close)
+            close_output_streams();
+            if (play_list_cnt && input_streams_count) {
+                play_list_cnt--;
+                input_streams_count = 0;
+            }
+            break;
+        case QAP_CALLBACK_EVENT_EOS_ASSOC:
+        case QAP_CALLBACK_EVENT_MAIN_2_EOS:
+            if (!has_system_input){
+                ALOGV("%s %d Received Secondary Input EOS", __func__, __LINE__);
+                pthread_mutex_lock(&sec_eos_lock);
+                pthread_cond_signal(&sec_eos_cond);
+                pthread_mutex_unlock(&sec_eos_lock);
+            }
+            break;
+        case QAP_CALLBACK_EVENT_ERROR:
+            break;
+        case QAP_CALLBACK_EVENT_SUCCESS:
+            break;
+        case QAP_CALLBACK_EVENT_METADATA:
+            break;
+        case QAP_CALLBACK_EVENT_OUTPUT_CFG_CHANGE:
+            if (data != NULL) {
+                qap_audio_buffer_t *buffer = (qap_audio_buffer_t *) data;
+                qap_output_config_t *new_conf = &buffer->buffer_parms.output_buf_params.output_config;
+                qap_output_config_t *cached_conf = NULL;
+                int index = -1;
+
+                ALOGV("%s %d Received Output cfg change", __func__, __LINE__);
+                if (buffer) {
+                    index = get_qap_out_config_index_for_id(
+                              buffer->buffer_parms.output_buf_params.output_id);
+                    if (index < 0 && new_output_conf_index < MAX_QAP_MODULE_OUT) {
+                        index = new_output_conf_index;
+                        cached_conf = &qap_out_configs[index];
+                        new_output_conf_index++;
+                    }
+                }
+
+                if (cached_conf == NULL) {
+                    ALOGE("Maximum output from QAP is reached");
+                    return;
+                }
+                if (memcmp(cached_conf, new_conf, sizeof(qap_output_config_t)) != 0) {
+                    memcpy(cached_conf, new_conf, sizeof(qap_output_config_t));
+                    cached_conf->id = buffer->buffer_parms.output_buf_params.output_id;
+                    is_media_fmt_changed[index] = true;
+                }
+            }
+            break;
+        case QAP_CALLBACK_EVENT_DATA:
+            if (data != NULL) {
+                qap_audio_buffer_t *buffer = (qap_audio_buffer_t *) data;
+
+                if (buffer && timestamp_mode) {
+                    char ch[100] = {0};
+                    if (kpi_mode) {
+                        if ((data_callback_count > 5) && (data_callback_count < TIMESTAMP_ARRAY_SIZE)) {
+                            gettimeofday(&tcont_ts2, NULL);
+                            data_callback_ts_arr[data_callback_count] = buffer->common_params.timestamp;
+                            data_callback_st_arr[data_callback_count] = (tcont_ts2.tv_sec) * 1000 + (tcont_ts2.tv_usec) / 1000;
+                            ALOGV("%s::%d data size %d, Kpi cont ts2 %lf, buffer timestamp %ld",
+                                  __func__, __LINE__, buffer->common_params.size,
+                                 data_callback_st_arr[data_callback_count], data_callback_ts_arr[data_callback_count]);
+                        }
+                        if (data_callback_count < TIMESTAMP_ARRAY_SIZE)
+                            data_callback_count++;
+                    }
+                    if (fp_output_timestamp_file == NULL) {
+                        fp_output_timestamp_file =
+                                 fopen("/sdcard/output_timestamp_file.txt","w");
+                        if(fp_output_timestamp_file) {
+                            fprintf(stdout, "output file :: "
+                                   "/sdcard/output_file_timestamp.txt"
+                                   " has been generated.");
+                            }
+                    }
+                    if (fp_output_timestamp_file) {
+                        sprintf(ch, "%d,%lld\n", buffer->common_params.size, buffer->common_params.timestamp);
+                        fprintf(stdout, "%s: %s", __func__, ch);
+                        ret = fwrite((char *)&ch, sizeof(char),
+                                     strlen(ch), fp_output_timestamp_file);
+                        fflush(fp_output_timestamp_file);
+                    }
+                }
+
+                if (buffer && buffer->common_params.data) {
+                    int index = -1;
+                    bool is_reopen_stream = false;
+                    index = get_qap_out_config_index_for_id(buffer->buffer_parms.output_buf_params.output_id);
+                    if (index > -1 && is_media_fmt_changed[index]) {
+                        session_output_config.output_config->sample_rate = qap_out_configs[index].sample_rate;
+                        session_output_config.output_config->bit_width = qap_out_configs[index].bit_width;
+                        session_output_config.output_config->channels = qap_out_configs[index].channels;
+                        is_reopen_stream = true;
+                        is_media_fmt_changed[index] = false;
+                    }
+
+                    if (buffer->buffer_parms.output_buf_params.output_id &
+                            AUDIO_DEVICE_OUT_HDMI) {
+                        if (!hdmi_connected) {
+                            char param[100] = {0};
+                            snprintf(param, sizeof(param), "%s=%d", "connect", AUDIO_DEVICE_OUT_HDMI);
+                            qahw_set_parameters(qap_out_hal_handle, param);
+                            hdmi_connected = true;
+                        }
+                        if (encode) {
+                            if (enable_dump && fp_output_writer_hdmi == NULL) {
+                                if (buffer->buffer_parms.output_buf_params.output_id ==
+                                        (AUDIO_FORMAT_E_AC3|AUDIO_DEVICE_OUT_HDMI))
+                                    qap_wrapper_create_multi_channel_dump("/sdcard/output_hdmi.ddp");
+                                else if (buffer->buffer_parms.output_buf_params.output_id ==
+                                            (AUDIO_FORMAT_AC3|AUDIO_DEVICE_OUT_HDMI))
+                                    qap_wrapper_create_multi_channel_dump("/sdcard/output_hdmi.dd");
+                                else
+                                    qap_wrapper_create_multi_channel_dump("/sdcard/output_hdmi_dts.dts");
+                            }
+                        } else {
+                            if (enable_dump && fp_output_writer_hdmi == NULL)
+                                qap_wrapper_create_multi_channel_dump("/sdcard/output_hdmi.dump");
+                        }
+                        if (fp_output_writer_hdmi) {
+                            ret = fwrite((unsigned char *)buffer->common_params.data, sizeof(unsigned char),
+                                          buffer->common_params.size, fp_output_writer_hdmi);
+                            fflush(fp_output_writer_hdmi);
+                        }
+
+                        if (is_reopen_stream && qap_out_hdmi_handle) {
+                            qahw_close_output_stream(qap_out_hdmi_handle);
+                            qap_out_hdmi_handle = NULL;
+                            is_reopen_stream = false;
+                        }
+
+                        if (hdmi_connected && qap_out_hdmi_handle == NULL) {
+                            struct audio_config config;
+                            audio_devices_t devices;
+
+                            config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
+                            config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
+                            config.sample_rate = config.offload_info.sample_rate =
+                                                        session_output_config.output_config->sample_rate;
+                            if (session_output_config.output_config->bit_width == 24) {
+                                config.format = config.offload_info.format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+                                config.offload_info.bit_width = 24;
+                            } else {
+                                config.format = config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
+                                config.offload_info.bit_width = 16;
+                            }
+
+                            if (session_output_config.output_config->channels == 2) {
+                                config.offload_info.channel_mask = config.channel_mask =
+                                    AUDIO_CHANNEL_OUT_STEREO;
+                            } else {
+                                config.offload_info.channel_mask = config.channel_mask =
+                                    audio_channel_out_mask_from_count(MAX_OUTPUT_CHANNELS);
+                            }
+                            devices = AUDIO_DEVICE_OUT_HDMI;
+                            if (timestamp_mode)
+                                flags |= AUDIO_OUTPUT_FLAG_TIMESTAMP;
+                            if (encode) {
+                                if (buffer->buffer_parms.output_buf_params.output_id ==
+                                       (AUDIO_FORMAT_AC3|AUDIO_DEVICE_OUT_HDMI))
+                                    config.format = config.offload_info.format = AUDIO_FORMAT_AC3;
+                                else if (buffer->buffer_parms.output_buf_params.output_id ==
+                                            (AUDIO_FORMAT_E_AC3|AUDIO_DEVICE_OUT_HDMI))
+                                    config.format = config.offload_info.format = AUDIO_FORMAT_E_AC3;
+                                else
+                                    config.format = config.offload_info.format = AUDIO_FORMAT_DTS;
+                                ALOGV("%s:%d output format %x", __func__, __LINE__,
+                                        config.format, config.offload_info.format);
+                                ret = qahw_open_output_stream(qap_out_hal_handle, qap_stream_out_cmpr_handle, devices,
+                                                              flags, &config, &qap_out_hdmi_handle, "stream");
+                            } else {
+                                ret = qahw_open_output_stream(qap_out_hal_handle, qap_stream_out_hdmi_handle, devices,
+                                                              flags, &config, &qap_out_hdmi_handle, "stream");
+                            }
+
+                            ret = qahw_out_set_volume(qap_out_hdmi_handle, vol_level, vol_level);
+                            if (ret < 0)
+                                ALOGE("unable to set volume");
+                        }
+                        if (qap_out_hdmi_handle) {
+                                bytes_written = qap_wrapper_write_to_hal(qap_out_hdmi_handle,
+                                                    buffer->common_params.data, buffer->common_params.size);
+                                if (bytes_written == -1) {
+                                    ALOGE("%s::%d write failed in hal", __func__, __LINE__);
+                                }
+                            if (kpi_mode && data_callback_count == 6)
+                                dsp_latency = qahw_out_get_latency(qap_out_hdmi_handle);
+                        }
+                        if (kpi_mode && data_callback_count == 1) {
+                             gettimeofday(&tcold_stop, NULL);
+                             cold_stop = (tcold_stop.tv_sec) * 1000 + (tcold_stop.tv_usec) / 1000;
+                             ALOGD("%s::%d Measuring Kpi cold stop %lf", __func__, __LINE__, cold_stop);
+                        }
+                    }
+                    if (buffer->buffer_parms.output_buf_params.output_id & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
+                        if (enable_dump && fp_output_writer_hp == NULL) {
+                            fp_output_writer_hp =
+                                         fopen("/sdcard/output_hp.dump","wb");
+                            if (fp_output_writer_hp) {
+                                fprintf(stdout, "output file :: "
+                                      "/sdcard/output_hp.dump"
+                                      " has been generated.\n");
+                            } else {
+                                fprintf(stderr, "Failed open hp dump file\n");
+                            }
+                        }
+                        if (fp_output_writer_hp) {
+                            ret = fwrite((unsigned char *)buffer->common_params.data, sizeof(unsigned char),
+                                          buffer->common_params.size, fp_output_writer_hp);
+                            fflush(fp_output_writer_hp);
+                        }
+                        if (is_reopen_stream && qap_out_hp_handle) {
+                            qahw_close_output_stream(qap_out_hp_handle);
+                            qap_out_hp_handle = NULL;
+                            is_reopen_stream = false;
+                        }
+
+                        if (qap_out_hp_handle == NULL) {
+                            struct audio_config config;
+                            audio_devices_t devices;
+                            config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
+                            config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
+                            config.sample_rate = config.offload_info.sample_rate =
+                                                        session_output_config.output_config->sample_rate;
+                            if (session_output_config.output_config->bit_width == 24) {
+                                config.format = config.offload_info.format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+                                config.offload_info.bit_width = 24;
+                            } else {
+                                config.format = config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
+                                config.offload_info.bit_width = 16;
+                            }
+
+                            config.offload_info.channel_mask = config.channel_mask =
+                                    AUDIO_CHANNEL_OUT_STEREO;
+                            devices = AUDIO_DEVICE_OUT_LINE;//ToDO - Need to change to AUDIO_DEVICE_OUT_WIRED_HEADPHONE
+
+                            if (timestamp_mode)
+                                flags |= AUDIO_OUTPUT_FLAG_TIMESTAMP;
+                            ret = qahw_open_output_stream(qap_out_hal_handle, qap_stream_out_hp_handle, devices,
+                                 flags, &config, &qap_out_hp_handle, "stream");
+
+                            if (ret) {
+                                ALOGE("%s:%d could not open output stream, error - %d", __func__, __LINE__, ret);
+                                return;
+                            }
+                            ret = qahw_out_set_volume(qap_out_hp_handle, vol_level, vol_level);
+                            if (ret < 0)
+                                 ALOGE("unable to set volume");
+                        }
+                        if (qap_out_hp_handle) {
+                                bytes_written = qap_wrapper_write_to_hal(qap_out_hp_handle,
+                                                    buffer->common_params.data, buffer->common_params.size);
+                                if (bytes_written == -1) {
+                                    ALOGE("%s::%d write failed in hal", __func__, __LINE__);
+                                }
+                            if (kpi_mode && data_callback_count == 6)
+                                dsp_latency = qahw_out_get_latency(qap_out_hp_handle);
+                        }
+                        if (kpi_mode && data_callback_count == 1) {
+                             gettimeofday(&tcold_stop, NULL);
+                             cold_stop = (tcold_stop.tv_sec) * 1000 + (tcold_stop.tv_usec) / 1000;
+                             ALOGD("%s::%d Measuring Kpi cold stop %lf", __func__, __LINE__, cold_stop);
+                        }
+                    }
+                    if (buffer->buffer_parms.output_buf_params.output_id & AUDIO_DEVICE_OUT_SPEAKER) {
+                        if (enable_dump && fp_output_writer_spk == NULL) {
+                            char ch[4] = {0};
+                            fp_output_writer_spk =
+                                         fopen("/sdcard/output_speaker.dump","wb");
+                            if (fp_output_writer_spk) {
+                                fprintf(stdout, "output file :: "
+                                      "/sdcard/output_speaker.dump"
+                                      " has been generated.\n");
+                                if (dolby_formats) {
+                                    ret = fwrite((unsigned char *)&ch, sizeof(unsigned char),
+                                                  4, fp_output_writer_spk);
+                                }
+                            } else {
+                                fprintf(stderr, "Failed open speaker dump file\n");
+                            }
+                        }
+                        if (fp_output_writer_spk) {
+                            ret = fwrite((unsigned char *)buffer->common_params.data, sizeof(unsigned char),
+                                          buffer->common_params.size, fp_output_writer_spk);
+                            fflush(fp_output_writer_spk);
+                        }
+                        if (is_reopen_stream && qap_out_spk_handle) {
+                            qahw_close_output_stream(qap_out_spk_handle);
+                            qap_out_spk_handle = NULL;
+                            is_reopen_stream = false;
+                        }
+                        if (qap_out_spk_handle == NULL) {
+                            struct audio_config config;
+                            audio_devices_t devices;
+                            config.offload_info.version = AUDIO_INFO_INITIALIZER.version;
+                            config.offload_info.size = AUDIO_INFO_INITIALIZER.size;
+                            config.sample_rate = config.offload_info.sample_rate =
+                                                        session_output_config.output_config->sample_rate;
+                            if (session_output_config.output_config->bit_width == 24) {
+                                config.format = config.offload_info.format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+                                config.offload_info.bit_width = 24;
+                            } else {
+                                config.format = config.offload_info.format = AUDIO_FORMAT_PCM_16_BIT;
+                                config.offload_info.bit_width = 16;
+                            }
+
+                            config.offload_info.channel_mask = config.channel_mask =
+                                    AUDIO_CHANNEL_OUT_STEREO;
+                            if (play_through_bt) {
+                                fprintf(stderr, "%s::%d: connecting BT\n", __func__, __LINE__);
+                                char param[100] = {0};
+                                snprintf(param, sizeof(param), "%s=%d", "connect", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP);
+                                qahw_set_parameters(qap_out_hal_handle, param);
+                                devices = AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+                            } else {
+                                devices = AUDIO_DEVICE_OUT_SPEAKER;
+                            }
+                            if (timestamp_mode)
+                                flags |= AUDIO_OUTPUT_FLAG_TIMESTAMP;
+                            ALOGD("%s::%d: open output for device %d", __func__, __LINE__, devices);
+                            ret = qahw_open_output_stream(qap_out_hal_handle, qap_stream_out_spk_handle, devices,
+                                 flags, &config, &qap_out_spk_handle, "stream");
+
+                            if (ret) {
+                                ALOGE("%s:%d could not open output stream, error - %d", __func__, __LINE__, ret);
+                                return;
+                            }
+                            ret = qahw_out_set_volume(qap_out_spk_handle, vol_level, vol_level);
+                            if (ret < 0)
+                                 ALOGE("unable to set volume");
+                        }
+                        if (qap_out_spk_handle) {
+                                bytes_written = qap_wrapper_write_to_hal(qap_out_spk_handle,
+                                                    buffer->common_params.data, buffer->common_params.size);
+                                if (bytes_written == -1) {
+                                    ALOGE("%s::%d write failed in hal", __func__, __LINE__);
+                                }
+                            if (kpi_mode && data_callback_count == 6)
+                                dsp_latency = qahw_out_get_latency(qap_out_spk_handle);
+                        }
+                        if (kpi_mode && data_callback_count == 1) {
+                             gettimeofday(&tcold_stop, NULL);
+                             cold_stop = (tcold_stop.tv_sec) * 1000 + (tcold_stop.tv_usec) / 1000;
+                             ALOGD("%s::%d Measuring Kpi cold stop %lf", __func__, __LINE__, cold_stop);
+                        }
+                    }
+                }
+            }
+            break;
+        default:
+            break;
+    }
+}
+
+static void qap_wrapper_is_dap_enabled(char *kv_pairs, int out_device_id) {
+    int status = 0;
+    int temp = 0;
+    char *dap_kvp = NULL;
+    int *dap_value = NULL;
+    int dap_enable = 0;
+
+    dap_kvp = qap_wrapper_get_single_kvp("dap_enable", kv_pairs, &status);
+    if (dap_kvp != NULL) {
+        dap_value = qap_wrapper_get_int_value_array(dap_kvp, &temp, &status);
+        if (dap_value != NULL)
+            dap_enable = dap_value[0];
+        if (dap_enable) {
+            fprintf(stdout, "dap enable %d and device id %d\n", dap_enable, out_device_id);
+            char *dev_kvp = NULL;
+            if (out_device_id == AUDIO_DEVICE_OUT_SPEAKER) {
+                dev_kvp = (char *) calloc(1, status + strlen("o_device=1; "));
+                if (dev_kvp != NULL) {
+                    strcat(dev_kvp, "o_device=1;");
+                    strcat(session_kv_pairs, dev_kvp);
+                    fprintf(stdout, "session set params %s\n", session_kv_pairs);
+                    free(dev_kvp);
+                    dev_kvp = NULL;
+                }
+            } else if ((out_device_id == AUDIO_DEVICE_OUT_LINE)||
+                       (out_device_id == AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
+                dev_kvp = (char *) calloc(1, status + strlen("o_device=2; "));
+                if (dev_kvp != NULL) {
+                    strcat(dev_kvp, "o_device=2;");
+                    strcat(session_kv_pairs, dev_kvp);
+                    fprintf(stdout, "session set params %s\n", session_kv_pairs);
+                    free(dev_kvp);
+                    dev_kvp = NULL;
+                }
+            }
+        }
+        free(dap_kvp);
+        dap_kvp = NULL;
+    }
+}
+
+int qap_wrapper_session_open(char *kv_pairs, void* stream_data, int num_of_streams,  qahw_module_handle_t *hal_handle)
+{
+    int status = 0;
+    int ret = 0;
+    int i;
+    int temp = 0;
+    stream_config *stream = (stream_config *)stream_data;
+    char *session_type_kvp = NULL;
+    char *encode_kvp = NULL;
+    int *temp_val = NULL;
+    char *bitwidth_kvp = NULL;
+
+    qap_out_hal_handle = hal_handle;
+    if (kpi_mode) {
+        memset(data_input_st_arr, 0, sizeof(data_input_st_arr));
+        memset(data_input_ts_arr, 0, sizeof(data_input_ts_arr));
+        memset(data_callback_st_arr, 0, sizeof(data_callback_st_arr));
+        memset(data_callback_ts_arr, 0, sizeof(data_callback_ts_arr));
+        gettimeofday(&tcold_start, NULL);
+        cold_start = (tcold_start.tv_sec) * 1000 + (tcold_start.tv_usec) / 1000;
+        ALOGD("%s::%d Measuring Kpi cold start %lf", __func__, __LINE__, cold_start);
+    }
+    if (play_list)
+        play_list_cnt = num_of_streams;
+
+    memset(&session_output_config, 0, sizeof(session_output_config));
+    strcpy(session_kv_pairs, kv_pairs);
+
+    if (NULL != (session_type_kvp = qap_wrapper_get_single_kvp("broadcast", kv_pairs, &status))) {
+        session_type = SESSION_BROADCAST;
+        fprintf(stdout, "Session Type is Broadcast\n");
+        free(session_type_kvp);
+        session_type_kvp = NULL;
+    } else if (NULL != (session_type_kvp = qap_wrapper_get_single_kvp("bd", kv_pairs, &status))) {
+        session_type = SESSION_BLURAY;
+        free(session_type_kvp);
+        session_type_kvp = NULL;
+        fprintf(stdout, "Session Type is Bluray\n");
+    }
+
+    if (session_type == SESSION_BLURAY) {
+        if ((stream->filetype == FILE_WAV) ||
+            (stream->filetype == FILE_AAC)) {
+            fprintf(stderr, "Format is not supported for BD usecase\n");
+            return -EINVAL;
+        }
+        if (!play_list && num_of_streams > 1) {
+            fprintf(stderr, "Please specifiy proper session type\n");
+            return -EINVAL;
+        }
+    }
+
+    if (stream->filetype == FILE_DTS) {
+        m8_lib_handle = (qap_session_handle_t) qap_load_library(QAC_LIB_M8);
+        if (m8_lib_handle == NULL) {
+            fprintf(stdout, "Failed to load M8 library\n");
+            return -EINVAL;
+        }
+        fprintf(stdout, "loaded M8 library\n");
+        dolby_formats = false;
+    } else if ((stream->filetype == FILE_AC3) ||
+                (stream->filetype == FILE_EAC3) ||
+                (stream->filetype == FILE_EAC3_JOC) ||
+                (stream->filetype == FILE_WAV) ||
+                (stream->filetype == FILE_AAC) ||
+                (stream->filetype == FILE_AAC_ADTS) ||
+                (stream->filetype == FILE_AAC_LATM)) {
+        ms12_lib_handle = (qap_session_handle_t) qap_load_library(QAC_LIB_MS12);
+        if (ms12_lib_handle == NULL) {
+            fprintf(stderr, "Failed to load MS12 library\n");
+            return -EINVAL;
+        }
+        dolby_formats = true;
+    }
+
+    qap_wrapper_is_dap_enabled(kv_pairs, stream->output_device);
+
+    // To-Do - Need to check SPDIF out also when SPDIF out is supported
+    ALOGD("%s::%d output device %d", __func__, __LINE__, stream->output_device);
+    if (stream->output_device & AUDIO_DEVICE_OUT_HDMI)
+        update_kvpairs_for_encode(AUDIO_DEVICE_OUT_HDMI);
+
+    if (stream->filetype == FILE_DTS)
+        session_output_config.output_config->bit_width = 24;
+
+    bitwidth_kvp = qap_wrapper_get_single_kvp("bitwidth", kv_pairs, &status);
+    if (bitwidth_kvp != NULL) {
+        temp_val = qap_wrapper_get_int_value_array(bitwidth_kvp, &temp, &status);
+        if (temp_val != NULL) {
+            if (stream->filetype == FILE_DTS)
+                session_output_config.output_config->bit_width = temp_val[0];
+            free(temp_val);
+            temp_val = NULL;
+        }
+        free(bitwidth_kvp);
+        bitwidth_kvp = NULL;
+    }
+
+    if ((session_type == SESSION_BROADCAST) && dolby_formats) {
+        fprintf(stdout, "%s::%d Setting BROADCAST session for dolby formats\n", __func__, __LINE__);
+        qap_session_handle = (qap_session_handle_t) qap_session_open(QAP_SESSION_BROADCAST, ms12_lib_handle);
+        if (qap_session_handle == NULL)
+            return -EINVAL;
+    } else if ((session_type == SESSION_BROADCAST) && !dolby_formats) {
+        fprintf(stdout, "%s::%d Setting BROADCAST session for dts formats\n", __func__, __LINE__);
+        qap_session_handle = (qap_session_handle_t) qap_session_open(QAP_SESSION_BROADCAST, m8_lib_handle);
+        if (qap_session_handle == NULL)
+            return -EINVAL;
+    } else if (session_type == SESSION_BLURAY) {
+        fprintf(stdout, "%s::%d Setting BD session\n", __func__, __LINE__);
+        if (!encode && dolby_formats) {
+            fprintf(stdout, "%s::%d Setting BD session for decoding dolby formats\n", __func__, __LINE__);
+            qap_session_handle = (qap_session_handle_t) qap_session_open(QAP_SESSION_DECODE_ONLY, ms12_lib_handle);
+            if (qap_session_handle == NULL)
+                return -EINVAL;
+        } else if (!encode && !dolby_formats) {
+            fprintf(stdout, "%s::%d Setting BD session for decoding dts formats \n", __func__, __LINE__, qap_session_handle);
+            qap_session_handle = (qap_session_handle_t) qap_session_open(QAP_SESSION_DECODE_ONLY, m8_lib_handle);
+            if (qap_session_handle == NULL)
+                return -EINVAL;
+        } else if (encode && dolby_formats)  {
+            fprintf(stdout, "%s::%d Setting BD session for encoding dolby formats \n", __func__, __LINE__, qap_session_handle);
+            qap_session_handle = (qap_session_handle_t) qap_session_open(QAP_SESSION_ENCODE_ONLY, ms12_lib_handle);
+            if (qap_session_handle == NULL)
+                return -EINVAL;
+        } else if (encode && !dolby_formats) {
+            fprintf(stdout, "%s::%d Setting BD session for encoding dts formats \n", __func__, __LINE__, qap_session_handle);
+            qap_session_handle = (qap_session_handle_t) qap_session_open(QAP_SESSION_ENCODE_ONLY, m8_lib_handle);
+            if (qap_session_handle == NULL)
+                return -EINVAL;
+        }
+    }
+
+    ret = qap_session_set_callback(qap_session_handle, &qap_wrapper_session_callback);
+    if (ret != QAP_STATUS_OK) {
+        fprintf(stderr, "!!!! Please specify appropriate Session\n");
+        return -EINVAL;
+    }
+
+    if (!session_output_configured) {
+        session_output_config.output_config->channels = stream->channels;
+        session_output_config.output_config->sample_rate = stream->config.sample_rate;
+        if (session_type == SESSION_BROADCAST)
+            session_output_config.output_config->sample_rate = 48000;
+
+        output_device_id = stream->output_device;
+        if (output_device_id & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) {
+            output_device_id |= AUDIO_DEVICE_OUT_SPEAKER;
+            play_through_bt = true;
+        }
+        if (output_device_id & AUDIO_DEVICE_OUT_LINE) {
+            output_device_id |= AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+        }
+        if (encode) {
+            if (render_format == 1)
+                output_device_id |= AUDIO_FORMAT_AC3;
+            else if (render_format == 2)
+                output_device_id |= AUDIO_FORMAT_E_AC3;
+            else if (render_format == 3)
+                output_device_id |= AUDIO_FORMAT_DTS;
+        }
+        session_output_config.output_config->id = output_device_id;
+        update_combo_dev_kvpairs();
+        if (stream->filetype != FILE_DTS)
+            session_output_config.output_config->bit_width = stream->config.offload_info.bit_width;
+        session_output_config.num_output = 1;
+
+        ret = qap_session_cmd(qap_session_handle, QAP_SESSION_CMD_SET_OUTPUTS, sizeof(session_output_config), &session_output_config, NULL, NULL);
+        if (ret != QAP_STATUS_OK) {
+            fprintf(stderr, "Output config failed\n");
+            return -EINVAL;
+        }
+
+        ALOGV("Session set params %s", session_kv_pairs);
+        ret = qap_session_cmd(qap_session_handle, QAP_SESSION_CMD_SET_KVPAIRS, sizeof(session_kv_pairs), session_kv_pairs, NULL, NULL);
+        if (ret != QAP_STATUS_OK) {
+            fprintf(stderr, "Session set params failed\n");
+            return -EINVAL;
+        }
+        usleep(2000);
+        session_output_configured = true;
+    }
+
+    pthread_mutex_init(&main_eos_lock, (const pthread_mutexattr_t *)NULL);
+    pthread_mutex_init(&sec_eos_lock, (const pthread_mutexattr_t *)NULL);
+    pthread_cond_init(&main_eos_cond, (const pthread_condattr_t *) NULL);
+    pthread_cond_init(&sec_eos_cond, (const pthread_condattr_t *) NULL);
+    fprintf(stdout, "Session open returing success\n");
+    return 0;
+}
+
+int qap_wrapper_session_close ()
+{
+    ALOGD("closing QAP session");
+    session_output_configured = false;
+    qap_session_close(qap_session_handle);
+    qap_session_handle = NULL;
+}
+
+void *qap_wrapper_start_stream (void* stream_data)
+{
+    int ret = 0;
+    qap_audio_buffer_t *buffer;
+    int8_t first_read = 1;
+    int bytes_wanted;
+    int bytes_read;
+    int bytes_consumed = 0, status = 0;;
+    qap_module_handle_t qap_module_handle = NULL;
+    stream_config *stream_info = (stream_config *)stream_data;
+    FILE *fp_input = stream_info->file_stream;
+    int is_buffer_available = 0;
+    char *temp_str = NULL;
+    void *reply_data;
+    char* temp_ptr = NULL;
+    qap_audio_format_t format;
+
+    if (fp_input == NULL) {
+        fprintf(stderr, "Open File Failed for %s\n", stream_info->filename);
+        pthread_exit(0);
+    }
+    qap_module_handle = stream_info->qap_module_handle;
+    buffer = (qap_audio_buffer_t *) calloc(1, sizeof(qap_audio_buffer_t));
+    if (buffer == NULL) {
+        fprintf(stderr, "%s::%d: Memory Alloc Error\n", __func__, __LINE__);
+        pthread_exit(0);
+    }
+    buffer->common_params.data = calloc(1, FRAME_SIZE);
+    if (buffer->common_params.data == NULL) {
+        fprintf(stderr, "%s::%d: Memory Alloc Error\n", __func__, __LINE__);
+        pthread_exit(0);
+        if (NULL != buffer) {
+            free( buffer);
+            buffer = NULL;
+        }
+    }
+    buffer->buffer_parms.output_buf_params.output_id = output_device_id;
+    fprintf(stdout, "%s::%d: output device id %d\n",
+                __func__, __LINE__, buffer->buffer_parms.output_buf_params.output_id);
+
+    fprintf(stdout, "Opened Input File %s format %d handle %p\n", stream_info->filename, format, fp_input);
+
+    ret = qap_module_cmd(qap_module_handle, QAP_MODULE_CMD_START, sizeof(QAP_MODULE_CMD_START), NULL, NULL, NULL);
+    if (ret != QAP_STATUS_OK) {
+        fprintf(stderr, "START failed\n");
+        pthread_exit(0);
+        if (NULL != buffer &&  NULL != buffer->common_params.data) {
+            free( buffer->common_params.data);
+            buffer->common_params.data = NULL;
+            free( buffer);
+            buffer = NULL;
+        }
+    }
+
+    do {
+        if (stream_info->filetype == FILE_WAV) {
+            if (first_read) {
+                first_read = 0;
+                int wav_header_len = get_wav_header_length(stream_info->file_stream);
+                fseek(fp_input, wav_header_len, SEEK_SET);
+            }
+            if (stream_info->channels > 6)
+                stream_info->bytes_to_read = (FRAME_SIZE_FOR_2CH_PCM * 4);
+            else
+                stream_info->bytes_to_read = (FRAME_SIZE_FOR_2CH_PCM * 3);
+        }
+        buffer->buffer_parms.input_buf_params.flags = QAP_BUFFER_NO_TSTAMP;
+        buffer->common_params.timestamp = QAP_BUFFER_NO_TSTAMP;
+        buffer->common_params.size = stream_info->bytes_to_read;
+
+        if (stream_info->timestamp_filename != NULL) {
+            if (!stream_info->timestamp_file_ptr) {
+                stream_info->timestamp_file_ptr = fopen(stream_info->timestamp_filename, "r");
+                if (!stream_info->timestamp_file_ptr) {
+                    fprintf(stderr, "Cannot open audio file %s\n", stream_info->filename);
+                    goto exit;
+                }
+            }
+            read_bytes_timestamps_from_file(buffer, stream_info->timestamp_file_ptr, fp_input);
+            if (buffer->common_params.timestamp == CONTIGUOUS_TIMESTAMP)
+                buffer->buffer_parms.input_buf_params.flags = QAP_BUFFER_TSTAMP_CONTINUE;
+            else
+                buffer->buffer_parms.input_buf_params.flags = QAP_BUFFER_TSTAMP;
+            timestamp_mode = true;
+        }
+
+        bytes_wanted = buffer->common_params.size;
+        bytes_read = fread(data_buf, sizeof(unsigned char), bytes_wanted, fp_input);
+
+        buffer->common_params.offset = 0;
+        buffer->common_params.size = bytes_read;
+        memcpy(buffer->common_params.data, data_buf, bytes_read);
+        if (bytes_read <= 0) {
+            buffer->buffer_parms.input_buf_params.flags = QAP_BUFFER_EOS;
+            bytes_consumed = qap_module_process(qap_module_handle, buffer);
+            ret = qap_module_cmd(qap_module_handle, QAP_MODULE_CMD_STOP, sizeof(QAP_MODULE_CMD_STOP), NULL, NULL, NULL);
+            fprintf(stdout, "Stopped feeding input %s : %p\n", stream_info->filename, fp_input);
+            ALOGV("Stopped feeding input %s : %p", stream_info->filename, fp_input);
+            break;
+        }
+
+        reply_data = (char*) calloc(1, 100);
+        is_buffer_available = 0;
+        temp_ptr = buffer->common_params.data;
+        int time_index = data_write_count;
+        if (kpi_mode) {
+            if (data_write_count > 5 && data_write_count < TIMESTAMP_ARRAY_SIZE) {
+                gettimeofday(&tcont_ts1, NULL);
+                data_input_ts_arr[data_write_count] = buffer->common_params.timestamp;
+                data_input_st_arr[data_write_count] = (tcont_ts1.tv_sec) * 1000 + (tcont_ts1.tv_usec) / 1000;
+                ALOGV("%s::%d Kpi cont ts1 %lf, buffer timestamp %ld count %d",
+                      __func__, __LINE__, data_input_st_arr[data_write_count], data_input_ts_arr[data_write_count], data_write_count);
+            }
+            if (data_write_count < TIMESTAMP_ARRAY_SIZE)
+                data_write_count++;
+        }
+        do {
+            bytes_consumed = qap_module_process(qap_module_handle, buffer);
+            if (bytes_consumed > 0) {
+                buffer->common_params.data += bytes_consumed;
+                buffer->common_params.size -= bytes_consumed;
+            }
+            ALOGV("%s %d feeding Input of size %d  and bytes_cosumed is %d",
+                      __FUNCTION__, __LINE__,bytes_read, bytes_consumed);
+            if (stream_info->filetype == FILE_DTS) {
+                if (bytes_consumed < 0) {
+                    while (!is_buffer_available) {
+                        usleep(1000);
+                        ret = qap_module_cmd(qap_module_handle, QAP_MODULE_CMD_GET_PARAM,
+                                             sizeof(QAP_MODULE_CMD_GET_PARAM), "buf_available", NULL, reply_data
+                        );
+                        if (reply_data)
+                            temp_str = get_string_value(reply_data, &status);
+                        if (temp_str) {
+                            is_buffer_available = atoi(temp_str);
+                            free(temp_str);
+                        }
+                        ALOGV("%s : %d, dts clip reply_data is %d buffer availabale is %d",
+                              __FUNCTION__, __LINE__, reply_data, is_buffer_available);
+                    }
+
+                    if(kpi_mode && time_index > 5) {
+                        gettimeofday(&tcont_ts1, NULL);
+                        data_input_st_arr[time_index] = (tcont_ts1.tv_sec) * 1000 + (tcont_ts1.tv_usec) / 1000;
+                    }
+                }
+            }
+        } while (buffer->common_params.size > 0);
+        if (reply_data)
+            free(reply_data);
+        buffer->common_params.data = temp_ptr;
+        if (!(stream_info->system_input || stream_info->sec_input) && !(kpi_mode)) {
+            usleep(5000); //To swtich between main and secondary threads incase of dual input
+        }
+    } while (1);
+
+wait_for_eos:
+    if (stream_info->sec_input && !stream_info->aac_fmt_type) {
+        pthread_mutex_lock(&sec_eos_lock);
+        pthread_cond_wait(&sec_eos_cond, &sec_eos_lock);
+        pthread_mutex_unlock(&sec_eos_lock);
+        fprintf(stdout, "Received EOS event for secondary input\n");
+        ALOGV("Received EOS event for secondary input\n");
+    }
+    if (!(stream_info->system_input || stream_info->sec_input)){
+        pthread_mutex_lock(&main_eos_lock);
+        pthread_cond_wait(&main_eos_cond, &main_eos_lock);
+        pthread_mutex_unlock(&main_eos_lock);
+        fprintf(stdout, "Received EOS event for main input\n");
+        ALOGV("Received EOS event for main input\n");
+    }
+
+exit:
+    if (NULL != buffer &&  NULL != buffer->common_params.data) {
+        free( buffer->common_params.data);
+        buffer->common_params.data = NULL;
+        free( buffer);
+        buffer = NULL;
+    }
+    if ((true == play_list) && (0 == play_list_cnt) && qap_out_hal_handle) {
+         ALOGV("%s %d QAP_CALLBACK_EVENT_EOS for play list received and unload_hals", __func__, __LINE__);
+         unload_hals();
+         qap_out_hal_handle = NULL;
+    } else if (!play_list && qap_out_hal_handle) {
+         ALOGV("%s %d QAP_CALLBACK_EVENT_EOS and unload_hals", __func__, __LINE__);
+         unload_hals();
+         qap_out_hal_handle = NULL;
+    }
+    qap_module_deinit(qap_module_handle);
+    if (kpi_mode) {
+        qap_wrapper_measure_kpi_values(cold_start, cold_stop);
+    }
+    fprintf(stdout, "%s::%d , THREAD EXIT \n", __func__, __LINE__);
+    ALOGD("%s::%d , THREAD EXIT \n", __func__, __LINE__);
+    return NULL;
+}
+
+qap_module_handle_t qap_wrapper_stream_open(void* stream_data)
+{
+    qap_module_config_t *input_config = NULL;
+    int ret = 0;
+    int i = 0;
+    stream_config *stream_info = (stream_config *)stream_data;
+    qap_module_handle_t qap_module_handle = NULL;
+
+    input_config = (qap_module_config_t *) calloc(1, sizeof(qap_module_config_t));
+    if (input_config == NULL) {
+        fprintf(stderr, "%s::%d Memory Alloc Error\n", __func__, __LINE__);
+        return NULL;
+    }
+    input_config->sample_rate = stream_info->config.sample_rate;
+    input_config->channels = stream_info->channels;
+    input_config->bit_width = stream_info->config.offload_info.bit_width;
+
+    if (stream_info->filetype == FILE_DTS)
+        stream_info->bytes_to_read = FRAME_SIZE;
+    else
+        stream_info->bytes_to_read = 1024;
+    input_streams_count++;
+    if (input_streams_count == 2) {
+        if (stream_info->filetype == FILE_WAV) {
+            input_config->flags = QAP_MODULE_FLAG_SYSTEM_SOUND;
+            stream_info->system_input = true;
+            has_system_input = true;
+            ALOGV("%s::%d Set Secondary System Sound Flag", __func__, __LINE__);
+        } else if (stream_info->filetype != FILE_WAV) {
+            if (stream_info->flags & AUDIO_OUTPUT_FLAG_ASSOCIATED) {
+                 ALOGV("%s::%d Set Secondary Assoc Input Flag", __func__, __LINE__);
+                 input_config->flags = QAP_MODULE_FLAG_SECONDARY;
+                 stream_info->sec_input = true;
+            } else {
+                ALOGV("%s::%d Set Secondary Main Input Flag", __func__, __LINE__);
+                input_config->flags = QAP_MODULE_FLAG_PRIMARY;
+                stream_info->sec_input = true;
+            }
+        }
+        stream_info->bytes_to_read = 2048;
+    } else {
+        if (stream_info->filetype == FILE_WAV) {
+            ALOGV("%s::%d Set Secondary System Sound Flag", __func__, __LINE__);
+            input_config->flags = QAP_MODULE_FLAG_SYSTEM_SOUND;
+            stream_info->system_input = true;
+        } else {
+            ALOGV("%s::%d Set Primary Main Input Flag", __func__, __LINE__);
+            input_config->flags = QAP_MODULE_FLAG_PRIMARY;
+        }
+    }
+
+    if (!encode)
+        input_config->module_type = QAP_MODULE_DECODER;
+    else
+        input_config->module_type = QAP_MODULE_ENCODER;
+
+    ret = qap_wrapper_map_input_format(stream_info->config.offload_info.format, &input_config->format);
+    if (ret == -EINVAL)
+        return NULL;
+
+    ret = qap_module_init(qap_session_handle, input_config, &qap_module_handle);
+    if (qap_module_handle == NULL) {
+        fprintf(stderr, "%s Module Handle is Null\n", __func__);
+        return NULL;
+    }
+
+    stream_close = false;
+    return qap_module_handle;
+
+}
+void get_play_list(FILE *fp, stream_config (*stream_param)[], int *num_of_streams, char *kvp_str[])
+{
+    char *token = NULL;
+    char *strings[100] = {NULL};
+    char cmd_str[500] = {0};
+    char *tmp_str = NULL;
+    int i = 0;
+
+    do {
+        int j = 0, cnt = 1, status = 0;
+
+        if (fgets(cmd_str, sizeof(cmd_str), fp) != NULL)
+            tmp_str = strdup(cmd_str);
+        else
+            break;
+        fprintf(stdout, "%s %d\n", __FUNCTION__, __LINE__);
+        token = strtok(tmp_str, " ");
+        if (NULL != token) {
+            strings[cnt] = (char*)calloc(1, (strlen(token) +1));
+            memset(strings[cnt], '\0', strlen(token) +1);
+            strncpy(strings[cnt], token, strlen(token));
+            cnt++;
+            while (NULL != (token = strtok(NULL, " "))) {
+                strings[cnt] = (char*)calloc(1, (strlen(token) +1));
+                memset(strings[cnt], '\0', strlen(token) +1);
+                strncpy(strings[cnt], token, strlen(token));
+                cnt++;
+            }
+            strings[0] = calloc(1, 4);
+            memset(strings[0], '\0', 4);
+            strncpy(strings[0], "play_list", 3);
+            for (j = 0;j< cnt;j++) {
+                if (!strncmp(strings[j], "-f", 2)) {
+                   (*stream_param)[i].filename = strdup(strings[j+1]);
+                } else if (!strncmp(strings[j], "-r", 2)) {
+                    (*stream_param)[i].config.offload_info.sample_rate = atoi(strings[j+1]);
+                    (*stream_param)[i].config.sample_rate = atoi(strings[j+1]);
+                } else if (!strncmp(strings[j], "-c", 2)) {
+                   (*stream_param)[i].channels = atoi(strings[j+1]);
+                   (*stream_param)[i].config.channel_mask = audio_channel_out_mask_from_count(atoi(strings[j+1]));
+                } else if (!strncmp(strings[j], "-b", 2)) {
+                    (*stream_param)[i].config.offload_info.bit_width = atoi(strings[j+1]);
+                } else if (!strncmp(strings[j], "-d", 2)) {
+                    (*stream_param)[i].output_device = atoll(strings[j+1]);
+                } else if (!strncmp(strings[j], "-t", 2)) {
+                    (*stream_param)[i].filetype = atoi(strings[j+1]);
+                } else if (!strncmp(strings[j], "-a", 2)) {
+                    (*stream_param)[i].aac_fmt_type = atoi(strings[j+1]);
+                }
+            }
+        }
+        if(NULL != (*stream_param)[i].filename) {
+            *num_of_streams = i+1;
+            play_list = true;
+            kvp_str[i] = (char *)qap_wrapper_get_cmd_string_from_arg_array(cnt, (char**)strings, &status);
+        }
+        free(tmp_str);
+        for (j=0; j < cnt; j++)
+           free(strings[j]);
+        i++;
+    }while(NULL != cmd_str);
+
+    return;
+}
+
+void hal_test_qap_usage() {
+    printf(" \n qap commands \n");
+    printf(" -qap                                      - Enabling playback through QAP for nun tunnel decoding mode\n");
+    printf(" -bd                                       - Enabling Broadcast Decode/Encode session through QAP\n");
+    printf(" -broadcast                                - Enabling playback through QAP for nun tunnel decoding mode\n");
+    printf(" -y  --timestamp filename                  - Input timestamp file to be used to send timestamp and bytes to be read from main input file.\n");
+    printf(" -z  --framesize filename                  - Input framesize file to be used to send bytes to be read from main input file.\n");
+    printf(" hal_play_test -qap -broadcast -f /data/5ch_dd_25fps_channeld_id.ac3 -t 9 -d 2 -v 0.01 -r 48000 -c 6 \n");
+    printf("                                          -> plays AC3 stream(-t = 9) on speaker device(-d = 2)\n");
+    printf("                                          -> 6 channels and 48000 sample rate\n\n");
+    printf("                                          -> using QAP with Broadcast session\n\n");
+    printf(" hal_play_test -qap -bd -f /data/200_48_16_ieq_mix_voice_40s.ec3 -t 11 -d 2 -v 0.01 -r 48000 -c 2 \n");
+    printf("                                          -> plays EAC3 stream(-t = 11) on speaker device(-d = 2)\n");
+    printf("                                          -> 2 channels and 48000 sample rate\n\n");
+    printf("                                          -> using QAP with Bluray session\n\n");
+}
diff --git a/qahw_api/test/trans_loopback_test.c b/qahw_api/test/trans_loopback_test.c
index 009e288..1ba2c55 100644
--- a/qahw_api/test/trans_loopback_test.c
+++ b/qahw_api/test/trans_loopback_test.c
@@ -45,6 +45,7 @@
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <utils/Log.h>
+#include <math.h>
 
 #include <cutils/list.h>
 #include "qahw_api.h"
@@ -87,6 +88,7 @@
 
 FILE * log_file = NULL;
 volatile bool stop_loopback = false;
+static float loopback_gain = 1.0;
 const char *log_filename = NULL;
 
 #define TRANSCODE_LOOPBACK_SOURCE_PORT_ID 0x4C00
@@ -138,6 +140,34 @@
    stop_loopback = true;
 }
 
+int poll_data_event_init()
+{
+    struct sockaddr_nl sock_addr;
+    int sz = (64*1024);
+    int soc;
+
+    memset(&sock_addr, 0, sizeof(sock_addr));
+    sock_addr.nl_family = AF_NETLINK;
+    sock_addr.nl_pid = getpid();
+    sock_addr.nl_groups = 0xffffffff;
+
+    soc = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+    if (soc < 0) {
+        return 0;
+    }
+
+    setsockopt(soc, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
+
+    if (bind(soc, (struct sockaddr*) &sock_addr, sizeof(sock_addr)) < 0) {
+        close(soc);
+        return 0;
+    }
+
+    sock_event_fd = soc;
+
+    return (soc > 0);
+}
+
 void init_transcode_loopback_config(transcode_loopback_config_t **p_transcode_loopback_config)
 {
     fprintf(log_file,"\nInitializing global transcode loopback config\n");
@@ -366,6 +396,23 @@
                         &transcode_loopback_config->sink_config,
                         &transcode_loopback_config->patch_handle);
     fprintf(log_file,"\nCreate patch returned %d\n",rc);
+    if(!rc) {
+        struct audio_port_config sink_gain_config;
+        /* Convert loopback gain to millibels */
+        int loopback_gain_in_millibels = 2000 * log10(loopback_gain);
+        sink_gain_config.gain.index = 0;
+        sink_gain_config.gain.mode = AUDIO_GAIN_MODE_JOINT;
+        sink_gain_config.gain.channel_mask = 1;
+        sink_gain_config.gain.values[0] = loopback_gain_in_millibels;
+        sink_gain_config.id = transcode_loopback_config->sink_config.id;
+        sink_gain_config.role = transcode_loopback_config->sink_config.role;
+        sink_gain_config.type = transcode_loopback_config->sink_config.type;
+        sink_gain_config.config_mask = AUDIO_PORT_CONFIG_GAIN;
+
+        (void)qahw_set_audio_port_config(transcode_loopback_config->hal_handle,
+                    &sink_gain_config);
+    }
+
     return rc;
 }
 
@@ -396,34 +443,6 @@
 }
 
 
-int poll_data_event_init()
-{
-    struct sockaddr_nl sock_addr;
-    int sz = (64*1024);
-    int soc;
-
-    memset(&sock_addr, 0, sizeof(sock_addr));
-    sock_addr.nl_family = AF_NETLINK;
-    sock_addr.nl_pid = getpid();
-    sock_addr.nl_groups = 0xffffffff;
-
-    soc = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
-    if (soc < 0) {
-        return 0;
-    }
-
-    setsockopt(soc, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
-
-    if (bind(soc, (struct sockaddr*) &sock_addr, sizeof(sock_addr)) < 0) {
-        close(soc);
-        return 0;
-    }
-
-    sock_event_fd = soc;
-
-    return (soc > 0);
-}
-
 void source_data_event_handler(transcode_loopback_config_t *transcode_loopback_config)
 {
     int status =0;
@@ -494,7 +513,7 @@
                     j++;
                 }
 
-                if ((dev_path != NULL) && (switch_name != NULL)) 
+                if ((dev_path != NULL) && (switch_name != NULL))
                     fprintf(log_file,"devpath = %s, switch_name = %s \n",dev_path, switch_name);
 
                 if((DEV_NODE_CHECK(tlb_hdmi_in_audio_dev_path, dev_path) == 0)  || (DEV_NODE_CHECK(tlb_hdmi_in_audio_sample_rate_dev_path, dev_path) == 0)
@@ -512,23 +531,9 @@
     pthread_exit(0);
 }
 
-bool is_device_supported(uint32_t device_id)
-{
-    switch(device_id)
-    {
-        case AUDIO_DEVICE_OUT_SPEAKER :
-        case AUDIO_DEVICE_OUT_WIRED_HEADSET :
-        case AUDIO_DEVICE_OUT_WIRED_HEADPHONE :
-            return true;
-        default :
-            return false;
-    }
-}
-
 void set_device(uint32_t device_type, uint32_t device_id)
 {
     transcode_loopback_config_t *transcode_loopback_config = &g_trnscode_loopback_config;
-    device_id = is_device_supported(device_id) ? device_id : AUDIO_DEVICE_OUT_SPEAKER;
     switch( device_type )
     {
         case DEVICE_SINK:
@@ -543,7 +548,7 @@
 int main(int argc, char *argv[]) {
 
     int status = 0;
-    uint32_t play_duration_in_seconds = 600,play_duration_elapsed_msec = 0,play_duration_in_msec = 0, sink_device = 2;
+    uint32_t play_duration_in_seconds = 600,play_duration_elapsed_msec = 0,play_duration_in_msec = 0, sink_device = 2, volume_in_millibels = 0;
     source_port_type_t source_port_type = SOURCE_PORT_NONE;
     log_file = stdout;
     transcode_loopback_config_t    *transcode_loopback_config = NULL;
@@ -553,6 +558,7 @@
         /* These options set a flag. */
         {"sink-device", required_argument,    0, 'd'},
         {"play-duration",  required_argument,    0, 'p'},
+        {"play-volume",  required_argument,    0, 'v'},
         {"help",          no_argument,          0, 'h'},
         {0, 0, 0, 0}
     };
@@ -562,7 +568,7 @@
 
     while ((opt = getopt_long(argc,
                               argv,
-                              "-d:p:h",
+                              "-d:p:v:h",
                               long_options,
                               &option_index)) != -1) {
 
@@ -575,6 +581,9 @@
         case 'p':
             play_duration_in_seconds = atoi(optarg);
             break;
+        case 'v':
+            loopback_gain = atof(optarg);
+            break;
         case 'h':
         default :
             usage();
@@ -584,9 +593,9 @@
     }
 
     fprintf(log_file,"\nTranscode loopback test begin\n");
-    if (play_duration_in_seconds < 0 | play_duration_in_seconds > 3600) {
+    if (play_duration_in_seconds < 0 | play_duration_in_seconds > 360000) {
             fprintf(log_file,
-                    "\nPlayback duration %d invalid or unsupported(range : 1 to 3600, defaulting to 600 seconds )\n",
+                    "\nPlayback duration %d invalid or unsupported(range : 1 to 360000, defaulting to 600 seconds )\n",
                     play_duration_in_seconds);
             play_duration_in_seconds = 600;
     }
@@ -654,8 +663,8 @@
 
 void usage()
 {
-    fprintf(log_file,"\nUsage : trans_loopback_test -p <duration_in_seconds> -d <sink_device_id>\n");
-    fprintf(log_file,"\nExample to play for 1 minute on speaker device: trans_loopback_test -p 60 -d 2\n");
+    fprintf(log_file,"\nUsage : trans_loopback_test -p <duration_in_seconds> -d <sink_device_id> -v <loopback_volume(range 0 to 4.0)>\n");
+    fprintf(log_file,"\nExample to play for 1 minute on speaker device with volume unity: trans_loopback_test -p 60 -d 2 -v 1.0\n");
     fprintf(log_file,"\nExample to play for 5 minutes on headphone device: trans_loopback_test -p 300 -d 8\n");
     fprintf(log_file,"\nHelp : trans_loopback_test -h\n");
  }