Main.cxx 14.5 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright 2003-2020 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"
Max Kellermann's avatar
Max Kellermann committed
27
#include "Mapper.hxx"
28
#include "Permission.hxx"
Max Kellermann's avatar
Max Kellermann committed
29
#include "Listen.hxx"
30
#include "client/Config.hxx"
31
#include "client/List.hxx"
32
#include "command/AllCommands.hxx"
33
#include "Partition.hxx"
34
#include "tag/Config.hxx"
35
#include "ReplayGainGlobal.hxx"
36
#include "IdleFlags.hxx"
37
#include "Log.hxx"
38
#include "LogInit.hxx"
Max Kellermann's avatar
Max Kellermann committed
39
#include "input/Init.hxx"
40 41
#include "input/cache/Config.hxx"
#include "input/cache/Manager.hxx"
42
#include "event/Loop.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 "pcm/AudioParser.hxx"
49
#include "pcm/Convert.hxx"
50
#include "unix/SignalHandlers.hxx"
51
#include "thread/Slack.hxx"
52
#include "net/Init.hxx"
53
#include "lib/icu/Init.hxx"
54
#include "config/Check.hxx"
55
#include "config/Data.hxx"
56
#include "config/Param.hxx"
57
#include "config/Path.hxx"
58 59 60
#include "config/Defaults.hxx"
#include "config/Option.hxx"
#include "config/Domain.hxx"
61
#include "config/Parser.hxx"
62
#include "util/RuntimeError.hxx"
63
#include "util/ScopeExit.hxx"
Max Kellermann's avatar
Max Kellermann committed
64

65 66 67 68
#ifdef ENABLE_DAEMON
#include "unix/Daemon.hxx"
#endif

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

81 82 83 84
#ifdef ENABLE_NEIGHBOR_PLUGINS
#include "neighbor/Glue.hxx"
#endif

85
#ifdef ENABLE_SQLITE
86
#include "sticker/Database.hxx"
87 88
#endif

89
#ifdef ENABLE_ARCHIVE
90
#include "archive/ArchiveList.hxx"
91
#endif
Max Kellermann's avatar
Max Kellermann committed
92

Max Kellermann's avatar
Max Kellermann committed
93
#ifdef ANDROID
94 95
#include "java/Global.hxx"
#include "java/File.hxx"
96
#include "android/Environment.hxx"
97
#include "android/Context.hxx"
98
#include "android/LogListener.hxx"
99
#include "config/File.hxx"
100
#include "fs/FileSystem.hxx"
Max Kellermann's avatar
Max Kellermann committed
101 102 103
#include "org_musicpd_Bridge.h"
#endif

104 105
#ifdef ENABLE_DBUS
#include "lib/dbus/Init.hxx"
106 107
#endif

108 109
#ifdef ENABLE_SYSTEMD_DAEMON
#include <systemd/sd-daemon.h>
110 111
#endif

112
#include <climits>
113

114 115
#ifdef HAVE_CLOCALE
#include <clocale>
116 117
#endif

118 119 120 121
static constexpr size_t KILOBYTE = 1024;
static constexpr size_t MEGABYTE = 1024 * KILOBYTE;

static constexpr size_t DEFAULT_BUFFER_SIZE = 4 * MEGABYTE;
122

123
static constexpr
124 125
size_t MIN_BUFFER_SIZE = std::max(CHUNK_SIZE * 32,
				  64 * KILOBYTE);
126

127 128
#ifdef ANDROID
Context *context;
129
LogListener *logListener;
130 131
#endif

132
Instance *global_instance;
133

134
struct Config {
135
	ReplayGainConfig replay_gain;
136

137 138 139
	explicit Config(const ConfigData &raw)
		:replay_gain(LoadReplayGainConfig(raw)) {}
};
140

141
#ifdef ENABLE_DAEMON
142

143
static void
144 145
glue_daemonize_init(const struct options *options,
		    const ConfigData &config)
146
{
147 148 149
	daemonize_init(config.GetString(ConfigOption::USER),
		       config.GetString(ConfigOption::GROUP),
		       config.GetPath(ConfigOption::PID_FILE));
150 151 152 153 154

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

155 156
#endif

157
static void
158
glue_mapper_init(const ConfigData &config)
159
{
160
	mapper_init(config.GetPath(ConfigOption::PLAYLIST_DIR));
161
}
162

163 164
#ifdef ENABLE_DATABASE

165
static void
166 167
InitStorage(Instance &instance, EventLoop &event_loop,
	    const ConfigData &config)
168
{
169
	auto storage = CreateConfiguredStorage(config, event_loop);
170
	if (storage == nullptr)
171
		return;
172

Max Kellermann's avatar
Max Kellermann committed
173
	auto *composite = new CompositeStorage();
174
	instance.storage = composite;
175
	composite->Mount("", std::move(storage));
176 177
}

178 179 180 181 182 183
/**
 * 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
184
glue_db_init_and_load(Instance &instance, const ConfigData &config)
185
{
186 187 188
	auto db = CreateConfiguredDatabase(config, instance.event_loop,
					   instance.io_thread.GetEventLoop(),
					   instance);
189
	if (!db)
190
		return true;
191

192
	if (db->GetPlugin().RequireStorage()) {
193 194
		InitStorage(instance, instance.io_thread.GetEventLoop(),
			    config);
195

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

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

215
	instance.database = std::move(db);
216

217
	auto *sdb = dynamic_cast<SimpleDatabase *>(instance.database.get());
218
	if (sdb == nullptr)
219 220
		return true;

221 222 223 224
	instance.update = new UpdateService(config,
					    instance.event_loop, *sdb,
					    static_cast<CompositeStorage &>(*instance.storage),
					    instance);
225

226
	/* run database update after daemonization? */
227
	return sdb->FileExists();
Warren Dukes's avatar
Warren Dukes committed
228
}
Warren Dukes's avatar
Warren Dukes committed
229

230
static bool
231
InitDatabaseAndStorage(Instance &instance, const ConfigData &config)
232
{
233
	const bool create_db = !glue_db_init_and_load(instance, config);
234 235 236
	return create_db;
}

237 238
#endif

239 240
#ifdef ENABLE_SQLITE

241 242 243
/**
 * Configure and initialize the sticker subsystem.
 */
244 245
static std::unique_ptr<StickerDatabase>
LoadStickerDatabase(const ConfigData &config)
246
{
247
	auto sticker_file = config.GetPath(ConfigOption::STICKER_FILE);
248
	if (sticker_file.IsNull())
249
		return nullptr;
250

251
	return std::make_unique<StickerDatabase>(std::move(sticker_file));
252 253
}

254 255
#endif

256
static void
257
glue_state_file_init(Instance &instance, const ConfigData &raw_config)
258
{
259 260
	StateFileConfig config(raw_config);
	if (!config.IsEnabled())
261
		return;
262

263 264 265
	instance.state_file = std::make_unique< StateFile>(std::move(config),
							   instance.partitions.front(),
							   instance.event_loop);
266
	instance.state_file->Read();
267 268
}

Max Kellermann's avatar
Max Kellermann committed
269 270 271 272
/**
 * Initialize the decoder and player core, including the music pipe.
 */
static void
273 274
initialize_decoder_and_player(Instance &instance,
			      const ConfigData &config,
275
			      const ReplayGainConfig &replay_gain_config)
Max Kellermann's avatar
Max Kellermann committed
276
{
277
	const ConfigParam *param;
Max Kellermann's avatar
Max Kellermann committed
278

279
	size_t buffer_size;
280
	param = config.GetParam(ConfigOption::AUDIO_BUFFER_SIZE);
281
	if (param != nullptr) {
282
		buffer_size = param->With([](const char *s){
283 284
			size_t result = ParseSize(s, KILOBYTE);
			if (result <= 0)
285 286 287 288 289 290 291 292 293 294 295 296
				throw FormatRuntimeError("buffer size \"%s\" is not a "
							 "positive integer", s);

			if (result < MIN_BUFFER_SIZE) {
				FormatWarning(config_domain, "buffer size %lu is too small, using %lu bytes instead",
					      (unsigned long)result,
					      (unsigned long)MIN_BUFFER_SIZE);
				result = MIN_BUFFER_SIZE;
			}

			return result;
		});
Max Kellermann's avatar
Max Kellermann committed
297 298 299
	} else
		buffer_size = DEFAULT_BUFFER_SIZE;

300
	const unsigned buffered_chunks = buffer_size / CHUNK_SIZE;
Max Kellermann's avatar
Max Kellermann committed
301 302

	if (buffered_chunks >= 1 << 15)
303 304
		throw FormatRuntimeError("buffer size \"%lu\" is too big",
					 (unsigned long)buffer_size);
Max Kellermann's avatar
Max Kellermann committed
305

306
	const unsigned max_length =
307 308
		config.GetPositive(ConfigOption::MAX_PLAYLIST_LENGTH,
				   DEFAULT_PLAYLIST_MAX_LENGTH);
309

310 311 312 313 314 315
	AudioFormat configured_audio_format = config.With(ConfigOption::AUDIO_OUTPUT_FORMAT, [](const char *s){
		if (s == nullptr)
			return AudioFormat::Undefined();

		return ParseAudioFormat(s, true);
	});
316

317 318 319 320 321 322 323
	instance.partitions.emplace_back(instance,
					 "default",
					 max_length,
					 buffered_chunks,
					 configured_audio_format,
					 replay_gain_config);
	auto &partition = instance.partitions.back();
324

325 326 327 328 329
	partition.replay_gain_mode = config.With(ConfigOption::REPLAYGAIN, [](const char *s){
		return s != nullptr
			? FromString(s)
			: ReplayGainMode::OFF;
	});
Max Kellermann's avatar
Max Kellermann committed
330 331
}

332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
inline void
Instance::BeginShutdownUpdate() noexcept
{
#ifdef ENABLE_DATABASE
#ifdef ENABLE_INOTIFY
	mpd_inotify_finish();
#endif

	if (update != nullptr)
		update->CancelAllAsync();
#endif
}

inline void
Instance::BeginShutdownPartitions() noexcept
{
348
	for (auto &partition : partitions) {
349
		partition.BeginShutdown();
350
	}
351 352
}

353
static inline void
354
MainConfigured(const struct options &options, const ConfigData &raw_config)
355
{
356
#ifdef ENABLE_DAEMON
357
	daemonize_close_stdin();
358
#endif
359

360
#ifndef ANDROID
361
#ifdef HAVE_CLOCALE
362
	/* initialize locale */
363 364
	std::setlocale(LC_CTYPE,"");
	std::setlocale(LC_COLLATE, "");
365
#endif
366
#endif
Max Kellermann's avatar
Max Kellermann committed
367

368
	const ScopeIcuInit icu_init;
369 370
	const ScopeNetInit net_init;

371 372 373 374
#ifdef ENABLE_DBUS
	const ODBus::ScopeInit dbus_init;
#endif

375
	InitPathParser(raw_config);
376
	const Config config(raw_config);
377

378
#ifdef ENABLE_DAEMON
379
	glue_daemonize_init(&options, raw_config);
380
#endif
381

382
	TagLoadConfig(raw_config);
383

384
	log_init(raw_config, options.verbose, options.log_stderr);
385

386 387
	Instance instance;
	global_instance = &instance;
388

389
#ifdef ENABLE_NEIGHBOR_PLUGINS
390 391 392 393
	instance.neighbors = std::make_unique<NeighborGlue>();
	instance.neighbors->Init(raw_config,
				 instance.io_thread.GetEventLoop(),
				 instance);
394

395 396
	if (instance.neighbors->IsEmpty())
		instance.neighbors.reset();
397 398
#endif

399
	const unsigned max_clients =
400
		raw_config.GetPositive(ConfigOption::MAX_CONN, 100);
401
	instance.client_list = std::make_unique<ClientList>(max_clients);
402

403 404 405 406 407 408
	const auto *input_cache_config = raw_config.GetBlock(ConfigBlockOption::INPUT_CACHE);
	if (input_cache_config != nullptr) {
		const InputCacheConfig c(*input_cache_config);
		instance.input_cache = std::make_unique<InputCacheManager>(c);
	}

409 410
	initialize_decoder_and_player(instance,
				      raw_config, config.replay_gain);
411

412
	listen_global_init(raw_config, *instance.partitions.front().listener);
413

414
#ifdef ENABLE_DAEMON
415
	daemonize_set_user();
416
	daemonize_begin(options.daemon);
417
	AtScopeExit() { daemonize_finish(); };
418
#endif
Warren Dukes's avatar
Warren Dukes committed
419

420
	ConfigureFS(raw_config);
421
	AtScopeExit() { DeinitFS(); };
422

423
	glue_mapper_init(raw_config);
424

425
	initPermissions(raw_config);
426
	spl_global_init(raw_config);
427
#ifdef ENABLE_ARCHIVE
428
	const ScopeArchivePluginsInit archive_plugins_init;
429
#endif
430

431
	pcm_convert_global_init(raw_config);
432

433
	const ScopeDecoderPluginsInit decoder_plugins_init(raw_config);
434

435
#ifdef ENABLE_DATABASE
436
	const bool create_db = InitDatabaseAndStorage(instance, raw_config);
437
#endif
438

439
#ifdef ENABLE_SQLITE
440
	instance.sticker_database = LoadStickerDatabase(raw_config);
441
#endif
442

Max Kellermann's avatar
Max Kellermann committed
443
	command_init();
444

445 446
	for (auto &partition : instance.partitions) {
		partition.outputs.Configure(instance.rtio_thread.GetEventLoop(),
447
					    raw_config,
448
					    config.replay_gain);
449 450
		partition.UpdateEffectiveReplayGainMode();
	}
451

452
	client_manager_init(raw_config);
453
	const ScopeInputPluginsInit input_plugins_init(raw_config,
454
						       instance.io_thread.GetEventLoop());
455

456
	const ScopePlaylistPluginsInit playlist_plugins_init(raw_config);
457

458
#ifdef ENABLE_DAEMON
459
	daemonize_commit();
460
#endif
461

462
#ifndef ANDROID
463
	setup_log_output();
Warren Dukes's avatar
Warren Dukes committed
464

465
	const ScopeSignalHandlersInit signal_handlers_init(instance);
466
#endif
467

468 469
	instance.io_thread.Start();
	instance.rtio_thread.Start();
470

471
#ifdef ENABLE_NEIGHBOR_PLUGINS
472 473
	if (instance.neighbors != nullptr)
		instance.neighbors->Open();
474

475 476 477
	AtScopeExit(&instance) {
		if (instance.neighbors != nullptr)
			instance.neighbors->Close();
478
	};
479 480
#endif

481
	ZeroconfInit(raw_config, instance.event_loop);
482

483
#ifdef ENABLE_DATABASE
484
	if (create_db) {
485 486
		/* the database failed to load: recreate the
		   database */
487
		instance.update->Enqueue("", true);
488
	}
489
#endif
490

491
	glue_state_file_init(instance, raw_config);
492

493
#ifdef ENABLE_DATABASE
494
	if (raw_config.GetBool(ConfigOption::AUTO_UPDATE, false)) {
495
#ifdef ENABLE_INOTIFY
496 497 498 499 500
		if (instance.storage != nullptr &&
		    instance.update != nullptr)
			mpd_inotify_init(instance.event_loop,
					 *instance.storage,
					 *instance.update,
501 502
					 raw_config.GetUnsigned(ConfigOption::AUTO_UPDATE_DEPTH,
								INT_MAX));
503
#else
504
		FormatWarning(config_domain,
505
			      "inotify: auto_update was disabled. enable during compilation phase");
506
#endif
507
	}
508
#endif
509

510
	Check(raw_config);
511

512 513
	/* enable all audio outputs (if not already done by
	   playlist_state_restore() */
514
	for (auto &partition : instance.partitions)
515
		partition.pc.LockUpdateAudio();
516

517
#ifdef _WIN32
518 519
	win32_app_started();
#endif
520

521 522
	/* the MPD frontend does not care about timer slack; set it to
	   a huge value to allow the kernel to reduce CPU wakeups */
523
	SetThreadTimerSlack(std::chrono::milliseconds(100));
524

525 526 527 528
#ifdef ENABLE_SYSTEMD_DAEMON
	sd_notify(0, "READY=1");
#endif

529
	/* run the main loop */
530
	instance.event_loop.Run();
531

532
#ifdef _WIN32
533 534 535
	win32_app_stopping();
#endif

536 537
	/* cleanup */

538
	instance.BeginShutdownUpdate();
539

540 541
	ZeroconfDeinit();

542
	instance.BeginShutdownPartitions();
Warren Dukes's avatar
Warren Dukes committed
543
}
Max Kellermann's avatar
Max Kellermann committed
544 545 546

#ifdef ANDROID

547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
static void
AndroidMain()
{
	struct options options;
	ConfigData raw_config;

	const auto sdcard = Environment::getExternalStorageDirectory();
	if (!sdcard.IsNull()) {
		const auto config_path =
			sdcard / Path::FromFS("mpd.conf");
		if (FileExists(config_path))
			ReadConfigFile(raw_config, config_path);
	}

	MainConfigured(options, raw_config);
}

Max Kellermann's avatar
Max Kellermann committed
564 565
gcc_visibility_default
JNIEXPORT void JNICALL
566
Java_org_musicpd_Bridge_run(JNIEnv *env, jclass, jobject _context, jobject _logListener)
Max Kellermann's avatar
Max Kellermann committed
567
{
568
	Java::Init(env);
569
	Java::Object::Initialise(env);
570
	Java::File::Initialise(env);
571
	Environment::Initialise(env);
572
	AtScopeExit(env) { Environment::Deinitialise(env); };
573

574
	context = new Context(env, _context);
575 576
	AtScopeExit() { delete context; };

577 578
	if (_logListener != nullptr)
		logListener = new LogListener(env, _logListener);
579
	AtScopeExit() { delete logListener; };
580

581 582 583 584 585
	try {
		AndroidMain();
	} catch (...) {
		LogError(std::current_exception());
	}
Max Kellermann's avatar
Max Kellermann committed
586 587
}

588 589 590 591
gcc_visibility_default
JNIEXPORT void JNICALL
Java_org_musicpd_Bridge_shutdown(JNIEnv *, jclass)
{
592 593
	if (global_instance != nullptr)
		global_instance->Break();
594 595
}

596 597
#else

598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
static inline void
MainOrThrow(int argc, char *argv[])
{
	struct options options;
	ConfigData raw_config;

	ParseCommandLine(argc, argv, options, raw_config);

	MainConfigured(options, raw_config);
}

int mpd_main(int argc, char *argv[]) noexcept
{
	AtScopeExit() { log_deinit(); };

	try {
		MainOrThrow(argc, argv);
		return EXIT_SUCCESS;
	} catch (...) {
		LogError(std::current_exception());
		return EXIT_FAILURE;
	}
}

622 623 624 625 626 627 628 629 630 631
int
main(int argc, char *argv[]) noexcept
{
#ifdef _WIN32
	return win32_main(argc, argv);
#else
	return mpd_main(argc, argv);
#endif
}

Max Kellermann's avatar
Max Kellermann committed
632
#endif