Merge "hal: mpq:  configure HDMI channel number"
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 3f457d2..80ce063 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -61,13 +61,6 @@
 void audio_extn_hfp_set_parameters(struct audio_device *adev,
                                            struct str_parms *parms);
 #endif
-#ifndef SSR_ENABLED
-#define audio_extn_ssr_get_parameters(query, reply) (0)
-#else
-void audio_extn_ssr_get_parameters(struct str_parms *query,
-
-                                          struct str_parms *reply);
-#endif
 
 #ifndef ANC_HEADSET_ENABLED
 #define audio_extn_set_anc_parameters(adev, parms)       (0)
@@ -335,7 +328,6 @@
                               struct str_parms *reply)
 {
     audio_extn_get_afe_proxy_parameters(query, reply);
-    audio_extn_ssr_get_parameters(query, reply);
 
     ALOGD("%s: returns %s", __func__, str_parms_to_str(reply));
 }
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 6bd03ee..72f8642 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -70,14 +70,14 @@
 #ifndef SSR_ENABLED
 #define audio_extn_ssr_init(adev, in)                 (0)
 #define audio_extn_ssr_deinit()                       (0)
-#define audio_extn_ssr_update_enabled(adev)           (0)
+#define audio_extn_ssr_update_enabled()               (0)
 #define audio_extn_ssr_get_enabled()                  (0)
 #define audio_extn_ssr_read(stream, buffer, bytes)    (0)
 #else
 int32_t audio_extn_ssr_init(struct audio_device *adev,
                             struct stream_in *in);
 int32_t audio_extn_ssr_deinit();
-int32_t audio_extn_ssr_update_enabled(struct audio_device *adev);
+void audio_extn_ssr_update_enabled();
 bool audio_extn_ssr_get_enabled();
 int32_t audio_extn_ssr_read(struct audio_stream_in *stream,
                        void *buffer, size_t bytes);
@@ -165,4 +165,10 @@
 int audio_extn_dolby_set_DMID(struct audio_device *adev);
 #endif
 
+#ifndef HFP_ENABLED
+#define audio_extn_hfp_is_active(adev)                  (0)
+#else
+bool audio_extn_hfp_is_active(struct audio_device *adev);
+#endif
+
 #endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c
index 6b0546a..2d6e1e0 100644
--- a/hal/audio_extn/hfp.c
+++ b/hal/audio_extn/hfp.c
@@ -42,6 +42,7 @@
 
 #ifdef HFP_ENABLED
 #define AUDIO_PARAMETER_HFP_ENABLE      "hfp_enable"
+#define AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE "hfp_set_sampling_rate"
 
 static int32_t start_hfp(struct audio_device *adev,
                                struct str_parms *parms);
@@ -55,6 +56,7 @@
     struct pcm *hfp_pcm_tx;
     bool is_hfp_running;
     int hfp_volume;
+    audio_usecase_t ucid;
 };
 
 static struct hfp_module hfpmod = {
@@ -64,6 +66,7 @@
     .hfp_pcm_tx = NULL,
     .hfp_volume = 0,
     .is_hfp_running = 0,
+    .ucid = USECASE_AUDIO_HFP_SCO,
 };
 static struct pcm_config pcm_config_hfp = {
     .channels = 1,
@@ -86,7 +89,7 @@
     ALOGD("%s: enter", __func__);
 
     uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
-    uc_info->id = USECASE_AUDIO_HFP_SCO;
+    uc_info->id = hfpmod.ucid;
     uc_info->type = PCM_HFP_CALL;
     uc_info->stream.out = adev->primary_output;
     uc_info->devices = adev->primary_output->devices;
@@ -95,7 +98,7 @@
 
     list_add_tail(&adev->usecase_list, &uc_info->list);
 
-    select_devices(adev, USECASE_AUDIO_HFP_SCO);
+    select_devices(adev, hfpmod.ucid);
 
     pcm_dev_rx_id = platform_get_pcm_device_id(uc_info->id, PCM_PLAYBACK);
     pcm_dev_tx_id = platform_get_pcm_device_id(uc_info->id, PCM_CAPTURE);
@@ -193,10 +196,10 @@
         hfpmod.hfp_pcm_tx = NULL;
     }
 
-    uc_info = get_usecase_from_list(adev, USECASE_AUDIO_HFP_SCO);
+    uc_info = get_usecase_from_list(adev, hfpmod.ucid);
     if (uc_info == NULL) {
         ALOGE("%s: Could not find the usecase (%d) in the list",
-              __func__, USECASE_AUDIO_HFP_SCO);
+              __func__, hfpmod.ucid);
         return -EINVAL;
     }
 
@@ -214,9 +217,22 @@
     return ret;
 }
 
+bool audio_extn_hfp_is_active(struct audio_device *adev)
+{
+    struct audio_usecase *hfp_usecase = NULL;
+    hfp_usecase = get_usecase_from_list(adev, USECASE_AUDIO_HFP_SCO);
+
+    if (hfp_usecase != NULL)
+        return true;
+    else
+        return false;
+}
+
 void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
 {
     int ret;
+    int rate;
+    int val;
     char value[32]={0};
 
     ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
@@ -227,5 +243,32 @@
            else
                stop_hfp(adev);
     }
+    memset(value, 0, sizeof(value));
+    ret = str_parms_get_str(parms,AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE, value,
+                            sizeof(value));
+    if (ret >= 0) {
+           rate = atoi(value);
+           if (rate == 8000){
+               hfpmod.ucid = USECASE_AUDIO_HFP_SCO;
+               pcm_config_hfp.rate = rate;
+           }
+           else if (rate == 16000){
+               hfpmod.ucid = USECASE_AUDIO_HFP_SCO_WB;
+               pcm_config_hfp.rate = rate;
+           }
+           else
+               ALOGE("Unsupported rate..");
+    }
+
+    if(hfpmod.is_hfp_running) {
+        memset(value, 0, sizeof(value));
+        ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
+                                value, sizeof(value));
+        if (ret >= 0) {
+            val = atoi(value);
+            if(val > 0)
+                select_devices(adev, hfpmod.ucid);
+        }
+    }
 }
 #endif /*HFP_ENABLED*/
diff --git a/hal/audio_extn/ssr.c b/hal/audio_extn/ssr.c
index efd92ea..ac6da8b 100644
--- a/hal/audio_extn/ssr.c
+++ b/hal/audio_extn/ssr.c
@@ -34,14 +34,13 @@
 #include "surround_filters_interface.h"
 
 #ifdef SSR_ENABLED
-#define COEFF_ARRAY_SIZE      4
-#define FILT_SIZE             ((512+1)* 6)  /* # ((FFT bins)/2+1)*numOutputs */
-#define SSR_FRAME_SIZE        512
-#define SSR_INPUT_FRAME_SIZE  (SSR_FRAME_SIZE * 4)
-#define SSR_OUTPUT_FRAME_SIZE (SSR_FRAME_SIZE * 6)
-#define SSR_CHANNEL_COUNT     4
-#define SSR_PERIOD_SIZE       256
-#define SSR_PERIOD_COUNT      8
+#define COEFF_ARRAY_SIZE            4
+#define FILT_SIZE                   ((512+1)* 6)  /* # ((FFT bins)/2+1)*numOutputs */
+#define SSR_CHANNEL_INPUT_NUM       4
+#define SSR_CHANNEL_OUTPUT_NUM      6
+#define SSR_PERIOD_COUNT            8
+#define SSR_PERIOD_SIZE             512
+#define SSR_INPUT_FRAME_SIZE        (SSR_PERIOD_SIZE * SSR_PERIOD_COUNT)
 
 #define SURROUND_FILE_1R "/system/etc/surround_sound/filter1r.pcm"
 #define SURROUND_FILE_2R "/system/etc/surround_sound/filter2r.pcm"
@@ -52,7 +51,7 @@
 #define SURROUND_FILE_2I "/system/etc/surround_sound/filter2i.pcm"
 #define SURROUND_FILE_3I "/system/etc/surround_sound/filter3i.pcm"
 #define SURROUND_FILE_4I "/system/etc/surround_sound/filter4i.pcm"
-#define AUDIO_PARAMETER_KEY_SSR "ssr"
+
 #define LIB_SURROUND_PROC       "libsurround_proc.so"
 
 typedef int  (*surround_filters_init_t)(void *, int, int, Word16 **,
@@ -67,11 +66,7 @@
     int16_t             **real_coeffs;
     int16_t             **imag_coeffs;
     void                *surround_obj;
-
-    int16_t             *surround_input_buffer;
-    int16_t             *surround_output_buffer;
-    int                 surround_input_bufferIdx;
-    int                 surround_output_bufferIdx;
+    int16_t             *surround_raw_buffer;
     bool                is_ssr_enabled;
 
     void *surround_filters_handle;
@@ -81,19 +76,13 @@
     surround_filters_intl_process_t surround_filters_intl_process;
 };
 
-static int32_t ssr_init_surround_sound_lib(unsigned long buffersize);
-static int32_t ssr_read_coeffs_from_file();
-
 static struct ssr_module ssrmod = {
     .fp_4ch = NULL,
-    .fp_6ch= NULL,
+    .fp_6ch = NULL,
     .real_coeffs = NULL,
     .imag_coeffs = NULL,
     .surround_obj = NULL,
-    .surround_output_buffer = NULL,
-    .surround_input_buffer = NULL,
-    .surround_output_bufferIdx = 0,
-    .surround_input_bufferIdx= 0,
+    .surround_raw_buffer = NULL,
     .is_ssr_enabled = 0,
 
     .surround_filters_handle = NULL,
@@ -230,32 +219,20 @@
     int high_freq = 100;
     int i, ret = 0;
 
-    ssrmod.surround_input_bufferIdx = 0;
-    ssrmod.surround_output_bufferIdx = 0;
-
     if ( ssrmod.surround_obj ) {
         ALOGE("%s: ola filter library is already initialized", __func__);
         return 0;
     }
 
     /* Allocate memory for input buffer */
-    ssrmod.surround_input_buffer = (Word16 *) calloc(2 * SSR_INPUT_FRAME_SIZE,
+    ssrmod.surround_raw_buffer = (Word16 *) calloc(buffersize,
                                               sizeof(Word16));
-    if ( !ssrmod.surround_input_buffer ) {
+    if ( !ssrmod.surround_raw_buffer ) {
        ALOGE("%s: Memory allocation failure. Not able to allocate "
              "memory for surroundInputBuffer", __func__);
        goto init_fail;
     }
 
-    /* Allocate memory for output buffer */
-    ssrmod.surround_output_buffer = (Word16 *) calloc(2 * SSR_OUTPUT_FRAME_SIZE,
-                                               sizeof(Word16));
-    if ( !ssrmod.surround_output_buffer ) {
-       ALOGE("%s: Memory allocation failure. Not able to "
-             "allocate memory for surroundOutputBuffer", __func__);
-       goto init_fail;
-    }
-
     /* Allocate memory for real and imag coeffs array */
     ssrmod.real_coeffs = (Word16 **) calloc(COEFF_ARRAY_SIZE, sizeof(Word16 *));
     if ( !ssrmod.real_coeffs ) {
@@ -353,13 +330,9 @@
         free(ssrmod.surround_obj);
         ssrmod.surround_obj = NULL;
     }
-    if (ssrmod.surround_output_buffer) {
-        free(ssrmod.surround_output_buffer);
-        ssrmod.surround_output_buffer = NULL;
-    }
-    if (ssrmod.surround_input_buffer) {
-        free(ssrmod.surround_input_buffer);
-        ssrmod.surround_input_buffer = NULL;
+    if (ssrmod.surround_raw_buffer) {
+        free(ssrmod.surround_raw_buffer);
+        ssrmod.surround_raw_buffer = NULL;
     }
     if (ssrmod.real_coeffs){
         for (i =0; i<COEFF_ARRAY_SIZE; i++ ) {
@@ -385,7 +358,7 @@
     return -ENOMEM;
 }
 
-int32_t audio_extn_ssr_update_enabled(struct audio_device *adev)
+void audio_extn_ssr_update_enabled()
 {
     char ssr_enabled[PROPERTY_VALUE_MAX] = "false";
 
@@ -397,7 +370,6 @@
         ALOGD("%s: surround sound recording is not supported", __func__);
         ssrmod.is_ssr_enabled = false;
     }
-    return 0;
 }
 
 bool audio_extn_ssr_get_enabled()
@@ -414,12 +386,13 @@
     uint32_t buffer_size;
 
     ALOGD("%s: ssr case ", __func__);
-    in->config.channels = SSR_CHANNEL_COUNT;
+    in->config.channels = SSR_CHANNEL_INPUT_NUM;
     in->config.period_size = SSR_PERIOD_SIZE;
     in->config.period_count = SSR_PERIOD_COUNT;
 
-    buffer_size = (SSR_PERIOD_SIZE)*(SSR_PERIOD_COUNT);
-    ALOGD("%s: buffer_size: %d", __func__, buffer_size);
+    /* use 4k hardcoded buffer size for ssr*/
+    buffer_size = SSR_INPUT_FRAME_SIZE;
+    ALOGV("%s: buffer_size: %d", __func__, buffer_size);
 
     ret = ssr_init_surround_sound_lib(buffer_size);
     if (0 != ret) {
@@ -429,16 +402,16 @@
     }
 
     property_get("ssr.pcmdump",c_multi_ch_dump,"0");
-    if (0 == strncmp("true",c_multi_ch_dump, sizeof("ssr.dump-pcm"))) {
-    /* Remember to change file system permission of data(e.g. chmod 777 data/),
-      otherwise, fopen may fail */
-    if ( !ssrmod.fp_4ch)
-    ssrmod.fp_4ch = fopen("/data/media/0/4ch_ssr.pcm", "wb");
-    if ( !ssrmod.fp_6ch)
-    ssrmod.fp_6ch = fopen("/data/media/0/6ch_ssr.pcm", "wb");
-    if ((!ssrmod.fp_4ch) || (!ssrmod.fp_6ch))
-        ALOGE("%s: mfp_4ch or mfp_6ch open failed: mfp_4ch:%p mfp_6ch:%p",
-              __func__, ssrmod.fp_4ch, ssrmod.fp_6ch);
+    if (0 == strncmp("true", c_multi_ch_dump, sizeof("ssr.dump-pcm"))) {
+        /* Remember to change file system permission of data(e.g. chmod 777 data/),
+          otherwise, fopen may fail */
+        if ( !ssrmod.fp_4ch)
+            ssrmod.fp_4ch = fopen("/data/4ch.pcm", "wb");
+        if ( !ssrmod.fp_6ch)
+            ssrmod.fp_6ch = fopen("/data/6ch.pcm", "wb");
+        if ((!ssrmod.fp_4ch) || (!ssrmod.fp_6ch))
+            ALOGE("%s: mfp_4ch or mfp_6ch open failed: mfp_4ch:%p mfp_6ch:%p",
+                  __func__, ssrmod.fp_4ch, ssrmod.fp_6ch);
     }
 
     return 0;
@@ -449,7 +422,7 @@
     int i;
 
     if (ssrmod.surround_obj) {
-        ALOGD("%s: entry", __func__);
+        ALOGV("%s: entry", __func__);
         ssrmod.surround_filters_release(ssrmod.surround_obj);
         if (ssrmod.surround_obj)
             free(ssrmod.surround_obj);
@@ -474,25 +447,21 @@
             free(ssrmod.imag_coeffs);
             ssrmod.imag_coeffs = NULL;
         }
-        if (ssrmod.surround_output_buffer){
-            free(ssrmod.surround_output_buffer);
-            ssrmod.surround_output_buffer = NULL;
+        if (ssrmod.surround_raw_buffer) {
+            free(ssrmod.surround_raw_buffer);
+            ssrmod.surround_raw_buffer = NULL;
         }
-        if (ssrmod.surround_input_buffer) {
-            free(ssrmod.surround_input_buffer);
-            ssrmod.surround_input_buffer = NULL;
-        }
-
-        if ( ssrmod.fp_4ch ) fclose(ssrmod.fp_4ch);
-        if ( ssrmod.fp_6ch ) fclose(ssrmod.fp_6ch);
+        if (ssrmod.fp_4ch)
+            fclose(ssrmod.fp_4ch);
+        if (ssrmod.fp_6ch)
+            fclose(ssrmod.fp_6ch);
     }
 
-    if(ssrmod.surround_filters_handle)
-    {
+    if(ssrmod.surround_filters_handle) {
         dlclose(ssrmod.surround_filters_handle);
         ssrmod.surround_filters_handle = NULL;
     }
-    ALOGD("%s: exit", __func__);
+    ALOGV("%s: exit", __func__);
 
     return 0;
 }
@@ -500,120 +469,36 @@
 int32_t audio_extn_ssr_read(struct audio_stream_in *stream,
                        void *buffer, size_t bytes)
 {
-    int processed = 0;
-    int processed_pending;
-    void *buffer_start = buffer;
-    unsigned period_bytes;
-    unsigned period_samples;
-    int read_pending, n;
-    size_t read_bytes = 0;
-    int samples = bytes >> 1;
-
     struct stream_in *in = (struct stream_in *)stream;
     struct audio_device *adev = in->dev;
+    size_t peroid_bytes;
+    int32_t ret;
 
-    period_bytes = in->config.period_size;
-    ALOGD("%s: period_size: %d", __func__, in->config.period_size);
-    period_samples = period_bytes >> 1;
+    /* Convert bytes for 6ch to 4ch*/
+    peroid_bytes = (bytes / SSR_CHANNEL_OUTPUT_NUM) * SSR_CHANNEL_INPUT_NUM;
 
-    if (!ssrmod.surround_obj)
+    if (!ssrmod.surround_obj) {
+        ALOGE("%s: surround_obj not initialized", __func__);
         return -ENOMEM;
-
-    do {
-            if (ssrmod.surround_output_bufferIdx > 0) {
-                ALOGV("%s: copy processed output "
-                     "to buffer, surround_output_bufferIdx = %d",
-                     __func__, ssrmod.surround_output_bufferIdx);
-                /* Copy processed output to buffer */
-                processed_pending = ssrmod.surround_output_bufferIdx;
-                if (processed_pending > (samples - processed)) {
-                    processed_pending = (samples - processed);
-                }
-                memcpy(buffer, ssrmod.surround_output_buffer, processed_pending * sizeof(Word16));
-                buffer = (char*)buffer + processed_pending * sizeof(Word16);
-                processed += processed_pending;
-                if (ssrmod.surround_output_bufferIdx > processed_pending) {
-                    /* Shift leftover samples to beginning of the buffer */
-                    memcpy(&ssrmod.surround_output_buffer[0],
-                           &ssrmod.surround_output_buffer[processed_pending],
-                           (ssrmod.surround_output_bufferIdx - processed_pending) * sizeof(Word16));
-                }
-                ssrmod.surround_output_bufferIdx -= processed_pending;
-            }
-
-            if (processed >= samples) {
-                ALOGV("%s: done processing buffer, "
-                     "processed = %d", __func__, processed);
-                /* Done processing this buffer */
-                break;
-            }
-
-            /* Fill input buffer until there is enough to process */
-            read_pending = SSR_INPUT_FRAME_SIZE - ssrmod.surround_input_bufferIdx;
-            read_bytes = ssrmod.surround_input_bufferIdx;
-            while (in->pcm && read_pending > 0) {
-                n = pcm_read(in->pcm, &ssrmod.surround_input_buffer[read_bytes],
-                             period_bytes);
-                ALOGV("%s: pcm_read() returned n = %d buffer:%p size:%d", __func__,
-                    n, &ssrmod.surround_input_buffer[read_bytes], period_bytes);
-                if (n && n != -EAGAIN) {
-                    /* Recovery part of pcm_read. TODO:split recovery */
-                    return (ssize_t)n;
-                }
-                else if (n < 0) {
-                    /* Recovery is part of pcm_write. TODO split is later */
-                    return (ssize_t)n;
-                }
-                else {
-                    read_pending -= period_samples;
-                    read_bytes += period_samples;
-                }
-            }
-
-
-            if (ssrmod.fp_4ch) {
-                fwrite( ssrmod.surround_input_buffer, 1,
-                        SSR_INPUT_FRAME_SIZE * sizeof(Word16), ssrmod.fp_4ch);
-            }
-
-            /* apply ssr libs to conver 4ch to 6ch */
-            ssrmod.surround_filters_intl_process(ssrmod.surround_obj,
-                &ssrmod.surround_output_buffer[ssrmod.surround_output_bufferIdx],
-                (Word16 *)ssrmod.surround_input_buffer);
-
-            /* Shift leftover samples to beginning of input buffer */
-            if (read_pending < 0) {
-                memcpy(&ssrmod.surround_input_buffer[0],
-                       &ssrmod.surround_input_buffer[SSR_INPUT_FRAME_SIZE],
-                       (-read_pending) * sizeof(Word16));
-            }
-            ssrmod.surround_input_bufferIdx = -read_pending;
-
-            if (ssrmod.fp_6ch) {
-                fwrite( &ssrmod.surround_output_buffer[ssrmod.surround_output_bufferIdx],
-                        1, SSR_OUTPUT_FRAME_SIZE * sizeof(Word16), ssrmod.fp_6ch);
-            }
-
-            ssrmod.surround_output_bufferIdx += SSR_OUTPUT_FRAME_SIZE;
-            ALOGV("%s: do_while loop: processed=%d, samples=%d\n", __func__, processed, samples);
-        } while (in->pcm && processed < samples);
-        read_bytes = processed * sizeof(Word16);
-        buffer = buffer_start;
-
-    return 0;
-}
-
-void audio_extn_ssr_get_parameters(struct str_parms *query,
-                                   struct str_parms *reply)
-{
-    int ret, val;
-    char value[32]={0};
-
-    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_SSR, value, sizeof(value));
-
-    if (ret >= 0) {
-        memcpy(value, "true", 4);
-        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_SSR, value);
     }
+
+    ret = pcm_read(in->pcm, ssrmod.surround_raw_buffer, peroid_bytes);
+    if (ret < 0) {
+        ALOGE("%s: %s ret:%d", __func__, pcm_get_error(in->pcm),ret);
+        return ret;
+    }
+
+    /* apply ssr libs to conver 4ch to 6ch */
+    ssrmod.surround_filters_intl_process(ssrmod.surround_obj,
+        buffer, ssrmod.surround_raw_buffer);
+
+    /*dump for raw pcm data*/
+    if (ssrmod.fp_4ch)
+        fwrite(ssrmod.surround_raw_buffer, 1, peroid_bytes, ssrmod.fp_4ch);
+    if (ssrmod.fp_6ch)
+        fwrite(buffer, 1, bytes, ssrmod.fp_6ch);
+
+    return ret;
 }
+
 #endif /* SSR_ENABLED */
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index ec24265..19fdda2 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -53,7 +53,8 @@
 #include "voice_extn.h"
 
 #include "sound/compress_params.h"
-
+#define MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE (256 * 1024)
+#define MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE (8 * 1024)
 #define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024)
 #define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4
 /* ToDo: Check and update a proper value in msec */
@@ -112,6 +113,7 @@
     [USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record",
     [USECASE_AUDIO_PLAYBACK_FM] = "play-fm",
     [USECASE_AUDIO_HFP_SCO] = "hfp-sco",
+    [USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb",
     [USECASE_VOICE_CALL] = "voice-call",
     
     [USECASE_VOICE2_CALL] = "voice2-call",
@@ -150,6 +152,8 @@
 static unsigned int audio_device_ref_count;
 
 static int set_voice_volume_l(struct audio_device *adev, float volume);
+static uint32_t get_offload_buffer_size();
+static int set_gapless_mode(struct audio_device *adev);
 
 static bool is_supported_format(audio_format_t format)
 {
@@ -366,7 +370,7 @@
 
     list_for_each(node, &adev->usecase_list) {
         usecase = node_to_item(node, struct audio_usecase, list);
-        if (usecase->type == PCM_PLAYBACK &&
+        if (usecase->type != PCM_CAPTURE &&
                 usecase != uc_info &&
                 usecase->out_snd_device != snd_device &&
                 usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
@@ -410,8 +414,6 @@
                 enable_audio_route(adev, usecase, false);
             }
         }
-
-        audio_route_update_mixer(adev->audio_route);
     }
 }
 
@@ -439,7 +441,7 @@
 
     list_for_each(node, &adev->usecase_list) {
         usecase = node_to_item(node, struct audio_usecase, list);
-        if (usecase->type == PCM_CAPTURE &&
+        if (usecase->type != PCM_PLAYBACK &&
                 usecase != uc_info &&
                 usecase->in_snd_device != snd_device) {
             ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
@@ -459,6 +461,12 @@
             usecase = node_to_item(node, struct audio_usecase, list);
             if (switch_device[usecase->id]) {
                 disable_snd_device(adev, usecase->in_snd_device, false);
+            }
+        }
+
+        list_for_each(node, &adev->usecase_list) {
+            usecase = node_to_item(node, struct audio_usecase, list);
+            if (switch_device[usecase->id]) {
                 enable_snd_device(adev, snd_device, false);
             }
         }
@@ -476,57 +484,9 @@
                 enable_audio_route(adev, usecase, false);
             }
         }
-
-        audio_route_update_mixer(adev->audio_route);
     }
 }
 
-static int disable_all_usecases_of_type(struct audio_device *adev,
-                                        usecase_type_t usecase_type,
-                                        bool update_mixer)
-{
-    struct audio_usecase *usecase;
-    struct listnode *node;
-    int ret = 0;
-
-    list_for_each(node, &adev->usecase_list) {
-        usecase = node_to_item(node, struct audio_usecase, list);
-        if (usecase->type == usecase_type) {
-            ALOGV("%s: usecase id %d", __func__, usecase->id);
-            ret = disable_audio_route(adev, usecase, update_mixer);
-            if (ret) {
-                ALOGE("%s: Failed to disable usecase id %d",
-                      __func__, usecase->id);
-            }
-        }
-    }
-
-    return ret;
-}
-
-static int enable_all_usecases_of_type(struct audio_device *adev,
-                                       usecase_type_t usecase_type,
-                                       bool update_mixer)
-{
-    struct audio_usecase *usecase;
-    struct listnode *node;
-    int ret = 0;
-
-    list_for_each(node, &adev->usecase_list) {
-        usecase = node_to_item(node, struct audio_usecase, list);
-        if (usecase->type == usecase_type) {
-            ALOGV("%s: usecase id %d", __func__, usecase->id);
-            ret = enable_audio_route(adev, usecase, update_mixer);
-            if (ret) {
-                ALOGE("%s: Failed to enable usecase id %d",
-                      __func__, usecase->id);
-            }
-        }
-    }
-
-    return ret;
-}
-
 /* must be called with hw device mutex locked */
 static int read_hdmi_channel_masks(struct stream_out *out)
 {
@@ -555,6 +515,21 @@
     return ret;
 }
 
+static void update_devices_for_all_voice_usecases(struct audio_device *adev)
+{
+    struct listnode *node;
+    struct audio_usecase *usecase;
+
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if (usecase->type == VOICE_CALL) {
+            ALOGV("%s: updating device for usecase:%s", __func__,
+                  use_case_table[usecase->id]);
+            select_devices(adev, usecase->id);
+        }
+    }
+}
+
 static audio_usecase_t get_voice_usecase_id_from_list(struct audio_device *adev)
 {
     struct audio_usecase *usecase;
@@ -591,6 +566,7 @@
     struct audio_usecase *usecase = NULL;
     struct audio_usecase *vc_usecase = NULL;
     struct audio_usecase *voip_usecase = NULL;
+    struct audio_usecase *hfp_usecase = NULL;
     struct listnode *node;
     int status = 0;
 
@@ -629,6 +605,12 @@
                     in_snd_device = voip_usecase->in_snd_device;
                     out_snd_device = voip_usecase->out_snd_device;
             }
+        } else if (audio_extn_hfp_is_active(adev)) {
+            hfp_usecase = get_usecase_from_list(adev, USECASE_AUDIO_HFP_SCO);
+            if (hfp_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
+                   in_snd_device = hfp_usecase->in_snd_device;
+                   out_snd_device = hfp_usecase->out_snd_device;
+            }
         }
         if (usecase->type == PCM_PLAYBACK) {
             usecase->devices = usecase->stream.out->devices;
@@ -674,7 +656,6 @@
      */
     if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
         status = platform_switch_voice_call_device_pre(adev->platform);
-        disable_all_usecases_of_type(adev, VOICE_CALL, true);
     }
 
     /* Disable current sound devices */
@@ -710,10 +691,7 @@
     usecase->in_snd_device = in_snd_device;
     usecase->out_snd_device = out_snd_device;
 
-    if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)
-        enable_all_usecases_of_type(adev, usecase->type, true);
-    else
-        enable_audio_route(adev, usecase, true);
+    enable_audio_route(adev, usecase, true);
 
     /* Applicable only on the targets that has external modem.
      * Enable device command should be sent to modem only after
@@ -1302,26 +1280,39 @@
 {
     int ret = 0;
     char value[32];
+    bool is_meta_data_params = false;
     struct compr_gapless_mdata tmp_mdata;
-
+    tmp_mdata.encoder_delay = 0;
+    tmp_mdata.encoder_padding = 0;
     if (!out || !parms) {
+        ALOGE("%s: return invalid ",__func__);
         return -EINVAL;
     }
 
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_SAMPLE_RATE, value, sizeof(value));
+    if(ret >= 0)
+        is_meta_data_params = true;
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_NUM_CHANNEL, value, sizeof(value));
+    if(ret >= 0 )
+        is_meta_data_params = true;
+    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE, value, sizeof(value));
+    if(ret >= 0 )
+        is_meta_data_params = true;
     ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value));
     if (ret >= 0) {
+        is_meta_data_params = true;
         tmp_mdata.encoder_delay = atoi(value); //whats a good limit check?
-    } else {
-        return -EINVAL;
     }
-
     ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value));
     if (ret >= 0) {
+        is_meta_data_params = true;
         tmp_mdata.encoder_padding = atoi(value);
-    } else {
-        return -EINVAL;
     }
 
+    if(!is_meta_data_params) {
+        ALOGV("%s: Not gapless meta data params", __func__);
+        return 0;
+    }
     out->gapless_mdata = tmp_mdata;
     out->send_new_metadata = 1;
     ALOGV("%s new encoder delay %u and padding %u", __func__,
@@ -1339,14 +1330,14 @@
     struct listnode *node;
     struct str_parms *parms;
     char value[32];
-    int ret, val = 0;
+    int ret = 0, val = 0, err;
     bool select_new_device = false;
 
     ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s",
           __func__, out->usecase, use_case_table[out->usecase], kvpairs);
     parms = str_parms_create_str(kvpairs);
-    ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
-    if (ret >= 0) {
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
+    if (err >= 0) {
         val = atoi(value);
         pthread_mutex_lock(&out->lock);
         pthread_mutex_lock(&adev->lock);
@@ -1390,18 +1381,18 @@
             if ((adev->mode == AUDIO_MODE_IN_CALL) &&
                     !voice_is_in_call(adev) &&
                     (out == adev->primary_output)) {
-                voice_start_call(adev);
+                ret = voice_start_call(adev);
             } else if ((adev->mode == AUDIO_MODE_IN_CALL) &&
                             voice_is_in_call(adev) &&
                             (out == adev->primary_output)) {
-                select_devices(adev, get_voice_usecase_id_from_list(adev));
+                update_devices_for_all_voice_usecases(adev);
             }
         }
 
         if ((adev->mode == AUDIO_MODE_NORMAL) &&
                 voice_is_in_call(adev) &&
                 (out == adev->primary_output)) {
-            voice_stop_call(adev);
+            ret = voice_stop_call(adev);
         }
 
         pthread_mutex_unlock(&adev->lock);
@@ -1414,7 +1405,9 @@
         pthread_mutex_unlock(&adev->lock);
     }
     if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+        pthread_mutex_lock(&out->lock);
         parse_compress_metadata(out, parms);
+        pthread_mutex_unlock(&out->lock);
     }
 
     str_parms_destroy(parms);
@@ -1819,16 +1812,16 @@
     struct str_parms *parms;
     char *str;
     char value[32];
-    int ret, val = 0;
+    int ret = 0, val = 0, err;
 
     ALOGV("%s: enter: kvpairs=%s", __func__, kvpairs);
     parms = str_parms_create_str(kvpairs);
 
-    ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof(value));
-
     pthread_mutex_lock(&in->lock);
     pthread_mutex_lock(&adev->lock);
-    if (ret >= 0) {
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof(value));
+    if (err >= 0) {
         val = atoi(value);
         /* no audio source uses val == 0 */
         if ((in->source != val) && (val != 0)) {
@@ -1836,8 +1829,8 @@
         }
     }
 
-    ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
-    if (ret >= 0) {
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
+    if (err >= 0) {
         val = atoi(value);
         if ((in->device != val) && (val != 0)) {
             in->device = val;
@@ -1990,7 +1983,7 @@
 {
     struct audio_device *adev = (struct audio_device *)dev;
     struct stream_out *out;
-    int i, ret;
+    int i, ret = 0;
 
     ALOGV("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)",
           __func__, config->sample_rate, config->channel_mask, devices, flags);
@@ -2089,7 +2082,7 @@
         else
             out->compr_config.codec->id =
                 get_snd_codec_id(config->offload_info.format);
-        out->compr_config.fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE;
+        out->compr_config.fragment_size = get_offload_buffer_size();
         out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
         out->compr_config.codec->sample_rate =
                     compress_get_alsa_rate(config->offload_info.sample_rate);
@@ -2120,6 +2113,9 @@
             }
         }
 
+        //Decide if we need to use gapless mode by default
+        set_gapless_mode(adev);
+
     } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) {
         ret = voice_check_and_set_incall_music_usecase(adev, out);
         if (ret != 0) {
@@ -2234,18 +2230,23 @@
     char *str;
     char value[32];
     int val;
-    int ret;
+    int ret = 0, err;
 
     ALOGD("%s: enter: %s", __func__, kvpairs);
 
     pthread_mutex_lock(&adev->lock);
     parms = str_parms_create_str(kvpairs);
 
-    voice_set_parameters(adev, parms);
-    platform_set_parameters(adev->platform, parms);
+    ret = voice_set_parameters(adev, parms);
+    if (ret != 0)
+        goto done;
 
-    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value));
-    if (ret >= 0) {
+    ret = platform_set_parameters(adev->platform, parms);
+    if (ret != 0)
+        goto done;
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value));
+    if (err >= 0) {
         /* When set to false, HAL should disable EC and NS
          * But it is currently not supported.
          */
@@ -2255,16 +2256,16 @@
             adev->bluetooth_nrec = false;
     }
 
-    ret = str_parms_get_str(parms, "screen_state", value, sizeof(value));
-    if (ret >= 0) {
+    err = str_parms_get_str(parms, "screen_state", value, sizeof(value));
+    if (err >= 0) {
         if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
             adev->screen_off = false;
         else
             adev->screen_off = true;
     }
 
-    ret = str_parms_get_int(parms, "rotation", &val);
-    if (ret >= 0) {
+    err = str_parms_get_int(parms, "rotation", &val);
+    if (err >= 0) {
         bool reverse_speakers = false;
         switch(val) {
         // FIXME: note that the code below assumes that the speakers are in the correct placement
@@ -2296,8 +2297,9 @@
     }
 
     audio_extn_set_parameters(adev, parms);
-    str_parms_destroy(parms);
 
+done:
+    str_parms_destroy(parms);
     pthread_mutex_unlock(&adev->lock);
     ALOGV("%s: exit with code(%d)", __func__, ret);
     return ret;
@@ -2314,7 +2316,7 @@
     pthread_mutex_lock(&adev->lock);
 
     audio_extn_get_parameters(adev, query, reply);
-    voice_extn_get_parameters(adev, query, reply);
+    voice_get_parameters(adev, query, reply);
     platform_get_parameters(adev->platform, query, reply);
     str = str_parms_to_str(reply);
     str_parms_destroy(query);
@@ -2648,6 +2650,55 @@
     return 0;
 }
 
+/* Read  offload buffer size from a property.
+ * If value is not power of 2  round it to
+ * power of 2.
+ */
+static uint32_t get_offload_buffer_size()
+{
+    char value[PROPERTY_VALUE_MAX] = {0};
+    uint32_t fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE;
+    if((property_get("audio.offload.buffer.size.kb", value, "")) &&
+            atoi(value)) {
+        fragment_size =  atoi(value) * 1024;
+        //ring buffer size needs to be 4k aligned.
+        CHECK(!(fragment_size * COMPRESS_OFFLOAD_NUM_FRAGMENTS % 4096));
+    }
+    if(fragment_size < MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE)
+        fragment_size = MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE;
+    else if(fragment_size > MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE)
+        fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE;
+    ALOGVV("%s: fragment_size %d", __func__, fragment_size);
+    return fragment_size;
+}
+
+static int set_gapless_mode(struct audio_device *adev) {
+
+
+    char value[PROPERTY_VALUE_MAX] = {0};
+    bool gapless_enabled = false;
+    const char *mixer_ctl_name = "Compress Gapless Playback";
+    struct mixer_ctl *ctl;
+
+    ALOGV("%s:", __func__);
+    property_get("audio.offload.gapless.enabled", value, NULL);
+    gapless_enabled = atoi(value) || !strncmp("true", value, 4);
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                               __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+
+    if (mixer_ctl_set_value(ctl, 0, gapless_enabled) < 0) {
+        ALOGE("%s: Could not set gapless mode %d",
+                       __func__, gapless_enabled);
+         return -EINVAL;
+    }
+    return 0;
+
+}
 static struct hw_module_methods_t hal_module_methods = {
     .open = adev_open,
 };
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 3055470..205977b 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -65,6 +65,7 @@
 
     /* HFP Use case*/
     USECASE_AUDIO_HFP_SCO,
+    USECASE_AUDIO_HFP_SCO_WB,
 
     /* Capture usecases */
     USECASE_AUDIO_RECORD,
@@ -250,6 +251,12 @@
                               bool update_mixer);
 struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
                                                    audio_usecase_t uc_id);
+
+#define LITERAL_TO_STRING(x) #x
+#define CHECK(condition) LOG_ALWAYS_FATAL_IF(!(condition), "%s",\
+            __FILE__ ":" LITERAL_TO_STRING(__LINE__)\
+            " ASSERT_FATAL(" #condition ") failed.")
+
 /*
  * NOTE: when multiple mutexes have to be acquired, always take the
  * stream_in or stream_out mutex first, followed by the audio_device mutex.
diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c
index 58ca4dc..128e4af 100644
--- a/hal/msm8974/hw_info.c
+++ b/hal/msm8974/hw_info.c
@@ -51,11 +51,6 @@
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 
-#define LITERAL_TO_STRING(x) #x
-#define CHECK(condition) LOG_ALWAYS_FATAL_IF(!(condition), "%s",\
-            __FILE__ ":" LITERAL_TO_STRING(__LINE__)\
-            " ASSERT_FATAL(" #condition ") failed.")
-
 static const snd_device_t taiko_fluid_variant_devices[] = {
     SND_DEVICE_OUT_SPEAKER,
     SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
@@ -266,8 +261,7 @@
         ALOGV("8084 - variant soundcard");
         update_hardware_info_8084(hw_info, snd_card_name);
     } else {
-        ALOGE("%s: Unupported target %s:",__func__, snd_card_name);
-        CHECK(0);
+        ALOGE("%s: Unsupported target %s:",__func__, snd_card_name);
         free(hw_info);
         hw_info = NULL;
     }
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 272dea8..c7896ae 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -61,6 +61,12 @@
 #define AUDIO_PARAMETER_KEY_FLUENCE_TYPE  "fluence"
 #define AUDIO_PARAMETER_KEY_BTSCO         "bt_samplerate"
 #define AUDIO_PARAMETER_KEY_SLOWTALK      "st_enable"
+#define AUDIO_PARAMETER_KEY_VOLUME_BOOST  "volume_boost"
+
+enum {
+	VOICE_FEATURE_SET_DEFAULT,
+	VOICE_FEATURE_SET_VOLUME_BOOST
+};
 
 struct audio_block_header
 {
@@ -73,6 +79,7 @@
 typedef int  (*acdb_init_t)();
 typedef void (*acdb_send_audio_cal_t)(int, int);
 typedef void (*acdb_send_voice_cal_t)(int, int);
+typedef int (*acdb_reload_vocvoltable_t)(int);
 
 struct platform_data {
     struct audio_device *adev;
@@ -84,11 +91,13 @@
     int  btsco_sample_rate;
     bool slowtalk;
     /* Audio calibration related functions */
-    void *acdb_handle;
-    acdb_init_t acdb_init;
-    acdb_deallocate_t acdb_deallocate;
-    acdb_send_audio_cal_t acdb_send_audio_cal;
-    acdb_send_voice_cal_t acdb_send_voice_cal;
+    void                       *acdb_handle;
+    int                        voice_feature_set;
+    acdb_init_t                acdb_init;
+    acdb_deallocate_t          acdb_deallocate;
+    acdb_send_audio_cal_t      acdb_send_audio_cal;
+    acdb_send_voice_cal_t      acdb_send_voice_cal;
+    acdb_reload_vocvoltable_t  acdb_reload_vocvoltable;
 
     void *hw_info;
     struct csd_data *csd;
@@ -111,6 +120,7 @@
                                   MULTIMEDIA2_PCM_DEVICE},
     [USECASE_AUDIO_PLAYBACK_FM] = {FM_PLAYBACK_PCM_DEVICE, FM_CAPTURE_PCM_DEVICE},
     [USECASE_AUDIO_HFP_SCO] = {HFP_PCM_RX, HFP_SCO_RX},
+    [USECASE_AUDIO_HFP_SCO_WB] = {HFP_PCM_RX, HFP_SCO_RX},
     [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE, VOICE_CALL_PCM_DEVICE},
     [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE},
     [USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE},
@@ -194,6 +204,7 @@
     [SND_DEVICE_IN_CAMCORDER_MIC] = "camcorder-mic",
     [SND_DEVICE_IN_VOICE_DMIC] = "voice-dmic-ef",
     [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = "voice-speaker-dmic-ef",
+    [SND_DEVICE_IN_VOICE_SPEAKER_QMIC] = "voice-speaker-qmic",
     [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic",
     [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic",
     [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic",
@@ -266,6 +277,7 @@
     [SND_DEVICE_IN_CAMCORDER_MIC] = 4,
     [SND_DEVICE_IN_VOICE_DMIC] = 41,
     [SND_DEVICE_IN_VOICE_SPEAKER_DMIC] = 43,
+    [SND_DEVICE_IN_VOICE_SPEAKER_QMIC] = 19,
     [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16,
     [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36,
     [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16,
@@ -522,6 +534,7 @@
         }
     }
 
+    my_data->voice_feature_set = VOICE_FEATURE_SET_DEFAULT;
     my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
     if (my_data->acdb_handle == NULL) {
         ALOGE("%s: DLOPEN failed for %s", __func__, LIB_ACDB_LOADER);
@@ -529,13 +542,28 @@
         ALOGV("%s: DLOPEN successful for %s", __func__, LIB_ACDB_LOADER);
         my_data->acdb_deallocate = (acdb_deallocate_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_deallocate_ACDB");
+        if (!my_data->acdb_deallocate)
+            ALOGE("%s: Could not find the symbol acdb_loader_deallocate_ACDB from %s",
+                  __func__, LIB_ACDB_LOADER);
+
         my_data->acdb_send_audio_cal = (acdb_send_audio_cal_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_send_audio_cal");
         if (!my_data->acdb_send_audio_cal)
-            ALOGW("%s: Could not find the symbol acdb_send_audio_cal from %s",
+            ALOGE("%s: Could not find the symbol acdb_send_audio_cal from %s",
                   __func__, LIB_ACDB_LOADER);
+
         my_data->acdb_send_voice_cal = (acdb_send_voice_cal_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_send_voice_cal");
+        if (!my_data->acdb_send_voice_cal)
+            ALOGE("%s: Could not find the symbol acdb_loader_send_voice_cal from %s",
+                  __func__, LIB_ACDB_LOADER);
+
+        my_data->acdb_reload_vocvoltable = (acdb_reload_vocvoltable_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_reload_vocvoltable");
+        if (!my_data->acdb_reload_vocvoltable)
+            ALOGE("%s: Could not find the symbol acdb_loader_reload_vocvoltable from %s",
+                  __func__, LIB_ACDB_LOADER);
+
         my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_init_ACDB");
         if (my_data->acdb_init == NULL)
@@ -561,7 +589,7 @@
     audio_extn_usb_set_proxy_sound_card(adev->snd_card);
 
     /* Read one time ssr property */
-    audio_extn_ssr_update_enabled(adev);
+    audio_extn_ssr_update_enabled();
     audio_extn_spkr_prot_init(adev);
     return my_data;
 }
@@ -843,6 +871,36 @@
         goto exit;
     }
 
+    if (popcount(devices) == 2) {
+        if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+                        AUDIO_DEVICE_OUT_SPEAKER)) {
+            snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
+        } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET |
+                               AUDIO_DEVICE_OUT_SPEAKER)) {
+            if (audio_extn_get_anc_enabled())
+                snd_device = SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET;
+            else
+                snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
+        } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL |
+                               AUDIO_DEVICE_OUT_SPEAKER)) {
+            snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI;
+        } else if (devices == (AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
+                               AUDIO_DEVICE_OUT_SPEAKER)) {
+            snd_device = SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET;
+        } else {
+            ALOGE("%s: Invalid combo device(%#x)", __func__, devices);
+            goto exit;
+        }
+        if (snd_device != SND_DEVICE_NONE) {
+            goto exit;
+        }
+    }
+
+    if (popcount(devices) != 1) {
+        ALOGE("%s: Invalid output devices(%#x)", __func__, devices);
+        goto exit;
+    }
+
     if ((mode == AUDIO_MODE_IN_CALL) ||
         voice_extn_compress_voip_is_active(adev)) {
         if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
@@ -894,36 +952,6 @@
         }
     }
 
-    if (popcount(devices) == 2) {
-        if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
-                        AUDIO_DEVICE_OUT_SPEAKER)) {
-            snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
-        } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET |
-                               AUDIO_DEVICE_OUT_SPEAKER)) {
-            if (audio_extn_get_anc_enabled())
-                snd_device = SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET;
-            else
-                snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
-        } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL |
-                               AUDIO_DEVICE_OUT_SPEAKER)) {
-            snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI;
-        } else if (devices == (AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
-                               AUDIO_DEVICE_OUT_SPEAKER)) {
-            snd_device = SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET;
-        } else {
-            ALOGE("%s: Invalid combo device(%#x)", __func__, devices);
-            goto exit;
-        }
-        if (snd_device != SND_DEVICE_NONE) {
-            goto exit;
-        }
-    }
-
-    if (popcount(devices) != 1) {
-        ALOGE("%s: Invalid output devices(%#x)", __func__, devices);
-        goto exit;
-    }
-
     if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
         devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
         if (devices & AUDIO_DEVICE_OUT_WIRED_HEADSET
@@ -1329,14 +1357,14 @@
 {
     struct platform_data *my_data = (struct platform_data *)platform;
     char *str;
-    char value[32];
+    char value[256] = {0};
     int val;
-    int ret = 0;
+    int ret = 0, err;
 
     ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms));
 
-    ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_BTSCO, &val);
-    if (ret >= 0) {
+    err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_BTSCO, &val);
+    if (err >= 0) {
         str_parms_del(parms, AUDIO_PARAMETER_KEY_BTSCO);
         my_data->btsco_sample_rate = val;
         if (val == SAMPLE_RATE_16KHZ) {
@@ -1346,14 +1374,37 @@
         }
     }
 
-    ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_SLOWTALK, &val);
-    if (ret >= 0) {
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SLOWTALK, value, sizeof(value));
+    if (err >= 0) {
+        bool state = false;
+        if (!strncmp("true", value, sizeof("true"))) {
+            state = true;
+        }
+
         str_parms_del(parms, AUDIO_PARAMETER_KEY_SLOWTALK);
-        ret = platform_set_slowtalk(my_data, val);
+        ret = platform_set_slowtalk(my_data, state);
         if (ret)
             ALOGE("%s: Failed to set slow talk err: %d", __func__, ret);
     }
 
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOLUME_BOOST,
+                            value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_VOLUME_BOOST);
+
+        if (my_data->acdb_reload_vocvoltable == NULL) {
+            ALOGE("%s: acdb_reload_vocvoltable is NULL", __func__);
+        } else if (!strcmp(value, "on")) {
+            if (!my_data->acdb_reload_vocvoltable(VOICE_FEATURE_SET_VOLUME_BOOST)) {
+                my_data->voice_feature_set = 1;
+            }
+        } else {
+            if (!my_data->acdb_reload_vocvoltable(VOICE_FEATURE_SET_DEFAULT)) {
+                my_data->voice_feature_set = 0;
+            }
+        }
+    }
+
     ALOGV("%s: exit with code(%d)", __func__, ret);
     return ret;
 }
@@ -1472,8 +1523,20 @@
     ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_SLOWTALK,
                             value, sizeof(value));
     if (ret >= 0) {
-        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_SLOWTALK,
-                          my_data->slowtalk);
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_SLOWTALK,
+                          my_data->slowtalk?"true":"false");
+    }
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOLUME_BOOST,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        if (my_data->voice_feature_set == VOICE_FEATURE_SET_VOLUME_BOOST) {
+            strlcpy(value, "on", sizeof(value));
+        } else {
+            strlcpy(value, "off", sizeof(value));
+        }
+
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VOLUME_BOOST, value);
     }
 
     ALOGV("%s: exit: returns - %s", __func__, str_parms_to_str(reply));
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index e7980d6..bb1f787 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -204,8 +204,8 @@
 #elif PLATFORM_MSM8610
 #define VOICE_CALL_PCM_DEVICE 2
 #define VOICE2_CALL_PCM_DEVICE 13
-#define VOLTE_CALL_PCM_DEVICE 14
-#define QCHAT_CALL_PCM_DEVICE 20
+#define VOLTE_CALL_PCM_DEVICE 15
+#define QCHAT_CALL_PCM_DEVICE 14
 #else
 #define VOICE_CALL_PCM_DEVICE 2
 #define VOICE2_CALL_PCM_DEVICE 22
diff --git a/hal/voice.c b/hal/voice.c
index cbf8956..8783f01 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -351,20 +351,32 @@
     return ret;
 }
 
+void voice_get_parameters(struct audio_device *adev,
+                          struct str_parms *query,
+                          struct str_parms *reply)
+{
+    voice_extn_get_parameters(adev, query, reply);
+}
+
 int voice_set_parameters(struct audio_device *adev, struct str_parms *parms)
 {
     char *str;
     char value[32];
     int val;
-    int ret = 0;
+    int ret = 0, err;
 
     ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms));
 
-    voice_extn_set_parameters(adev, parms);
-    voice_extn_compress_voip_set_parameters(adev, parms);
+    ret = voice_extn_set_parameters(adev, parms);
+    if (ret != 0)
+        goto done;
 
-    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value));
-    if (ret >= 0) {
+    ret = voice_extn_compress_voip_set_parameters(adev, parms);
+    if (ret != 0)
+        goto done;
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value));
+    if (err >= 0) {
         int tty_mode;
         str_parms_del(parms, AUDIO_PARAMETER_KEY_TTY_MODE);
         if (strcmp(value, AUDIO_PARAMETER_VALUE_TTY_OFF) == 0)
@@ -389,9 +401,9 @@
         }
     }
 
-    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_INCALLMUSIC,
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_INCALLMUSIC,
                             value, sizeof(value));
-    if (ret >= 0) {
+    if (err >= 0) {
         str_parms_del(parms, AUDIO_PARAMETER_KEY_INCALLMUSIC);
         if (strcmp(value, AUDIO_PARAMETER_VALUE_TRUE) == 0)
             platform_start_incall_music_usecase(adev->platform);
@@ -412,6 +424,7 @@
     adev->voice.tty_mode = TTY_MODE_OFF;
     adev->voice.volume = 1.0f;
     adev->voice.mic_mute = false;
+    adev->voice.voice_device_set = false;
     for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
         adev->voice.session[i].pcm_rx = NULL;
         adev->voice.session[i].pcm_tx = NULL;
diff --git a/hal/voice.h b/hal/voice.h
index eeb65dc..a7733b1 100644
--- a/hal/voice.h
+++ b/hal/voice.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -60,6 +60,7 @@
     int tty_mode;
     bool mic_mute;
     float volume;
+    bool voice_device_set;
 };
 
 enum {
@@ -72,6 +73,8 @@
 int voice_start_call(struct audio_device *adev);
 int voice_stop_call(struct audio_device *adev);
 int voice_set_parameters(struct audio_device *adev, struct str_parms *parms);
+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);
 int voice_set_mic_mute(struct audio_device *dev, bool state);
diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c
index ee9fd30..5c87c9c 100644
--- a/hal/voice_extn/compress_voip.c
+++ b/hal/voice_extn/compress_voip.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -60,6 +60,7 @@
     struct pcm *pcm_tx;
     struct stream_out *out_stream;
     int ref_count;
+    int out_stream_count;
 };
 
 #define MODE_IS127              0x2
@@ -76,12 +77,14 @@
 #define AUDIO_PARAMETER_KEY_VOIP_DTX_MODE           "dtx_on"
 #define AUDIO_PARAMETER_VALUE_VOIP_TRUE             "true"
 #define AUDIO_PARAMETER_KEY_VOIP_CHECK              "voip_flag"
+#define AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT   "voip_out_stream_count"
 
 static struct voip_data voip_data = {
   .pcm_rx = NULL,
   .pcm_tx = NULL,
   .out_stream = NULL,
-  .ref_count = 0
+  .ref_count = 0,
+  .out_stream_count = 0
 };
 
 static int voip_set_volume(struct audio_device *adev, int volume);
@@ -400,53 +403,73 @@
     return ret;
 }
 
-void voice_extn_compress_voip_set_parameters(struct audio_device *adev,
+int voice_extn_compress_voip_set_parameters(struct audio_device *adev,
                                              struct str_parms *parms)
 {
     char *str;
     char value[32]={0};
-    int ret, rate;
+    int ret = 0, err, rate;
     int min_rate, max_rate;
     bool flag;
 
     ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms));
 
-    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_RATE,
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_RATE,
                             value, sizeof(value));
-    if (ret >= 0) {
+    if (err >= 0) {
         rate = atoi(value);
         voip_set_rate(adev, rate);
         voip_set_evrc_min_max_rate(adev, rate, rate);
     }
 
     memset(value, 0, sizeof(value));
-    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN,
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN,
                             value, sizeof(value));
-    if (ret >= 0) {
+    if (err >= 0) {
         min_rate = atoi(value);
         str_parms_del(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MIN);
         memset(value, 0, sizeof(value));
-        ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX,
+        err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX,
                                 value, sizeof(value));
-        if (ret >= 0) {
+        if (err >= 0) {
             max_rate = atoi(value);
             voip_set_evrc_min_max_rate(adev, min_rate, max_rate);
-        }
-        else
+        } else {
             ALOGE("%s: AUDIO_PARAMETER_KEY_VOIP_EVRC_RATE_MAX not found", __func__);
+            ret = -EINVAL;
+            goto done;
+        }
     }
 
     memset(value, 0, sizeof(value));
-    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_DTX_MODE,
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOIP_DTX_MODE,
                             value, sizeof(value));
-    if (ret >= 0) {
+    if (err >= 0) {
         flag = false;
         if (strcmp(value, AUDIO_PARAMETER_VALUE_VOIP_TRUE) == 0)
             flag = true;
         voip_set_dtx(adev, flag);
     }
 
+done:
     ALOGV("%s: exit", __func__);
+    return ret;
+}
+
+void voice_extn_compress_voip_get_parameters(const struct audio_device *adev,
+                                             struct str_parms *query,
+                                             struct str_parms *reply)
+{
+    int ret;
+    char value[32]={0};
+    char *str = NULL;
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_VOIP_OUT_STREAM_COUNT,
+                          voip_data.out_stream_count);
+    }
 }
 
 void voice_extn_compress_voip_out_get_parameters(struct stream_out *out,
@@ -550,6 +573,7 @@
 
     ret = voip_stop_call(adev);
     voip_data.out_stream = NULL;
+    voip_data.out_stream_count--;
 
     ALOGV("%s: exit: status(%d)", __func__, ret);
     return ret;
@@ -570,6 +594,7 @@
         out->config = pcm_config_voip_nb;
 
     voip_data.out_stream = out;
+    voip_data.out_stream_count++;
 
     ret = voip_set_mode(out->dev, out->format);
 
diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c
index 989a871..b8bc2df 100644
--- a/hal/voice_extn/voice_extn.c
+++ b/hal/voice_extn/voice_extn.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -34,8 +34,12 @@
 #include "platform_api.h"
 #include "voice_extn.h"
 
-#define AUDIO_PARAMETER_KEY_VSID        "vsid"
-#define AUDIO_PARAMETER_KEY_CALL_STATE  "call_state"
+#define AUDIO_PARAMETER_KEY_VSID                "vsid"
+#define AUDIO_PARAMETER_KEY_CALL_STATE          "call_state"
+#define AUDIO_PARAMETER_KEY_AUDIO_MODE          "audio_mode"
+#define AUDIO_PARAMETER_KEY_ALL_CALL_STATES     "all_call_states"
+
+#define VOICE_EXTN_PARAMETER_VALUE_MAX_LEN 256
 
 #define VOICE2_VSID 0x10DC1000
 #define VOLTE_VSID  0x10C02000
@@ -139,6 +143,7 @@
     struct voice_session *session = NULL;
     int fd = 0;
     int ret = 0;
+    bool is_in_call = false;
 
     ALOGD("%s: enter:", __func__);
 
@@ -198,6 +203,10 @@
                     ALOGE("%s: voice_end_call() failed for usecase: %d\n",
                           __func__, usecase_id);
                 } else {
+                    voice_extn_is_in_call(adev, &is_in_call);
+                    if (!is_in_call) {
+                        adev->voice.voice_device_set = false;
+                    }
                     session->state.current = session->state.new;
                 }
                 break;
@@ -270,6 +279,7 @@
     struct voice_session *session = NULL;
     int i = 0;
     bool is_in_call;
+    int no_of_calls_active = 0;
 
     for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
         if (vsid == adev->voice.session[i].vsid) {
@@ -278,17 +288,27 @@
         }
     }
 
+    for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+        if (CALL_INACTIVE != adev->voice.session[i].state.current)
+            no_of_calls_active++;
+    }
+
+    /* When there is only one call active, wait for audio policy manager to set
+     * the mode to AUDIO_MODE_NORMAL and trigger routing to end the last call.
+     */
+    if (no_of_calls_active == 1 && call_state == CALL_INACTIVE)
+        return 0;
+
     if (session) {
         session->state.new = call_state;
         voice_extn_is_in_call(adev, &is_in_call);
-        ALOGD("%s is_in_call:%d mode:%d\n", __func__, is_in_call, adev->mode);
+        ALOGD("%s is_in_call:%d voice_device_set:%d, mode:%d\n",
+              __func__, is_in_call, adev->voice.voice_device_set, adev->mode);
         /* Dont start voice call before device routing for voice usescases has
          * occured, otherwise voice calls will be started unintendedly on
          * speaker.
          */
-        if (is_in_call ||
-            (adev->mode == AUDIO_MODE_IN_CALL &&
-             adev->primary_output->devices != AUDIO_DEVICE_OUT_SPEAKER)) {
+        if (is_in_call || adev->voice.voice_device_set) {
             /* Device routing is not triggered for voice calls on the subsequent
              * subs, Hence update the call states if voice call is already
              * active on other sub.
@@ -373,6 +393,7 @@
      * udpated.
      */
     ALOGV("%s: enter:", __func__);
+    adev->voice.voice_device_set = true;
     return update_calls(adev);
 }
 
@@ -405,17 +426,17 @@
 {
     char *str;
     int value;
-    int ret = 0;
+    int ret = 0, err;
 
     ALOGV("%s: enter: %s", __func__, str_parms_to_str(parms));
 
-    ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_VSID, &value);
-    if (ret >= 0) {
+    err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_VSID, &value);
+    if (err >= 0) {
         str_parms_del(parms, AUDIO_PARAMETER_KEY_VSID);
-        int vsid = value;
+        uint32_t vsid = value;
         int call_state = -1;
-        ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_CALL_STATE, &value);
-        if (ret >= 0) {
+        err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_CALL_STATE, &value);
+        if (err >= 0) {
             call_state = value;
         } else {
             ALOGE("%s: call_state key not found", __func__);
@@ -432,7 +453,7 @@
             goto done;
         }
     } else {
-        ALOGD("%s: Not handled here", __func__);
+        ALOGV("%s: Not handled here", __func__);
     }
 
 done:
@@ -440,21 +461,53 @@
     return ret;
 }
 
+int get_all_call_states_str(const struct audio_device *adev,
+                            char *value)
+{
+    int ret = 0;
+    char *cur_ptr = value;
+    int i, len=0;
+
+    for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
+        snprintf(cur_ptr, VOICE_EXTN_PARAMETER_VALUE_MAX_LEN - len,
+                 "%d:%d,",adev->voice.session[i].vsid,
+                 adev->voice.session[i].state.current);
+        len = strlen(cur_ptr);
+        cur_ptr = cur_ptr + len;
+    }
+    ALOGV("%s:value=%s", __func__, value);
+    return ret;
+}
+
 void voice_extn_get_parameters(const struct audio_device *adev,
                                struct str_parms *query,
                                struct str_parms *reply)
 {
     int ret;
-    char value[32]={0};
+    char value[VOICE_EXTN_PARAMETER_VALUE_MAX_LEN] = {0};
     char *str = NULL;
 
-    ret = str_parms_get_str(query, "audio_mode", value,
+    ALOGV("%s: enter %s", __func__, str_parms_to_str(query));
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_AUDIO_MODE, value,
                             sizeof(value));
     if (ret >= 0) {
-        str_parms_add_int(reply, "audio_mode", adev->mode);
+        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_AUDIO_MODE, adev->mode);
     }
 
-    ALOGV("%s: returns %s", __func__, str_parms_to_str(reply));
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_ALL_CALL_STATES,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        ret = get_all_call_states_str(adev, value);
+        if (ret) {
+            ALOGE("%s: Error fetching call states, err:%d", __func__, ret);
+            return;
+        }
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_ALL_CALL_STATES, value);
+    }
+    voice_extn_compress_voip_get_parameters(adev, query, reply);
+
+    ALOGV("%s: exit: returns \"%s\"", __func__, str_parms_to_str(reply));
 }
 
 void voice_extn_out_get_parameters(struct stream_out *out,
diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h
index 0ca2386..f7d20e4 100644
--- a/hal/voice_extn/voice_extn.h
+++ b/hal/voice_extn/voice_extn.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -128,8 +128,11 @@
 int voice_extn_compress_voip_select_devices(struct audio_device *adev,
                                             snd_device_t *out_snd_device,
                                             snd_device_t *in_snd_device);
-void voice_extn_compress_voip_set_parameters(struct audio_device *adev,
+int voice_extn_compress_voip_set_parameters(struct audio_device *adev,
                                              struct str_parms *parms);
+void voice_extn_compress_voip_get_parameters(const struct audio_device *adev,
+                                             struct str_parms *query,
+                                             struct str_parms *reply);
 
 void voice_extn_compress_voip_out_get_parameters(struct stream_out *out,
                                                  struct str_parms *query,
@@ -166,7 +169,7 @@
     return -ENOSYS;
 }
 
-static int voice_extn_compress_voip_out_get_buffer_size(struct audio_stream *stream)
+static int voice_extn_compress_voip_out_get_buffer_size(struct stream_out *stream)
 {
     ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
     return -ENOSYS;
@@ -210,10 +213,18 @@
     return -ENOSYS;
 }
 
-static void voice_extn_compress_voip_set_parameters(struct audio_device *adev,
+static int voice_extn_compress_voip_set_parameters(struct audio_device *adev,
                                                     struct str_parms *parms)
 {
     ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
+    return -ENOSYS;
+}
+
+static void voice_extn_compress_voip_get_parameters(const struct audio_device *adev,
+                                                    struct str_parms *query,
+                                                    struct str_parms *reply)
+{
+    ALOGE("%s: COMPRESS_VOIP_ENABLED is not defined", __func__);
 }
 
 static void voice_extn_compress_voip_out_get_parameters(struct stream_out *out,
diff --git a/hal_mpq/Android.mk b/hal_mpq/Android.mk
index 683de7a..1cb7e60 100644
--- a/hal_mpq/Android.mk
+++ b/hal_mpq/Android.mk
@@ -44,9 +44,9 @@
 	$(call include-path-for, audio-effects) \
 	$(LOCAL_PATH)/$(AUDIO_PLATFORM)
 
-ifeq ($(strip $(AUDIO_FEATURE_ENABLED_AUXPCM_BT)),true)
-    LOCAL_CFLAGS += -DAUXPCM_BT_ENABLED
-endif
+
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
 
 LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM)
 
diff --git a/hal_mpq/audio_stream_out.c b/hal_mpq/audio_stream_out.c
index b766770..e7f29de 100644
--- a/hal_mpq/audio_stream_out.c
+++ b/hal_mpq/audio_stream_out.c
@@ -1043,6 +1043,7 @@
     handle->compr_config.codec->ch_in =
         popcount(out->channel_mask);
     handle->compr_config.codec->ch_out = handle->compr_config.codec->ch_in;
+    handle->compr_config.codec->format = out->compr_config.codec->format;
     memcpy(&handle->compr_config.codec->options,
                     &out->compr_config.codec->options,
                      sizeof(union snd_codec_options));
@@ -1328,9 +1329,18 @@
 
 static bool is_supported_format(audio_format_t format)
 {
-    if (format == AUDIO_FORMAT_MP3 ||
-            format == AUDIO_FORMAT_AAC)
+    switch (format) {
+    case AUDIO_FORMAT_PCM_16_BIT:
+    case AUDIO_FORMAT_MP3:
+    case AUDIO_FORMAT_AAC:
+    case AUDIO_FORMAT_WMA:
+    case AUDIO_FORMAT_WMA_PRO:
+    case AUDIO_FORMAT_MP2:
         return true;
+    default:
+        ALOGE("%s: Unsupported audio format: %x", __func__, format);
+        break;
+    }
 
     return false;
 }
@@ -1340,14 +1350,26 @@
     int id = 0;
 
     switch (format) {
+    case AUDIO_FORMAT_PCM_16_BIT:
+        id = SND_AUDIOCODEC_PCM;
+        break;
     case AUDIO_FORMAT_MP3:
         id = SND_AUDIOCODEC_MP3;
         break;
     case AUDIO_FORMAT_AAC:
         id = SND_AUDIOCODEC_AAC;
         break;
+    case AUDIO_FORMAT_WMA:
+        id = SND_AUDIOCODEC_WMA;
+        break;
+    case AUDIO_FORMAT_WMA_PRO:
+        id = SND_AUDIOCODEC_WMA_PRO;
+        break;
+    case AUDIO_FORMAT_MP2:
+        id = SND_AUDIOCODEC_MP2;
+        break;
     default:
-        ALOGE("%s: Unsupported audio format", __func__);
+        ALOGE("%s: Unsupported audio format %x", __func__, format);
     }
 
     return id;
@@ -1829,6 +1851,7 @@
     int ret = 0;
     char value[32];
     struct compr_gapless_mdata tmp_mdata;
+    bool gapless_meta_set = true;
 
     if (!out || !parms) {
         return -EINVAL;
@@ -1838,21 +1861,61 @@
     if (ret >= 0) {
         tmp_mdata.encoder_delay = atoi(value); //whats a good limit check?
     } else {
-        return -EINVAL;
+        gapless_meta_set = false;
     }
 
     ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value));
     if (ret >= 0) {
         tmp_mdata.encoder_padding = atoi(value);
     } else {
-        return -EINVAL;
+        gapless_meta_set = false;
     }
 
-    out->gapless_mdata = tmp_mdata;
-    out->send_new_metadata = 1;
-    ALOGV("%s new encoder delay %u and padding %u", __func__,
-          out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding);
+    if (gapless_meta_set) {
+        out->gapless_mdata = tmp_mdata;
+        out->send_new_metadata = 1;
+        ALOGV("%s new encoder delay %u and padding %u", __func__,
+            out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding);
+    }
 
+    if(out->format == AUDIO_FORMAT_WMA || out->format == AUDIO_FORMAT_WMA_PRO) {
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_FORMAT_TAG, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->format = atoi(value);
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BLOCK_ALIGN, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.wma.super_block_align = atoi(value);
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BIT_PER_SAMPLE, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.wma.bits_per_sample = atoi(value);
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_CHANNEL_MASK, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.wma.channelmask = atoi(value);
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.wma.encodeopt = atoi(value);
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION1, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.wma.encodeopt1 = atoi(value);
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION2, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.wma.encodeopt2 = atoi(value);
+        }
+        ALOGV("WMA params: fmt %x, balgn %x, sr %d, chmsk %x, encop %x, op1 %x, op2 %x",
+                                out->compr_config.codec->format,
+                                out->compr_config.codec->options.wma.super_block_align,
+                                out->compr_config.codec->options.wma.bits_per_sample,
+                                out->compr_config.codec->options.wma.channelmask,
+                                out->compr_config.codec->options.wma.encodeopt,
+                                out->compr_config.codec->options.wma.encodeopt1,
+                                out->compr_config.codec->options.wma.encodeopt2);
+    }
     return 0;
 }
 
@@ -1968,7 +2031,7 @@
     }
 
     if (out->uc_strm_type == OFFLOAD_PLAYBACK_STREAM) {
-        parse_compress_metadata(out, parms);
+        ret = parse_compress_metadata(out, parms);
     }
 
     str_parms_destroy(parms);
@@ -2076,6 +2139,7 @@
         /* TODO:disnable this if ms12 */
 
         if (ret >= 0 && ret < (ssize_t)bytes) {
+            handle->cmd_pending = true;
             send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
         }
         return ret;
diff --git a/hal_mpq/mpq8092/hw_info.c b/hal_mpq/mpq8092/hw_info.c
index 97b7804..2a0231f 100644
--- a/hal_mpq/mpq8092/hw_info.c
+++ b/hal_mpq/mpq8092/hw_info.c
@@ -285,8 +285,7 @@
         ALOGV("8084 - variant soundcard");
         update_hardware_info_8084(hw_info, snd_card_name);
     } else {
-        ALOGE("%s: Unupported target %s:",__func__, snd_card_name);
-        CHECK(0);
+        ALOGE("%s: Unsupported target %s:",__func__, snd_card_name);
         free(hw_info);
         hw_info = NULL;
     }
diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp
index 4fa2356..f64bbfe 100644
--- a/policy_hal/AudioPolicyManager.cpp
+++ b/policy_hal/AudioPolicyManager.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2009 The Android Open Source Project
@@ -539,9 +539,9 @@
                 if (device) break;
                 device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
                 if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+                if (device) break;
             }
-            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
-            if (device) break;
             device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
             if (device) break;
             device = mDefaultOutputDevice;
@@ -590,7 +590,7 @@
     case STRATEGY_MEDIA: {
         uint32_t device2 = AUDIO_DEVICE_NONE;
 
-        if (isInCall()) {
+        if (isInCall() && (device == AUDIO_DEVICE_NONE)) {
             // when in call, get the device for Phone strategy
             device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/);
             break;
@@ -637,7 +637,8 @@
             device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
         }
         if ((device2 == AUDIO_DEVICE_NONE) &&
-                (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_ANALOG_DOCK)) {
+                (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_ANALOG_DOCK)
+                && (strategy != STRATEGY_SONIFICATION)) {
             device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
         }
 #ifdef AUDIO_EXTN_FM_ENABLED