Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package mpd for openSUSE:Factory checked in at 2021-11-13 22:48:37 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/mpd (Old) and /work/SRC/openSUSE:Factory/.mpd.new.1890 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "mpd" Sat Nov 13 22:48:37 2021 rev:36 rq:931211 version:0.23.4 Changes: -------- --- /work/SRC/openSUSE:Factory/mpd/mpd.changes 2021-11-06 18:21:31.464996826 +0100 +++ /work/SRC/openSUSE:Factory/.mpd.new.1890/mpd.changes 2021-11-13 22:49:07.509277537 +0100 @@ -1,0 +2,16 @@ +Fri Nov 12 23:12:23 UTC 2021 - ???????? ???????????? <[email protected]> + +- Updated to 0.23.4 + * Changed file mpd-user.conf??? (disabled pid_file). + * Refreshed patch mpd-conf.patch. + * Removed patch mpd-service.patch. + * https://raw.githubusercontent.com/MusicPlayerDaemon/MPD/v0.23.4/NEWS + * protocol: add optional position parameter to "searchaddpl" + * decoder: ffmpeg: support libavcodec 59 + * output: alsa: add option "thesycon_dsd_workaround" to work around device bug + * fix crash on debug builds if startup fails + * systemd: + * remove "RuntimeDirectory" directive because it caused problems + * ignore the "pid_file" setting if started as systemd service + +------------------------------------------------------------------- Old: ---- mpd-0.23.3.tar.xz mpd-0.23.3.tar.xz.sig mpd-service.patch New: ---- mpd-0.23.4.tar.xz mpd-0.23.4.tar.xz.sig ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ mpd.spec ++++++ --- /var/tmp/diff_new_pack.wxl7FG/_old 2021-11-13 22:49:07.909277844 +0100 +++ /var/tmp/diff_new_pack.wxl7FG/_new 2021-11-13 22:49:07.909277844 +0100 @@ -20,7 +20,7 @@ %bcond_with faad %bcond_without mpd_iso9660 Name: mpd -Version: 0.23.3 +Version: 0.23.4 Release: 0 Summary: Music Player Daemon License: GPL-2.0-or-later @@ -32,8 +32,7 @@ Source4: %{name}.firewalld Source5: %{name}.tmpfiles.d Patch0: %{name}-conf.patch -Patch1: %{name}-service.patch -Patch2: %{name}-sndfile.patch +Patch1: %{name}-sndfile.patch BuildRequires: cmake BuildRequires: gcc BuildRequires: gcc-c++ ++++++ mpd-0.23.3.tar.xz -> mpd-0.23.4.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/NEWS new/mpd-0.23.4/NEWS --- old/mpd-0.23.3/NEWS 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/NEWS 2021-11-11 10:16:36.000000000 +0100 @@ -1,3 +1,17 @@ +ver 0.23.4 (2021/11/11) +* protocol + - add optional position parameter to "searchaddpl" +* decoder + - ffmpeg: support libavcodec 59 +* output + - alsa: add option "thesycon_dsd_workaround" to work around device bug +* fix crash on debug builds if startup fails +* systemd + - remove "RuntimeDirectory" directive because it caused problems + - ignore the "pid_file" setting if started as systemd service +* Windows + - enable the "openmpt" decoder plugin + ver 0.23.3 (2021/10/31) * protocol - add optional position parameter to "add" and "playlistadd" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/android/AndroidManifest.xml new/mpd-0.23.4/android/AndroidManifest.xml --- old/mpd-0.23.3/android/AndroidManifest.xml 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/android/AndroidManifest.xml 2021-11-11 10:16:36.000000000 +0100 @@ -2,8 +2,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.musicpd" android:installLocation="auto" - android:versionCode="63" - android:versionName="0.23.3"> + android:versionCode="64" + android:versionName="0.23.4"> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29"/> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/doc/conf.py new/mpd-0.23.4/doc/conf.py --- old/mpd-0.23.3/doc/conf.py 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/doc/conf.py 2021-11-11 10:16:36.000000000 +0100 @@ -38,7 +38,7 @@ # built documents. # # The short X.Y version. -version = '0.23.3' +version = '0.23.4' # The full version, including alpha/beta/rc tags. #release = version + '~git' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/doc/mpdconf.example new/mpd-0.23.4/doc/mpdconf.example --- old/mpd-0.23.3/doc/mpdconf.example 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/doc/mpdconf.example 2021-11-11 10:16:36.000000000 +0100 @@ -26,22 +26,25 @@ # files over an accepted protocol. # #db_file "~/.mpd/database" -# + # These settings are the locations for the daemon log files for the daemon. -# These logs are great for troubleshooting, depending on your log_level -# settings. # # The special value "syslog" makes MPD use the local syslog daemon. This # setting defaults to logging to syslog. # -#log_file "~/.mpd/log" +# If you use systemd, do not configure a log_file. With systemd, MPD +# defaults to the systemd journal, which is fine. # +#log_file "~/.mpd/log" + # This setting sets the location of the file which stores the process ID # for use of mpd --kill and some init scripts. This setting is disabled by # default and the pid file will not be stored. # -#pid_file "~/.mpd/pid" +# If you use systemd, do not configure a pid_file. # +#pid_file "~/.mpd/pid" + # This setting sets the location of the file which contains information about # most variables to get MPD back into the same general shape it was in before # it was brought down. This setting is disabled by default and the server diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/doc/plugins.rst new/mpd-0.23.4/doc/plugins.rst --- old/mpd-0.23.3/doc/plugins.rst 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/doc/plugins.rst 2021-11-11 10:16:36.000000000 +0100 @@ -61,6 +61,15 @@ Provides access to UPnP media servers. +.. list-table:: + :widths: 20 80 + :header-rows: 1 + + * - Setting + - Description + * - **interface** + - Interface used to discover media servers. Decided by upnp if left unconfigured. + Storage plugins =============== @@ -841,6 +850,11 @@ ("stop" or "pause") in DSD mode (native DSD or DoP). This is a workaround for some DACs which emit noise when stopping DSD playback. + * - **thesycon_dsd_workaround yes|no** + - If enabled, enables a workaround for a bug in Thesycon USB + audio receivers. On these devices, playing DSD512 or PCM + causes all subsequent attempts to play other DSD rates to fail, + which can be fixed by briefly playing PCM at 44.1 kHz. * - **allowed_formats F1 F2 ...** - Specifies a list of allowed audio formats, separated by a space. All items may contain asterisks as a wild card, and may be followed by "=dop" to enable DoP (DSD over PCM) for this particular format. The first matching format is used, and if none matches, MPD chooses the best fallback of this list. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/doc/protocol.rst new/mpd-0.23.4/doc/protocol.rst --- old/mpd-0.23.3/doc/protocol.rst 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/doc/protocol.rst 2021-11-11 10:16:36.000000000 +0100 @@ -1225,7 +1225,7 @@ .. _command_searchaddpl: -:command:`searchaddpl {NAME} {FILTER} [sort {TYPE}] [window {START:END}]` +:command:`searchaddpl {NAME} {FILTER} [sort {TYPE}] [window {START:END}] [position POS]` Search the database for songs matching ``FILTER`` (see :ref:`Filters <filter_syntax>`) and add them to the playlist named ``NAME``. @@ -1234,6 +1234,9 @@ Parameters have the same meaning as for :ref:`search <command_search>`. + The ``position`` parameter specifies where the songs will be + inserted. [#since_0_23_4]_ + .. _command_update: :command:`update [URI]` @@ -1655,3 +1658,4 @@ .. [#since_0_23] Since :program:`MPD` 0.23 .. [#since_0_23_1] Since :program:`MPD` 0.23.1 .. [#since_0_23_3] Since :program:`MPD` 0.23.3 +.. [#since_0_23_4] Since :program:`MPD` 0.23.4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/meson.build new/mpd-0.23.4/meson.build --- old/mpd-0.23.3/meson.build 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/meson.build 2021-11-11 10:16:36.000000000 +0100 @@ -1,7 +1,7 @@ project( 'mpd', ['c', 'cpp'], - version: '0.23.3', + version: '0.23.4', meson_version: '>= 0.56.0', default_options: [ 'c_std=c11', @@ -44,7 +44,7 @@ version_conf.set_quoted('PACKAGE', meson.project_name()) version_conf.set_quoted('PACKAGE_NAME', meson.project_name()) version_conf.set_quoted('VERSION', meson.project_version()) -version_conf.set_quoted('PROTOCOL_VERSION', '0.23.3') +version_conf.set_quoted('PROTOCOL_VERSION', '0.23.4') configure_file(output: 'Version.h', configuration: version_conf) conf = configuration_data() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/python/build/libs.py new/mpd-0.23.4/python/build/libs.py --- old/mpd-0.23.3/python/build/libs.py 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/python/build/libs.py 2021-11-11 10:16:36.000000000 +0100 @@ -116,8 +116,12 @@ '892aea7a599b5d21842bebf463b5aafdad5711be7008dd84401920c6234820af', 'lib/libopenmpt.a', [ - '--disable-shared', '--enable-static' + '--disable-shared', '--enable-static', + '--disable-openmpt123', + '--without-mpg123', '--without-ogg', '--without-vorbis', '--without-vorbisfile', + '--without-portaudio', '--without-portaudiocpp', '--without-sndfile', ], + base='libopenmpt-0.5.12+release.autotools', ) wildmidi = CmakeProject( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/CommandLine.cxx new/mpd-0.23.4/src/CommandLine.cxx --- old/mpd-0.23.3/src/CommandLine.cxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/CommandLine.cxx 2021-11-11 10:16:36.000000000 +0100 @@ -86,6 +86,9 @@ OPTION_KILL, OPTION_NO_CONFIG, OPTION_NO_DAEMON, +#ifdef __linux__ + OPTION_SYSTEMD, +#endif OPTION_STDOUT, OPTION_STDERR, OPTION_VERBOSE, @@ -98,6 +101,9 @@ {"kill", "kill the currently running mpd session"}, {"no-config", "don't read from config"}, {"no-daemon", "don't detach from console"}, +#ifdef __linux__ + {"systemd", "systemd service mode"}, +#endif {"stdout", nullptr}, // hidden, compatibility with old versions {"stderr", "print messages to stderr"}, {"verbose", 'v', "verbose logging"}, @@ -328,7 +334,7 @@ } void -ParseCommandLine(int argc, char **argv, struct options &options, +ParseCommandLine(int argc, char **argv, CommandLineOptions &options, ConfigData &config) { bool use_config_file = true; @@ -349,6 +355,13 @@ options.daemon = false; break; +#ifdef __linux__ + case OPTION_SYSTEMD: + options.daemon = false; + options.systemd = true; + break; +#endif + case OPTION_STDOUT: case OPTION_STDERR: options.log_stderr = true; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/CommandLine.hxx new/mpd-0.23.4/src/CommandLine.hxx --- old/mpd-0.23.3/src/CommandLine.hxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/CommandLine.hxx 2021-11-11 10:16:36.000000000 +0100 @@ -22,15 +22,20 @@ struct ConfigData; -struct options { +struct CommandLineOptions { bool kill = false; bool daemon = true; + +#ifdef __linux__ + bool systemd = false; +#endif + bool log_stderr = false; bool verbose = false; }; void -ParseCommandLine(int argc, char **argv, struct options &options, +ParseCommandLine(int argc, char **argv, CommandLineOptions &options, ConfigData &config); #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/Main.cxx new/mpd-0.23.4/src/Main.cxx --- old/mpd-0.23.3/src/Main.cxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/Main.cxx 2021-11-11 10:16:36.000000000 +0100 @@ -142,14 +142,24 @@ #ifdef ENABLE_DAEMON static void -glue_daemonize_init(const struct options *options, +glue_daemonize_init(const CommandLineOptions &options, const ConfigData &config) { + auto pid_file = config.GetPath(ConfigOption::PID_FILE); + +#ifdef __linux__ + if (options.systemd && pid_file != nullptr) { + pid_file = nullptr; + fprintf(stderr, + "Ignoring the 'pid_file' setting in systemd mode\n"); + } +#endif + daemonize_init(config.GetString(ConfigOption::USER), config.GetString(ConfigOption::GROUP), - config.GetPath(ConfigOption::PID_FILE)); + std::move(pid_file)); - if (options->kill) + if (options.kill) daemonize_kill(); } @@ -361,7 +371,8 @@ } static inline void -MainConfigured(const struct options &options, const ConfigData &raw_config) +MainConfigured(const CommandLineOptions &options, + const ConfigData &raw_config) { #ifdef ENABLE_DAEMON daemonize_close_stdin(); @@ -384,7 +395,7 @@ const Config config(raw_config); #ifdef ENABLE_DAEMON - glue_daemonize_init(&options, raw_config); + glue_daemonize_init(options, raw_config); #endif TagLoadConfig(raw_config); @@ -582,7 +593,7 @@ static void AndroidMain() { - struct options options; + CommandLineOptions options; ConfigData raw_config; const auto sdcard = Environment::getExternalStorageDirectory(); @@ -642,7 +653,7 @@ static inline void MainOrThrow(int argc, char *argv[]) { - struct options options; + CommandLineOptions options; ConfigData raw_config; ParseCommandLine(argc, argv, options, raw_config); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/command/DatabaseCommands.cxx new/mpd-0.23.4/src/command/DatabaseCommands.cxx --- old/mpd-0.23.3/src/command/DatabaseCommands.cxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/command/DatabaseCommands.cxx 2021-11-11 10:16:36.000000000 +0100 @@ -199,13 +199,20 @@ { const char *playlist = args.shift(); + const unsigned position = ParseQueuePosition(args, UINT_MAX); + SongFilter filter; const auto selection = ParseDatabaseSelection(args, true, filter); const Database &db = client.GetDatabaseOrThrow(); - search_add_to_playlist(db, client.GetStorage(), - playlist, selection); + if (position == UINT_MAX) + search_add_to_playlist(db, client.GetStorage(), + playlist, selection); + else + SearchInsertIntoPlaylist(db, client.GetStorage(), selection, + playlist, position); + return CommandResult::OK; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/command/PlaylistCommands.cxx new/mpd-0.23.4/src/command/PlaylistCommands.cxx --- old/mpd-0.23.3/src/command/PlaylistCommands.cxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/command/PlaylistCommands.cxx 2021-11-11 10:16:36.000000000 +0100 @@ -231,15 +231,14 @@ editor.Insert(position, uri); } else { #ifdef ENABLE_DATABASE - const auto &db = client.GetDatabaseOrThrow(); - const auto *storage = client.GetStorage(); const DatabaseSelection selection(uri, true, nullptr); - db.Visit(selection, [&editor, &position, storage](const auto &song){ - editor.Insert(position, - DatabaseDetachSong(storage, song)); - ++position; - }); + if (SearchInsertIntoPlaylist(client.GetDatabaseOrThrow(), + client.GetStorage(), + selection, + editor, position) == 0) + /* no song was found, don't need to save */ + return CommandResult::OK; #else (void)client; r.Error(ACK_ERROR_NO_EXIST, "No database"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/db/DatabasePlaylist.cxx new/mpd-0.23.4/src/db/DatabasePlaylist.cxx --- old/mpd-0.23.3/src/db/DatabasePlaylist.cxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/db/DatabasePlaylist.cxx 2021-11-11 10:16:36.000000000 +0100 @@ -22,6 +22,7 @@ #include "PlaylistFile.hxx" #include "Interface.hxx" #include "song/DetachedSong.hxx" +#include "protocol/Ack.hxx" #include <functional> @@ -41,3 +42,42 @@ const auto f = [=](auto && arg1) { return AddSong(storage, playlist_path_utf8, arg1); }; db.Visit(selection, f); } + +unsigned +SearchInsertIntoPlaylist(const Database &db, const Storage *storage, + const DatabaseSelection &selection, + PlaylistFileEditor &playlist, + unsigned position) +{ + assert(position <= playlist.size()); + + unsigned n = 0; + + db.Visit(selection, [&playlist, &position, &n, storage](const auto &song){ + playlist.Insert(position + n, + DatabaseDetachSong(storage, song)); + ++position; + ++n; + }); + + return n; +} + +void +SearchInsertIntoPlaylist(const Database &db, const Storage *storage, + const DatabaseSelection &selection, + const char *playlist_name, + unsigned position) +{ + PlaylistFileEditor editor{ + playlist_name, + PlaylistFileEditor::LoadMode::TRY, + }; + + if (position > editor.size()) + throw ProtocolError{ACK_ERROR_ARG, "Bad position"}; + + if (SearchInsertIntoPlaylist(db, storage, selection, + editor, position) > 0) + editor.Save(); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/db/DatabasePlaylist.hxx new/mpd-0.23.4/src/db/DatabasePlaylist.hxx --- old/mpd-0.23.3/src/db/DatabasePlaylist.hxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/db/DatabasePlaylist.hxx 2021-11-11 10:16:36.000000000 +0100 @@ -25,6 +25,7 @@ class Database; class Storage; struct DatabaseSelection; +class PlaylistFileEditor; gcc_nonnull(3) void @@ -32,4 +33,19 @@ const char *playlist_path_utf8, const DatabaseSelection &selection); +/** + * @return the number of songs added + */ +unsigned +SearchInsertIntoPlaylist(const Database &db, const Storage *storage, + const DatabaseSelection &selection, + PlaylistFileEditor &playlist, + unsigned position); + +void +SearchInsertIntoPlaylist(const Database &db, const Storage *storage, + const DatabaseSelection &selection, + const char *playlist_name, + unsigned position); + #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/db/plugins/upnp/UpnpDatabasePlugin.cxx new/mpd-0.23.4/src/db/plugins/upnp/UpnpDatabasePlugin.cxx --- old/mpd-0.23.3/src/db/plugins/upnp/UpnpDatabasePlugin.cxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/db/plugins/upnp/UpnpDatabasePlugin.cxx 2021-11-11 10:16:36.000000000 +0100 @@ -39,6 +39,7 @@ #include "util/ConstBuffer.hxx" #include "util/RecursiveMap.hxx" #include "util/SplitString.hxx" +#include "config/Block.hxx" #include <cassert> #include <string> @@ -76,10 +77,13 @@ UpnpClient_Handle handle; UPnPDeviceDirectory *discovery; + const char* interface; + public: - explicit UpnpDatabase(EventLoop &_event_loop) noexcept + explicit UpnpDatabase(EventLoop &_event_loop, const ConfigBlock &block) noexcept :Database(upnp_db_plugin), - event_loop(_event_loop) {} + event_loop(_event_loop), + interface(block.GetBlockValue("interface", nullptr)) {} static DatabasePtr Create(EventLoop &main_event_loop, EventLoop &io_event_loop, @@ -147,15 +151,15 @@ DatabasePtr UpnpDatabase::Create(EventLoop &, EventLoop &io_event_loop, [[maybe_unused]] DatabaseListener &listener, - const ConfigBlock &) noexcept + const ConfigBlock &block) noexcept { - return std::make_unique<UpnpDatabase>(io_event_loop); + return std::make_unique<UpnpDatabase>(io_event_loop, block);; } void UpnpDatabase::Open() { - handle = UpnpClientGlobalInit(); + handle = UpnpClientGlobalInit(interface); discovery = new UPnPDeviceDirectory(event_loop, handle); try { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/decoder/plugins/FfmpegDecoderPlugin.cxx new/mpd-0.23.4/src/decoder/plugins/FfmpegDecoderPlugin.cxx --- old/mpd-0.23.3/src/decoder/plugins/FfmpegDecoderPlugin.cxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/decoder/plugins/FfmpegDecoderPlugin.cxx 2021-11-11 10:16:36.000000000 +0100 @@ -502,7 +502,7 @@ FmtDebug(ffmpeg_domain, "codec '{}'", codec_descriptor->name); - AVCodec *codec = avcodec_find_decoder(codec_params.codec_id); + const AVCodec *codec = avcodec_find_decoder(codec_params.codec_id); if (!codec) { LogError(ffmpeg_domain, "Unsupported audio codec"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/event/Loop.cxx new/mpd-0.23.4/src/event/Loop.cxx --- old/mpd-0.23.3/src/event/Loop.cxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/event/Loop.cxx 2021-11-11 10:16:36.000000000 +0100 @@ -52,6 +52,13 @@ EventLoop::~EventLoop() noexcept { +#if defined(HAVE_URING) && !defined(NDEBUG) + /* if Run() was never called (maybe because startup failed and + an exception is pending), we need to destruct the + Uring::Manager here or else the assertions below fail */ + uring.reset(); +#endif + assert(defer.empty()); assert(idle.empty()); #ifdef HAVE_THREADED_EVENT_LOOP diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/input/plugins/AlsaInputPlugin.cxx new/mpd-0.23.4/src/input/plugins/AlsaInputPlugin.cxx --- old/mpd-0.23.3/src/input/plugins/AlsaInputPlugin.cxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/input/plugins/AlsaInputPlugin.cxx 2021-11-11 10:16:36.000000000 +0100 @@ -26,6 +26,7 @@ #include "AlsaInputPlugin.hxx" #include "lib/alsa/NonBlock.hxx" +#include "lib/alsa/Error.hxx" #include "lib/alsa/Format.hxx" #include "../InputPlugin.hxx" #include "../AsyncInputStream.hxx" @@ -332,28 +333,23 @@ snd_pcm_hw_params_alloca(&hw_params); if ((err = snd_pcm_hw_params_any(capture_handle, hw_params)) < 0) - throw FormatRuntimeError("Cannot initialize hardware parameter structure (%s)", - snd_strerror(err)); + throw Alsa::MakeError(err, "snd_pcm_hw_params_any() failed"); if ((err = snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) - throw FormatRuntimeError("Cannot set access type (%s)", - snd_strerror(err)); + throw Alsa::MakeError(err, "snd_pcm_hw_params_set_access() failed"); if ((err = snd_pcm_hw_params_set_format(capture_handle, hw_params, ToAlsaPcmFormat(audio_format.format))) < 0) - throw FormatRuntimeError("Cannot set sample format (%s)", - snd_strerror(err)); + throw Alsa::MakeError(err, "Cannot set sample format"); if ((err = snd_pcm_hw_params_set_channels(capture_handle, hw_params, audio_format.channels)) < 0) - throw FormatRuntimeError("Cannot set channels (%s)", - snd_strerror(err)); + throw Alsa::MakeError(err, "Cannot set channels"); if ((err = snd_pcm_hw_params_set_rate(capture_handle, hw_params, audio_format.sample_rate, 0)) < 0) - throw FormatRuntimeError("Cannot set sample rate (%s)", - snd_strerror(err)); + throw Alsa::MakeError(err, "Cannot set sample rate"); snd_pcm_uframes_t buffer_size_min, buffer_size_max; snd_pcm_hw_params_get_buffer_size_min(hw_params, &buffer_size_min); @@ -388,26 +384,22 @@ int direction = -1; if ((err = snd_pcm_hw_params_set_period_size_near(capture_handle, hw_params, &period_size, &direction)) < 0) - throw FormatRuntimeError("Cannot set period size (%s)", - snd_strerror(err)); + throw Alsa::MakeError(err, "Cannot set period size"); } if ((err = snd_pcm_hw_params(capture_handle, hw_params)) < 0) - throw FormatRuntimeError("Cannot set parameters (%s)", - snd_strerror(err)); + throw Alsa::MakeError(err, "snd_pcm_hw_params() failed"); snd_pcm_uframes_t alsa_buffer_size; err = snd_pcm_hw_params_get_buffer_size(hw_params, &alsa_buffer_size); if (err < 0) - throw FormatRuntimeError("snd_pcm_hw_params_get_buffer_size() failed: %s", - snd_strerror(-err)); + throw Alsa::MakeError(err, "snd_pcm_hw_params_get_buffer_size() failed"); snd_pcm_uframes_t alsa_period_size; err = snd_pcm_hw_params_get_period_size(hw_params, &alsa_period_size, nullptr); if (err < 0) - throw FormatRuntimeError("snd_pcm_hw_params_get_period_size() failed: %s", - snd_strerror(-err)); + throw Alsa::MakeError(err, "snd_pcm_hw_params_get_period_size() failed"); FmtDebug(alsa_input_domain, "buffer_size={} period_size={}", alsa_buffer_size, alsa_period_size); @@ -418,8 +410,7 @@ snd_pcm_sw_params_current(capture_handle, sw_params); if ((err = snd_pcm_sw_params(capture_handle, sw_params)) < 0) - throw FormatRuntimeError("unable to install sw params (%s)", - snd_strerror(err)); + throw Alsa::MakeError(err, "snd_pcm_sw_params() failed"); } inline void @@ -430,8 +421,9 @@ if ((err = snd_pcm_open(&capture_handle, spec.GetDeviceName(), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK | global_config.mode)) < 0) - throw FormatRuntimeError("Failed to open device: %s (%s)", - spec.GetDeviceName(), snd_strerror(err)); + throw Alsa::MakeError(err, + fmt::format("Failed to open device {}", + spec.GetDeviceName()).c_str()); try { ConfigureCapture(spec.GetAudioFormat()); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/lib/alsa/Error.cxx new/mpd-0.23.4/src/lib/alsa/Error.cxx --- old/mpd-0.23.3/src/lib/alsa/Error.cxx 1970-01-01 01:00:00.000000000 +0100 +++ new/mpd-0.23.4/src/lib/alsa/Error.cxx 2021-11-11 10:16:36.000000000 +0100 @@ -0,0 +1,44 @@ +/* + * Copyright 2021 Max Kellermann <[email protected]> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Error.hxx" + +#include <alsa/error.h> + +namespace Alsa { + +ErrorCategory error_category; + +std::string +ErrorCategory::message(int condition) const +{ + return snd_strerror(condition); +} + +} // namespace Avahi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/lib/alsa/Error.hxx new/mpd-0.23.4/src/lib/alsa/Error.hxx --- old/mpd-0.23.3/src/lib/alsa/Error.hxx 1970-01-01 01:00:00.000000000 +0100 +++ new/mpd-0.23.4/src/lib/alsa/Error.hxx 2021-11-11 10:16:36.000000000 +0100 @@ -0,0 +1,53 @@ +/* + * Copyright 2021 Max Kellermann <[email protected]> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <system_error> + +namespace Alsa { + +class ErrorCategory final : public std::error_category { +public: + const char *name() const noexcept override { + return "libasound"; + } + + std::string message(int condition) const override; +}; + +extern ErrorCategory error_category; + +inline std::system_error +MakeError(int error, const char *msg) noexcept +{ + return std::system_error(error, error_category, msg); +} + +} // namespace Avahi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/lib/alsa/HwSetup.cxx new/mpd-0.23.4/src/lib/alsa/HwSetup.cxx --- old/mpd-0.23.3/src/lib/alsa/HwSetup.cxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/lib/alsa/HwSetup.cxx 2021-11-11 10:16:36.000000000 +0100 @@ -18,7 +18,9 @@ */ #include "HwSetup.hxx" +#include "Error.hxx" #include "Format.hxx" +#include "lib/fmt/AudioFormatFormatter.hxx" #include "util/ByteOrder.hxx" #include "util/Domain.hxx" #include "util/RuntimeError.hxx" @@ -185,29 +187,27 @@ /* configure HW params */ err = snd_pcm_hw_params_any(pcm, hwparams); if (err < 0) - throw FormatRuntimeError("snd_pcm_hw_params_any() failed: %s", - snd_strerror(-err)); + throw Alsa::MakeError(err, "snd_pcm_hw_params_any() failed"); err = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) - throw FormatRuntimeError("snd_pcm_hw_params_set_access() failed: %s", - snd_strerror(-err)); + throw Alsa::MakeError(err, "snd_pcm_hw_params_set_access() failed"); err = SetupSampleFormat(pcm, hwparams, audio_format.format, params); if (err < 0) - throw FormatRuntimeError("Failed to configure format %s: %s", - sample_format_to_string(audio_format.format), - snd_strerror(-err)); + throw Alsa::MakeError(err, + fmt::format("Failed to configure format {}", + audio_format.format).c_str()); unsigned int channels = audio_format.channels; err = snd_pcm_hw_params_set_channels_near(pcm, hwparams, &channels); if (err < 0) - throw FormatRuntimeError("Failed to configure %i channels: %s", - (int)audio_format.channels, - snd_strerror(-err)); + throw Alsa::MakeError(err, + fmt::format("Failed to configure {} channels", + audio_format.channels).c_str()); audio_format.channels = (int8_t)channels; @@ -218,9 +218,9 @@ err = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &output_sample_rate, nullptr); if (err < 0) - throw FormatRuntimeError("Failed to configure sample rate %u Hz: %s", - requested_sample_rate, - snd_strerror(-err)); + throw Alsa::MakeError(err, + fmt::format("Failed to configure sample rate {} Hz", + requested_sample_rate).c_str()); if (output_sample_rate == 0) throw FormatRuntimeError("Failed to configure sample rate %u Hz", @@ -253,8 +253,7 @@ err = snd_pcm_hw_params_set_buffer_time_near(pcm, hwparams, &buffer_time, nullptr); if (err < 0) - throw FormatRuntimeError("snd_pcm_hw_params_set_buffer_time_near() failed: %s", - snd_strerror(-err)); + throw Alsa::MakeError(err, "snd_pcm_hw_params_set_buffer_time_near() failed"); } else { err = snd_pcm_hw_params_get_buffer_time(hwparams, &buffer_time, nullptr); @@ -275,32 +274,27 @@ err = snd_pcm_hw_params_set_period_time_near(pcm, hwparams, &period_time, nullptr); if (err < 0) - throw FormatRuntimeError("snd_pcm_hw_params_set_period_time_near() failed: %s", - snd_strerror(-err)); + throw Alsa::MakeError(err, "snd_pcm_hw_params_set_period_time_near() failed"); } err = snd_pcm_hw_params(pcm, hwparams); if (err < 0) - throw FormatRuntimeError("snd_pcm_hw_params() failed: %s", - snd_strerror(-err)); + throw Alsa::MakeError(err, "snd_pcm_hw_params() failed"); HwResult result; err = snd_pcm_hw_params_get_format(hwparams, &result.format); if (err < 0) - throw FormatRuntimeError("snd_pcm_hw_params_get_format() failed: %s", - snd_strerror(-err)); + throw Alsa::MakeError(err, "snd_pcm_hw_params_get_format() failed"); err = snd_pcm_hw_params_get_buffer_size(hwparams, &result.buffer_size); if (err < 0) - throw FormatRuntimeError("snd_pcm_hw_params_get_buffer_size() failed: %s", - snd_strerror(-err)); + throw Alsa::MakeError(err, "snd_pcm_hw_params_get_buffer_size() failed"); err = snd_pcm_hw_params_get_period_size(hwparams, &result.period_size, nullptr); if (err < 0) - throw FormatRuntimeError("snd_pcm_hw_params_get_period_size() failed: %s", - snd_strerror(-err)); + throw Alsa::MakeError(err, "snd_pcm_hw_params_get_period_size() failed"); return result; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/lib/alsa/NonBlock.cxx new/mpd-0.23.4/src/lib/alsa/NonBlock.cxx --- old/mpd-0.23.3/src/lib/alsa/NonBlock.cxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/lib/alsa/NonBlock.cxx 2021-11-11 10:16:36.000000000 +0100 @@ -18,6 +18,7 @@ */ #include "NonBlock.hxx" +#include "Error.hxx" #include "event/MultiSocketMonitor.hxx" #include "util/RuntimeError.hxx" @@ -29,8 +30,7 @@ if (count == 0) throw std::runtime_error("snd_pcm_poll_descriptors_count() failed"); else - throw FormatRuntimeError("snd_pcm_poll_descriptors_count() failed: %s", - snd_strerror(-count)); + throw Alsa::MakeError(count, "snd_pcm_poll_descriptors_count() failed"); } struct pollfd *pfds = pfd_buffer.Get(count); @@ -40,8 +40,7 @@ if (count == 0) throw std::runtime_error("snd_pcm_poll_descriptors() failed"); else - throw FormatRuntimeError("snd_pcm_poll_descriptors() failed: %s", - snd_strerror(-count)); + throw Alsa::MakeError(count, "snd_pcm_poll_descriptors() failed"); } m.ReplaceSocketList(pfds, count); @@ -71,8 +70,7 @@ unsigned short dummy; int err = snd_pcm_poll_descriptors_revents(pcm, pfds, i - pfds, &dummy); if (err < 0) - throw FormatRuntimeError("snd_pcm_poll_descriptors_revents() failed: %s", - snd_strerror(-err)); + throw Alsa::MakeError(err, "snd_pcm_poll_descriptors_revents() failed"); } Event::Duration diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/lib/alsa/meson.build new/mpd-0.23.4/src/lib/alsa/meson.build --- old/mpd-0.23.3/src/lib/alsa/meson.build 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/lib/alsa/meson.build 2021-11-11 10:16:36.000000000 +0100 @@ -14,6 +14,7 @@ alsa = static_library( 'alsa', 'Version.cxx', + 'Error.cxx', 'AllowedFormat.cxx', 'HwSetup.cxx', 'NonBlock.cxx', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/lib/ffmpeg/Codec.hxx new/mpd-0.23.4/src/lib/ffmpeg/Codec.hxx --- old/mpd-0.23.3/src/lib/ffmpeg/Codec.hxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/lib/ffmpeg/Codec.hxx 2021-11-11 10:16:36.000000000 +0100 @@ -36,7 +36,7 @@ public: CodecContext() = default; - explicit CodecContext(AVCodec &codec) + explicit CodecContext(const AVCodec &codec) :codec_context(avcodec_alloc_context3(&codec)) { if (codec_context == nullptr) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/lib/fmt/AudioFormatFormatter.hxx new/mpd-0.23.4/src/lib/fmt/AudioFormatFormatter.hxx --- old/mpd-0.23.3/src/lib/fmt/AudioFormatFormatter.hxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/lib/fmt/AudioFormatFormatter.hxx 2021-11-11 10:16:36.000000000 +0100 @@ -36,6 +36,16 @@ #include <fmt/format.h> template<> +struct fmt::formatter<SampleFormat> : formatter<string_view> +{ + template<typename FormatContext> + auto format(const SampleFormat format, FormatContext &ctx) { + return formatter<string_view>::format(sample_format_to_string(format), + ctx); + } +}; + +template<> struct fmt::formatter<AudioFormat> : formatter<string_view> { template<typename FormatContext> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/lib/upnp/ClientInit.cxx new/mpd-0.23.4/src/lib/upnp/ClientInit.cxx --- old/mpd-0.23.3/src/lib/upnp/ClientInit.cxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/lib/upnp/ClientInit.cxx 2021-11-11 10:16:36.000000000 +0100 @@ -57,9 +57,9 @@ } UpnpClient_Handle -UpnpClientGlobalInit() +UpnpClientGlobalInit(const char* iface) { - UpnpGlobalInit(); + UpnpGlobalInit(iface); try { const std::lock_guard<Mutex> protect(upnp_client_init_mutex); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/lib/upnp/ClientInit.hxx new/mpd-0.23.4/src/lib/upnp/ClientInit.hxx --- old/mpd-0.23.3/src/lib/upnp/ClientInit.hxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/lib/upnp/ClientInit.hxx 2021-11-11 10:16:36.000000000 +0100 @@ -23,7 +23,7 @@ #include "Compat.hxx" UpnpClient_Handle -UpnpClientGlobalInit(); +UpnpClientGlobalInit(const char* iface); void UpnpClientGlobalFinish() noexcept; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/lib/upnp/Init.cxx new/mpd-0.23.4/src/lib/upnp/Init.cxx --- old/mpd-0.23.3/src/lib/upnp/Init.cxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/lib/upnp/Init.cxx 2021-11-11 10:16:36.000000000 +0100 @@ -33,12 +33,13 @@ static unsigned upnp_ref; static void -DoInit() +DoInit(const char* iface) { + #ifdef UPNP_ENABLE_IPV6 - auto code = UpnpInit2(nullptr, 0); + auto code = UpnpInit2(iface, 0); #else - auto code = UpnpInit(nullptr, 0); + auto code = UpnpInit(iface, 0); #endif if (code != UPNP_E_SUCCESS) throw FormatRuntimeError("UpnpInit() failed: %s", @@ -53,12 +54,12 @@ } void -UpnpGlobalInit() +UpnpGlobalInit(const char* iface) { const std::lock_guard<Mutex> protect(upnp_init_mutex); if (upnp_ref == 0) - DoInit(); + DoInit(iface); ++upnp_ref; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/lib/upnp/Init.hxx new/mpd-0.23.4/src/lib/upnp/Init.hxx --- old/mpd-0.23.3/src/lib/upnp/Init.hxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/lib/upnp/Init.hxx 2021-11-11 10:16:36.000000000 +0100 @@ -21,7 +21,7 @@ #define MPD_UPNP_INIT_HXX void -UpnpGlobalInit(); +UpnpGlobalInit(const char* iface); void UpnpGlobalFinish() noexcept; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/mixer/plugins/AlsaMixerPlugin.cxx new/mpd-0.23.4/src/mixer/plugins/AlsaMixerPlugin.cxx --- old/mpd-0.23.3/src/mixer/plugins/AlsaMixerPlugin.cxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/mixer/plugins/AlsaMixerPlugin.cxx 2021-11-11 10:16:36.000000000 +0100 @@ -18,6 +18,7 @@ */ #include "lib/alsa/NonBlock.hxx" +#include "lib/alsa/Error.hxx" #include "mixer/MixerInternal.hxx" #include "mixer/Listener.hxx" #include "output/OutputAPI.hxx" @@ -264,16 +265,15 @@ int err; if ((err = snd_mixer_attach(handle, device)) < 0) - throw FormatRuntimeError("failed to attach to %s: %s", - device, snd_strerror(err)); + throw Alsa::MakeError(err, + fmt::format("failed to attach to {}", + device).c_str()); if ((err = snd_mixer_selem_register(handle, nullptr, nullptr)) < 0) - throw FormatRuntimeError("snd_mixer_selem_register() failed: %s", - snd_strerror(err)); + throw Alsa::MakeError(err, "snd_mixer_selem_register() failed"); if ((err = snd_mixer_load(handle)) < 0) - throw FormatRuntimeError("snd_mixer_load() failed: %s\n", - snd_strerror(err)); + throw Alsa::MakeError(err, "snd_mixer_load() failed"); elem = alsa_mixer_lookup_elem(handle, control, index); if (elem == nullptr) @@ -294,8 +294,7 @@ err = snd_mixer_open(&handle, 0); if (err < 0) - throw FormatRuntimeError("snd_mixer_open() failed: %s", - snd_strerror(err)); + throw Alsa::MakeError(err, "snd_mixer_open() failed"); try { Setup(); @@ -325,8 +324,7 @@ err = snd_mixer_handle_events(handle); if (err < 0) - throw FormatRuntimeError("snd_mixer_handle_events() failed: %s", - snd_strerror(err)); + throw Alsa::MakeError(err, "snd_mixer_handle_events() failed"); int volume = GetPercentVolume(); if (resulting_volume >= 0 && volume == resulting_volume) @@ -343,8 +341,7 @@ int err = set_normalized_playback_volume(elem, 0.01*volume, 1); if (err < 0) - throw FormatRuntimeError("failed to set ALSA volume: %s", - snd_strerror(err)); + throw Alsa::MakeError(err, "failed to set ALSA volume"); desired_volume = volume; resulting_volume = GetPercentVolume(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/neighbor/plugins/UpnpNeighborPlugin.cxx new/mpd-0.23.4/src/neighbor/plugins/UpnpNeighborPlugin.cxx --- old/mpd-0.23.3/src/neighbor/plugins/UpnpNeighborPlugin.cxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/neighbor/plugins/UpnpNeighborPlugin.cxx 2021-11-11 10:16:36.000000000 +0100 @@ -74,7 +74,7 @@ void UpnpNeighborExplorer::Open() { - auto handle = UpnpClientGlobalInit(); + auto handle = UpnpClientGlobalInit(nullptr); discovery = new UPnPDeviceDirectory(event_loop, handle, this); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/output/plugins/AlsaOutputPlugin.cxx new/mpd-0.23.4/src/output/plugins/AlsaOutputPlugin.cxx --- old/mpd-0.23.3/src/output/plugins/AlsaOutputPlugin.cxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/output/plugins/AlsaOutputPlugin.cxx 2021-11-11 10:16:36.000000000 +0100 @@ -20,6 +20,7 @@ #include "config.h" #include "AlsaOutputPlugin.hxx" #include "lib/alsa/AllowedFormat.hxx" +#include "lib/alsa/Error.hxx" #include "lib/alsa/HwSetup.hxx" #include "lib/alsa/NonBlock.hxx" #include "lib/alsa/PeriodBuffer.hxx" @@ -42,6 +43,10 @@ #include "event/Call.hxx" #include "Log.hxx" +#ifdef ENABLE_DSD +#include "util/AllocatedArray.hxx" +#endif + #include <alsa/asoundlib.h> #include <boost/lockfree/spsc_queue.hpp> @@ -101,6 +106,16 @@ * Are we currently draining with #stop_dsd_silence? */ bool in_stop_dsd_silence; + + /** + * Enable the DSD sync workaround for Thesycon USB audio + * receivers? On this device, playing DSD512 or PCM causes + * all subsequent attempts to play other DSD rates to fail, + * which can be fixed by briefly playing PCM at 44.1 kHz. + */ + const bool thesycon_dsd_workaround; + + bool need_thesycon_dsd_workaround = thesycon_dsd_workaround; #endif /** libasound's buffer_time setting (in microseconds) */ @@ -432,6 +447,8 @@ /* legacy name from MPD 0.18 and older: */ block.GetBlockValue("dsd_usb", false)), stop_dsd_silence(block.GetBlockValue("stop_dsd_silence", false)), + thesycon_dsd_workaround(block.GetBlockValue("thesycon_dsd_workaround", + false)), #endif buffer_time(block.GetPositiveValue("buffer_time", MPD_ALSA_BUFFER_TIME_US)), @@ -519,24 +536,20 @@ int err = snd_pcm_sw_params_current(pcm, swparams); if (err < 0) - throw FormatRuntimeError("snd_pcm_sw_params_current() failed: %s", - snd_strerror(-err)); + throw Alsa::MakeError(err, "snd_pcm_sw_params_current() failed"); err = snd_pcm_sw_params_set_start_threshold(pcm, swparams, start_threshold); if (err < 0) - throw FormatRuntimeError("snd_pcm_sw_params_set_start_threshold() failed: %s", - snd_strerror(-err)); + throw Alsa::MakeError(err, "snd_pcm_sw_params_set_start_threshold() failed"); err = snd_pcm_sw_params_set_avail_min(pcm, swparams, avail_min); if (err < 0) - throw FormatRuntimeError("snd_pcm_sw_params_set_avail_min() failed: %s", - snd_strerror(-err)); + throw Alsa::MakeError(err, "snd_pcm_sw_params_set_avail_min() failed"); err = snd_pcm_sw_params(pcm, swparams); if (err < 0) - throw FormatRuntimeError("snd_pcm_sw_params() failed: %s", - snd_strerror(-err)); + throw Alsa::MakeError(err, "snd_pcm_sw_params() failed"); } inline void @@ -678,6 +691,97 @@ return haystack.front(); } +#ifdef ENABLE_DSD + +static void +Play_44_1_Silence(snd_pcm_t *pcm) +{ + snd_pcm_hw_params_t *hw; + snd_pcm_hw_params_alloca(&hw); + + int err; + + err = snd_pcm_hw_params_any(pcm, hw); + if (err < 0) + throw Alsa::MakeError(err, "snd_pcm_hw_params_any() failed"); + + err = snd_pcm_hw_params_set_access(pcm, hw, + SND_PCM_ACCESS_RW_INTERLEAVED); + if (err < 0) + throw Alsa::MakeError(err, "snd_pcm_hw_params_set_access() failed"); + + err = snd_pcm_hw_params_set_format(pcm, hw, SND_PCM_FORMAT_S16); + if (err < 0) + throw Alsa::MakeError(err, "snd_pcm_hw_params_set_format() failed"); + + unsigned channels = 1; + err = snd_pcm_hw_params_set_channels_near(pcm, hw, &channels); + if (err < 0) + throw Alsa::MakeError(err, "snd_pcm_hw_params_set_channels_near() failed"); + + constexpr snd_pcm_uframes_t rate = 44100; + err = snd_pcm_hw_params_set_rate(pcm, hw, rate, 0); + if (err < 0) + throw Alsa::MakeError(err, "snd_pcm_hw_params_set_rate() failed"); + + snd_pcm_uframes_t buffer_size = 1; + err = snd_pcm_hw_params_set_buffer_size_near(pcm, hw, &buffer_size); + if (err < 0) + throw Alsa::MakeError(err, "snd_pcm_hw_params_set_buffer_size_near() failed"); + + snd_pcm_uframes_t period_size = 1; + int dir = 0; + err = snd_pcm_hw_params_set_period_size_near(pcm, hw, &period_size, + &dir); + if (err < 0) + throw Alsa::MakeError(err, "snd_pcm_hw_params_set_period_size_near() failed"); + + err = snd_pcm_hw_params(pcm, hw); + if (err < 0) + throw Alsa::MakeError(err, "snd_pcm_hw_params() failed"); + + snd_pcm_sw_params_t *sw; + snd_pcm_sw_params_alloca(&sw); + + err = snd_pcm_sw_params_current(pcm, sw); + if (err < 0) + throw Alsa::MakeError(err, "snd_pcm_sw_params_current() failed"); + + err = snd_pcm_sw_params_set_start_threshold(pcm, sw, period_size); + if (err < 0) + throw Alsa::MakeError(err, "snd_pcm_sw_params_set_start_threshold() failed"); + + err = snd_pcm_sw_params(pcm, sw); + if (err < 0) + throw Alsa::MakeError(err, "snd_pcm_sw_params() failed"); + + err = snd_pcm_prepare(pcm); + if (err < 0) + throw Alsa::MakeError(err, "snd_pcm_prepare() failed"); + + AllocatedArray<int16_t> buffer{channels * period_size}; + std::fill(buffer.begin(), buffer.end(), 0); + + /* play at least 250ms of silence */ + for (snd_pcm_uframes_t remaining_frames = rate / 4;;) { + auto n = snd_pcm_writei(pcm, buffer.data(), + period_size); + if (n < 0) + throw Alsa::MakeError(err, "snd_pcm_writei() failed"); + + if (snd_pcm_uframes_t(n) >= remaining_frames) + break; + + remaining_frames -= snd_pcm_uframes_t(n); + } + + err = snd_pcm_drain(pcm); + if (err < 0) + throw Alsa::MakeError(err, "snd_pcm_drain() failed"); +} + +#endif + void AlsaOutput::Open(AudioFormat &audio_format) { @@ -704,13 +808,30 @@ int err = snd_pcm_open(&pcm, GetDevice(), SND_PCM_STREAM_PLAYBACK, mode); if (err < 0) - throw FormatRuntimeError("Failed to open ALSA device \"%s\": %s", - GetDevice(), snd_strerror(err)); + throw Alsa::MakeError(err, + fmt::format("Failed to open ALSA device \"{}\"", + GetDevice()).c_str()); FmtDebug(alsa_output_domain, "opened {} type={}", snd_pcm_name(pcm), snd_pcm_type_name(snd_pcm_type(pcm))); +#ifdef ENABLE_DSD + if (need_thesycon_dsd_workaround && + audio_format.format == SampleFormat::DSD && + audio_format.sample_rate <= 256 * 44100 / 8) { + LogDebug(alsa_output_domain, "Playing some 44.1 kHz silence"); + + try { + Play_44_1_Silence(pcm); + } catch (...) { + LogError(std::current_exception()); + } + + need_thesycon_dsd_workaround = false; + } +#endif + PcmExport::Params params; params.alsa_channel_order = true; @@ -735,6 +856,11 @@ use_dsd = audio_format.format == SampleFormat::DSD; in_stop_dsd_silence = false; + if (thesycon_dsd_workaround && + (!use_dsd || + audio_format.sample_rate > 256 * 44100 / 8)) + need_thesycon_dsd_workaround = true; + if (params.dsd_mode == PcmExport::DsdMode::DOP) LogDebug(alsa_output_domain, "DoP (DSD over PCM) enabled"); #endif @@ -897,8 +1023,8 @@ if (frames_written == -EAGAIN) return false; - throw FormatRuntimeError("snd_pcm_writei() failed: %s", - snd_strerror(-frames_written)); + throw Alsa::MakeError(frames_written, + "snd_pcm_writei() failed"); } /* need to call CopyRingToPeriodBuffer() and @@ -947,8 +1073,7 @@ else if (result == -EAGAIN) return false; else - throw FormatRuntimeError("snd_pcm_drain() failed: %s", - snd_strerror(-result)); + throw Alsa::MakeError(result, "snd_pcm_drain() failed"); } void @@ -1147,8 +1272,7 @@ int err = snd_pcm_prepare(pcm); if (err < 0) - throw FormatRuntimeError("snd_pcm_prepare() failed: %s", - snd_strerror(-err)); + throw Alsa::MakeError(err, "snd_pcm_prepare() failed"); } { @@ -1236,8 +1360,8 @@ return; if (Recover(frames_written) < 0) - throw FormatRuntimeError("snd_pcm_writei() failed: %s", - snd_strerror(-frames_written)); + throw Alsa::MakeError(frames_written, + "snd_pcm_writei() failed"); /* recovered; try again in the next DispatchSockets() call */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/src/output/plugins/PipeWireOutputPlugin.cxx new/mpd-0.23.4/src/output/plugins/PipeWireOutputPlugin.cxx --- old/mpd-0.23.3/src/output/plugins/PipeWireOutputPlugin.cxx 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/src/output/plugins/PipeWireOutputPlugin.cxx 2021-11-11 10:16:36.000000000 +0100 @@ -55,6 +55,7 @@ #include <boost/lockfree/spsc_queue.hpp> #include <algorithm> +#include <array> #include <stdexcept> #include <string> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/systemd/system/mpd.service.in new/mpd-0.23.4/systemd/system/mpd.service.in --- old/mpd-0.23.3/systemd/system/mpd.service.in 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/systemd/system/mpd.service.in 2021-11-11 10:16:36.000000000 +0100 @@ -5,11 +5,7 @@ [Service] Type=notify -ExecStart=@prefix@/bin/mpd --no-daemon - -# Create /run/mpd (if MPD is launched without the socket unit and is -# configured to bind listener sockets there). -RuntimeDirectory=mpd +ExecStart=@prefix@/bin/mpd --systemd # Enable this setting to ask systemd to watch over MPD, see # systemd.service(5). This is disabled by default because it causes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/systemd/user/mpd.service.in new/mpd-0.23.4/systemd/user/mpd.service.in --- old/mpd-0.23.3/systemd/user/mpd.service.in 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/systemd/user/mpd.service.in 2021-11-11 10:16:36.000000000 +0100 @@ -5,11 +5,7 @@ [Service] Type=notify -ExecStart=@prefix@/bin/mpd --no-daemon - -# Create /run/user/$UID/mpd (if MPD is launched without the socket -# unit and is configured to bind listener sockets there). -RuntimeDirectory=mpd +ExecStart=@prefix@/bin/mpd --systemd # Enable this setting to ask systemd to watch over MPD, see # systemd.service(5). This is disabled by default because it causes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.23.3/win32/build.py new/mpd-0.23.4/win32/build.py --- old/mpd-0.23.3/win32/build.py 2021-10-31 18:13:10.000000000 +0100 +++ new/mpd-0.23.4/win32/build.py 2021-11-11 10:16:36.000000000 +0100 @@ -99,6 +99,7 @@ libid3tag, liblame, libmodplug, + libopenmpt, wildmidi, gme, ffmpeg, ++++++ mpd-conf.patch ++++++ --- /var/tmp/diff_new_pack.wxl7FG/_old 2021-11-13 22:49:08.281278130 +0100 +++ /var/tmp/diff_new_pack.wxl7FG/_new 2021-11-13 22:49:08.281278130 +0100 @@ -1,5 +1,6 @@ ---- mpd-0.22.4.orig/doc/mpdconf.example 2021-01-21 19:21:20.000000000 +0300 -+++ mpd-0.22.4/doc/mpdconf.example 2021-01-23 14:43:26.000000000 +0300 +diff -Pdpru mpd-0.23.4.orig/doc/mpdconf.example mpd-0.23.4/doc/mpdconf.example +--- mpd-0.23.4.orig/doc/mpdconf.example 2021-11-11 12:16:36.000000000 +0300 ++++ mpd-0.23.4/doc/mpdconf.example 2021-11-13 01:39:07.843410617 +0300 @@ -17,7 +17,7 @@ # playlist files not created by the server but only if they are in the MPD # format. This setting defaults to playlist saving being disabled. @@ -15,23 +16,25 @@ # -#db_file "~/.mpd/database" +#db_file "/var/lib/mpd/mpd.db" - # + # These settings are the locations for the daemon log files for the daemon. - # These logs are great for troubleshooting, depending on your log_level -@@ -34,25 +34,25 @@ - # The special value "syslog" makes MPD use the local syslog daemon. This - # setting defaults to logging to syslog. # --#log_file "~/.mpd/log" -+log_file "/var/log/mpd.log" +@@ -35,7 +35,7 @@ + # If you use systemd, do not configure a log_file. With systemd, MPD + # defaults to the systemd journal, which is fine. # +-#log_file "~/.mpd/log" ++#log_file "/var/log/mpd.log" + # This setting sets the location of the file which stores the process ID # for use of mpd --kill and some init scripts. This setting is disabled by - # default and the pid file will not be stored. +@@ -43,19 +43,19 @@ # --#pid_file "~/.mpd/pid" -+pid_file "/run/mpd/mpd.pid" + # If you use systemd, do not configure a pid_file. # +-#pid_file "~/.mpd/pid" ++#pid_file "/run/mpd/mpd.pid" + # This setting sets the location of the file which contains information about # most variables to get MPD back into the same general shape it was in before # it was brought down. This setting is disabled by default and the server @@ -48,7 +51,7 @@ # ############################################################################### -@@ -64,14 +64,14 @@ +@@ -67,14 +67,14 @@ # initialization. This setting is disabled by default and MPD is run as the # current user. # @@ -65,7 +68,7 @@ # # This setting sets the address for the daemon to listen on. Careful attention # should be paid if this is assigned to anything other than the default, any. -@@ -82,7 +82,7 @@ +@@ -85,7 +85,7 @@ #bind_to_address "any" # # And for Unix Socket @@ -74,7 +77,7 @@ # # This setting is the TCP port that is desired for the daemon to get assigned # to. -@@ -93,7 +93,7 @@ +@@ -96,7 +96,7 @@ # troubleshooting. Available setting arguments are "notice", "info", "verbose", # "warning" and "error". # @@ -83,7 +86,7 @@ # # Setting "restore_paused" to "yes" puts MPD into pause mode instead # of starting playback after startup. -@@ -117,7 +117,7 @@ +@@ -120,7 +120,7 @@ # This setting enables automatic update of MPD's database when files in # music_directory are changed. # @@ -92,7 +95,7 @@ # # Limit the depth of the directories being watched, 0 means only watch # the music directory itself. There is no limit by default. -@@ -147,7 +147,7 @@ +@@ -150,7 +150,7 @@ # If this setting is set to "yes", service information will be published with # Zeroconf / Avahi. # @@ -101,7 +104,7 @@ # # The argument to this setting will be the Zeroconf / Avahi unique name for # this MPD server on the network. %h will be replaced with the hostname. -@@ -214,8 +214,9 @@ input { +@@ -217,8 +217,9 @@ input { # #audio_output { # type "alsa" @@ -109,11 +112,17 @@ -## device "hw:0,0" # optional +# name "ALSA Device" +## device "plug:plugequal" # optional -+## mixer_control "Master" # optional ++## mixer_control "Master" # optional ## mixer_type "hardware" # optional ## mixer_device "default" # optional ## mixer_control "PCM" # optional -@@ -243,9 +244,9 @@ input { +@@ -241,14 +242,14 @@ input { + #audio_output { + # type "shout" + # encoder "vorbis" # optional +-# name "My Shout Stream" ++# name "Shout Stream" + # host "localhost" # port "8000" # mount "/mpd.ogg" # password "hackme" @@ -126,16 +135,16 @@ ## protocol "icecast2" # optional ## user "source" # optional ## description "My Stream Description" # optional -@@ -263,34 +264,34 @@ input { +@@ -266,34 +267,34 @@ input { # name "My recorder" # encoder "vorbis" # optional, vorbis or lame # path "/var/lib/mpd/recorder/mpd.ogg" -## quality "5.0" # do not define if bitrate is defined -# bitrate "128" # do not define if quality is defined -# format "44100:16:1" -+# quality "6.0" # do not define if bitrate is defined -+## bitrate "192" # do not define if quality is defined -+## format "48000:16:2" #optional ++## quality "6.0" # do not define if bitrate is defined ++# bitrate "192" # do not define if quality is defined ++# format "48000:16:2" #} # # An example of a httpd output (built-in HTTP streaming server): @@ -147,16 +156,14 @@ +# name "HTTP Stream" +# encoder "vorbis" # optional, vorbis or lame # port "8000" --# bind_to_address "0.0.0.0" # optional, IPv4 or IPv6 + # bind_to_address "0.0.0.0" # optional, IPv4 or IPv6 -## quality "5.0" # do not define if bitrate is defined -# bitrate "128" # do not define if quality is defined -# format "44100:16:1" --# max_clients "0" # optional 0=no limit -+# bind_to_address "0.0.0.0" # optional, IPv4 or IPv6 -+# quality "6.0" # do not define if bitrate is defined -+## bitrate "192" # do not define if quality is defined -+## format "48000:16:2" #optional -+## max_clients "0" # optional 0=no limit ++## quality "6.0" # do not define if bitrate is defined ++# bitrate "192" # do not define if quality is defined ++# format "48000:16:2" + # max_clients "0" # optional 0=no limit #} # # An example of a pulseaudio output (streaming to a remote pulseaudio server) @@ -175,16 +182,16 @@ # # An example of a winmm output (Windows multimedia API). # -@@ -352,7 +353,7 @@ input { +@@ -355,7 +356,7 @@ input { # command "AudioCompress -m | aplay -f cd 2>/dev/null" ## Or to send raw PCM stream through PCM: # command "nc example.org 8765" -# format "44100:16:2" -+## format "48000:16:2" # optional ++# format "48000:16:2" #} # ## An example of a null output (for no audio output): -@@ -410,6 +411,6 @@ input { +@@ -413,6 +414,6 @@ input { # If file or directory names do not display correctly for your locale then you # may need to modify this setting. # ++++++ mpd-user.conf ++++++ --- /var/tmp/diff_new_pack.wxl7FG/_old 2021-11-13 22:49:08.309278151 +0100 +++ /var/tmp/diff_new_pack.wxl7FG/_new 2021-11-13 22:49:08.309278151 +0100 @@ -2,7 +2,7 @@ playlist_directory "~/.mpd/playlists" db_file "~/.mpd/database" log_file "~/.mpd/log" -pid_file "~/.mpd/pid" +#pid_file "~/.mpd/pid" state_file "~/.mpd/state" sticker_file "~/.mpd/sticker.sql" bind_to_address "127.0.0.1"
