Merge "hal: post_proc: add volume based audio calibration support"
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 1f1058e..7bbe2f8 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -75,7 +75,7 @@
 
 #ifndef WMA_OFFLOAD_ENABLED
 #define AUDIO_FORMAT_WMA 0x13000000UL
-#define AUDIO_FORMAT_WMAPRO 0x14000000UL
+#define AUDIO_FORMAT_WMA_PRO 0x14000000UL
 #endif
 
 #ifndef ALAC_OFFLOAD_ENABLED
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_hw.c b/hal/audio_hw.c
index a752f80..daafa77 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -912,6 +912,9 @@
         (usecase->in_snd_device != SND_DEVICE_NONE) &&
         (usecase->out_snd_device != SND_DEVICE_NONE)) {
         status = platform_switch_voice_call_device_pre(adev->platform);
+        /* Disable sidetone only if voice call already exists */
+        if (voice_is_call_state_active(adev))
+            voice_set_sidetone(adev, usecase->out_snd_device, false);
     }
 
     /* Disable current sound devices */
@@ -954,6 +957,9 @@
                                                         out_snd_device,
                                                         in_snd_device);
         enable_audio_route_for_voice_usecases(adev, usecase);
+        /* Enable sidetone only if voice call already exists */
+        if (voice_is_call_state_active(adev))
+            voice_set_sidetone(adev, out_snd_device, true);
     }
 
     usecase->in_snd_device = in_snd_device;
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..5fab099 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) {
@@ -1160,3 +1160,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/platform.c b/hal/msm8974/platform.c
index 28a75df..fc81443 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
@@ -3993,3 +4002,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..5542a6d 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -115,4 +115,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/hal/voice.c b/hal/voice.c
index 9fc1081..b1532f6 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -55,6 +55,59 @@
     return session;
 }
 
+static bool voice_is_sidetone_device(snd_device_t out_device,
+            char *mixer_path)
+{
+    bool is_sidetone_dev;
+
+    switch (out_device) {
+    case SND_DEVICE_OUT_VOICE_HANDSET:
+        is_sidetone_dev = true;
+        strlcpy(mixer_path, "sidetone-handset", MIXER_PATH_MAX_LENGTH);
+        break;
+    case SND_DEVICE_OUT_VOICE_HEADPHONES:
+    case SND_DEVICE_OUT_VOICE_ANC_HEADSET:
+    case SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET:
+        is_sidetone_dev = true;
+        strlcpy(mixer_path, "sidetone-headphones", MIXER_PATH_MAX_LENGTH);
+        break;
+    default:
+        is_sidetone_dev = false;
+        break;
+    }
+
+    return is_sidetone_dev;
+}
+
+void voice_set_sidetone(struct audio_device *adev,
+        snd_device_t out_snd_device, bool enable)
+{
+    char mixer_path[MIXER_PATH_MAX_LENGTH];
+    bool is_sidetone_dev;
+
+    ALOGD("%s: %s, out_snd_device: %d\n",
+          __func__, (enable ? "enable" : "disable"),
+          out_snd_device);
+
+    is_sidetone_dev = voice_is_sidetone_device(out_snd_device, mixer_path);
+
+    if (!is_sidetone_dev) {
+        ALOGD("%s: device %d does not support sidetone\n",
+              __func__, out_snd_device);
+        return;
+    }
+
+    ALOGD("%s: sidetone out device = %s\n",
+          __func__, mixer_path);
+
+    if (enable)
+        audio_route_apply_and_update_path(adev->audio_route, mixer_path);
+    else
+        audio_route_reset_and_update_path(adev->audio_route, mixer_path);
+
+    return;
+}
+
 int voice_stop_usecase(struct audio_device *adev, audio_usecase_t usecase_id)
 {
     int i, ret = 0;
@@ -69,10 +122,21 @@
         return -EINVAL;
     }
 
+    uc_info = get_usecase_from_list(adev, usecase_id);
+    if (uc_info == NULL) {
+        ALOGE("%s: Could not find the usecase (%d) in the list",
+              __func__, usecase_id);
+        return -EINVAL;
+    }
+
     session->state.current = CALL_INACTIVE;
     if (adev->mode == AUDIO_MODE_NORMAL)
         adev->voice.is_in_call = false;
 
+    /* Disable sidetone only when no calls are active */
+    if (!voice_is_call_state_active(adev))
+        voice_set_sidetone(adev, uc_info->out_snd_device, false);
+
     ret = platform_stop_voice_call(adev->platform, session->vsid);
 
     /* 1. Close the PCM devices */
@@ -85,13 +149,6 @@
         session->pcm_tx = NULL;
     }
 
-    uc_info = get_usecase_from_list(adev, usecase_id);
-    if (uc_info == NULL) {
-        ALOGE("%s: Could not find the usecase (%d) in the list",
-              __func__, usecase_id);
-        return -EINVAL;
-    }
-
     /* 2. Get and set stream specific mixer controls */
     disable_audio_route(adev, uc_info);
 
@@ -159,6 +216,17 @@
 
     voice_set_mic_mute(adev, adev->voice.mic_mute);
 
+    ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+          __func__, adev->snd_card, pcm_dev_tx_id);
+    session->pcm_tx = pcm_open(adev->snd_card,
+                               pcm_dev_tx_id,
+                               PCM_IN, &voice_config);
+    if (session->pcm_tx && !pcm_is_ready(session->pcm_tx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_tx));
+        ret = -EIO;
+        goto error_start_voice;
+    }
+
     ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
           __func__, adev->snd_card, pcm_dev_rx_id);
     session->pcm_rx = pcm_open(adev->snd_card,
@@ -170,18 +238,12 @@
         goto error_start_voice;
     }
 
-    ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
-          __func__, adev->snd_card, pcm_dev_tx_id);
-    session->pcm_tx = pcm_open(adev->snd_card,
-                               pcm_dev_tx_id,
-                               PCM_IN, &voice_config);
-    if (session->pcm_tx && !pcm_is_ready(session->pcm_tx)) {
-        ALOGE("%s: %s", __func__, pcm_get_error(session->pcm_tx));
-        ret = -EIO;
-        goto error_start_voice;
-    }
-    pcm_start(session->pcm_rx);
     pcm_start(session->pcm_tx);
+    pcm_start(session->pcm_rx);
+
+    /* Enable sidetone only when no calls are already active */
+    if (!voice_is_call_state_active(adev))
+        voice_set_sidetone(adev, uc_info->out_snd_device, true);
 
     voice_set_volume(adev, adev->voice.volume);
 
diff --git a/hal/voice.h b/hal/voice.h
index 5a9cce1..139a8c8 100644
--- a/hal/voice.h
+++ b/hal/voice.h
@@ -95,4 +95,8 @@
                                             struct stream_in *in);
 void voice_update_devices_for_all_voice_usecases(struct audio_device *adev);
 snd_device_t voice_get_incall_rec_snd_device(snd_device_t in_snd_device);
+void voice_set_sidetone(struct audio_device *adev,
+                       snd_device_t out_snd_device,
+                       bool enable);
+bool voice_is_call_state_active(struct audio_device *adev);
 #endif //VOICE_H
diff --git a/post_proc/bass_boost.c b/post_proc/bass_boost.c
index ad1e7c9..d397c6b 100644
--- a/post_proc/bass_boost.c
+++ b/post_proc/bass_boost.c
@@ -176,6 +176,7 @@
         ALOGV("%s: set PBE mode, device: %x", __func__, device);
     } else if (device == AUDIO_DEVICE_OUT_WIRED_HEADSET ||
         device == AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+        device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP ||
         device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) {
         ALOGV("%s: set BB mode, device: %x", __func__, device);
         bass_ctxt->active_index = BASS_BOOST;
@@ -318,6 +319,7 @@
     bass_ctxt->device = device;
     if (device == AUDIO_DEVICE_OUT_WIRED_HEADSET ||
         device == AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+        device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP ||
         device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) {
         if (bass_ctxt->temp_disabled) {
             if (effect_is_active(&bass_ctxt->common)) {