Merge "post_proc: fix crash in offload effect bundle during stop output"
diff --git a/audiod/Android.mk b/audiod/Android.mk
index c382c9d..c89b3cd 100644
--- a/audiod/Android.mk
+++ b/audiod/Android.mk
@@ -1,7 +1,10 @@
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
+
+ifneq (,$(findstring $(PLATFORM_VERSION), 5.0 5.1 5.1.1))
 include external/stlport/libstlport.mk
+endif
 
 LOCAL_SRC_FILES:= \
 	audiod_main.cpp \
@@ -13,8 +16,11 @@
 	libcutils \
 	libutils \
 	libbinder \
-	libmedia \
-	libstlport
+	libmedia
+
+ifneq (,$(findstring $(PLATFORM_VERSION), 5.0 5.1 5.1.1))
+LOCAL_SHARED_LIBRARIES += libstlport
+endif
 
 LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
 
diff --git a/audiod/AudioDaemon.cpp b/audiod/AudioDaemon.cpp
index b4857c4..6f38218 100644
--- a/audiod/AudioDaemon.cpp
+++ b/audiod/AudioDaemon.cpp
@@ -125,6 +125,7 @@
         struct dirent* in_file;
         int fd;
         String8 path;
+        String8 d_name;
 
         if ((dp = opendir(events_dir)) == NULL) {
             ALOGE("Cannot open switch directory to get list of audio events %s", events_dir);
@@ -148,8 +149,9 @@
             if (fd == -1) {
                 ALOGE("Open %s failed : %s", path.string(), strerror(errno));
             } else {
-                mAudioEvents.push_back(std::make_pair(in_file->d_name, fd));
-                mAudioEventsStatus.push_back(std::make_pair(in_file->d_name, 0));
+                d_name = in_file->d_name;
+                mAudioEvents.push_back(std::make_pair(d_name, fd));
+                mAudioEventsStatus.push_back(std::make_pair(d_name, 0));
                 ALOGD("event status mAudioEventsStatus= %s",
                           mAudioEventsStatus[0].first.string());
             }
diff --git a/hal/Android.mk b/hal/Android.mk
index e0149f9..315aab2 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -53,6 +53,7 @@
 LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
 
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HDMI_EDID)),true)
+    LOCAL_CFLAGS += -DHDMI_EDID
     LOCAL_SRC_FILES += edid.c
 endif
 
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 7bbe2f8..e443f06 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -46,6 +46,9 @@
 #define AUDIO_FORMAT_PCM_24_BIT_OFFLOAD (AUDIO_FORMAT_PCM_OFFLOAD | AUDIO_FORMAT_PCM_SUB_8_24_BIT)
 #define AUDIO_OFFLOAD_CODEC_FORMAT  "music_offload_codec_format"
 #define audio_is_offload_pcm(format) (0)
+#define OFFLOAD_USE_SMALL_BUFFER false
+#else
+#define OFFLOAD_USE_SMALL_BUFFER (info->use_small_bufs)
 #endif
 
 #ifndef AFE_PROXY_ENABLED
@@ -316,6 +319,9 @@
 void audio_extn_dolby_set_dmid(struct audio_device *adev);
 #else
 #define audio_extn_dolby_set_dmid(adev)                 (0)
+#define AUDIO_CHANNEL_OUT_PENTA (AUDIO_CHANNEL_OUT_QUAD | AUDIO_CHANNEL_OUT_FRONT_CENTER)
+#define AUDIO_CHANNEL_OUT_SURROUND (AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT | \
+                                    AUDIO_CHANNEL_OUT_FRONT_CENTER | AUDIO_CHANNEL_OUT_BACK_CENTER)
 #endif
 
 
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
index 669842e..5ea5a43 100644
--- a/hal/audio_extn/spkr_protection.c
+++ b/hal/audio_extn/spkr_protection.c
@@ -35,6 +35,7 @@
 #include <math.h>
 #include <cutils/log.h>
 #include <fcntl.h>
+#include <dirent.h>
 #include "audio_hw.h"
 #include "platform.h"
 #include "platform_api.h"
@@ -61,6 +62,9 @@
 #define MIN_RESISTANCE_SPKR_Q24 (2 * (1 << 24))
 #define MAX_RESISTANCE_SPKR_Q24 (40 * (1 << 24))
 
+/*Number of Attempts for WSA equilibrium t0 reads*/
+#define NUM_ATTEMPTS 5
+
 /*Path where the calibration file will be stored*/
 #define CALIB_FILE "/data/misc/audio/audio.cal"
 
@@ -86,6 +90,10 @@
 #define SPKR_PROCESSING_IN_PROGRESS 1
 #define SPKR_PROCESSING_IN_IDLE 0
 
+#define MAX_PATH             (256)
+#define THERMAL_SYSFS "/sys/class/thermal"
+#define TZ_TYPE "/sys/class/thermal/thermal_zone%d/type"
+#define TZ_WSA "/sys/class/thermal/thermal_zone%d/temp"
 /*Modes of Speaker Protection*/
 enum speaker_protection_mode {
     SPKR_PROTECTION_DISABLED = -1,
@@ -117,7 +125,12 @@
     int (*thermal_client_request)(char *client_name, int req_data);
     bool spkr_prot_enable;
     bool spkr_in_use;
-   struct timespec spkr_last_time_used;
+    struct timespec spkr_last_time_used;
+    bool wsa_found;
+    char *spkr_1_tz_name;
+    char *spkr_2_tz_name;
+    int spkr_1_tzn;
+    int spkr_2_tzn;
 };
 
 static struct pcm_config pcm_config_skr_prot = {
@@ -134,6 +147,93 @@
 static struct speaker_prot_session handle;
 static int vi_feed_no_channels;
 
+int read_line_from_file(const char *path, char *buf, size_t count)
+{
+    char * fgets_ret;
+    FILE * fd;
+    int rv;
+
+    fd = fopen(path, "r");
+    if (fd == NULL)
+        return -1;
+
+    fgets_ret = fgets(buf, (int)count, fd);
+    if (NULL != fgets_ret) {
+        rv = (int)strlen(buf);
+    } else {
+        rv = ferror(fd);
+    }
+    fclose(fd);
+
+   return rv;
+}
+
+/*===========================================================================
+FUNCTION get_tzn
+
+Utility function to match a sensor name with thermal zone id.
+
+ARGUMENTS
+	sensor_name - name of sensor to match
+
+RETURN VALUE
+	Thermal zone id on success,
+	-1 on failure.
+===========================================================================*/
+int get_tzn(const char *sensor_name)
+{
+    DIR *tdir = NULL;
+    struct dirent *tdirent = NULL;
+    int found = -1;
+    int tzn = 0;
+    char name[MAX_PATH] = {0};
+    char cwd[MAX_PATH] = {0};
+
+    if (!getcwd(cwd, sizeof(cwd)))
+        return found;
+
+    chdir(THERMAL_SYSFS); /* Change dir to read the entries. Doesnt work
+                             otherwise */
+    tdir = opendir(THERMAL_SYSFS);
+    if (!tdir) {
+        ALOGE("Unable to open %s\n", THERMAL_SYSFS);
+        return found;
+    }
+
+    while ((tdirent = readdir(tdir))) {
+        char buf[50];
+        struct dirent *tzdirent;
+        DIR *tzdir = NULL;
+
+        tzdir = opendir(tdirent->d_name);
+        if (!tzdir)
+            continue;
+        while ((tzdirent = readdir(tzdir))) {
+            if (strcmp(tzdirent->d_name, "type"))
+                continue;
+            snprintf(name, MAX_PATH, TZ_TYPE, tzn);
+            ALOGD("Opening %s\n", name);
+            read_line_from_file(name, buf, sizeof(buf));
+            buf[strlen(sensor_name)] = '\0';
+            if (!strcmp(buf, sensor_name)) {
+                found = 1;
+                break;
+            }
+            tzn++;
+        }
+        closedir(tzdir);
+        if (found == 1)
+            break;
+    }
+    closedir(tdir);
+    chdir(cwd); /* Restore current working dir */
+    if (found == 1) {
+        found = tzn;
+        ALOGE("Sensor %s found at tz: %d\n", sensor_name, tzn);
+    }
+    return found;
+}
+
 static void spkr_prot_set_spkrstatus(bool enable)
 {
     struct timespec ts;
@@ -302,7 +402,7 @@
      return -EINVAL;
 }
 
-static int spkr_calibrate(int t0)
+static int spkr_calibrate(int t0_spk_1, int t0_spk_2)
 {
     struct audio_device *adev = handle.adev_handle;
     struct audio_cal_info_spk_prot_cfg protCfg;
@@ -328,9 +428,8 @@
         return -ENODEV;
     } else {
         protCfg.mode = MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS;
-        /* HAL for speaker protection gets only one Temperature */
-        protCfg.t0[SP_V2_SPKR_1] = t0;
-        protCfg.t0[SP_V2_SPKR_2] = t0;
+        protCfg.t0[SP_V2_SPKR_1] = t0_spk_1;
+        protCfg.t0[SP_V2_SPKR_2] = t0_spk_2;
         if (set_spkr_prot_cal(acdb_fd, &protCfg)) {
             ALOGE("%s: spkr_prot_thread set failed AUDIO_SET_SPEAKER_PROT",
             __func__);
@@ -534,13 +633,20 @@
 {
     unsigned long sec = 0;
     int t0;
+    int i = 0;
+    int t0_spk_1 = 0;
+    int t0_spk_2 = 0;
+    int t0_spk_prior = 0;
     bool goahead = false;
     struct audio_cal_info_spk_prot_cfg protCfg;
     FILE *fp;
-    int acdb_fd;
+    int acdb_fd, thermal_fd;
     struct audio_device *adev = handle.adev_handle;
     unsigned long min_idle_time = MIN_SPKR_IDLE_SEC;
     char value[PROPERTY_VALUE_MAX];
+    char wsa_path[MAX_PATH] = {0};
+    int spk_1_tzn, spk_2_tzn;
+    char buf[32] = {0};
 
     /* If the value of this persist.spkr.cal.duration is 0
      * then it means it will take 30min to calibrate
@@ -620,7 +726,93 @@
 
     while (1) {
         ALOGV("%s: start calibration", __func__);
-        if (!handle.thermal_client_request("spkr",1)) {
+        if (handle.wsa_found) {
+            spk_1_tzn = handle.spkr_1_tzn;
+            spk_2_tzn = handle.spkr_2_tzn;
+            goahead = false;
+            pthread_mutex_lock(&adev->lock);
+            if (is_speaker_in_use(&sec)) {
+                ALOGD("%s: WSA Speaker in use retry calibration", __func__);
+                pthread_mutex_unlock(&adev->lock);
+                continue;
+            } else {
+                ALOGD("%s: wsa speaker idle %ld min time %ld", __func__, sec, min_idle_time);
+                if (sec < min_idle_time) {
+                    ALOGD("%s: speaker idle is less retry", __func__);
+                    pthread_mutex_unlock(&adev->lock);
+                    continue;
+               }
+               goahead = true;
+           }
+           if (!list_empty(&adev->usecase_list)) {
+                ALOGD("%s: Usecase active re-try calibration", __func__);
+                goahead = false;
+           }
+           if (goahead) {
+               if (spk_1_tzn >= 0) {
+                   snprintf(wsa_path, MAX_PATH, TZ_WSA, spk_1_tzn);
+                   ALOGD("%s: wsa_path: %s\n", __func__, wsa_path);
+                   thermal_fd = -1;
+                   thermal_fd = open(wsa_path, O_RDONLY);
+                   if (thermal_fd > 0) {
+                       for (i = 0; i < NUM_ATTEMPTS; i++) {
+                            if (read(thermal_fd, buf, sizeof(buf))) {
+                                t0_spk_1 = atoi(buf);
+                                if (i > 0 && (t0_spk_1 != t0_spk_prior))
+                                    break;
+                                t0_spk_prior = t0_spk_1;
+                            } else {
+                               ALOGE("%s: read fail for %s\n", __func__, wsa_path);
+                               break;
+                            }
+                        }
+                        close(thermal_fd);
+                   } else {
+                       ALOGE("%s: fd for %s is NULL\n", __func__, wsa_path);
+                   }
+                   if (i == NUM_ATTEMPTS) {
+                       /*Convert temp into q6 format*/
+                       t0_spk_1 = (t0_spk_1 * (1 << 6));
+                       ALOGE("%s: temp T0 for spkr1 %d\n", __func__, t0_spk_1);
+                   } else {
+                       ALOGE("%s: thermal equilibrium failed for spkr1 in %d readings\n",
+                                                __func__, NUM_ATTEMPTS);
+                       t0_spk_1 = SAFE_SPKR_TEMP_Q6;
+                   }
+               }
+               if (spk_2_tzn >= 0) {
+                   snprintf(wsa_path, MAX_PATH, TZ_WSA, spk_2_tzn);
+                   ALOGE("%s: wsa_path: %s\n", __func__, wsa_path);
+                   thermal_fd = open(wsa_path, O_RDONLY);
+                   if (thermal_fd > 0) {
+                       for (i = 0; i < NUM_ATTEMPTS; i++) {
+                            if (read(thermal_fd, buf, sizeof(buf))) {
+                                t0_spk_2 = atoi(buf);
+                                if (i > 0 && (t0_spk_2 != t0_spk_prior))
+                                    break;
+                                t0_spk_prior = t0_spk_2;
+                            } else {
+                               ALOGE("%s: read fail for %s\n", __func__, wsa_path);
+                               break;
+                            }
+                        }
+                        close(thermal_fd);
+                   } else {
+                       ALOGE("%s: fd for %s is NULL\n", __func__, wsa_path);
+                   }
+                   if (i == NUM_ATTEMPTS) {
+                       /*Convert temp into q6 format*/
+                       t0_spk_2 = (t0_spk_2 * (1 << 6));
+                       ALOGE("%s: temp T0 for spkr2 %d\n", __func__, t0_spk_2);
+                   } else {
+                       ALOGE("%s: thermal equilibrium failed for spkr2 in %d readings\n",
+                                                __func__, NUM_ATTEMPTS);
+                       t0_spk_2 = SAFE_SPKR_TEMP_Q6;
+                   }
+               }
+           }
+           pthread_mutex_unlock(&adev->lock);
+        } else if (!handle.thermal_client_request("spkr",1)) {
             ALOGD("%s: wait for callback from thermal daemon", __func__);
             pthread_mutex_lock(&handle.spkr_prot_thermalsync_mutex);
             pthread_cond_wait(&handle.spkr_prot_thermalsync,
@@ -633,12 +825,15 @@
                       handle.spkr_prot_t0);
                 continue;
             }
+            t0_spk_1 = t0;
+            t0_spk_2 = t0;
             ALOGD("%s: Request t0 success value %d", __func__,
             handle.spkr_prot_t0);
         } else {
             ALOGE("%s: Request t0 failed", __func__);
             /*Assume safe value for temparature*/
-            t0 = SAFE_SPKR_TEMP_Q6;
+            t0_spk_1 = SAFE_SPKR_TEMP_Q6;
+            t0_spk_2 = SAFE_SPKR_TEMP_Q6;
         }
         goahead = false;
         pthread_mutex_lock(&adev->lock);
@@ -662,7 +857,7 @@
         }
         if (goahead) {
                 int status;
-                status = spkr_calibrate(t0);
+                status = spkr_calibrate(t0_spk_1, t0_spk_2);
                 pthread_mutex_unlock(&adev->lock);
                 if (status == -EAGAIN) {
                     ALOGE("%s: failed to calibrate try again %s",
@@ -696,6 +891,17 @@
     return 0;
 }
 
+static bool is_wsa_present(void)
+{
+   handle.spkr_1_tz_name = platform_get_spkr_1_tz_name(SND_DEVICE_OUT_SPEAKER);
+   handle.spkr_2_tz_name = platform_get_spkr_2_tz_name(SND_DEVICE_OUT_SPEAKER);
+   handle.spkr_1_tzn = get_tzn(handle.spkr_1_tz_name);
+   handle.spkr_2_tzn = get_tzn(handle.spkr_2_tz_name);
+   if ((handle.spkr_1_tzn >= 0) || (handle.spkr_2_tzn >= 0))
+        handle.wsa_found = true;
+   return handle.wsa_found;
+}
+
 void audio_extn_spkr_prot_init(void *adev)
 {
     char value[PROPERTY_VALUE_MAX];
@@ -717,6 +923,17 @@
     handle.spkr_prot_mode = MSM_SPKR_PROT_DISABLED;
     handle.spkr_processing_state = SPKR_PROCESSING_IN_IDLE;
     handle.spkr_prot_t0 = -1;
+
+    if (is_wsa_present()) {
+        pthread_cond_init(&handle.spkr_calib_cancel, NULL);
+        pthread_cond_init(&handle.spkr_calibcancel_ack, NULL);
+        pthread_mutex_init(&handle.mutex_spkr_prot, NULL);
+        pthread_mutex_init(&handle.spkr_calib_cancelack_mutex, NULL);
+        ALOGD("%s:WSA Create calibration thread", __func__);
+        (void)pthread_create(&handle.spkr_calibration_thread,
+        (const pthread_attr_t *) NULL, spkr_calibration_thread, &handle);
+        return;
+    }
     pthread_cond_init(&handle.spkr_prot_thermalsync, NULL);
     pthread_cond_init(&handle.spkr_calib_cancel, NULL);
     pthread_cond_init(&handle.spkr_calibcancel_ack, NULL);
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 3dbf159..7ad4811 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -71,7 +71,9 @@
 #ifdef COMPRESS_VOIP_ENABLED
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_VOIP_RX),
 #endif
+#ifdef HDMI_PASSTHROUGH_ENABLED
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH),
+#endif
 };
 
 const struct string_to_enum s_format_name_to_enum_table[] = {
@@ -566,8 +568,11 @@
     app_type_cfg[len++] = out->app_type_cfg.app_type;
     app_type_cfg[len++] = acdb_dev_id;
     if (((out->format == AUDIO_FORMAT_E_AC3) ||
-        (out->format == AUDIO_FORMAT_E_AC3_JOC)) &&
-        (out->flags  & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH))
+        (out->format == AUDIO_FORMAT_E_AC3_JOC))
+#ifdef HDMI_PASSTHROUGH_ENABLED
+        && (out->flags  & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH)
+#endif
+        )
         app_type_cfg[len++] = sample_rate * 4;
     else
         app_type_cfg[len++] = sample_rate;
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index daafa77..80f56a4 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -2921,7 +2921,7 @@
         if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
             out->non_blocking = 1;
 
-        if (config->offload_info.use_small_bufs) {
+        if (platform_use_small_buffer(&config->offload_info)) {
             //this flag is set from framework only if its for PCM formats
             //no need to check for PCM format again
             out->non_blocking = 0;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 67f5279..5e61d36 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -38,6 +38,7 @@
 #ifndef QCOM_AUDIO_HW_H
 #define QCOM_AUDIO_HW_H
 
+#include <stdlib.h>
 #include <cutils/list.h>
 #include <hardware/audio.h>
 #include <tinyalsa/asoundlib.h>
diff --git a/hal/edid.h b/hal/edid.h
index ec83ec8..0d7fbe6 100644
--- a/hal/edid.h
+++ b/hal/edid.h
@@ -92,5 +92,9 @@
     int  channel_allocation;
 } edid_audio_info;
 
+#ifndef HDMI_EDID
+#define edid_get_sink_caps(info, edid_data) (0)
+#else
 bool edid_get_sink_caps(edid_audio_info* info, char *edid_data);
+#endif
 #endif /* EDID_H */
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index b5b7cb7..8d47a8b 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -68,17 +68,14 @@
 #define COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING (2 * 1024)
 #define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024)
 /* Used in calculating fragment size for pcm offload */
-#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV 1000 /* 1 sec */
-#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING 80 /* 80 millisecs */
-#define PCM_OFFLOAD_BUFFER_DURATION_FOR_SMALL_BUFFERS 20 /* 20 millisecs */
-#define PCM_OFFLOAD_BUFFER_DURATION_MAX 1200  /* 1200 millisecs */
+#define PCM_OFFLOAD_BUFFER_DURATION 40 /* 40 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
  * 24 - lcm of channels supported by DSP
  */
 #define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024)
-#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE (4 * 1024)
+#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE  512
 
 /*
  * Offload buffer size for compress passthrough
@@ -2009,7 +2006,7 @@
         goto exit;
     }
 
-    if (popcount(devices) == 2) {
+    if (popcount(devices) == 2 && !voice_is_in_call(adev)) {
         if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
                         AUDIO_DEVICE_OUT_SPEAKER)) {
             if (my_data->external_spk_1)
@@ -2048,7 +2045,8 @@
         goto exit;
     }
 
-    if (voice_is_in_call(adev) || voice_extn_compress_voip_is_active(adev)) {
+    if ((mode == AUDIO_MODE_IN_CALL) ||
+        voice_extn_compress_voip_is_active(adev)) {
         if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
             devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
             if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
@@ -2197,8 +2195,8 @@
     ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
           __func__, out_device, in_device);
     if (my_data->external_mic) {
-        if ((out_device != AUDIO_DEVICE_NONE && voice_is_in_call(adev)) ||
-            voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev)) {
+        if ((out_device != AUDIO_DEVICE_NONE) && ((mode == AUDIO_MODE_IN_CALL) ||
+            voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev))) {
             if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
                out_device & AUDIO_DEVICE_OUT_EARPIECE ||
                out_device & AUDIO_DEVICE_OUT_SPEAKER )
@@ -2212,7 +2210,7 @@
     if (snd_device != AUDIO_DEVICE_NONE)
         goto exit;
 
-    if ((out_device != AUDIO_DEVICE_NONE) && ((voice_is_in_call(adev)) ||
+    if ((out_device != AUDIO_DEVICE_NONE) && ((mode == AUDIO_MODE_IN_CALL) ||
         voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev))) {
         if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
             !voice_extn_compress_voip_is_active(adev)) {
@@ -3268,25 +3266,13 @@
 {
     uint32_t fragment_size = 0;
     uint32_t bits_per_sample = 16;
-    uint32_t pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_SMALL_BUFFERS;
+    uint32_t pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION;
 
     if (info->format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) {
         bits_per_sample = 32;
     }
 
-    if (info->use_small_bufs) {
-        pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_SMALL_BUFFERS;
-    } else {
-        if (!info->has_video) {
-            pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_MAX;
-        } else if (info->has_video && info->is_streaming) {
-            pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING;
-        } else if (info->has_video) {
-            pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_AV;
-        }
-    }
-
-    //duration is set to 20 ms worth of stereo data at 48Khz
+    //duration is set to 40 ms worth of stereo data at 48Khz
     //with 16 bit per sample, modify this when the channel
     //configuration is different
     fragment_size = (pcm_offload_time
@@ -4090,3 +4076,57 @@
 done:
     return ret;
 }
+
+/*
+ * This is a lookup table to map names of speaker device with respective left and right TZ names.
+ * Also the tz names for a particular left or right speaker can be overriden by adding
+ * corresponding entry in audio_platform_info.xml file.
+ */
+struct speaker_device_to_tz_names speaker_device_tz_names = {
+    {SND_DEVICE_OUT_SPEAKER, "", ""},
+};
+
+const char *platform_get_spkr_1_tz_name(snd_device_t snd_device)
+{
+    if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX)
+        return speaker_device_tz_names.spkr_1_tz_name;
+    else
+        return "";
+}
+
+const char *platform_get_spkr_2_tz_name(snd_device_t snd_device)
+{
+    if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX)
+        return speaker_device_tz_names.spkr_2_tz_name;
+    else
+        return "";
+}
+
+int platform_set_spkr_device_tz_names(snd_device_t index,
+                                      const char *spkr_1_tz_name, const char *spkr_2_tz_name)
+{
+    int ret = 0;
+
+    if (spkr_1_tz_name == NULL && spkr_2_tz_name == NULL) {
+        ALOGE("%s: Invalid input", __func__);
+        ret = -EINVAL;
+        goto done;
+    }
+    if (index != speaker_device_tz_names.snd_device) {
+        ALOGE("%s: not matching speaker device\n");
+        ret = -EINVAL;
+        goto done;
+    }
+    ALOGD("%s: Enter, spkr_1_tz_name :%s, spkr_2_tz_name:%s",
+            __func__, spkr_1_tz_name, spkr_2_tz_name);
+
+    if (spkr_1_tz_name != NULL)
+        strlcpy(speaker_device_tz_names.spkr_1_tz_name, spkr_1_tz_name,
+                sizeof(speaker_device_tz_names.spkr_1_tz_name));
+
+    if (spkr_2_tz_name != NULL)
+        strlcpy(speaker_device_tz_names.spkr_2_tz_name, spkr_2_tz_name,
+                sizeof(speaker_device_tz_names.spkr_2_tz_name));
+done:
+    return ret;
+}
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index aae05d0..3ce4c57 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -306,4 +306,10 @@
     char device_name[100];
     char interface_name[100];
 };
+
+struct speaker_device_to_tz_names {
+    snd_device_t snd_device;
+    char spkr_1_tz_name[100];
+    char spkr_2_tz_name[100];
+};
 #endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index f9b7851..1d5d1e6 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -667,7 +667,7 @@
         goto exit;
     }
 
-    if (voice_is_in_call(adev)) {
+    if (mode == AUDIO_MODE_IN_CALL) {
         if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
             devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
             if (adev->voice.tty_mode == TTY_MODE_FULL)
@@ -759,7 +759,7 @@
 
     ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
           __func__, out_device, in_device);
-    if ((out_device != AUDIO_DEVICE_NONE) && voice_is_in_call(adev)) {
+    if ((out_device != AUDIO_DEVICE_NONE) && (mode == AUDIO_MODE_IN_CALL)) {
         if (adev->voice.tty_mode != TTY_MODE_OFF) {
             if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
                 out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
@@ -1098,6 +1098,11 @@
     return 0;
 }
 
+bool platform_use_small_buffer(audio_offload_info_t* info)
+{
+    return false;
+}
+
 int platform_get_edid_info(void *platform __unused)
 {
    return -ENOSYS;
@@ -1160,3 +1165,9 @@
 {
     return -ENOSYS;
 }
+
+int platform_set_spkr_device_tz_names(snd_device_t index,
+                                      const char *spkr_1_tz_name, const char *spkr_2_tz_name)
+{
+    return -ENOSYS;
+}
diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c
index c96d11e..7849644 100644
--- a/hal/msm8974/hw_info.c
+++ b/hal/msm8974/hw_info.c
@@ -134,6 +134,10 @@
     SND_DEVICE_IN_HANDSET_MIC_EXTERNAL
 };
 
+static const snd_device_t tasha_DB_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER
+};
+
 static const snd_device_t taiko_apq8084_sbc_variant_devices[] = {
     SND_DEVICE_IN_HANDSET_MIC,
     SND_DEVICE_IN_SPEAKER_MIC,
@@ -278,6 +282,12 @@
         hw_info->snd_devices = (snd_device_t *)tomtom_liquid_variant_devices;
         hw_info->num_snd_devices = ARRAY_SIZE(tomtom_liquid_variant_devices);
         strlcpy(hw_info->dev_extn, "-liquid", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8996-tasha-db-snd-card")) {
+        strlcpy(hw_info->type, " dragon-board", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8996", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)tasha_DB_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(tasha_DB_variant_devices);
+        strlcpy(hw_info->dev_extn, "-db", sizeof(hw_info->dev_extn));
     } else {
         ALOGW("%s: Not a 8996 device", __func__);
     }
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 28a75df..eccf5b0 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -65,17 +65,14 @@
 #define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024)
 
 /* Used in calculating fragment size for pcm offload */
-#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV 1000 /* 1 sec */
-#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING 80 /* 80 millisecs */
-#define PCM_OFFLOAD_BUFFER_DURATION_FOR_SMALL_BUFFERS 20 /* 20 millisecs */
-#define PCM_OFFLOAD_BUFFER_DURATION_MAX 1200  /* 1200 millisecs */
+#define PCM_OFFLOAD_BUFFER_DURATION 40 /* 40 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
  * 24 - lcm of channels supported by DSP
  */
 #define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024)
-#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE (4 * 1024)
+#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE 512
 
 /*
  * Offload buffer size for compress passthrough
@@ -696,6 +693,14 @@
 static int msm_be_id_array_len  =
     sizeof(msm_device_to_be_id) / sizeof(msm_device_to_be_id[0]);
 
+/*
+ * This is a lookup table to map names of speaker device with respective left and right TZ names.
+ * Also the tz names for a particular left or right speaker can be overriden by adding
+ * corresponding entry in audio_platform_info.xml file.
+ */
+struct speaker_device_to_tz_names speaker_device_tz_names = {
+    {SND_DEVICE_OUT_SPEAKER, "", ""},
+};
 
 #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
 #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
@@ -1375,6 +1380,22 @@
         return "";
 }
 
+const char *platform_get_spkr_1_tz_name(snd_device_t snd_device)
+{
+    if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX)
+        return speaker_device_tz_names.spkr_1_tz_name;
+    else
+        return "";
+}
+
+const char *platform_get_spkr_2_tz_name(snd_device_t snd_device)
+{
+    if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX)
+        return speaker_device_tz_names.spkr_2_tz_name;
+    else
+        return "";
+}
+
 int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device,
                                       char *device_name)
 {
@@ -1995,7 +2016,7 @@
         goto exit;
     }
 
-    if (popcount(devices) == 2) {
+    if (popcount(devices) == 2 && !voice_is_in_call(adev)) {
         if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
                         AUDIO_DEVICE_OUT_SPEAKER)) {
             if (my_data->external_spk_1)
@@ -2034,7 +2055,7 @@
         goto exit;
     }
 
-    if (voice_is_in_call(adev) ||
+    if ((mode == AUDIO_MODE_IN_CALL) ||
         voice_extn_compress_voip_is_active(adev)) {
         if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
             devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
@@ -2157,8 +2178,8 @@
     ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
           __func__, out_device, in_device);
     if (my_data->external_mic) {
-        if ((out_device != AUDIO_DEVICE_NONE && voice_is_in_call(adev)) ||
-            voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev)) {
+        if ((out_device != AUDIO_DEVICE_NONE) && ((mode == AUDIO_MODE_IN_CALL) ||
+            voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev))) {
             if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
                out_device & AUDIO_DEVICE_OUT_EARPIECE ||
                out_device & AUDIO_DEVICE_OUT_SPEAKER )
@@ -2172,7 +2193,7 @@
     if (snd_device != AUDIO_DEVICE_NONE)
         goto exit;
 
-    if ((out_device != AUDIO_DEVICE_NONE) && ((voice_is_in_call(adev)) ||
+    if ((out_device != AUDIO_DEVICE_NONE) && ((mode == AUDIO_MODE_IN_CALL) ||
         voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev))) {
         if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
             !voice_extn_compress_voip_is_active(adev)) {
@@ -3150,25 +3171,13 @@
 {
     uint32_t fragment_size = 0;
     uint32_t bits_per_sample = 16;
-    uint32_t pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_SMALL_BUFFERS;
+    uint32_t pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION;
 
     if (info->format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) {
         bits_per_sample = 32;
     }
 
-    if (info->use_small_bufs) {
-        pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_SMALL_BUFFERS;
-    } else {
-        if (!info->has_video) {
-            pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_MAX;
-        } else if (info->has_video && info->is_streaming) {
-            pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING;
-        } else if (info->has_video) {
-            pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_AV;
-        }
-    }
-
-    //duration is set to 20 ms worth of stereo data at 48Khz
+    //duration is set to 40 ms worth of stereo data at 48Khz
     //with 16 bit per sample, modify this when the channel
     //configuration is different
     fragment_size = (pcm_offload_time
@@ -3188,6 +3197,11 @@
     return fragment_size;
 }
 
+bool platform_use_small_buffer(audio_offload_info_t* info)
+{
+    return OFFLOAD_USE_SMALL_BUFFER;
+}
+
 int platform_set_codec_backend_cfg(struct audio_device* adev,
                          snd_device_t snd_device,
                          unsigned int bit_width, unsigned int sample_rate)
@@ -3993,3 +4007,32 @@
 done:
     return ret;
 }
+
+int platform_set_spkr_device_tz_names(snd_device_t index,
+                                      const char *spkr_1_tz_name, const char *spkr_2_tz_name)
+{
+    int ret = 0;
+
+    if (spkr_1_tz_name == NULL && spkr_2_tz_name == NULL) {
+        ALOGE("%s: Invalid input", __func__);
+        ret = -EINVAL;
+        goto done;
+    }
+    if (index != speaker_device_tz_names.snd_device) {
+        ALOGE("%s: not matching speaker device\n");
+        ret = -EINVAL;
+        goto done;
+    }
+    ALOGD("%s: Enter, spkr_1_tz_name :%s, spkr_2_tz_name:%s",
+           __func__, spkr_1_tz_name, spkr_2_tz_name);
+
+    if (spkr_1_tz_name != NULL)
+        strlcpy(speaker_device_tz_names.spkr_1_tz_name, spkr_1_tz_name,
+                sizeof(speaker_device_tz_names.spkr_1_tz_name));
+
+    if (spkr_2_tz_name != NULL)
+        strlcpy(speaker_device_tz_names.spkr_2_tz_name, spkr_2_tz_name,
+                sizeof(speaker_device_tz_names.spkr_2_tz_name));
+done:
+    return ret;
+}
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 6b0f13e..4b90f8b 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -396,4 +396,10 @@
     char device_name[100];
     char interface_name[100];
 };
+
+struct speaker_device_to_tz_names {
+    snd_device_t snd_device;
+    char spkr_1_tz_name[100];
+    char spkr_2_tz_name[100];
+};
 #endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 7e86174..59cb554 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -92,6 +92,7 @@
 struct audio_offload_info_t;
 uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info);
 uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info);
+bool platform_use_small_buffer(audio_offload_info_t* info);
 uint32_t platform_get_compress_passthrough_buffer_size(audio_offload_info_t* info);
 
 bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev,
@@ -115,4 +116,8 @@
 int platform_set_device_params(struct stream_out *out, int param, int value);
 int platform_set_audio_device_interface(const char * device_name, const char *intf_name,
                                         const char * codec_type);
+int platform_set_spkr_device_tz_names(snd_device_t index,
+                                       const char *spkr_1_tz_name, const char *spkr_2_tz_name);
+const char *platform_get_spkr_1_tz_name(snd_device_t snd_device);
+const char *platform_get_spkr_2_tz_name(snd_device_t snd_device);
 #endif // AUDIO_PLATFORM_API_H
diff --git a/hal/platform_info.c b/hal/platform_info.c
index 02f4988..e6cc15d 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -48,6 +48,7 @@
     PCM_ID,
     BACKEND_NAME,
     INTERFACE_NAME,
+    TZ_NAME,
 } section_t;
 
 typedef void (* section_process_fn)(const XML_Char **attr);
@@ -58,6 +59,7 @@
 static void process_pcm_id(const XML_Char **attr);
 static void process_backend_name(const XML_Char **attr);
 static void process_interface_name(const XML_Char **attr);
+static void process_tz_name(const XML_Char **attr);
 static void process_root(const XML_Char **attr);
 
 static section_process_fn section_table[] = {
@@ -68,6 +70,7 @@
     [PCM_ID] = process_pcm_id,
     [BACKEND_NAME] = process_backend_name,
     [INTERFACE_NAME] = process_interface_name,
+    [TZ_NAME] = process_tz_name,
 };
 
 static section_t section;
@@ -94,6 +97,11 @@
  * ...
  * ...
  * </interface_names>
+ * <tz_names>
+ * <device name="???" spkr_1_tz_name="???" spkr_2_tz_name="???"/>
+ * ...
+ * ...
+ * </tz_names>
  * </audio_platform_info>
  */
 
@@ -308,6 +316,42 @@
     return;
 }
 
+static void process_tz_name(const XML_Char **attr)
+{
+    int ret, index;
+
+    if (strcmp(attr[0], "name") != 0) {
+        ALOGE("%s: 'name' not found, no Audio Interface set!", __func__);
+        goto done;
+    }
+
+    index = platform_get_snd_device_index((char *)attr[1]);
+    if (index < 0) {
+        ALOGE("%s: Device %s not found, no snd device set!",
+              __func__, attr[1]);
+        goto done;
+    }
+
+    if (strcmp(attr[2], "spkr_1_tz_name") != 0) {
+        ALOGE("%s: Device %s has no spkr_1_tz_name set!",
+              __func__, attr[1]);
+    }
+
+    if (strcmp(attr[4], "spkr_2_tz_name") != 0) {
+        ALOGE("%s: Device %s has no spkr_2_tz_name set!",
+              __func__, attr[1]);
+    }
+
+    ret = platform_set_spkr_device_tz_names(index, (char *)attr[3], (char *)attr[5]);
+    if (ret < 0) {
+        ALOGE("%s: Audio Interface not set!", __func__);
+        goto done;
+    }
+
+done:
+    return;
+}
+
 static void start_tag(void *userdata __unused, const XML_Char *tag_name,
                       const XML_Char **attr)
 {
@@ -327,10 +371,12 @@
         section = INTERFACE_NAME;
     } else if (strcmp(tag_name, "native_configs") == 0) {
         section = NATIVESUPPORT;
+    } else if (strcmp(tag_name, "tz_names") == 0) {
+        section = TZ_NAME;
     } else if (strcmp(tag_name, "device") == 0) {
         if ((section != ACDB) && (section != BACKEND_NAME) && (section != BITWIDTH) &&
-            (section != INTERFACE_NAME)) {
-            ALOGE("device tag only supported for acdb/backend names/bitwitdh/interface names");
+            (section != INTERFACE_NAME) && (section != TZ_NAME)) {
+            ALOGE("device tag only supported for acdb/backend names/bitwitdh/interface/tz names");
             return;
         }
 
diff --git a/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp b/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp
index 6af9269..4cfee1b 100644
--- a/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp
+++ b/mm-audio/aenc-aac/qdsp6/src/omx_aac_aenc.cpp
@@ -4208,6 +4208,16 @@
                buffer->nOffset = 0;
                buffer->nTimeStamp = nTimestamp;
                frame_done_cb((OMX_BUFFERHEADERTYPE *)buffer);
+
+               if (errno == ENETRESET)
+               {
+                   ALOGE("In SSR, return error to close the session");
+                   m_cb.EventHandler(&m_cmp,
+                       m_app_data,
+                      OMX_EventError,
+                      OMX_ErrorHardware,
+                      0, NULL );
+               }
                return OMX_ErrorNone;
            }
         }
diff --git a/post_proc/Android.mk b/post_proc/Android.mk
index be70166..192320a 100644
--- a/post_proc/Android.mk
+++ b/post_proc/Android.mk
@@ -14,8 +14,12 @@
 	virtualizer.c \
 	reverb.c \
 	effect_api.c \
-	effect_util.c \
-        hw_accelerator.c
+	effect_util.c
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HW_ACCELERATED_EFFECTS)),true)
+    LOCAL_CFLAGS += -DHW_ACCELERATED_EFFECTS
+    LOCAL_SRC_FILES += hw_accelerator.c
+endif
 
 LOCAL_CFLAGS+= -O2 -fvisibility=hidden
 
@@ -68,3 +72,32 @@
 
 include $(BUILD_STATIC_LIBRARY)
 endif
+
+
+################################################################################
+
+ifneq ($(filter msm8992 msm8994 msm8996 msm8952,$(TARGET_BOARD_PLATFORM)),)
+
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS := -DLIB_AUDIO_HAL="/system/lib/hw/audio.primary."$(TARGET_BOARD_PLATFORM)".so"
+
+LOCAL_SRC_FILES:= \
+        volume_listener.c
+
+LOCAL_CFLAGS+= -O2 -fvisibility=hidden
+
+LOCAL_SHARED_LIBRARIES := \
+        libcutils \
+        liblog \
+        libdl
+
+LOCAL_MODULE_RELATIVE_PATH := soundfx
+LOCAL_MODULE:= libvolumelistener
+
+LOCAL_C_INCLUDES := \
+        $(call include-path-for, audio-effects)
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/post_proc/bundle.c b/post_proc/bundle.c
index bb21f7e..6f1bdfa 100644
--- a/post_proc/bundle.c
+++ b/post_proc/bundle.c
@@ -38,6 +38,7 @@
 #define LOG_TAG "offload_effect_bundle"
 //#define LOG_NDEBUG 0
 
+#include <stdlib.h>
 #include <cutils/list.h>
 #include <cutils/log.h>
 #include <system/thread_defs.h>
@@ -69,7 +70,9 @@
         &ins_env_reverb_descriptor,
         &aux_preset_reverb_descriptor,
         &ins_preset_reverb_descriptor,
+#ifdef HW_ACCELERATED_EFFECTS
         &hw_accelerator_descriptor,
+#endif
         NULL,
 };
 
@@ -604,6 +607,7 @@
             reverb_preset_init(reverb_ctxt);
         }
         reverb_ctxt->ctl = NULL;
+#ifdef HW_ACCELERATED_EFFECTS
     } else if (memcmp(uuid, &hw_accelerator_descriptor.uuid,
                sizeof(effect_uuid_t)) == 0) {
         hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)
@@ -625,6 +629,7 @@
         context->ops.process = hw_accelerator_process;
 
         context->desc = &hw_accelerator_descriptor;
+#endif
     } else {
         return -EINVAL;
     }
@@ -911,6 +916,7 @@
 
         } break;
 
+#ifdef HW_ACCELERATED_EFFECTS
     case EFFECT_CMD_HW_ACC: {
         ALOGV("EFFECT_CMD_HW_ACC cmdSize %d pCmdData %p, *replySize %d, pReplyData %p",
               cmdSize, pCmdData, *replySize, pReplyData);
@@ -925,6 +931,7 @@
         context->hw_acc_enabled = (value > 0) ? true : false;
         break;
     }
+#endif
     default:
         if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
             status = context->ops.command(context, cmdCode, cmdSize,
diff --git a/post_proc/effect_api.c b/post_proc/effect_api.c
index e15db17..16c370b 100644
--- a/post_proc/effect_api.c
+++ b/post_proc/effect_api.c
@@ -55,6 +55,7 @@
 #endif
 
 #include <stdbool.h>
+#include <errno.h>
 #include <cutils/log.h>
 #include <tinyalsa/asoundlib.h>
 #include <sound/audio_effects.h>
diff --git a/post_proc/effect_util.c b/post_proc/effect_util.c
index 8f7a604..52f623d 100644
--- a/post_proc/effect_util.c
+++ b/post_proc/effect_util.c
@@ -16,6 +16,7 @@
 
 #include <utils/Log.h>
 #include <stdlib.h>
+#include <string.h>
 #include "effect_util.h"
 
 #ifdef LOG_TAG
diff --git a/post_proc/volume_listener.c b/post_proc/volume_listener.c
new file mode 100644
index 0000000..51f8803
--- /dev/null
+++ b/post_proc/volume_listener.c
@@ -0,0 +1,769 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of The Linux Foundation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "volume_listener"
+//#define LOG_NDEBUG 0
+#include <stdlib.h>
+#include <dlfcn.h>
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <hardware/audio_effect.h>
+#include <cutils/properties.h>
+
+#define PRIMARY_HAL_PATH XSTR(LIB_AUDIO_HAL)
+#define XSTR(x) STR(x)
+#define STR(x) #x
+
+#define VOL_FLAG ( EFFECT_FLAG_TYPE_INSERT | \
+                   EFFECT_FLAG_VOLUME_IND | \
+                   EFFECT_FLAG_DEVICE_IND | \
+                   EFFECT_FLAG_OFFLOAD_SUPPORTED)
+
+#define PRINT_STREAM_TYPE(i) ALOGV("descriptor found and is of stream type %s ",\
+                                                            i == MUSIC?"MUSIC": \
+                                                            i == RING?"RING": \
+                                                            i == ALARM?"ALARM": \
+                                                            i == VOICE_CALL?"Voice_call": \
+                                                            i == NOTIFICATION?"Notification":\
+                                                            "--INVALID--"); \
+
+#define MAX_GAIN_LEVELS 5
+
+#define AHAL_GAIN_DEPENDENT_INTERFACE_FUNCTION "audio_hw_send_gain_dep_calibration"
+
+enum {
+    VOL_LISTENER_STATE_UNINITIALIZED,
+    VOL_LISTENER_STATE_INITIALIZED,
+    VOL_LISTENER_STATE_ACTIVE,
+};
+
+typedef struct vol_listener_context_s vol_listener_context_t;
+static const struct effect_interface_s effect_interface;
+
+/* flag to avoid multiple initialization */
+static bool initialized = false;
+
+/* current gain dep cal level that was pushed succesfully */
+static int current_gain_dep_cal_level = -1;
+
+enum STREAM_TYPE {
+    MUSIC,
+    RING,
+    ALARM,
+    VOICE_CALL,
+    NOTIFICATION,
+    MAX_STREAM_TYPES,
+};
+
+struct vol_listener_context_s {
+    const struct effect_interface_s *itfe;
+    struct listnode effect_list_node;
+    effect_config_t config;
+    const effect_descriptor_t *desc;
+    uint32_t stream_type;
+    uint32_t session_id;
+    uint32_t state;
+    uint32_t dev_id;
+    float left_vol;
+    float right_vol;
+};
+
+/* volume listener, music UUID: 08b8b058-0590-11e5-ac71-0025b32654a0 */
+const effect_descriptor_t vol_listener_music_descriptor = {
+    { 0x08b8b058, 0x0590, 0x11e5, 0xac71, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } },  // type
+    { 0x08b8b058, 0x0590, 0x11e5, 0xac71, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } },  // uuid
+    EFFECT_CONTROL_API_VERSION,
+    VOL_FLAG,
+    0, /* TODO */
+    1,
+    "Volume listener for Music",
+    "Qualcomm Technologies Inc.",
+};
+
+/* volume listener, ring UUID: 0956df94-0590-11e5-bdbe-0025b32654a0 */
+const effect_descriptor_t vol_listener_ring_descriptor = {
+    { 0x0956df94, 0x0590, 0x11e5, 0xbdbe, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // type
+    { 0x0956df94, 0x0590, 0x11e5, 0xbdbe, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // uuid
+    EFFECT_CONTROL_API_VERSION,
+    VOL_FLAG,
+    0, /* TODO */
+    1,
+    "Volume listener for ring",
+    "Qualcomm Technologies Inc",
+};
+
+/* volume listener, alarm UUID: 09f303e2-0590-11e5-8fdb-0025b32654a0 */
+const effect_descriptor_t vol_listener_alarm_descriptor = {
+    { 0x09f303e2, 0x0590, 0x11e5, 0x8fdb, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // type
+    { 0x09f303e2, 0x0590, 0x11e5, 0x8fdb, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // uuid
+    EFFECT_CONTROL_API_VERSION,
+    VOL_FLAG,
+    0, /* TODO */
+    1,
+    "Volume listener for alarm",
+    "Qualcomm Technologies Inc",
+};
+
+/* volume listener, voice call UUID: 0ace5c08-0590-11e5-ae9e-0025b32654a0 */
+const effect_descriptor_t vol_listener_voice_call_descriptor = {
+    { 0x0ace5c08, 0x0590, 0x11e5, 0xae9e, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // type
+    { 0x0ace5c08, 0x0590, 0x11e5, 0xae9e, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // uuid
+    EFFECT_CONTROL_API_VERSION,
+    VOL_FLAG,
+    0, /* TODO */
+    1,
+    "Volume listener for voice call",
+    "Qualcomm Technologies Inc",
+};
+
+/* volume listener, notification UUID: 0b776dde-0590-11e5-81ba-0025b32654a0 */
+const effect_descriptor_t vol_listener_notification_descriptor = {
+    { 0x0b776dde, 0x0590, 0x11e5, 0x81ba, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // type
+    { 0x0b776dde, 0x0590, 0x11e5, 0x81ba, { 0x00, 0x25, 0xb3, 0x26, 0x54, 0xa0 } }, // uuid
+    EFFECT_CONTROL_API_VERSION,
+    VOL_FLAG,
+    0, /* TODO */
+    1,
+    "Volume listener for notification",
+    "Qualcomm Technologies Inc",
+};
+
+struct amp_db_and_gain_table {
+    float amp;
+    float db;
+    uint32_t level;
+} amp_to_dBLevel_table;
+
+// using gain level for non-drc volume curve
+static const struct amp_db_and_gain_table  volume_curve_gain_mapping_table[MAX_GAIN_LEVELS] = {
+    /* Level 0 in the calibration database contains default calibration */
+    { 0.001774, -55, 5 },
+    { 0.501187,  -6, 4 },
+    { 0.630957,  -4, 3 },
+    { 0.794328,  -2, 2 },
+    { 1.0,        0, 1 },
+};
+
+static const effect_descriptor_t *descriptors[] = {
+    &vol_listener_music_descriptor,
+    &vol_listener_ring_descriptor,
+    &vol_listener_alarm_descriptor,
+    &vol_listener_voice_call_descriptor,
+    &vol_listener_notification_descriptor,
+    NULL,
+};
+
+pthread_once_t once = PTHREAD_ONCE_INIT;
+/* flag to indicate if init was success */
+static int init_status;
+
+/* current volume level for which gain dep cal level was selected */
+static float current_vol = 0.0;
+
+/* HAL interface to send calibration */
+static bool (*send_gain_dep_cal)(int);
+
+/* if dumping allowed */
+static bool dumping_enabled = false;
+
+/* list of created effects. */
+struct listnode vol_effect_list;
+
+/* lock must be held when modifying or accessing created_effects_list */
+pthread_mutex_t vol_listner_init_lock;
+
+/*
+ *  Local functions
+ */
+static void dump_list_l()
+{
+    struct listnode *node;
+    vol_listener_context_t *context;
+
+    ALOGW("DUMP_START :: ===========");
+
+    list_for_each(node, &vol_effect_list) {
+        context = node_to_item(node, struct vol_listener_context_s, effect_list_node);
+        // dump stream_type / Device / session_id / left / righ volume
+        ALOGW("%s: streamType [%s] Device [%d] state [%d] sessionID [%d] volume (L/R) [%f / %f] ",
+        __func__,
+        context->stream_type == MUSIC ? "MUSIC" :
+        context->stream_type == RING ? "RING" :
+        context->stream_type == ALARM ? "ALARM" :
+        context->stream_type == VOICE_CALL ? "VOICE_CALL" :
+        context->stream_type == NOTIFICATION ? "NOTIFICATION" : "--INVALID--",
+        context->dev_id, context->state, context->session_id, context->left_vol,context->right_vol);
+    }
+
+    ALOGW("DUMP_END :: ===========");
+}
+
+static void check_and_set_gain_dep_cal()
+{
+    // iterate through list and make decision to set new gain dep cal level for speaker device
+    // 1. find all usecase active on speaker
+    // 2. find average of left and right for each usecase
+    // 3. find the highest of all the active usecase
+    // 4. if new value is different than the current value then load new calibration
+
+    struct listnode *node = NULL;
+    float new_vol = 0.0;
+    int max_level = 0;
+    vol_listener_context_t *context = NULL;
+    if (dumping_enabled) {
+        dump_list_l();
+    }
+
+    ALOGV("%s ==> Start ...", __func__);
+
+    // select the highest volume on speaker device
+    list_for_each(node, &vol_effect_list) {
+        context = node_to_item(node, struct vol_listener_context_s, effect_list_node);
+        if ((context->state == VOL_LISTENER_STATE_ACTIVE) &&
+            (context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) &&
+            (new_vol < (context->left_vol + context->right_vol) / 2)) {
+            new_vol = (context->left_vol + context->right_vol) / 2;
+        }
+    }
+
+    if (new_vol != current_vol) {
+        ALOGV("%s:: Change in decision :: current volume is %f new volume is %f",
+              __func__, current_vol, new_vol);
+
+        if (send_gain_dep_cal != NULL) {
+            // send Gain dep cal level
+            int gain_dep_cal_level = -1;
+
+            if (new_vol >= 1) { // max amplitude, use highest DRC level
+                gain_dep_cal_level = volume_curve_gain_mapping_table[MAX_GAIN_LEVELS - 1].level;
+            } else if (new_vol <= 0) {
+                gain_dep_cal_level = volume_curve_gain_mapping_table[0].level;
+            } else {
+                for (max_level = 0; max_level + 1 < MAX_GAIN_LEVELS; max_level++) {
+                    if (new_vol < volume_curve_gain_mapping_table[max_level + 1].amp &&
+                        new_vol >= volume_curve_gain_mapping_table[max_level].amp) {
+                        gain_dep_cal_level = volume_curve_gain_mapping_table[max_level].level;
+                        ALOGV("%s: volume(%f), gain dep cal selcetd %d ",
+                              __func__, current_vol, gain_dep_cal_level);
+                        break;
+                    }
+                }
+            }
+
+            // check here if previous gain dep cal level was not same
+            if (gain_dep_cal_level != -1) {
+                if (gain_dep_cal_level != current_gain_dep_cal_level) {
+                    // decision made .. send new level now
+                    if (!send_gain_dep_cal(gain_dep_cal_level)) {
+                        ALOGE("%s: Failed to set gain dep cal level", __func__);
+                    } else {
+                        // Success in setting the gain dep cal level, store new level and Volume
+                        if (dumping_enabled) {
+                            ALOGW("%s: (old/new) Volume (%f/%f) (old/new) level (%d/%d)",
+                                  __func__, current_vol, new_vol, current_gain_dep_cal_level,
+                                  gain_dep_cal_level);
+                        } else {
+                            ALOGV("%s: Change in Cal::(old/new) Volume (%f/%f) (old/new) level (%d/%d)",
+                                  __func__, current_vol, new_vol, current_gain_dep_cal_level,
+                                  gain_dep_cal_level);
+                        }
+                        current_gain_dep_cal_level = gain_dep_cal_level;
+                        current_vol = new_vol;
+                    }
+                } else {
+                    if (dumping_enabled) {
+                        ALOGW("%s: volume changed but gain dep cal level is still the same",
+                              __func__);
+                    } else {
+                        ALOGV("%s: volume changed but gain dep cal level is still the same",
+                              __func__);
+                    }
+                }
+            } else {
+                ALOGW("%s: Failed to find gain dep cal level for volume %f", __func__, new_vol);
+            }
+        } else {
+            ALOGE("%s: not able to send calibration, NULL function pointer",
+                  __func__);
+        }
+    } else {
+        ALOGV("%s:: volume not changed, stick to same config ..... ", __func__);
+    }
+
+    ALOGV("check_and_set_gain_dep_cal ==> End ");
+}
+
+/*
+ * Effect Control Interface Implementation
+ */
+
+static int vol_effect_process(effect_handle_t self,
+                              audio_buffer_t *in_buffer,
+                              audio_buffer_t *out_buffer)
+{
+    int status = 0;
+    ALOGV("%s Called ", __func__);
+
+    vol_listener_context_t *context = (vol_listener_context_t *)self;
+    pthread_mutex_lock(&vol_listner_init_lock);
+
+    if (context->state != VOL_LISTENER_STATE_ACTIVE) {
+        ALOGE("%s: state is not active .. return error", __func__);
+        status = -EINVAL;
+        goto exit;
+    }
+
+    // calculation based on channel count 2
+    if (in_buffer->raw != out_buffer->raw) {
+        memcpy(out_buffer->raw, in_buffer->raw, out_buffer->frameCount * 2 * sizeof(int16_t));
+    } else {
+        ALOGW("%s: something wrong, didn't handle in_buffer and out_buffer same address case",
+              __func__);
+    }
+
+exit:
+    pthread_mutex_unlock(&vol_listner_init_lock);
+    return status;
+}
+
+
+static int vol_effect_command(effect_handle_t self,
+                              uint32_t cmd_code, uint32_t cmd_size,
+                              void *p_cmd_data, uint32_t *reply_size,
+                              void *p_reply_data)
+{
+    vol_listener_context_t *context = (vol_listener_context_t *)self;
+    int status = 0;
+
+    ALOGV("%s Called ", __func__);
+    pthread_mutex_lock(&vol_listner_init_lock);
+
+    if (context == NULL || context->state == VOL_LISTENER_STATE_UNINITIALIZED) {
+        ALOGE("%s: %s is NULL", __func__, (context == NULL) ?
+              "context" : "context->state");
+        status = -EINVAL;
+        goto exit;
+    }
+
+    switch (cmd_code) {
+    case EFFECT_CMD_INIT:
+        ALOGV("%s :: cmd called EFFECT_CMD_INIT", __func__);
+        if (p_reply_data == NULL || *reply_size != sizeof(int)) {
+            ALOGE("%s: EFFECT_CMD_INIT: %s, sending -EINVAL", __func__,
+                  (p_reply_data == NULL) ? "p_reply_data is NULL" :
+                  "*reply_size != sizeof(int)");
+            return -EINVAL;
+        }
+        *(int *)p_reply_data = 0;
+        break;
+
+    case EFFECT_CMD_SET_CONFIG:
+        ALOGV("%s :: cmd called EFFECT_CMD_SET_CONFIG", __func__);
+        break;
+
+    case EFFECT_CMD_GET_CONFIG:
+        ALOGV("%s :: cmd called EFFECT_CMD_GET_CONFIG", __func__);
+        break;
+
+    case EFFECT_CMD_RESET:
+        ALOGV("%s :: cmd called EFFECT_CMD_RESET", __func__);
+        break;
+
+    case EFFECT_CMD_SET_AUDIO_MODE:
+        ALOGV("%s :: cmd called EFFECT_CMD_SET_AUDIO_MODE", __func__);
+        break;
+
+    case EFFECT_CMD_OFFLOAD:
+        ALOGV("%s :: cmd called EFFECT_CMD_OFFLOAD", __func__);
+        if (p_reply_data == NULL || *reply_size != sizeof(int)) {
+            ALOGE("%s: EFFECT_CMD_OFFLOAD: %s, sending -EINVAL", __func__,
+                  (p_reply_data == NULL) ? "p_reply_data is NULL" :
+                  "*reply_size != sizeof(int)");
+            return -EINVAL;
+        }
+        *(int *)p_reply_data = 0;
+        break;
+
+    case EFFECT_CMD_ENABLE:
+        ALOGV("%s :: cmd called EFFECT_CMD_ENABLE", __func__);
+        if (p_reply_data == NULL || *reply_size != sizeof(int)) {
+            ALOGE("%s: EFFECT_CMD_ENABLE: %s, sending -EINVAL", __func__,
+                   (p_reply_data == NULL) ? "p_reply_data is NULL" :
+                   "*reply_size != sizeof(int)");
+            status = -EINVAL;
+            goto exit;
+        }
+
+        if (context->state != VOL_LISTENER_STATE_INITIALIZED) {
+            ALOGE("%s: EFFECT_CMD_ENABLE : state not INITIALIZED", __func__);
+            status = -ENOSYS;
+            goto exit;
+        }
+
+        context->state = VOL_LISTENER_STATE_ACTIVE;
+        *(int *)p_reply_data = 0;
+
+        // After changing the state and if device is speaker
+        // recalculate gain dep cal level
+        if (context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) {
+                check_and_set_gain_dep_cal();
+        }
+
+        break;
+
+    case EFFECT_CMD_DISABLE:
+        ALOGV("%s :: cmd called EFFECT_CMD_DISABLE", __func__);
+        if (p_reply_data == NULL || *reply_size != sizeof(int)) {
+            ALOGE("%s: EFFECT_CMD_DISABLE: %s, sending -EINVAL", __func__,
+                  (p_reply_data == NULL) ? "p_reply_data is NULL" :
+                  "*reply_size != sizeof(int)");
+            status = -EINVAL;
+            goto exit;
+        }
+
+        if (context->state != VOL_LISTENER_STATE_ACTIVE) {
+            ALOGE("%s: EFFECT_CMD_ENABLE : state not ACTIVE", __func__);
+            status = -ENOSYS;
+            goto exit;
+        }
+
+        context->state = VOL_LISTENER_STATE_INITIALIZED;
+        *(int *)p_reply_data = 0;
+
+        // After changing the state and if device is speaker
+        // recalculate gain dep cal level
+        if (context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) {
+            check_and_set_gain_dep_cal();
+        }
+
+        break;
+
+    case EFFECT_CMD_GET_PARAM:
+        ALOGV("%s :: cmd called EFFECT_CMD_GET_PARAM", __func__);
+        break;
+
+    case EFFECT_CMD_SET_PARAM:
+        ALOGV("%s :: cmd called EFFECT_CMD_SET_PARAM", __func__);
+        break;
+
+    case EFFECT_CMD_SET_DEVICE:
+        {
+            uint32_t new_device;
+            bool recompute_gain_dep_cal_Level = false;
+            ALOGV("cmd called EFFECT_CMD_SET_DEVICE ");
+
+            if (p_cmd_data == NULL) {
+                ALOGE("%s: EFFECT_CMD_SET_DEVICE: cmd data NULL", __func__);
+                status = -EINVAL;
+                goto exit;
+            }
+
+            new_device = *(uint32_t *)p_cmd_data;
+            ALOGV("%s :: EFFECT_CMD_SET_DEVICE: (current/new) device (0x%x / 0x%x)",
+                   __func__, context->dev_id, new_device);
+
+            // check if old or new device is speaker
+            if ((context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) ||
+                (new_device & AUDIO_DEVICE_OUT_SPEAKER)) {
+                recompute_gain_dep_cal_Level = true;
+            }
+
+            context->dev_id = new_device;
+
+            if (recompute_gain_dep_cal_Level) {
+                check_and_set_gain_dep_cal();
+            }
+        }
+        break;
+
+    case EFFECT_CMD_SET_VOLUME:
+        {
+            float left_vol = 0, right_vol = 0;
+            bool recompute_gain_dep_cal_Level = false;
+
+            ALOGV("cmd called EFFECT_CMD_SET_VOLUME");
+            if (p_cmd_data == NULL || cmd_size != 2 * sizeof(uint32_t)) {
+                ALOGE("%s: EFFECT_CMD_SET_VOLUME: %s", __func__, (p_cmd_data == NULL) ?
+                      "p_cmd_data is NULL" : "cmd_size issue");
+                status = -EINVAL;
+                goto exit;
+            }
+
+            if (context->dev_id & AUDIO_DEVICE_OUT_SPEAKER) {
+                recompute_gain_dep_cal_Level = true;
+            }
+
+            left_vol = (float)(*(uint32_t *)p_cmd_data) / (1 << 24);
+            right_vol = (float)(*((uint32_t *)p_cmd_data + 1)) / (1 << 24);
+            ALOGV("Current Volume (%f / %f ) new Volume (%f / %f)", context->left_vol,
+                  context->right_vol, left_vol, right_vol);
+
+            context->left_vol = left_vol;
+            context->right_vol = right_vol;
+
+            // recompute gan dep cal level only if volume changed on speaker device
+            if (recompute_gain_dep_cal_Level) {
+                check_and_set_gain_dep_cal();
+            }
+        }
+        break;
+
+    default:
+        ALOGW("volume_listener_command invalid command %d", cmd_code);
+        status = -ENOSYS;
+        break;
+    }
+
+exit:
+    pthread_mutex_unlock(&vol_listner_init_lock);
+    return status;
+}
+
+/* Effect Control Interface Implementation: get_descriptor */
+static int vol_effect_get_descriptor(effect_handle_t   self,
+                                     effect_descriptor_t *descriptor)
+{
+    vol_listener_context_t *context = (vol_listener_context_t *)self;
+    ALOGV("%s Called ", __func__);
+
+    if (descriptor == NULL) {
+        ALOGE("%s: descriptor is NULL", __func__);
+        return -EINVAL;
+    }
+
+    *descriptor = *context->desc;
+    return 0;
+}
+
+static void init_once()
+{
+    int i = 0;
+    if (initialized) {
+        ALOGV("%s : already init .. do nothing", __func__);
+        return;
+    }
+
+    ALOGD("%s Called ", __func__);
+    pthread_mutex_init(&vol_listner_init_lock, NULL);
+
+    // get hal function pointer
+    if (access(PRIMARY_HAL_PATH, R_OK) == 0) {
+        void *hal_lib_pointer = dlopen(PRIMARY_HAL_PATH, RTLD_NOW);
+        if (hal_lib_pointer == NULL) {
+            ALOGE("%s: DLOPEN failed for %s", __func__, PRIMARY_HAL_PATH);
+            send_gain_dep_cal = NULL;
+        } else {
+            ALOGV("%s: DLOPEN of %s Succes .. next get HAL entry function", __func__, PRIMARY_HAL_PATH);
+            send_gain_dep_cal = (bool (*)(int))dlsym(hal_lib_pointer, AHAL_GAIN_DEPENDENT_INTERFACE_FUNCTION);
+            if (send_gain_dep_cal == NULL) {
+                ALOGE("Couldnt able to get the function symbol");
+            }
+        }
+    } else {
+        ALOGE("%s: not able to acces lib %s ", __func__, PRIMARY_HAL_PATH);
+        send_gain_dep_cal = NULL;
+    }
+
+    // check system property to see if dumping is required
+    char check_dump_val[PROPERTY_VALUE_MAX];
+    property_get("audio.volume.listener.dump", check_dump_val, "0");
+    if (atoi(check_dump_val)) {
+        dumping_enabled = true;
+    }
+
+    init_status = 0;
+    list_init(&vol_effect_list);
+    initialized = true;
+}
+
+static int lib_init()
+{
+    pthread_once(&once, init_once);
+    ALOGV("%s Called ", __func__);
+    return init_status;
+}
+
+static int vol_prc_lib_create(const effect_uuid_t *uuid,
+                              int32_t session_id,
+                              int32_t io_id,
+                              effect_handle_t *p_handle)
+{
+    int itt = 0;
+    vol_listener_context_t *context = NULL;
+
+    ALOGV("volume_prc_lib_create .. called ..");
+
+    if (lib_init() != 0) {
+        return init_status;
+    }
+
+    if (p_handle == NULL || uuid == NULL) {
+        ALOGE("%s: %s is NULL", __func__, (p_handle == NULL) ? "p_handle" : "uuid");
+        return -EINVAL;
+    }
+
+    context = (vol_listener_context_t *)calloc(1, sizeof(vol_listener_context_t));
+
+    if (context == NULL) {
+        ALOGE("%s: failed to allocate for context .. oops !!", __func__);
+        return -EINVAL;
+    }
+
+    // check if UUID is supported
+    for (itt = 0; descriptors[itt] != NULL; itt++) {
+        if (memcmp(uuid, &descriptors[itt]->uuid, sizeof(effect_uuid_t)) == 0) {
+            // check if this correct .. very imp
+            context->desc = descriptors[itt];
+            context->stream_type = itt;
+            PRINT_STREAM_TYPE(itt)
+            break;
+        }
+    }
+
+    if (descriptors[itt] == NULL) {
+        ALOGE("%s .. couldnt find passed uuid, something wrong", __func__);
+        free(context);
+        return -EINVAL;
+    }
+
+    ALOGV("%s CREATED_CONTEXT %p", __func__, context);
+
+    context->itfe = &effect_interface;
+    context->state = VOL_LISTENER_STATE_INITIALIZED;
+    context->dev_id = AUDIO_DEVICE_NONE;
+    context->session_id = session_id;
+
+    // Add this to master list
+    pthread_mutex_lock(&vol_listner_init_lock);
+    list_add_tail(&vol_effect_list, &context->effect_list_node);
+    if (dumping_enabled) {
+        dump_list_l();
+    }
+    pthread_mutex_unlock(&vol_listner_init_lock);
+
+    *p_handle = (effect_handle_t)context;
+    return 0;
+}
+
+static int vol_prc_lib_release(effect_handle_t handle)
+{
+    struct listnode *node = NULL;
+    vol_listener_context_t *context = NULL;
+    vol_listener_context_t *recv_contex = (vol_listener_context_t *)handle;
+    int status = -1;
+    bool recompute_flag = false;
+    int active_stream_count = 0;
+    ALOGV("%s context %p", __func__, handle);
+    pthread_mutex_lock(&vol_listner_init_lock);
+
+    // check if the handle/context provided is valid
+    list_for_each(node, &vol_effect_list) {
+        context = node_to_item(node, struct vol_listener_context_s, effect_list_node);
+        if ((memcmp(&(context->desc->uuid), &(recv_contex->desc->uuid), sizeof(effect_uuid_t)) == 0)
+            && (context->session_id == recv_contex->session_id)
+            && (context->stream_type == recv_contex->stream_type)) {
+            ALOGV("--- Found something to remove ---");
+            list_remove(&context->effect_list_node);
+            PRINT_STREAM_TYPE(context->stream_type);
+            if (context->dev_id && AUDIO_DEVICE_OUT_SPEAKER) {
+                recompute_flag = true;
+            }
+            free(context);
+            status = 0;
+        } else {
+            ++active_stream_count;
+        }
+    }
+
+    if (status != 0) {
+        ALOGE("something wrong ... <<<--- Found NOTHING to remove ... ???? --->>>>>");
+    }
+
+    // if there are no active streams, reset cal and volume level
+    if (active_stream_count == 0) {
+        current_gain_dep_cal_level = -1;
+        current_vol = 0.0;
+    }
+
+    if (recompute_flag) {
+        check_and_set_gain_dep_cal();
+    }
+
+    if (dumping_enabled) {
+        dump_list_l();
+    }
+    pthread_mutex_unlock(&vol_listner_init_lock);
+    return status;
+}
+
+static int vol_prc_lib_get_descriptor(const effect_uuid_t *uuid,
+                                      effect_descriptor_t *descriptor)
+{
+    int i = 0;
+    ALOGV("%s Called ", __func__);
+    if (lib_init() != 0) {
+        return init_status;
+    }
+
+    if (descriptor == NULL || uuid == NULL) {
+        ALOGE("%s: %s is NULL", __func__, (descriptor == NULL) ? "descriptor" : "uuid");
+        return -EINVAL;
+    }
+
+    for (i = 0; descriptors[i] != NULL; i++) {
+        if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
+            *descriptor = *descriptors[i];
+            return 0;
+        }
+    }
+
+    ALOGE("%s: couldnt found uuid passed, oops", __func__);
+    return  -EINVAL;
+}
+
+
+/* effect_handle_t interface implementation for volume listener effect */
+static const struct effect_interface_s effect_interface = {
+    vol_effect_process,
+    vol_effect_command,
+    vol_effect_get_descriptor,
+    NULL,
+};
+
+__attribute__((visibility("default")))
+audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
+    .tag = AUDIO_EFFECT_LIBRARY_TAG,
+    .version = EFFECT_LIBRARY_API_VERSION,
+    .name = "Volume Listener Effect Library",
+    .implementor = "Qualcomm Technologies Inc.",
+    .create_effect = vol_prc_lib_create,
+    .release_effect = vol_prc_lib_release,
+    .get_descriptor = vol_prc_lib_get_descriptor,
+};
diff --git a/voice_processing/voice_processing.c b/voice_processing/voice_processing.c
index 1d18a3d..72e4d84 100644
--- a/voice_processing/voice_processing.c
+++ b/voice_processing/voice_processing.c
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "voice_processing"
 /*#define LOG_NDEBUG 0*/
+#include <stdlib.h>
 #include <dlfcn.h>
 #include <cutils/log.h>
 #include <cutils/list.h>