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:
		@@ -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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user