src/modules/module-filter-apply.c |  130 +++++++++++++++++++++++++++++++-------
 1 file changed, 107 insertions(+), 23 deletions(-)

New commits:
commit b8858ff24d03dcd0828db529d455e3b2d2493b98
Author: KimJeongYeon <jeongyeon....@samsung.com>
Date:   Sat Apr 29 11:32:23 2017 +0200

    filter-apply: Do not re-route stream to master sink/source when manually 
moved to filter
    
    Currently, if a stream is manually moved to a filter sink or source managed 
by
    module-filter-apply, the stream will be silently re-routed to the master 
sink
    or source, because the filter.apply property is not set on that stream. We 
can
    assume, that the users intention however was to have the stream filtered.
    
    Therefore this patch changes the logic, so that the stream will not be moved
    to the master but remains on the filter sink or source. To handle the change
    of a property correctly, the filter.apply property must be set temporarily.
    An additional property filter.apply.set_by_mfa was introduced to mark those
    streams, so that filter.apply can be removed again when the stream moves 
away
    from the filter.

diff --git a/src/modules/module-filter-apply.c 
b/src/modules/module-filter-apply.c
index e91fb37d..6ca062ba 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,67 @@ static const char* get_filter_parameters(pa_object *o, 
const char *want, bool is
     return parameters;
 }
 
+/* This function is used to set or unset the filter related stream properties. 
This is necessary
+ * if a stream does not have filter.apply set and is manually moved to a 
filter sink or source.
+ * In this case, the properies must be temporarily set and removed when the 
stream is moved away
+ * from the filter. */
+static void set_filter_properties(pa_proplist *pl, struct filter *filter, bool 
set_properties) {
+    char *prop_parameters;
+
+    if (set_properties) {
+        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);
+        }
+
+        pa_proplist_sets(pl, PA_PROP_FILTER_APPLY_SET_BY_MFA, "1");
+
+    } else {
+        const char *old_filter_name = NULL;
+
+        if (filter)
+            old_filter_name = filter->name;
+        else
+            old_filter_name = pa_proplist_gets(pl, PA_PROP_FILTER_APPLY);
+
+        /* If the filter name cannot be determined, properties cannot be 
removed. */
+        if (!old_filter_name)
+            return;
+
+        prop_parameters = pa_sprintf_malloc(PA_PROP_FILTER_APPLY_PARAMETERS, 
old_filter_name);
+        pa_proplist_unset(pl, prop_parameters);
+        pa_xfree(prop_parameters);
+
+        pa_proplist_unset(pl, PA_PROP_FILTER_APPLY);
+        pa_proplist_unset(pl, PA_PROP_FILTER_APPLY_SET_BY_MFA);
+    }
+}
+
+static struct filter* get_filter_for_object(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");
 }
@@ -309,7 +371,7 @@ static int do_move(struct userdata *u, pa_object *obj, 
pa_object *parent, bool i
     }
 }
 
-static void move_object_for_filter(struct userdata *u, pa_object *o, struct 
filter* filter, bool restore, bool is_sink_input) {
+static void move_object_for_filter(struct userdata *u, pa_object *o, struct 
filter *filter, bool restore, bool is_sink_input) {
     pa_object *parent;
     pa_proplist *pl;
     const char *name;
@@ -343,7 +405,7 @@ static void move_object_for_filter(struct userdata *u, 
pa_object *o, struct filt
     pa_proplist_unset(pl, PA_PROP_FILTER_APPLY_MOVING);
 }
 
-static void move_objects_for_filter(struct userdata *u, pa_object *o, struct 
filter* filter, bool restore,
+static void move_objects_for_filter(struct userdata *u, pa_object *o, struct 
filter *filter, bool restore,
         bool is_sink_input) {
 
     if (!should_group_filter(filter))
@@ -431,7 +493,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_property_change) {
     const char *want;
     const char *parameters;
     bool done_something = false;
@@ -440,24 +502,23 @@ 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 */
     if ((is_sink_input && !sink) || (!is_sink_input && !source))
         goto done;
 
-    /* If the stream doesn't what any filter, then let it be. */
+    /* If the stream doesn't want any filter, then let it be. */
     if ((want = get_filter_name(o, is_sink_input))) {
         /* We need to ensure the SI is playing on a sink of this type
          * attached to the sink it's "officially" playing on */
@@ -471,6 +532,24 @@ static pa_hook_result_t process(struct userdata *u, 
pa_object *o, bool is_sink_i
             goto done;
         }
 
+        /* If the stream originally did not have the filter.apply property set 
and is
+         * manually moved away from the filter, remove the filter properties 
from the
+         * stream */
+        if (pa_proplist_gets(pl, PA_PROP_FILTER_APPLY_SET_BY_MFA)) {
+
+            set_filter_properties(pl, NULL, false);
+
+            /* If the new sink/source is also a filter, the stream has been 
moved from
+             * one filter to another, so add the properties for the new 
filter. */
+            if ((filter = get_filter_for_object(u, o, is_sink_input)))
+                set_filter_properties(pl, filter, true);
+
+            done_something = true;
+            goto done;
+        }
+
+        /* The stream needs 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,23 +594,28 @@ static pa_hook_result_t process(struct userdata *u, 
pa_object *o, bool is_sink_i
             done_something = true;
         }
     } else {
-        void *state;
+        /* The filter.apply property is not set. If the stream is nevertheless 
using a
+         * filter sink/source, it either has been moved to the filter manually 
or the
+         * user just removed the filter.apply property. */
 
-        /* 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_filter_for_object(u, o, is_sink_input))) {
+            if (is_property_change) {
+                /* '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);
                 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);
             }
         }
     }
 
+done:
     if (done_something)
         trigger_housekeeping(u);
 
-done:
     pa_xfree(module_name);
     filter_free(fltr);
 
@@ -542,7 +626,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, false);
 }
 
 static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input 
*i, struct userdata *u) {
@@ -555,14 +639,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, false);
 }
 
 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, true);
 }
 
 static pa_hook_result_t sink_input_unlink_cb(pa_core *core, pa_sink_input *i, 
struct userdata *u) {
@@ -619,7 +703,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, false);
 }
 
 static pa_hook_result_t source_output_move_finish_cb(pa_core *core, 
pa_source_output *o, struct userdata *u) {
@@ -632,14 +716,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, 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), false, true);
 }
 
 static pa_hook_result_t source_output_unlink_cb(pa_core *core, 
pa_source_output *o, struct userdata *u) {

_______________________________________________
pulseaudio-commits mailing list
pulseaudio-commits@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/pulseaudio-commits

Reply via email to