hal: update snd device selection in auto hal

Use BUS device associated usecases for SND
device selection on automotive platform.

The criteria for SND device selection are
* HFP calls: usecase->id;
* NON HFP calls: out->car_audio_stream.

Change-Id: If5eb1283e6bfec074efceb4f545a28fdd3dbf601
Signed-off-by: Guodong Hu <guodhu@codeaurora.org>
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index c0784d3..70d9306 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -5465,10 +5465,6 @@
 typedef bool (*auto_hal_is_bus_device_usecase_t)(audio_usecase_t);
 static auto_hal_is_bus_device_usecase_t auto_hal_is_bus_device_usecase;
 
-typedef snd_device_t (*auto_hal_get_snd_device_for_car_audio_stream_t)(
-                                struct stream_out*);
-static auto_hal_get_snd_device_for_car_audio_stream_t auto_hal_get_snd_device_for_car_audio_stream;
-
 typedef int (*auto_hal_get_audio_port_t)(struct audio_hw_device*,
                                 struct audio_port*);
 static auto_hal_get_audio_port_t auto_hal_get_audio_port;
@@ -5489,6 +5485,14 @@
                                 struct audio_usecase*);
 static auto_hal_stop_hfp_downlink_t auto_hal_stop_hfp_downlink;
 
+typedef snd_device_t (*auto_hal_get_input_snd_device_t)(struct audio_device*,
+                                audio_usecase_t);
+static auto_hal_get_input_snd_device_t auto_hal_get_input_snd_device;
+
+typedef snd_device_t (*auto_hal_get_output_snd_device_t)(struct audio_device*,
+                                audio_usecase_t);
+static auto_hal_get_output_snd_device_t auto_hal_get_output_snd_device;
+
 int auto_hal_feature_init(bool is_feature_enabled)
 {
     ALOGD("%s: Called with feature %s", __func__,
@@ -5521,9 +5525,6 @@
             !(auto_hal_is_bus_device_usecase =
                  (auto_hal_is_bus_device_usecase_t)dlsym(
                             auto_hal_lib_handle, "auto_hal_is_bus_device_usecase")) ||
-            !(auto_hal_get_snd_device_for_car_audio_stream =
-                 (auto_hal_get_snd_device_for_car_audio_stream_t)dlsym(
-                            auto_hal_lib_handle, "auto_hal_get_snd_device_for_car_audio_stream")) ||
             !(auto_hal_get_audio_port =
                  (auto_hal_get_audio_port_t)dlsym(
                             auto_hal_lib_handle, "auto_hal_get_audio_port")) ||
@@ -5538,7 +5539,13 @@
                             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"))) {
+                            auto_hal_lib_handle, "auto_hal_stop_hfp_downlink")) ||
+            !(auto_hal_get_input_snd_device =
+                 (auto_hal_get_input_snd_device_t)dlsym(
+                            auto_hal_lib_handle, "auto_hal_get_input_snd_device")) ||
+            !(auto_hal_get_output_snd_device =
+                 (auto_hal_get_output_snd_device_t)dlsym(
+                            auto_hal_lib_handle, "auto_hal_get_output_snd_device"))) {
             ALOGE("%s: dlsym failed", __func__);
             goto feature_disabled;
         }
@@ -5559,12 +5566,13 @@
     auto_hal_get_car_audio_stream_from_address = NULL;
     auto_hal_open_output_stream = NULL;
     auto_hal_is_bus_device_usecase = NULL;
-    auto_hal_get_snd_device_for_car_audio_stream = NULL;
     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;
+    auto_hal_get_input_snd_device = NULL;
+    auto_hal_get_output_snd_device = NULL;
 
     ALOGW(":: %s: ---- Feature AUTO_HAL is disabled ----", __func__);
     return -ENOSYS;
@@ -5584,6 +5592,8 @@
         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;
+        auto_hal_init_config.fp_adev_get_active_input = adev_get_active_input;
+        auto_hal_init_config.fp_platform_set_echo_reference = platform_set_echo_reference;
         return auto_hal_init(adev, auto_hal_init_config);
     }
     else
@@ -5622,25 +5632,19 @@
 int audio_extn_auto_hal_get_car_audio_stream_from_address(const char *address)
 {
     return ((auto_hal_get_car_audio_stream_from_address) ?
-                            auto_hal_get_car_audio_stream_from_address(address): 0);
+                            auto_hal_get_car_audio_stream_from_address(address): -ENOSYS);
 }
 
 int audio_extn_auto_hal_open_output_stream(struct stream_out *out)
 {
     return ((auto_hal_open_output_stream) ?
-                            auto_hal_open_output_stream(out): 0);
+                            auto_hal_open_output_stream(out): -ENOSYS);
 }
 
 bool audio_extn_auto_hal_is_bus_device_usecase(audio_usecase_t uc_id)
 {
     return ((auto_hal_is_bus_device_usecase) ?
-                            auto_hal_is_bus_device_usecase(uc_id): 0);
-}
-
-snd_device_t audio_extn_auto_hal_get_snd_device_for_car_audio_stream(struct stream_out *out)
-{
-    return ((auto_hal_get_snd_device_for_car_audio_stream) ?
-                            auto_hal_get_snd_device_for_car_audio_stream(out): 0);
+                            auto_hal_is_bus_device_usecase(uc_id): false);
 }
 
 int audio_extn_auto_hal_get_audio_port(struct audio_hw_device *dev,
@@ -5677,6 +5681,20 @@
     return ((auto_hal_stop_hfp_downlink) ?
                             auto_hal_stop_hfp_downlink(adev, uc_info): 0);
 }
+
+snd_device_t audio_extn_auto_hal_get_input_snd_device(struct audio_device *adev,
+                                audio_usecase_t uc_id)
+{
+    return ((auto_hal_get_input_snd_device) ?
+                            auto_hal_get_input_snd_device(adev, uc_id): SND_DEVICE_NONE);
+}
+
+snd_device_t audio_extn_auto_hal_get_output_snd_device(struct audio_device *adev,
+                                audio_usecase_t uc_id)
+{
+    return ((auto_hal_get_output_snd_device) ?
+                            auto_hal_get_output_snd_device(adev, uc_id): SND_DEVICE_NONE);
+}
 // 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 36d2367..5402b81 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -1315,7 +1315,6 @@
 int audio_extn_auto_hal_get_car_audio_stream_from_address(const char *address);
 int audio_extn_auto_hal_open_output_stream(struct stream_out *out);
 bool audio_extn_auto_hal_is_bus_device_usecase(audio_usecase_t uc_id);
-snd_device_t audio_extn_auto_hal_get_snd_device_for_car_audio_stream(struct stream_out *out);
 int audio_extn_auto_hal_get_audio_port(struct audio_hw_device *dev,
                                 struct audio_port *config);
 int audio_extn_auto_hal_set_audio_port_config(struct audio_hw_device *dev,
@@ -1326,11 +1325,16 @@
                                 struct audio_usecase *uc_info);
 int audio_extn_auto_hal_stop_hfp_downlink(struct audio_device *adev,
                                 struct audio_usecase *uc_info);
+snd_device_t audio_extn_auto_hal_get_input_snd_device(struct audio_device *adev,
+                                audio_usecase_t uc_id);
+snd_device_t audio_extn_auto_hal_get_output_snd_device(struct audio_device *adev,
+                                audio_usecase_t uc_id);
 
 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);
 typedef size_t (*fp_get_output_period_size_t)(uint32_t, audio_format_t, int, int);
 typedef int (*fp_audio_extn_ext_hw_plugin_set_audio_gain_t)(void*, struct audio_usecase*, uint32_t);
+typedef struct stream_in* (*fp_adev_get_active_input_t)(const struct audio_device*);
 
 typedef struct auto_hal_init_config {
     fp_in_get_stream_t                           fp_in_get_stream;
@@ -1343,6 +1347,8 @@
     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;
+    fp_adev_get_active_input_t                   fp_adev_get_active_input;
+    fp_platform_set_echo_reference_t             fp_platform_set_echo_reference;
 } 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 df0fcca..739d564 100644
--- a/hal/audio_extn/auto_hal.c
+++ b/hal/audio_extn/auto_hal.c
@@ -57,6 +57,8 @@
 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;
+static fp_adev_get_active_input_t                   fp_adev_get_active_input;
+static fp_platform_set_echo_reference_t             fp_platform_set_echo_reference;
 
 /* Auto hal module struct */
 static struct auto_hal_module *auto_hal = NULL;
@@ -773,6 +775,145 @@
     return ret;
 }
 
+snd_device_t auto_hal_get_input_snd_device(struct audio_device *adev,
+                                audio_usecase_t uc_id)
+{
+    snd_device_t snd_device = SND_DEVICE_NONE;
+    audio_devices_t out_device = AUDIO_DEVICE_NONE;
+    struct audio_usecase *usecase = NULL;
+    struct stream_in *in = fp_adev_get_active_input(adev);
+    audio_devices_t in_device = ((in == NULL) ?
+                                    AUDIO_DEVICE_NONE : in->device)
+                                & ~AUDIO_DEVICE_BIT_IN;
+
+    if (uc_id == USECASE_INVALID) {
+        ALOGE("%s: Invalid usecase (%d)", __func__, uc_id);
+        return -EINVAL;
+    }
+
+    usecase = fp_get_usecase_from_list(adev, uc_id);
+    if (usecase == NULL) {
+        ALOGE("%s: Could not find the usecase (%d)", __func__, uc_id);
+        return -EINVAL;
+    }
+
+    if (usecase->stream.out == NULL) {
+        ALOGE("%s: stream.out is NULL", __func__);
+        return -EINVAL;
+    }
+
+    out_device = usecase->stream.out->devices;
+    if (out_device == AUDIO_DEVICE_NONE ||
+        out_device & AUDIO_DEVICE_BIT_IN) {
+        ALOGE("%s: Invalid output devices (%#x)", __func__, out_device);
+        return -EINVAL;
+    }
+
+    ALOGV("%s: output device(%#x), input device(%#x), usecase(%d)",
+        __func__, out_device, in_device, uc_id);
+
+    if (out_device & AUDIO_DEVICE_OUT_BUS) {
+        /* usecase->id is token as judgement for HFP calls */
+        switch (usecase->id) {
+        case USECASE_AUDIO_HFP_SCO:
+        case USECASE_AUDIO_HFP_SCO_WB:
+            snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP;
+            if (adev->enable_hfp)
+                fp_platform_set_echo_reference(adev, true, out_device);
+            break;
+        case USECASE_AUDIO_HFP_SCO_DOWNLINK:
+            snd_device = SND_DEVICE_IN_BT_SCO_MIC;
+            break;
+        case USECASE_AUDIO_HFP_SCO_WB_DOWNLINK:
+            snd_device = SND_DEVICE_IN_BT_SCO_MIC_WB;
+            break;
+        case USECASE_VOICE_CALL:
+            snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC;
+            break;
+        default:
+            ALOGE("%s: Usecase (%d) not supported", __func__, uc_id);
+            return -EINVAL;
+        }
+    } else {
+        ALOGE("%s: Output devices (%#x) not supported", __func__, out_device);
+        return -EINVAL;
+    }
+
+    return snd_device;
+}
+
+snd_device_t auto_hal_get_output_snd_device(struct audio_device *adev,
+                                audio_usecase_t uc_id)
+{
+    snd_device_t snd_device = SND_DEVICE_NONE;
+    audio_devices_t devices = AUDIO_DEVICE_NONE;
+    struct audio_usecase *usecase = NULL;
+
+    if (uc_id == USECASE_INVALID) {
+        ALOGE("%s: Invalid usecase (%d)", __func__, uc_id);
+        return -EINVAL;
+    }
+
+    usecase = fp_get_usecase_from_list(adev, uc_id);
+    if (usecase == NULL) {
+        ALOGE("%s: Could not find the usecase (%d)", __func__, uc_id);
+        return -EINVAL;
+    }
+
+    if (usecase->stream.out == NULL) {
+        ALOGE("%s: stream.out is NULL", __func__);
+        return -EINVAL;
+    }
+
+    devices = usecase->stream.out->devices;
+    if (devices == AUDIO_DEVICE_NONE ||
+        devices & AUDIO_DEVICE_BIT_IN) {
+        ALOGE("%s: Invalid output devices (%#x)", __func__, devices);
+        return -EINVAL;
+    }
+
+    ALOGV("%s: output devices(%#x), usecase(%d)", __func__, devices, uc_id);
+
+    if (devices & AUDIO_DEVICE_OUT_BUS) {
+        /* usecase->id is token as judgement for HFP calls */
+        switch (usecase->id) {
+        case USECASE_AUDIO_HFP_SCO:
+            snd_device = SND_DEVICE_OUT_BT_SCO;
+            break;
+        case USECASE_AUDIO_HFP_SCO_WB:
+            snd_device = SND_DEVICE_OUT_BT_SCO_WB;
+            break;
+        case USECASE_AUDIO_HFP_SCO_DOWNLINK:
+        case USECASE_AUDIO_HFP_SCO_WB_DOWNLINK:
+            snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_HFP;
+            break;
+        case USECASE_VOICE_CALL:
+            snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
+            break;
+        case USECASE_AUDIO_PLAYBACK_MEDIA:
+            snd_device = SND_DEVICE_OUT_BUS_MEDIA;
+            break;
+        case USECASE_AUDIO_PLAYBACK_SYS_NOTIFICATION:
+            snd_device = SND_DEVICE_OUT_BUS_SYS;
+            break;
+        case USECASE_AUDIO_PLAYBACK_NAV_GUIDANCE:
+            snd_device = SND_DEVICE_OUT_BUS_NAV;
+            break;
+        case USECASE_AUDIO_PLAYBACK_PHONE:
+            snd_device = SND_DEVICE_OUT_BUS_PHN;
+            break;
+        default:
+            ALOGE("%s: Usecase (%d) not supported", __func__, uc_id);
+            return -EINVAL;
+        }
+    } else {
+        ALOGE("%s: Output devices (%#x) not supported", __func__, devices);
+        return -EINVAL;
+    }
+
+    return snd_device;
+}
+
 int auto_hal_init(struct audio_device *adev, auto_hal_init_config_t init_config)
 {
     int ret = 0;
@@ -803,6 +944,8 @@
     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;
+    fp_adev_get_active_input = init_config.fp_adev_get_active_input;
+    fp_platform_set_echo_reference = init_config.fp_platform_set_echo_reference;
 
     return ret;
 }
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 40cea6c..cea5e74 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -2432,11 +2432,18 @@
             ALOGE("%s: stream.out is NULL", __func__);
             return -EINVAL;
         }
-        out_snd_device = platform_get_output_snd_device(adev->platform,
-                                                        usecase->stream.out);
-        in_snd_device = platform_get_input_snd_device(adev->platform,
-                                                      NULL,
-                                                      usecase->stream.out->devices);
+        if (usecase->devices & AUDIO_DEVICE_OUT_BUS) {
+            out_snd_device = audio_extn_auto_hal_get_output_snd_device(adev,
+                                                                       uc_id);
+            in_snd_device = audio_extn_auto_hal_get_input_snd_device(adev,
+                                                                     uc_id);
+        } else {
+            out_snd_device = platform_get_output_snd_device(adev->platform,
+                                                            usecase->stream.out);
+            in_snd_device = platform_get_input_snd_device(adev->platform,
+                                                          NULL,
+                                                          usecase->stream.out->devices);
+        }
         usecase->devices = usecase->stream.out->devices;
     } else if (usecase->type == TRANSCODE_LOOPBACK_RX) {
         if (usecase->stream.inout == NULL) {
@@ -2517,8 +2524,11 @@
             if (out_snd_device == SND_DEVICE_NONE) {
                 struct stream_out *voip_out = adev->primary_output;
                 struct stream_in *voip_in = get_voice_communication_input(adev);
-                out_snd_device = platform_get_output_snd_device(adev->platform,
-                                                                usecase->stream.out);
+                if (usecase->devices & AUDIO_DEVICE_OUT_BUS)
+                    out_snd_device = audio_extn_auto_hal_get_output_snd_device(adev, uc_id);
+                else
+                    out_snd_device = platform_get_output_snd_device(adev->platform,
+                                                                    usecase->stream.out);
                 voip_usecase = get_usecase_from_list(adev, USECASE_AUDIO_PLAYBACK_VOIP);
 
                 if (voip_usecase)
@@ -2580,10 +2590,11 @@
             return 0;
     }
 
-    if ((is_btsco_device(out_snd_device,in_snd_device) && !adev->bt_sco_on) ||
-         (is_a2dp_device(out_snd_device) && !audio_extn_a2dp_source_is_ready())) {
-          ALOGD("SCO/A2DP is selected but they are not connected/ready hence dont route");
-          return 0;
+    if (!(usecase->devices & AUDIO_DEVICE_OUT_BUS) &&
+        ((is_btsco_device(out_snd_device,in_snd_device) && !adev->bt_sco_on) ||
+            (is_a2dp_device(out_snd_device) && !audio_extn_a2dp_source_is_ready()))) {
+        ALOGD("SCO/A2DP is selected but they are not connected/ready hence dont route");
+        return 0;
     }
 
     if (out_snd_device != SND_DEVICE_NONE &&
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index f860df5..ab63925 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -6097,8 +6097,7 @@
                 snd_device = SND_DEVICE_OUT_BT_SCO_WB;
             else
                 snd_device = SND_DEVICE_OUT_BT_SCO;
-        } else if ((devices & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_SPEAKER_SAFE)) ||
-                   (devices & AUDIO_DEVICE_OUT_BUS)) {
+        } else if (devices & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
             if (my_data->is_vbat_speaker || my_data->is_bcl_speaker) {
                 if (hw_info_is_stereo_spkr(my_data->hw_info)) {
                     if (my_data->mono_speaker == SPKR_1)
@@ -6274,7 +6273,7 @@
         snd_device = SND_DEVICE_OUT_AFE_PROXY;
         audio_extn_set_afe_proxy_channel_mixer(adev, channel_count, snd_device);
     } else if (devices & AUDIO_DEVICE_OUT_BUS) {
-        snd_device = audio_extn_auto_hal_get_snd_device_for_car_audio_stream(out);
+        snd_device = audio_extn_auto_hal_get_output_snd_device(adev, out->usecase);
     } else {
         ALOGE("%s: Unknown device(s) %#x", __func__, devices);
     }
@@ -6653,8 +6652,7 @@
         } else if (out_device & AUDIO_DEVICE_OUT_SPEAKER ||
                    out_device & AUDIO_DEVICE_OUT_SPEAKER_SAFE ||
                    out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
-                   out_device & AUDIO_DEVICE_OUT_LINE ||
-                   out_device & AUDIO_DEVICE_OUT_BUS) {
+                   out_device & AUDIO_DEVICE_OUT_LINE) {
             if (my_data->fluence_type != FLUENCE_NONE &&
                 (my_data->fluence_in_voice_call ||
                  my_data->fluence_in_hfp_call) &&