Merge "hal: fix incorrect VOIP volume when device switch"
diff --git a/configs/sdm670/mixer_paths_mtp.xml b/configs/sdm670/mixer_paths_mtp.xml
index efb37b1..048e039 100644
--- a/configs/sdm670/mixer_paths_mtp.xml
+++ b/configs/sdm670/mixer_paths_mtp.xml
@@ -1618,6 +1618,10 @@
         <ctl name="SLIMBUS_7_RX Audio Mixer MultiMedia10" value="1" />
     </path>
 
+    <path name="audio-playback-voip bt-a2dp">
+        <ctl name="SLIMBUS_7_RX Audio Mixer MultiMedia10" value="1" />
+    </path>
+
     <path name="audio-playback-voip bt-sco-wb">
         <ctl name="BT SampleRate" value="KHZ_16" />
         <path name="audio-playback-voip bt-sco" />
diff --git a/configs/sdm670/mixer_paths_tavil.xml b/configs/sdm670/mixer_paths_tavil.xml
index d77f623..0409cc1 100644
--- a/configs/sdm670/mixer_paths_tavil.xml
+++ b/configs/sdm670/mixer_paths_tavil.xml
@@ -1686,6 +1686,10 @@
         <ctl name="SLIMBUS_7_RX Audio Mixer MultiMedia10" value="1" />
     </path>
 
+    <path name="audio-playback-voip bt-a2dp">
+        <ctl name="SLIMBUS_7_RX Audio Mixer MultiMedia10" value="1" />
+    </path>
+
     <path name="audio-playback-voip bt-sco-wb">
         <ctl name="BT SampleRate" value="KHZ_16" />
         <path name="audio-playback-voip bt-sco" />
diff --git a/configs/sdm845/mixer_paths_tavil.xml b/configs/sdm845/mixer_paths_tavil.xml
index 4a05733..87bdae0 100644
--- a/configs/sdm845/mixer_paths_tavil.xml
+++ b/configs/sdm845/mixer_paths_tavil.xml
@@ -1697,6 +1697,10 @@
         <ctl name="SLIMBUS_7_RX Audio Mixer MultiMedia10" value="1" />
     </path>
 
+    <path name="audio-playback-voip bt-a2dp">
+        <ctl name="SLIMBUS_7_RX Audio Mixer MultiMedia10" value="1" />
+    </path>
+
     <path name="audio-playback-voip bt-sco-wb">
         <ctl name="BT SampleRate" value="KHZ_16" />
         <path name="audio-playback-voip bt-sco" />
diff --git a/configs/sdm845/sound_trigger_mixer_paths_wcd9340.xml b/configs/sdm845/sound_trigger_mixer_paths_wcd9340.xml
index 55dd42f..093002b 100644
--- a/configs/sdm845/sound_trigger_mixer_paths_wcd9340.xml
+++ b/configs/sdm845/sound_trigger_mixer_paths_wcd9340.xml
@@ -36,6 +36,14 @@
     <ctl name="LSM6 Mixer SLIMBUS_5_TX" value="0" />
     <ctl name="LSM7 Mixer SLIMBUS_5_TX" value="0" />
     <ctl name="LSM8 Mixer SLIMBUS_5_TX" value="0" />
+    <ctl name="LSM1 Mixer SLIMBUS_0_TX" value="0" />
+    <ctl name="LSM2 Mixer SLIMBUS_0_TX" value="0" />
+    <ctl name="LSM3 Mixer SLIMBUS_0_TX" value="0" />
+    <ctl name="LSM4 Mixer SLIMBUS_0_TX" value="0" />
+    <ctl name="LSM5 Mixer SLIMBUS_0_TX" value="0" />
+    <ctl name="LSM6 Mixer SLIMBUS_0_TX" value="0" />
+    <ctl name="LSM7 Mixer SLIMBUS_0_TX" value="0" />
+    <ctl name="LSM8 Mixer SLIMBUS_0_TX" value="0" />
     <ctl name="LSM1 Port" value="None" />
     <ctl name="LSM2 Port" value="None" />
     <ctl name="LSM3 Port" value="None" />
@@ -45,6 +53,7 @@
     <ctl name="LSM7 Port" value="None" />
     <ctl name="LSM8 Port" value="None" />
     <ctl name="SLIMBUS_5_TX LSM Function" value="None" />
+    <ctl name="SLIMBUS_0_TX LSM Function" value="None" />
     <ctl name="MADONOFF Switch" value="0" />
     <ctl name="MAD Input" value="DMIC1" />
     <ctl name="MAD_SEL MUX" value="SPE" />
@@ -89,6 +98,7 @@
     <ctl name= "WDMA3 CH1 MUX" value="PORT_0" />
     <ctl name= "WDMA3 CH2 MUX" value="PORT_0" />
     <ctl name= "WDMA3_ON_OFF Switch" value="0" />
+    <ctl name="SLIM_0_TX Channels" value="One" />
 
     <path name="listen-voice-wakeup-1">
         <ctl name="SLIMBUS_5_TX LSM Function" value="AUDIO" />
diff --git a/configure.ac b/configure.ac
index f9f36e3..a84e2cd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -77,6 +77,10 @@
          AC_SUBST([TARGET_PLATFORM], ["msm8974"])
          TARGET_CFLAGS="-DPLATFORM_SDX24"
 fi
+if (test x$TARGET_SUPPORT = x8x96autogvmquintcu); then
+         AC_SUBST([TARGET_PLATFORM], ["msm8974"])
+         TARGET_CFLAGS="-DPLATFORM_MSM8996"
+fi
 AC_SUBST([TARGET_CFLAGS])
 
 AM_CONDITIONAL([QTI_AUDIO_SERVER_ENABLED],[test x$BOARD_SUPPORTS_QTI_AUDIO_SERVER = xtrue])
diff --git a/hal/Android.mk b/hal/Android.mk
index 5d85a2c..96d4c6b 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -56,6 +56,8 @@
 endif
 endif
 
+LOCAL_CFLAGS += -Wno-macro-redefined
+
 LOCAL_SRC_FILES := \
 	audio_hw.c \
 	voice.c \
diff --git a/hal/audio_extn/a2dp.c b/hal/audio_extn/a2dp.c
index c484713..91a1e15 100644
--- a/hal/audio_extn/a2dp.c
+++ b/hal/audio_extn/a2dp.c
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -788,6 +788,10 @@
     bool is_configured = false;
     int ret = 0;
     int sample_rate_backup;
+
+    if(aptx_bt_cfg == NULL)
+        return false;
+
 #ifndef LINUX_ENABLED
     struct aptx_enc_cfg_t aptx_dsp_cfg;
     mixer_size = sizeof(struct aptx_enc_cfg_t);
@@ -798,9 +802,6 @@
     sample_rate_backup = aptx_bt_cfg->sampling_rate;
 #endif
 
-    if(aptx_bt_cfg == NULL)
-        return false;
-
     ctl_enc_data = mixer_get_ctl_by_name(a2dp.adev->mixer, MIXER_ENC_CONFIG_BLOCK);
     if (!ctl_enc_data) {
         ALOGE(" ERROR  a2dp encoder CONFIG data mixer control not identifed");
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index e267e39..5db3706 100755
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -1254,6 +1254,7 @@
 {
     bool ssr_supported = false;
     in->config.rate = config->sample_rate;
+    in->sample_rate = config->sample_rate;
     ssr_supported = audio_extn_ssr_check_usecase(in);
     if (ssr_supported) {
         return audio_extn_ssr_set_usecase(in, config, update_params);
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index f29ca30..f1f45c0 100755
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -221,6 +221,7 @@
 #define audio_extn_usb_get_max_bit_width(p)                            (0)
 #define audio_extn_usb_get_sup_sample_rates(t, s, l)                   (0)
 #define audio_extn_usb_is_tunnel_supported()                           (0)
+#define audio_extn_usb_alive(adev)                                     (false)
 #else
 void audio_extn_usb_init(void *adev);
 void audio_extn_usb_deinit();
@@ -238,6 +239,7 @@
 int audio_extn_usb_get_max_bit_width(bool playback);
 int audio_extn_usb_get_sup_sample_rates(int type, uint32_t *sr, uint32_t l);
 bool audio_extn_usb_is_tunnel_supported();
+bool audio_extn_usb_alive(int card);
 #endif
 
 #ifndef SPLIT_A2DP_ENABLED
diff --git a/hal/audio_extn/ffv.c b/hal/audio_extn/ffv.c
index 511179a..027849c 100644
--- a/hal/audio_extn/ffv.c
+++ b/hal/audio_extn/ffv.c
@@ -324,7 +324,7 @@
 {
     char ffv_enabled[PROPERTY_VALUE_MAX] = "false";
 
-    property_get("ro.qc.sdk.audio.ffv", ffv_enabled, "0");
+    property_get("ro.vendor.audio.sdk.ffv", ffv_enabled, "0");
     if (!strncmp("true", ffv_enabled, 4)) {
         ALOGD("%s: ffv is supported", __func__);
         ffvmod.is_ffv_enabled = true;
diff --git a/hal/audio_extn/passthru.c b/hal/audio_extn/passthru.c
index 99949fc..3ba2111 100755
--- a/hal/audio_extn/passthru.c
+++ b/hal/audio_extn/passthru.c
@@ -207,6 +207,8 @@
        channel_count = audio_channel_count_from_out_mask(out->channel_mask);
 #endif
        break;
+    case AUDIO_FORMAT_IEC61937:
+       channel_count = audio_channel_count_from_out_mask(out->channel_mask);
    default:
        break;
    }
@@ -441,18 +443,20 @@
         struct audio_device *adev, struct stream_out *out,
         const void *buffer __unused, size_t bytes __unused)
 {
-    if (audio_extn_passthru_is_passt_supported(adev, out)) {
-        ALOGV("%s:PASSTHROUGH", __func__);
-        out->compr_config.codec->compr_passthr = PASSTHROUGH;
-    } else if (audio_extn_passthru_is_convert_supported(adev, out)) {
-        ALOGV("%s:PASSTHROUGH CONVERT", __func__);
-        out->compr_config.codec->compr_passthr = PASSTHROUGH_CONVERT;
-    } else if (out->format == AUDIO_FORMAT_IEC61937) {
-        ALOGV("%s:PASSTHROUGH IEC61937", __func__);
-        out->compr_config.codec->compr_passthr = PASSTHROUGH_IEC61937;
-    } else {
-        ALOGV("%s:NO PASSTHROUGH", __func__);
-        out->compr_config.codec->compr_passthr = LEGACY_PCM;
+    if(out->compr_config.codec != NULL) {
+        if (audio_extn_passthru_is_passt_supported(adev, out)) {
+            ALOGV("%s:PASSTHROUGH", __func__);
+            out->compr_config.codec->compr_passthr = PASSTHROUGH;
+        } else if (audio_extn_passthru_is_convert_supported(adev, out)) {
+            ALOGV("%s:PASSTHROUGH CONVERT", __func__);
+            out->compr_config.codec->compr_passthr = PASSTHROUGH_CONVERT;
+        } else if (out->format == AUDIO_FORMAT_IEC61937) {
+            ALOGV("%s:PASSTHROUGH IEC61937", __func__);
+            out->compr_config.codec->compr_passthr = PASSTHROUGH_IEC61937;
+        } else {
+            ALOGV("%s:NO PASSTHROUGH", __func__);
+            out->compr_config.codec->compr_passthr = LEGACY_PCM;
+       }
     }
 }
 
diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c
index 8fa47a8..af8cc89 100644
--- a/hal/audio_extn/usb.c
+++ b/hal/audio_extn/usb.c
@@ -1133,6 +1133,13 @@
     return;
 }
 
+bool audio_extn_usb_alive(int card) {
+    char path[PATH_MAX] = {0};
+    // snprintf should never fail
+    (void) snprintf(path, sizeof(path), "/proc/asound/card%u/stream0", card);
+    return access(path, F_OK) == 0;
+}
+
 void audio_extn_usb_init(void *adev)
 {
     if (usbmod == NULL) {
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 314b14d..4b63666 100755
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -3573,6 +3573,15 @@
     return;
 }
 
+static int get_alive_usb_card(struct str_parms* parms) {
+    int card;
+    if ((str_parms_get_int(parms, "card", &card) >= 0) &&
+        !audio_extn_usb_alive(card)) {
+        return card;
+    }
+    return -ENODEV;
+}
+
 static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
 {
     struct stream_out *out = (struct stream_out *)stream;
@@ -3640,6 +3649,22 @@
                 }
             }
         }
+
+        audio_devices_t new_dev = val;
+
+        // Workaround: If routing to an non existing usb device, fail gracefully
+        // The routing request will otherwise block during 10 second
+        int card;
+        if (audio_is_usb_out_device(new_dev) &&
+            (card = get_alive_usb_card(parms)) >= 0) {
+
+            ALOGW("out_set_parameters() ignoring rerouting to non existing USB card %d", card);
+            pthread_mutex_unlock(&adev->lock);
+            pthread_mutex_unlock(&out->lock);
+            ret = -ENOSYS;
+            goto routing_fail;
+        }
+
         /*
          * select_devices() call below switches all the usecases on the same
          * backend to the new device. Refer to check_usecases_codec_backend() in
@@ -3715,6 +3740,7 @@
         pthread_mutex_unlock(&adev->lock);
         pthread_mutex_unlock(&out->lock);
     }
+    routing_fail:
 
     if (out == adev->primary_output) {
         pthread_mutex_lock(&adev->lock);
@@ -5126,15 +5152,29 @@
     err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
     if (err >= 0) {
         val = atoi(value);
-        if (((int)in->device != val) && (val != 0)) {
-            in->device = val;
-            /* If recording is in progress, change the tx device to new device */
-            if (!in->standby && !in->is_st_session) {
-                ALOGV("update input routing change");
-                if (adev->adm_on_routing_change)
+        if (((int)in->device != val) && (val != 0) && audio_is_input_device(val) ) {
+
+            // Workaround: If routing to an non existing usb device, fail gracefully
+            // The routing request will otherwise block during 10 second
+            int card;
+            if (audio_is_usb_in_device(val) &&
+                (card = get_alive_usb_card(parms)) >= 0) {
+
+                ALOGW("in_set_parameters() ignoring rerouting to non existing USB card %d", card);
+                ret = -ENOSYS;
+            } else {
+
+                in->device = val;
+                /* If recording is in progress, change the tx device to new device */
+                if (!in->standby && !in->is_st_session) {
+                    ALOGV("update input routing change");
+                    // inform adm before actual routing to prevent glitches.
+                    if (adev->adm_on_routing_change) {
                         adev->adm_on_routing_change(adev->adm_data,
                                                     in->capture_handle);
-                ret = select_devices(adev, in->usecase);
+                        ret = select_devices(adev, in->usecase);
+                    }
+                }
             }
         }
     }
@@ -6723,6 +6763,10 @@
         channel_count = audio_channel_count_from_in_mask(config->channel_mask);
     } else if (config->format == AUDIO_FORMAT_DEFAULT) {
         config->format = AUDIO_FORMAT_PCM_16_BIT;
+    } else if (property_get_bool("vendor.audio.capture.pcm.32bit.enable", false)
+                                 && config->format == AUDIO_FORMAT_PCM_32_BIT) {
+            in->config.format = PCM_FORMAT_S32_LE;
+            in->bit_width = 32;
     } else if ((config->format == AUDIO_FORMAT_PCM_FLOAT) ||
                (config->format == AUDIO_FORMAT_PCM_32_BIT) ||
                (config->format == AUDIO_FORMAT_PCM_24_BIT_PACKED) ||
diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c
index bdc41a5..7b17ae4 100644
--- a/hal/msm8974/hw_info.c
+++ b/hal/msm8974/hw_info.c
@@ -210,6 +210,7 @@
     SND_DEVICE_IN_SPEAKER_STEREO_DMIC,
 };
 
+
 static const snd_device_t tavil_qrd_variant_devices[] = {
     SND_DEVICE_OUT_SPEAKER,
     SND_DEVICE_OUT_VOICE_SPEAKER,
@@ -218,6 +219,10 @@
     SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET,
 };
 
+static const snd_device_t auto_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER
+};
+
 static void  update_hardware_info_8084(struct hardware_info *hw_info, const char *snd_card_name)
 {
     if (!strcmp(snd_card_name, "apq8084-taiko-mtp-snd-card") ||
@@ -271,6 +276,24 @@
         hw_info->snd_devices = NULL;
         hw_info->num_snd_devices = 0;
         strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "apq8096-auto-snd-card")) {
+        strlcpy(hw_info->type, " dragon-board", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "apq8096", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)auto_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(auto_variant_devices);
+        strlcpy(hw_info->dev_extn, "-db", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "apq8096-adp-agave-snd-card")) {
+        strlcpy(hw_info->type, " agave", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "apq8096", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)auto_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(auto_variant_devices);
+        strlcpy(hw_info->dev_extn, "-agave", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "apq8096-adp-mmxf-snd-card")) {
+        strlcpy(hw_info->type, " mmxf", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "apq8096", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)auto_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(auto_variant_devices);
+        strlcpy(hw_info->dev_extn, "-mmxf", sizeof(hw_info->dev_extn));
     } else {
         ALOGW("%s: Not an 8096 device", __func__);
     }
diff --git a/mm-audio/aenc-aac/qdsp6/test/omx_aac_enc_test.c b/mm-audio/aenc-aac/qdsp6/test/omx_aac_enc_test.c
index 5239a8e..636c38b 100644
--- a/mm-audio/aenc-aac/qdsp6/test/omx_aac_enc_test.c
+++ b/mm-audio/aenc-aac/qdsp6/test/omx_aac_enc_test.c
@@ -1,5 +1,5 @@
 /*--------------------------------------------------------------------------
-Copyright (c) 2010-2014, 2016-2017 The Linux Foundation. All rights reserved.
+Copyright (c) 2010-2014, 2016-2018 The Linux Foundation. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
@@ -271,14 +271,15 @@
     int status = 0;
 
     errno = 0;
-    ptr = (char *)malloc(strlen(input) + 1);
-    if (ptr == NULL) {
-        DEBUG_PRINT("Low memory\n");
+
+    if (input == NULL){
+        DEBUG_PRINT("No input is given\n");
         status = -1;
         goto exit;
     }
-    if (input == NULL){
-        DEBUG_PRINT("No input is given\n");
+    ptr = (char *)malloc(strlen(input) + 1);
+    if (ptr == NULL) {
+        DEBUG_PRINT("Low memory\n");
         status = -1;
         goto exit;
     }
@@ -320,6 +321,8 @@
             break;
     }
 exit:
+    if (ptr != NULL)
+        free(ptr);
     if (status != 0)
         exit(0);
     return value;
diff --git a/mm-audio/aenc-evrc/qdsp6/test/omx_evrc_enc_test.c b/mm-audio/aenc-evrc/qdsp6/test/omx_evrc_enc_test.c
index f9071dc..8053fa1 100644
--- a/mm-audio/aenc-evrc/qdsp6/test/omx_evrc_enc_test.c
+++ b/mm-audio/aenc-evrc/qdsp6/test/omx_evrc_enc_test.c
@@ -1,6 +1,6 @@
 
 /*--------------------------------------------------------------------------
-Copyright (c) 2010-2014, 2017 The Linux Foundation. All rights reserved.
+Copyright (c) 2010-2014, 2017-2018 The Linux Foundation. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
@@ -284,14 +284,15 @@
     int status = 0;
 
     errno = 0;
-    ptr = (char *)malloc(strlen(input) + 1);
-    if (ptr == NULL) {
-        DEBUG_PRINT("Low memory\n");
+
+    if (input == NULL){
+        DEBUG_PRINT("No input is given\n");
         status = -1;
         goto exit;
     }
-    if (input == NULL){
-        DEBUG_PRINT("No input is given\n");
+    ptr = (char *)malloc(strlen(input) + 1);
+    if (ptr == NULL) {
+        DEBUG_PRINT("Low memory\n");
         status = -1;
         goto exit;
     }
@@ -333,6 +334,8 @@
             break;
     }
 exit:
+    if (ptr != NULL)
+        free(ptr);
     if (status != 0)
         exit(0);
     return value;
diff --git a/mm-audio/aenc-qcelp13/qdsp6/test/omx_qcelp13_enc_test.c b/mm-audio/aenc-qcelp13/qdsp6/test/omx_qcelp13_enc_test.c
index 258fd2a..3aa6ff6 100644
--- a/mm-audio/aenc-qcelp13/qdsp6/test/omx_qcelp13_enc_test.c
+++ b/mm-audio/aenc-qcelp13/qdsp6/test/omx_qcelp13_enc_test.c
@@ -1,6 +1,6 @@
 
 /*--------------------------------------------------------------------------
-Copyright (c) 2010-2014, 2017 The Linux Foundation. All rights reserved.
+Copyright (c) 2010-2014, 2017-2018 The Linux Foundation. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
@@ -283,14 +283,15 @@
     int status = 0;
 
     errno = 0;
-    ptr = (char *)malloc(strlen(input) + 1);
-    if (ptr == NULL) {
-        DEBUG_PRINT("Low memory\n");
+
+    if (input == NULL){
+        DEBUG_PRINT("No input is given\n");
         status = -1;
         goto exit;
     }
-    if (input == NULL){
-        DEBUG_PRINT("No input is given\n");
+    ptr = (char *)malloc(strlen(input) + 1);
+    if (ptr == NULL) {
+        DEBUG_PRINT("Low memory\n");
         status = -1;
         goto exit;
     }
@@ -332,6 +333,8 @@
             break;
     }
 exit:
+    if (ptr != NULL)
+        free(ptr);
     if (status != 0)
         exit(0);
     return value;
diff --git a/qahw_api/test/qahw_playback_test.c b/qahw_api/test/qahw_playback_test.c
index d42f89d..ba7f4bf 100644
--- a/qahw_api/test/qahw_playback_test.c
+++ b/qahw_api/test/qahw_playback_test.c
@@ -256,6 +256,8 @@
         pthread_cond_init(&stream_param[i].write_cond, (const pthread_condattr_t *) NULL);
         pthread_mutex_init(&stream_param[i].drain_lock, (const pthread_mutexattr_t *)NULL);
         pthread_cond_init(&stream_param[i].drain_cond, (const pthread_condattr_t *) NULL);
+        pthread_mutex_init(&stream_param[i].input_buffer_available_lock, (const pthread_mutexattr_t *)NULL);
+        pthread_cond_init(&stream_param[i].input_buffer_available_cond, (const pthread_condattr_t *) NULL);
 
         stream_param[i].handle                              =   stream_handle;
         stream_handle--;
@@ -264,6 +266,21 @@
     pthread_cond_init(&dual_main_cond, (const pthread_condattr_t *) NULL);
 }
 
+static void deinit_streams(void)
+{
+    int i = 0;
+    for ( i = 0; i < MAX_PLAYBACK_STREAMS; i++) {
+        pthread_cond_destroy(&stream_param[i].write_cond);
+        pthread_mutex_destroy(&stream_param[i].write_lock);
+        pthread_cond_destroy(&stream_param[i].drain_cond);
+        pthread_mutex_destroy(&stream_param[i].drain_lock);
+        pthread_cond_destroy(&stream_param[i].input_buffer_available_cond);
+        pthread_mutex_destroy(&stream_param[i].input_buffer_available_lock);
+    }
+    pthread_cond_destroy(&dual_main_cond);
+    pthread_mutex_destroy(&dual_main_lock);
+}
+
 void read_kvpair(char *kvpair, char* kvpair_values, int filetype)
 {
     char *kvpair_type = NULL;
@@ -2600,6 +2617,7 @@
         }
     }
 
+    deinit_streams();
     rc = unload_hals();
 
     if ((log_file != stdout) && (log_file != nullptr))
diff --git a/qahw_api/test/qahw_playback_test.h b/qahw_api/test/qahw_playback_test.h
index b643c1d..66229f5 100644
--- a/qahw_api/test/qahw_playback_test.h
+++ b/qahw_api/test/qahw_playback_test.h
@@ -140,9 +140,11 @@
     qahw_mix_matrix_params_t mm_params_downmix;
     int mix_ctrl;
     int pan_scale_ctrl;
+    pthread_cond_t input_buffer_available_cond;
+    pthread_mutex_t input_buffer_available_lock;
+    uint32_t input_buffer_available_size;
 }stream_config;
 
-
 qahw_module_handle_t * load_hal(audio_devices_t dev);
 int unload_hals();
 int get_wav_header_length (FILE* file_stream);
diff --git a/qahw_api/test/qap_wrapper_extn.c b/qahw_api/test/qap_wrapper_extn.c
index 3240cb6..4b27674 100644
--- a/qahw_api/test/qap_wrapper_extn.c
+++ b/qahw_api/test/qap_wrapper_extn.c
@@ -790,7 +790,36 @@
     primary_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)
+void qap_wrapper_module_callback(qap_module_handle_t module_handle, void* priv_data, qap_module_callback_event_t event_id, int size, void *data)
+{
+    stream_config *p_stream_param = (stream_config*)priv_data;
+    if(p_stream_param == NULL) {
+        ALOGE("%s %d, callback handle is null.",__func__,__LINE__);
+    }
+    ALOGV("%s %d Received event id %d\n", __func__, __LINE__, event_id);
+
+    switch (event_id) {
+        case QAP_MODULE_CALLBACK_EVENT_SEND_INPUT_BUFFER:
+        {
+            if (size < sizeof(qap_send_buffer_t)) {
+                ALOGE("%s %d event id %d, wrong payload size %d\n",
+                      __func__, __LINE__, event_id, size);
+                break;
+            }
+            qap_send_buffer_t *p_send_buffer_event = (qap_send_buffer_t*)data;
+            pthread_mutex_lock(&p_stream_param->input_buffer_available_lock);
+            p_stream_param->input_buffer_available_size = p_send_buffer_event->bytes_available;
+            pthread_cond_signal(&p_stream_param->input_buffer_available_cond);
+            pthread_mutex_unlock(&p_stream_param->input_buffer_available_lock);
+
+            break;
+        }
+        default:
+        break;
+    }
+}
+
+void qap_wrapper_session_callback(qap_session_handle_t session_handle __unused, void* priv_data __unused, qap_callback_event_t event_id, int size, void *data)
 {
     int ret = 0;
     int bytes_written = 0;
@@ -1368,7 +1397,7 @@
         }
     }
 
-    ret = qap_session_set_callback(qap_session_handle, &qap_wrapper_session_callback);
+    ret = qap_session_set_callback(qap_session_handle, &qap_wrapper_session_callback, NULL);
     if (ret != QAP_STATUS_OK) {
         fprintf(stderr, "!!!! Please specify appropriate Session\n");
         return -EINVAL;
@@ -1556,6 +1585,7 @@
                       __FUNCTION__, __LINE__,bytes_read, bytes_consumed);
             if (stream_info->filetype == FILE_DTS) {
                 if (bytes_consumed < 0) {
+#if 0
                     while (!is_buffer_available) {
                         usleep(1000);
                         ret = qap_module_cmd(qap_module_handle, QAP_MODULE_CMD_GET_PARAM,
@@ -1570,7 +1600,24 @@
                         ALOGV("%s : %d, dts clip reply_data is %d buffer availabale is %d",
                               __FUNCTION__, __LINE__, reply_data, is_buffer_available);
                     }
+#else
+                    pthread_mutex_lock(&stream_info->input_buffer_available_lock);
+                    stream_info->input_buffer_available_size = 0;
+                    pthread_mutex_unlock(&stream_info->input_buffer_available_lock);
 
+                    while (buffer->common_params.size > stream_info->input_buffer_available_size) {
+                        ALOGV("%s %d: %s waiting for input buffer availability.",
+                                     __FUNCTION__, __LINE__, stream_info->filename);
+                        pthread_mutex_lock(&stream_info->input_buffer_available_lock);
+                        pthread_cond_wait(&stream_info->input_buffer_available_cond,
+                                          &stream_info->input_buffer_available_lock);
+                        pthread_mutex_unlock(&stream_info->input_buffer_available_lock);
+                        ALOGV("%s %d: %s input buffer available, size %lu.",
+                                     __FUNCTION__, __LINE__,
+                                     stream_info->filename,
+                                     stream_info->input_buffer_available_size);
+                    }
+#endif
                     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;
@@ -1633,20 +1680,15 @@
 
 qap_module_handle_t qap_wrapper_stream_open(void* stream_data)
 {
-    qap_module_config_t *input_config = NULL;
+    qap_module_config_t input_config = {0};
     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;
+    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;
@@ -1655,18 +1697,18 @@
     input_streams_count++;
     if (input_streams_count == 2) {
         if (stream_info->filetype == FILE_WAV) {
-            input_config->flags = QAP_MODULE_FLAG_SYSTEM_SOUND;
+            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;
+                 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;
+                input_config.flags = QAP_MODULE_FLAG_PRIMARY;
                 stream_info->sec_input = true;
             }
         }
@@ -1674,29 +1716,31 @@
     } 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;
+            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;
+            input_config.flags = QAP_MODULE_FLAG_PRIMARY;
         }
     }
 
     if (!encode)
-        input_config->module_type = QAP_MODULE_DECODER;
+        input_config.module_type = QAP_MODULE_DECODER;
     else
-        input_config->module_type = QAP_MODULE_ENCODER;
+        input_config.module_type = QAP_MODULE_ENCODER;
 
-    ret = qap_wrapper_map_input_format(stream_info->config.offload_info.format, &input_config->format);
+    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);
+    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;
     }
 
+    qap_module_set_callback(qap_module_handle, &qap_wrapper_module_callback, stream_info);
+
     primary_stream_close = false;
     stream_cnt++;
     return qap_module_handle;