Merge commit '0110e267d11ed5aa7a64a306771e71aeb289db6a' into remote

Conflicts:
	policy_hal/AudioPolicyManager.cpp

Change-Id: Ia056c051af478e9853a05fea0ee2c8c7eca0670a
diff --git a/Android.mk b/Android.mk
index 58cf834..b081de0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,4 +1,4 @@
-ifneq ($(filter mpq8092 msm8960 msm8226 msm8x26 msm8610 msm8974 msm8x74 apq8084 msm8916 msm8994 msm8992 msm8909 msm8996 msm8952 msm8937 thorium titanium msmgold,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter mpq8092 msm8960 msm8226 msm8x26 msm8610 msm8974 msm8x74 apq8084 msm8916 msm8994 msm8992 msm8909 msm8996 msm8952 msm8937 thorium msm8953 msmgold,$(TARGET_BOARD_PLATFORM)),)
 
 MY_LOCAL_PATH := $(call my-dir)
 
diff --git a/hal/Android.mk b/hal/Android.mk
index ea54bd5..537260d 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -32,7 +32,7 @@
 endif
 endif
 
-ifneq ($(filter msm8916 msm8909 msm8952 msm8937 thorium titanium msmgold,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8916 msm8909 msm8952 msm8937 thorium msm8953 msmgold,$(TARGET_BOARD_PLATFORM)),)
   AUDIO_PLATFORM = msm8916
   MULTIPLE_HW_VARIANTS_ENABLED := true
   LOCAL_CFLAGS := -DPLATFORM_MSM8916
@@ -282,6 +282,8 @@
     LOCAL_SHARED_LIBRARIES += libperipheral_client
 endif
 
+#LOCAL_CFLAGS += -Wall -Werror
+
 LOCAL_COPY_HEADERS_TO   := mm-audio
 LOCAL_COPY_HEADERS      := audio_extn/audio_defs.h
 
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index b8b8b85..db91b51 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -222,7 +222,7 @@
 #else
 void audio_extn_source_track_set_parameters(struct audio_device *adev,
                                             struct str_parms *parms);
-void audio_extn_source_track_get_parameters(struct audio_device *adev,
+void audio_extn_source_track_get_parameters(const struct audio_device *adev,
                                             struct str_parms *query,
                                             struct str_parms *reply);
 #endif
@@ -764,6 +764,7 @@
    audio_extn_hpx_set_parameters(adev, parms);
    audio_extn_pm_set_parameters(parms);
    audio_extn_source_track_set_parameters(adev, parms);
+   audio_extn_fbsp_set_parameters(parms);
    check_and_set_hdmi_connection_status(parms);
    if (adev->offload_effects_set_parameters != NULL)
        adev->offload_effects_set_parameters(parms);
@@ -781,6 +782,7 @@
     audio_extn_dts_eagle_get_parameters(adev, query, reply);
     audio_extn_hpx_get_parameters(query, reply);
     audio_extn_source_track_get_parameters(adev, query, reply);
+    audio_extn_fbsp_get_parameters(query, reply);
     if (adev->offload_effects_get_parameters != NULL)
         adev->offload_effects_get_parameters(query, reply);
 
@@ -1110,7 +1112,8 @@
 {
 
     if (!perf_lock_opts || !size || !perf_lock_acq || !handle) {
-        ALOGE("%s: Invalid arguments", __func__);
+        ALOGE("%s: Incorrect params, Failed to acquire perf lock, err ",
+              __func__);
         return;
     }
     /*
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 10693ea..8980026 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -210,15 +210,19 @@
 #endif
 
 #ifndef HW_VARIANTS_ENABLED
-#define hw_info_init(snd_card_name)                  (0)
-#define hw_info_deinit(hw_info)                      (0)
+#define hw_info_init(snd_card_name)                      (0)
+#define hw_info_deinit(hw_info)                          (0)
 #define hw_info_append_hw_type(hw_info,\
-        snd_device, device_name)                     (0)
+        snd_device, device_name)                         (0)
+#define hw_info_enable_wsa_combo_usecase_support(hw_info)   (0)
+
 #else
 void *hw_info_init(const char *snd_card_name);
 void hw_info_deinit(void *hw_info);
 void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device,
                              char *device_name);
+void hw_info_enable_wsa_combo_usecase_support(void *hw_info);
+
 #endif
 
 #ifndef AUDIO_LISTEN_ENABLED
@@ -294,6 +298,8 @@
 #define audio_extn_spkr_prot_stop_processing(snd_device)     (0)
 #define audio_extn_spkr_prot_is_enabled() (false)
 #define audio_extn_spkr_prot_set_parameters(parms, value, len)   (0)
+#define audio_extn_fbsp_set_parameters(parms)   (0)
+#define audio_extn_fbsp_get_parameters(query, reply)   (0)
 #else
 void audio_extn_spkr_prot_init(void *adev);
 int audio_extn_spkr_prot_start_processing(snd_device_t snd_device);
@@ -302,6 +308,9 @@
 void audio_extn_spkr_prot_calib_cancel(void *adev);
 void audio_extn_spkr_prot_set_parameters(struct str_parms *parms,
                                          char *value, int len);
+int audio_extn_fbsp_set_parameters(struct str_parms *parms);
+int audio_extn_fbsp_get_parameters(struct str_parms *query,
+                                   struct str_parms *reply);
 #endif
 
 #ifndef COMPRESS_CAPTURE_ENABLED
diff --git a/hal/audio_extn/dolby.c b/hal/audio_extn/dolby.c
index c8bf543..115057c 100644
--- a/hal/audio_extn/dolby.c
+++ b/hal/audio_extn/dolby.c
@@ -655,7 +655,8 @@
     ds2extnmod.dap_hal_set_hw_info(SND_CARD, (void*)(&snd_card));
     ALOGV("%s Sound card number is:%d",__func__,snd_card);
 
-    platform_get_device_to_be_id_map(&device_be_id_map.device_id_to_be_id, &device_be_id_map.len);
+    platform_get_device_to_be_id_map((int**)&device_be_id_map.device_id_to_be_id,
+            &device_be_id_map.len);
     ds2extnmod.dap_hal_set_hw_info(DEVICE_BE_ID_MAP, (void*)(&device_be_id_map));
     ALOGV("%s Set be id map len:%d",__func__,device_be_id_map.len);
     ret = 0;
@@ -771,8 +772,9 @@
     if (ds2extnmod.dap_hal_set_hw_info) {
         ds2extnmod.dap_hal_set_hw_info(DMID, (void*)(&dolby_license.dmid));
     } else {
-        ALOGV("%s: dap_hal_set_hw_info is NULL", __func__);
+        ALOGE("%s: dap_hal_set_hw_info is NULL", __func__);
     }
+    return;
 }
 
 
diff --git a/hal/audio_extn/soundtrigger.c b/hal/audio_extn/soundtrigger.c
index 3c16c88..8882b90 100644
--- a/hal/audio_extn/soundtrigger.c
+++ b/hal/audio_extn/soundtrigger.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -174,7 +174,7 @@
     struct sound_trigger_info  *st_ses_info = NULL;
     audio_event_info_t event;
 
-    if (!st_dev || !in)
+    if (!st_dev || !in || !in->is_st_session_active)
        return;
 
     pthread_mutex_lock(&st_dev->lock);
@@ -184,6 +184,7 @@
         event.u.ses_info = st_ses_info->st_ses;
         ALOGV("%s: AUDIO_EVENT_STOP_LAB pcm %p", __func__, st_ses_info->st_ses.pcm);
         st_dev->st_callback(AUDIO_EVENT_STOP_LAB, &event);
+        in->is_st_session_active = false;
     }
 }
 void audio_extn_sound_trigger_check_and_get_session(struct stream_in *in)
diff --git a/hal/audio_extn/source_track.c b/hal/audio_extn/source_track.c
index 316e52d..8bf4c67 100644
--- a/hal/audio_extn/source_track.c
+++ b/hal/audio_extn/source_track.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -91,8 +91,8 @@
 #define MAX_SECTORS                                         8
 #define MAX_STR_SIZE                                       2048
 
-struct audio_device_to_audio_interface audio_device_to_interface_table[];
-int audio_device_to_interface_table_len;
+extern struct audio_device_to_audio_interface audio_device_to_interface_table[];
+extern int audio_device_to_interface_table_len;
 
 struct sound_focus_param {
     uint16_t start_angle[MAX_SECTORS];
@@ -203,7 +203,7 @@
     return in_device;
 }
 
-static int derive_mixer_ctl_from_usecase_intf(struct audio_device *adev,
+static int derive_mixer_ctl_from_usecase_intf(const struct audio_device *adev,
                                               char *mixer_ctl_name) {
     struct audio_usecase *usecase = NULL;
     audio_devices_t in_device;
@@ -330,7 +330,7 @@
     return ret;
 }
 
-static int get_soundfocus_sourcetracking_data(struct audio_device *adev,
+static int get_soundfocus_sourcetracking_data(const struct audio_device *adev,
                                         const int bitmask,
                                         struct sound_focus_param *sound_focus_data,
                                         struct source_tracking_param *source_tracking_data)
@@ -496,7 +496,7 @@
     }
 }
 
-void audio_extn_source_track_get_parameters(struct audio_device *adev,
+void audio_extn_source_track_get_parameters(const struct audio_device *adev,
                                             struct str_parms *query,
                                             struct str_parms *reply)
 {
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
index fdfbfad..44ff952 100644
--- a/hal/audio_extn/spkr_protection.c
+++ b/hal/audio_extn/spkr_protection.c
@@ -66,9 +66,6 @@
 #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"
 
@@ -106,6 +103,12 @@
 #define AUDIO_PARAMETER_KEY_SPKR_TZ_1     "spkr_1_tz_name"
 #define AUDIO_PARAMETER_KEY_SPKR_TZ_2     "spkr_2_tz_name"
 
+#define AUDIO_PARAMETER_KEY_FBSP_TRIGGER_SPKR_CAL   "trigger_spkr_cal"
+#define AUDIO_PARAMETER_KEY_FBSP_GET_SPKR_CAL       "get_spkr_cal"
+#define AUDIO_PARAMETER_KEY_FBSP_CFG_WAIT_TIME      "fbsp_cfg_wait_time"
+#define AUDIO_PARAMETER_KEY_FBSP_CFG_FTM_TIME       "fbsp_cfg_ftm_time"
+#define AUDIO_PARAMETER_KEY_FBSP_GET_FTM_PARAM      "get_ftm_param"
+
 /*Modes of Speaker Protection*/
 enum speaker_protection_mode {
     SPKR_PROTECTION_DISABLED = -1,
@@ -141,6 +144,9 @@
     bool wsa_found;
     int spkr_1_tzn;
     int spkr_2_tzn;
+    bool trigger_cal;
+    pthread_mutex_t cal_wait_cond_mutex;
+    pthread_cond_t cal_wait_condition;
 };
 
 static struct pcm_config pcm_config_skr_prot = {
@@ -277,14 +283,15 @@
         ALOGE("%s: Invalid params", __func__);
         return true;
     }
-     if (handle.spkr_in_use) {
+    if (handle.spkr_in_use) {
         *sec = 0;
-         return true;
-     } else {
-         clock_gettime(CLOCK_BOOTTIME, &temp);
-         *sec = temp.tv_sec - handle.spkr_last_time_used.tv_sec;
-         return false;
-     }
+        handle.trigger_cal = false;
+        return true;
+    } else {
+        clock_gettime(CLOCK_BOOTTIME, &temp);
+        *sec = temp.tv_sec - handle.spkr_last_time_used.tv_sec;
+        return false;
+    }
 }
 
 
@@ -414,6 +421,7 @@
     struct timespec ts;
     bool acquire_device = false;
 
+    status.status = 0;
     if (!adev) {
         ALOGE("%s: Invalid params", __func__);
         return -EINVAL;
@@ -451,6 +459,8 @@
         uc_info_rx->out_snd_device = SND_DEVICE_OUT_SPEAKER_PROTECTED;
     disable_rx = true;
     list_add_tail(&adev->usecase_list, &uc_info_rx->list);
+    platform_check_and_set_codec_backend_cfg(adev, uc_info_rx,
+                                             uc_info_rx->out_snd_device);
     if (audio_extn_is_vbat_enabled())
          enable_snd_device(adev, SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT);
     else
@@ -540,15 +550,6 @@
                 ALOGD("%s: spkr_prot_thread calib Success R0 %d %d",
                  __func__, status.r0[SP_V2_SPKR_1], status.r0[SP_V2_SPKR_2]);
                 FILE *fp;
-
-                vi_feed_no_channels = vi_feed_get_channels(adev);
-                ALOGD("%s: vi_feed_no_channels %d", __func__, vi_feed_no_channels);
-                if (vi_feed_no_channels < 0) {
-                    ALOGE("%s: no of channels negative !!", __func__);
-                    /* limit the number of channels to 2*/
-                    vi_feed_no_channels = 2;
-                }
-
                 fp = fopen(CALIB_FILE,"wb");
                 if (!fp) {
                     ALOGE("%s: spkr_prot_thread File open failed %s",
@@ -639,6 +640,19 @@
     return status.status;
 }
 
+static void spkr_calibrate_wait()
+{
+    struct timespec ts;
+
+    clock_gettime(CLOCK_REALTIME, &ts);
+    ts.tv_sec += WAKEUP_MIN_IDLE_CHECK;
+    ts.tv_nsec = 0;
+    pthread_mutex_lock(&handle.cal_wait_cond_mutex);
+    pthread_cond_timedwait(&handle.cal_wait_condition,
+                           &handle.cal_wait_cond_mutex, &ts);
+    pthread_mutex_unlock(&handle.cal_wait_cond_mutex);
+}
+
 static void* spkr_calibration_thread()
 {
     unsigned long sec = 0;
@@ -646,7 +660,6 @@
     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;
@@ -693,14 +706,6 @@
     if (fp) {
         int i;
         bool spkr_calibrated = true;
-        /* HAL for speaker protection is always calibrating for stereo usecase*/
-        vi_feed_no_channels = vi_feed_get_channels(adev);
-        ALOGD("%s: vi_feed_no_channels %d", __func__, vi_feed_no_channels);
-        if (vi_feed_no_channels < 0) {
-            ALOGE("%s: no of channels negative !!", __func__);
-            /* limit the number of channels to 2*/
-            vi_feed_no_channels = 2;
-        }
         for (i = 0; i < vi_feed_no_channels; i++) {
             fread(&protCfg.r0[i], sizeof(protCfg.r0[i]), 1, fp);
             fread(&protCfg.t0[i], sizeof(protCfg.t0[i]), 1, fp);
@@ -745,13 +750,13 @@
             if (is_speaker_in_use(&sec)) {
                 ALOGV("%s: WSA Speaker in use retry calibration", __func__);
                 pthread_mutex_unlock(&adev->lock);
-                sleep(WAKEUP_MIN_IDLE_CHECK);
+                spkr_calibrate_wait();
                 continue;
             } else {
                 ALOGD("%s: wsa speaker idle %ld,minimum time %ld", __func__, sec, min_idle_time);
-                if (sec < min_idle_time) {
+                if (!(sec > min_idle_time || handle.trigger_cal)) {
                     pthread_mutex_unlock(&adev->lock);
-                    sleep(WAKEUP_MIN_IDLE_CHECK);
+                    spkr_calibrate_wait();
                     continue;
                }
                goahead = true;
@@ -759,7 +764,7 @@
            if (!list_empty(&adev->usecase_list)) {
                 ALOGD("%s: Usecase active re-try calibration", __func__);
                 pthread_mutex_unlock(&adev->lock);
-                sleep(WAKEUP_MIN_IDLE_CHECK);
+                spkr_calibrate_wait();
                 continue;
            }
            if (goahead) {
@@ -769,92 +774,46 @@
                    thermal_fd = -1;
                    thermal_fd = open(wsa_path, O_RDONLY);
                    if (thermal_fd > 0) {
-                       for (i = 0; i < NUM_ATTEMPTS; i++) {
-                            if ((ret = read(thermal_fd, buf, sizeof(buf))) >= 0) {
-                                t0_spk_1 = atoi(buf);
-                                if (i > 0 && (t0_spk_1 != t0_spk_prior)) {
-                                    ALOGE("%s: spkr1 curr temp: %d, prev temp: %d\n",
-                                          __func__, t0_spk_1, t0_spk_prior);
-                                    break;
-                                }
-                                t0_spk_prior = t0_spk_1;
-                                pthread_mutex_unlock(&adev->lock);
-                                sleep(1);
-                                pthread_mutex_lock(&adev->lock);
-                                if (is_speaker_in_use(&sec))
-                                    break;
-                            } else {
-                               ALOGE("%s: read fail for %s err:%d\n", __func__, wsa_path, ret);
-                               break;
-                            }
-                        }
-                        close(thermal_fd);
+                       if ((ret = read(thermal_fd, buf, sizeof(buf))) >= 0)
+                            t0_spk_1 = atoi(buf);
+                       else
+                           ALOGE("%s: read fail for %s err:%d\n", __func__, wsa_path, ret);
+                       close(thermal_fd);
                    } else {
                        ALOGE("%s: fd for %s is NULL\n", __func__, wsa_path);
                    }
-                   if (i == NUM_ATTEMPTS) {
-                       if (t0_spk_1 < TZ_TEMP_MIN_THRESHOLD ||
-                           t0_spk_1 > TZ_TEMP_MAX_THRESHOLD) {
-                           pthread_mutex_unlock(&adev->lock);
-                           sleep(WAKEUP_MIN_IDLE_CHECK);
-                           continue;
-                       }
-                       ALOGD("%s: temp T0 for spkr1 %d\n", __func__, t0_spk_1);
-                       /*Convert temp into q6 format*/
-                       t0_spk_1 = (t0_spk_1 * (1 << 6));
-                   } else {
-                       ALOGV("%s: thermal equilibrium failed for spkr1 in %d/%d readings\n",
-                                                __func__, i, NUM_ATTEMPTS);
+                   if (t0_spk_1 < TZ_TEMP_MIN_THRESHOLD ||
+                       t0_spk_1 > TZ_TEMP_MAX_THRESHOLD) {
                        pthread_mutex_unlock(&adev->lock);
-                       sleep(WAKEUP_MIN_IDLE_CHECK);
+                       spkr_calibrate_wait();
                        continue;
                    }
+                   ALOGD("%s: temp T0 for spkr1 %d\n", __func__, t0_spk_1);
+                   /*Convert temp into q6 format*/
+                   t0_spk_1 = (t0_spk_1 * (1 << 6));
                }
                if (spk_2_tzn >= 0) {
                    snprintf(wsa_path, MAX_PATH, TZ_WSA, spk_2_tzn);
                    ALOGV("%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 ((ret = read(thermal_fd, buf, sizeof(buf))) >= 0) {
-                                t0_spk_2 = atoi(buf);
-                                if (i > 0 && (t0_spk_2 != t0_spk_prior)) {
-                                    ALOGE("%s: spkr2 curr temp: %d, prev temp: %d\n",
-                                          __func__, t0_spk_2, t0_spk_prior);
-                                    break;
-                                }
-                                t0_spk_prior = t0_spk_2;
-                                pthread_mutex_unlock(&adev->lock);
-                                sleep(1);
-                                pthread_mutex_lock(&adev->lock);
-                                if (is_speaker_in_use(&sec))
-                                    break;
-                            } else {
-                               ALOGE("%s: read fail for %s err:%d\n", __func__, wsa_path, ret);
-                               break;
-                            }
-                        }
-                        close(thermal_fd);
+                       if ((ret = read(thermal_fd, buf, sizeof(buf))) >= 0)
+                           t0_spk_2 = atoi(buf);
+                       else
+                           ALOGE("%s: read fail for %s err:%d\n", __func__, wsa_path, ret);
+                       close(thermal_fd);
                    } else {
                        ALOGE("%s: fd for %s is NULL\n", __func__, wsa_path);
                    }
-                   if (i == NUM_ATTEMPTS) {
-                       if (t0_spk_2 < TZ_TEMP_MIN_THRESHOLD ||
-                           t0_spk_2 > TZ_TEMP_MAX_THRESHOLD) {
-                           pthread_mutex_unlock(&adev->lock);
-                           sleep(WAKEUP_MIN_IDLE_CHECK);
-                           continue;
-                       }
-                       ALOGD("%s: temp T0 for spkr2 %d\n", __func__, t0_spk_2);
-                       /*Convert temp into q6 format*/
-                       t0_spk_2 = (t0_spk_2 * (1 << 6));
-                   } else {
-                       ALOGV("%s: thermal equilibrium failed for spkr2 in %d/%d readings\n",
-                                                __func__, i, NUM_ATTEMPTS);
+                   if (t0_spk_2 < TZ_TEMP_MIN_THRESHOLD ||
+                       t0_spk_2 > TZ_TEMP_MAX_THRESHOLD) {
                        pthread_mutex_unlock(&adev->lock);
-                       sleep(WAKEUP_MIN_IDLE_CHECK);
+                       spkr_calibrate_wait();
                        continue;
                    }
+                   ALOGD("%s: temp T0 for spkr2 %d\n", __func__, t0_spk_2);
+                   /*Convert temp into q6 format*/
+                   t0_spk_2 = (t0_spk_2 * (1 << 6));
                }
            }
            pthread_mutex_unlock(&adev->lock);
@@ -886,12 +845,12 @@
         if (is_speaker_in_use(&sec)) {
             ALOGV("%s: Speaker in use retry calibration", __func__);
             pthread_mutex_unlock(&adev->lock);
-            sleep(WAKEUP_MIN_IDLE_CHECK);
+            spkr_calibrate_wait();
             continue;
         } else {
-            if (sec < min_idle_time) {
+            if (!(sec > min_idle_time || handle.trigger_cal)) {
                 pthread_mutex_unlock(&adev->lock);
-                sleep(WAKEUP_MIN_IDLE_CHECK);
+                spkr_calibrate_wait();
                 continue;
             }
             goahead = true;
@@ -900,7 +859,7 @@
             ALOGD("%s: Usecase active re-try calibration", __func__);
             goahead = false;
             pthread_mutex_unlock(&adev->lock);
-            sleep(WAKEUP_MIN_IDLE_CHECK);
+            spkr_calibrate_wait();
             continue;
         }
         if (goahead) {
@@ -973,6 +932,319 @@
           tz_names.spkr_1_name, tz_names.spkr_2_name);
 }
 
+static int spkr_vi_channels(struct audio_device *adev)
+{
+    int vi_channels;
+
+    vi_channels = vi_feed_get_channels(adev);
+    ALOGD("%s: vi_channels %d", __func__, vi_channels);
+    if (vi_channels < 0 || vi_channels > SP_V2_NUM_MAX_SPKRS) {
+        /* limit the number of channels to SP_V2_NUM_MAX_SPKRS */
+        vi_channels = SP_V2_NUM_MAX_SPKRS;
+    }
+    return vi_channels;
+}
+
+static void get_spkr_prot_thermal_cal(char *param)
+{
+    int i, status = 0;
+    int r0[SP_V2_NUM_MAX_SPKRS] = {0}, t0[SP_V2_NUM_MAX_SPKRS] = {0};
+    double dr0[SP_V2_NUM_MAX_SPKRS] = {0}, dt0[SP_V2_NUM_MAX_SPKRS] = {0};
+
+    FILE *fp = fopen(CALIB_FILE,"rb");
+    if (fp) {
+        for (i = 0; i < vi_feed_no_channels; i++) {
+            fread(&r0[i], sizeof(int), 1, fp);
+            fread(&t0[i], sizeof(int), 1, fp);
+            /* Convert from ADSP format to readable format */
+            dr0[i] = ((double)r0[i])/(1 << 24);
+            dt0[i] = ((double)t0[i])/(1 << 6);
+        }
+        ALOGV("%s: R0= %lf, %lf, T0= %lf, %lf",
+              __func__, dr0[0], dr0[1], dt0[0], dt0[1]);
+        fclose(fp);
+    } else {
+        ALOGE("%s: failed to open cal file\n", __func__);
+        status = -EINVAL;
+    }
+    sprintf(param, "SpkrCalStatus: %d; R0: %lf, %lf; T0: %lf, %lf",
+            status, dr0[SP_V2_SPKR_1], dr0[SP_V2_SPKR_2],
+            dt0[SP_V2_SPKR_1], dt0[SP_V2_SPKR_2]);
+    ALOGD("%s:: param = %s\n", __func__, param);
+
+    return;
+}
+
+#ifdef MSM_SPKR_PROT_IN_FTM_MODE
+
+static int set_spkr_prot_ftm_cfg(int wait_time, int ftm_time)
+{
+    int ret = 0;
+    struct audio_cal_sp_th_vi_ftm_cfg th_cal_data;
+    struct audio_cal_sp_ex_vi_ftm_cfg ex_cal_data;
+
+    int cal_fd = open("/dev/msm_audio_cal",O_RDWR | O_NONBLOCK);
+    if (cal_fd < 0) {
+        ALOGE("%s: open msm_acdb failed", __func__);
+        ret = -ENODEV;
+        goto done;
+    }
+
+    memset(&th_cal_data, 0, sizeof(th_cal_data));
+    th_cal_data.hdr.data_size = sizeof(th_cal_data);
+    th_cal_data.hdr.version = VERSION_0_0;
+    th_cal_data.hdr.cal_type = AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE;
+    th_cal_data.hdr.cal_type_size = sizeof(th_cal_data.cal_type);
+    th_cal_data.cal_type.cal_hdr.version = VERSION_0_0;
+    th_cal_data.cal_type.cal_hdr.buffer_number = 0;
+    th_cal_data.cal_type.cal_info.wait_time[SP_V2_SPKR_1] = wait_time;
+    th_cal_data.cal_type.cal_info.wait_time[SP_V2_SPKR_2] = wait_time;
+    th_cal_data.cal_type.cal_info.ftm_time[SP_V2_SPKR_1] = ftm_time;
+    th_cal_data.cal_type.cal_info.ftm_time[SP_V2_SPKR_2] = ftm_time;
+    th_cal_data.cal_type.cal_info.mode = MSM_SPKR_PROT_IN_FTM_MODE; // FTM mode
+    th_cal_data.cal_type.cal_data.mem_handle = -1;
+
+    if (ioctl(cal_fd, AUDIO_SET_CALIBRATION, &th_cal_data))
+        ALOGE("%s: failed to set TH VI FTM_CFG, errno = %d", __func__, errno);
+
+    memset(&ex_cal_data, 0, sizeof(ex_cal_data));
+    ex_cal_data.hdr.data_size = sizeof(ex_cal_data);
+    ex_cal_data.hdr.version = VERSION_0_0;
+    ex_cal_data.hdr.cal_type = AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE;
+    ex_cal_data.hdr.cal_type_size = sizeof(ex_cal_data.cal_type);
+    ex_cal_data.cal_type.cal_hdr.version = VERSION_0_0;
+    ex_cal_data.cal_type.cal_hdr.buffer_number = 0;
+    ex_cal_data.cal_type.cal_info.wait_time[SP_V2_SPKR_1] = wait_time;
+    ex_cal_data.cal_type.cal_info.wait_time[SP_V2_SPKR_2] = wait_time;
+    ex_cal_data.cal_type.cal_info.ftm_time[SP_V2_SPKR_1] = ftm_time;
+    ex_cal_data.cal_type.cal_info.ftm_time[SP_V2_SPKR_2] = ftm_time;
+    ex_cal_data.cal_type.cal_info.mode = MSM_SPKR_PROT_IN_FTM_MODE; // FTM mode
+    ex_cal_data.cal_type.cal_data.mem_handle = -1;
+
+    if (ioctl(cal_fd, AUDIO_SET_CALIBRATION, &ex_cal_data))
+        ALOGE("%s: failed to set EX VI FTM_CFG, ret = %d", __func__, errno);
+
+    if (cal_fd > 0)
+        close(cal_fd);
+done:
+    return ret;
+}
+
+static void get_spkr_prot_ftm_param(char *param)
+{
+    struct audio_cal_sp_th_vi_param th_vi_cal_data;
+    struct audio_cal_sp_ex_vi_param ex_vi_cal_data;
+    int i;
+    int ftm_status[SP_V2_NUM_MAX_SPKRS];
+    double rdc[SP_V2_NUM_MAX_SPKRS], temp[SP_V2_NUM_MAX_SPKRS];
+    double f[SP_V2_NUM_MAX_SPKRS], r[SP_V2_NUM_MAX_SPKRS], q[SP_V2_NUM_MAX_SPKRS];
+
+    int cal_fd = open("/dev/msm_audio_cal",O_RDWR | O_NONBLOCK);
+    if (cal_fd < 0) {
+        ALOGE("%s: open msm_acdb failed", __func__);
+        goto done;
+    }
+
+    memset(&th_vi_cal_data, 0, sizeof(th_vi_cal_data));
+    th_vi_cal_data.cal_type.cal_info.status[SP_V2_SPKR_1] = -EINVAL;
+    th_vi_cal_data.cal_type.cal_info.status[SP_V2_SPKR_2] = -EINVAL;
+    th_vi_cal_data.hdr.data_size = sizeof(th_vi_cal_data);
+    th_vi_cal_data.hdr.version = VERSION_0_0;
+    th_vi_cal_data.hdr.cal_type = AFE_FB_SPKR_PROT_TH_VI_CAL_TYPE;
+    th_vi_cal_data.hdr.cal_type_size = sizeof(th_vi_cal_data.cal_type);
+    th_vi_cal_data.cal_type.cal_hdr.version = VERSION_0_0;
+    th_vi_cal_data.cal_type.cal_hdr.buffer_number = 0;
+    th_vi_cal_data.cal_type.cal_data.mem_handle = -1;
+
+    if (ioctl(cal_fd, AUDIO_GET_CALIBRATION, &th_vi_cal_data))
+        ALOGE("%s: Error %d in getting th_vi_cal_data", __func__, errno);
+
+    memset(&ex_vi_cal_data, 0, sizeof(ex_vi_cal_data));
+    ex_vi_cal_data.cal_type.cal_info.status[SP_V2_SPKR_1] = -EINVAL;
+    ex_vi_cal_data.cal_type.cal_info.status[SP_V2_SPKR_2] = -EINVAL;
+    ex_vi_cal_data.hdr.data_size = sizeof(ex_vi_cal_data);
+    ex_vi_cal_data.hdr.version = VERSION_0_0;
+    ex_vi_cal_data.hdr.cal_type = AFE_FB_SPKR_PROT_EX_VI_CAL_TYPE;
+    ex_vi_cal_data.hdr.cal_type_size = sizeof(ex_vi_cal_data.cal_type);
+    ex_vi_cal_data.cal_type.cal_hdr.version = VERSION_0_0;
+    ex_vi_cal_data.cal_type.cal_hdr.buffer_number = 0;
+    ex_vi_cal_data.cal_type.cal_data.mem_handle = -1;
+
+    if (ioctl(cal_fd, AUDIO_GET_CALIBRATION, &ex_vi_cal_data))
+        ALOGE("%s: Error %d in getting ex_vi_cal_data", __func__, errno);
+
+    for (i = 0; i < vi_feed_no_channels; i++) {
+        /* Convert from ADSP format to readable format */
+        rdc[i] = ((double)th_vi_cal_data.cal_type.cal_info.r_dc_q24[i])/(1<<24);
+        temp[i] = ((double)th_vi_cal_data.cal_type.cal_info.temp_q22[i])/(1<<22);
+        f[i] = ((double)ex_vi_cal_data.cal_type.cal_info.freq_q20[i])/(1<<20);
+        r[i] = ((double)ex_vi_cal_data.cal_type.cal_info.resis_q24[i])/(1<<24);
+        q[i] = ((double)ex_vi_cal_data.cal_type.cal_info.qmct_q24[i])/(1<<24);
+
+        if (th_vi_cal_data.cal_type.cal_info.status[i] == 0 &&
+            ex_vi_cal_data.cal_type.cal_info.status[i] == 0) {
+            ftm_status[i] = 0;
+        } else if (th_vi_cal_data.cal_type.cal_info.status[i] == -EAGAIN &&
+                   ex_vi_cal_data.cal_type.cal_info.status[i] == -EAGAIN) {
+            ftm_status[i] = -EAGAIN;
+        } else {
+            ftm_status[i] = -EINVAL;
+        }
+    }
+    sprintf(param, "SpkrParamStatus: %d, %d; Rdc: %lf, %lf; Temp: %lf, %lf;"
+            " Freq: %lf, %lf; Rect: %lf, %lf; Qmct: %lf, %lf",
+            ftm_status[SP_V2_SPKR_1], ftm_status[SP_V2_SPKR_2],
+            rdc[SP_V2_SPKR_1], rdc[SP_V2_SPKR_2], temp[SP_V2_SPKR_1],
+            temp[SP_V2_SPKR_2], f[SP_V2_SPKR_1], f[SP_V2_SPKR_2],
+            r[SP_V2_SPKR_1], r[SP_V2_SPKR_2], q[SP_V2_SPKR_1], q[SP_V2_SPKR_2]);
+    ALOGD("%s:: param = %s\n", __func__, param);
+
+    if (cal_fd > 0)
+        close(cal_fd);
+done:
+    return;
+}
+
+#else
+
+static void get_spkr_prot_ftm_param(char *param __unused)
+{
+
+    ALOGD("%s: not supported", __func__);
+    return;
+}
+
+static int set_spkr_prot_ftm_cfg(int wait_time __unused, int ftm_time __unused)
+{
+    ALOGD("%s: not supported", __func__);
+    return -ENOSYS;
+}
+#endif
+
+static void spkr_calibrate_signal()
+{
+    pthread_mutex_lock(&handle.cal_wait_cond_mutex);
+    pthread_cond_signal(&handle.cal_wait_condition);
+    pthread_mutex_unlock(&handle.cal_wait_cond_mutex);
+}
+
+int audio_extn_fbsp_set_parameters(struct str_parms *parms)
+{
+    int ret= 0 , err;
+    char *str;
+    char *value = NULL;
+    int val, len, i;
+    char *test_r = NULL;
+    char *cfg_str;
+    int wait_time, ftm_time;
+    char *kv_pairs = str_parms_to_str(parms);
+
+    if(kv_pairs == NULL) {
+        ret = -ENOMEM;
+        ALOGE("[%s] key-value pair is NULL",__func__);
+        goto done;
+    }
+    ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
+
+    len = strlen(kv_pairs);
+    value = (char*)calloc(len, sizeof(char));
+    if(value == NULL) {
+        ret = -ENOMEM;
+        ALOGE("[%s] failed to allocate memory",__func__);
+        goto done;
+    }
+    if (!handle.spkr_prot_enable) {
+        ALOGD("%s: Speaker protection disabled", __func__);
+        goto done;
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_FBSP_TRIGGER_SPKR_CAL, value,
+                            len);
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_FBSP_TRIGGER_SPKR_CAL);
+        if ((strcmp(value, "true") == 0) || (strcmp(value, "yes") == 0)) {
+            handle.trigger_cal = true;
+            spkr_calibrate_signal();
+        }
+        goto done;
+    }
+
+    /* Expected key value pair is in below format:
+     * AUDIO_PARAM_FBSP_CFG_WAIT_TIME=waittime;AUDIO_PARAM_FBSP_CFG_FTM_TIME=ftmtime;
+     * Parse waittime and ftmtime from it.
+     */
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_FBSP_CFG_WAIT_TIME,
+                            value, len);
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_FBSP_CFG_WAIT_TIME);
+        cfg_str = strtok_r(value, ";", &test_r);
+        if (cfg_str == NULL) {
+            ALOGE("%s: incorrect wait time cfg_str", __func__);
+            ret = -EINVAL;
+            goto done;
+        }
+        wait_time = atoi(cfg_str);
+        ALOGV(" %s: cfg_str = %s, wait_time = %d", __func__, cfg_str, wait_time);
+
+        err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_FBSP_CFG_FTM_TIME,
+                                value, len);
+        if (err >= 0) {
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_FBSP_CFG_FTM_TIME);
+            cfg_str = strtok_r(value, ";", &test_r);
+            if (cfg_str == NULL) {
+                ALOGE("%s: incorrect ftm time cfg_str", __func__);
+                ret = -EINVAL;
+                goto done;
+            }
+            ftm_time = atoi(cfg_str);
+            ALOGV(" %s: cfg_str = %s, ftm_time = %d", __func__, cfg_str, ftm_time);
+
+            ret = set_spkr_prot_ftm_cfg(wait_time, ftm_time);
+            if (ret < 0) {
+                ALOGE("%s: set_spkr_prot_ftm_cfg failed", __func__);
+                goto done;
+            }
+        }
+    }
+
+done:
+    ALOGV("%s: exit with code(%d)", __func__, ret);
+
+    if(kv_pairs != NULL)
+        free(kv_pairs);
+    if(value != NULL)
+        free(value);
+
+    return ret;
+}
+
+int audio_extn_fbsp_get_parameters(struct str_parms *query,
+                                   struct str_parms *reply)
+{
+    int err = 0;
+    char value[1024] = {0};
+
+    if (!handle.spkr_prot_enable) {
+        ALOGD("%s: Speaker protection disabled", __func__);
+        return -EINVAL;
+    }
+
+    err = str_parms_get_str(query, AUDIO_PARAMETER_KEY_FBSP_GET_SPKR_CAL, value,
+                                                          sizeof(value));
+    if (err >= 0) {
+        get_spkr_prot_thermal_cal(value);
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_FBSP_GET_SPKR_CAL, value);
+    }
+    err = str_parms_get_str(query, AUDIO_PARAMETER_KEY_FBSP_GET_FTM_PARAM, value,
+                            sizeof(value));
+    if (err >= 0) {
+        get_spkr_prot_ftm_param(value);
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_FBSP_GET_FTM_PARAM, value);
+    }
+done:
+    return err;
+}
+
 void audio_extn_spkr_prot_init(void *adev)
 {
     char value[PROPERTY_VALUE_MAX];
@@ -994,6 +1266,11 @@
     handle.spkr_prot_mode = MSM_SPKR_PROT_DISABLED;
     handle.spkr_processing_state = SPKR_PROCESSING_IN_IDLE;
     handle.spkr_prot_t0 = -1;
+    handle.trigger_cal = false;
+    /* HAL for speaker protection is always calibrating for stereo usecase*/
+    vi_feed_no_channels = spkr_vi_channels(adev);
+    pthread_cond_init(&handle.cal_wait_condition, NULL);
+    pthread_mutex_init(&handle.cal_wait_cond_mutex, NULL);
 
     if (is_wsa_present()) {
         if (platform_spkr_prot_is_wsa_analog_mode(adev) == 1) {
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
old mode 100644
new mode 100755
index e4b8a37..d7a3169
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -714,13 +714,15 @@
            specified usecase to new snd devices */
         list_for_each(node, &adev->usecase_list) {
             usecase = node_to_item(node, struct audio_usecase, list);
-            /* Update the out_snd_device only for the usecases that are enabled here */
-            if (switch_device[usecase->id] && (usecase->type != VOICE_CALL)) {
-                    usecase->out_snd_device = snd_device;
+            /* Update the out_snd_device only before enabling the audio route */
+            if (switch_device[usecase->id]) {
+                usecase->out_snd_device = snd_device;
+                if (usecase->type != VOICE_CALL) {
                     ALOGD("%s:becf: enabling usecase (%s) on (%s)", __func__,
-                      use_case_table[usecase->id],
-                      platform_get_snd_device_name(usecase->out_snd_device));
+                         use_case_table[usecase->id],
+                         platform_get_snd_device_name(usecase->out_snd_device));
                     enable_audio_route(adev, usecase);
+                }
             }
         }
     }
@@ -754,7 +756,8 @@
                 usecase != uc_info &&
                 usecase->in_snd_device != snd_device &&
                 ((uc_info->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
-                ((usecase->devices & ~AUDIO_DEVICE_BIT_IN) & AUDIO_DEVICE_IN_ALL_CODEC_BACKEND)) &&
+                 (((usecase->devices & ~AUDIO_DEVICE_BIT_IN) & AUDIO_DEVICE_IN_ALL_CODEC_BACKEND) ||
+                  (usecase->type == VOICE_CALL))) &&
                 (usecase->id != USECASE_AUDIO_SPKR_CALIB_TX)) {
             ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
                   __func__, use_case_table[usecase->id],
@@ -834,7 +837,7 @@
     return ret;
 }
 
-audio_usecase_t get_usecase_id_from_usecase_type(struct audio_device *adev,
+audio_usecase_t get_usecase_id_from_usecase_type(const struct audio_device *adev,
                                                  usecase_type_t type)
 {
     struct audio_usecase *usecase;
@@ -850,7 +853,7 @@
     return USECASE_INVALID;
 }
 
-struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
+struct audio_usecase *get_usecase_from_list(const struct audio_device *adev,
                                             audio_usecase_t uc_id)
 {
     struct audio_usecase *usecase;
@@ -912,7 +915,9 @@
 
     if (is_offload_usecase(usecase->id) &&
         (usecase->stream.out) &&
-        (usecase->stream.out->sample_rate == OUTPUT_SAMPLING_RATE_44100)) {
+        (usecase->stream.out->sample_rate == OUTPUT_SAMPLING_RATE_44100) &&
+        (usecase->stream.out->devices == AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+         usecase->stream.out->devices == AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) {
         is_it_true_mode = (NATIVE_AUDIO_MODE_TRUE_44_1 == platform_get_native_support()? true : false);
          if ((is_it_true_mode && !adev->native_playback_enabled) ||
              (!is_it_true_mode && adev->native_playback_enabled)){
@@ -1338,7 +1343,7 @@
 {
     audio_usecase_t ret_uc = USECASE_INVALID;
     unsigned int offload_uc_index;
-    int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
+    unsigned int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
     if (!adev->multi_offload_enable) {
         if (is_direct_pcm)
             ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD2;
@@ -1370,7 +1375,7 @@
                                  audio_usecase_t uc_id)
 {
     unsigned int offload_uc_index;
-    int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
+    unsigned int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
 
     if (!adev->multi_offload_enable)
         return;
@@ -2346,7 +2351,7 @@
     }
 
     if (adev->is_channel_status_set == false && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)){
-        audio_utils_set_hdmi_channel_status(out, buffer, bytes);
+        audio_utils_set_hdmi_channel_status(out, (void *)buffer, bytes);
         adev->is_channel_status_set = true;
     }
 
@@ -2426,7 +2431,7 @@
 
     if (ret != 0) {
         if (out->pcm)
-            ALOGE("%s: error %zu - %s", __func__, ret, pcm_get_error(out->pcm));
+            ALOGE("%s: error %d, %s", __func__, (int)ret, pcm_get_error(out->pcm));
         if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
             pthread_mutex_lock(&adev->lock);
             voice_extn_compress_voip_close_output_stream(&out->stream.common);
@@ -2777,7 +2782,8 @@
             if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) &&
                 (in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
                 (voice_extn_compress_voip_is_format_supported(in->format)) &&
-                (in->config.rate == 8000 || in->config.rate == 16000) &&
+                (in->config.rate == 8000 || in->config.rate == 16000 ||
+                 in->config.rate == 32000 || in->config.rate == 48000 ) &&
                 (audio_channel_count_from_in_mask(in->channel_mask) == 1)) {
                 err = voice_extn_compress_voip_open_input_stream(in);
                 if (err != 0) {
@@ -3128,7 +3134,7 @@
         }
 
         if (out->usecase == USECASE_INVALID) {
-            ALOGE("%s: Max allowed OFFLOAD usecase reached ... ");
+            ALOGE("%s, Max allowed OFFLOAD usecase reached ... ", __func__);
             ret = -EEXIST;
             goto error_open;
         }
@@ -3429,6 +3435,8 @@
             struct audio_usecase *usecase;
             ALOGD("Received sound card OFFLINE status");
             set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
+            //close compress sessions on OFFLINE status
+            close_compress_sessions(adev);
         } else if (strstr(snd_card_status, "ONLINE")) {
             ALOGD("Received sound card ONLINE status");
             set_snd_card_state(adev,SND_CARD_STATE_ONLINE);
@@ -3779,7 +3787,8 @@
         if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) &&
                (in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
                (voice_extn_compress_voip_is_format_supported(in->format)) &&
-               (in->config.rate == 8000 || in->config.rate == 16000) &&
+               (in->config.rate == 8000 || in->config.rate == 16000 ||
+                in->config.rate == 32000 || in->config.rate == 48000) &&
                (audio_channel_count_from_in_mask(in->channel_mask) == 1)) {
             voice_extn_compress_voip_open_input_stream(in);
         }
@@ -3829,6 +3838,10 @@
             audio_extn_compr_cap_format_supported(in->config.format))
         audio_extn_compr_cap_deinit();
 
+    if (in->is_st_session) {
+        ALOGV("%s: sound trigger pcm stop lab", __func__);
+        audio_extn_sound_trigger_stop_lab(in);
+    }
     free(stream);
     return;
 }
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 47c9070..a7d4483 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -373,7 +373,7 @@
 int enable_audio_route(struct audio_device *adev,
                        struct audio_usecase *usecase);
 
-struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
+struct audio_usecase *get_usecase_from_list(const struct audio_device *adev,
                                                    audio_usecase_t uc_id);
 
 bool is_offload_usecase(audio_usecase_t uc_id);
@@ -383,7 +383,7 @@
 int pcm_ioctl(struct pcm *pcm, int request, ...);
 
 int get_snd_card_state(struct audio_device *adev);
-audio_usecase_t get_usecase_id_from_usecase_type(struct audio_device *adev,
+audio_usecase_t get_usecase_id_from_usecase_type(const struct audio_device *adev,
                                                  usecase_type_t type);
 
 #define LITERAL_TO_STRING(x) #x
diff --git a/hal/msm8916/hw_info.c b/hal/msm8916/hw_info.c
index 6140698..fb8d648 100644
--- a/hal/msm8916/hw_info.c
+++ b/hal/msm8916/hw_info.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -47,9 +47,11 @@
     uint32_t num_snd_devices;
     char dev_extn[HW_INFO_ARRAY_MAX_SIZE];
     snd_device_t  *snd_devices;
+    bool is_wsa_combo_suppported;
 };
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define WSA_MIXER_PATH_EXTENSION "wsa-"
 
 static const snd_device_t taiko_fluid_variant_devices[] = {
     SND_DEVICE_OUT_SPEAKER,
@@ -123,6 +125,14 @@
     SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
 };
 
+static const snd_device_t wsa_combo_devices[] = {
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_LINE,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2,
+    SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET
+};
+
 static void update_hardware_info_8x16(struct hardware_info *hw_info, const char *snd_card_name)
 {
     if (!strcmp(snd_card_name, "msm8x16-snd-card")) {
@@ -332,6 +342,8 @@
     } else {
         ALOGW("%s: Not an  8x16/8939/8909/8952 device", __func__);
     }
+
+    hw_info->is_wsa_combo_suppported = false;
 }
 
 void *hw_info_init(const char *snd_card_name)
@@ -363,19 +375,52 @@
 {
     struct hardware_info *my_data = (struct hardware_info*) hw_info;
 
-    if(!my_data)
+    if(my_data != NULL)
         free(my_data);
 }
 
+void hw_info_enable_wsa_combo_usecase_support(void *hw_info)
+{
+    struct hardware_info *my_data = (struct hardware_info*) hw_info;
+    if(!my_data) {
+        ALOGE(" ERROR wsa combo update is called with invalid hw_info");
+        return;
+    }
+    my_data->is_wsa_combo_suppported = true;
+
+}
+
 void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device,
                             char *device_name)
 {
     struct hardware_info *my_data = (struct hardware_info*) hw_info;
     uint32_t i = 0;
 
+    if(!my_data) {
+        ALOGE(" ERROR hw_info_append_hw_type is called with invalid hw_info");
+        return;
+    }
+
     snd_device_t *snd_devices =
             (snd_device_t *) my_data->snd_devices;
 
+
+    if(my_data->is_wsa_combo_suppported) {
+        for (i = 0; i < ARRAY_SIZE(wsa_combo_devices) ; i++) {
+            if (snd_device == (snd_device_t)wsa_combo_devices[i]) {
+                char mixer_device_name[DEVICE_NAME_MAX_SIZE] = {0};
+                ALOGD("appending wsa extension to device %s",
+                        device_name);
+               strlcpy(mixer_device_name, WSA_MIXER_PATH_EXTENSION,
+                        sizeof(WSA_MIXER_PATH_EXTENSION)) ;
+                strlcat(mixer_device_name, device_name, DEVICE_NAME_MAX_SIZE);
+                strlcpy(device_name, mixer_device_name, DEVICE_NAME_MAX_SIZE-1);
+                break;
+            }
+        }
+    }
+
+
     if(snd_devices != NULL) {
         for (i = 0; i <  my_data->num_snd_devices; i++) {
             if (snd_device == (snd_device_t)snd_devices[i]) {
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 378ca83..923135e 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -1303,7 +1303,7 @@
     backend_table[SND_DEVICE_OUT_VOICE_SPEAKER_VBAT] = strdup("vbat-voice-speaker");
 
     /*remove ALAC & APE from DSP decoder list based on software decoder availability*/
-    for (count = 0; count < sizeof(dsp_only_decoders_mime)/sizeof(dsp_only_decoders_mime[0]);
+    for (count = 0; count < (int32_t) (sizeof(dsp_only_decoders_mime)/sizeof(dsp_only_decoders_mime[0]));
             count++) {
 
         if (!strncmp(MEDIA_MIMETYPE_AUDIO_ALAC, dsp_only_decoders_mime[count],
@@ -1311,14 +1311,14 @@
 
             if(property_get_bool("use.qti.sw.alac.decoder", false)) {
                 ALOGD("Alac software decoder is available...removing alac from DSP decoder list");
-                strncpy(dsp_only_decoders_mime[count],"none",5);
+                strlcpy(dsp_only_decoders_mime[count],"none",5);
             }
         } else if (!strncmp(MEDIA_MIMETYPE_AUDIO_APE, dsp_only_decoders_mime[count],
              strlen(dsp_only_decoders_mime[count]))) {
 
             if(property_get_bool("use.qti.sw.ape.decoder", false)) {
                 ALOGD("APE software decoder is available...removing ape from DSP decoder list");
-                strncpy(dsp_only_decoders_mime[count],"none",5);
+                strlcpy(dsp_only_decoders_mime[count],"none",5);
            }
         }
     }
@@ -1445,7 +1445,7 @@
                               sizeof(struct param_data), &calib);
         if (ret < 0) {
             ALOGE("%s get_calibration failed type=%s calib.size=%d\n"
-                , __func__, cal_name_info[type], codec_buffer.size);
+                , __func__, cal_name_info[type], calib.buff_size);
             free(calib.buff);
             continue;
         }
@@ -1564,7 +1564,8 @@
 #define TZ_TYPE "/sys/class/thermal/thermal_zone%d/type"
 #define TZ_WSA "/sys/class/thermal/thermal_zone%d/temp"
 
-static bool is_wsa_found(int *wsaCount)
+static bool check_and_get_wsa_info(char *snd_card_name, int *wsaCount,
+                                   bool *is_wsa_combo_supported)
 {
     DIR *tdir = NULL;
     struct dirent *tdirent = NULL;
@@ -1614,6 +1615,19 @@
          ALOGD("Found %d WSA present on the platform", wsa_count);
          found = true;
          *wsaCount = wsa_count;
+
+        /* update wsa combo supported flag based on sound card name */
+        /* wsa combo flag needs to be set to true only for hardware
+           combinations which has support for both wsa and non-wsa speaker */
+        *is_wsa_combo_supported = false;
+        if(snd_card_name) {
+            if ((!strncmp(snd_card_name, "msm8953-snd-card-mtp",
+                    sizeof("msm8953-snd-card-mtp")) ||
+                (!strncmp(snd_card_name, "msm8952-skum-snd-card",
+                    sizeof("msm8952-skum-snd-card"))))) {
+                *is_wsa_combo_supported = true;
+            }
+        }
     }
     closedir(tdir);
     chdir(cwd); /* Restore current working dir */
@@ -1634,6 +1648,7 @@
     struct mixer_ctl *ctl = NULL;
     int idx;
     int wsaCount =0;
+    bool is_wsa_combo_supported = false;
 
     my_data = calloc(1, sizeof(struct platform_data));
 
@@ -1749,14 +1764,19 @@
         }
     }
 
-    if (is_wsa_found(&wsaCount)) {
+    if (check_and_get_wsa_info((char *)snd_card_name, &wsaCount, &is_wsa_combo_supported)) {
         /*Set ACDB ID of Stereo speaker if two WSAs are present*/
         /*Default ACDB ID for wsa speaker is that for mono*/
         if (wsaCount == 2) {
             platform_set_snd_device_acdb_id(SND_DEVICE_OUT_SPEAKER_WSA, 15);
             platform_set_snd_device_acdb_id(SND_DEVICE_OUT_SPEAKER_VBAT, 15);
         }
+
         my_data->is_wsa_speaker = true;
+
+        if (is_wsa_combo_supported)
+            hw_info_enable_wsa_combo_usecase_support(my_data->hw_info);
+
     }
 
     property_get("persist.audio.FFSP.enable", ffspEnable, "");
@@ -2287,11 +2307,14 @@
 int native_audio_set_params(struct platform_data *platform,
                             struct str_parms *parms, char *value, int len)
 {
-    int ret = 0;
+    int ret = -1;
     struct audio_usecase *usecase;
     struct listnode *node;
     int mode = NATIVE_AUDIO_MODE_INVALID;
 
+    if (!value)
+        return ret;
+
     ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_NATIVE_AUDIO_MODE,
                              value, len);
     if (ret >= 0) {
@@ -2340,7 +2363,7 @@
                     OUTPUT_SAMPLING_RATE_44100 == usecase->stream.out->sample_rate) {
                          ALOGD("%s:napb: triggering dynamic device switch for usecase(%d: %s)"
                                " stream(%p), device(%d)", __func__, usecase->id,
-                               use_case_table[usecase->id], usecase->stream,
+                               use_case_table[usecase->id], (void*) usecase->stream.out,
                                usecase->stream.out->devices);
                          select_devices(platform->adev, usecase->id);
                  }
@@ -3448,7 +3471,7 @@
 
 static void set_audiocal(void *platform, struct str_parms *parms, char *value, int len) {
     struct platform_data *my_data = (struct platform_data *)platform;
-    struct stream_out out={0};
+    struct stream_out out;
     acdb_audio_cal_cfg_t cal={0};
     uint8_t *dptr = NULL;
     int32_t dlen;
@@ -3689,7 +3712,7 @@
 
 static void get_audiocal(void *platform, void *keys, void *pReply) {
     struct platform_data *my_data = (struct platform_data *)platform;
-    struct stream_out out={0};
+    struct stream_out out;
     struct str_parms *query = (struct str_parms *)keys;
     struct str_parms *reply=(struct str_parms *)pReply;
     acdb_audio_cal_cfg_t cal={0};
@@ -3838,7 +3861,7 @@
 
             //check if unsupported mime type or not
             if(decoder_mime_type) {
-                int i = 0;
+                unsigned int i = 0;
                 for (i = 0; i < sizeof(dsp_only_decoders_mime)/sizeof(dsp_only_decoders_mime[0]); i++) {
                     if (!strncmp(decoder_mime_type, dsp_only_decoders_mime[i],
                     strlen(dsp_only_decoders_mime[i]))) {
@@ -4420,7 +4443,7 @@
 
 void platform_get_device_to_be_id_map(int **device_to_be_id, int *length)
 {
-     *device_to_be_id = msm_device_to_be_id;
+     *device_to_be_id = (int*) msm_device_to_be_id;
      *length = msm_be_id_array_len;
 }
 int platform_set_stream_channel_map(void *platform, audio_channel_mask_t channel_mask, int snd_id)
@@ -5000,7 +5023,7 @@
  * corresponding entry in audio_platform_info.xml file.
  */
 struct speaker_device_to_tz_names speaker_device_tz_names = {
-    {SND_DEVICE_OUT_SPEAKER, "", ""},
+    SND_DEVICE_OUT_SPEAKER, "", ""
 };
 
 const char *platform_get_spkr_1_tz_name(snd_device_t snd_device)
@@ -5031,7 +5054,7 @@
         goto done;
     }
     if (index != speaker_device_tz_names.snd_device) {
-        ALOGE("%s: not matching speaker device\n");
+        ALOGE("%s: not matching speaker device\n", __func__);
         ret = -EINVAL;
         goto done;
     }
@@ -5052,7 +5075,7 @@
 int platform_spkr_prot_is_wsa_analog_mode(void *adev)
 {
     struct audio_device *adev_h = adev;
-    char *snd_card_name;
+    const char *snd_card_name;
 
     /*
      * wsa analog mode is decided based on the sound card name
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 516179a..c8edd3e 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -1067,7 +1067,7 @@
 
 
      /*remove ALAC & APE from DSP decoder list based on software decoder availability*/
-     for (count = 0; count < sizeof(dsp_only_decoders_mime)/sizeof(dsp_only_decoders_mime[0]);
+     for (count = 0; count < (int32_t)(sizeof(dsp_only_decoders_mime)/sizeof(dsp_only_decoders_mime[0]));
             count++) {
 
          if (!strncmp(MEDIA_MIMETYPE_AUDIO_ALAC, dsp_only_decoders_mime[count],
@@ -1300,7 +1300,7 @@
     char value[PROPERTY_VALUE_MAX];
     struct platform_data *my_data = NULL;
     int retry_num = 0, snd_card_num = 0, key = 0;
-    const char *snd_card_name = NULL, *snd_card_name_t = NULL;
+    char *snd_card_name = NULL, *snd_card_name_t = NULL;
     char *cvd_version = NULL;
     char *snd_internal_name = NULL;
     char *tmp = NULL;
@@ -1399,9 +1399,12 @@
             if (!adev->audio_route) {
                 ALOGE("%s: Failed to init audio route controls, aborting.",
                        __func__);
-                free(my_data);
-                free(snd_card_name);
-                free(snd_card_name_t);
+                if (my_data)
+                    free(my_data);
+                if (snd_card_name)
+                    free(snd_card_name);
+                if (snd_card_name_t)
+                    free(snd_card_name_t);
                 mixer_close(adev->mixer);
                 return NULL;
             }
@@ -1416,11 +1419,13 @@
 
     if (snd_card_num >= MAX_SND_CARD) {
         ALOGE("%s: Unable to find correct sound card, aborting.", __func__);
-        free(my_data);
+        if (my_data)
+            free(my_data);
         if (snd_card_name)
             free(snd_card_name);
         if (snd_card_name_t)
             free(snd_card_name_t);
+        mixer_close(adev->mixer);
         return NULL;
     }
 
@@ -1891,6 +1896,7 @@
 
 int platform_get_default_app_type_v2(void *platform, usecase_type_t  type)
 {
+    ALOGV("%s: Platform: %p, type: %d", __func__, platform, type);
     if(type == PCM_CAPTURE)
         return DEFAULT_APP_TYPE_TX_PATH;
     else
@@ -2035,9 +2041,10 @@
                     (usecase->stream.out->devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
                     usecase->stream.out->devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) &&
                     OUTPUT_SAMPLING_RATE_44100 == usecase->stream.out->sample_rate) {
-                         ALOGD("%s:napb: triggering dynamic device switch for usecase(%d: %s)"
-                               " stream(%p), device(%d)", __func__, usecase->id,
-                               use_case_table[usecase->id], usecase->stream,
+                         ALOGD("%s:napb: triggering dynamic device switch for usecase %d, %s"
+                               " stream %p, device (%u)", __func__, usecase->id,
+                               use_case_table[usecase->id],
+                               (void*) usecase->stream.out,
                                usecase->stream.out->devices);
                          select_devices(platform->adev, usecase->id);
                  }
@@ -2679,11 +2686,16 @@
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
             if (channel_count == 2) {
                 snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_STEREO;
-            } else if (adev->active_input->enable_ns)
-                snd_device = SND_DEVICE_IN_VOICE_REC_MIC_NS;
-            else if (my_data->fluence_type != FLUENCE_NONE &&
+            } else if (my_data->fluence_type != FLUENCE_NONE &&
                      my_data->fluence_in_voice_rec) {
-                snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE;
+                if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                    snd_device = SND_DEVICE_IN_HANDSET_QMIC;
+                } else {
+                    snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE;
+                }
+                platform_set_echo_reference(adev->platform, true, out_device);
+            } else if (adev->active_input->enable_ns) {
+                snd_device = SND_DEVICE_IN_VOICE_REC_MIC_NS;
             } else {
                 snd_device = SND_DEVICE_IN_VOICE_REC_MIC;
             }
@@ -3540,7 +3552,7 @@
 
             //check if unsupported mime type or not
             if(decoder_mime_type) {
-                int i = 0;
+                unsigned int i = 0;
                 for (i = 0; i < sizeof(dsp_only_decoders_mime)/sizeof(dsp_only_decoders_mime[0]); i++) {
                     if (!strncmp(decoder_mime_type, dsp_only_decoders_mime[i],
                     strlen(dsp_only_decoders_mime[i]))) {
@@ -3995,7 +4007,7 @@
 
 void platform_get_device_to_be_id_map(int **device_to_be_id, int *length)
 {
-     *device_to_be_id = msm_device_to_be_id;
+     *device_to_be_id = (int*) msm_device_to_be_id;
      *length = msm_be_id_array_len;
 }
 int platform_set_stream_channel_map(void *platform, audio_channel_mask_t channel_mask, int snd_id)
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 6263f4e..4f2bb3d 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -263,7 +263,7 @@
 #define PLAYBACK_OFFLOAD_DEVICE2 17
 #endif
 
-#ifdef PLATFORM_APQ8084
+#if defined (PLATFORM_APQ8084) || defined (PLATFORM_MSM8996)
 #define PLAYBACK_OFFLOAD_DEVICE3 18
 #define PLAYBACK_OFFLOAD_DEVICE4 34
 #define PLAYBACK_OFFLOAD_DEVICE5 35
@@ -272,7 +272,7 @@
 #define PLAYBACK_OFFLOAD_DEVICE8 38
 #define PLAYBACK_OFFLOAD_DEVICE9 39
 #endif
-#if defined (PLATFORM_MSM8994) || defined (PLATFORM_MSM8996)
+#ifdef PLATFORM_MSM8994
 #define PLAYBACK_OFFLOAD_DEVICE3 18
 #define PLAYBACK_OFFLOAD_DEVICE4 37
 #define PLAYBACK_OFFLOAD_DEVICE5 38
diff --git a/hal/voice.c b/hal/voice.c
index b10de17..d1db987 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -276,12 +276,12 @@
     return call_state;
 }
 
-bool voice_is_in_call(struct audio_device *adev)
+bool voice_is_in_call(const struct audio_device *adev)
 {
     return adev->voice.in_call;
 }
 
-bool voice_is_in_call_rec_stream(struct stream_in *in)
+bool voice_is_in_call_rec_stream(const struct stream_in *in)
 {
     bool in_call_rec = false;
 
diff --git a/hal/voice.h b/hal/voice.h
index 7cb9e1a..efe48d8 100644
--- a/hal/voice.h
+++ b/hal/voice.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -81,8 +81,8 @@
 void voice_get_parameters(struct audio_device *adev, struct str_parms *query,
                           struct str_parms *reply);
 void voice_init(struct audio_device *adev);
-bool voice_is_in_call(struct audio_device *adev);
-bool voice_is_in_call_rec_stream(struct stream_in *in);
+bool voice_is_in_call(const struct audio_device *adev);
+bool voice_is_in_call_rec_stream(const struct stream_in *in);
 int voice_set_mic_mute(struct audio_device *dev, bool state);
 bool voice_get_mic_mute(struct audio_device *dev);
 int voice_set_volume(struct audio_device *adev, float volume);
diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c
index 1dcf865..7404617 100644
--- a/hal/voice_extn/compress_voip.c
+++ b/hal/voice_extn/compress_voip.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -38,6 +38,8 @@
 
 #define COMPRESS_VOIP_IO_BUF_SIZE_NB 320
 #define COMPRESS_VOIP_IO_BUF_SIZE_WB 640
+#define COMPRESS_VOIP_IO_BUF_SIZE_SWB 1280
+#define COMPRESS_VOIP_IO_BUF_SIZE_FB 1920
 
 struct pcm_config pcm_config_voip_nb = {
     .channels = 1,
@@ -55,6 +57,22 @@
     .format = PCM_FORMAT_S16_LE,
 };
 
+struct pcm_config pcm_config_voip_swb = {
+    .channels = 1,
+    .rate = 32000, /* changed when the stream is opened */
+    .period_size = COMPRESS_VOIP_IO_BUF_SIZE_SWB/2,
+    .period_count = 10,
+    .format = PCM_FORMAT_S16_LE,
+};
+
+struct pcm_config pcm_config_voip_fb = {
+    .channels = 1,
+    .rate = 48000, /* changed when the stream is opened */
+    .period_size = COMPRESS_VOIP_IO_BUF_SIZE_FB/2,
+    .period_count = 10,
+    .format = PCM_FORMAT_S16_LE,
+};
+
 struct voip_data {
     struct pcm *pcm_rx;
     struct pcm *pcm_tx;
@@ -467,15 +485,24 @@
 
 int voice_extn_compress_voip_out_get_buffer_size(struct stream_out *out)
 {
-    if (out->config.rate == 16000)
+    if (out->config.rate == 48000)
+        return COMPRESS_VOIP_IO_BUF_SIZE_FB;
+    else if (out->config.rate== 32000)
+        return COMPRESS_VOIP_IO_BUF_SIZE_SWB;
+    else if (out->config.rate == 16000)
         return COMPRESS_VOIP_IO_BUF_SIZE_WB;
     else
         return COMPRESS_VOIP_IO_BUF_SIZE_NB;
+
 }
 
 int voice_extn_compress_voip_in_get_buffer_size(struct stream_in *in)
 {
-    if (in->config.rate == 16000)
+    if (in->config.rate == 48000)
+        return COMPRESS_VOIP_IO_BUF_SIZE_FB;
+    else if (in->config.rate== 32000)
+        return COMPRESS_VOIP_IO_BUF_SIZE_SWB;
+    else if (in->config.rate == 16000)
         return COMPRESS_VOIP_IO_BUF_SIZE_WB;
     else
         return COMPRESS_VOIP_IO_BUF_SIZE_NB;
@@ -570,7 +597,11 @@
     out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_MONO;
     out->channel_mask = AUDIO_CHANNEL_OUT_MONO;
     out->usecase = USECASE_COMPRESS_VOIP_CALL;
-    if (out->sample_rate == 16000)
+    if (out->sample_rate == 48000)
+        out->config = pcm_config_voip_fb;
+    else if (out->sample_rate == 32000)
+        out->config = pcm_config_voip_swb;
+    else if (out->sample_rate == 16000)
         out->config = pcm_config_voip_wb;
     else
         out->config = pcm_config_voip_nb;
@@ -624,7 +655,11 @@
         goto done;
 
     in->usecase = USECASE_COMPRESS_VOIP_CALL;
-    if (in->config.rate == 16000)
+    if (in->config.rate == 48000)
+        in->config = pcm_config_voip_fb;
+    else if (in->config.rate == 32000)
+        in->config = pcm_config_voip_swb;
+    else if (in->config.rate == 16000)
         in->config = pcm_config_voip_wb;
     else
         in->config = pcm_config_voip_nb;
@@ -689,7 +724,7 @@
         return false;
 }
 
-bool voice_extn_compress_voip_is_active(struct audio_device *adev)
+bool voice_extn_compress_voip_is_active(const struct audio_device *adev)
 {
     struct audio_usecase *voip_usecase = NULL;
     voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
@@ -716,7 +751,8 @@
     ret = voice_extn_compress_voip_is_format_supported(config->format);
     if (ret) {
         if ((popcount(config->channel_mask) == 1) &&
-            (config->sample_rate == 8000 || config->sample_rate == 16000))
+            (config->sample_rate == 8000 || config->sample_rate == 16000 ||
+             config->sample_rate == 32000 || config->sample_rate == 48000))
             ret = ((voip_data.sample_rate == 0) ? true:
                     (voip_data.sample_rate == config->sample_rate));
         else
diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h
index af0ad08..989ee79 100644
--- a/hal/voice_extn/voice_extn.h
+++ b/hal/voice_extn/voice_extn.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 2016, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -142,7 +142,7 @@
                                                 struct str_parms *query,
                                                 struct str_parms *reply);
 bool voice_extn_compress_voip_pcm_prop_check();
-bool voice_extn_compress_voip_is_active(struct audio_device *adev);
+bool voice_extn_compress_voip_is_active(const struct audio_device *adev);
 bool voice_extn_compress_voip_is_format_supported(audio_format_t format);
 bool voice_extn_compress_voip_is_config_supported(struct audio_config *config);
 bool voice_extn_compress_voip_is_started(struct audio_device *adev);
diff --git a/policy_hal/Android.mk b/policy_hal/Android.mk
index 70814d8..811c2c9 100644
--- a/policy_hal/Android.mk
+++ b/policy_hal/Android.mk
@@ -27,6 +27,8 @@
 LOCAL_STATIC_LIBRARIES := \
     libmedia_helper \
 
+LOCAL_CFLAGS += -Wall -Werror
+
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_VOICE_CONCURRENCY)),true)
 LOCAL_CFLAGS += -DVOICE_CONCURRENCY
 endif
diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp
index 2f657d5..b3ba637 100644
--- a/policy_hal/AudioPolicyManager.cpp
+++ b/policy_hal/AudioPolicyManager.cpp
@@ -291,9 +291,6 @@
                mPrimaryOutput->changeRefCount(AUDIO_STREAM_MUSIC, -1);
            }
            AudioParameter param = AudioParameter();
-           float volumeDb = mPrimaryOutput->mCurVolume[AUDIO_STREAM_MUSIC];
-           mPrevFMVolumeDb = volumeDb;
-           param.addFloat(String8("fm_volume"), Volume::DbToAmpl(volumeDb));
            param.addInt(String8("handle_fm"), (int)newDevice);
            mpClientInterface->setParameters(mPrimaryOutput->mIoHandle, param.toString());
         }
@@ -672,7 +669,7 @@
     /// Opens: can these line be executed after the switch of volume curves???
     // if leaving call state, handle special case of active streams
     // pertaining to sonification strategy see handleIncallSonification()
-    if (isInCall()) {
+    if (isStateInCall(oldState)) {
         ALOGV("setPhoneState() in call state management: new state is %d", state);
         for (size_t j = 0; j < mOutputs.size(); j++) {
             audio_io_handle_t curOutput = mOutputs.keyAt(j);
@@ -684,7 +681,7 @@
             }
         }
 
-        // force reevaluating accessibility routing when call starts
+        // force reevaluating accessibility routing when call stops
         mpClientInterface->invalidateStream(AUDIO_STREAM_ACCESSIBILITY);
     }
 
@@ -960,6 +957,9 @@
                 handleIncallSonification((audio_stream_type_t)stream, true, true, curOutput);
            }
         }
+
+       // force reevaluating accessibility routing when call starts
+       mpClientInterface->invalidateStream(AUDIO_STREAM_ACCESSIBILITY);
     }
 
     // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE
@@ -1471,7 +1471,8 @@
 
     if ((stream == AUDIO_STREAM_VOICE_CALL) &&
         (channelMask == 1) &&
-        (samplingRate == 8000 || samplingRate == 16000)) {
+        (samplingRate == 8000 || samplingRate == 16000 ||
+         samplingRate == 32000 || samplingRate == 48000)) {
         // Allow Voip direct output only if:
         // audio mode is MODE_IN_COMMUNCATION; AND
         // voip output is not opened already; AND
diff --git a/post_proc/Android.mk b/post_proc/Android.mk
index 527406b..e5f0824 100644
--- a/post_proc/Android.mk
+++ b/post_proc/Android.mk
@@ -81,7 +81,7 @@
 
 ################################################################################
 
-ifneq ($(filter msm8992 msm8994 msm8996 msm8952 msm8937 thorium titanium msmgold,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8992 msm8994 msm8996 msm8952 msm8937 thorium msm8953 msmgold,$(TARGET_BOARD_PLATFORM)),)
 
 include $(CLEAR_VARS)
 
diff --git a/post_proc/bundle.c b/post_proc/bundle.c
index 2bc7fad..d39a8b7 100644
--- a/post_proc/bundle.c
+++ b/post_proc/bundle.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -287,7 +287,7 @@
 __attribute__ ((visibility ("default")))
 int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id)
 {
-    int ret;
+    int ret = -1;
     struct listnode *node;
     struct listnode *fx_node;
     output_context_t *out_ctxt;