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

KimJeongYeon jeongyeon.kim at samsung.com
Wed Apr 19 09:03:49 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 goes to filter's
***master sink or source*** due to unexpected restoring operation.
It should attached to filter sink or source properly.

Also, includes further fix according to Georg's comment, [1]
  If a stream that had filter.apply set initially is moved to another sink/source, then the filter
  should be applied again (a new filter, since the master sink/source has changed).

  If a stream that did not have filter.apply set initially is moved away, the property should
  be removed and no new filter applied.

  Also, a property list change might add or remove the filter.apply property. If it is added,
  we want that the filter is applied. Your patch does nothing and assumes that the stream
  is already filtered, even if the stream is not on a filter sink.

[1] https://lists.freedesktop.org/archives/pulseaudio-discuss/2017-April/027980.html

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

diff --git a/src/modules/module-filter-apply.c b/src/modules/module-filter-apply.c
index e91fb37..562221a 100644
--- a/src/modules/module-filter-apply.c
+++ b/src/modules/module-filter-apply.c
@@ -39,6 +39,7 @@
 
 #define PA_PROP_FILTER_APPLY_PARAMETERS PA_PROP_FILTER_APPLY".%s.parameters"
 #define PA_PROP_FILTER_APPLY_MOVING     "filter.apply.moving"
+#define PA_PROP_FILTER_APPLY_SET_BY_MFA "filter.apply.set_by_mfa"
 #define PA_PROP_MDM_AUTO_FILTERED       "module-device-manager.auto_filtered"
 
 PA_MODULE_AUTHOR("Colin Guthrie");
@@ -161,6 +162,53 @@ static const char* get_filter_parameters(pa_object *o, const char *want, bool is
     return parameters;
 }
 
+static void set_filter_properties(pa_proplist *pl, struct filter* filter, bool is_set) {
+    const char *apply;
+    char *prop_parameters;
+
+    if (is_set) {
+        pa_assert(filter);
+
+        pa_proplist_sets(pl, PA_PROP_FILTER_APPLY, filter->name);
+        if (filter->parameters) {
+            prop_parameters = pa_sprintf_malloc(PA_PROP_FILTER_APPLY_PARAMETERS, filter->name);
+            pa_proplist_sets(pl, prop_parameters, filter->parameters);
+            pa_xfree(prop_parameters);
+        }
+    } else {
+        if (filter)
+            prop_parameters = pa_sprintf_malloc(PA_PROP_FILTER_APPLY_PARAMETERS, filter->name);
+        else {
+            if (!(apply = pa_proplist_gets(pl, PA_PROP_FILTER_APPLY)))
+                return;
+            prop_parameters = pa_sprintf_malloc(PA_PROP_FILTER_APPLY_PARAMETERS, apply);
+        }
+        pa_proplist_unset(pl, prop_parameters);
+        pa_xfree(prop_parameters);
+        pa_proplist_unset(pl, PA_PROP_FILTER_APPLY);
+    }
+}
+
+static struct filter* get_attached_filter(struct userdata *u, pa_object *o, bool is_sink_input) {
+    pa_sink *sink = NULL;
+    pa_source *source = NULL;
+    struct filter *filter = NULL;
+    void *state;
+
+    if (is_sink_input)
+        sink = PA_SINK_INPUT(o)->sink;
+    else
+        source = PA_SOURCE_OUTPUT(o)->source;
+
+    PA_HASHMAP_FOREACH(filter, u->filters, state) {
+        if ((is_sink_input && sink == filter->sink) || (!is_sink_input && source == filter->source)) {
+            return filter;
+        }
+    }
+
+    return NULL;
+}
+
 static bool should_group_filter(struct filter *filter) {
     return pa_streq(filter->name, "echo-cancel");
 }
@@ -431,7 +479,7 @@ 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 pa_hook_result_t process(struct userdata *u, pa_object *o, bool is_sink_input, bool is_put_or_move) {
     const char *want;
     const char *parameters;
     bool done_something = false;
@@ -440,17 +488,16 @@ static pa_hook_result_t process(struct userdata *u, pa_object *o, bool is_sink_i
     pa_module *module = NULL;
     char *module_name = NULL;
     struct filter *fltr = NULL, *filter = NULL;
+    pa_proplist *pl;
 
     if (is_sink_input) {
-        sink = PA_SINK_INPUT(o)->sink;
-
-        if (sink)
+        if ((sink = PA_SINK_INPUT(o)->sink))
             module = sink->module;
+        pl = PA_SINK_INPUT(o)->proplist;
     } else {
-        source = PA_SOURCE_OUTPUT(o)->source;
-
-        if (source)
+        if ((source = PA_SOURCE_OUTPUT(o)->source))
             module = source->module;
+        pl = PA_SOURCE_OUTPUT(o)->proplist;
     }
 
     /* If there is no sink/source yet, we can't do much */
@@ -471,6 +518,24 @@ static pa_hook_result_t process(struct userdata *u, pa_object *o, bool is_sink_i
             goto done;
         }
 
+        if (pa_proplist_gets(pl, PA_PROP_FILTER_APPLY_SET_BY_MFA)) {
+            /* The stream has been manually moved away from the filter.
+             * Keep sink/source as is. */
+
+            if ((filter = get_attached_filter(u, o, is_sink_input))) {
+                /* Change 'filter.apply'. */
+                set_filter_properties(pl, NULL, false);
+                set_filter_properties(pl, filter, true);
+            } else {
+                set_filter_properties(pl, NULL, false);
+                pa_proplist_unset(pl, PA_PROP_FILTER_APPLY_SET_BY_MFA);
+            }
+
+            trigger_housekeeping(u);
+            goto done;
+        }
+        /* Else, normal case. The stream should be moved to a filter. */
+
         /* Some filter modules might require parameters by default.
          * (e.g 'plugin', 'label', 'control' of module-ladspa-sink) */
         parameters = get_filter_parameters(o, want, is_sink_input);
@@ -515,15 +580,21 @@ static pa_hook_result_t process(struct userdata *u, pa_object *o, bool is_sink_i
             done_something = true;
         }
     } else {
-        void *state;
-
         /* We do not want to filter... but are we already filtered?
          * This can happen if an input's proplist changes */
-        PA_HASHMAP_FOREACH(filter, u->filters, state) {
-            if ((is_sink_input && sink == filter->sink) || (!is_sink_input && source == filter->source)) {
+
+        if ((filter = get_attached_filter(u, o, is_sink_input))) {
+            if (!is_put_or_move) {
+                /* 'filter.apply' has been manually unset. Do restore. */
                 move_objects_for_filter(u, o, filter, true, is_sink_input);
+                set_filter_properties(pl, filter, false);
+                pa_proplist_unset(pl, PA_PROP_FILTER_APPLY_SET_BY_MFA);
                 done_something = true;
-                break;
+            } else {
+                /* Stream has been manually moved to a filter sink/source
+                 * without 'filter.apply' set. Leave sink as it is. */
+                set_filter_properties(pl, filter, true);
+                pa_proplist_sets(pl, PA_PROP_FILTER_APPLY_SET_BY_MFA, "1");
             }
         }
     }
@@ -542,7 +613,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), true, true);
 }
 
 static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
@@ -555,14 +626,14 @@ static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input *
     /* 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);
 
-    return process(u, PA_OBJECT(i), true);
+    return process(u, PA_OBJECT(i), true, 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), true, false);
 }
 
 static pa_hook_result_t sink_input_unlink_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
@@ -619,7 +690,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), false, true);
 }
 
 static pa_hook_result_t source_output_move_finish_cb(pa_core *core, pa_source_output *o, struct userdata *u) {
@@ -632,14 +703,14 @@ static pa_hook_result_t source_output_move_finish_cb(pa_core *core, pa_source_ou
     /* 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);
 
-    return process(u, PA_OBJECT(o), false);
+    return process(u, PA_OBJECT(o), false, true);
 }
 
 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), false, false);
 }
 
 static pa_hook_result_t source_output_unlink_cb(pa_core *core, pa_source_output *o, struct userdata *u) {
-- 
2.7.4



More information about the pulseaudio-discuss mailing list