From b54bde6f2b9f826cd7189182d733aada66c95dd8 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 25 Dec 2009 14:27:32 +0100 Subject: [PATCH] filter_plugin: allow open() to force an input format Make the audio_format argument non-const. Allow the open() method to modify it, to indicate that it wants a different input audio format than the one specified. Check that condition in chain_filter_open(), and fail. --- src/filter/chain_filter_plugin.c | 39 +++++++++++++++++++++++++--- src/filter/convert_filter_plugin.c | 5 ++-- src/filter/normalize_filter_plugin.c | 18 +++---------- src/filter/null_filter_plugin.c | 3 +-- src/filter/route_filter_plugin.c | 3 +-- src/filter/volume_filter_plugin.c | 12 +++------ src/filter_plugin.c | 13 +++++++--- src/filter_plugin.h | 11 +++++--- 8 files changed, 64 insertions(+), 40 deletions(-) diff --git a/src/filter/chain_filter_plugin.c b/src/filter/chain_filter_plugin.c index edfa70f35..56fa3a5e1 100644 --- a/src/filter/chain_filter_plugin.c +++ b/src/filter/chain_filter_plugin.c @@ -23,6 +23,7 @@ #include "filter_plugin.h" #include "filter_internal.h" #include "filter_registry.h" +#include "audio_format.h" #include @@ -33,6 +34,12 @@ struct filter_chain { GSList *children; }; +static inline GQuark +filter_quark(void) +{ + return g_quark_from_static_string("filter"); +} + static struct filter * chain_filter_init(G_GNUC_UNUSED const struct config_param *param, G_GNUC_UNUSED GError **error_r) @@ -92,16 +99,42 @@ chain_close_until(struct filter_chain *chain, const struct filter *until) } static const struct audio_format * -chain_filter_open(struct filter *_filter, - const struct audio_format *audio_format, +chain_open_child(struct filter *filter, + const struct audio_format *prev_audio_format, + GError **error_r) +{ + struct audio_format conv_audio_format = *prev_audio_format; + const struct audio_format *next_audio_format; + + next_audio_format = filter_open(filter, &conv_audio_format, error_r); + if (next_audio_format == NULL) + return NULL; + + if (!audio_format_equals(&conv_audio_format, prev_audio_format)) { + struct audio_format_string s; + + filter_close(filter); + g_set_error(error_r, filter_quark(), 0, + "Audio format not supported by filter '%s': %s", + filter->plugin->name, + audio_format_to_string(prev_audio_format, &s)); + return NULL; + } + + return next_audio_format; +} + +static const struct audio_format * +chain_filter_open(struct filter *_filter, struct audio_format *in_audio_format, GError **error_r) { struct filter_chain *chain = (struct filter_chain *)_filter; + const struct audio_format *audio_format = in_audio_format; for (GSList *i = chain->children; i != NULL; i = g_slist_next(i)) { struct filter *filter = i->data; - audio_format = filter_open(filter, audio_format, error_r); + audio_format = chain_open_child(filter, audio_format, error_r); if (audio_format == NULL) { /* rollback, close all children */ chain_close_until(chain, filter); diff --git a/src/filter/convert_filter_plugin.c b/src/filter/convert_filter_plugin.c index 982ec7c4c..87070fa3a 100644 --- a/src/filter/convert_filter_plugin.c +++ b/src/filter/convert_filter_plugin.c @@ -71,8 +71,7 @@ convert_filter_finish(struct filter *filter) } static const struct audio_format * -convert_filter_open(struct filter *_filter, - const struct audio_format *audio_format, +convert_filter_open(struct filter *_filter, struct audio_format *audio_format, G_GNUC_UNUSED GError **error_r) { struct convert_filter *filter = (struct convert_filter *)_filter; @@ -82,7 +81,7 @@ convert_filter_open(struct filter *_filter, filter->in_audio_format = filter->out_audio_format = *audio_format; pcm_convert_init(&filter->state); - return audio_format; + return &filter->in_audio_format; } static void diff --git a/src/filter/normalize_filter_plugin.c b/src/filter/normalize_filter_plugin.c index 2694646ee..4a8bde51d 100644 --- a/src/filter/normalize_filter_plugin.c +++ b/src/filter/normalize_filter_plugin.c @@ -61,23 +61,13 @@ normalize_filter_finish(struct filter *filter) static const struct audio_format * normalize_filter_open(struct filter *_filter, - const struct audio_format *audio_format, - GError **error_r) + struct audio_format *audio_format, + G_GNUC_UNUSED GError **error_r) { struct normalize_filter *filter = (struct normalize_filter *)_filter; - if (audio_format->format != SAMPLE_FORMAT_S16) { - g_set_error(error_r, normalize_quark(), 0, - "Unsupported audio format"); - return false; - } - - if (audio_format->reverse_endian) { - g_set_error(error_r, normalize_quark(), 0, - "Normalize for reverse endian " - "samples is not implemented"); - return false; - } + audio_format->format = SAMPLE_FORMAT_S16; + audio_format->reverse_endian = false; filter->compressor = Compressor_new(0); diff --git a/src/filter/null_filter_plugin.c b/src/filter/null_filter_plugin.c index 5671ba907..d677780dc 100644 --- a/src/filter/null_filter_plugin.c +++ b/src/filter/null_filter_plugin.c @@ -54,8 +54,7 @@ null_filter_finish(struct filter *_filter) } static const struct audio_format * -null_filter_open(struct filter *_filter, - const struct audio_format *audio_format, +null_filter_open(struct filter *_filter, struct audio_format *audio_format, G_GNUC_UNUSED GError **error_r) { struct null_filter *filter = (struct null_filter *)_filter; diff --git a/src/filter/route_filter_plugin.c b/src/filter/route_filter_plugin.c index 7fef2bc12..d9ca149c8 100644 --- a/src/filter/route_filter_plugin.c +++ b/src/filter/route_filter_plugin.c @@ -248,8 +248,7 @@ route_filter_finish(struct filter *_filter) } static const struct audio_format * -route_filter_open(struct filter *_filter, - const struct audio_format *audio_format, +route_filter_open(struct filter *_filter, struct audio_format *audio_format, G_GNUC_UNUSED GError **error_r) { struct route_filter *filter = (struct route_filter *)_filter; diff --git a/src/filter/volume_filter_plugin.c b/src/filter/volume_filter_plugin.c index 11549784f..82eed3acc 100644 --- a/src/filter/volume_filter_plugin.c +++ b/src/filter/volume_filter_plugin.c @@ -69,18 +69,12 @@ volume_filter_finish(struct filter *filter) } static const struct audio_format * -volume_filter_open(struct filter *_filter, - const struct audio_format *audio_format, - GError **error_r) +volume_filter_open(struct filter *_filter, struct audio_format *audio_format, + G_GNUC_UNUSED GError **error_r) { struct volume_filter *filter = (struct volume_filter *)_filter; - if (audio_format->reverse_endian) { - g_set_error(error_r, volume_quark(), 0, - "Software volume for reverse endian " - "samples is not implemented"); - return false; - } + audio_format->reverse_endian = false; filter->audio_format = *audio_format; pcm_buffer_init(&filter->buffer); diff --git a/src/filter_plugin.c b/src/filter_plugin.c index ecc4b5432..21cb2f277 100644 --- a/src/filter_plugin.c +++ b/src/filter_plugin.c @@ -74,18 +74,23 @@ filter_free(struct filter *filter) } const struct audio_format * -filter_open(struct filter *filter, const struct audio_format *audio_format, +filter_open(struct filter *filter, struct audio_format *audio_format, GError **error_r) { + const struct audio_format *out_audio_format; + assert(filter != NULL); assert(audio_format != NULL); assert(audio_format_valid(audio_format)); assert(error_r == NULL || *error_r == NULL); - audio_format = filter->plugin->open(filter, audio_format, error_r); - assert(audio_format == NULL || audio_format_valid(audio_format)); + out_audio_format = filter->plugin->open(filter, audio_format, error_r); - return audio_format; + assert(out_audio_format == NULL || audio_format_valid(audio_format)); + assert(out_audio_format == NULL || + audio_format_valid(out_audio_format)); + + return out_audio_format; } void diff --git a/src/filter_plugin.h b/src/filter_plugin.h index dc5903b59..cec15794f 100644 --- a/src/filter_plugin.h +++ b/src/filter_plugin.h @@ -50,10 +50,14 @@ struct filter_plugin { /** * Opens a filter. + * + * @param audio_format the audio format of incoming data; the + * plugin may modify the object to enforce another input + * format */ const struct audio_format * (*open)(struct filter *filter, - const struct audio_format *audio_format, + struct audio_format *audio_format, GError **error_r); /** @@ -108,13 +112,14 @@ filter_free(struct filter *filter); * Opens the filter, preparing it for filter_filter(). * * @param filter the filter object - * @param audio_format the audio format of incoming data + * @param audio_format the audio format of incoming data; the plugin + * may modify the object to enforce another input format * @param error location to store the error occuring, or NULL to * ignore errors. * @return the format of outgoing data */ const struct audio_format * -filter_open(struct filter *filter, const struct audio_format *audio_format, +filter_open(struct filter *filter, struct audio_format *audio_format, GError **error_r); /**