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_internal.h" | ||||
| #include "filter_registry.h" | ||||
| #include "audio_format.h" | ||||
|  | ||||
| #include <assert.h> | ||||
|  | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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); | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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); | ||||
|  | ||||
| /** | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Max Kellermann
					Max Kellermann