am 98fd4533: Disable fast capture by default for 8974

* commit '98fd45339a56253ea5fe117f2c91daaf586adeae':
  Disable fast capture by default for 8974
diff --git a/hal/Android.mk b/hal/Android.mk
index 69f46f9..910edbe 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -10,6 +10,12 @@
 ifneq ($(filter msm8974 msm8226 msm8084,$(TARGET_BOARD_PLATFORM)),)
   # B-family platform uses msm8974 code base
   AUDIO_PLATFORM = msm8974
+ifneq ($(filter msm8226,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_CFLAGS := -DPLATFORM_MSM8x26
+endif
+ifneq ($(filter msm8084,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_CFLAGS := -DPLATFORM_MSM8084
+endif
 endif
 
 LOCAL_SRC_FILES := \
@@ -24,13 +30,23 @@
 	libaudioroute \
 	libdl
 
-
 LOCAL_C_INCLUDES += \
 	external/tinyalsa/include \
 	external/tinycompress/include \
 	$(call include-path-for, audio-route) \
 	$(call include-path-for, audio-effects) \
-	$(LOCAL_PATH)/$(AUDIO_PLATFORM)
+	$(LOCAL_PATH)/$(AUDIO_PLATFORM) \
+	$(LOCAL_PATH)/audio_extn
+
+ifneq ($(filter msm8084,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_SHARED_LIBRARIES += libmdmdetect
+  LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/libmdmdetect/inc
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HFP)),true)
+    LOCAL_CFLAGS += -DHFP_ENABLED
+    LOCAL_SRC_FILES += audio_extn/hfp.c
+endif
 
 LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM)
 
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
new file mode 100644
index 0000000..efa63aa
--- /dev/null
+++ b/hal/audio_extn/audio_extn.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AUDIO_EXTN_H
+#define AUDIO_EXTN_H
+
+#include <cutils/str_parms.h>
+
+#ifndef HFP_ENABLED
+#define audio_extn_hfp_is_active(adev)                  (0)
+#define audio_extn_hfp_get_usecase()                    (-1)
+#define audio_extn_hfp_set_parameters(adev, params)     (0)
+#else
+bool audio_extn_hfp_is_active(struct audio_device *adev);
+
+audio_usecase_t audio_extn_hfp_get_usecase();
+
+void audio_extn_hfp_set_parameters(struct audio_device *adev,
+                                    struct str_parms *parms);
+#endif
+
+#endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c
new file mode 100644
index 0000000..fb81c1b
--- /dev/null
+++ b/hal/audio_extn/hfp.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_hfp"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <math.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include <stdlib.h>
+#include <cutils/str_parms.h>
+
+#define AUDIO_PARAMETER_HFP_ENABLE      "hfp_enable"
+#define AUDIO_PARAMETER_HFP_SET_SAMPLING_RATE "hfp_set_sampling_rate"
+#define AUDIO_PARAMETER_KEY_HFP_VOLUME "hfp_volume"
+
+static int32_t start_hfp(struct audio_device *adev,
+                               struct str_parms *parms);
+
+static int32_t stop_hfp(struct audio_device *adev);
+
+struct hfp_module {
+    struct pcm *hfp_sco_rx;
+    struct pcm *hfp_sco_tx;
+    struct pcm *hfp_pcm_rx;
+    struct pcm *hfp_pcm_tx;
+    float  hfp_volume;
+    bool   is_hfp_running;
+    audio_usecase_t ucid;
+};
+
+static struct hfp_module hfpmod = {
+    .hfp_sco_rx = NULL,
+    .hfp_sco_tx = NULL,
+    .hfp_pcm_rx = NULL,
+    .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,
+    .rate = 8000,
+    .period_size = 240,
+    .period_count = 2,
+    .format = PCM_FORMAT_S16_LE,
+    .start_threshold = 0,
+    .stop_threshold = INT_MAX,
+    .avail_min = 0,
+};
+
+static int32_t hfp_set_volume(struct audio_device *adev, float value)
+{
+    int32_t vol, ret = 0;
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "Internal HFP RX Volume";
+
+    ALOGV("%s: entry", __func__);
+    ALOGD("%s: (%f)\n", __func__, value);
+
+    if (value < 0.0) {
+        ALOGW("%s: (%f) Under 0.0, assuming 0.0\n", __func__, value);
+        value = 0.0;
+    } else {
+        value = ((value > 15.000000) ? 1.0 : (value / 15));
+        ALOGW("%s: Volume brought with in range (%f)\n", __func__, value);
+    }
+    vol  = lrint((value * 0x2000) + 0.5);
+    hfpmod.hfp_volume = value;
+
+    if (!hfpmod.is_hfp_running) {
+        ALOGV("%s: HFP not active, ignoring set_hfp_volume call", __func__);
+        return -EIO;
+    }
+
+    ALOGD("%s: Setting HFP volume to %d \n", __func__, vol);
+    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, vol) < 0) {
+        ALOGE("%s: Couldn't set HFP Volume: [%d]", __func__, vol);
+        return -EINVAL;
+    }
+
+    ALOGV("%s: exit", __func__);
+    return ret;
+}
+
+static int32_t start_hfp(struct audio_device *adev,
+                               struct str_parms *parms)
+{
+    int32_t i, ret = 0;
+    struct audio_usecase *uc_info;
+    int32_t pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, pcm_dev_asm_tx_id;
+
+    ALOGD("%s: enter", __func__);
+
+    uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+    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;
+    uc_info->in_snd_device = SND_DEVICE_NONE;
+    uc_info->out_snd_device = SND_DEVICE_NONE;
+
+    list_add_tail(&adev->usecase_list, &uc_info->list);
+
+    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);
+    pcm_dev_asm_rx_id = HFP_ASM_RX_TX;
+    pcm_dev_asm_tx_id = HFP_ASM_RX_TX;
+    if (pcm_dev_rx_id < 0 || pcm_dev_tx_id < 0 ||
+        pcm_dev_asm_rx_id < 0 || pcm_dev_asm_tx_id < 0 ) {
+        ALOGE("%s: Invalid PCM devices (rx: %d tx: %d asm: rx tx %d) for the usecase(%d)",
+              __func__, pcm_dev_rx_id, pcm_dev_tx_id, pcm_dev_asm_rx_id, uc_info->id);
+        ret = -EIO;
+        goto exit;
+    }
+
+    ALOGV("%s: HFP PCM devices (hfp rx tx: %d pcm rx tx: %d) for the usecase(%d)",
+              __func__, pcm_dev_rx_id, pcm_dev_tx_id, uc_info->id);
+
+    ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
+          __func__, SOUND_CARD, pcm_dev_rx_id);
+    hfpmod.hfp_sco_rx = pcm_open(SOUND_CARD,
+                                  pcm_dev_asm_rx_id,
+                                  PCM_OUT, &pcm_config_hfp);
+    if (hfpmod.hfp_sco_rx && !pcm_is_ready(hfpmod.hfp_sco_rx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_rx));
+        ret = -EIO;
+        goto exit;
+    }
+    ALOGD("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+          __func__, SOUND_CARD, pcm_dev_tx_id);
+    hfpmod.hfp_pcm_rx = pcm_open(SOUND_CARD,
+                                   pcm_dev_rx_id,
+                                   PCM_OUT, &pcm_config_hfp);
+    if (hfpmod.hfp_pcm_rx && !pcm_is_ready(hfpmod.hfp_pcm_rx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_rx));
+        ret = -EIO;
+        goto exit;
+    }
+    hfpmod.hfp_sco_tx = pcm_open(SOUND_CARD,
+                                  pcm_dev_asm_tx_id,
+                                  PCM_IN, &pcm_config_hfp);
+    if (hfpmod.hfp_sco_tx && !pcm_is_ready(hfpmod.hfp_sco_tx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_sco_tx));
+        ret = -EIO;
+        goto exit;
+    }
+    ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
+          __func__, SOUND_CARD, pcm_dev_tx_id);
+    hfpmod.hfp_pcm_tx = pcm_open(SOUND_CARD,
+                                   pcm_dev_tx_id,
+                                   PCM_IN, &pcm_config_hfp);
+    if (hfpmod.hfp_pcm_tx && !pcm_is_ready(hfpmod.hfp_pcm_tx)) {
+        ALOGE("%s: %s", __func__, pcm_get_error(hfpmod.hfp_pcm_tx));
+        ret = -EIO;
+        goto exit;
+    }
+    pcm_start(hfpmod.hfp_sco_rx);
+    pcm_start(hfpmod.hfp_sco_tx);
+    pcm_start(hfpmod.hfp_pcm_rx);
+    pcm_start(hfpmod.hfp_pcm_tx);
+
+    hfpmod.is_hfp_running = true;
+    hfp_set_volume(adev, hfpmod.hfp_volume);
+
+    ALOGD("%s: exit: status(%d)", __func__, ret);
+    return 0;
+
+exit:
+    stop_hfp(adev);
+    ALOGE("%s: Problem in HFP start: status(%d)", __func__, ret);
+    return ret;
+}
+
+static int32_t stop_hfp(struct audio_device *adev)
+{
+    int32_t i, ret = 0;
+    struct audio_usecase *uc_info;
+
+    ALOGD("%s: enter", __func__);
+    hfpmod.is_hfp_running = false;
+
+    /* 1. Close the PCM devices */
+    if (hfpmod.hfp_sco_rx) {
+        pcm_close(hfpmod.hfp_sco_rx);
+        hfpmod.hfp_sco_rx = NULL;
+    }
+    if (hfpmod.hfp_sco_tx) {
+        pcm_close(hfpmod.hfp_sco_tx);
+        hfpmod.hfp_sco_tx = NULL;
+    }
+    if (hfpmod.hfp_pcm_rx) {
+        pcm_close(hfpmod.hfp_pcm_rx);
+        hfpmod.hfp_pcm_rx = NULL;
+    }
+    if (hfpmod.hfp_pcm_tx) {
+        pcm_close(hfpmod.hfp_pcm_tx);
+        hfpmod.hfp_pcm_tx = NULL;
+    }
+
+    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__, hfpmod.ucid);
+        return -EINVAL;
+    }
+
+    /* 2. Get and set stream specific mixer controls */
+    disable_audio_route(adev, uc_info);
+
+    /* 3. Disable the rx and tx devices */
+    disable_snd_device(adev, uc_info->out_snd_device);
+    disable_snd_device(adev, uc_info->in_snd_device);
+
+    list_remove(&uc_info->list);
+    free(uc_info);
+
+    ALOGD("%s: exit: status(%d)", __func__, ret);
+    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, hfpmod.ucid);
+
+    if (hfp_usecase != NULL)
+        return true;
+    else
+        return false;
+}
+
+audio_usecase_t audio_extn_hfp_get_usecase()
+{
+    return hfpmod.ucid;
+}
+
+void audio_extn_hfp_set_parameters(struct audio_device *adev, struct str_parms *parms)
+{
+    int ret;
+    int rate;
+    int val;
+    float vol;
+    char value[32]={0};
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_HFP_ENABLE, value,
+                            sizeof(value));
+    if (ret >= 0) {
+           if (!strncmp(value,"true",sizeof(value)))
+               ret = start_hfp(adev,parms);
+           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);
+        }
+    }
+
+    memset(value, 0, sizeof(value));
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HFP_VOLUME,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        if (sscanf(value, "%f", &vol) != 1){
+            ALOGE("%s: error in retrieving hfp volume", __func__);
+            ret = -EIO;
+            goto exit;
+        }
+        ALOGD("%s: set_hfp_volume usecase, Vol: [%f]", __func__, vol);
+        hfp_set_volume(adev, vol);
+    }
+exit:
+    ALOGV("%s Exit",__func__);
+}
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 9c16d4d..615c5c1 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -45,6 +45,7 @@
 #include <audio_effects/effect_aec.h>
 #include <audio_effects/effect_ns.h>
 #include "audio_hw.h"
+#include "audio_extn.h"
 #include "platform_api.h"
 #include <platform.h>
 
@@ -117,6 +118,8 @@
     [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback",
     [USECASE_AUDIO_RECORD] = "audio-record",
     [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
+    [USECASE_AUDIO_HFP_SCO] = "hfp-sco",
+    [USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb",
     [USECASE_VOICE_CALL] = "voice-call",
     [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
 };
@@ -164,8 +167,8 @@
     return id;
 }
 
-static int enable_audio_route(struct audio_device *adev,
-                              struct audio_usecase *usecase)
+int enable_audio_route(struct audio_device *adev,
+                       struct audio_usecase *usecase)
 {
     snd_device_t snd_device;
     char mixer_path[50];
@@ -189,8 +192,8 @@
     return 0;
 }
 
-static int disable_audio_route(struct audio_device *adev,
-                               struct audio_usecase *usecase)
+int disable_audio_route(struct audio_device *adev,
+                        struct audio_usecase *usecase)
 {
     snd_device_t snd_device;
     char mixer_path[50];
@@ -212,7 +215,7 @@
     return 0;
 }
 
-static int enable_snd_device(struct audio_device *adev,
+int enable_snd_device(struct audio_device *adev,
                              snd_device_t snd_device)
 {
     if (snd_device < SND_DEVICE_MIN ||
@@ -240,7 +243,7 @@
     return 0;
 }
 
-static int disable_snd_device(struct audio_device *adev,
+int disable_snd_device(struct audio_device *adev,
                               snd_device_t snd_device)
 {
     if (snd_device < SND_DEVICE_MIN ||
@@ -416,8 +419,8 @@
     return ret;
 }
 
-static struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
-                                                   audio_usecase_t uc_id)
+struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
+                                            audio_usecase_t uc_id)
 {
     struct audio_usecase *usecase;
     struct listnode *node;
@@ -430,13 +433,15 @@
     return NULL;
 }
 
-static int select_devices(struct audio_device *adev,
-                          audio_usecase_t uc_id)
+int select_devices(struct audio_device *adev,
+                   audio_usecase_t uc_id)
 {
     snd_device_t out_snd_device = SND_DEVICE_NONE;
     snd_device_t in_snd_device = SND_DEVICE_NONE;
     struct audio_usecase *usecase = NULL;
     struct audio_usecase *vc_usecase = NULL;
+    struct audio_usecase *hfp_usecase = NULL;
+    audio_usecase_t hfp_ucid;
     struct listnode *node;
     int status = 0;
 
@@ -446,7 +451,8 @@
         return -EINVAL;
     }
 
-    if (usecase->type == VOICE_CALL) {
+    if ((usecase->type == VOICE_CALL) ||
+        (usecase->type == PCM_HFP_CALL)) {
         out_snd_device = platform_get_output_snd_device(adev->platform,
                                                         usecase->stream.out->devices);
         in_snd_device = platform_get_input_snd_device(adev->platform, usecase->stream.out->devices);
@@ -465,6 +471,13 @@
                 in_snd_device = vc_usecase->in_snd_device;
                 out_snd_device = vc_usecase->out_snd_device;
             }
+        } else if (audio_extn_hfp_is_active(adev)) {
+            hfp_ucid = audio_extn_hfp_get_usecase();
+            hfp_usecase = get_usecase_from_list(adev, hfp_ucid);
+            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;
@@ -523,6 +536,15 @@
         disable_snd_device(adev, usecase->in_snd_device);
     }
 
+    /* Applicable only on the targets that has external modem.
+     * New device information should be sent to modem before enabling
+     * the devices to reduce in-call device switch time.
+     */
+    if (usecase->type == VOICE_CALL)
+        status = platform_switch_voice_call_enable_device_config(adev->platform,
+                                                                 out_snd_device,
+                                                                 in_snd_device);
+
     /* Enable new sound devices */
     if (out_snd_device != SND_DEVICE_NONE) {
         if (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)
@@ -545,6 +567,15 @@
 
     enable_audio_route(adev, usecase);
 
+    /* Applicable only on the targets that has external modem.
+     * Enable device command should be sent to modem only after
+     * enabling voice call mixer controls
+     */
+    if (usecase->type == VOICE_CALL)
+        status = platform_switch_voice_call_usecase_route_post(adev->platform,
+                                                               out_snd_device,
+                                                               in_snd_device);
+
     return status;
 }
 
@@ -2132,6 +2163,7 @@
         pthread_mutex_unlock(&adev->lock);
     }
 
+    audio_extn_hfp_set_parameters(adev, parms);
     str_parms_destroy(parms);
     ALOGV("%s: exit with code(%d)", __func__, status);
     return status;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 3a30688..37805ab 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -17,6 +17,7 @@
 #ifndef QCOM_AUDIO_HW_H
 #define QCOM_AUDIO_HW_H
 
+#include <cutils/str_parms.h>
 #include <cutils/list.h>
 #include <hardware/audio.h>
 
@@ -55,6 +56,10 @@
     USECASE_AUDIO_PLAYBACK_MULTI_CH,
     USECASE_AUDIO_PLAYBACK_OFFLOAD,
 
+    /* HFP Use case*/
+    USECASE_AUDIO_HFP_SCO,
+    USECASE_AUDIO_HFP_SCO_WB,
+
     /* Capture usecases */
     USECASE_AUDIO_RECORD,
     USECASE_AUDIO_RECORD_LOW_LATENCY,
@@ -150,7 +155,8 @@
 typedef enum {
     PCM_PLAYBACK,
     PCM_CAPTURE,
-    VOICE_CALL
+    VOICE_CALL,
+    PCM_HFP_CALL
 } usecase_type_t;
 
 union stream_ptr {
@@ -206,6 +212,19 @@
     struct pcm_params *use_case_table[AUDIO_USECASE_MAX];
 };
 
+int select_devices(struct audio_device *adev,
+                   audio_usecase_t uc_id);
+int disable_audio_route(struct audio_device *adev,
+                        struct audio_usecase *usecase);
+int disable_snd_device(struct audio_device *adev,
+                       snd_device_t snd_device);
+int enable_snd_device(struct audio_device *adev,
+                      snd_device_t snd_device);
+int enable_audio_route(struct audio_device *adev,
+                       struct audio_usecase *usecase);
+struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
+                                            audio_usecase_t uc_id);
+
 /*
  * 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/msm8960/platform.c b/hal/msm8960/platform.c
index e9c205a..ae551b9 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -923,3 +923,17 @@
             return 0;
     }
 }
+
+int platform_switch_voice_call_enable_device_config(void *platform,
+                                                    snd_device_t out_snd_device,
+                                                    snd_device_t in_snd_device)
+{
+    return 0;
+}
+
+int platform_switch_voice_call_usecase_route_post(void *platform,
+                                                  snd_device_t out_snd_device,
+                                                  snd_device_t in_snd_device)
+{
+    return 0;
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index ed125c1..b7acc85 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -26,6 +26,9 @@
 #include <audio_hw.h>
 #include <platform_api.h>
 #include "platform.h"
+#ifdef PLATFORM_MSM8084
+#include "mdm_detect.h"
+#endif
 
 #define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
 #define LIB_ACDB_LOADER "libacdbloader.so"
@@ -63,10 +66,16 @@
     int length;
 };
 
+/* Audio calibration related functions */
 typedef void (*acdb_deallocate_t)();
+#ifdef PLATFORM_MSM8084
+typedef int  (*acdb_init_t)(char *);
+#else
 typedef int  (*acdb_init_t)();
+#endif
 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);
 
 /* Audio calibration related functions */
 struct platform_data {
@@ -80,16 +89,26 @@
     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;
+    struct csd_data *csd;
 };
 
 static const int pcm_device_table[AUDIO_USECASE_MAX][2] = {
-    [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0},
-    [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {15, 15},
-    [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {1, 1},
-    [USECASE_AUDIO_PLAYBACK_OFFLOAD] = {9, 9},
-    [USECASE_AUDIO_RECORD] = {0, 0},
-    [USECASE_AUDIO_RECORD_LOW_LATENCY] = {15, 15},
-    [USECASE_VOICE_CALL] = {2, 2},
+    [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {DEEP_BUFFER_PCM_DEVICE,
+                                            DEEP_BUFFER_PCM_DEVICE},
+    [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
+                                            LOWLATENCY_PCM_DEVICE},
+    [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTIMEDIA2_PCM_DEVICE,
+                                         MULTIMEDIA2_PCM_DEVICE},
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD] = {PLAYBACK_OFFLOAD_DEVICE,
+                                        PLAYBACK_OFFLOAD_DEVICE},
+    [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE,
+                              AUDIO_RECORD_PCM_DEVICE},
+    [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
+                                          LOWLATENCY_PCM_DEVICE},
+    [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE,
+                            VOICE_CALL_PCM_DEVICE},
+    [USECASE_AUDIO_HFP_SCO] = {HFP_PCM_RX, HFP_SCO_RX},
 };
 
 /* Array to store sound devices */
@@ -156,7 +175,7 @@
     [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 15,
     [SND_DEVICE_OUT_BT_SCO] = 22,
     [SND_DEVICE_OUT_BT_SCO_WB] = 39,
-    [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = 88,
+    [SND_DEVICE_OUT_VOICE_HANDSET_TMUS] = ACDB_ID_VOICE_HANDSET_TMUS,
     [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17,
     [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
     [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37,
@@ -175,7 +194,7 @@
     [SND_DEVICE_IN_CAMCORDER_MIC] = 61,
     [SND_DEVICE_IN_VOICE_DMIC_EF] = 41,
     [SND_DEVICE_IN_VOICE_DMIC_BS] = 5,
-    [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = 89,
+    [SND_DEVICE_IN_VOICE_DMIC_EF_TMUS] = ACDB_ID_VOICE_DMIC_EF_TMUS,
     [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_EF] = 43,
     [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BS] = 12,
     [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16,
@@ -265,11 +284,176 @@
     return 0;
 }
 
+static struct csd_data *open_csd_client(bool i2s_ext_modem)
+{
+    struct csd_data *csd = calloc(1, sizeof(struct csd_data));
+
+    csd->csd_client = dlopen(LIB_CSD_CLIENT, RTLD_NOW);
+    if (csd->csd_client == NULL) {
+        ALOGE("%s: DLOPEN failed for %s", __func__, LIB_CSD_CLIENT);
+        goto error;
+    } else {
+        ALOGV("%s: DLOPEN successful for %s", __func__, LIB_CSD_CLIENT);
+
+        csd->deinit = (deinit_t)dlsym(csd->csd_client,
+                                             "csd_client_deinit");
+        if (csd->deinit == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_deinit", __func__,
+                  dlerror());
+            goto error;
+        }
+        csd->disable_device = (disable_device_t)dlsym(csd->csd_client,
+                                             "csd_client_disable_device");
+        if (csd->disable_device == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_disable_device",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->enable_device_config = (enable_device_config_t)dlsym(csd->csd_client,
+                                               "csd_client_enable_device_config");
+        if (csd->enable_device_config == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_enable_device_config",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->enable_device = (enable_device_t)dlsym(csd->csd_client,
+                                             "csd_client_enable_device");
+        if (csd->enable_device == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_enable_device",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->start_voice = (start_voice_t)dlsym(csd->csd_client,
+                                             "csd_client_start_voice");
+        if (csd->start_voice == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_start_voice",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->stop_voice = (stop_voice_t)dlsym(csd->csd_client,
+                                             "csd_client_stop_voice");
+        if (csd->stop_voice == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_stop_voice",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->volume = (volume_t)dlsym(csd->csd_client,
+                                             "csd_client_volume");
+        if (csd->volume == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_volume",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->mic_mute = (mic_mute_t)dlsym(csd->csd_client,
+                                             "csd_client_mic_mute");
+        if (csd->mic_mute == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_mic_mute",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->slow_talk = (slow_talk_t)dlsym(csd->csd_client,
+                                             "csd_client_slow_talk");
+        if (csd->slow_talk == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_slow_talk",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->start_playback = (start_playback_t)dlsym(csd->csd_client,
+                                             "csd_client_start_playback");
+        if (csd->start_playback == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_start_playback",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->stop_playback = (stop_playback_t)dlsym(csd->csd_client,
+                                             "csd_client_stop_playback");
+        if (csd->stop_playback == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_stop_playback",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->start_record = (start_record_t)dlsym(csd->csd_client,
+                                             "csd_client_start_record");
+        if (csd->start_record == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_start_record",
+                  __func__, dlerror());
+            goto error;
+        }
+        csd->stop_record = (stop_record_t)dlsym(csd->csd_client,
+                                             "csd_client_stop_record");
+        if (csd->stop_record == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_stop_record",
+                  __func__, dlerror());
+            goto error;
+        }
+
+        csd->get_sample_rate = (get_sample_rate_t)dlsym(csd->csd_client,
+                                             "csd_client_get_sample_rate");
+        if (csd->get_sample_rate == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_get_sample_rate",
+                  __func__, dlerror());
+
+            goto error;
+        }
+
+        csd->init = (init_t)dlsym(csd->csd_client, "csd_client_init");
+
+        if (csd->init == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_init",
+                  __func__, dlerror());
+            goto error;
+        } else {
+            csd->init(i2s_ext_modem);
+        }
+    }
+    return csd;
+
+error:
+    free(csd);
+    csd = NULL;
+    return csd;
+}
+
+void close_csd_client(struct csd_data *csd)
+{
+    if (csd != NULL) {
+        csd->deinit();
+        dlclose(csd->csd_client);
+        free(csd);
+        csd = NULL;
+    }
+}
+
+static void platform_csd_init(struct platform_data *my_data)
+{
+#ifdef PLATFORM_MSM8084
+    struct dev_info mdm_detect_info;
+    int ret = 0;
+
+    /* Call ESOC API to get the number of modems.
+     * If the number of modems is not zero, load CSD Client specific
+     * symbols. Voice call is handled by MDM and apps processor talks to
+     * MDM through CSD Client
+     */
+    ret = get_system_info(&mdm_detect_info);
+    if (ret > 0) {
+        ALOGE("%s: Failed to get system info, ret %d", __func__, ret);
+    }
+    ALOGD("%s: num_modems %d\n", __func__, mdm_detect_info.num_modems);
+
+    if (mdm_detect_info.num_modems > 0)
+        my_data->csd = open_csd_client(false /*is_i2s_ext_modem*/);
+#else
+     my_data->csd = NULL;
+#endif
+}
+
 void *platform_init(struct audio_device *adev)
 {
     char value[PROPERTY_VALUE_MAX];
     struct platform_data *my_data;
     int retry_num = 0;
+    const char *snd_card_name;
 
     adev->mixer = mixer_open(MIXER_CARD);
 
@@ -284,6 +468,9 @@
         return NULL;
     }
 
+    snd_card_name = mixer_get_name(adev->mixer);
+    ALOGD("%s: snd_card_name: %s", __func__, snd_card_name);
+
     adev->audio_route = audio_route_init(MIXER_CARD, MIXER_XML_PATH);
     if (!adev->audio_route) {
         ALOGE("%s: Failed to init audio route controls, aborting.", __func__);
@@ -331,21 +518,47 @@
         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);
+#ifdef PLATFORM_MSM8084
+        my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_init_v2");
+        if (my_data->acdb_init == NULL)
+            ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__, dlerror());
+        else
+            my_data->acdb_init(snd_card_name);
+#else
         my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_init_ACDB");
         if (my_data->acdb_init == NULL)
             ALOGE("%s: dlsym error %s for acdb_loader_init_ACDB", __func__, dlerror());
         else
             my_data->acdb_init();
+#endif
     }
 
+    /* load csd client */
+    platform_csd_init(my_data);
+
     return my_data;
 }
 
@@ -413,7 +626,48 @@
 
 int platform_switch_voice_call_device_pre(void *platform)
 {
-    return 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int ret = 0;
+
+    if (my_data->csd != NULL &&
+        my_data->adev->mode == AUDIO_MODE_IN_CALL) {
+        /* This must be called before disabling mixer controls on APQ side */
+        ret = my_data->csd->disable_device();
+        if (ret < 0) {
+            ALOGE("%s: csd_client_disable_device, failed, error %d",
+                  __func__, ret);
+        }
+    }
+    return ret;
+}
+
+int platform_switch_voice_call_enable_device_config(void *platform,
+                                                    snd_device_t out_snd_device,
+                                                    snd_device_t in_snd_device)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int acdb_rx_id, acdb_tx_id;
+    int ret = 0;
+
+    if (my_data->csd == NULL)
+        return ret;
+
+    acdb_rx_id = acdb_device_table[out_snd_device];
+
+    acdb_tx_id = acdb_device_table[in_snd_device];
+
+    if (acdb_rx_id > 0 && acdb_tx_id > 0) {
+        ret = my_data->csd->enable_device_config(acdb_rx_id, acdb_tx_id);
+        if (ret < 0) {
+            ALOGE("%s: csd_enable_device_config, failed, error %d",
+                  __func__, ret);
+        }
+    } else {
+        ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+              acdb_rx_id, acdb_tx_id);
+    }
+
+    return ret;
 }
 
 int platform_switch_voice_call_device_post(void *platform,
@@ -439,14 +693,61 @@
     return 0;
 }
 
+int platform_switch_voice_call_usecase_route_post(void *platform,
+                                                  snd_device_t out_snd_device,
+                                                  snd_device_t in_snd_device)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int acdb_rx_id, acdb_tx_id;
+    int ret = 0;
+
+    if (my_data->csd == NULL)
+        return ret;
+
+    acdb_rx_id = acdb_device_table[out_snd_device];
+
+    acdb_tx_id = acdb_device_table[in_snd_device];
+
+    if (acdb_rx_id > 0 && acdb_tx_id > 0) {
+        ret = my_data->csd->enable_device(acdb_rx_id, acdb_tx_id,
+                                          my_data->adev->acdb_settings);
+        if (ret < 0) {
+            ALOGE("%s: csd_enable_device, failed, error %d", __func__, ret);
+        }
+    } else {
+        ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+              acdb_rx_id, acdb_tx_id);
+    }
+
+    return ret;
+}
+
 int platform_start_voice_call(void *platform)
 {
-    return 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int ret = 0;
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->start_voice(VOICE_VSID);
+        if (ret < 0) {
+            ALOGE("%s: csd_start_voice error %d\n", __func__, ret);
+        }
+    }
+    return ret;
 }
 
 int platform_stop_voice_call(void *platform)
 {
-    return 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int ret = 0;
+
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->stop_voice(VOICE_VSID);
+        if (ret < 0) {
+            ALOGE("%s: csd_stop_voice error %d\n", __func__, ret);
+        }
+    }
+    return ret;
 }
 
 int platform_set_voice_volume(void *platform, int volume)
@@ -479,8 +780,14 @@
         ALOGV("%s: failed set mixer ctl by %d", __func__, ret);
         return -EINVAL;
     }
-
-    return 0;
+    if (my_data->csd != NULL) {
+        ret = my_data->csd->volume(ALL_SESSION_VSID, volume,
+                                   DEFAULT_VOLUME_RAMP_DURATION_MS);
+        if (ret < 0) {
+            ALOGE("%s: csd_volume error %d", __func__, ret);
+        }
+    }
+    return ret;
 }
 
 int platform_set_mic_mute(void *platform, bool state)
@@ -654,6 +961,7 @@
             out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE) {
             if (my_data->fluence_in_voice_call == false) {
                 snd_device = SND_DEVICE_IN_HANDSET_MIC;
+                set_echo_reference(adev->mixer, "SLIM_RX");
             } else {
                 if (my_data->dualmic_config == DUALMIC_CONFIG_ENDFIRE) {
                     if (is_operator_tmus())
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 8c052a5..6b01067 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -97,12 +97,19 @@
 #define DEFAULT_OUTPUT_SAMPLING_RATE 48000
 
 #define ALL_SESSION_VSID    0xFFFFFFFF
-#define DEFAULT_MUTE_RAMP_DURATION      500
+#define DEFAULT_MUTE_RAMP_DURATION      20
 #define DEFAULT_VOLUME_RAMP_DURATION_MS 20
 #define VOLUME_SET 0
 #define MUTE_SET 1
 #define VOLUME_CTL_PARAM_NUM 3
 
+#ifdef MSM8084
+#define ACDB_ID_VOICE_HANDSET_TMUS 88
+#define ACDB_ID_VOICE_DMIC_EF_TMUS 89
+#else
+#define ACDB_ID_VOICE_HANDSET_TMUS 7
+#define ACDB_ID_VOICE_DMIC_EF_TMUS 41
+#endif
 /*
  * tinyAlsa library interprets period size as number of frames
  * one frame = channel_count * sizeof (pcm sample)
@@ -128,4 +135,64 @@
 #define LOW_LATENCY_CAPTURE_PERIOD_SIZE 480
 #define LOW_LATENCY_CAPTURE_USE_CASE 1
 
+#define DEEP_BUFFER_PCM_DEVICE 0
+#define AUDIO_RECORD_PCM_DEVICE 0
+#define MULTIMEDIA2_PCM_DEVICE 1
+#define PLAYBACK_OFFLOAD_DEVICE 9
+#define LOWLATENCY_PCM_DEVICE 15
+#define VOICE_VSID  0x10C01000
+#ifdef PLATFORM_MSM8084
+#define VOICE_CALL_PCM_DEVICE 20
+#else
+#define VOICE_CALL_PCM_DEVICE 2
+#endif
+
+#define HFP_PCM_RX 5
+#ifdef PLATFORM_MSM8x26
+#define HFP_SCO_RX 28
+#define HFP_ASM_RX_TX 29
+#else
+#define HFP_SCO_RX 23
+#define HFP_ASM_RX_TX 24
+#endif
+
+#define LIB_CSD_CLIENT "libcsd-client.so"
+#define LIB_MDM_DETECT "libmdmdetect.so"
+
+/* CSD-CLIENT related functions */
+typedef int (*init_t)(bool);
+typedef int (*deinit_t)();
+typedef int (*disable_device_t)();
+typedef int (*enable_device_config_t)(int, int);
+typedef int (*enable_device_t)(int, int, uint32_t);
+typedef int (*volume_t)(uint32_t, int, uint16_t);
+typedef int (*mic_mute_t)(uint32_t, int, uint16_t);
+typedef int (*slow_talk_t)(uint32_t, uint8_t);
+typedef int (*start_voice_t)(uint32_t);
+typedef int (*stop_voice_t)(uint32_t);
+typedef int (*start_playback_t)(uint32_t);
+typedef int (*stop_playback_t)(uint32_t);
+typedef int (*start_record_t)(uint32_t, int);
+typedef int (*stop_record_t)(uint32_t);
+typedef int (*get_sample_rate_t)(uint32_t *);
+/* CSD Client structure */
+struct csd_data {
+    void *csd_client;
+    init_t init;
+    deinit_t deinit;
+    disable_device_t disable_device;
+    enable_device_config_t enable_device_config;
+    enable_device_t enable_device;
+    volume_t volume;
+    mic_mute_t mic_mute;
+    slow_talk_t slow_talk;
+    start_voice_t start_voice;
+    stop_voice_t stop_voice;
+    start_playback_t start_playback;
+    stop_playback_t stop_playback;
+    start_record_t start_record;
+    stop_record_t stop_record;
+    get_sample_rate_t get_sample_rate;
+};
+
 #endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/platform_api.h b/hal/platform_api.h
index afd2ee4..7079e8c 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -24,9 +24,15 @@
 int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type);
 int platform_send_audio_calibration(void *platform, snd_device_t snd_device);
 int platform_switch_voice_call_device_pre(void *platform);
+int platform_switch_voice_call_enable_device_config(void *platform,
+                                                    snd_device_t out_snd_device,
+                                                    snd_device_t in_snd_device);
 int platform_switch_voice_call_device_post(void *platform,
                                            snd_device_t out_snd_device,
                                            snd_device_t in_snd_device);
+int platform_switch_voice_call_usecase_route_post(void *platform,
+                                                  snd_device_t out_snd_device,
+                                                  snd_device_t in_snd_device);
 int platform_start_voice_call(void *platform);
 int platform_stop_voice_call(void *platform);
 int platform_set_voice_volume(void *platform, int volume);