Upgrading to GitLab 12.1.0.

Commit a0284952 authored by Florian Schlichting's avatar Florian Schlichting

New upstream version 0.21.5

parent 0caa279e
ver 0.21.5 (2019/02/22)
* protocol
- fix deadlock in "albumart" command
- fix "tagtypes disable" command
* database
- simple: fix assertion failure
- fix assertion failures with mount points
* storage
- udisks: fix "AlreadyMounted" error
- udisks: use relative path from mount URI
- fix memory leak
* input
- buffer: fix crash bug when playing remote WAV file
* tags
- ape: map "Album Artist"
* output
- shout: add support for TLS
* mixer
- pulse: add "scale_volume" setting
ver 0.21.4 (2019/01/04)
* database
- inotify: fix crash bug "terminate called after throwing ..."
......
......@@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.musicpd"
android:installLocation="auto"
android:versionCode="26"
android:versionName="0.21.4">
android:versionCode="27"
android:versionName="0.21.5">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="26"/>
......
#!/bin/sh -e
# This is a wrapper for pkg-config which helps with cross-compiling;
# it sets up environment variables to pkg-config searches for
# libraries in the sysroot where a copy of this script is located.
BIN=`dirname $0`
ROOT=`dirname "$BIN"`
......
......@@ -38,7 +38,7 @@ author = 'Max Kellermann'
# built documents.
#
# The short X.Y version.
version = '0.21.4'
version = '0.21.5'
# The full version, including alpha/beta/rc tags.
release = version
......
......@@ -87,6 +87,22 @@ Mount file systems (e.g. USB sticks or other removable media) using
the udisks2 daemon via D-Bus. To obtain a valid udisks2 URI, consult
:ref:`the according neighbor plugin <neighbor_plugin>`.
It might be necessary to grant :program:`MPD` privileges to control
:program:`udisks2` through :program:`policykit`. To do this, create a
file called :file:`/usr/share/polkit-1/rules.d/mpd-udisks.rules` with
the following text::
polkit.addRule(function(action, subject) {
if ((action.id == "org.freedesktop.udisks2.filesystem-mount" ||
action.id == "org.freedesktop.udisks2.filesystem-mount-other-seat") &&
subject.user == "mpd") {
return polkit.Result.YES;
}
});
If you run MPD as a different user, change ``mpd`` to the name of your
MPD user.
.. _neighbor_plugin:
Neighbor plugins
......@@ -935,6 +951,8 @@ The pulse plugin connects to a `PulseAudio <http://www.freedesktop.org/wiki/Soft
- Sets the host name of the PulseAudio server. By default, :program:`MPD` connects to the local PulseAudio server.
* - **sink NAME**
- Specifies the name of the PulseAudio sink :program:`MPD` should play on.
* - **scale_volume FACTOR**
- Specifies a linear scaling coefficient (ranging from 0.5 to 5.0) to apply when adjusting volume through :program:`MPD`. For example, chosing a factor equal to ``"0.7"`` means that setting the volume to 100 in :program:`MPD` will set the PulseAudio volume to 70%, and a factor equal to ``"3.5"`` means that volume 100 in :program:`MPD` corresponds to a 350% PulseAudio volume.
recorder
~~~~~~~~
......@@ -974,6 +992,8 @@ You must set a format.
- Set the timeout for the shout connection in seconds. Defaults to 2 seconds.
* - **protocol icecast2|icecast1|shoutcast**
- Specifies the protocol that wil be used to connect to the server. The default is "icecast2".
* - **tls disabled|auto|auto_no_plain|rfc2818|rfc2817**
- Specifies what kind of TLS to use. The default is "disabled" (no TLS).
* - **mount URI**
- Mounts the :program:`MPD` stream in the specified URI.
* - **user USERNAME**
......
......@@ -909,7 +909,7 @@ The music database
.. _command_lsinfo:
:command:`lsinfo {URI}`
:command:`lsinfo [URI]`
Lists the contents of the directory
``URI``. The response contains records
starting with ``file``,
......@@ -1131,7 +1131,7 @@ Connection settings
``tagtypes`` sub commands configure this
list.
:command:`tagtypes disable {NAME...]`
:command:`tagtypes disable {NAME...}`
Remove one or more tags from the list of tag types the
client is interested in. These will be omitted from
responses to this client.
......
project(
'mpd',
['c', 'cpp'],
version: '0.21.4',
version: '0.21.5',
meson_version: '>= 0.47.2',
default_options: [
'c_std=c99',
......
......@@ -128,6 +128,7 @@ option('mpg123', type: 'feature', description: 'MP3 decoder using libmpg123')
option('opus', type: 'feature', description: 'Opus decoder plugin')
option('sidplay', type: 'feature', description: 'C64 SID support via libsidplayfp or libsidplay2')
option('sndfile', type: 'feature', description: 'libsndfile decoder plugin')
option('tremor', type: 'feature', description: 'Fixed-point vorbis decoder plugin')
option('vorbis', type: 'feature', description: 'Vorbis decoder plugin')
option('wavpack', type: 'feature', description: 'WavPack decoder plugin')
option('wildmidi', type: 'feature', description: 'WildMidi decoder plugin')
......
......@@ -112,8 +112,8 @@ liblame = AutotoolsProject(
)
ffmpeg = FfmpegProject(
'http://ffmpeg.org/releases/ffmpeg-4.1.tar.xz',
'a38ec4d026efb58506a99ad5cd23d5a9793b4bf415f2c4c2e9c1bb444acd1994',
'http://ffmpeg.org/releases/ffmpeg-4.1.1.tar.xz',
'373749824dfd334d84e55dff406729edfd1606575ee44dd485d97d45ea4d2d86',
'lib/libavcodec.a',
[
'--disable-shared', '--enable-static',
......@@ -341,8 +341,8 @@ ffmpeg = FfmpegProject(
)
curl = AutotoolsProject(
'http://curl.haxx.se/download/curl-7.62.0.tar.xz',
'dab5643a5fe775ae92570b9f3df6b0ef4bc2a827a959361fb130c73b721275c1',
'http://curl.haxx.se/download/curl-7.64.0.tar.xz',
'2f2f13fa34d44aa29cb444077ad7dc4dc6d189584ad552e0aaeb06e608af6001',
'lib/libcurl.a',
[
'--disable-shared', '--enable-static',
......@@ -392,7 +392,7 @@ libnfs = AutotoolsProject(
)
boost = BoostProject(
'http://downloads.sourceforge.net/project/boost/boost/1.68.0/boost_1_68_0.tar.bz2',
'7f6130bc3cf65f56a618888ce9d5ea704fa10b462be126ad053e80e553d6d8b7',
'http://downloads.sourceforge.net/project/boost/boost/1.69.0/boost_1_69_0.tar.bz2',
'8f32d4617390d1c2d16f26a27ab60d97807b35440d45891fa340fc2648b04406',
'include/boost/version.hpp',
)
......@@ -30,6 +30,9 @@
#ifdef ENABLE_DATABASE
#include "db/DatabaseError.hxx"
#include "db/Interface.hxx"
#include "db/update/Service.hxx"
#include "storage/StorageInterface.hxx"
#ifdef ENABLE_SQLITE
#include "sticker/StickerDatabase.hxx"
......@@ -48,7 +51,19 @@ Instance::Instance()
{
}
Instance::~Instance() noexcept = default;
Instance::~Instance() noexcept
{
#ifdef ENABLE_DATABASE
delete update;
if (database != nullptr) {
database->Close();
database.reset();
}
delete storage;
#endif
}
Partition *
Instance::FindPartition(const char *name) noexcept
......
......@@ -41,7 +41,7 @@ class NeighborGlue;
#ifdef ENABLE_DATABASE
#include "db/DatabaseListener.hxx"
class Database;
#include "db/Ptr.hxx"
class Storage;
class UpdateService;
#endif
......@@ -104,7 +104,7 @@ struct Instance final
#endif
#ifdef ENABLE_DATABASE
Database *database;
DatabasePtr database;
/**
* This is really a #CompositeStorage. To avoid heavy include
......@@ -147,7 +147,6 @@ struct Instance final
Partition *FindPartition(const char *name) noexcept;
void BeginShutdownPartitions() noexcept;
void FinishShutdownPartitions() noexcept;
#ifdef ENABLE_DATABASE
/**
......@@ -156,7 +155,7 @@ struct Instance final
* music_directory was configured).
*/
Database *GetDatabase() {
return database;
return database.get();
}
/**
......@@ -168,8 +167,6 @@ struct Instance final
#endif
void BeginShutdownUpdate() noexcept;
void FinishShutdownUpdate() noexcept;
void ShutdownDatabase() noexcept;
#ifdef ENABLE_CURL
void LookupRemoteTag(const char *uri) noexcept;
......
......@@ -109,7 +109,7 @@ parse_log_level(const char *value, int line)
#endif
void
log_early_init(bool verbose)
log_early_init(bool verbose) noexcept
{
#ifdef ANDROID
(void)verbose;
......@@ -171,7 +171,7 @@ log_init(const ConfigData &config, bool verbose, bool use_stdout)
#ifndef ANDROID
static void
close_log_files(void)
close_log_files() noexcept
{
#ifdef HAVE_SYSLOG
LogFinishSysLog();
......@@ -181,7 +181,7 @@ close_log_files(void)
#endif
void
log_deinit(void)
log_deinit() noexcept
{
#ifndef ANDROID
close_log_files();
......@@ -213,7 +213,8 @@ void setup_log_output()
#endif
}
int cycle_log_files(void)
int
cycle_log_files() noexcept
{
#ifdef ANDROID
return 0;
......
......@@ -31,7 +31,7 @@ struct ConfigData;
* @param verbose true when the program is started with --verbose
*/
void
log_early_init(bool verbose);
log_early_init(bool verbose) noexcept;
/**
* Throws #std::runtime_error on error.
......@@ -40,12 +40,12 @@ void
log_init(const ConfigData &config, bool verbose, bool use_stdout);
void
log_deinit();
log_deinit() noexcept;
void
setup_log_output();
int
cycle_log_files();
cycle_log_files() noexcept;
#endif /* LOG_H */
......@@ -185,19 +185,16 @@ InitStorage(const ConfigData &config, EventLoop &event_loop)
static bool
glue_db_init_and_load(const ConfigData &config)
{
instance->database =
CreateConfiguredDatabase(config, instance->event_loop,
instance->io_thread.GetEventLoop(),
*instance);
if (instance->database == nullptr)
auto db = CreateConfiguredDatabase(config, instance->event_loop,
instance->io_thread.GetEventLoop(),
*instance);
if (!db)
return true;
if (instance->database->GetPlugin().RequireStorage()) {
if (db->GetPlugin().RequireStorage()) {
InitStorage(config, instance->io_thread.GetEventLoop());
if (instance->storage == nullptr) {
delete instance->database;
instance->database = nullptr;
LogDefault(config_domain,
"Found database setting without "
"music_directory - disabling database");
......@@ -211,22 +208,24 @@ glue_db_init_and_load(const ConfigData &config)
}
try {
instance->database->Open();
db->Open();
} catch (...) {
std::throw_with_nested(std::runtime_error("Failed to open database plugin"));
}
auto *db = dynamic_cast<SimpleDatabase *>(instance->database);
if (db == nullptr)
instance->database = std::move(db);
auto *sdb = dynamic_cast<SimpleDatabase *>(instance->database.get());
if (sdb == nullptr)
return true;
instance->update = new UpdateService(config,
instance->event_loop, *db,
instance->event_loop, *sdb,
static_cast<CompositeStorage &>(*instance->storage),
*instance);
/* run database update after daemonization? */
return db->FileExists();
return sdb->FileExists();
}
static bool
......@@ -351,27 +350,6 @@ Instance::BeginShutdownUpdate() noexcept
#endif
}
inline void
Instance::FinishShutdownUpdate() noexcept
{
#ifdef ENABLE_DATABASE
delete update;
#endif
}
inline void
Instance::ShutdownDatabase() noexcept
{
#ifdef ENABLE_DATABASE
if (instance->database != nullptr) {
instance->database->Close();
delete instance->database;
}
delete instance->storage;
#endif
}
inline void
Instance::BeginShutdownPartitions() noexcept
{
......@@ -381,12 +359,6 @@ Instance::BeginShutdownPartitions() noexcept
}
}
inline void
Instance::FinishShutdownPartitions() noexcept
{
partitions.clear();
}
void
Instance::OnIdle(unsigned flags)
{
......@@ -523,18 +495,19 @@ static int
mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
{
ConfigureFS(raw_config);
AtScopeExit() { DeinitFS(); };
glue_mapper_init(raw_config);
initPermissions(raw_config);
spl_global_init(raw_config);
#ifdef ENABLE_ARCHIVE
archive_plugin_init_all();
const ScopeArchivePluginsInit archive_plugins_init;
#endif
pcm_convert_global_init(raw_config);
decoder_plugin_init_all(raw_config);
const ScopeDecoderPluginsInit decoder_plugins_init(raw_config);
#ifdef ENABLE_DATABASE
const bool create_db = InitDatabaseAndStorage(raw_config);
......@@ -553,9 +526,9 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
}
client_manager_init(raw_config);
input_stream_global_init(raw_config,
instance->io_thread.GetEventLoop());
playlist_list_global_init(raw_config);
const ScopeInputPluginsInit input_plugins_init(raw_config,
instance->io_thread.GetEventLoop());
const ScopePlaylistPluginsInit playlist_plugins_init(raw_config);
#ifdef ENABLE_DAEMON
daemonize_commit();
......@@ -564,7 +537,7 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
#ifndef ANDROID
setup_log_output();
SignalHandlersInit(instance->event_loop);
const ScopeSignalHandlersInit signal_handlers_init(instance->event_loop);
#endif
instance->io_thread.Start();
......@@ -652,34 +625,10 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
}
#endif
instance->FinishShutdownUpdate();
instance->ShutdownDatabase();
#ifdef ENABLE_SQLITE
sticker_global_finish();
#endif
playlist_list_global_finish();
input_stream_global_finish();
#ifdef ENABLE_DATABASE
mapper_finish();
#endif
DeinitFS();
instance->FinishShutdownPartitions();
command_finish();
decoder_plugin_deinit_all();
#ifdef ENABLE_ARCHIVE
archive_plugin_deinit_all();
#endif
instance->rtio_thread.Stop();
instance->io_thread.Stop();
#ifndef ANDROID
SignalHandlersFinish();
#endif
return EXIT_SUCCESS;
}
......
......@@ -58,11 +58,6 @@ mapper_init(AllocatedPath &&_playlist_dir)
mapper_set_playlist_dir(std::move(_playlist_dir));
}
void
mapper_finish() noexcept
{
}
#ifdef ENABLE_DATABASE
AllocatedPath
......
......@@ -37,9 +37,6 @@ class AllocatedPath;
void
mapper_init(AllocatedPath &&playlist_dir);
void
mapper_finish() noexcept;
#ifdef ENABLE_DATABASE
/**
......
......@@ -119,7 +119,7 @@ try {
TextFile file(config.path);
#ifdef ENABLE_DATABASE
const SongLoader song_loader(partition.instance.database,
const SongLoader song_loader(partition.instance.GetDatabase(),
partition.instance.storage);
#else
const SongLoader song_loader(nullptr, nullptr);
......
......@@ -124,7 +124,7 @@ stats_print(Response &r, const Partition &partition)
std::lround(partition.pc.GetTotalPlayTime().count()));
#ifdef ENABLE_DATABASE
const Database *db = partition.instance.database;
const Database *db = partition.instance.GetDatabase();
if (db != nullptr)
db_stats_print(r, *db);
#endif
......
......@@ -25,8 +25,9 @@
void
tag_print_types(Response &r) noexcept
{
const auto tag_mask = global_tag_mask & r.GetTagMask();
for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++)
if (IsTagEnabled(i))
if (tag_mask.Test(TagType(i)))
r.Format("tagtype: %s\n", tag_item_names[i]);
}
......
......@@ -49,7 +49,7 @@ static bool archive_plugins_enabled[ARRAY_SIZE(archive_plugins) - 1];
if (archive_plugins_enabled[archive_plugin_iterator - archive_plugins])
const ArchivePlugin *
archive_plugin_from_suffix(const char *suffix)
archive_plugin_from_suffix(const char *suffix) noexcept
{
if (suffix == nullptr)
return nullptr;
......@@ -63,7 +63,7 @@ archive_plugin_from_suffix(const char *suffix)
}
const ArchivePlugin *
archive_plugin_from_name(const char *name)
archive_plugin_from_name(const char *name) noexcept
{
archive_plugins_for_each_enabled(plugin)
if (strcmp(plugin->name, name) == 0)
......@@ -81,7 +81,8 @@ void archive_plugin_init_all(void)
}
}
void archive_plugin_deinit_all(void)
void
archive_plugin_deinit_all() noexcept
{
archive_plugins_for_each_enabled(plugin)
if (plugin->finish != nullptr)
......
......@@ -33,10 +33,10 @@ extern const ArchivePlugin *const archive_plugins[];
/* interface for using plugins */
const ArchivePlugin *
archive_plugin_from_suffix(const char *suffix);
archive_plugin_from_suffix(const char *suffix) noexcept;
const ArchivePlugin *
archive_plugin_from_name(const char *name);
archive_plugin_from_name(const char *name) noexcept;
/* this is where we "load" all the "plugins" ;-) */
void
......@@ -44,6 +44,17 @@ archive_plugin_init_all();
/* this is where we "unload" all the "plugins" */
void
archive_plugin_deinit_all();
archive_plugin_deinit_all() noexcept;
class ScopeArchivePluginsInit {
public:
ScopeArchivePluginsInit() {
archive_plugin_init_all();
}
~ScopeArchivePluginsInit() noexcept {
archive_plugin_deinit_all();
}
};
#endif
......@@ -285,11 +285,6 @@ command_init()
#endif
}
void
command_finish()
{
}
static const struct command *
command_lookup(const char *name)
{
......
......@@ -37,9 +37,11 @@
#include "fs/FileInfo.hxx"
#include "fs/DirectoryReader.hxx"
#include "input/InputStream.hxx"
#include "input/Error.hxx"
#include "LocateUri.hxx"
#include "TimePrint.hxx"
#include "thread/Mutex.hxx"
#include "Log.hxx"
#include <assert.h>
#include <inttypes.h> /* for PRIu64 */
......@@ -256,7 +258,11 @@ find_stream_art(const char *directory, Mutex &mutex)
try {
return InputStream::OpenReady(art_file.c_str(), mutex);
} catch (const std::exception &e) {}
} catch (...) {
auto e = std::current_exception();
if (!IsFileNotFound(e))
LogError(e);
}
}
return nullptr;
}
......@@ -285,8 +291,11 @@ read_stream_art(Response &r, const char *uri, size_t offset)
uint8_t buffer[CHUNK_SIZE];
size_t read_size;
is->Seek(offset);
read_size = is->Read(&buffer, CHUNK_SIZE);
{
const std::lock_guard<Mutex> protect(mutex);
is->Seek(offset);
read_size = is->Read(&buffer, CHUNK_SIZE);
}
r.Format("size: %" PRIoffset "\n"
"binary: %u\n",
......
......@@ -294,7 +294,7 @@ handle_update(Client &client, Request args, Response &r, bool discard)
if (update != nullptr)
return handle_update(r, *update, path, discard);
Database *db = client.GetInstance().database;
Database *db = client.GetInstance().GetDatabase();
if (db != nullptr)
return handle_update(r, *db, path, discard);
#else
......
......@@ -209,7 +209,7 @@ handle_mount(Client &client, Request args, Response &r)
instance.EmitIdle(IDLE_MOUNT);
#ifdef ENABLE_DATABASE
if (auto *db = dynamic_cast<SimpleDatabase *>(instance.database)) {
if (auto *db = dynamic_cast<SimpleDatabase *>(instance.GetDatabase())) {
try {
db->Mount(local_uri, remote_uri);
} catch (...) {
......@@ -253,7 +253,7 @@ handle_unmount(Client &client, Request args, Response &r)
destroy here */
instance.update->CancelMount(local_uri);
if (auto *db = dynamic_cast<SimpleDatabase *>(instance.database)) {
if (auto *db = dynamic_cast<SimpleDatabase *>(instance.GetDatabase())) {
if (db->Unmount(local_uri))
// TODO: call Instance::OnDatabaseModified()?
instance.EmitIdle(IDLE_DATABASE);
......
/*
* Copyright 2003-2018 The Music Player Daemon Project
* Copyright 2003-2019 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
......@@ -19,6 +19,7 @@
#include "Configured.hxx"
#include "DatabaseGlue.hxx"
#include "Interface.hxx"
#include "config/Data.hxx"
#include "config/Param.hxx"
#include "config/Block.hxx"
......@@ -26,7 +27,7 @@
#include "fs/StandardDirectory.hxx"
#include "util/RuntimeError.hxx"
Database *
DatabasePtr
CreateConfiguredDatabase(const ConfigData &config,
EventLoop &main_event_loop, EventLoop &io_event_loop,
DatabaseListener &listener)
......
/*
* Copyright 2003-2018 The Music Player Daemon Project
* Copyright 2003-2019 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
......@@ -20,10 +20,11 @@
#ifndef MPD_DB_CONFIG_HXX
#define MPD_DB_CONFIG_HXX
#include "Ptr.hxx"
struct ConfigData;
class EventLoop;
class DatabaseListener;
class Database;
/**
* Read database configuration settings and create a #Database
......@@ -32,7 +33,7 @@ class Database;
*
* Throws #std::runtime_error on error.
*/
Database *
DatabasePtr
CreateConfiguredDatabase(const ConfigData &config,
EventLoop &main_event_loop, EventLoop &io_event_loop,
DatabaseListener &listener);
......
/*
* Copyright 2003-2018 The Music Player Daemon Project
* Copyright 2003-2019 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
......@@ -18,13 +18,14 @@
*/
#include "DatabaseGlue.hxx"
#include "Interface.hxx"