output_init.c 8.49 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2011 The Music Player Daemon Project
3
 * http://www.musicpd.org
4 5 6 7 8 9 10 11 12 13
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
14 15 16 17
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 19
 */

20
#include "config.h"
21 22
#include "output_control.h"
#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 28 29
#include "mixer_type.h"
#include "mixer_list.h"
#include "mixer/software_mixer_plugin.h"
30 31
#include "filter_plugin.h"
#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"
36

37 38
#include <glib.h>

39 40
#include <assert.h>

41 42 43
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "output"

44 45 46
#define AUDIO_OUTPUT_TYPE	"type"
#define AUDIO_OUTPUT_NAME	"name"
#define AUDIO_OUTPUT_FORMAT	"format"
47
#define AUDIO_FILTERS		"filters"
48

49
static const struct audio_output_plugin *
50
audio_output_detect(GError **error)
51 52 53
{
	g_warning("Attempt to detect audio output device");

54
	audio_output_plugins_for_each(plugin) {
55 56 57 58 59 60 61 62 63
		if (plugin->test_default_device == NULL)
			continue;

		g_warning("Attempting to detect a %s audio device",
			  plugin->name);
		if (ao_plugin_test_default_device(plugin))
			return plugin;
	}

64 65
	g_set_error(error, audio_output_quark(), 0,
		    "Unable to detect an audio device");
66 67 68
	return NULL;
}

69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
/**
 * Determines the mixer type which should be used for the specified
 * configuration block.
 *
 * This handles the deprecated options mixer_type (global) and
 * mixer_enabled, if the mixer_type setting is not configured.
 */
static enum mixer_type
audio_output_mixer_type(const struct config_param *param)
{
	/* read the local "mixer_type" setting */
	const char *p = config_get_block_string(param, "mixer_type", NULL);
	if (p != NULL)
		return mixer_type_parse(p);

	/* try the local "mixer_enabled" setting next (deprecated) */
	if (!config_get_block_bool(param, "mixer_enabled", true))
		return MIXER_TYPE_NONE;

	/* fall back to the global "mixer_type" setting (also
	   deprecated) */
	return mixer_type_parse(config_get_string("mixer_type", "hardware"));
}

93
static struct mixer *
94 95
audio_output_load_mixer(struct audio_output *ao,
			const struct config_param *param,
96
			const struct mixer_plugin *plugin,
97 98
			struct filter *filter_chain,
			GError **error_r)
99
{
100
	struct mixer *mixer;
101

102 103 104
	switch (audio_output_mixer_type(param)) {
	case MIXER_TYPE_NONE:
	case MIXER_TYPE_UNKNOWN:
105 106
		return NULL;

107 108 109 110
	case MIXER_TYPE_HARDWARE:
		if (plugin == NULL)
			return NULL;

111
		return mixer_new(plugin, ao, param, error_r);
112 113

	case MIXER_TYPE_SOFTWARE:
114
		mixer = mixer_new(&software_mixer_plugin, NULL, NULL, NULL);
115 116 117 118 119 120 121 122 123
		assert(mixer != NULL);

		filter_chain_append(filter_chain,
				    software_mixer_get_filter(mixer));
		return mixer;
	}

	assert(false);
	return NULL;
124 125
}

126
bool
127 128 129
ao_base_init(struct audio_output *ao,
	     const struct audio_output_plugin *plugin,
	     const struct config_param *param, GError **error_r)
130
{
131
	assert(ao != NULL);
132 133 134 135 136
	assert(plugin != NULL);
	assert(plugin->finish != NULL);
	assert(plugin->open != NULL);
	assert(plugin->close != NULL);
	assert(plugin->play != NULL);
137

138
	GError *error = NULL;
139 140

	if (param) {
141
		const char *p;
142

143 144 145
		ao->name = config_get_block_string(param, AUDIO_OUTPUT_NAME,
						   NULL);
		if (ao->name == NULL) {
146
			g_set_error(error_r, audio_output_quark(), 0,
147 148 149 150
				    "Missing \"name\" configuration");
			return false;
		}

151
		p = config_get_block_string(param, AUDIO_OUTPUT_FORMAT,
152
						 NULL);
153
		if (p != NULL) {
154
			bool success =
155
				audio_format_parse(&ao->config_audio_format,
156
						   p, true, error_r);
157 158
			if (!success)
				return false;
159 160
		} else
			audio_format_clear(&ao->config_audio_format);
161
	} else {
162
		ao->name = "default detected output";
163 164

		audio_format_clear(&ao->config_audio_format);
165 166 167
	}

	ao->plugin = plugin;
168
	ao->always_on = config_get_block_bool(param, "always_on", false);
169
	ao->enabled = config_get_block_bool(param, "enabled", true);
170
	ao->really_enabled = false;
171
	ao->open = false;
172
	ao->pause = false;
173
	ao->allow_play = true;
174
	ao->fail_timer = NULL;
175

176 177
	pcm_buffer_init(&ao->cross_fade_buffer);

178 179 180 181
	/* set up the filter chain */

	ao->filter = filter_chain_new();
	assert(ao->filter != NULL);
182

183 184
	/* create the normalization filter (if configured) */

185 186 187 188 189 190 191 192 193
	if (config_get_bool(CONF_VOLUME_NORMALIZATION, false)) {
		struct filter *normalize_filter =
			filter_new(&normalize_filter_plugin, NULL, NULL);
		assert(normalize_filter != NULL);

		filter_chain_append(ao->filter,
				    autoconvert_filter_new(normalize_filter));
	}

194
	filter_chain_parse(ao->filter,
195 196
	                   config_get_block_string(param, AUDIO_FILTERS, ""),
	                   &error
197
	);
198

199 200 201 202 203 204 205 206
	// It's not really fatal - Part of the filter chain has been set up already
	// and even an empty one will work (if only with unexpected behaviour)
	if (error != NULL) {
		g_warning("Failed to initialize filter chain for '%s': %s",
			  ao->name, error->message);
		g_error_free(error);
	}

207
	ao->thread = NULL;
208
	ao->command = AO_COMMAND_NONE;
209
	ao->mutex = g_mutex_new();
210
	ao->cond = g_cond_new();
211

212
	ao->mixer = NULL;
213 214
	ao->replay_gain_filter = NULL;
	ao->other_replay_gain_filter = NULL;
215 216 217 218 219 220 221 222 223 224 225 226

	/* done */

	return true;
}

static bool
audio_output_setup(struct audio_output *ao, const struct config_param *param,
		   GError **error_r)
{

	/* create the replay_gain filter */
227

228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
	const char *replay_gain_handler =
		config_get_block_string(param, "replay_gain_handler",
					"software");

	if (strcmp(replay_gain_handler, "none") != 0) {
		ao->replay_gain_filter = filter_new(&replay_gain_filter_plugin,
						    param, NULL);
		assert(ao->replay_gain_filter != NULL);

		ao->replay_gain_serial = 0;

		ao->other_replay_gain_filter = filter_new(&replay_gain_filter_plugin,
							  param, NULL);
		assert(ao->other_replay_gain_filter != NULL);

		ao->other_replay_gain_serial = 0;
	} else {
		ao->replay_gain_filter = NULL;
		ao->other_replay_gain_filter = NULL;
	}

	/* set up the mixer */

	GError *error = NULL;
	ao->mixer = audio_output_load_mixer(ao, param,
					    ao->plugin->mixer_plugin,
254 255 256 257 258 259
					    ao->filter, &error);
	if (ao->mixer == NULL && error != NULL) {
		g_warning("Failed to initialize hardware mixer for '%s': %s",
			  ao->name, error->message);
		g_error_free(error);
	}
260

261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
	/* use the hardware mixer for replay gain? */

	if (strcmp(replay_gain_handler, "mixer") == 0) {
		if (ao->mixer != NULL)
			replay_gain_filter_set_mixer(ao->replay_gain_filter,
						     ao->mixer, 100);
		else
			g_warning("No such mixer for output '%s'", ao->name);
	} else if (strcmp(replay_gain_handler, "software") != 0 &&
		   ao->replay_gain_filter != NULL) {
		g_set_error(error_r, audio_output_quark(), 0,
			    "Invalid \"replay_gain_handler\" value");
		return false;
	}

276 277 278 279 280 281 282
	/* the "convert" filter must be the last one in the chain */

	ao->convert_filter = filter_new(&convert_filter_plugin, NULL, NULL);
	assert(ao->convert_filter != NULL);

	filter_chain_append(ao->filter, ao->convert_filter);

283 284
	return true;
}
285

286 287 288 289 290 291
struct audio_output *
audio_output_new(const struct config_param *param,
		 struct player_control *pc,
		 GError **error_r)
{
	const struct audio_output_plugin *plugin;
292

293 294
	if (param) {
		const char *p;
295

296 297 298 299 300 301
		p = config_get_block_string(param, AUDIO_OUTPUT_TYPE, NULL);
		if (p == NULL) {
			g_set_error(error_r, audio_output_quark(), 0,
				    "Missing \"type\" configuration");
			return false;
		}
302

303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
		plugin = audio_output_plugin_get(p);
		if (plugin == NULL) {
			g_set_error(error_r, audio_output_quark(), 0,
				    "No such audio output plugin: %s", p);
			return false;
		}
	} else {
		g_warning("No \"%s\" defined in config file\n",
			  CONF_AUDIO_OUTPUT);

		plugin = audio_output_detect(error_r);
		if (plugin == NULL)
			return false;

		g_message("Successfully detected a %s audio device",
			  plugin->name);
	}

	struct audio_output *ao = ao_plugin_init(plugin, param, error_r);
	if (ao == NULL)
		return NULL;

	if (!audio_output_setup(ao, param, error_r)) {
		ao_plugin_finish(ao);
		return NULL;
	}

	ao->player_control = pc;
	return ao;
332
}