stream-manager: Add support for filter modules for compatibility with tizen routing... 65/137265/6
authorSangchul Lee <sc11.lee@samsung.com>
Wed, 5 Jul 2017 05:29:12 +0000 (14:29 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Thu, 6 Jul 2017 03:17:01 +0000 (12:17 +0900)
Now it considers streams using filter modules in terms of audio routing
so that these streams can sound out properly according to device connecetion changes.

[Version] 5.0.158
[Issue Type] Enhancement

Change-Id: I5ebf3a101646d111ee22678c6c494e78f9f33ea6
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
packaging/pulseaudio-modules-tizen.spec
src/module-tizenaudio-policy.c
src/stream-manager-dbus.c
src/stream-manager-filter-priv.h
src/stream-manager-filter.c
src/stream-manager.c
src/stream-manager.h

index e5b555a5598f742dafe6c1d27860074decb3df48..618ed88519aa0c1084270bf64032ab20ddbdc39f 100644 (file)
@@ -1,6 +1,6 @@
 Name:             pulseaudio-modules-tizen
 Summary:          Pulseaudio modules for Tizen
-Version:          5.0.157
+Version:          5.0.158
 Release:          0
 Group:            Multimedia/Audio
 License:          LGPL-2.1+
index ae0e44bb2ce880688c9d80390c1531f58bf81826..209ae2dc5f20f72a5364144bd80efba3e5232abe 100644 (file)
@@ -487,8 +487,10 @@ static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stre
                         } else
                             *(data->proper_source) = pa_tz_device_get_source(device, data->device_role);
 
-                        if (data->route_type == STREAM_ROUTE_TYPE_AUTO)
+                        if (data->route_type == STREAM_ROUTE_TYPE_AUTO) {
+                            pa_proplist_sets(GET_STREAM_NEW_PROPLIST(data->stream, data->stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
                             return PA_HOOK_OK;
+                        }
                     }
                 }
             }
@@ -788,6 +790,8 @@ static void route_change_rollback_streams(struct userdata *u, pa_stream_manager_
             if (((combine_sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK)) &&
                 ((pa_sink_input*)s)->sink == combine_sink))
                 break;
+            if ((pa_stream_manager_check_filter_apply_stream(s, STREAM_SINK_INPUT)))
+                continue;
             pa_sink_input_move_to(s, sink, false);
             pa_log_info("[ROUTE][ROLLBACK] *** sink-input(%p,%u) moves to sink(%p,%s)",
                          s, ((pa_sink_input*)s)->index, sink, sink->name);
index d96a9ea876ce67c0f8044d931f972ad5c6d17c06..06569a62aa80ca4f03b3eb8d1ff15b13fd514c59 100644 (file)
@@ -113,11 +113,11 @@ static pa_dbus_arg_info update_focus_status_by_focus_id_args[]  = { { "focus_id"
 static pa_dbus_arg_info update_restriction_args[]  = { { "name", "s", "in" },
                                                       { "value", "u", "in" },
                                                  { "ret_msg", "s", "out" } };
-static pa_dbus_arg_info set_filter_args[] =     { { "filter_name",       "s",  "in" },
-                                                  { "filter_parameters", "s",  "in" },
-                                                  { "filter_group",      "s",  "in" },
-                                                  { "stream_type",       "s",  "in" },
-                                                { "ret_msg",           "s", "out" } };
+static pa_dbus_arg_info set_filter_args[] = { { "filter_name",       "s",  "in" },
+                                              { "filter_parameters", "s",  "in" },
+                                              { "filter_group",      "s",  "in" },
+                                              { "stream_type",       "s",  "in" },
+                                            { "ret_msg",           "s", "out" } };
 static pa_dbus_arg_info unset_filter_args[] =   { { "stream_type",       "s",  "in" },
                                                 { "ret_msg",           "s", "out" } };
 static pa_dbus_arg_info control_filter_args[] = { { "filter_name",       "s",  "in" },
index 5aef1b225a6de88e8fb9691602a5a78828aca548..94c2403dd7abcc66ccc3a0fc8d51ca0e80971d6a 100644 (file)
@@ -29,6 +29,7 @@ int32_t update_filter(pa_stream_manager *m, const char *filter_name, const char
                       const char *stream_type);
 int32_t control_filter(pa_stream_manager *m, const char *filter_name, const char *filter_controls, const char *stream_type,
                        DBusConnection *conn);
+int32_t reload_filter(pa_stream_manager *m, const char *stream_role, pa_sink *new_master_sink);
 void init_filters(pa_stream_manager *m);
 void deinit_filters(pa_stream_manager *m);
 
index 9959e2e365a1b8cf2e2297111a72c0709360b072..e8a447ed03c7b0a17692d3fbe82573335dcc7b3a 100644 (file)
@@ -328,6 +328,101 @@ int32_t control_filter(pa_stream_manager *m, const char *filter_name, const char
     return 0;
 }
 
+static pa_sink* get_master_sink_of_filter(pa_stream_manager *m, const char *filter_name, const char *filter_group) {
+    pa_sink_input *i;
+    pa_sink *master_sink;
+    uint32_t idx;
+    const char *role = NULL;
+    const char *filter_apply = NULL;
+
+    pa_assert(m);
+    pa_assert(filter_name);
+    pa_assert(filter_group);
+
+    /* We can not find sink_master directly only with module_name and stream_role,
+     * therefore, we use sink-input information instead of it */
+    PA_IDXSET_FOREACH(i, m->core->sink_inputs, idx) {
+        role = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_ROLE);
+        filter_apply = pa_proplist_gets(i->proplist, PA_PROP_FILTER_APPLY);
+        if (pa_safe_streq(filter_name, filter_apply) && pa_safe_streq(role, filter_group)) {
+            if ((master_sink = pa_sink_get_master(i->sink))) {
+                pa_log_info("Found master sink name[%s] of [module-%s, filter_group:%s]",
+                            master_sink->name, filter_name, filter_group);
+                return master_sink;
+            } else
+                continue;
+        }
+    }
+    pa_log_error("Failed to get master sink of [module-%s, filter_group:%s]", filter_name, filter_group);
+
+    return NULL;
+}
+
+int32_t reload_filter(pa_stream_manager *m, const char *stream_role, pa_sink *new_master_sink) {
+    filter_info *f = NULL;
+    const char *filter_name = NULL;
+    const char *filter_params = NULL;
+    const char *filter_group = NULL;
+    const char *role = NULL;
+    pa_sink *prev_master_sink = NULL;
+    pa_sink_input *i;
+    uint32_t idx;
+    int ret = 0;
+
+    pa_assert(m);
+    pa_assert(stream_role);
+    pa_assert(new_master_sink);
+
+    if (!(f = pa_hashmap_get(m->filter_infos, stream_role))) {
+        pa_log_error("could not find any filter info for [%s]", stream_role);
+        return -1;
+    }
+
+    filter_name = pa_xstrdup(f->filter_apply);
+    filter_params = pa_xstrdup(f->parameters);
+    filter_group = pa_xstrdup(f->group);
+    pa_log_debug("found filter: name[%s], params[%s], group[%s] for [%s]", filter_name, filter_params, filter_group, stream_role);
+
+    if (!(prev_master_sink = get_master_sink_of_filter(m, filter_name, filter_group))) {
+        ret = -1;
+        goto leave;
+    }
+
+    if (prev_master_sink == new_master_sink) {
+        pa_log_info("master sink is same as before, [%s], skip it", new_master_sink->name);
+        ret = 0;
+        goto leave;
+    }
+
+    if (update_filter(m, NULL, NULL, NULL, stream_role)) {
+        pa_log_error("failed to update filter to unload,");
+        ret = -1;
+        goto leave;
+    }
+
+    /* move all streams belongs to stream_role */
+    PA_IDXSET_FOREACH(i, prev_master_sink->inputs, idx) {
+        role = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_ROLE);
+        if (pa_safe_streq(role, stream_role))
+            pa_sink_input_move_to(i, new_master_sink, false);
+    }
+
+    pa_log_info("name:%s, params:%s, group:%s", filter_name, filter_params, filter_group);
+    if (update_filter(m, filter_name, filter_params, filter_group, stream_role)) {
+        pa_log_error("failed to update filter to load");
+        ret = -1;
+        goto leave;
+    }
+    pa_log_info("reload filter successfully for [stream_role:%s, sink:%s]", stream_role, new_master_sink->name);
+
+leave:
+    pa_xfree((void*)filter_name);
+    pa_xfree((void*)filter_params);
+    pa_xfree((void*)filter_group);
+
+    return ret;
+}
+
 static void filter_info_key_free_cb(char *key) {
     pa_xfree(key);
 }
@@ -360,8 +455,10 @@ void init_filters(pa_stream_manager *m) {
         }
     }
     if (!module) {
-        pa_module_load(m->core, MODULE_FILTER_APPLY, NULL);
+        char *args = pa_sprintf_malloc("autoclean_interval=%d", 0);
+        pa_module_load(m->core, MODULE_FILTER_APPLY, args);
         pa_log("module-filter-apply loaded");
+        pa_xfree(args);
     }
 }
 
index 5b5112cf414b5ce948812e6ef2965e02d5caa126..2a97e1b7a97a77a823e35a8cb2772dd4a417f8df 100644 (file)
@@ -2478,8 +2478,88 @@ static void process_stream_as_device_change_for_auto_route(pa_stream_manager *m,
     }
 }
 
-static void update_sink_or_source_as_device_change(stream_route_type_t stream_route_type, pa_idxset *streams,
-                                                   stream_type_t stream_type, pa_tz_device *device, bool is_connected, pa_stream_manager *m) {
+static bool is_filter_apply_stream(void *s, stream_type_t stream_type) {
+    const char *filter_apply = NULL;
+
+    pa_assert(s);
+
+    if ((filter_apply = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_FILTER_APPLY))) {
+        pa_log_info("stream index(%u) is for filter.apply(%s)", GET_STREAM_INDEX(s, stream_type), filter_apply);
+        return true;
+    }
+    return false;
+}
+
+static bool manage_filter_apply_stream(pa_stream_manager *m, pa_sink_input *si, pa_tz_device *device, bool is_connected) {
+    stream_route_type_t route_type;
+
+    pa_assert(m);
+    pa_assert(si);
+    pa_assert(device);
+
+    if (get_route_type(si, STREAM_SINK_INPUT, false, &route_type))
+        return false;
+    if (route_type != STREAM_ROUTE_TYPE_AUTO && route_type != STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED)
+        return false;
+
+    if (is_filter_apply_stream(si, STREAM_SINK_INPUT)) {
+        const char *stream_role = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROLE);
+        const char *cur_device_type = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
+        char *device_type = pa_tz_device_get_type(device);
+        pa_tz_device *cur_device = pa_device_manager_get_device(m->dm, cur_device_type);
+        pa_sink *sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL);
+
+        if (is_connected) {
+            bool available = false;
+            pa_sink *cur_sink = pa_tz_device_get_sink(cur_device, DEVICE_ROLE_NORMAL);
+            if (cur_sink == sink)
+                return true;
+
+            is_available_device_for_auto_route(m, route_type, cur_device_type, device_type,
+                                               stream_role, STREAM_SINK_INPUT, &available);
+            if (available) {
+                if (!reload_filter(m, stream_role, sink)) {
+                    pa_proplist_sets(si->proplist, PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, device_type);
+                    pa_log_info("[%s] is CONNECTED and will be set for the next device", device_type);
+                    process_stream_as_device_change_for_auto_route(m, si, STREAM_SINK_INPUT, is_connected, device);
+                } else
+                    pa_log_error("failed to reload filter");
+            }
+        } else {
+            pa_tz_device *next_device = NULL;
+            char *new_device_type = NULL;
+            pa_sink *cur_sink = NULL;
+
+            if (cur_device)
+                cur_sink = pa_tz_device_get_sink(cur_device, DEVICE_ROLE_NORMAL);
+            if (cur_sink && (cur_sink != sink))
+                return true;
+
+            if (is_active_device_of_stream(si, STREAM_SINK_INPUT, device_type)) {
+                pa_sink *next_sink = NULL;
+                find_next_device_for_auto_route(m, route_type, stream_role, STREAM_SINK_INPUT, cur_device_type, &next_device);
+                if (!next_device) {
+                    pa_log_error("failed to get next_device");
+                    return true;
+                }
+                next_sink = pa_tz_device_get_sink(next_device, DEVICE_ROLE_NORMAL);
+                if (!reload_filter(m, stream_role, next_sink)) {
+                    new_device_type = pa_tz_device_get_type(next_device);
+                    pa_proplist_sets(si->proplist, PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, new_device_type);
+                    pa_log_info("[%s] is DISCONNECTED and [%s] will be set for the next device", device_type, new_device_type);
+                    process_stream_as_device_change_for_auto_route(m, si, STREAM_SINK_INPUT, is_connected, next_device);
+                } else
+                    pa_log_error("failed to reload filter");
+            }
+        }
+        return true;
+    }
+
+    return false;
+}
+
+static void update_sink_or_source_as_device_change(pa_stream_manager *m, stream_route_type_t stream_route_type, pa_idxset *streams,
+                                                   stream_type_t stream_type, pa_tz_device *device, bool is_connected) {
     #define MAX_CACHED_LEN 128
     typedef struct _cached_device_list {
         const char *device_type;
@@ -2504,9 +2584,9 @@ static void update_sink_or_source_as_device_change(stream_route_type_t stream_ro
     uint32_t cnt = 0;
     pa_sink *combine_sink = NULL;
 
+    pa_assert(m);
     pa_assert(streams);
     pa_assert(device);
-    pa_assert(m);
 
     null_sink = (pa_sink*)pa_namereg_get(m->core, SINK_NAME_NULL, PA_NAMEREG_SINK);
     null_source = (pa_source*)pa_namereg_get(m->core, SOURCE_NAME_NULL, PA_NAMEREG_SOURCE);
@@ -2529,6 +2609,9 @@ static void update_sink_or_source_as_device_change(stream_route_type_t stream_ro
                 continue;
             if (route_type != stream_route_type)
                 continue;
+            if (stream_type == STREAM_SINK_INPUT && manage_filter_apply_stream(m, s, device, is_connected))
+                continue;
+
             role = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROLE);
             pa_log_debug("  -- idx(%u), route_type(%d), role(%s)", s_idx, route_type, role);
             if (is_connected) {
@@ -2792,11 +2875,7 @@ static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_tz_devi
     uint32_t device_id = 0;
     pa_sink *sink = NULL;
     pa_source *source = NULL;
-
     pa_sink_input *si = NULL;
-    uint32_t si_idx = 0;
-    const char *media_role = NULL;
-    hal_route_option route_option;
 
     pa_assert(c);
     pa_assert(data);
@@ -2812,6 +2891,9 @@ static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_tz_devi
 
     /* mute all the streams belong to this device, those will be un-muted in event_fully_handled_hook_cb */
     if (!data->is_connected && (device_direction & DM_DEVICE_DIRECTION_OUT)) {
+        const char *media_role = NULL;
+        hal_route_option route_option;
+
         if ((sink = pa_tz_device_get_sink(data->device, DEVICE_ROLE_NORMAL))) {
             pa_idxset *filtered_streams = get_streams_for_matching_active_device(sink->inputs, device_type);
             mute_sink_inputs_as_device_disconnection(m, data->event_id, true, filtered_streams);
@@ -2821,7 +2903,7 @@ static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_tz_devi
         /* If Earjack is disconnected, search for sink-input which has radio role,
            if found, let radio mute to avoid intermediate noise */
         if (pa_safe_streq(device_type, DEVICE_TYPE_AUDIO_JACK)) {
-            PA_IDXSET_FOREACH(si, c->sink_inputs, si_idx) {
+            PA_IDXSET_FOREACH(si, c->sink_inputs, s_idx) {
                 media_role = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROLE);
                 if (pa_safe_streq(media_role, STREAM_ROLE_RADIO)) {
                     pa_log_info(" sink-input(%d) is radio, let HAL mute for disconnect of earjack", si->index);
@@ -2836,86 +2918,78 @@ static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_tz_devi
     }
 
     /* Update streams belong to this external device that have MAUAL_EXT route type */
-    if (!use_internal_codec && (device_direction & DM_DEVICE_DIRECTION_IN)) {
-        if ((source = pa_tz_device_get_source(data->device, DEVICE_ROLE_NORMAL)))
-            update_sink_or_source_as_device_change(STREAM_ROUTE_TYPE_MANUAL_EXT, source->outputs,
-                                                   STREAM_SOURCE_OUTPUT, data->device, data->is_connected, m);
-        else
-            pa_log_error("[SM][CONN] could not get source");
-    }
-    if (!use_internal_codec && (device_direction & DM_DEVICE_DIRECTION_OUT)) {
-        if ((sink = pa_tz_device_get_sink(data->device, DEVICE_ROLE_NORMAL)))
-            update_sink_or_source_as_device_change(STREAM_ROUTE_TYPE_MANUAL_EXT, sink->inputs,
-                                                   STREAM_SINK_INPUT, data->device, data->is_connected, m);
-        else
-            pa_log_error("[SM][CONN] could not get sink");
+    if (!use_internal_codec) {
+        if (device_direction & DM_DEVICE_DIRECTION_IN) {
+            if ((source = pa_tz_device_get_source(data->device, DEVICE_ROLE_NORMAL)))
+                update_sink_or_source_as_device_change(m, STREAM_ROUTE_TYPE_MANUAL_EXT, source->outputs,
+                                                       STREAM_SOURCE_OUTPUT, data->device, data->is_connected);
+        }
+        if (device_direction & DM_DEVICE_DIRECTION_OUT) {
+            if ((sink = pa_tz_device_get_sink(data->device, DEVICE_ROLE_NORMAL)))
+                update_sink_or_source_as_device_change(m, STREAM_ROUTE_TYPE_MANUAL_EXT, sink->inputs,
+                                                       STREAM_SINK_INPUT, data->device, data->is_connected);
+        }
     }
 
     /* Update all the streams that have AUTO route type */
     if (device_direction & DM_DEVICE_DIRECTION_IN) {
-        update_sink_or_source_as_device_change(STREAM_ROUTE_TYPE_AUTO, m->core->source_outputs,
-                                               STREAM_SOURCE_OUTPUT, data->device, data->is_connected, m);
-        update_sink_or_source_as_device_change(STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED, m->core->source_outputs,
-                                               STREAM_SOURCE_OUTPUT, data->device, data->is_connected, m);
+        update_sink_or_source_as_device_change(m, STREAM_ROUTE_TYPE_AUTO, m->core->source_outputs,
+                                               STREAM_SOURCE_OUTPUT, data->device, data->is_connected);
+        update_sink_or_source_as_device_change(m, STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED, m->core->source_outputs,
+                                               STREAM_SOURCE_OUTPUT, data->device, data->is_connected);
     }
     if (device_direction & DM_DEVICE_DIRECTION_OUT) {
-        update_sink_or_source_as_device_change(STREAM_ROUTE_TYPE_AUTO, m->core->sink_inputs,
-                                               STREAM_SINK_INPUT, data->device, data->is_connected, m);
-        update_sink_or_source_as_device_change(STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED, m->core->sink_inputs,
-                                               STREAM_SINK_INPUT, data->device, data->is_connected, m);
-    }
-
-
-    /* If the route type of the stream is not manual, notify again */
-    if (m->cur_highest_priority.source_output && (device_direction & DM_DEVICE_DIRECTION_IN)) {
-        if (!get_route_type(m->cur_highest_priority.source_output, STREAM_SOURCE_OUTPUT, false, &route_type)) {
-            if (route_type != STREAM_ROUTE_TYPE_MANUAL && route_type != STREAM_ROUTE_TYPE_MANUAL_EXT) {
-                if (use_internal_codec) {
-                    PA_IDXSET_FOREACH(s, m->cur_highest_priority.source_output->source->outputs, s_idx) {
-                        if (!data->is_connected && !get_route_type(s, STREAM_SOURCE_OUTPUT, false, &route_type) &&
-                            ((route_type == STREAM_ROUTE_TYPE_AUTO) || (route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED))) {
-                            /* remove activated device info. if it has the AUTO route type */
-                            active_dev = pa_proplist_gets(GET_STREAM_PROPLIST(s, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
-                            if (pa_safe_streq(active_dev, device_type))
-                                pa_proplist_sets(GET_STREAM_PROPLIST(s, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, ACTIVE_DEV_REMOVED);
-                        }
-                    }
-                    do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SOURCE_OUTPUT, false, m->cur_highest_priority.source_output);
-                    if (!((pa_source_output*)(m->cur_highest_priority.source_output))->source->use_internal_codec) {
-                        /* If the source of the cur_highest_priority stream uses external codec, it should be updated.
-                         * As only the process_stream(PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED)
-                         * can update the cur_highest_priority, call it here */
-                        process_stream(m, m->cur_highest_priority.source_output, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
-                    }
+        update_sink_or_source_as_device_change(m, STREAM_ROUTE_TYPE_AUTO, m->core->sink_inputs,
+                                               STREAM_SINK_INPUT, data->device, data->is_connected);
+        update_sink_or_source_as_device_change(m, STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED, m->core->sink_inputs,
+                                               STREAM_SINK_INPUT, data->device, data->is_connected);
+    }
+
+    /* If the route type is AUTO SERIES, notify again */
+    if ((device_direction & DM_DEVICE_DIRECTION_IN) && m->cur_highest_priority.source_output &&
+        !get_route_type(m->cur_highest_priority.source_output, STREAM_SOURCE_OUTPUT, false, &route_type)) {
+        if (IS_AUTO_ROUTE_TYPE_SERIES(route_type) && use_internal_codec) {
+            PA_IDXSET_FOREACH(s, m->cur_highest_priority.source_output->source->outputs, s_idx) {
+                if (!data->is_connected && !get_route_type(s, STREAM_SOURCE_OUTPUT, false, &route_type) &&
+                    ((route_type == STREAM_ROUTE_TYPE_AUTO) || (route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED))) {
+                    /* remove activated device info. if it has the AUTO route type */
+                    active_dev = pa_proplist_gets(GET_STREAM_PROPLIST(s, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
+                    if (pa_safe_streq(active_dev, device_type))
+                        pa_proplist_sets(GET_STREAM_PROPLIST(s, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, ACTIVE_DEV_REMOVED);
                 }
             }
+            do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SOURCE_OUTPUT, false, m->cur_highest_priority.source_output);
+            if (!((pa_source_output*)(m->cur_highest_priority.source_output))->source->use_internal_codec) {
+                /* If the source of the cur_highest_priority stream uses external codec, it should be updated.
+                 * As only the process_stream(PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED)
+                 * can update the cur_highest_priority, call it here */
+                process_stream(m, m->cur_highest_priority.source_output, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
+            }
         }
     }
-    if (m->cur_highest_priority.sink_input && (device_direction & DM_DEVICE_DIRECTION_OUT)) {
-        if (!get_route_type(m->cur_highest_priority.sink_input, STREAM_SINK_INPUT, false, &route_type)) {
-            if (route_type != STREAM_ROUTE_TYPE_MANUAL && route_type != STREAM_ROUTE_TYPE_MANUAL_EXT) {
-                if (use_internal_codec) {
-                    PA_IDXSET_FOREACH(s, m->cur_highest_priority.sink_input->sink->inputs, s_idx) {
-                        if (!data->is_connected && !get_route_type(s, STREAM_SINK_INPUT, false, &route_type) &&
-                            ((route_type == STREAM_ROUTE_TYPE_AUTO) || (route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED))) {
-                            /* remove activated device info. if it has the AUTO route type */
-                            active_dev = pa_proplist_gets(GET_STREAM_PROPLIST(s, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
-                            if (pa_safe_streq(active_dev, device_type))
-                                pa_proplist_sets(GET_STREAM_PROPLIST(s, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, ACTIVE_DEV_REMOVED);
-                        }
-                    }
-                    do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SINK_INPUT, false, m->cur_highest_priority.sink_input);
-                    if (((route_type == STREAM_ROUTE_TYPE_AUTO) || (route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED)) &&
-                       !((pa_sink_input*)(m->cur_highest_priority.sink_input))->sink->use_internal_codec) {
-                        /* If the sink of the cur_highest_priority stream uses external codec, it should be updated.
-                         * As only the process_stream(PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED)
-                         * can update the cur_highest_priority, call it here */
-                        process_stream(m, m->cur_highest_priority.sink_input, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
-                    }
-                } else if (route_type == STREAM_ROUTE_TYPE_AUTO_ALL)
-                    do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SINK_INPUT, false, m->cur_highest_priority.sink_input);
+
+    if ((device_direction & DM_DEVICE_DIRECTION_OUT) && m->cur_highest_priority.sink_input &&
+        !get_route_type(m->cur_highest_priority.sink_input, STREAM_SINK_INPUT, false, &route_type)) {
+        if (IS_AUTO_ROUTE_TYPE_SERIES(route_type) && use_internal_codec) {
+            PA_IDXSET_FOREACH(s, m->cur_highest_priority.sink_input->sink->inputs, s_idx) {
+                if (!data->is_connected && !get_route_type(s, STREAM_SINK_INPUT, false, &route_type) &&
+                    ((route_type == STREAM_ROUTE_TYPE_AUTO) || (route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED))) {
+                    /* remove activated device info. if it has the AUTO route type */
+                    active_dev = pa_proplist_gets(GET_STREAM_PROPLIST(s, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
+                    if (pa_safe_streq(active_dev, device_type))
+                        pa_proplist_sets(GET_STREAM_PROPLIST(s, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, ACTIVE_DEV_REMOVED);
+                }
             }
-        }
+            do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SINK_INPUT, false, m->cur_highest_priority.sink_input);
+            if (((route_type == STREAM_ROUTE_TYPE_AUTO) || (route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED)) &&
+               (!((pa_sink_input*)(m->cur_highest_priority.sink_input))->sink->use_internal_codec) && !is_filter_apply_stream(m->cur_highest_priority.sink_input, STREAM_SINK_INPUT)) {
+                /* If the sink of the cur_highest_priority stream uses external codec, it should be updated.
+                 * As only the process_stream(PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED)
+                 * can update the cur_highest_priority, call it here */
+                process_stream(m, m->cur_highest_priority.sink_input, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
+            }
+        } else if (route_type == STREAM_ROUTE_TYPE_AUTO_ALL)
+            do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SINK_INPUT, false, m->cur_highest_priority.sink_input);
     }
 
     if (m->on_call) {
@@ -3038,6 +3112,10 @@ int32_t pa_stream_manager_get_route_type(void *stream, stream_type_t stream_type
     return get_route_type(stream, stream_type, is_new_data, stream_route_type);
 }
 
+bool pa_stream_manager_check_filter_apply_stream(void *stream, stream_type_t stream_type) {
+    return is_filter_apply_stream(stream, stream_type);
+}
+
 pa_stream_manager* pa_stream_manager_init(pa_core *c) {
     pa_stream_manager *m;
 
index bdaa256d2a83949c00286caed9238f3c70174469..3e19b61e446fe574323aef5446cd7e10a23c8892 100644 (file)
@@ -136,6 +136,7 @@ typedef struct _hook_call_data_for_update_info {
 
 int32_t pa_stream_manager_get_route_type(void *stream, stream_type_t stream_type, bool is_new_data, stream_route_type_t *stream_route_type);
 bool pa_stream_manager_check_name_is_vstream(void *stream, stream_type_t type, bool is_new_data);
+bool pa_stream_manager_check_filter_apply_stream(void *stream, stream_type_t stream_type);
 
 pa_stream_manager* pa_stream_manager_init(pa_core *c);
 void pa_stream_manager_done(pa_stream_manager* m);