2
* Copyright (C) 2003-2010 The Music Player Daemon Project
3
* http://www.musicpd.org
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License along
16
* with this program; if not, write to the Free Software Foundation, Inc.,
17
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
#include "filter/chain_filter_plugin.h"
23
#include "filter_plugin.h"
24
#include "filter_internal.h"
25
#include "filter_registry.h"
26
#include "audio_format.h"
40
return g_quark_from_static_string("filter");
43
static struct filter *
44
chain_filter_init(G_GNUC_UNUSED const struct config_param *param,
45
G_GNUC_UNUSED GError **error_r)
47
struct filter_chain *chain = g_new(struct filter_chain, 1);
49
filter_init(&chain->base, &chain_filter_plugin);
50
chain->children = NULL;
56
chain_free_child(gpointer data, G_GNUC_UNUSED gpointer user_data)
58
struct filter *filter = data;
64
chain_filter_finish(struct filter *_filter)
66
struct filter_chain *chain = (struct filter_chain *)_filter;
68
g_slist_foreach(chain->children, chain_free_child, NULL);
69
g_slist_free(chain->children);
75
* Close all filters in the chain until #until is reached. #until
76
* itself is not closed.
79
chain_close_until(struct filter_chain *chain, const struct filter *until)
81
GSList *i = chain->children;
82
struct filter *filter;
85
/* this assertion fails if #until does not exist
90
/* don't close this filter */
93
/* close this filter */
101
static const struct audio_format *
102
chain_open_child(struct filter *filter,
103
const struct audio_format *prev_audio_format,
106
struct audio_format conv_audio_format = *prev_audio_format;
107
const struct audio_format *next_audio_format;
109
next_audio_format = filter_open(filter, &conv_audio_format, error_r);
110
if (next_audio_format == NULL)
113
if (!audio_format_equals(&conv_audio_format, prev_audio_format)) {
114
struct audio_format_string s;
116
filter_close(filter);
117
g_set_error(error_r, filter_quark(), 0,
118
"Audio format not supported by filter '%s': %s",
119
filter->plugin->name,
120
audio_format_to_string(prev_audio_format, &s));
124
return next_audio_format;
127
static const struct audio_format *
128
chain_filter_open(struct filter *_filter, struct audio_format *in_audio_format,
131
struct filter_chain *chain = (struct filter_chain *)_filter;
132
const struct audio_format *audio_format = in_audio_format;
134
for (GSList *i = chain->children; i != NULL; i = g_slist_next(i)) {
135
struct filter *filter = i->data;
137
audio_format = chain_open_child(filter, audio_format, error_r);
138
if (audio_format == NULL) {
139
/* rollback, close all children */
140
chain_close_until(chain, filter);
145
/* return the output format of the last filter */
150
chain_close_child(gpointer data, G_GNUC_UNUSED gpointer user_data)
152
struct filter *filter = data;
154
filter_close(filter);
158
chain_filter_close(struct filter *_filter)
160
struct filter_chain *chain = (struct filter_chain *)_filter;
162
g_slist_foreach(chain->children, chain_close_child, NULL);
166
chain_filter_filter(struct filter *_filter,
167
const void *src, size_t src_size,
168
size_t *dest_size_r, GError **error_r)
170
struct filter_chain *chain = (struct filter_chain *)_filter;
172
for (GSList *i = chain->children; i != NULL; i = g_slist_next(i)) {
173
struct filter *filter = i->data;
175
/* feed the output of the previous filter as input
176
into the current one */
177
src = filter_filter(filter, src, src_size, &src_size, error_r);
182
/* return the output of the last filter */
183
*dest_size_r = src_size;
187
const struct filter_plugin chain_filter_plugin = {
189
.init = chain_filter_init,
190
.finish = chain_filter_finish,
191
.open = chain_filter_open,
192
.close = chain_filter_close,
193
.filter = chain_filter_filter,
197
filter_chain_new(void)
199
struct filter *filter = filter_new(&chain_filter_plugin, NULL, NULL);
200
/* chain_filter_init() never fails */
201
assert(filter != NULL);
207
filter_chain_append(struct filter *_chain, struct filter *filter)
209
struct filter_chain *chain = (struct filter_chain *)_chain;
211
chain->children = g_slist_append(chain->children, filter);