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.
This commit is contained in:
parent
d2051c7f50
commit
b54bde6f2b
@ -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 {
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
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
|
void
|
||||||
|
@ -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);
|
|||||||
* 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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user