[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