[pulseaudio-discuss] [PATCH v3] filter-apply: Fixed a stream moves to wrong sink(or source).

KimJeongYeon see2002 at gmail.com
Tue Apr 11 13:33:22 UTC 2017


For example, a normal stream tried to attach to filter sink(or source), which
filter loaded and managed by filter-apply. But, the stream become to attach to
the ***master sink(or source)*** of filter module due to restoring operation.
It seems should to be attached to the filter sink(or source) properly.

Signed-off-by: KimJeongYeon <jeongyeon.kim at samsung.com>
---
 src/modules/module-filter-apply.c | 103 +++++++++++++++++++++++++++++++++++---
 1 file changed, 96 insertions(+), 7 deletions(-)

diff --git a/src/modules/module-filter-apply.c b/src/modules/module-filter-apply.c
index 364d68b..07d1c52 100644
--- a/src/modules/module-filter-apply.c
+++ b/src/modules/module-filter-apply.c
@@ -54,6 +54,12 @@ static const char* const valid_modargs[] = {
 #define DEFAULT_AUTOCLEAN true
 #define HOUSEKEEPING_INTERVAL (10 * PA_USEC_PER_SEC)
 
+typedef enum _process_cmd_type {
+    PROCESS_CMD_SINK_INPUT_SOURCE_OUTPUT_PUT,
+    PROCESS_CMD_SINK_INPUT_SOURCE_OUTPUT_MOVE_FINISH,
+    PROCESS_CMD_SINK_INPUT_SOURCE_OUTPUT_PROPLIST,
+} process_cmd_type_t;
+
 struct filter {
     char *name;
     uint32_t module_index;
@@ -72,6 +78,7 @@ struct userdata {
     pa_hashmap *mdm_ignored_inputs, *mdm_ignored_outputs;
     bool autoclean;
     pa_time_event *housekeeping_time_event;
+    bool skip_prop_change;
 };
 
 static unsigned filter_hash(const void *p) {
@@ -410,7 +417,77 @@ static bool can_unload_module(struct userdata *u, uint32_t idx) {
     return true;
 }
 
-static pa_hook_result_t process(struct userdata *u, pa_object *o, bool is_sink_input) {
+static bool make_sure_filter_apply(struct userdata *u, pa_object *o, process_cmd_type_t cmd, bool is_sink_input) {
+    pa_sink *sink = NULL;
+    pa_source *source = NULL;
+    pa_proplist *pl;
+    void *state;
+    struct filter *filter;
+    bool is_attached = false;
+
+    if (is_sink_input) {
+        sink = PA_SINK_INPUT(o)->sink;
+        pl = PA_SINK_INPUT(o)->proplist;
+    } else {
+        source = PA_SOURCE_OUTPUT(o)->source;
+        pl = PA_SOURCE_OUTPUT(o)->proplist;
+    }
+
+    /* Make sure to exist of 'filter.apply' property of stream that puts or
+     * moves to filter according to request. Append the property if not exists.
+     * No action required if 'filter.apply' property exists. */
+    PA_HASHMAP_FOREACH(filter, u->filters, state) {
+        if ((is_sink_input && sink == filter->sink) || (!is_sink_input && source == filter->source)) {
+            is_attached = true;
+
+            switch (cmd) {
+                case PROCESS_CMD_SINK_INPUT_SOURCE_OUTPUT_PUT:
+                case PROCESS_CMD_SINK_INPUT_SOURCE_OUTPUT_MOVE_FINISH:
+                    if (!pa_proplist_gets(pl, PA_PROP_FILTER_APPLY))
+                        pa_proplist_sets(pl, PA_PROP_FILTER_APPLY, filter->name);
+                    break;
+                case PROCESS_CMD_SINK_INPUT_SOURCE_OUTPUT_PROPLIST:
+                    if (pa_proplist_gets(pl, PA_PROP_FILTER_APPLY) || u->skip_prop_change)
+                        goto do_nothing;
+                    /* Else, will be restore to master sink or source. */
+                    break;
+            }
+            break;
+        }
+    }
+
+    /* Make sure to remove 'filter.apply' property of stream that moved away
+     * from filter. Remove the property if exists.
+     * No action required if 'filter.apply' property not exists. */
+    if (!is_attached) {
+        switch (cmd) {
+            case PROCESS_CMD_SINK_INPUT_SOURCE_OUTPUT_PUT:
+                if (!pa_proplist_gets(pl, PA_PROP_FILTER_APPLY))
+                    goto do_nothing;
+                /* Else, will be apply filter. */
+                break;
+            case PROCESS_CMD_SINK_INPUT_SOURCE_OUTPUT_MOVE_FINISH:
+                if (pa_proplist_gets(pl, PA_PROP_FILTER_APPLY)) {
+                    pa_proplist_unset(pl, PA_PROP_FILTER_APPLY);
+                    if (pa_hashmap_size(u->filters) > 0)
+                        trigger_housekeeping(u);
+                }
+                goto do_nothing;
+            case PROCESS_CMD_SINK_INPUT_SOURCE_OUTPUT_PROPLIST:
+                if (!pa_proplist_gets(pl, PA_PROP_FILTER_APPLY) || u->skip_prop_change)
+                    goto do_nothing;
+                /* Else, will be apply filter. */
+                break;
+        }
+    }
+
+    return true;
+
+do_nothing:
+    return false;
+}
+
+static pa_hook_result_t process(struct userdata *u, pa_object *o, process_cmd_type_t cmd, bool is_sink_input) {
     const char *want;
     bool done_something = false;
     pa_sink *sink = NULL;
@@ -435,6 +512,9 @@ static pa_hook_result_t process(struct userdata *u, pa_object *o, bool is_sink_i
     if ((is_sink_input && !sink) || (!is_sink_input && !source))
         goto done;
 
+    if (!make_sure_filter_apply(u, o, cmd, is_sink_input))
+        goto done;
+
     /* If the stream doesn't what any filter, then let it be. */
     if ((want = should_filter(o, is_sink_input))) {
         /* We need to ensure the SI is playing on a sink of this type
@@ -515,7 +595,7 @@ static pa_hook_result_t sink_input_put_cb(pa_core *core, pa_sink_input *i, struc
     pa_core_assert_ref(core);
     pa_sink_input_assert_ref(i);
 
-    return process(u, PA_OBJECT(i), true);
+    return process(u, PA_OBJECT(i), PROCESS_CMD_SINK_INPUT_SOURCE_OUTPUT_PUT, true);
 }
 
 static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
@@ -525,17 +605,19 @@ static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input *
     if (pa_proplist_gets(i->proplist, PA_PROP_FILTER_APPLY_MOVING))
         return PA_HOOK_OK;
 
+    u->skip_prop_change = true;
     /* If we're managing m-d-m.auto_filtered on this, remove and re-add if we're continuing to manage it */
     pa_hashmap_remove(u->mdm_ignored_inputs, i);
+    u->skip_prop_change = false;
 
-    return process(u, PA_OBJECT(i), true);
+    return process(u, PA_OBJECT(i), PROCESS_CMD_SINK_INPUT_SOURCE_OUTPUT_MOVE_FINISH, true);
 }
 
 static pa_hook_result_t sink_input_proplist_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
     pa_core_assert_ref(core);
     pa_sink_input_assert_ref(i);
 
-    return process(u, PA_OBJECT(i), true);
+    return process(u, PA_OBJECT(i), PROCESS_CMD_SINK_INPUT_SOURCE_OUTPUT_PROPLIST, true);
 }
 
 static pa_hook_result_t sink_input_unlink_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
@@ -547,7 +629,9 @@ static pa_hook_result_t sink_input_unlink_cb(pa_core *core, pa_sink_input *i, st
     if (pa_hashmap_size(u->filters) > 0)
         trigger_housekeeping(u);
 
+    u->skip_prop_change = true;
     pa_hashmap_remove(u->mdm_ignored_inputs, i);
+    u->skip_prop_change = false;
 
     return PA_HOOK_OK;
 }
@@ -592,7 +676,7 @@ static pa_hook_result_t source_output_put_cb(pa_core *core, pa_source_output *o,
     pa_core_assert_ref(core);
     pa_source_output_assert_ref(o);
 
-    return process(u, PA_OBJECT(o), false);
+    return process(u, PA_OBJECT(o), PROCESS_CMD_SINK_INPUT_SOURCE_OUTPUT_PUT, false);
 }
 
 static pa_hook_result_t source_output_move_finish_cb(pa_core *core, pa_source_output *o, struct userdata *u) {
@@ -602,17 +686,19 @@ static pa_hook_result_t source_output_move_finish_cb(pa_core *core, pa_source_ou
     if (pa_proplist_gets(o->proplist, PA_PROP_FILTER_APPLY_MOVING))
         return PA_HOOK_OK;
 
+    u->skip_prop_change = true;
     /* If we're managing m-d-m.auto_filtered on this, remove and re-add if we're continuing to manage it */
     pa_hashmap_remove(u->mdm_ignored_outputs, o);
+    u->skip_prop_change = false;
 
-    return process(u, PA_OBJECT(o), false);
+    return process(u, PA_OBJECT(o), PROCESS_CMD_SINK_INPUT_SOURCE_OUTPUT_MOVE_FINISH, false);
 }
 
 static pa_hook_result_t source_output_proplist_cb(pa_core *core, pa_source_output *o, struct userdata *u) {
     pa_core_assert_ref(core);
     pa_source_output_assert_ref(o);
 
-    return process(u, PA_OBJECT(o), false);
+    return process(u, PA_OBJECT(o), PROCESS_CMD_SINK_INPUT_SOURCE_OUTPUT_PROPLIST, false);
 }
 
 static pa_hook_result_t source_output_unlink_cb(pa_core *core, pa_source_output *o, struct userdata *u) {
@@ -624,7 +710,9 @@ static pa_hook_result_t source_output_unlink_cb(pa_core *core, pa_source_output
     if (pa_hashmap_size(u->filters) > 0)
         trigger_housekeeping(u);
 
+    u->skip_prop_change = true;
     pa_hashmap_remove(u->mdm_ignored_outputs, o);
+    u->skip_prop_change = false;
 
     return PA_HOOK_OK;
 }
@@ -699,6 +787,7 @@ int pa__init(pa_module *m) {
     u->filters = pa_hashmap_new(filter_hash, filter_compare);
     u->mdm_ignored_inputs = pa_hashmap_new_full(NULL, NULL, (pa_free_cb_t) unset_mdm_ignore_input, NULL);
     u->mdm_ignored_outputs = pa_hashmap_new_full(NULL, NULL, (pa_free_cb_t) unset_mdm_ignore_output, NULL);
+    u->skip_prop_change = false;
 
     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_put_cb, u);
     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_move_finish_cb, u);
-- 
2.7.4



More information about the pulseaudio-discuss mailing list