Merge "hal: avoid audio rerouting to different device when hfp is active"
diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c
index 8414ee2..aabe804 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;
     }
 
@@ -228,6 +231,7 @@
 void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
 {
     int ret;
+    int rate;
     char value[32]={0};
 
     ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
@@ -238,5 +242,21 @@
            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..");
+    }
 }
 #endif /*HFP_ENABLED*/
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index f73f5fe..7f4bb7a 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1,8 +1,8 @@
 /*
- * 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
+ * Copyright (C) 2013-2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -113,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",
@@ -152,6 +153,7 @@
 
 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)
 {
@@ -1311,26 +1313,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__,
@@ -1348,14 +1363,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);
@@ -1399,18 +1414,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));
+                ret = select_devices(adev, get_voice_usecase_id_from_list(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);
@@ -1423,7 +1438,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);
@@ -1828,16 +1845,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)) {
@@ -1845,8 +1862,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;
@@ -1999,7 +2016,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);
@@ -2129,6 +2146,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) {
@@ -2243,18 +2263,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.
          */
@@ -2264,16 +2289,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
@@ -2305,8 +2330,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;
@@ -2323,7 +2349,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);
@@ -2679,6 +2705,33 @@
     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 73575e8..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,
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 9ba3b94..807ede4 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -1,8 +1,8 @@
 /*
- * 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
+ * Copyright (C) 2013-2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -120,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},
@@ -870,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 ||
@@ -921,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
@@ -1358,12 +1359,12 @@
     char *str;
     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) {
@@ -1373,8 +1374,8 @@
         }
     }
 
-    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SLOWTALK, value, sizeof(value));
-    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;
@@ -1386,9 +1387,9 @@
             ALOGE("%s: Failed to set slow talk err: %d", __func__, ret);
     }
 
-    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOLUME_BOOST,
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOLUME_BOOST,
                             value, sizeof(value));
-    if (ret >= 0) {
+    if (err >= 0) {
         str_parms_del(parms, AUDIO_PARAMETER_KEY_VOLUME_BOOST);
 
         if (my_data->acdb_reload_vocvoltable == NULL) {
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..74d1978 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -1,8 +1,8 @@
 /*
- * 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
+ * Copyright (C) 2013-2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -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);
diff --git a/hal/voice.h b/hal/voice.h
index eeb65dc..38b304e 100644
--- a/hal/voice.h
+++ b/hal/voice.h
@@ -72,6 +72,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..d119ff5 100644
--- a/hal/voice_extn/compress_voip.c
+++ b/hal/voice_extn/compress_voip.c
@@ -1,8 +1,8 @@
 /*
- * 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
+ * Copyright (C) 2013-2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -400,53 +400,57 @@
     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_out_get_parameters(struct stream_out *out,
diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c
index 989a871..12fce09 100644
--- a/hal/voice_extn/voice_extn.c
+++ b/hal/voice_extn/voice_extn.c
@@ -1,8 +1,8 @@
 /*
- * 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
+ * Copyright (C) 2013-2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -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
@@ -405,17 +409,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 +436,7 @@
             goto done;
         }
     } else {
-        ALOGD("%s: Not handled here", __func__);
+        ALOGV("%s: Not handled here", __func__);
     }
 
 done:
@@ -440,21 +444,51 @@
     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);
+    }
+    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..adee939 100644
--- a/hal/voice_extn/voice_extn.h
+++ b/hal/voice_extn/voice_extn.h
@@ -1,8 +1,8 @@
 /*
- * 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
+ * Copyright (C) 2013-2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -128,7 +128,7 @@
 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_out_get_parameters(struct stream_out *out,
@@ -210,10 +210,11 @@
     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_out_get_parameters(struct stream_out *out,
diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp
index 194cb46..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
@@ -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