tizenaudio-policy: Use new sub-functions inside of route_change_hook_cb() 05/214105/3
authorSangchul Lee <sc11.lee@samsung.com>
Wed, 18 Sep 2019 05:59:05 +0000 (14:59 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Thu, 19 Sep 2019 01:41:10 +0000 (10:41 +0900)
It'll reduce cyclomatic complexity of SAM.

[Version] 11.1.77
[Issue Type] Refactoring

Change-Id: I2d9aeefc4c503532273cf09668139c034f961589
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
packaging/pulseaudio-modules-tizen.spec
src/module-tizenaudio-policy.c

index 1a8a1f8..1fd3a47 100644 (file)
@@ -1,6 +1,6 @@
 Name:             pulseaudio-modules-tizen
 Summary:          Pulseaudio modules for Tizen
-Version:          11.1.76
+Version:          11.1.77
 Release:          0
 Group:            Multimedia/Audio
 License:          LGPL-2.1+
index 7bfbb8e..de7a79e 100644 (file)
@@ -1068,6 +1068,348 @@ static void fill_device_info(hal_route_info *route_info, const char *type, uint3
                 route_info->num_of_devices -1, type, direction, id);
 }
 
+static pa_hook_result_t update_combine_sink_and_bt_sco(struct userdata *u, pa_stream_manager_hook_data_for_route *data,
+                                                    pa_tz_device *device, const char *stream_role, const char *dm_device_type,
+                                                    pa_sink **combine_sink_arg1, pa_sink **combine_sink_arg2) {
+    pa_sink *sink = NULL;
+
+    pa_assert(u);
+    pa_assert(data);
+    pa_assert(device);
+
+    switch (data->route_type) {
+    case STREAM_ROUTE_TYPE_AUTO: {
+        /* unload combine sink */
+        if (data->stream_type == STREAM_SINK_INPUT) {
+            if ((sink = pa_tz_device_get_sink(device, data->device_role)))
+                unload_combine_sink_module(u, SINK_NAME_COMBINED, sink);
+            else
+                pa_log_error("[ROUTE][AUTO] could not get sink");
+        }
+        if (pa_safe_streq(dm_device_type, DEVICE_TYPE_BT_SCO)) {
+            if (IS_ROLE_AVAILABLE_BT_SCO_OPEN(stream_role)) {
+                if (update_bt_sco_state(u, true, false, stream_role)) {
+                    pa_log_error("  ** could not open BT SCO");
+                    return PA_HOOK_CANCEL;
+                }
+                update_bt_sco_option(u, stream_role);
+            }
+            return PA_HOOK_OK;
+        }
+        update_bt_sco_state(u, false, false, NULL);
+        break;
+    }
+    case STREAM_ROUTE_TYPE_AUTO_ALL: {
+        pa_source *source = NULL;
+        uint32_t s_idx = 0;
+        void *s = NULL;
+        stream_route_type_t route_type;
+
+        update_bt_sco_state(u, false, false, NULL);
+
+        /* find the proper sink/source */
+        /* currently, we support two sinks for combining */
+        if (data->stream_type == STREAM_SINK_INPUT && u->module_combine_sink) {
+            sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK);
+            pa_log_info("[ROUTE][AUTO_ALL] found the combine_sink already existed");
+
+        } else if (data->stream_type == STREAM_SINK_INPUT && !*combine_sink_arg1) {
+            sink = *combine_sink_arg1 = pa_tz_device_get_sink(device, data->device_role);
+            if (sink)
+                pa_log_info("[ROUTE][AUTO_ALL] combine_sink_arg1[%s], combine_sink_arg2[%p]", sink->name, *combine_sink_arg2);
+
+        } else if (data->stream_type == STREAM_SINK_INPUT && !*combine_sink_arg2) {
+            sink = *combine_sink_arg2 = pa_tz_device_get_sink(device, data->device_role);
+            if (sink && !pa_safe_streq(sink->name, (*combine_sink_arg1)->name)) {
+                pa_log_info("[ROUTE][AUTO_ALL] combine_sink_arg2[%s]", sink->name);
+                /* load combine sink */
+                if (!u->module_combine_sink) {
+                    char *args = pa_sprintf_malloc("sink_name=%s slaves=\"%s,%s\"",
+                                                SINK_NAME_COMBINED, (*combine_sink_arg1)->name, (*combine_sink_arg2)->name);
+                    pa_log_info("[ROUTE][AUTO_ALL] combined sink is not prepared, now load module[%s]", args);
+                    u->module_combine_sink = pa_module_load(u->core, MODULE_COMBINE_SINK, args);
+                    pa_xfree(args);
+                }
+                if ((sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK))) {
+                    PA_IDXSET_FOREACH(s, (*combine_sink_arg1)->inputs, s_idx) {
+                        if (s == data->stream) {
+                            pa_sink_input_move_to(s, sink, false);
+                            pa_log_info("[ROUTE][AUTO_ALL] *** sink-nput(%p,%u) moves to sink(%p,%s)",
+                                        s, ((pa_sink_input*)s)->index, sink, sink->name);
+                        }
+                    }
+                }
+            }
+
+        } else if (data->stream_type == STREAM_SOURCE_OUTPUT) {
+            source = pa_tz_device_get_source(device, data->device_role);
+        }
+
+        if (data->origins_from_new_data) {
+            if (data->stream_type == STREAM_SINK_INPUT)
+                *(data->proper_sink) = sink;
+            else
+                *(data->proper_source) = source;
+            break;
+        }
+        /* move sink-inputs/source-outputs if needed */
+        if (!data->idx_streams)
+            break;
+        PA_IDXSET_FOREACH(s, data->idx_streams, s_idx) { /* data->idx_streams: null_sink */
+            if (pa_stream_manager_get_route_type(s, data->stream_type, false, &route_type) ||
+                (route_type != STREAM_ROUTE_TYPE_AUTO_ALL))
+                continue;
+            if ((data->stream_type == STREAM_SINK_INPUT) && (sink && (sink != ((pa_sink_input*)s)->sink))) {
+                pa_sink_input_move_to(s, sink, false);
+                pa_log_info("[ROUTE][AUTO_ALL] *** sink-input(%p,%u) moves to sink(%p,%s)",
+                            s, ((pa_sink_input*)s)->index, sink, sink->name);
+            } else if ((data->stream_type == STREAM_SOURCE_OUTPUT) && (source && (source != ((pa_source_output*)s)->source))) {
+                pa_source_output_move_to(s, source, false);
+                pa_log_info("[ROUTE][AUTO_ALL] *** source-output(%p,%u) moves to source(%p,%s)",
+                            s, ((pa_source_output*)s)->index, source, source->name);
+            }
+        }
+        break;
+    }
+    default:
+        pa_log_error("it can not be here, route_type(%d)", data->route_type);
+        break;
+    }
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t handle_auto_or_auto_all_routing(struct userdata *u, pa_stream_manager_hook_data_for_route *data,
+                                                        hal_route_info *route_info, pa_idxset *conn_devices, pa_tz_device **device) {
+    const char *device_type = NULL;
+    const char *dm_device_type = NULL;
+    dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
+    uint32_t dm_device_id = 0;
+    uint32_t idx = 0;
+    uint32_t conn_idx = 0;
+    bool use_internal_codec = false;
+    pa_sink *combine_sink_arg1 = NULL;
+    pa_sink *combine_sink_arg2 = NULL;
+
+    pa_assert(u);
+    pa_assert(data);
+    pa_assert(route_info);
+    pa_assert(conn_devices);
+    pa_assert(device);
+
+    PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
+        pa_log_debug("[ROUTE][AUTO(_ALL)] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, route_info->role, device_type);
+        if (!is_cached_device_connected(device_type, data->stream_type))
+            continue;
+
+        PA_IDXSET_FOREACH(*device, conn_devices, conn_idx) {
+            dm_device_type = pa_tz_device_get_type(*device);
+            dm_device_direction = pa_tz_device_get_direction(*device);
+            dm_device_id = pa_tz_device_get_id(*device);
+            pa_log_debug("  -- type[%-16s], direction[0x%x], id[%u]",
+                            dm_device_type, dm_device_direction, dm_device_id);
+            if (!pa_safe_streq(device_type, dm_device_type) || !IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction))
+                continue;
+            pa_log_debug("  ** found a matched device: type[%-16s], direction[0x%x]", dm_device_type, dm_device_direction);
+            if (skip_usb_device(data->stream_role, *device))
+                continue;
+            if ((use_internal_codec = pa_tz_device_is_use_internal_codec(*device))) {
+                /* if it needs to skip it, keep going to next device for proper UCM setting */
+                if (skip_device(data->stream_role, dm_device_type))
+                    continue;
+                if (skip_bt_sco_device(u, data->stream_role, dm_device_type))
+                    continue;
+                fill_device_info(route_info, dm_device_type, CONVERT_TO_HAL_DIRECTION(data->stream_type), dm_device_id);
+                break;
+            }
+            pa_log_debug("  -- it does not use internal audio codec, skip it");
+            break;
+        }
+        if (*device == NULL)
+            continue;
+
+        if (data->route_type == STREAM_ROUTE_TYPE_AUTO) {
+            if (data->origins_from_new_data)
+                pa_proplist_sets(GET_STREAM_NEW_PROPLIST(data->stream, data->stream_type),
+                                PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
+            else
+                pa_proplist_sets(GET_STREAM_PROPLIST(data->stream, data->stream_type),
+                                PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
+            return update_combine_sink_and_bt_sco(u, data, *device, route_info->role, dm_device_type, NULL, NULL);
+
+        } else if (data->route_type == STREAM_ROUTE_TYPE_AUTO_ALL) {
+            update_combine_sink_and_bt_sco(u, data, *device, NULL, NULL, &combine_sink_arg1, &combine_sink_arg2);
+        }
+    }
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t handle_auto_last_connected_routing(struct userdata *u, pa_stream_manager_hook_data_for_route *data,
+                                                        hal_route_info *route_info, pa_idxset *conn_devices, pa_tz_device **device) {
+    pa_tz_device *latest_device = NULL;
+    const char *device_type = NULL;
+    const char *latest_device_type = NULL;
+    const char *dm_device_type = NULL;
+    dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
+    uint32_t dm_device_id = 0;
+    uint32_t idx = 0;
+    uint32_t conn_idx = 0;
+    pa_usec_t creation_time = 0;
+    pa_usec_t latest_creation_time = 0;
+    bool use_internal_codec = false;
+    pa_sink *sink = NULL;
+
+    pa_assert(u);
+    pa_assert(data);
+    pa_assert(route_info);
+    pa_assert(conn_devices);
+    pa_assert(device);
+
+    PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
+        pa_log_debug("[ROUTE][AUTO_LAST_CONN] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, data->stream_role, device_type);
+        if (!is_cached_device_connected(device_type, data->stream_type))
+            continue;
+
+        PA_IDXSET_FOREACH(*device, conn_devices, conn_idx) {
+            dm_device_type = pa_tz_device_get_type(*device);
+            dm_device_direction = pa_tz_device_get_direction(*device);
+            dm_device_id = pa_tz_device_get_id(*device);
+            creation_time = pa_tz_device_get_creation_time(*device);
+            pa_log_debug("  -- type[%-16s], direction[0x%x], id[%u], creation_time[%llu]",
+                            dm_device_type, dm_device_direction, dm_device_id, creation_time);
+            if (!pa_safe_streq(device_type, dm_device_type) || !IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction))
+                continue;
+            if (skip_usb_device(data->stream_role, *device))
+                continue;
+            if ((use_internal_codec = pa_tz_device_is_use_internal_codec(*device))) {
+                /* if it needs to skip it, keep going to next device for proper UCM setting */
+                if (skip_device(data->stream_role, dm_device_type) ||
+                    skip_bt_sco_device(u, data->stream_role, dm_device_type))
+                    continue;
+            }
+            if (!latest_device || (latest_creation_time <= creation_time)) {
+                if (device_type_is_builtin(dm_device_type) && pa_safe_streq(latest_device_type, dm_device_type)) {
+                    if (data->stream_type == STREAM_SINK_INPUT ?
+                                                    (void*)pa_tz_device_get_sink(latest_device, data->device_role) :
+                                                    (void*)pa_tz_device_get_source(latest_device, data->device_role))
+                        continue;
+                }
+                latest_device = *device;
+                latest_creation_time = creation_time;
+                latest_device_type = dm_device_type;
+                pa_log_info("  ** updated the last connected device: type[%-16s], direction[0x%x]", dm_device_type, dm_device_direction);
+            }
+        }
+    }
+    /* update activated device if it is found */
+    if (latest_device) {
+        dm_device_type = pa_tz_device_get_type(latest_device);
+        dm_device_id = pa_tz_device_get_id(latest_device);
+        if ((use_internal_codec = pa_tz_device_is_use_internal_codec(latest_device)))
+            fill_device_info(route_info, dm_device_type, CONVERT_TO_HAL_DIRECTION(data->stream_type), dm_device_id);
+        else
+            pa_log_debug("  -- it does not use internal audio codec, skip it");
+
+        if (data->origins_from_new_data)
+            pa_proplist_sets(GET_STREAM_NEW_PROPLIST(data->stream, data->stream_type),
+                            PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
+        else
+            pa_proplist_sets(GET_STREAM_PROPLIST(data->stream, data->stream_type),
+                            PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
+
+        /* unload combine sink */
+        if (data->stream_type == STREAM_SINK_INPUT) {
+            if ((sink = pa_tz_device_get_sink(latest_device, data->device_role)))
+                unload_combine_sink_module(u, SINK_NAME_COMBINED, sink);
+            else
+                pa_log_error("[ROUTE][AUTO_LAST_CONN] could not get sink");
+        }
+
+        if (pa_safe_streq(dm_device_type, DEVICE_TYPE_BT_SCO)) {
+            if (IS_ROLE_AVAILABLE_BT_SCO_OPEN(route_info->role)) {
+                if (update_bt_sco_state(u, true, false, route_info->role)) {
+                    pa_log_error("  ** could not open BT SCO");
+                    return PA_HOOK_CANCEL;
+                }
+                update_bt_sco_option(u, route_info->role);
+            }
+        } else {
+            update_bt_sco_state(u, false, false, NULL);
+        }
+
+        /* Update device with latest_device to use be used later in this function */
+        *device = latest_device;
+    }
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t handle_manual_routing(struct userdata *u, pa_stream_manager_hook_data_for_route *data,
+                                hal_route_info *route_info, pa_tz_device **device) {
+    const char *device_type = NULL;
+    const char *dm_device_type = NULL;
+    dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
+    bool use_internal_codec = false;
+    uint32_t idx = 0;
+    uint32_t d_idx = 0;
+    uint32_t *device_id = NULL;
+
+    pa_assert(u);
+    pa_assert(data);
+    pa_assert(route_info);
+    pa_assert(device);
+
+    PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
+        pa_log_info("[ROUTE][MANUAL] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, data->stream_role, device_type);
+        if (!is_cached_device_connected(device_type, data->stream_type))
+            continue;
+
+        PA_IDXSET_FOREACH(device_id, data->idx_manual_devices, d_idx) {
+            pa_log_debug("  -- manual_device[%u] for this role[%-16s]: device_id(%u)", idx, data->stream_role, *device_id);
+            if (!(*device = pa_device_manager_get_device_by_id(u->device_manager, *device_id)))
+                continue;
+            dm_device_type = pa_tz_device_get_type(*device);
+            if (!pa_safe_streq(device_type, dm_device_type))
+                continue;
+            dm_device_direction = pa_tz_device_get_direction(*device);
+            pa_log_debug("  ** found a matched device: type[%-16s], direction[0x%x]",
+                            dm_device_type, dm_device_direction);
+            /* Check for availability for opening Bluetooth SCO */
+            if (pa_safe_streq(dm_device_type, DEVICE_TYPE_BT_SCO) && IS_ROLE_AVAILABLE_BT_SCO_OPEN(route_info->role)) {
+                /* update BT SCO: open */
+                if (update_bt_sco_state(u, true, false, route_info->role)) {
+                    pa_log_error("  ** could not open BT SCO");
+                    return PA_HOOK_CANCEL;
+                }
+                update_bt_sco_option(u, route_info->role);
+            } else {
+                /* update BT SCO: close */
+                update_bt_sco_state(u, false, false, NULL);
+            }
+            /* Check for in/out devices in case of loopback */
+            if (pa_safe_streq(data->stream_role, STREAM_ROLE_LOOPBACK)) {
+                if ((data->stream_type == STREAM_SINK_INPUT) && (dm_device_direction & DM_DEVICE_DIRECTION_OUT))
+                    u->loopback_args.sink = pa_tz_device_get_sink(*device, NULL);
+                else if ((data->stream_type == STREAM_SOURCE_OUTPUT) && (dm_device_direction & DM_DEVICE_DIRECTION_IN))
+                    u->loopback_args.source = pa_tz_device_get_source(*device, NULL);
+            }
+
+            if (IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
+                if ((use_internal_codec = pa_tz_device_is_use_internal_codec(*device)))
+                    fill_device_info(route_info, dm_device_type, CONVERT_TO_HAL_DIRECTION(data->stream_type), *device_id);
+                else
+                    pa_log_debug("  -- it does not use internal audio codec, skip it");
+            }
+        }
+    }
+    if (pa_safe_streq(data->stream_role, STREAM_ROLE_LOOPBACK)) {
+        /* load module-loopback */
+        if (u->loopback_args.sink && u->loopback_args.source)
+            update_loopback_module(u, true);
+    }
+
+    return PA_HOOK_OK;
+}
+
 /* Change the route setting according to the data from argument.
  * This function is called only when it needs to change routing path via HAL.
  * - stream is null
@@ -1093,20 +1435,9 @@ static void fill_device_info(hal_route_info *route_info, const char *type, uint3
  *     2. Update the state of devices.
  *     3. Call HAL API to apply the routing setting. */
 static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_data_for_route *data, struct userdata *u) {
-    uint32_t idx = 0;
     hal_route_info route_info = {NULL, NULL, 0};
-    uint32_t *device_id = NULL;
-    uint32_t dm_device_id = 0;
-    stream_route_type_t route_type;
-    const char *device_type = NULL;
     pa_tz_device *device = NULL;
-    const char *dm_device_type = NULL;
-    dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
-    pa_sink *sink = NULL;
-    pa_source *source = NULL;
-    pa_sink *combine_sink_arg1 = NULL;
-    pa_sink *combine_sink_arg2 = NULL;
-    bool use_internal_codec = false;
+    pa_hook_result_t result;
 
     pa_assert(c);
     pa_assert(data);
@@ -1137,7 +1468,6 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
     route_info.role = data->stream_role;
 
     if (IS_AUTO_ROUTE_TYPE_SERIES(data->route_type)) {
-        uint32_t conn_idx = 0;
         pa_idxset *conn_devices = NULL;
 
         /* unload module-loopback */
@@ -1151,266 +1481,17 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
         /* get current connected devices */
         conn_devices = pa_device_manager_get_device_list(u->device_manager);
         if (data->route_type == STREAM_ROUTE_TYPE_AUTO || data->route_type == STREAM_ROUTE_TYPE_AUTO_ALL) {
-            PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
-                pa_log_debug("[ROUTE][AUTO(_ALL)] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, route_info.role, device_type);
-                if (!is_cached_device_connected(device_type, data->stream_type))
-                    continue;
-                PA_IDXSET_FOREACH(device, conn_devices, conn_idx) {
-                    dm_device_type = pa_tz_device_get_type(device);
-                    dm_device_direction = pa_tz_device_get_direction(device);
-                    dm_device_id = pa_tz_device_get_id(device);
-                    pa_log_debug("  -- type[%-16s], direction[0x%x], id[%u]",
-                                 dm_device_type, dm_device_direction, dm_device_id);
-                    if (pa_safe_streq(device_type, dm_device_type) && IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
-                        pa_log_debug("  ** found a matched device: type[%-16s], direction[0x%x]", dm_device_type, dm_device_direction);
-                        if (skip_usb_device(data->stream_role, device))
-                            continue;
-                        use_internal_codec = pa_tz_device_is_use_internal_codec(device);
-                        if (use_internal_codec) {
-                            /* if it needs to skip it, keep going to next device for proper UCM setting */
-                            if (skip_device(data->stream_role, dm_device_type))
-                                continue;
-                            if (skip_bt_sco_device(u, data->stream_role, dm_device_type))
-                                continue;
-                            fill_device_info(&route_info, dm_device_type, CONVERT_TO_HAL_DIRECTION(data->stream_type), dm_device_id);
-                        } else
-                            pa_log_debug("  -- it does not use internal audio codec, skip it");
-                        break;
-                    }
-                }
-                if (device == NULL)
-                    continue;
-
-                if (data->route_type == STREAM_ROUTE_TYPE_AUTO) {
-                    if (data->origins_from_new_data)
-                        pa_proplist_sets(GET_STREAM_NEW_PROPLIST(data->stream, data->stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
-                    else
-                        pa_proplist_sets(GET_STREAM_PROPLIST(data->stream, data->stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
-
-                    /* unload combine sink */
-                    if (data->stream_type == STREAM_SINK_INPUT) {
-                        if ((sink = pa_tz_device_get_sink(device, data->device_role)))
-                            unload_combine_sink_module(u, SINK_NAME_COMBINED, sink);
-                        else
-                            pa_log_error("[ROUTE][AUTO] could not get sink");
-                    }
-
-                    if (pa_safe_streq(dm_device_type, DEVICE_TYPE_BT_SCO)) {
-                        if (IS_ROLE_AVAILABLE_BT_SCO_OPEN(route_info.role)) {
-                            if (update_bt_sco_state(u, true, false, route_info.role)) {
-                                pa_log_error("  ** could not open BT SCO");
-                                return PA_HOOK_CANCEL;
-                            }
-                            update_bt_sco_option(u, route_info.role);
-                        }
-                    } else {
-                        update_bt_sco_state(u, false, false, NULL);
-                    }
-
-                    break;
-                } else if (data->route_type == STREAM_ROUTE_TYPE_AUTO_ALL) {
-                    uint32_t s_idx = 0;
-                    void *s = NULL;
-
-                    update_bt_sco_state(u, false, false, NULL);
-
-                    /* find the proper sink/source */
-                    /* currently, we support two sinks for combining */
-                    if (data->stream_type == STREAM_SINK_INPUT && u->module_combine_sink) {
-                        sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK);
-                        pa_log_info("[ROUTE][AUTO_ALL] found the combine_sink already existed");
-                    } else if (data->stream_type == STREAM_SINK_INPUT && !combine_sink_arg1) {
-                        sink = combine_sink_arg1 = pa_tz_device_get_sink(device, data->device_role);
-                        if (sink)
-                            pa_log_info("[ROUTE][AUTO_ALL] combine_sink_arg1[%s], combine_sink_arg2[%p]", sink->name, combine_sink_arg2);
-                        else
-                            pa_log_error("[ROUTE][AUTO_ALL] could not get sink from pa_device_manager_get_sink");
-                    } else if (data->stream_type == STREAM_SINK_INPUT && !combine_sink_arg2) {
-                        sink = combine_sink_arg2 = pa_tz_device_get_sink(device, data->device_role);
-                        if (sink && !pa_safe_streq(sink->name, combine_sink_arg1->name)) {
-                            pa_log_info("[ROUTE][AUTO_ALL] combine_sink_arg2[%s]", sink->name);
-                            /* load combine sink */
-                            if (!u->module_combine_sink) {
-                                char *args = pa_sprintf_malloc("sink_name=%s slaves=\"%s,%s\"", SINK_NAME_COMBINED, combine_sink_arg1->name, combine_sink_arg2->name);
-                                pa_log_info("[ROUTE][AUTO_ALL] combined sink is not prepared, now load module[%s]", args);
-                                u->module_combine_sink = pa_module_load(u->core, MODULE_COMBINE_SINK, args);
-                                pa_xfree(args);
-                            }
-                            if ((sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK))) {
-                                PA_IDXSET_FOREACH(s, combine_sink_arg1->inputs, s_idx) {
-                                    if (s == data->stream) {
-                                        pa_sink_input_move_to(s, sink, false);
-                                        pa_log_info("[ROUTE][AUTO_ALL] *** sink-nput(%p,%u) moves to sink(%p,%s)",
-                                                     s, ((pa_sink_input*)s)->index, sink, sink->name);
-                                    }
-                                }
-                            } else
-                                pa_log_error("[ROUTE][AUTO_ALL] could not get combine_sink");
-                        }
-                    } else if (data->stream_type == STREAM_SOURCE_OUTPUT)
-                        source = pa_tz_device_get_source(device, data->device_role);
+            if ((result = handle_auto_or_auto_all_routing(u, data, &route_info, conn_devices, &device)))
+                return result;
 
-                    if (data->origins_from_new_data) {
-                        if (data->stream_type == STREAM_SINK_INPUT)
-                            *(data->proper_sink) = sink;
-                        else
-                            *(data->proper_source) = source;
-                    } else {
-                        /* move sink-inputs/source-outputs if needed */
-                        if (!data->idx_streams)
-                            continue;
-                        PA_IDXSET_FOREACH(s, data->idx_streams, s_idx) { /* data->idx_streams: null_sink */
-                            if (pa_stream_manager_get_route_type(s, data->stream_type, false, &route_type))
-                                continue;
-                            if (route_type != STREAM_ROUTE_TYPE_AUTO_ALL)
-                                continue;
-                            if ((data->stream_type == STREAM_SINK_INPUT) && (sink && (sink != ((pa_sink_input*)s)->sink))) {
-                                pa_sink_input_move_to(s, sink, false);
-                                pa_log_info("[ROUTE][AUTO_ALL] *** sink-input(%p,%u) moves to sink(%p,%s)",
-                                            s, ((pa_sink_input*)s)->index, sink, sink->name);
-                            } else if ((data->stream_type == STREAM_SOURCE_OUTPUT) && (source && (source != ((pa_source_output*)s)->source))) {
-                                pa_source_output_move_to(s, source, false);
-                                pa_log_info("[ROUTE][AUTO_ALL] *** source-output(%p,%u) moves to source(%p,%s)",
-                                            s, ((pa_source_output*)s)->index, source, source->name);
-                            }
-                        }
-                    }
-                }
-            }
         } else if (data->route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
-            pa_tz_device *latest_device = NULL;
-            const char *latest_device_type = NULL;
-            pa_usec_t creation_time = 0;
-            pa_usec_t latest_creation_time = 0;
-
-            PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
-                pa_log_debug("[ROUTE][AUTO_LAST_CONN] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, data->stream_role, device_type);
-                if (!is_cached_device_connected(device_type, data->stream_type))
-                    continue;
-                PA_IDXSET_FOREACH(device, conn_devices, conn_idx) {
-                    dm_device_type = pa_tz_device_get_type(device);
-                    dm_device_direction = pa_tz_device_get_direction(device);
-                    dm_device_id = pa_tz_device_get_id(device);
-                    creation_time = pa_tz_device_get_creation_time(device);
-                    pa_log_debug("  -- type[%-16s], direction[0x%x], id[%u], creation_time[%llu]",
-                                 dm_device_type, dm_device_direction, dm_device_id, creation_time);
-                    if (pa_safe_streq(device_type, dm_device_type) && IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
-                        if (skip_usb_device(data->stream_role, device))
-                            continue;
-                        use_internal_codec = pa_tz_device_is_use_internal_codec(device);
-                        if (use_internal_codec) {
-                            /* if it needs to skip it, keep going to next device for proper UCM setting */
-                            if (skip_device(data->stream_role, dm_device_type))
-                                continue;
-                            if (skip_bt_sco_device(u, data->stream_role, dm_device_type))
-                                continue;
-                        }
-                        if (!latest_device || (latest_creation_time <= creation_time)) {
-                            if (device_type_is_builtin(dm_device_type) && pa_safe_streq(latest_device_type, dm_device_type)) {
-                                if (data->stream_type == STREAM_SINK_INPUT ?
-                                                                (void*)pa_tz_device_get_sink(latest_device, data->device_role) :
-                                                                (void*)pa_tz_device_get_source(latest_device, data->device_role))
-                                    continue;
-                            }
-                            latest_device = device;
-                            latest_creation_time = creation_time;
-                            latest_device_type = dm_device_type;
-                            pa_log_info("  ** updated the last connected device: type[%-16s], direction[0x%x]", dm_device_type, dm_device_direction);
-                        }
-                    }
-                }
-            }
-            /* update activated device if it is found */
-            if (latest_device) {
-                dm_device_type = pa_tz_device_get_type(latest_device);
-                dm_device_id = pa_tz_device_get_id(latest_device);
-                use_internal_codec = pa_tz_device_is_use_internal_codec(latest_device);
-                if (use_internal_codec)
-                    fill_device_info(&route_info, dm_device_type, CONVERT_TO_HAL_DIRECTION(data->stream_type), dm_device_id);
-                else
-                    pa_log_debug("  -- it does not use internal audio codec, skip it");
-
-                if (data->origins_from_new_data)
-                    pa_proplist_sets(GET_STREAM_NEW_PROPLIST(data->stream, data->stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
-                else
-                    pa_proplist_sets(GET_STREAM_PROPLIST(data->stream, data->stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
-
-                /* unload combine sink */
-                if (data->stream_type == STREAM_SINK_INPUT) {
-                    if ((sink = pa_tz_device_get_sink(latest_device, data->device_role)))
-                        unload_combine_sink_module(u, SINK_NAME_COMBINED, sink);
-                    else
-                        pa_log_error("[ROUTE][AUTO_LAST_CONN] could not get sink");
-                }
-
-                if (pa_safe_streq(dm_device_type, DEVICE_TYPE_BT_SCO)) {
-                    if (IS_ROLE_AVAILABLE_BT_SCO_OPEN(route_info.role)) {
-                        if (update_bt_sco_state(u, true, false, route_info.role)) {
-                            pa_log_error("  ** could not open BT SCO");
-                            return PA_HOOK_CANCEL;
-                        }
-                        update_bt_sco_option(u, route_info.role);
-                    }
-                } else {
-                    update_bt_sco_state(u, false, false, NULL);
-                }
-
-                /* Update device with latest_device to use be used later in this function */
-                device = latest_device;
-            }
+            if ((result = handle_auto_last_connected_routing(u, data, &route_info, conn_devices, &device)))
+                return result;
         }
 
     } else if (data->route_type == STREAM_ROUTE_TYPE_MANUAL) {
-        uint32_t d_idx = 0;
-
-        PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
-            pa_log_info("[ROUTE][MANUAL] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, data->stream_role, device_type);
-            if (!is_cached_device_connected(device_type, data->stream_type))
-                continue;
-            PA_IDXSET_FOREACH(device_id, data->idx_manual_devices, d_idx) {
-                pa_log_debug("  -- manual_device[%u] for this role[%-16s]: device_id(%u)", idx, data->stream_role, *device_id);
-                if (!(device = pa_device_manager_get_device_by_id(u->device_manager, *device_id)))
-                    continue;
-                dm_device_type = pa_tz_device_get_type(device);
-                if (!pa_safe_streq(device_type, dm_device_type))
-                    continue;
-                dm_device_direction = pa_tz_device_get_direction(device);
-                pa_log_debug("  ** found a matched device: type[%-16s], direction[0x%x]",
-                             dm_device_type, dm_device_direction);
-                /* Check for availability for opening Bluetooth SCO */
-                if (pa_safe_streq(dm_device_type, DEVICE_TYPE_BT_SCO) && IS_ROLE_AVAILABLE_BT_SCO_OPEN(route_info.role)) {
-                    /* update BT SCO: open */
-                    if (update_bt_sco_state(u, true, false, route_info.role)) {
-                        pa_log_error("  ** could not open BT SCO");
-                        return PA_HOOK_CANCEL;
-                    }
-                    update_bt_sco_option(u, route_info.role);
-                } else {
-                    /* update BT SCO: close */
-                    update_bt_sco_state(u, false, false, NULL);
-                }
-                /* Check for in/out devices in case of loopback */
-                if (pa_safe_streq(data->stream_role, STREAM_ROLE_LOOPBACK)) {
-                    if ((data->stream_type == STREAM_SINK_INPUT) && (dm_device_direction & DM_DEVICE_DIRECTION_OUT))
-                        u->loopback_args.sink = pa_tz_device_get_sink(device, NULL);
-                    else if ((data->stream_type == STREAM_SOURCE_OUTPUT) && (dm_device_direction & DM_DEVICE_DIRECTION_IN))
-                        u->loopback_args.source = pa_tz_device_get_source(device, NULL);
-                }
-
-                if (IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
-                    use_internal_codec = pa_tz_device_is_use_internal_codec(device);
-                    if (use_internal_codec)
-                        fill_device_info(&route_info, dm_device_type, CONVERT_TO_HAL_DIRECTION(data->stream_type), *device_id);
-                    else
-                        pa_log_debug("  -- it does not use internal audio codec, skip it");
-                }
-            }
-        }
-        if (pa_safe_streq(data->stream_role, STREAM_ROLE_LOOPBACK)) {
-            /* load module-loopback */
-            if (u->loopback_args.sink && u->loopback_args.source)
-                update_loopback_module(u, true);
-        }
+        if ((result = handle_manual_routing(u, data, &route_info, &device)))
+            return result;
     }
 
     route_change_move_streams(u, data, device);