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

Max Kellermann's avatar
Max Kellermann committed
112
#include <stdlib.h>
113

114
#ifdef HAVE_LOCALE_H
115 116 117
#include <locale.h>
#endif

118
#include <climits>
119

120 121 122 123
static constexpr size_t KILOBYTE = 1024;
static constexpr size_t MEGABYTE = 1024 * KILOBYTE;

static constexpr size_t DEFAULT_BUFFER_SIZE = 4 * MEGABYTE;
124

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

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

134
Instance *global_instance;
135

136
struct Config {
137
	ReplayGainConfig replay_gain;
138

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

143
#ifdef ENABLE_DAEMON
144

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

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

157 158
#endif

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

165 166
#ifdef ENABLE_DATABASE

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

Max Kellermann's avatar
Max Kellermann committed
175
	auto *composite = new CompositeStorage();
176
	instance.storage = composite;
177
	composite->Mount("", std::move(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(Instance &instance, const ConfigData &config)
187
{
188 189 190
	auto db = CreateConfiguredDatabase(config, instance.event_loop,
					   instance.io_thread.GetEventLoop(),
					   instance);
191
	if (!db)
192
		return true;
193

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

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

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

217
	instance.database = std::move(db);
218

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

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

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

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

239 240
#endif

241 242
#ifdef ENABLE_SQLITE

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

253
	return std::make_unique<StickerDatabase>(std::move(sticker_file));
254 255
}

256 257
#endif

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

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

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

281
	size_t buffer_size;
282
	param = config.GetParam(ConfigOption::AUDIO_BUFFER_SIZE);
283
	if (param != nullptr) {
284
		buffer_size = param->With([](const char *s){
285 286
			size_t result = ParseSize(s, KILOBYTE);
			if (result <= 0)
287 288 289 290 291 292 293 294 295 296 297 298
				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
299 300 301
	} else
		buffer_size = DEFAULT_BUFFER_SIZE;

302
	const unsigned buffered_chunks = buffer_size / CHUNK_SIZE;
Max Kellermann's avatar
Max Kellermann committed
303 304

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

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

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

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

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

327 328 329 330 331
	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
332 333
}

334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
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
{
350
	for (auto &partition : partitions) {
351
		partition.BeginShutdown();
352
	}
353 354
}

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

362
#ifndef ANDROID
363
#ifdef HAVE_LOCALE_H
364 365
	/* initialize locale */
	setlocale(LC_CTYPE,"");
366
	setlocale(LC_COLLATE, "");
367
#endif
368
#endif
Max Kellermann's avatar
Max Kellermann committed
369

370
	const ScopeIcuInit icu_init;
371 372
	const ScopeNetInit net_init;

373 374 375 376
#ifdef ENABLE_DBUS
	const ODBus::ScopeInit dbus_init;
#endif

377
	InitPathParser(raw_config);
378
	const Config config(raw_config);
379

380
#ifdef ENABLE_DAEMON
381
	glue_daemonize_init(&options, raw_config);
382
#endif
383

384
	TagLoadConfig(raw_config);
385

386
	log_init(raw_config, options.verbose, options.log_stderr);
387

388 389
	Instance instance;
	global_instance = &instance;
390

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

397 398
	if (instance.neighbors->IsEmpty())
		instance.neighbors.reset();
399 400
#endif

401
	const unsigned max_clients =
402
		raw_config.GetPositive(ConfigOption::MAX_CONN, 10);
403
	instance.client_list = std::make_unique<ClientList>(max_clients);
404

405 406 407 408 409 410
	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);
	}

411 412
	initialize_decoder_and_player(instance,
				      raw_config, config.replay_gain);
413

414
	listen_global_init(raw_config, *instance.partitions.front().listener);
415

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

422
	ConfigureFS(raw_config);
423
	AtScopeExit() { DeinitFS(); };
424

425
	glue_mapper_init(raw_config);
426

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

433
	pcm_convert_global_init(raw_config);
434

435
	const ScopeDecoderPluginsInit decoder_plugins_init(raw_config);
436

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

441
#ifdef ENABLE_SQLITE
442
	instance.sticker_database = LoadStickerDatabase(raw_config);
443
#endif
444

Max Kellermann's avatar
Max Kellermann committed
445
	command_init();
446

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

454
	client_manager_init(raw_config);
455
	const ScopeInputPluginsInit input_plugins_init(raw_config,
456
						       instance.io_thread.GetEventLoop());
457

458
	const ScopePlaylistPluginsInit playlist_plugins_init(raw_config);
459

460
#ifdef ENABLE_DAEMON
461
	daemonize_commit();
462
#endif
463

464
#ifndef ANDROID
465
	setup_log_output();
Warren Dukes's avatar
Warren Dukes committed
466

467
	const ScopeSignalHandlersInit signal_handlers_init(instance);
468
#endif
469

470 471
	instance.io_thread.Start();
	instance.rtio_thread.Start();
472

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

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

483
	ZeroconfInit(raw_config, instance.event_loop);
484

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

493
	glue_state_file_init(instance, raw_config);
494

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

512
	Check(raw_config);
513

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

519
#ifdef _WIN32
520 521
	win32_app_started();
#endif
522

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

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

531
	/* run the main loop */
532
	instance.event_loop.Run();
533

534
#ifdef _WIN32
535 536 537
	win32_app_stopping();
#endif

538 539
	/* cleanup */

540
	instance.BeginShutdownUpdate();
541

542 543
	ZeroconfDeinit();

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

#ifdef ANDROID

549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
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
566 567
gcc_visibility_default
JNIEXPORT void JNICALL
568
Java_org_musicpd_Bridge_run(JNIEnv *env, jclass, jobject _context, jobject _logListener)
Max Kellermann's avatar
Max Kellermann committed
569
{
570
	Java::Init(env);
571
	Java::Object::Initialise(env);
572
	Java::File::Initialise(env);
573
	Environment::Initialise(env);
574
	AtScopeExit(env) { Environment::Deinitialise(env); };
575

576
	context = new Context(env, _context);
577 578
	AtScopeExit() { delete context; };

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

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

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

598 599
#else

600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
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;
	}
}

624 625 626 627 628 629 630 631 632 633
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
634
#endif