|
|
|
@ -129,7 +129,7 @@ Context *context;
|
|
|
|
|
LogListener *logListener;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
Instance *instance;
|
|
|
|
|
Instance *global_instance;
|
|
|
|
|
|
|
|
|
|
struct Config {
|
|
|
|
|
ReplayGainConfig replay_gain;
|
|
|
|
@ -166,14 +166,15 @@ glue_mapper_init(const ConfigData &config)
|
|
|
|
|
#ifdef ENABLE_DATABASE
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
InitStorage(const ConfigData &config, EventLoop &event_loop)
|
|
|
|
|
InitStorage(Instance &instance, EventLoop &event_loop,
|
|
|
|
|
const ConfigData &config)
|
|
|
|
|
{
|
|
|
|
|
auto storage = CreateConfiguredStorage(config, event_loop);
|
|
|
|
|
if (storage == nullptr)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
CompositeStorage *composite = new CompositeStorage();
|
|
|
|
|
instance->storage = composite;
|
|
|
|
|
instance.storage = composite;
|
|
|
|
|
composite->Mount("", std::move(storage));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -183,18 +184,19 @@ InitStorage(const ConfigData &config, EventLoop &event_loop)
|
|
|
|
|
* process has been daemonized.
|
|
|
|
|
*/
|
|
|
|
|
static bool
|
|
|
|
|
glue_db_init_and_load(const ConfigData &config)
|
|
|
|
|
glue_db_init_and_load(Instance &instance, const ConfigData &config)
|
|
|
|
|
{
|
|
|
|
|
auto db = CreateConfiguredDatabase(config, instance->event_loop,
|
|
|
|
|
instance->io_thread.GetEventLoop(),
|
|
|
|
|
*instance);
|
|
|
|
|
auto db = CreateConfiguredDatabase(config, instance.event_loop,
|
|
|
|
|
instance.io_thread.GetEventLoop(),
|
|
|
|
|
instance);
|
|
|
|
|
if (!db)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (db->GetPlugin().RequireStorage()) {
|
|
|
|
|
InitStorage(config, instance->io_thread.GetEventLoop());
|
|
|
|
|
InitStorage(instance, instance.io_thread.GetEventLoop(),
|
|
|
|
|
config);
|
|
|
|
|
|
|
|
|
|
if (instance->storage == nullptr) {
|
|
|
|
|
if (instance.storage == nullptr) {
|
|
|
|
|
LogDefault(config_domain,
|
|
|
|
|
"Found database setting without "
|
|
|
|
|
"music_directory - disabling database");
|
|
|
|
@ -213,25 +215,25 @@ glue_db_init_and_load(const ConfigData &config)
|
|
|
|
|
std::throw_with_nested(std::runtime_error("Failed to open database plugin"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
instance->database = std::move(db);
|
|
|
|
|
instance.database = std::move(db);
|
|
|
|
|
|
|
|
|
|
auto *sdb = dynamic_cast<SimpleDatabase *>(instance->database.get());
|
|
|
|
|
auto *sdb = dynamic_cast<SimpleDatabase *>(instance.database.get());
|
|
|
|
|
if (sdb == nullptr)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
instance->update = new UpdateService(config,
|
|
|
|
|
instance->event_loop, *sdb,
|
|
|
|
|
static_cast<CompositeStorage &>(*instance->storage),
|
|
|
|
|
*instance);
|
|
|
|
|
instance.update = new UpdateService(config,
|
|
|
|
|
instance.event_loop, *sdb,
|
|
|
|
|
static_cast<CompositeStorage &>(*instance.storage),
|
|
|
|
|
instance);
|
|
|
|
|
|
|
|
|
|
/* run database update after daemonization? */
|
|
|
|
|
return sdb->FileExists();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
InitDatabaseAndStorage(const ConfigData &config)
|
|
|
|
|
InitDatabaseAndStorage(Instance &instance, const ConfigData &config)
|
|
|
|
|
{
|
|
|
|
|
const bool create_db = !glue_db_init_and_load(config);
|
|
|
|
|
const bool create_db = !glue_db_init_and_load(instance, config);
|
|
|
|
|
return create_db;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -255,23 +257,24 @@ LoadStickerDatabase(const ConfigData &config)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
glue_state_file_init(const ConfigData &raw_config)
|
|
|
|
|
glue_state_file_init(Instance &instance, const ConfigData &raw_config)
|
|
|
|
|
{
|
|
|
|
|
StateFileConfig config(raw_config);
|
|
|
|
|
if (!config.IsEnabled())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
instance->state_file = new StateFile(std::move(config),
|
|
|
|
|
instance->partitions.front(),
|
|
|
|
|
instance->event_loop);
|
|
|
|
|
instance->state_file->Read();
|
|
|
|
|
instance.state_file = new StateFile(std::move(config),
|
|
|
|
|
instance.partitions.front(),
|
|
|
|
|
instance.event_loop);
|
|
|
|
|
instance.state_file->Read();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initialize the decoder and player core, including the music pipe.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
initialize_decoder_and_player(const ConfigData &config,
|
|
|
|
|
initialize_decoder_and_player(Instance &instance,
|
|
|
|
|
const ConfigData &config,
|
|
|
|
|
const ReplayGainConfig &replay_gain_config)
|
|
|
|
|
{
|
|
|
|
|
const ConfigParam *param;
|
|
|
|
@ -318,13 +321,13 @@ initialize_decoder_and_player(const ConfigData &config,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
instance->partitions.emplace_back(*instance,
|
|
|
|
|
instance.partitions.emplace_back(instance,
|
|
|
|
|
"default",
|
|
|
|
|
max_length,
|
|
|
|
|
buffered_chunks,
|
|
|
|
|
configured_audio_format,
|
|
|
|
|
replay_gain_config);
|
|
|
|
|
auto &partition = instance->partitions.back();
|
|
|
|
|
auto &partition = instance.partitions.back();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
param = config.GetParam(ConfigOption::REPLAYGAIN);
|
|
|
|
@ -386,7 +389,8 @@ main(int argc, char *argv[]) noexcept
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
mpd_main_after_fork(const ConfigData &raw_config,
|
|
|
|
|
mpd_main_after_fork(Instance &instance,
|
|
|
|
|
const ConfigData &raw_config,
|
|
|
|
|
const Config &config);
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
@ -422,29 +426,27 @@ MainConfigured(const struct options &options, const ConfigData &raw_config)
|
|
|
|
|
|
|
|
|
|
log_init(raw_config, options.verbose, options.log_stderr);
|
|
|
|
|
|
|
|
|
|
instance = new Instance();
|
|
|
|
|
AtScopeExit() {
|
|
|
|
|
delete instance;
|
|
|
|
|
instance = nullptr;
|
|
|
|
|
};
|
|
|
|
|
Instance instance;
|
|
|
|
|
global_instance = &instance;
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
|
|
|
|
instance->neighbors = std::make_unique<NeighborGlue>();
|
|
|
|
|
instance->neighbors->Init(raw_config,
|
|
|
|
|
instance->io_thread.GetEventLoop(),
|
|
|
|
|
*instance);
|
|
|
|
|
instance.neighbors = std::make_unique<NeighborGlue>();
|
|
|
|
|
instance.neighbors->Init(raw_config,
|
|
|
|
|
instance.io_thread.GetEventLoop(),
|
|
|
|
|
instance);
|
|
|
|
|
|
|
|
|
|
if (instance->neighbors->IsEmpty())
|
|
|
|
|
instance->neighbors.reset();
|
|
|
|
|
if (instance.neighbors->IsEmpty())
|
|
|
|
|
instance.neighbors.reset();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
const unsigned max_clients =
|
|
|
|
|
raw_config.GetPositive(ConfigOption::MAX_CONN, 10);
|
|
|
|
|
instance->client_list = new ClientList(max_clients);
|
|
|
|
|
instance.client_list = new ClientList(max_clients);
|
|
|
|
|
|
|
|
|
|
initialize_decoder_and_player(raw_config, config.replay_gain);
|
|
|
|
|
initialize_decoder_and_player(instance,
|
|
|
|
|
raw_config, config.replay_gain);
|
|
|
|
|
|
|
|
|
|
listen_global_init(raw_config, *instance->partitions.front().listener);
|
|
|
|
|
listen_global_init(raw_config, *instance.partitions.front().listener);
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_DAEMON
|
|
|
|
|
daemonize_set_user();
|
|
|
|
@ -452,7 +454,7 @@ MainConfigured(const struct options &options, const ConfigData &raw_config)
|
|
|
|
|
AtScopeExit() { daemonize_finish(); };
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
mpd_main_after_fork(raw_config, config);
|
|
|
|
|
mpd_main_after_fork(instance, raw_config, config);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef ANDROID
|
|
|
|
@ -484,7 +486,8 @@ int mpd_main(int argc, char *argv[]) noexcept
|
|
|
|
|
#endif /* !ANDROID */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
|
|
|
|
|
mpd_main_after_fork(Instance &instance,
|
|
|
|
|
const ConfigData &raw_config, const Config &config)
|
|
|
|
|
{
|
|
|
|
|
ConfigureFS(raw_config);
|
|
|
|
|
AtScopeExit() { DeinitFS(); };
|
|
|
|
@ -502,17 +505,17 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
|
|
|
|
|
const ScopeDecoderPluginsInit decoder_plugins_init(raw_config);
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_DATABASE
|
|
|
|
|
const bool create_db = InitDatabaseAndStorage(raw_config);
|
|
|
|
|
const bool create_db = InitDatabaseAndStorage(instance, raw_config);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_SQLITE
|
|
|
|
|
instance->sticker_database = LoadStickerDatabase(raw_config);
|
|
|
|
|
instance.sticker_database = LoadStickerDatabase(raw_config);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
command_init();
|
|
|
|
|
|
|
|
|
|
for (auto &partition : instance->partitions) {
|
|
|
|
|
partition.outputs.Configure(instance->rtio_thread.GetEventLoop(),
|
|
|
|
|
for (auto &partition : instance.partitions) {
|
|
|
|
|
partition.outputs.Configure(instance.rtio_thread.GetEventLoop(),
|
|
|
|
|
raw_config,
|
|
|
|
|
config.replay_gain,
|
|
|
|
|
partition.pc);
|
|
|
|
@ -521,7 +524,7 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
|
|
|
|
|
|
|
|
|
|
client_manager_init(raw_config);
|
|
|
|
|
const ScopeInputPluginsInit input_plugins_init(raw_config,
|
|
|
|
|
instance->io_thread.GetEventLoop());
|
|
|
|
|
instance.io_thread.GetEventLoop());
|
|
|
|
|
const ScopePlaylistPluginsInit playlist_plugins_init(raw_config);
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_DAEMON
|
|
|
|
@ -531,42 +534,42 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
|
|
|
|
|
#ifndef ANDROID
|
|
|
|
|
setup_log_output();
|
|
|
|
|
|
|
|
|
|
const ScopeSignalHandlersInit signal_handlers_init(instance->event_loop);
|
|
|
|
|
const ScopeSignalHandlersInit signal_handlers_init(instance.event_loop);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
instance->io_thread.Start();
|
|
|
|
|
instance->rtio_thread.Start();
|
|
|
|
|
instance.io_thread.Start();
|
|
|
|
|
instance.rtio_thread.Start();
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
|
|
|
|
if (instance->neighbors != nullptr)
|
|
|
|
|
instance->neighbors->Open();
|
|
|
|
|
if (instance.neighbors != nullptr)
|
|
|
|
|
instance.neighbors->Open();
|
|
|
|
|
|
|
|
|
|
AtScopeExit() {
|
|
|
|
|
if (instance->neighbors != nullptr)
|
|
|
|
|
instance->neighbors->Close();
|
|
|
|
|
AtScopeExit(&instance) {
|
|
|
|
|
if (instance.neighbors != nullptr)
|
|
|
|
|
instance.neighbors->Close();
|
|
|
|
|
};
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
ZeroconfInit(raw_config, instance->event_loop);
|
|
|
|
|
ZeroconfInit(raw_config, instance.event_loop);
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_DATABASE
|
|
|
|
|
if (create_db) {
|
|
|
|
|
/* the database failed to load: recreate the
|
|
|
|
|
database */
|
|
|
|
|
instance->update->Enqueue("", true);
|
|
|
|
|
instance.update->Enqueue("", true);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
glue_state_file_init(raw_config);
|
|
|
|
|
glue_state_file_init(instance, raw_config);
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_DATABASE
|
|
|
|
|
if (raw_config.GetBool(ConfigOption::AUTO_UPDATE, false)) {
|
|
|
|
|
#ifdef ENABLE_INOTIFY
|
|
|
|
|
if (instance->storage != nullptr &&
|
|
|
|
|
instance->update != nullptr)
|
|
|
|
|
mpd_inotify_init(instance->event_loop,
|
|
|
|
|
*instance->storage,
|
|
|
|
|
*instance->update,
|
|
|
|
|
if (instance.storage != nullptr &&
|
|
|
|
|
instance.update != nullptr)
|
|
|
|
|
mpd_inotify_init(instance.event_loop,
|
|
|
|
|
*instance.storage,
|
|
|
|
|
*instance.update,
|
|
|
|
|
raw_config.GetUnsigned(ConfigOption::AUTO_UPDATE_DEPTH,
|
|
|
|
|
INT_MAX));
|
|
|
|
|
#else
|
|
|
|
@ -580,7 +583,7 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
|
|
|
|
|
|
|
|
|
|
/* enable all audio outputs (if not already done by
|
|
|
|
|
playlist_state_restore() */
|
|
|
|
|
for (auto &partition : instance->partitions)
|
|
|
|
|
for (auto &partition : instance.partitions)
|
|
|
|
|
partition.pc.LockUpdateAudio();
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
@ -596,7 +599,7 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* run the main loop */
|
|
|
|
|
instance->event_loop.Run();
|
|
|
|
|
instance.event_loop.Run();
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
win32_app_stopping();
|
|
|
|
@ -604,18 +607,18 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
|
|
|
|
|
|
|
|
|
|
/* cleanup */
|
|
|
|
|
|
|
|
|
|
instance->BeginShutdownUpdate();
|
|
|
|
|
instance.BeginShutdownUpdate();
|
|
|
|
|
|
|
|
|
|
if (instance->state_file != nullptr) {
|
|
|
|
|
instance->state_file->Write();
|
|
|
|
|
delete instance->state_file;
|
|
|
|
|
if (instance.state_file != nullptr) {
|
|
|
|
|
instance.state_file->Write();
|
|
|
|
|
delete instance.state_file;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ZeroconfDeinit();
|
|
|
|
|
|
|
|
|
|
instance->BeginShutdownPartitions();
|
|
|
|
|
instance.BeginShutdownPartitions();
|
|
|
|
|
|
|
|
|
|
delete instance->client_list;
|
|
|
|
|
delete instance.client_list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef ANDROID
|
|
|
|
@ -665,8 +668,8 @@ gcc_visibility_default
|
|
|
|
|
JNIEXPORT void JNICALL
|
|
|
|
|
Java_org_musicpd_Bridge_shutdown(JNIEnv *, jclass)
|
|
|
|
|
{
|
|
|
|
|
if (instance != nullptr)
|
|
|
|
|
instance->Break();
|
|
|
|
|
if (global_instance != nullptr)
|
|
|
|
|
global_instance->Break();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|