configure.ac: Move OggVorbis Encoder to Encoder Plugins.
[mpd-mk.git] / src / output_init.c
blob6ee340edcecfcc0f99d70750e8a007fafa6ea05e
1 /*
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.
20 #include "config.h"
21 #include "output_control.h"
22 #include "output_api.h"
23 #include "output_internal.h"
24 #include "output_list.h"
25 #include "audio_parser.h"
26 #include "mixer_control.h"
27 #include "mixer_type.h"
28 #include "mixer_list.h"
29 #include "mixer/software_mixer_plugin.h"
30 #include "filter_plugin.h"
31 #include "filter_registry.h"
32 #include "filter_config.h"
33 #include "filter/chain_filter_plugin.h"
34 #include "filter/autoconvert_filter_plugin.h"
35 #include "filter/replay_gain_filter_plugin.h"
37 #include <glib.h>
39 #include <assert.h>
41 #undef G_LOG_DOMAIN
42 #define G_LOG_DOMAIN "output"
44 #define AUDIO_OUTPUT_TYPE "type"
45 #define AUDIO_OUTPUT_NAME "name"
46 #define AUDIO_OUTPUT_FORMAT "format"
47 #define AUDIO_FILTERS "filters"
49 static const struct audio_output_plugin *
50 audio_output_detect(GError **error)
52 const struct audio_output_plugin *plugin;
53 unsigned i;
55 g_warning("Attempt to detect audio output device");
57 audio_output_plugins_for_each(plugin, i) {
58 if (plugin->test_default_device == NULL)
59 continue;
61 g_warning("Attempting to detect a %s audio device",
62 plugin->name);
63 if (ao_plugin_test_default_device(plugin))
64 return plugin;
67 g_set_error(error, audio_output_quark(), 0,
68 "Unable to detect an audio device");
69 return NULL;
72 /**
73 * Determines the mixer type which should be used for the specified
74 * configuration block.
76 * This handles the deprecated options mixer_type (global) and
77 * mixer_enabled, if the mixer_type setting is not configured.
79 static enum mixer_type
80 audio_output_mixer_type(const struct config_param *param)
82 /* read the local "mixer_type" setting */
83 const char *p = config_get_block_string(param, "mixer_type", NULL);
84 if (p != NULL)
85 return mixer_type_parse(p);
87 /* try the local "mixer_enabled" setting next (deprecated) */
88 if (!config_get_block_bool(param, "mixer_enabled", true))
89 return MIXER_TYPE_NONE;
91 /* fall back to the global "mixer_type" setting (also
92 deprecated) */
93 return mixer_type_parse(config_get_string("mixer_type", "hardware"));
96 static struct mixer *
97 audio_output_load_mixer(void *ao, const struct config_param *param,
98 const struct mixer_plugin *plugin,
99 struct filter *filter_chain,
100 GError **error_r)
102 struct mixer *mixer;
104 switch (audio_output_mixer_type(param)) {
105 case MIXER_TYPE_NONE:
106 case MIXER_TYPE_UNKNOWN:
107 return NULL;
109 case MIXER_TYPE_HARDWARE:
110 if (plugin == NULL)
111 return NULL;
113 return mixer_new(plugin, ao, param, error_r);
115 case MIXER_TYPE_SOFTWARE:
116 mixer = mixer_new(&software_mixer_plugin, NULL, NULL, NULL);
117 assert(mixer != NULL);
119 filter_chain_append(filter_chain,
120 software_mixer_get_filter(mixer));
121 return mixer;
124 assert(false);
125 return NULL;
128 bool
129 audio_output_init(struct audio_output *ao, const struct config_param *param,
130 GError **error_r)
132 const struct audio_output_plugin *plugin = NULL;
133 GError *error = NULL;
135 if (param) {
136 const char *p;
138 p = config_get_block_string(param, AUDIO_OUTPUT_TYPE, NULL);
139 if (p == NULL) {
140 g_set_error(error_r, audio_output_quark(), 0,
141 "Missing \"type\" configuration");
142 return false;
145 plugin = audio_output_plugin_get(p);
146 if (plugin == NULL) {
147 g_set_error(error_r, audio_output_quark(), 0,
148 "No such audio output plugin: %s", p);
149 return false;
152 ao->name = config_get_block_string(param, AUDIO_OUTPUT_NAME,
153 NULL);
154 if (ao->name == NULL) {
155 g_set_error(error_r, audio_output_quark(), 0,
156 "Missing \"name\" configuration");
157 return false;
160 p = config_get_block_string(param, AUDIO_OUTPUT_FORMAT,
161 NULL);
162 if (p != NULL) {
163 bool success =
164 audio_format_parse(&ao->config_audio_format,
165 p, true, error_r);
166 if (!success)
167 return false;
168 } else
169 audio_format_clear(&ao->config_audio_format);
170 } else {
171 g_warning("No \"%s\" defined in config file\n",
172 CONF_AUDIO_OUTPUT);
174 plugin = audio_output_detect(error_r);
175 if (plugin == NULL)
176 return false;
178 g_message("Successfully detected a %s audio device",
179 plugin->name);
181 ao->name = "default detected output";
183 audio_format_clear(&ao->config_audio_format);
186 ao->plugin = plugin;
187 ao->always_on = config_get_block_bool(param, "always_on", false);
188 ao->enabled = config_get_block_bool(param, "enabled", true);
189 ao->really_enabled = false;
190 ao->open = false;
191 ao->pause = false;
192 ao->fail_timer = NULL;
194 /* set up the filter chain */
196 ao->filter = filter_chain_new();
197 assert(ao->filter != NULL);
199 /* create the replay_gain filter */
201 const char *replay_gain_handler =
202 config_get_block_string(param, "replay_gain_handler",
203 "software");
205 if (strcmp(replay_gain_handler, "none") != 0) {
206 ao->replay_gain_filter = filter_new(&replay_gain_filter_plugin,
207 param, NULL);
208 assert(ao->replay_gain_filter != NULL);
210 filter_chain_append(ao->filter, ao->replay_gain_filter);
211 ao->replay_gain_serial = 0;
212 } else
213 ao->replay_gain_filter = NULL;
215 /* create the normalization filter (if configured) */
217 if (config_get_bool(CONF_VOLUME_NORMALIZATION, false)) {
218 struct filter *normalize_filter =
219 filter_new(&normalize_filter_plugin, NULL, NULL);
220 assert(normalize_filter != NULL);
222 filter_chain_append(ao->filter,
223 autoconvert_filter_new(normalize_filter));
226 filter_chain_parse(ao->filter,
227 config_get_block_string(param, AUDIO_FILTERS, ""),
228 &error
231 // It's not really fatal - Part of the filter chain has been set up already
232 // and even an empty one will work (if only with unexpected behaviour)
233 if (error != NULL) {
234 g_warning("Failed to initialize filter chain for '%s': %s",
235 ao->name, error->message);
236 g_error_free(error);
239 ao->thread = NULL;
240 ao->command = AO_COMMAND_NONE;
241 ao->mutex = g_mutex_new();
242 ao->cond = g_cond_new();
244 ao->data = ao_plugin_init(plugin,
245 &ao->config_audio_format,
246 param, error_r);
247 if (ao->data == NULL)
248 return false;
250 ao->mixer = audio_output_load_mixer(ao->data, param,
251 plugin->mixer_plugin,
252 ao->filter, &error);
253 if (ao->mixer == NULL && error != NULL) {
254 g_warning("Failed to initialize hardware mixer for '%s': %s",
255 ao->name, error->message);
256 g_error_free(error);
259 /* use the hardware mixer for replay gain? */
261 if (strcmp(replay_gain_handler, "mixer") == 0) {
262 if (ao->mixer != NULL)
263 replay_gain_filter_set_mixer(ao->replay_gain_filter,
264 ao->mixer, 100);
265 else
266 g_warning("No such mixer for output '%s'", ao->name);
267 } else if (strcmp(replay_gain_handler, "software") != 0 &&
268 ao->replay_gain_filter != NULL) {
269 g_set_error(error_r, audio_output_quark(), 0,
270 "Invalid \"replay_gain_handler\" value");
271 return false;
274 /* the "convert" filter must be the last one in the chain */
276 ao->convert_filter = filter_new(&convert_filter_plugin, NULL, NULL);
277 assert(ao->convert_filter != NULL);
279 filter_chain_append(ao->filter, ao->convert_filter);
281 /* done */
283 return true;