hal: support calibration for hfp with dual asm loopback

Add support TX and RX calibration for HFP call
on both uplink and downlink ASM loopback path.

Change-Id: I66dec9ec01e0645ba6f5c21a4e64aabd10e2b6a5
Signed-off-by: Derek Chen <chenche@codeaurora.org>
Signed-off-by: Guodong Hu <guodhu@codeaurora.org>
diff --git a/hal/audio_extn/Android.mk b/hal/audio_extn/Android.mk
index 56d9179..4d3784c 100644
--- a/hal/audio_extn/Android.mk
+++ b/hal/audio_extn/Android.mk
@@ -475,6 +475,10 @@
   MULTIPLE_HW_VARIANTS_ENABLED := true
 endif
 
+ifeq ($(TARGET_BOARD_AUTO),true)
+  LOCAL_CFLAGS += -DPLATFORM_AUTO
+endif
+
 LOCAL_SRC_FILES:= \
         hfp.c
 
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 8512a4e..c0784d3 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -4509,6 +4509,10 @@
         init_config.fp_disable_audio_route = disable_audio_route;
         init_config.fp_disable_snd_device = disable_snd_device;
         init_config.fp_voice_get_mic_mute = voice_get_mic_mute;
+        init_config.fp_audio_extn_auto_hal_start_hfp_downlink =
+                                        audio_extn_auto_hal_start_hfp_downlink;
+        init_config.fp_audio_extn_auto_hal_stop_hfp_downlink =
+                                        audio_extn_auto_hal_stop_hfp_downlink;
 
         hfp_init(init_config);
         ALOGD("%s:: ---- Feature HFP is Enabled ----", __func__);
@@ -5477,6 +5481,14 @@
                                 struct str_parms*);
 static auto_hal_set_parameters_t auto_hal_set_parameters;
 
+typedef int (*auto_hal_start_hfp_downlink_t)(struct audio_device*,
+                                struct audio_usecase*);
+static auto_hal_start_hfp_downlink_t auto_hal_start_hfp_downlink;
+
+typedef int (*auto_hal_stop_hfp_downlink_t)(struct audio_device*,
+                                struct audio_usecase*);
+static auto_hal_stop_hfp_downlink_t auto_hal_stop_hfp_downlink;
+
 int auto_hal_feature_init(bool is_feature_enabled)
 {
     ALOGD("%s: Called with feature %s", __func__,
@@ -5520,7 +5532,13 @@
                             auto_hal_lib_handle, "auto_hal_set_audio_port_config")) ||
             !(auto_hal_set_parameters =
                  (auto_hal_set_parameters_t)dlsym(
-                            auto_hal_lib_handle, "auto_hal_set_parameters"))) {
+                            auto_hal_lib_handle, "auto_hal_set_parameters")) ||
+            !(auto_hal_start_hfp_downlink =
+                 (auto_hal_start_hfp_downlink_t)dlsym(
+                            auto_hal_lib_handle, "auto_hal_start_hfp_downlink")) ||
+            !(auto_hal_stop_hfp_downlink =
+                 (auto_hal_stop_hfp_downlink_t)dlsym(
+                            auto_hal_lib_handle, "auto_hal_stop_hfp_downlink"))) {
             ALOGE("%s: dlsym failed", __func__);
             goto feature_disabled;
         }
@@ -5545,6 +5563,8 @@
     auto_hal_get_audio_port = NULL;
     auto_hal_set_audio_port_config = NULL;
     auto_hal_set_parameters = NULL;
+    auto_hal_start_hfp_downlink = NULL;
+    auto_hal_stop_hfp_downlink = NULL;
 
     ALOGW(":: %s: ---- Feature AUTO_HAL is disabled ----", __func__);
     return -ENOSYS;
@@ -5561,6 +5581,9 @@
         auto_hal_init_config.fp_get_usecase_from_list = get_usecase_from_list;
         auto_hal_init_config.fp_get_output_period_size = get_output_period_size;
         auto_hal_init_config.fp_audio_extn_ext_hw_plugin_set_audio_gain = audio_extn_ext_hw_plugin_set_audio_gain;
+        auto_hal_init_config.fp_select_devices = select_devices;
+        auto_hal_init_config.fp_disable_audio_route = disable_audio_route;
+        auto_hal_init_config.fp_disable_snd_device = disable_snd_device;
         return auto_hal_init(adev, auto_hal_init_config);
     }
     else
@@ -5640,6 +5663,20 @@
     if (auto_hal_set_parameters)
         auto_hal_set_parameters(adev, parms);
 }
+
+int audio_extn_auto_hal_start_hfp_downlink(struct audio_device *adev,
+                                struct audio_usecase *uc_info)
+{
+    return ((auto_hal_start_hfp_downlink) ?
+                            auto_hal_start_hfp_downlink(adev, uc_info): 0);
+}
+
+int audio_extn_auto_hal_stop_hfp_downlink(struct audio_device *adev,
+                                struct audio_usecase *uc_info)
+{
+    return ((auto_hal_stop_hfp_downlink) ?
+                            auto_hal_stop_hfp_downlink(adev, uc_info): 0);
+}
 // END: AUTO_HAL ===================================================================
 
 void audio_extn_feature_init()
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 91204a7..36d2367 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -682,6 +682,10 @@
                                                 struct audio_usecase *);
 typedef int (*fp_disable_snd_device_t)(struct audio_device *, snd_device_t);
 typedef bool (*fp_voice_get_mic_mute_t)(struct audio_device *);
+typedef int (*fp_audio_extn_auto_hal_start_hfp_downlink_t)(struct audio_device *,
+                                                        struct audio_usecase *);
+typedef int (*fp_audio_extn_auto_hal_stop_hfp_downlink_t)(struct audio_device *,
+                                                        struct audio_usecase *);
 
 typedef struct hfp_init_config {
     fp_platform_set_mic_mute_t                   fp_platform_set_mic_mute;
@@ -694,6 +698,8 @@
     fp_disable_audio_route_t                     fp_disable_audio_route;
     fp_disable_snd_device_t                      fp_disable_snd_device;
     fp_voice_get_mic_mute_t                      fp_voice_get_mic_mute;
+    fp_audio_extn_auto_hal_start_hfp_downlink_t  fp_audio_extn_auto_hal_start_hfp_downlink;
+    fp_audio_extn_auto_hal_stop_hfp_downlink_t   fp_audio_extn_auto_hal_stop_hfp_downlink;
 } hfp_init_config_t;
 
 
@@ -1316,6 +1322,10 @@
                                 const struct audio_port_config *config);
 void audio_extn_auto_hal_set_parameters(struct audio_device *adev,
                                 struct str_parms *parms);
+int audio_extn_auto_hal_start_hfp_downlink(struct audio_device *adev,
+                                struct audio_usecase *uc_info);
+int audio_extn_auto_hal_stop_hfp_downlink(struct audio_device *adev,
+                                struct audio_usecase *uc_info);
 
 typedef streams_input_ctxt_t* (*fp_in_get_stream_t)(struct audio_device*, audio_io_handle_t);
 typedef streams_output_ctxt_t* (*fp_out_get_stream_t)(struct audio_device*, audio_io_handle_t);
@@ -1330,6 +1340,9 @@
     fp_get_usecase_from_list_t                   fp_get_usecase_from_list;
     fp_get_output_period_size_t                  fp_get_output_period_size;
     fp_audio_extn_ext_hw_plugin_set_audio_gain_t fp_audio_extn_ext_hw_plugin_set_audio_gain;
+    fp_select_devices_t                          fp_select_devices;
+    fp_disable_audio_route_t                     fp_disable_audio_route;
+    fp_disable_snd_device_t                      fp_disable_snd_device;
 } auto_hal_init_config_t;
 // END: AUTO_HAL FEATURE ==================================================
 
diff --git a/hal/audio_extn/auto_hal.c b/hal/audio_extn/auto_hal.c
index c18b55f..df0fcca 100644
--- a/hal/audio_extn/auto_hal.c
+++ b/hal/audio_extn/auto_hal.c
@@ -54,12 +54,17 @@
 static fp_get_usecase_from_list_t                   fp_get_usecase_from_list;
 static fp_get_output_period_size_t                  fp_get_output_period_size;
 static fp_audio_extn_ext_hw_plugin_set_audio_gain_t fp_audio_extn_ext_hw_plugin_set_audio_gain;
+static fp_select_devices_t                          fp_select_devices;
+static fp_disable_audio_route_t                     fp_disable_audio_route;
+static fp_disable_snd_device_t                      fp_disable_snd_device;
 
 /* Auto hal module struct */
 static struct auto_hal_module *auto_hal = NULL;
 
 int auto_hal_release_audio_patch(struct audio_hw_device *dev,
                                 audio_patch_handle_t handle);
+int auto_hal_stop_hfp_downlink(struct audio_device *adev,
+                               struct audio_usecase *uc_info);
 
 static struct audio_patch_record *get_patch_from_list(struct audio_device *adev,
                                                     audio_patch_handle_t patch_id)
@@ -677,6 +682,97 @@
     ALOGV("%s: exit", __func__);
 }
 
+int auto_hal_start_hfp_downlink(struct audio_device *adev,
+                                struct audio_usecase *uc_info)
+{
+    int32_t ret = 0;
+    struct audio_usecase *uc_downlink_info;
+
+    ALOGD("%s: enter", __func__);
+
+    uc_downlink_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+
+    if (!uc_downlink_info)
+        return -ENOMEM;
+
+    uc_downlink_info->type = PCM_HFP_CALL;
+    uc_downlink_info->stream.out = adev->primary_output;
+    uc_downlink_info->devices = adev->primary_output->devices;
+    uc_downlink_info->in_snd_device = SND_DEVICE_NONE;
+    uc_downlink_info->out_snd_device = SND_DEVICE_NONE;
+
+    switch (uc_info->id) {
+    case USECASE_AUDIO_HFP_SCO:
+        uc_downlink_info->id = USECASE_AUDIO_HFP_SCO_DOWNLINK;
+        break;
+    case USECASE_AUDIO_HFP_SCO_WB:
+        uc_downlink_info->id = USECASE_AUDIO_HFP_SCO_WB_DOWNLINK;
+        break;
+    default:
+        ALOGE("%s: Invalid usecase %d", __func__, uc_info->id);
+        free(uc_downlink_info);
+        return -EINVAL;
+    }
+
+    list_add_tail(&adev->usecase_list, &uc_downlink_info->list);
+
+    ret = fp_select_devices(adev, uc_downlink_info->id);
+    if (ret) {
+        ALOGE("%s: Select devices failed %d", __func__, ret);
+        goto exit;
+    }
+
+    ALOGD("%s: exit: status(%d)", __func__, ret);
+    return 0;
+
+exit:
+    auto_hal_stop_hfp_downlink(adev, uc_info);
+    ALOGE("%s: Problem in start hfp downlink: status(%d)", __func__, ret);
+    return ret;
+}
+
+int auto_hal_stop_hfp_downlink(struct audio_device *adev,
+                               struct audio_usecase *uc_info)
+{
+    int32_t ret = 0;
+    struct audio_usecase *uc_downlink_info;
+    audio_usecase_t ucid;
+
+    ALOGD("%s: enter", __func__);
+
+    switch (uc_info->id) {
+    case USECASE_AUDIO_HFP_SCO:
+        ucid = USECASE_AUDIO_HFP_SCO_DOWNLINK;
+        break;
+    case USECASE_AUDIO_HFP_SCO_WB:
+        ucid = USECASE_AUDIO_HFP_SCO_WB_DOWNLINK;
+        break;
+    default:
+        ALOGE("%s: Invalid usecase %d", __func__, uc_info->id);
+        return -EINVAL;
+    }
+
+    uc_downlink_info = fp_get_usecase_from_list(adev, ucid);
+    if (uc_downlink_info == NULL) {
+        ALOGE("%s: Could not find the usecase (%d) in the list",
+              __func__, ucid);
+        return -EINVAL;
+    }
+
+    /* Get and set stream specific mixer controls */
+    fp_disable_audio_route(adev, uc_downlink_info);
+
+    /* Disable the rx and tx devices */
+    fp_disable_snd_device(adev, uc_downlink_info->out_snd_device);
+    fp_disable_snd_device(adev, uc_downlink_info->in_snd_device);
+
+    list_remove(&uc_downlink_info->list);
+    free(uc_downlink_info);
+
+    ALOGD("%s: exit: status(%d)", __func__, ret);
+    return ret;
+}
+
 int auto_hal_init(struct audio_device *adev, auto_hal_init_config_t init_config)
 {
     int ret = 0;
@@ -704,6 +800,9 @@
     fp_get_usecase_from_list = init_config.fp_get_usecase_from_list;
     fp_get_output_period_size = init_config.fp_get_output_period_size;
     fp_audio_extn_ext_hw_plugin_set_audio_gain = init_config.fp_audio_extn_ext_hw_plugin_set_audio_gain;
+    fp_select_devices = init_config.fp_select_devices;
+    fp_disable_audio_route = init_config.fp_disable_audio_route;
+    fp_disable_snd_device = init_config.fp_disable_snd_device;
 
     return ret;
 }
diff --git a/hal/audio_extn/ext_hw_plugin.c b/hal/audio_extn/ext_hw_plugin.c
index 7460caa..6e784cb 100644
--- a/hal/audio_extn/ext_hw_plugin.c
+++ b/hal/audio_extn/ext_hw_plugin.c
@@ -182,6 +182,8 @@
         break;
     case USECASE_AUDIO_HFP_SCO:
     case USECASE_AUDIO_HFP_SCO_WB:
+    case USECASE_AUDIO_HFP_SCO_DOWNLINK:
+    case USECASE_AUDIO_HFP_SCO_WB_DOWNLINK:
         *plugin_usecase = AUDIO_HAL_PLUGIN_USECASE_HFP_VOICE_CALL;
         break;
     case USECASE_VOICE_CALL:
diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c
index 1088a0c..9b60083 100644
--- a/hal/audio_extn/hfp.c
+++ b/hal/audio_extn/hfp.c
@@ -125,6 +125,8 @@
 static fp_disable_audio_route_t                     fp_disable_audio_route;
 static fp_disable_snd_device_t                      fp_disable_snd_device;
 static fp_voice_get_mic_mute_t                      fp_voice_get_mic_mute;
+static fp_audio_extn_auto_hal_start_hfp_downlink_t  fp_audio_extn_auto_hal_start_hfp_downlink;
+static fp_audio_extn_auto_hal_stop_hfp_downlink_t   fp_audio_extn_auto_hal_stop_hfp_downlink;
 
 static int32_t hfp_set_volume(struct audio_device *adev, float value)
 {
@@ -332,15 +334,6 @@
     ALOGD("%s: HFP PCM devices (rx: %d tx: %d pcm dev id: %d) usecase(%d)",
               __func__, pcm_dev_rx_id, pcm_dev_tx_id, hfpmod.hfp_pcm_dev_id, uc_info->id);
 
-    hfpmod.hfp_sco_rx = pcm_open(adev->snd_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;
-    }
-
     hfpmod.hfp_pcm_rx = pcm_open(adev->snd_card,
                                  pcm_dev_rx_id,
                                  PCM_OUT, &pcm_config_hfp);
@@ -350,15 +343,6 @@
         goto exit;
     }
 
-    hfpmod.hfp_sco_tx = pcm_open(adev->snd_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;
-    }
-
     hfpmod.hfp_pcm_tx = pcm_open(adev->snd_card,
                                  pcm_dev_tx_id,
                                  PCM_IN, &pcm_config_hfp);
@@ -368,17 +352,6 @@
         goto exit;
     }
 
-    if (pcm_start(hfpmod.hfp_sco_rx) < 0) {
-        ALOGE("%s: pcm start for hfp sco rx failed", __func__);
-        ret = -EINVAL;
-        goto exit;
-    }
-    if (pcm_start(hfpmod.hfp_sco_tx) < 0) {
-        ALOGE("%s: pcm start for hfp sco tx failed", __func__);
-        ret = -EINVAL;
-        goto exit;
-    }
-
     if (pcm_start(hfpmod.hfp_pcm_rx) < 0) {
         ALOGE("%s: pcm start for hfp pcm rx failed", __func__);
         ret = -EINVAL;
@@ -390,6 +363,38 @@
         goto exit;
     }
 
+    if (fp_audio_extn_auto_hal_start_hfp_downlink(adev, uc_info))
+        ALOGE("%s: start hfp downlink failed", __func__);
+
+    hfpmod.hfp_sco_rx = pcm_open(adev->snd_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;
+    }
+
+    hfpmod.hfp_sco_tx = pcm_open(adev->snd_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;
+    }
+
+    if (pcm_start(hfpmod.hfp_sco_rx) < 0) {
+        ALOGE("%s: pcm start for hfp sco rx failed", __func__);
+        ret = -EINVAL;
+        goto exit;
+    }
+    if (pcm_start(hfpmod.hfp_sco_tx) < 0) {
+        ALOGE("%s: pcm start for hfp sco tx failed", __func__);
+        ret = -EINVAL;
+        goto exit;
+    }
+
     hfpmod.is_hfp_running = true;
     hfp_set_volume(adev, hfpmod.hfp_volume);
 
@@ -455,6 +460,9 @@
     fp_disable_snd_device(adev, uc_info->out_snd_device);
     fp_disable_snd_device(adev, uc_info->in_snd_device);
 
+    if (fp_audio_extn_auto_hal_stop_hfp_downlink(adev, uc_info))
+        ALOGE("%s: stop hfp downlink failed", __func__);
+
     /* Set the unmute Tx mixer control */
     if (fp_voice_get_mic_mute(adev)) {
         fp_platform_set_mic_mute(adev->platform, false);
@@ -483,6 +491,10 @@
     fp_disable_audio_route = init_config.fp_disable_audio_route;
     fp_disable_snd_device = init_config.fp_disable_snd_device;
     fp_voice_get_mic_mute = init_config.fp_voice_get_mic_mute;
+    fp_audio_extn_auto_hal_start_hfp_downlink =
+                                init_config.fp_audio_extn_auto_hal_start_hfp_downlink;
+    fp_audio_extn_auto_hal_stop_hfp_downlink =
+                                init_config.fp_audio_extn_auto_hal_stop_hfp_downlink;
 }
 
 bool hfp_is_active(struct audio_device *adev)
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index a29b6e5..b25fe3c 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -832,6 +832,25 @@
     return adev->vr_audio_mode_enabled;
 }
 
+static void audio_extn_btsco_get_sample_rate(int snd_device, int *sample_rate)
+{
+    switch (snd_device) {
+    case SND_DEVICE_OUT_BT_SCO:
+    case SND_DEVICE_IN_BT_SCO_MIC:
+    case SND_DEVICE_IN_BT_SCO_MIC_NREC:
+        *sample_rate = 8000;
+        break;
+    case SND_DEVICE_OUT_BT_SCO_WB:
+    case SND_DEVICE_IN_BT_SCO_MIC_WB:
+    case SND_DEVICE_IN_BT_SCO_MIC_WB_NREC:
+        *sample_rate = 16000;
+        break;
+    default:
+        ALOGD("%s:Not a BT SCO device, need not update sampling rate\n", __func__);
+        break;
+    }
+}
+
 void audio_extn_utils_update_stream_app_type_cfg_for_usecase(
                                     struct audio_device *adev,
                                     struct audio_usecase *usecase)
@@ -880,31 +899,46 @@
                                                 &usecase->stream.inout->out_app_type_cfg);
         ALOGV("%s Selected apptype: %d", __func__, usecase->stream.inout->out_app_type_cfg.app_type);
         break;
+    case PCM_HFP_CALL:
+        switch (usecase->id) {
+        case USECASE_AUDIO_HFP_SCO:
+        case USECASE_AUDIO_HFP_SCO_WB:
+            audio_extn_btsco_get_sample_rate(usecase->out_snd_device,
+                                             &usecase->out_app_type_cfg.sample_rate);
+            usecase->in_app_type_cfg.sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+            break;
+        case USECASE_AUDIO_HFP_SCO_DOWNLINK:
+        case USECASE_AUDIO_HFP_SCO_WB_DOWNLINK:
+            audio_extn_btsco_get_sample_rate(usecase->in_snd_device,
+                                             &usecase->in_app_type_cfg.sample_rate);
+            usecase->out_app_type_cfg.sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+            break;
+        default:
+            ALOGE("%s: usecase id (%d) not supported, use default sample rate",
+                __func__, usecase->id);
+            usecase->in_app_type_cfg.sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+            usecase->out_app_type_cfg.sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+            break;
+        }
+        /* update out_app_type_cfg */
+        usecase->out_app_type_cfg.bit_width =
+                                platform_get_snd_device_bit_width(usecase->out_snd_device);
+        usecase->out_app_type_cfg.app_type =
+                                platform_get_default_app_type_v2(adev->platform, PCM_PLAYBACK);
+        /* update in_app_type_cfg */
+        usecase->in_app_type_cfg.bit_width =
+                                platform_get_snd_device_bit_width(usecase->in_snd_device);
+        usecase->in_app_type_cfg.app_type =
+                                platform_get_default_app_type_v2(adev->platform, PCM_CAPTURE);
+        ALOGV("%s Selected apptype: playback %d capture %d",
+            __func__, usecase->out_app_type_cfg.app_type, usecase->in_app_type_cfg.app_type);
+        break;
     default:
         ALOGE("%s: app type cfg not supported for usecase type (%d)",
             __func__, usecase->type);
     }
 }
 
-void audio_extn_btsco_get_sample_rate(int snd_device, int *sample_rate)
-{
-    switch (snd_device) {
-    case SND_DEVICE_OUT_BT_SCO:
-    case SND_DEVICE_IN_BT_SCO_MIC:
-    case SND_DEVICE_IN_BT_SCO_MIC_NREC:
-        *sample_rate = 8000;
-        break;
-    case SND_DEVICE_OUT_BT_SCO_WB:
-    case SND_DEVICE_IN_BT_SCO_MIC_WB:
-    case SND_DEVICE_IN_BT_SCO_MIC_WB_NREC:
-        *sample_rate = 16000;
-        break;
-    default:
-        ALOGD("%s:Not a BT SCO device, need not update sampling rate\n", __func__);
-        break;
-    }
-}
-
 static int set_stream_app_type_mixer_ctrl(struct audio_device *adev,
                                           int pcm_device_id, int app_type,
                                           int acdb_dev_id, int sample_rate,
@@ -955,21 +989,27 @@
     int pcm_device_id, acdb_dev_id = 0, snd_device = usecase->out_snd_device;
     int32_t sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
     int app_type = 0, rc = 0;
+    bool is_bus_dev_usecase = false;
 
     ALOGV("%s", __func__);
 
     if (usecase->type != PCM_HFP_CALL) {
-        ALOGV("%s: not a playback or HFP path, no need to cfg app type", __func__);
+        ALOGV("%s: not a HFP path, no need to cfg app type", __func__);
         rc = 0;
         goto exit_send_app_type_cfg;
     }
     if ((usecase->id != USECASE_AUDIO_HFP_SCO) &&
-        (usecase->id != USECASE_AUDIO_HFP_SCO_WB)) {
-        ALOGV("%s: a playback path where app type cfg is not required", __func__);
+        (usecase->id != USECASE_AUDIO_HFP_SCO_WB) &&
+        (usecase->id != USECASE_AUDIO_HFP_SCO_DOWNLINK) &&
+        (usecase->id != USECASE_AUDIO_HFP_SCO_WB_DOWNLINK)) {
+        ALOGV("%s: a usecase where app type cfg is not required", __func__);
         rc = 0;
         goto exit_send_app_type_cfg;
     }
 
+    if (usecase->devices & AUDIO_DEVICE_OUT_BUS)
+        is_bus_dev_usecase = true;
+
     snd_device = usecase->out_snd_device;
     pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_PLAYBACK);
 
@@ -983,24 +1023,47 @@
     if (usecase->type == PCM_HFP_CALL) {
 
         /* config HFP session:1 playback path */
-        app_type = platform_get_default_app_type_v2(adev->platform, PCM_PLAYBACK);
-        sample_rate= CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+        if (is_bus_dev_usecase) {
+            app_type = usecase->out_app_type_cfg.app_type;
+            sample_rate= usecase->out_app_type_cfg.sample_rate;
+        } else {
+            snd_device = SND_DEVICE_NONE; // use legacy behavior
+            app_type = platform_get_default_app_type_v2(adev->platform, PCM_PLAYBACK);
+            sample_rate= CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+        }
         rc = set_stream_app_type_mixer_ctrl(adev, pcm_device_id, app_type,
                                             acdb_dev_id, sample_rate,
                                             PCM_PLAYBACK,
-                                            SND_DEVICE_NONE); // use legacy behavior
+                                            snd_device);
         if (rc < 0)
             goto exit_send_app_type_cfg;
 
         /* config HFP session:1 capture path */
-        app_type = platform_get_default_app_type_v2(adev->platform, PCM_CAPTURE);
+        if (is_bus_dev_usecase) {
+            snd_device = usecase->in_snd_device;
+            pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_CAPTURE);
+            acdb_dev_id = platform_get_snd_device_acdb_id(snd_device);
+            if (acdb_dev_id < 0) {
+                ALOGE("%s: Couldn't get the acdb dev id", __func__);
+                rc = -EINVAL;
+                goto exit_send_app_type_cfg;
+            }
+            app_type = usecase->in_app_type_cfg.app_type;
+            sample_rate= usecase->in_app_type_cfg.sample_rate;
+        } else {
+            snd_device = SND_DEVICE_NONE; // use legacy behavior
+            app_type = platform_get_default_app_type_v2(adev->platform, PCM_CAPTURE);
+        }
         rc = set_stream_app_type_mixer_ctrl(adev, pcm_device_id, app_type,
                                             acdb_dev_id, sample_rate,
                                             PCM_CAPTURE,
-                                            SND_DEVICE_NONE);
+                                            snd_device);
         if (rc < 0)
             goto exit_send_app_type_cfg;
 
+        if (is_bus_dev_usecase)
+            goto exit_send_app_type_cfg;
+
         /* config HFP session:2 capture path */
         pcm_device_id = HFP_ASM_RX_TX;
         snd_device = usecase->in_snd_device;