From: KimJeongYeon Date: Thu, 13 Apr 2017 23:06:36 +0000 (+0900) Subject: filter-apply: Add ability to pass parameters to a filter module X-Git-Tag: accepted/tizen/unified/20170531.082625~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F03%2F125103%2F2;p=platform%2Fupstream%2Fpulseaudio.git filter-apply: Add ability to pass parameters to a filter module Currently passing parameters to a filter loaded by module-filter-apply is not possible. To enable passing parameters to a filter this patch uses an additional property filter.apply.{MODULE_NAME}.parameters. This way, filters like virtual-surround-sink and ladspa-sink are fully supported. For example: paplay file.wav --property=filter.apply=ladspa-sink \ --property=filter.apply.ladspa-sink.parameters="plugin=ladspa \ label=ladspa_stereo control=0" This patch based on: https://cgit.freedesktop.org/pulseaudio/pulseaudio/commit/?id=caabff2728d9d588664f8a0ea2f8441804c8b91a Note for tizen: Proplist 'filter.apply.extra.parameters' and 'filter.apply.extra.group' are removed. Also, their names are modified as below. 1) 'filter.apply.extra.group' to 'filter.apply.{MODULE_NAME}.group' 2) 'filter.apply.extra.parameters' to 'filter.apply.{MODULE_NAME}.parameters' For example: paplay file1.wav --property=filter.apply=ladspa-sink \ --property=filter.apply.ladspa-sink.group=group1 \ --property=filter.apply.ladspa-sink.parameters="plugin=ladspa1 \ label=ladspa_stereo control=0" paplay file2.wav --property=filter.apply=ladspa-sink \ --property=filter.apply.ladspa-sink.group=group2 \ --property=filter.apply.ladspa-sink.parameters="plugin=ladspa2 \ label=ladspa_stereo control=0" Signed-off-by: KimJeongYeon Change-Id: Ia1c85aca2be1f7f4328674146e5caa5e78f5e536 --- diff --git a/src/modules/module-filter-apply.c b/src/modules/module-filter-apply.c index bf3fbaa..ce26d14 100644 --- a/src/modules/module-filter-apply.c +++ b/src/modules/module-filter-apply.c @@ -39,7 +39,9 @@ #include "module-filter-apply-symdef.h" -#define PA_PROP_FILTER_APPLY_MOVING "filter.apply.moving" +#define PA_PROP_FILTER_APPLY_GROUP PA_PROP_FILTER_APPLY".%s.group" +#define PA_PROP_FILTER_APPLY_PARAMETERS PA_PROP_FILTER_APPLY".%s.parameters" +#define PA_PROP_FILTER_APPLY_MOVING "filter.apply.moving" PA_MODULE_AUTHOR("Colin Guthrie"); PA_MODULE_DESCRIPTION("Load filter sinks automatically when needed"); @@ -58,6 +60,7 @@ static const char* const valid_modargs[] = { struct filter { char *name; char *group; + char *parameters; uint32_t module_index; pa_sink *sink; pa_sink *sink_master; @@ -106,7 +109,7 @@ static int filter_compare(const void *a, const void *b) { return 0; } -static struct filter *filter_new(const char *name, const char *group, pa_sink *sink, pa_source *source) { +static struct filter *filter_new(const char *name, const char *group, const char *parameters, pa_sink *sink, pa_source *source) { struct filter *f; pa_assert(sink || source); @@ -114,6 +117,7 @@ static struct filter *filter_new(const char *name, const char *group, pa_sink *s f = pa_xnew(struct filter, 1); f->name = pa_xstrdup(name); f->group = pa_xstrdup(group); + f->parameters = pa_xstrdup(parameters); f->sink_master = sink; f->source_master = source; f->module_index = PA_INVALID_INDEX; @@ -127,11 +131,12 @@ static void filter_free(struct filter *f) { if (f) { pa_xfree(f->name); pa_xfree(f->group); + pa_xfree(f->parameters); pa_xfree(f); } } -static const char* should_filter(pa_object *o, bool is_sink_input) { +static const char* get_filter_name(pa_object *o, bool is_sink_input) { const char *apply; pa_proplist *pl; @@ -151,8 +156,9 @@ static const char* should_filter(pa_object *o, bool is_sink_input) { return NULL; } -static const char* should_filter_parameters(pa_object *o, bool is_sink_input) { +static const char* get_filter_parameters(pa_object *o, const char *want, bool is_sink_input) { const char *parameters; + char *prop_parameters; pa_proplist *pl; if (is_sink_input) @@ -160,15 +166,16 @@ static const char* should_filter_parameters(pa_object *o, bool is_sink_input) { else pl = PA_SOURCE_OUTPUT(o)->proplist; - /* If the stream needs parameters, append them to module. */ - if ((parameters = pa_proplist_gets(pl, PA_PROP_FILTER_APPLY_EXTRA_PARAMETERS)) && !pa_streq(parameters, "")) - return parameters; + prop_parameters = pa_sprintf_malloc(PA_PROP_FILTER_APPLY_PARAMETERS, want); + parameters = pa_proplist_gets(pl, prop_parameters); + pa_xfree(prop_parameters); - return NULL; + return parameters; } -static const char* should_filter_group(pa_object *o, bool is_sink_input) { +static const char* get_filter_group(pa_object *o, const char *want, bool is_sink_input) { const char *group; + char *prop_group; pa_proplist *pl; if (is_sink_input) @@ -176,14 +183,14 @@ static const char* should_filter_group(pa_object *o, bool is_sink_input) { else pl = PA_SOURCE_OUTPUT(o)->proplist; - /* If the stream needs group of filters, allow multiple instances. */ - if ((group = pa_proplist_gets(pl, PA_PROP_FILTER_APPLY_EXTRA_GROUP)) && !pa_streq(group, "")) - return group; + prop_group = pa_sprintf_malloc(PA_PROP_FILTER_APPLY_GROUP, want); + group = pa_proplist_gets(pl, prop_group); + pa_xfree(prop_group); - return NULL; + return group; } -static bool is_duplex_filter(struct filter *filter) { +static bool should_group_filter(struct filter *filter) { return pa_streq(filter->name, "echo-cancel"); } @@ -363,7 +370,7 @@ static void move_object_for_filter(pa_object *o, struct filter* filter, bool res static void move_objects_for_filter(struct userdata *u, pa_object *o, struct filter* filter, bool restore, bool is_sink_input) { - if (!is_duplex_filter(filter)) + if (!should_group_filter(filter)) move_object_for_filter(o, filter, restore, is_sink_input); else { pa_source_output *so; @@ -397,7 +404,7 @@ static void move_objects_for_filter(struct userdata *u, pa_object *o, struct fil /* Note that we assume a filter will provide at most one sink and at most one * source (and at least one of either). */ -static void find_filters_for_module(struct userdata *u, pa_module *m, const char *name, const char *group) { +static void find_filters_for_module(struct userdata *u, pa_module *m, const char *name, const char *group, const char *parameters) { uint32_t idx; pa_sink *sink; pa_source *source; @@ -407,7 +414,7 @@ static void find_filters_for_module(struct userdata *u, pa_module *m, const char if (sink->module == m) { pa_assert(sink->input_to_master != NULL); - fltr = filter_new(name, group, sink->input_to_master->sink, NULL); + fltr = filter_new(name, group, parameters, sink->input_to_master->sink, NULL); fltr->module_index = m->index; fltr->sink = sink; @@ -420,7 +427,7 @@ static void find_filters_for_module(struct userdata *u, pa_module *m, const char pa_assert(source->output_from_master != NULL); if (!fltr) { - fltr = filter_new(name, group, NULL, source->output_from_master->source); + fltr = filter_new(name, group, parameters, NULL, source->output_from_master->source); fltr->module_index = m->index; fltr->source = source; } else { @@ -450,6 +457,8 @@ static bool can_unload_module(struct userdata *u, uint32_t idx) { static pa_hook_result_t process(struct userdata *u, pa_object *o, bool is_sink_input) { const char *want; + const char *group; + const char *parameters; bool done_something = false; pa_sink *sink = NULL; pa_source *source = NULL; @@ -472,11 +481,9 @@ static pa_hook_result_t process(struct userdata *u, pa_object *o, bool is_sink_i return PA_HOOK_OK; /* If the stream doesn't what any filter, then let it be. */ - if ((want = should_filter(o, is_sink_input))) { + if ((want = get_filter_name(o, is_sink_input))) { char *module_name; struct filter *fltr, *filter; - const char *parameters; - const char *group; /* We need to ensure the SI is playing on a sink of this type * attached to the sink it's "officially" playing on */ @@ -491,17 +498,18 @@ static pa_hook_result_t process(struct userdata *u, pa_object *o, bool is_sink_i return PA_HOOK_OK; } - /* Some filter modules might require parameters by default. - * (e.g. 'plugin', 'label', 'control' of module-ladspa-sink) */ - parameters = should_filter_parameters(o, is_sink_input); - /* Some applications may want group of filters. (optional) */ - group = should_filter_group(o, is_sink_input); + group = get_filter_group(o, want, is_sink_input); + + /* 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); - fltr = filter_new(want, group, sink, source); + fltr = filter_new(want, group, parameters, sink, source); - if (is_duplex_filter(fltr) && !find_paired_master(u, fltr, o, is_sink_input)) { + if (should_group_filter(fltr) && !find_paired_master(u, fltr, o, is_sink_input)) { pa_log_debug("Want group filtering but don't have enough streams."); + pa_xfree(module_name); filter_free(fltr); return PA_HOOK_OK; } @@ -520,7 +528,7 @@ static pa_hook_result_t process(struct userdata *u, pa_object *o, bool is_sink_i pa_log_debug("Loading %s with arguments '%s'", module_name, args); if ((m = pa_module_load(u->core, module_name, args))) { - find_filters_for_module(u, m, want, group); + find_filters_for_module(u, m, want, group, parameters); filter = pa_hashmap_get(u->filters, fltr); done_something = true; } diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h index 5240485..88548b8 100644 --- a/src/pulse/proplist.h +++ b/src/pulse/proplist.h @@ -71,13 +71,7 @@ PA_C_DECL_BEGIN /** For streams: the name of a filter that is desired, e.g.\ "echo-cancel" or "equalizer-sink". Differs from PA_PROP_FILTER_WANT in that it forces PulseAudio to apply the filter, regardless of whether PulseAudio thinks it makes sense to do so or not. If this is set, PA_PROP_FILTER_WANT is ignored. In other words, you almost certainly do not want to use this. \since 1.0 */ #define PA_PROP_FILTER_APPLY "filter.apply" -/** For streams: some modules require extra parameters, e.g.\ "plugin=ladspa label=ladspa_stereo control=0" in case of "ladspa-sink" filter */ -#define PA_PROP_FILTER_APPLY_EXTRA_PARAMETERS "filter.apply.extra.parameters" - -/** For streams: some applications may want to classify sub filter groups and they can be used as multiple instances. (e.g. load multiple plugin instances of "ladspa-sink" filter) */ -#define PA_PROP_FILTER_APPLY_EXTRA_GROUP "filter.apply.extra.group" - -/** For streams: the name of a filter that should specifically be suppressed (i.e.\ overrides PA_PROP_FILTER_WANT). Useful for the times that PA_PROP_FILTER_WANT is automatically added (e.g. echo-cancellation for phone streams when $VOIP_APP does it's own, internal AEC) \since 1.0 */ +/** For streams: the name of a filter that should specifically suppressed (i.e.\ overrides PA_PROP_FILTER_WANT). Useful for the times that PA_PROP_FILTER_WANT is automatically added (e.g. echo-cancellation for phone streams when $VOIP_APP does it's own, internal AEC) \since 1.0 */ #define PA_PROP_FILTER_SUPPRESS "filter.suppress" #ifdef __TIZEN__