Commit b54bde6f authored by Max Kellermann's avatar Max Kellermann

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.
parent d2051c7f
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "filter_plugin.h" #include "filter_plugin.h"
#include "filter_internal.h" #include "filter_internal.h"
#include "filter_registry.h" #include "filter_registry.h"
#include "audio_format.h"
#include <assert.h> #include <assert.h>
...@@ -33,6 +34,12 @@ struct filter_chain { ...@@ -33,6 +34,12 @@ struct filter_chain {
GSList *children; GSList *children;
}; };
static inline GQuark
filter_quark(void)
{
return g_quark_from_static_string("filter");
}
static struct filter * static struct filter *
chain_filter_init(G_GNUC_UNUSED const struct config_param *param, chain_filter_init(G_GNUC_UNUSED const struct config_param *param,
G_GNUC_UNUSED GError **error_r) G_GNUC_UNUSED GError **error_r)
...@@ -92,16 +99,42 @@ chain_close_until(struct filter_chain *chain, const struct filter *until) ...@@ -92,16 +99,42 @@ chain_close_until(struct filter_chain *chain, const struct filter *until)
} }
static const struct audio_format * static const struct audio_format *
chain_filter_open(struct filter *_filter, chain_open_child(struct filter *filter,
const struct audio_format *audio_format, 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) GError **error_r)
{ {
struct filter_chain *chain = (struct filter_chain *)_filter; 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)) { for (GSList *i = chain->children; i != NULL; i = g_slist_next(i)) {
struct filter *filter = i->data; 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) { if (audio_format == NULL) {
/* rollback, close all children */ /* rollback, close all children */
chain_close_until(chain, filter); chain_close_until(chain, filter);
......
...@@ -71,8 +71,7 @@ convert_filter_finish(struct filter *filter) ...@@ -71,8 +71,7 @@ convert_filter_finish(struct filter *filter)
} }
static const struct audio_format * static const struct audio_format *
convert_filter_open(struct filter *_filter, convert_filter_open(struct filter *_filter, struct audio_format *audio_format,
const struct audio_format *audio_format,
G_GNUC_UNUSED GError **error_r) G_GNUC_UNUSED GError **error_r)
{ {
struct convert_filter *filter = (struct convert_filter *)_filter; struct convert_filter *filter = (struct convert_filter *)_filter;
...@@ -82,7 +81,7 @@ convert_filter_open(struct filter *_filter, ...@@ -82,7 +81,7 @@ convert_filter_open(struct filter *_filter,
filter->in_audio_format = filter->out_audio_format = *audio_format; filter->in_audio_format = filter->out_audio_format = *audio_format;
pcm_convert_init(&filter->state); pcm_convert_init(&filter->state);
return audio_format; return &filter->in_audio_format;
} }
static void static void
......
...@@ -61,23 +61,13 @@ normalize_filter_finish(struct filter *filter) ...@@ -61,23 +61,13 @@ normalize_filter_finish(struct filter *filter)
static const struct audio_format * static const struct audio_format *
normalize_filter_open(struct filter *_filter, normalize_filter_open(struct filter *_filter,
const struct audio_format *audio_format, struct audio_format *audio_format,
GError **error_r) G_GNUC_UNUSED GError **error_r)
{ {
struct normalize_filter *filter = (struct normalize_filter *)_filter; struct normalize_filter *filter = (struct normalize_filter *)_filter;
if (audio_format->format != SAMPLE_FORMAT_S16) { audio_format->format = SAMPLE_FORMAT_S16;
g_set_error(error_r, normalize_quark(), 0, audio_format->reverse_endian = false;
"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;
}
filter->compressor = Compressor_new(0); filter->compressor = Compressor_new(0);
......
...@@ -54,8 +54,7 @@ null_filter_finish(struct filter *_filter) ...@@ -54,8 +54,7 @@ null_filter_finish(struct filter *_filter)
} }
static const struct audio_format * static const struct audio_format *
null_filter_open(struct filter *_filter, null_filter_open(struct filter *_filter, struct audio_format *audio_format,
const struct audio_format *audio_format,
G_GNUC_UNUSED GError **error_r) G_GNUC_UNUSED GError **error_r)
{ {
struct null_filter *filter = (struct null_filter *)_filter; struct null_filter *filter = (struct null_filter *)_filter;
......
...@@ -248,8 +248,7 @@ route_filter_finish(struct filter *_filter) ...@@ -248,8 +248,7 @@ route_filter_finish(struct filter *_filter)
} }
static const struct audio_format * static const struct audio_format *
route_filter_open(struct filter *_filter, route_filter_open(struct filter *_filter, struct audio_format *audio_format,
const struct audio_format *audio_format,
G_GNUC_UNUSED GError **error_r) G_GNUC_UNUSED GError **error_r)
{ {
struct route_filter *filter = (struct route_filter *)_filter; struct route_filter *filter = (struct route_filter *)_filter;
......
...@@ -69,18 +69,12 @@ volume_filter_finish(struct filter *filter) ...@@ -69,18 +69,12 @@ volume_filter_finish(struct filter *filter)
} }
static const struct audio_format * static const struct audio_format *
volume_filter_open(struct filter *_filter, volume_filter_open(struct filter *_filter, struct audio_format *audio_format,
const struct audio_format *audio_format, G_GNUC_UNUSED GError **error_r)
GError **error_r)
{ {
struct volume_filter *filter = (struct volume_filter *)_filter; struct volume_filter *filter = (struct volume_filter *)_filter;
if (audio_format->reverse_endian) { audio_format->reverse_endian = false;
g_set_error(error_r, volume_quark(), 0,
"Software volume for reverse endian "
"samples is not implemented");
return false;
}
filter->audio_format = *audio_format; filter->audio_format = *audio_format;
pcm_buffer_init(&filter->buffer); pcm_buffer_init(&filter->buffer);
......
...@@ -74,18 +74,23 @@ filter_free(struct filter *filter) ...@@ -74,18 +74,23 @@ filter_free(struct filter *filter)
} }
const struct audio_format * 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) GError **error_r)
{ {
const struct audio_format *out_audio_format;
assert(filter != NULL); assert(filter != NULL);
assert(audio_format != NULL); assert(audio_format != NULL);
assert(audio_format_valid(audio_format)); assert(audio_format_valid(audio_format));
assert(error_r == NULL || *error_r == NULL); assert(error_r == NULL || *error_r == NULL);
audio_format = filter->plugin->open(filter, audio_format, error_r); out_audio_format = filter->plugin->open(filter, audio_format, error_r);
assert(audio_format == NULL || audio_format_valid(audio_format));
assert(out_audio_format == NULL || audio_format_valid(audio_format));
assert(out_audio_format == NULL ||
audio_format_valid(out_audio_format));
return audio_format; return out_audio_format;
} }
void void
......
...@@ -50,10 +50,14 @@ struct filter_plugin { ...@@ -50,10 +50,14 @@ struct filter_plugin {
/** /**
* Opens a filter. * 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 * const struct audio_format *
(*open)(struct filter *filter, (*open)(struct filter *filter,
const struct audio_format *audio_format, struct audio_format *audio_format,
GError **error_r); GError **error_r);
/** /**
...@@ -108,13 +112,14 @@ filter_free(struct filter *filter); ...@@ -108,13 +112,14 @@ filter_free(struct filter *filter);
* Opens the filter, preparing it for filter_filter(). * Opens the filter, preparing it for filter_filter().
* *
* @param filter the filter object * @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 * @param error location to store the error occuring, or NULL to
* ignore errors. * ignore errors.
* @return the format of outgoing data * @return the format of outgoing data
*/ */
const struct audio_format * 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); GError **error_r);
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment