From 87570523f84817b19486ab9302314091424bbad8 Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Fri, 22 Apr 2011 17:33:03 +0530 Subject: filters: Handle filters on sources as well This makes the core code in the filter-* modules generic enough to be used on sources or sinks. We need special handling for modules that introduce more than one sink (for now echo-cancel only). --- src/modules/module-filter-heuristics.c | 65 ++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 14 deletions(-) (limited to 'src/modules/module-filter-heuristics.c') diff --git a/src/modules/module-filter-heuristics.c b/src/modules/module-filter-heuristics.c index 20a48355..4fba2913 100644 --- a/src/modules/module-filter-heuristics.c +++ b/src/modules/module-filter-heuristics.c @@ -49,30 +49,41 @@ struct userdata { pa_core *core; pa_hook_slot *sink_input_put_slot, - *sink_input_move_finish_slot; + *sink_input_move_finish_slot, + *source_output_put_slot, + *source_output_move_finish_slot; }; -static pa_hook_result_t process(struct userdata *u, pa_sink_input *i) { - const char *want, *sink_role, *si_role; +static pa_hook_result_t process(struct userdata *u, pa_object *o, pa_bool_t is_sink_input) { + const char *want, *int_role, *stream_role; + pa_proplist *pl, *parent_pl; + + if (is_sink_input) { + pl = PA_SINK_INPUT(o)->proplist; + parent_pl = PA_SINK_INPUT(o)->sink->proplist; + } else { + pl = PA_SOURCE_OUTPUT(o)->proplist; + parent_pl = PA_SOURCE_OUTPUT(o)->source->proplist; + } /* If the stream already specifies what it must have, then let it be. */ - if (!pa_proplist_gets(i->proplist, PA_PROP_FILTER_HEURISTICS) && pa_proplist_gets(i->proplist, PA_PROP_FILTER_APPLY)) + if (!pa_proplist_gets(pl, PA_PROP_FILTER_HEURISTICS) && pa_proplist_gets(pl, PA_PROP_FILTER_APPLY)) return PA_HOOK_OK; - want = pa_proplist_gets(i->proplist, PA_PROP_FILTER_WANT); + want = pa_proplist_gets(pl, PA_PROP_FILTER_WANT); if (!want) { /* This is a phone stream, maybe we want echo cancellation */ - if ((si_role = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_ROLE)) && pa_streq(si_role, "phone")) + if ((stream_role = pa_proplist_gets(pl, PA_PROP_MEDIA_ROLE)) && pa_streq(stream_role, "phone")) want = "echo-cancel"; } /* On phone sinks, make sure we're not applying echo cancellation */ - if ((sink_role = pa_proplist_gets(i->sink->proplist, PA_PROP_DEVICE_INTENDED_ROLES)) && strstr(sink_role, "phone")) { - const char *apply = pa_proplist_gets(i->proplist, PA_PROP_FILTER_APPLY); + if ((int_role = pa_proplist_gets(parent_pl, PA_PROP_DEVICE_INTENDED_ROLES)) && strstr(int_role, "phone")) { + const char *apply = pa_proplist_gets(pl, PA_PROP_FILTER_APPLY); if (apply && pa_streq(apply, "echo-cancel")) { - pa_proplist_unset(i->proplist, PA_PROP_FILTER_APPLY); - pa_proplist_unset(i->proplist, PA_PROP_FILTER_HEURISTICS); + pa_proplist_unset(pl, PA_PROP_FILTER_APPLY); + pa_proplist_unset(pl, PA_PROP_FILTER_HEURISTICS); } return PA_HOOK_OK; @@ -80,8 +91,8 @@ static pa_hook_result_t process(struct userdata *u, pa_sink_input *i) { if (want) { /* There's a filter that we want, ask module-filter-apply to apply it, and remember that we're managing filter.apply */ - pa_proplist_sets(i->proplist, PA_PROP_FILTER_APPLY, want); - pa_proplist_sets(i->proplist, PA_PROP_FILTER_HEURISTICS, "1"); + pa_proplist_sets(pl, PA_PROP_FILTER_APPLY, want); + pa_proplist_sets(pl, PA_PROP_FILTER_HEURISTICS, "1"); } return PA_HOOK_OK; @@ -92,7 +103,7 @@ static pa_hook_result_t sink_input_put_cb(pa_core *core, pa_sink_input *i, struc pa_sink_input_assert_ref(i); pa_assert(u); - return process(u, i); + return process(u, PA_OBJECT(i), TRUE); } static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input *i, struct userdata *u) { @@ -104,7 +115,27 @@ 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; - return process(u, i); + return process(u, PA_OBJECT(i), TRUE); +} + +static pa_hook_result_t source_output_put_cb(pa_core *core, pa_source_output *i, struct userdata *u) { + pa_core_assert_ref(core); + pa_source_output_assert_ref(i); + pa_assert(u); + + return process(u, PA_OBJECT(i), FALSE); +} + +static pa_hook_result_t source_output_move_finish_cb(pa_core *core, pa_source_output *i, struct userdata *u) { + pa_core_assert_ref(core); + pa_source_output_assert_ref(i); + pa_assert(u); + + /* module-filter-apply triggered this move, ignore */ + if (pa_proplist_gets(i->proplist, PA_PROP_FILTER_APPLY_MOVING)) + return PA_HOOK_OK; + + return process(u, PA_OBJECT(i), FALSE); } int pa__init(pa_module *m) { @@ -124,6 +155,8 @@ int pa__init(pa_module *m) { u->sink_input_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_LATE-1, (pa_hook_cb_t) sink_input_put_cb, u); u->sink_input_move_finish_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH], PA_HOOK_LATE-1, (pa_hook_cb_t) sink_input_move_finish_cb, u); + u->source_output_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], PA_HOOK_LATE-1, (pa_hook_cb_t) source_output_put_cb, u); + u->source_output_move_finish_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH], PA_HOOK_LATE-1, (pa_hook_cb_t) source_output_move_finish_cb, u); pa_modargs_free(ma); @@ -152,6 +185,10 @@ void pa__done(pa_module *m) { pa_hook_slot_free(u->sink_input_put_slot); if (u->sink_input_move_finish_slot) pa_hook_slot_free(u->sink_input_move_finish_slot); + if (u->source_output_put_slot) + pa_hook_slot_free(u->source_output_put_slot); + if (u->source_output_move_finish_slot) + pa_hook_slot_free(u->source_output_move_finish_slot); pa_xfree(u); -- cgit