Main.cxx 15.4 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright 2003-2017 The Music Player Daemon Project
3
 * http://www.musicpd.org
Warren Dukes's avatar
Warren Dukes committed
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.
Warren Dukes's avatar
Warren Dukes committed
18 19
 */

20
#include "config.h"
Max Kellermann's avatar
Max Kellermann committed
21
#include "Main.hxx"
22
#include "Instance.hxx"
Max Kellermann's avatar
Max Kellermann committed
23
#include "CommandLine.hxx"
Max Kellermann's avatar
Max Kellermann committed
24
#include "PlaylistFile.hxx"
25
#include "MusicChunk.hxx"
26
#include "StateFile.hxx"
27
#include "player/Thread.hxx"
Max Kellermann's avatar
Max Kellermann committed
28
#include "Mapper.hxx"
29
#include "Permission.hxx"
Max Kellermann's avatar
Max Kellermann committed
30
#include "Listen.hxx"
31 32
#include "client/Client.hxx"
#include "client/ClientList.hxx"
33
#include "command/AllCommands.hxx"
34
#include "Partition.hxx"
35
#include "tag/TagConfig.hxx"
36
#include "ReplayGainGlobal.hxx"
Max Kellermann's avatar
Max Kellermann committed
37
#include "Idle.hxx"
38
#include "Log.hxx"
39
#include "LogInit.hxx"
Max Kellermann's avatar
Max Kellermann committed
40
#include "input/Init.hxx"
41
#include "event/Loop.hxx"
42
#include "IOThread.hxx"
43
#include "fs/AllocatedPath.hxx"
44
#include "fs/Config.hxx"
45
#include "playlist/PlaylistRegistry.hxx"
46
#include "zeroconf/ZeroconfGlue.hxx"
47
#include "decoder/DecoderList.hxx"
48
#include "AudioParser.hxx"
49
#include "pcm/PcmConvert.hxx"
50
#include "unix/SignalHandlers.hxx"
51
#include "system/FatalError.hxx"
52
#include "thread/Slack.hxx"
53
#include "net/Init.hxx"
54
#include "lib/icu/Init.hxx"
55
#include "config/ConfigGlobal.hxx"
56
#include "config/Param.hxx"
57 58
#include "config/ConfigDefaults.hxx"
#include "config/ConfigOption.hxx"
59
#include "config/ConfigError.hxx"
60
#include "util/RuntimeError.hxx"
Max Kellermann's avatar
Max Kellermann committed
61

62 63 64 65
#ifdef ENABLE_DAEMON
#include "unix/Daemon.hxx"
#endif

66 67
#ifdef ENABLE_DATABASE
#include "db/update/Service.hxx"
68
#include "db/Configured.hxx"
69
#include "db/DatabasePlugin.hxx"
70
#include "db/plugins/simple/SimpleDatabasePlugin.hxx"
71
#include "storage/Configured.hxx"
72
#include "storage/CompositeStorage.hxx"
73 74 75
#ifdef ENABLE_INOTIFY
#include "db/update/InotifyUpdate.hxx"
#endif
76 77
#endif

78 79 80 81
#ifdef ENABLE_NEIGHBOR_PLUGINS
#include "neighbor/Glue.hxx"
#endif

82
#ifdef ENABLE_SQLITE
83
#include "sticker/StickerDatabase.hxx"
84 85
#endif

86
#ifdef ENABLE_ARCHIVE
87
#include "archive/ArchiveList.hxx"
88
#endif
Max Kellermann's avatar
Max Kellermann committed
89

Max Kellermann's avatar
Max Kellermann committed
90
#ifdef ANDROID
91 92
#include "java/Global.hxx"
#include "java/File.hxx"
93
#include "android/Environment.hxx"
94
#include "android/Context.hxx"
95
#include "fs/StandardDirectory.hxx"
96
#include "fs/FileSystem.hxx"
Max Kellermann's avatar
Max Kellermann committed
97 98 99
#include "org_musicpd_Bridge.h"
#endif

100 101 102 103
#ifdef ENABLE_SYSTEMD_DAEMON
#include <systemd/sd-daemon.h>
#endif

Max Kellermann's avatar
Max Kellermann committed
104
#include <stdlib.h>
105

106
#ifdef HAVE_LOCALE_H
107 108 109
#include <locale.h>
#endif

110 111
#include <limits.h>

112 113 114 115
static constexpr size_t KILOBYTE = 1024;
static constexpr size_t MEGABYTE = 1024 * KILOBYTE;

static constexpr size_t DEFAULT_BUFFER_SIZE = 4 * MEGABYTE;
116 117 118 119 120 121 122 123 124 125

static
#if GCC_OLDER_THAN(5,0)
/* gcc 4.x has no "constexpr" for std::max() */
const
#else
constexpr
#endif
size_t MIN_BUFFER_SIZE = std::max(CHUNK_SIZE * 32,
				  64 * KILOBYTE);
126

127
static constexpr unsigned DEFAULT_BUFFER_BEFORE_PLAY = 10;
Max Kellermann's avatar
Max Kellermann committed
128

129 130 131 132
#ifdef ANDROID
Context *context;
#endif

133
Instance *instance;
134

135
struct Config {
136
	ReplayGainConfig replay_gain;
137 138 139 140 141
};

static Config
LoadConfig()
{
142
	return {LoadReplayGainConfig()};
143 144
}

145
#ifdef ENABLE_DAEMON
146

147 148
static void
glue_daemonize_init(const struct options *options)
149
{
150 151
	daemonize_init(config_get_string(ConfigOption::USER, nullptr),
		       config_get_string(ConfigOption::GROUP, nullptr),
152
		       config_get_path(ConfigOption::PID_FILE));
153 154 155 156 157

	if (options->kill)
		daemonize_kill();
}

158 159
#endif

160 161
static void
glue_mapper_init()
162
{
163
	mapper_init(config_get_path(ConfigOption::PLAYLIST_DIR));
164
}
165

166 167
#ifdef ENABLE_DATABASE

168 169
static void
InitStorage()
170
{
171
	Storage *storage = CreateConfiguredStorage(io_thread_get());
172
	if (storage == nullptr)
173
		return;
174 175 176 177

	CompositeStorage *composite = new CompositeStorage();
	instance->storage = composite;
	composite->Mount("", storage);
178 179
}

180 181 182 183 184 185
/**
 * Returns the database.  If this function returns false, this has not
 * succeeded, and the caller should create the database after the
 * process has been daemonized.
 */
static bool
186
glue_db_init_and_load(void)
187
{
188
	instance->database =
189 190 191
		CreateConfiguredDatabase(instance->event_loop, *instance);
	if (instance->database == nullptr)
		return true;
192

193
	if (instance->database->GetPlugin().flags & DatabasePlugin::FLAG_REQUIRE_STORAGE) {
194
		InitStorage();
195

196 197 198 199 200 201 202 203 204 205 206 207 208
		if (instance->storage == nullptr) {
			delete instance->database;
			instance->database = nullptr;
			LogDefault(config_domain,
				   "Found database setting without "
				   "music_directory - disabling database");
			return true;
		}
	} else {
		if (IsStorageConfigured())
			LogDefault(config_domain,
				   "Ignoring the storage configuration "
				   "because the database does not need it");
209 210
	}

211 212 213 214 215
	try {
		instance->database->Open();
	} catch (...) {
		std::throw_with_nested(std::runtime_error("Failed to open database plugin"));
	}
216

217
	if (!instance->database->IsPlugin(simple_db_plugin))
218 219
		return true;

220
	SimpleDatabase &db = *(SimpleDatabase *)instance->database;
221
	instance->update = new UpdateService(instance->event_loop, db,
Max Kellermann's avatar
Max Kellermann committed
222
					     static_cast<CompositeStorage &>(*instance->storage),
223
					     *instance);
224

225
	/* run database update after daemonization? */
226
	return db.FileExists();
Warren Dukes's avatar
Warren Dukes committed
227
}
Warren Dukes's avatar
Warren Dukes committed
228

229 230 231 232 233 234 235
static bool
InitDatabaseAndStorage()
{
	const bool create_db = !glue_db_init_and_load();
	return create_db;
}

236 237
#endif

238 239 240 241
/**
 * Configure and initialize the sticker subsystem.
 */
static void
242
glue_sticker_init()
243 244
{
#ifdef ENABLE_SQLITE
245 246
	auto sticker_file = config_get_path(ConfigOption::STICKER_FILE);
	if (sticker_file.IsNull())
247
		return;
248

249
	sticker_global_init(std::move(sticker_file));
250 251 252
#endif
}

253 254
static void
glue_state_file_init()
255
{
256
	auto path_fs = config_get_path(ConfigOption::STATE_FILE);
257 258 259 260
	if (path_fs.IsNull()) {
#ifdef ANDROID
		const auto cache_dir = GetUserCacheDir();
		if (cache_dir.IsNull())
261
			return;
262 263 264

		path_fs = AllocatedPath::Build(cache_dir, "state");
#else
265
		return;
266 267
#endif
	}
268

269
	const auto interval =
270 271
		config_get_unsigned(ConfigOption::STATE_FILE_INTERVAL,
				    StateFile::DEFAULT_INTERVAL);
272

273 274 275 276
	instance->state_file = new StateFile(std::move(path_fs), interval,
					     *instance->partition,
					     instance->event_loop);
	instance->state_file->Read();
277 278
}

Max Kellermann's avatar
Max Kellermann committed
279 280 281 282
/**
 * Initialize the decoder and player core, including the music pipe.
 */
static void
283
initialize_decoder_and_player(const ReplayGainConfig &replay_gain_config)
Max Kellermann's avatar
Max Kellermann committed
284
{
285
	const ConfigParam *param;
Max Kellermann's avatar
Max Kellermann committed
286

287
	size_t buffer_size;
288
	param = config_get_param(ConfigOption::AUDIO_BUFFER_SIZE);
289
	if (param != nullptr) {
290
		char *test;
291
		long tmp = strtol(param->value.c_str(), &test, 10);
292
		if (*test != '\0' || tmp <= 0 || tmp == LONG_MAX)
293 294
			FormatFatalError("buffer size \"%s\" is not a "
					 "positive integer, line %i",
295
					 param->value.c_str(), param->line);
296
		buffer_size = tmp * KILOBYTE;
297 298 299 300 301 302 303

		if (buffer_size < MIN_BUFFER_SIZE) {
			FormatWarning(config_domain, "buffer size %lu is too small, using %lu bytes instead",
				      (unsigned long)buffer_size,
				      (unsigned long)MIN_BUFFER_SIZE);
			buffer_size = MIN_BUFFER_SIZE;
		}
Max Kellermann's avatar
Max Kellermann committed
304 305 306
	} else
		buffer_size = DEFAULT_BUFFER_SIZE;

307
	const unsigned buffered_chunks = buffer_size / CHUNK_SIZE;
Max Kellermann's avatar
Max Kellermann committed
308 309

	if (buffered_chunks >= 1 << 15)
310 311
		FormatFatalError("buffer size \"%lu\" is too big",
				 (unsigned long)buffer_size);
Max Kellermann's avatar
Max Kellermann committed
312

313
	float perc;
314
	param = config_get_param(ConfigOption::BUFFER_BEFORE_PLAY);
315
	if (param != nullptr) {
316
		char *test;
317
		perc = strtod(param->value.c_str(), &test);
Max Kellermann's avatar
Max Kellermann committed
318
		if (*test != '%' || perc < 0 || perc > 100) {
319 320 321
			FormatFatalError("buffered before play \"%s\" is not "
					 "a positive percentage and less "
					 "than 100 percent, line %i",
322
					 param->value.c_str(), param->line);
Max Kellermann's avatar
Max Kellermann committed
323
		}
324 325 326 327 328 329 330 331 332 333 334 335 336

		if (perc > 80) {
			/* this upper limit should avoid deadlocks
			   which can occur because the DecoderThread
			   cannot ever fill the music buffer to
			   exactly 100%; a few chunks always need to
			   be available to generate silence in
			   Player::SendSilence() */
			FormatError(config_domain,
				    "buffer_before_play is too large (%f%%), capping at 80%%; please fix your configuration",
				    perc);
			perc = 80;
		}
Max Kellermann's avatar
Max Kellermann committed
337 338 339
	} else
		perc = DEFAULT_BUFFER_BEFORE_PLAY;

340
	unsigned buffered_before_play = (perc / 100) * buffered_chunks;
Max Kellermann's avatar
Max Kellermann committed
341 342 343
	if (buffered_before_play > buffered_chunks)
		buffered_before_play = buffered_chunks;

344
	const unsigned max_length =
345
		config_get_positive(ConfigOption::MAX_PLAYLIST_LENGTH,
346 347
				    DEFAULT_PLAYLIST_MAX_LENGTH);

348 349 350 351 352 353 354 355 356 357 358 359
	AudioFormat configured_audio_format = AudioFormat::Undefined();
	param = config_get_param(ConfigOption::AUDIO_OUTPUT_FORMAT);
	if (param != nullptr) {
		try {
			configured_audio_format = ParseAudioFormat(param->value.c_str(),
								   true);
		} catch (const std::runtime_error &) {
			std::throw_with_nested(FormatRuntimeError("error parsing line %i",
								  param->line));
		}
	}

360 361 362
	instance->partition = new Partition(*instance,
					    max_length,
					    buffered_chunks,
363
					    buffered_before_play,
364
					    configured_audio_format,
365
					    replay_gain_config);
366 367 368 369 370 371 372 373 374 375

	try {
		param = config_get_param(ConfigOption::REPLAYGAIN);
		if (param != nullptr)
			instance->partition->replay_gain_mode =
				FromString(param->value.c_str());
	} catch (...) {
		std::throw_with_nested(FormatRuntimeError("Failed to parse line %i",
							  param->line));
	}
Max Kellermann's avatar
Max Kellermann committed
376 377
}

378 379
void
Instance::OnIdle(unsigned flags)
380
{
Max Kellermann's avatar
Max Kellermann committed
381
	/* send "idle" notifications to all subscribed
382
	   clients */
383
	client_list->IdleAdd(flags);
384

385
	if (flags & (IDLE_PLAYLIST|IDLE_PLAYER|IDLE_MIXER|IDLE_OUTPUT) &&
386 387
	    state_file != nullptr)
		state_file->CheckModified();
388 389
}

Max Kellermann's avatar
Max Kellermann committed
390 391
#ifndef ANDROID

392
int main(int argc, char *argv[])
393
{
394
#ifdef _WIN32
395 396 397 398 399 400
	return win32_main(argc, argv);
#else
	return mpd_main(argc, argv);
#endif
}

Max Kellermann's avatar
Max Kellermann committed
401 402
#endif

403
static int
404
mpd_main_after_fork(const Config &config);
405

406 407 408
#ifdef ANDROID
static inline
#endif
409
int mpd_main(int argc, char *argv[])
410
try {
Max Kellermann's avatar
Max Kellermann committed
411
	struct options options;
Warren Dukes's avatar
Warren Dukes committed
412

413
#ifdef ENABLE_DAEMON
414
	daemonize_close_stdin();
415
#endif
416

417
#ifndef ANDROID
418
#ifdef HAVE_LOCALE_H
419 420
	/* initialize locale */
	setlocale(LC_CTYPE,"");
421
	setlocale(LC_COLLATE, "");
422
#endif
423
#endif
Max Kellermann's avatar
Max Kellermann committed
424

425
	IcuInit();
426

427 428
	const ScopeNetInit net_init;

429
	io_thread_init();
430
	config_global_init();
Warren Dukes's avatar
Warren Dukes committed
431

432
#ifdef ANDROID
433 434 435 436 437 438 439 440 441 442
	(void)argc;
	(void)argv;

	const auto sdcard = Environment::getExternalStorageDirectory();
	if (!sdcard.IsNull()) {
		const auto config_path =
			AllocatedPath::Build(sdcard, "mpd.conf");
		if (FileExists(config_path))
			ReadConfigFile(config_path);
	}
443
#else
444
	ParseCommandLine(argc, argv, &options);
445
#endif
Warren Dukes's avatar
Warren Dukes committed
446

447 448
	const auto config = LoadConfig();

449
#ifdef ENABLE_DAEMON
450
	glue_daemonize_init(&options);
451
#endif
452

453
	TagLoadConfig();
454

455
	log_init(options.verbose, options.log_stderr);
456

457 458
	instance = new Instance();

459 460
#ifdef ENABLE_NEIGHBOR_PLUGINS
	instance->neighbors = new NeighborGlue();
461
	instance->neighbors->Init(io_thread_get(), *instance);
462 463 464 465 466 467 468

	if (instance->neighbors->IsEmpty()) {
		delete instance->neighbors;
		instance->neighbors = nullptr;
	}
#endif

469 470
	const unsigned max_clients =
		config_get_positive(ConfigOption::MAX_CONN, 10);
471
	instance->client_list = new ClientList(max_clients);
472

473
	initialize_decoder_and_player(config.replay_gain);
474

475
	listen_global_init(instance->event_loop, *instance->partition);
476

477
#ifdef ENABLE_DAEMON
478
	daemonize_set_user();
479
	daemonize_begin(options.daemon);
480
#endif
Warren Dukes's avatar
Warren Dukes committed
481

482
	return mpd_main_after_fork(config);
483

484 485 486
} catch (const std::exception &e) {
	LogError(e);
	return EXIT_FAILURE;
487 488
}

489
static int
490
mpd_main_after_fork(const Config &config)
491
try {
492
	ConfigureFS();
493

494
	glue_mapper_init();
495

496
	initPermissions();
497
	spl_global_init();
498
#ifdef ENABLE_ARCHIVE
499
	archive_plugin_init_all();
500
#endif
501

502
	pcm_convert_global_init();
503

504
	decoder_plugin_init_all();
505

506
#ifdef ENABLE_DATABASE
507
	const bool create_db = InitDatabaseAndStorage();
508
#endif
509

510
	glue_sticker_init();
511

Max Kellermann's avatar
Max Kellermann committed
512
	command_init();
513

514
	instance->partition->outputs.Configure(instance->event_loop,
515
					       config.replay_gain,
516
					       instance->partition->pc);
517 518
	instance->partition->UpdateEffectiveReplayGainMode();

519
	client_manager_init();
520
	input_stream_global_init();
521
	playlist_list_global_init();
522

523
#ifdef ENABLE_DAEMON
524
	daemonize_commit();
525
#endif
526

527
#ifndef ANDROID
528
	setup_log_output();
Warren Dukes's avatar
Warren Dukes committed
529

530
	SignalHandlersInit(instance->event_loop);
531
#endif
532

533
	io_thread_start();
534

535
#ifdef ENABLE_NEIGHBOR_PLUGINS
536 537
	if (instance->neighbors != nullptr)
		instance->neighbors->Open();
538 539
#endif

540
	ZeroconfInit(instance->event_loop);
541

542
	StartPlayerThread(instance->partition->pc);
543

544
#ifdef ENABLE_DATABASE
545
	if (create_db) {
546 547
		/* the database failed to load: recreate the
		   database */
548
		unsigned job = instance->update->Enqueue("", true);
549
		if (job == 0)
550
			FatalError("directory update failed");
551
	}
552
#endif
553

554
	glue_state_file_init();
555

556
#ifdef ENABLE_DATABASE
557
	if (config_get_bool(ConfigOption::AUTO_UPDATE, false)) {
558
#ifdef ENABLE_INOTIFY
559
		if (instance->storage != nullptr &&
560
		    instance->update != nullptr)
561
			mpd_inotify_init(instance->event_loop,
562 563
					 *instance->storage,
					 *instance->update,
564
					 config_get_unsigned(ConfigOption::AUTO_UPDATE_DEPTH,
565
							     INT_MAX));
566
#else
567
		FormatWarning(config_domain,
568
			      "inotify: auto_update was disabled. enable during compilation phase");
569
#endif
570
	}
571
#endif
572

573 574
	config_global_check();

575 576
	/* enable all audio outputs (if not already done by
	   playlist_state_restore() */
577
	instance->partition->pc.LockUpdateAudio();
578

579
#ifdef _WIN32
580 581
	win32_app_started();
#endif
582

583 584 585 586
	/* the MPD frontend does not care about timer slack; set it to
	   a huge value to allow the kernel to reduce CPU wakeups */
	SetThreadTimerSlackMS(100);

587 588 589 590
#ifdef ENABLE_SYSTEMD_DAEMON
	sd_notify(0, "READY=1");
#endif

591
	/* run the main loop */
592
	instance->event_loop.Run();
593

594
#ifdef _WIN32
595 596 597
	win32_app_stopping();
#endif

598 599
	/* cleanup */

600
#if defined(ENABLE_DATABASE) && defined(ENABLE_INOTIFY)
601
	mpd_inotify_finish();
602 603 604

	if (instance->update != nullptr)
		instance->update->CancelAllAsync();
605
#endif
606

607 608 609
	if (instance->state_file != nullptr) {
		instance->state_file->Write();
		delete instance->state_file;
610 611
	}

612
	instance->partition->pc.Kill();
613
	ZeroconfDeinit();
Max Kellermann's avatar
Max Kellermann committed
614
	listen_global_finish();
615
	delete instance->client_list;
616

617 618 619 620 621 622 623
#ifdef ENABLE_NEIGHBOR_PLUGINS
	if (instance->neighbors != nullptr) {
		instance->neighbors->Close();
		delete instance->neighbors;
	}
#endif

624
#ifdef ENABLE_DATABASE
625
	delete instance->update;
626 627 628 629 630

	if (instance->database != nullptr) {
		instance->database->Close();
		delete instance->database;
	}
631 632

	delete instance->storage;
633
#endif
634

635 636 637 638
#ifdef ENABLE_SQLITE
	sticker_global_finish();
#endif

639
	playlist_list_global_finish();
640
	input_stream_global_finish();
641 642

#ifdef ENABLE_DATABASE
643
	mapper_finish();
644 645
#endif

646 647
	DeinitFS();

648
	delete instance->partition;
Max Kellermann's avatar
Max Kellermann committed
649
	command_finish();
650
	decoder_plugin_deinit_all();
651
#ifdef ENABLE_ARCHIVE
652
	archive_plugin_deinit_all();
653
#endif
654
	config_global_finish();
655
	io_thread_deinit();
656
#ifndef ANDROID
657
	SignalHandlersFinish();
658
#endif
659
	delete instance;
660
	instance = nullptr;
661 662

#ifdef ENABLE_DAEMON
663
	daemonize_finish();
664
#endif
665

666
	IcuFinish();
667

668
	log_deinit();
669
	return EXIT_SUCCESS;
670 671 672
} catch (const std::exception &e) {
	LogError(e);
	return EXIT_FAILURE;
Warren Dukes's avatar
Warren Dukes committed
673
}
Max Kellermann's avatar
Max Kellermann committed
674 675 676 677 678

#ifdef ANDROID

gcc_visibility_default
JNIEXPORT void JNICALL
679
Java_org_musicpd_Bridge_run(JNIEnv *env, jclass, jobject _context)
Max Kellermann's avatar
Max Kellermann committed
680
{
681 682
	Java::Init(env);
	Java::File::Initialise(env);
683
	Environment::Initialise(env);
684

685 686
	context = new Context(env, _context);

Max Kellermann's avatar
Max Kellermann committed
687
	mpd_main(0, nullptr);
688

689
	delete context;
690
	Environment::Deinitialise(env);
Max Kellermann's avatar
Max Kellermann committed
691 692
}

693 694 695 696 697
gcc_visibility_default
JNIEXPORT void JNICALL
Java_org_musicpd_Bridge_shutdown(JNIEnv *, jclass)
{
	if (instance != nullptr)
698
		instance->Shutdown();
699 700
}

Max Kellermann's avatar
Max Kellermann committed
701
#endif