Hello community,

here is the log from the commit of package mpd for openSUSE:Factory checked in 
at 2020-04-27 23:34:24
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/mpd (Old)
 and      /work/SRC/openSUSE:Factory/.mpd.new.2738 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "mpd"

Mon Apr 27 23:34:24 2020 rev:20 rq:797726 version:0.21.23

Changes:
--------
--- /work/SRC/openSUSE:Factory/mpd/mpd.changes  2020-04-05 20:55:58.705341844 
+0200
+++ /work/SRC/openSUSE:Factory/.mpd.new.2738/mpd.changes        2020-04-27 
23:34:41.007090530 +0200
@@ -1,0 +2,16 @@
+Sat Apr 25 18:01:18 UTC 2020 - Илья Индиго <i...@ilya.pp.ua>
+
+- Update to 0.21.23
+  * https://raw.githubusercontent.com/MusicPlayerDaemon/MPD/v0.21.23/NEWS
+  * protocol: add tag fallback for AlbumSort
+  * storage
+    * curl: fix corrupt "href" values in the presence of XML entities
+    * curl: unescape "href" values
+  * input
+    * nfs: fix crash bug
+    * nfs: fix freeze bug on reconnect
+  * decoder: gme: adapt to API change in the upcoming version 0.7.0
+  * output: alsa: implement channel mapping for 5.0 and 7.0
+  * player: drain: outputs at end of song in "single" mode
+
+-------------------------------------------------------------------

Old:
----
  mpd-0.21.22.tar.xz

New:
----
  mpd-0.21.23.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ mpd.spec ++++++
--- /var/tmp/diff_new_pack.IpNRmZ/_old  2020-04-27 23:34:42.103092669 +0200
+++ /var/tmp/diff_new_pack.IpNRmZ/_new  2020-04-27 23:34:42.107092678 +0200
@@ -20,7 +20,7 @@
 %bcond_with    faad
 %bcond_without mpd_iso9660
 Name:           mpd
-Version:        0.21.22
+Version:        0.21.23
 Release:        0
 Summary:        Music Player Daemon
 License:        GPL-2.0-or-later

++++++ mpd-0.21.22.tar.xz -> mpd-0.21.23.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/NEWS new/mpd-0.21.23/NEWS
--- old/mpd-0.21.22/NEWS        2020-04-02 17:48:56.000000000 +0200
+++ new/mpd-0.21.23/NEWS        2020-04-23 17:46:20.000000000 +0200
@@ -1,3 +1,21 @@
+ver 0.21.23 (2020/04/23)
+* protocol
+  - add tag fallback for AlbumSort
+* storage
+  - curl: fix corrupt "href" values in the presence of XML entities
+  - curl: unescape "href" values
+* input
+  - nfs: fix crash bug
+  - nfs: fix freeze bug on reconnect
+* decoder
+  - gme: adapt to API change in the upcoming version 0.7.0
+* output
+  - alsa: implement channel mapping for 5.0 and 7.0
+* player
+  - drain outputs at end of song in "single" mode
+* Windows
+  - fix case insensitive search
+
 ver 0.21.22 (2020/04/02)
 * database
   - simple: optimize startup
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/android/AndroidManifest.xml 
new/mpd-0.21.23/android/AndroidManifest.xml
--- old/mpd-0.21.22/android/AndroidManifest.xml 2020-04-02 17:48:56.000000000 
+0200
+++ new/mpd-0.21.23/android/AndroidManifest.xml 2020-04-23 17:46:20.000000000 
+0200
@@ -2,8 +2,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android";
           package="org.musicpd"
           android:installLocation="auto"
-          android:versionCode="45"
-          android:versionName="0.21.22">
+          android:versionCode="46"
+          android:versionName="0.21.23">
 
   <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/doc/conf.py new/mpd-0.21.23/doc/conf.py
--- old/mpd-0.21.22/doc/conf.py 2020-04-02 17:48:56.000000000 +0200
+++ new/mpd-0.21.23/doc/conf.py 2020-04-23 17:46:20.000000000 +0200
@@ -38,7 +38,7 @@
 # built documents.
 #
 # The short X.Y version.
-version = '0.21.22'
+version = '0.21.23'
 # The full version, including alpha/beta/rc tags.
 release = version
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/meson.build new/mpd-0.21.23/meson.build
--- old/mpd-0.21.22/meson.build 2020-04-02 17:48:56.000000000 +0200
+++ new/mpd-0.21.23/meson.build 2020-04-23 17:46:20.000000000 +0200
@@ -1,7 +1,7 @@
 project(
   'mpd',
   ['c', 'cpp'],
-  version: '0.21.22',
+  version: '0.21.23',
   meson_version: '>= 0.49.0',
   default_options: [
     'c_std=c99',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/decoder/plugins/GmeDecoderPlugin.cxx 
new/mpd-0.21.23/src/decoder/plugins/GmeDecoderPlugin.cxx
--- old/mpd-0.21.22/src/decoder/plugins/GmeDecoderPlugin.cxx    2020-04-02 
17:48:56.000000000 +0200
+++ new/mpd-0.21.23/src/decoder/plugins/GmeDecoderPlugin.cxx    2020-04-23 
17:46:20.000000000 +0200
@@ -185,7 +185,11 @@
                LogWarning(gme_domain, gme_err);
 
        if (length > 0)
-               gme_set_fade(emu, length);
+               gme_set_fade(emu, length
+#if GME_VERSION >= 0x000700
+                            , 8000
+#endif
+                            );
 
        /* play */
        DecoderCommand cmd;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/event/PollGroupWinSelect.cxx 
new/mpd-0.21.23/src/event/PollGroupWinSelect.cxx
--- old/mpd-0.21.22/src/event/PollGroupWinSelect.cxx    2020-04-02 
17:48:56.000000000 +0200
+++ new/mpd-0.21.23/src/event/PollGroupWinSelect.cxx    2020-04-23 
17:46:20.000000000 +0200
@@ -23,8 +23,8 @@
 
 #include "PollGroupWinSelect.hxx"
 
-constexpr int EVENT_READ = 0;
-constexpr int EVENT_WRITE = 1;
+static constexpr int EVENT_READ = 0;
+static constexpr int EVENT_WRITE = 1;
 
 static constexpr
 bool HasEvent(unsigned events, int event_id) noexcept
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/event/SocketMonitor.cxx 
new/mpd-0.21.23/src/event/SocketMonitor.cxx
--- old/mpd-0.21.22/src/event/SocketMonitor.cxx 2020-04-02 17:48:56.000000000 
+0200
+++ new/mpd-0.21.23/src/event/SocketMonitor.cxx 2020-04-23 17:46:20.000000000 
+0200
@@ -20,6 +20,10 @@
 #include "SocketMonitor.hxx"
 #include "Loop.hxx"
 
+#ifdef USE_EPOLL
+#include <cerrno>
+#endif
+
 #include <assert.h>
 
 #ifdef _WIN32
@@ -86,6 +90,21 @@
 
        if (success)
                scheduled_flags = flags;
+#ifdef USE_EPOLL
+       else if (errno == EBADF || errno == ENOENT)
+               /* the socket was probably closed by somebody else
+                  (EBADF) or a new file descriptor with the same
+                  number was created but not registered already
+                  (ENOENT) - we can assume that there are no
+                  scheduled events */
+               /* note that when this happens, we're actually lucky
+                  that it has failed - imagine another thread may
+                  meanwhile have created something on the same file
+                  descriptor number, and has registered it; the
+                  epoll_ctl() call above would then have succeeded,
+                  but broke the other thread's epoll registration */
+               scheduled_flags = 0;
+#endif
 
        return success;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/event/SocketMonitor.hxx 
new/mpd-0.21.23/src/event/SocketMonitor.hxx
--- old/mpd-0.21.22/src/event/SocketMonitor.hxx 2020-04-02 17:48:56.000000000 
+0200
+++ new/mpd-0.21.23/src/event/SocketMonitor.hxx 2020-04-23 17:46:20.000000000 
+0200
@@ -109,7 +109,7 @@
        }
 
        bool ScheduleRead() noexcept {
-               return Schedule(GetScheduledFlags() | READ | HANGUP | ERROR);
+               return Schedule(GetScheduledFlags() | READ);
        }
 
        bool ScheduleWrite() noexcept {
@@ -117,7 +117,7 @@
        }
 
        void CancelRead() noexcept {
-               Schedule(GetScheduledFlags() & ~(READ|HANGUP|ERROR));
+               Schedule(GetScheduledFlags() & ~READ);
        }
 
        void CancelWrite() noexcept {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/fs/NarrowPath.hxx 
new/mpd-0.21.23/src/fs/NarrowPath.hxx
--- old/mpd-0.21.22/src/fs/NarrowPath.hxx       2020-04-02 17:48:56.000000000 
+0200
+++ new/mpd-0.21.23/src/fs/NarrowPath.hxx       2020-04-23 17:46:20.000000000 
+0200
@@ -90,6 +90,11 @@
        constexpr
 #endif
        operator Path() const noexcept {
+#ifdef _UNICODE
+               if (value.IsNull())
+                       return nullptr;
+#endif
+
                return value;
        }
 };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/lib/icu/CaseFold.cxx 
new/mpd-0.21.23/src/lib/icu/CaseFold.cxx
--- old/mpd-0.21.22/src/lib/icu/CaseFold.cxx    2020-04-02 17:48:56.000000000 
+0200
+++ new/mpd-0.21.23/src/lib/icu/CaseFold.cxx    2020-04-23 17:46:20.000000000 
+0200
@@ -36,11 +36,6 @@
 #include <ctype.h>
 #endif
 
-#ifdef _WIN32
-#include "Win32.hxx"
-#include <windows.h>
-#endif
-
 #include <memory>
 
 #include <assert.h>
@@ -72,25 +67,6 @@
        folded.SetSize(folded_length);
        return UCharToUTF8({folded.begin(), folded.size()});
 
-#elif defined(_WIN32)
-       const auto u = MultiByteToWideChar(CP_UTF8, src);
-
-       const int size = LCMapStringEx(LOCALE_NAME_INVARIANT,
-                                      LCMAP_SORTKEY|LINGUISTIC_IGNORECASE,
-                                      u.c_str(), -1, nullptr, 0,
-                                      nullptr, nullptr, 0);
-       if (size <= 0)
-               return AllocatedString<>::Duplicate(src);
-
-       std::unique_ptr<wchar_t[]> buffer(new wchar_t[size]);
-       if (LCMapStringEx(LOCALE_NAME_INVARIANT,
-                         LCMAP_SORTKEY|LINGUISTIC_IGNORECASE,
-                         u.c_str(), -1, buffer.get(), size,
-                         nullptr, nullptr, 0) <= 0)
-               return AllocatedString<>::Duplicate(src);
-
-       return WideCharToMultiByte(CP_UTF8, buffer.get());
-
 #else
 #error not implemented
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/lib/icu/CaseFold.hxx 
new/mpd-0.21.23/src/lib/icu/CaseFold.hxx
--- old/mpd-0.21.22/src/lib/icu/CaseFold.hxx    2020-04-02 17:48:56.000000000 
+0200
+++ new/mpd-0.21.23/src/lib/icu/CaseFold.hxx    2020-04-23 17:46:20.000000000 
+0200
@@ -22,7 +22,7 @@
 
 #include "config.h"
 
-#if defined(HAVE_ICU) || defined(_WIN32)
+#ifdef HAVE_ICU
 #define HAVE_ICU_CASE_FOLD
 
 #include "util/Compiler.h"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/lib/icu/Collate.cxx 
new/mpd-0.21.23/src/lib/icu/Collate.cxx
--- old/mpd-0.21.22/src/lib/icu/Collate.cxx     2020-04-02 17:48:56.000000000 
+0200
+++ new/mpd-0.21.23/src/lib/icu/Collate.cxx     2020-04-23 17:46:20.000000000 
+0200
@@ -109,7 +109,7 @@
        }
 
        auto result = CompareStringEx(LOCALE_NAME_INVARIANT,
-                                     LINGUISTIC_IGNORECASE,
+                                     NORM_IGNORECASE,
                                      wa.c_str(), -1,
                                      wb.c_str(), -1,
                                      nullptr, nullptr, 0);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/lib/icu/Compare.cxx 
new/mpd-0.21.23/src/lib/icu/Compare.cxx
--- old/mpd-0.21.22/src/lib/icu/Compare.cxx     2020-04-02 17:48:56.000000000 
+0200
+++ new/mpd-0.21.23/src/lib/icu/Compare.cxx     2020-04-23 17:46:20.000000000 
+0200
@@ -22,6 +22,11 @@
 #include "util/StringAPI.hxx"
 #include "config.h"
 
+#ifdef _WIN32
+#include "Win32.hxx"
+#include <windows.h>
+#endif
+
 #include <string.h>
 
 #ifdef HAVE_ICU_CASE_FOLD
@@ -29,6 +34,17 @@
 IcuCompare::IcuCompare(const char *_needle) noexcept
        :needle(IcuCaseFold(_needle)) {}
 
+#elif defined(_WIN32)
+
+IcuCompare::IcuCompare(const char *_needle) noexcept
+       :needle(nullptr)
+{
+       try {
+               needle = MultiByteToWideChar(CP_UTF8, _needle);
+       } catch (...) {
+       }
+}
+
 #else
 
 IcuCompare::IcuCompare(const char *_needle) noexcept
@@ -41,6 +57,22 @@
 {
 #ifdef HAVE_ICU_CASE_FOLD
        return StringIsEqual(IcuCaseFold(haystack).c_str(), needle.c_str());
+#elif defined(_WIN32)
+       if (needle.IsNull())
+               /* the MultiByteToWideChar() call in the constructor
+                  has failed, so let's always fail the comparison */
+               return false;
+
+       try {
+               auto w_haystack = MultiByteToWideChar(CP_UTF8, haystack);
+               return CompareStringEx(LOCALE_NAME_INVARIANT,
+                                      NORM_IGNORECASE,
+                                      w_haystack.c_str(), -1,
+                                      needle.c_str(), -1,
+                                      nullptr, nullptr, 0) == CSTR_EQUAL;
+       } catch (...) {
+               return false;
+       }
 #else
        return strcasecmp(haystack, needle.c_str());
 #endif
@@ -52,6 +84,24 @@
 #ifdef HAVE_ICU_CASE_FOLD
        return StringFind(IcuCaseFold(haystack).c_str(),
                          needle.c_str()) != nullptr;
+#elif defined(_WIN32)
+       if (needle.IsNull())
+               /* the MultiByteToWideChar() call in the constructor
+                  has failed, so let's always fail the comparison */
+               return false;
+
+       try {
+               auto w_haystack = MultiByteToWideChar(CP_UTF8, haystack);
+               return FindNLSStringEx(LOCALE_NAME_INVARIANT,
+                                      FIND_FROMSTART|NORM_IGNORECASE,
+                                      w_haystack.c_str(), -1,
+                                      needle.c_str(), -1,
+                                      nullptr,
+                                      nullptr, nullptr, 0) >= 0;
+       } catch (...) {
+               /* MultiByteToWideChar() has failed */
+               return false;
+       }
 #elif defined(HAVE_STRCASESTR)
        return strcasestr(haystack, needle.c_str()) != nullptr;
 #else
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/lib/icu/Compare.hxx 
new/mpd-0.21.23/src/lib/icu/Compare.hxx
--- old/mpd-0.21.22/src/lib/icu/Compare.hxx     2020-04-02 17:48:56.000000000 
+0200
+++ new/mpd-0.21.23/src/lib/icu/Compare.hxx     2020-04-23 17:46:20.000000000 
+0200
@@ -23,13 +23,23 @@
 #include "util/Compiler.h"
 #include "util/AllocatedString.hxx"
 
+#ifdef _WIN32
+#include <wchar.h>
+#endif
+
 /**
  * This class can compare one string ("needle") with lots of other
  * strings ("haystacks") efficiently, ignoring case.  With some
  * configurations, it can prepare a case-folded version of the needle.
  */
 class IcuCompare {
+#ifdef _WIN32
+       /* Windows API functions work with wchar_t strings, so let's
+          cache the MultiByteToWideChar() result for performance */
+       AllocatedString<wchar_t> needle;
+#else
        AllocatedString<> needle;
+#endif
 
 public:
        IcuCompare():needle(nullptr) {}
@@ -38,12 +48,12 @@
 
        IcuCompare(const IcuCompare &src) noexcept
                :needle(src
-                       ? AllocatedString<>::Duplicate(src.needle.c_str())
+                       ? src.needle.Clone()
                        : nullptr) {}
 
        IcuCompare &operator=(const IcuCompare &src) noexcept {
                needle = src
-                       ? AllocatedString<>::Duplicate(src.needle.c_str())
+                       ? src.needle.Clone()
                        : nullptr;
                return *this;
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/lib/nfs/Connection.cxx 
new/mpd-0.21.23/src/lib/nfs/Connection.cxx
--- old/mpd-0.21.22/src/lib/nfs/Connection.cxx  2020-04-02 17:48:56.000000000 
+0200
+++ new/mpd-0.21.23/src/lib/nfs/Connection.cxx  2020-04-23 17:46:20.000000000 
+0200
@@ -191,7 +191,9 @@
 events_to_libnfs(unsigned i) noexcept
 {
        return ((i & SocketMonitor::READ) ? POLLIN : 0) |
-               ((i & SocketMonitor::WRITE) ? POLLOUT : 0);
+               ((i & SocketMonitor::WRITE) ? POLLOUT : 0) |
+               ((i & SocketMonitor::HANGUP) ? POLLHUP : 0) |
+               ((i & SocketMonitor::ERROR) ? POLLERR : 0);
 }
 
 NfsConnection::~NfsConnection() noexcept
@@ -450,8 +452,7 @@
                SocketMonitor::Open(_fd);
        }
 
-       SocketMonitor::Schedule(libnfs_to_events(which_events)
-                               | SocketMonitor::HANGUP);
+       SocketMonitor::Schedule(libnfs_to_events(which_events));
 }
 
 inline int
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/lib/nfs/FileReader.cxx 
new/mpd-0.21.23/src/lib/nfs/FileReader.cxx
--- old/mpd-0.21.22/src/lib/nfs/FileReader.cxx  2020-04-02 17:48:56.000000000 
+0200
+++ new/mpd-0.21.23/src/lib/nfs/FileReader.cxx  2020-04-23 17:46:20.000000000 
+0200
@@ -180,7 +180,6 @@
 inline void
 NfsFileReader::OpenCallback(nfsfh *_fh) noexcept
 {
-       assert(state == State::OPEN);
        assert(connection != nullptr);
        assert(_fh != nullptr);
 
@@ -197,27 +196,33 @@
 }
 
 inline void
-NfsFileReader::StatCallback(const struct stat *st) noexcept
+NfsFileReader::StatCallback(const struct stat *_st) noexcept
 {
-       assert(state == State::STAT);
        assert(connection != nullptr);
        assert(fh != nullptr);
-       assert(st != nullptr);
+       assert(_st != nullptr);
+
+#if defined(_WIN32) && !defined(_WIN64)
+       /* on 32-bit Windows, libnfs enables -D_FILE_OFFSET_BITS=64,
+          but MPD (Meson) doesn't - to work around this mismatch, we
+          cast explicitly to "struct stat64" */
+       const auto *st = (const struct stat64 *)_st;
+#else
+       const auto *st = _st;
+#endif
 
        if (!S_ISREG(st->st_mode)) {
                OnNfsFileError(std::make_exception_ptr(std::runtime_error("Not 
a regular file")));
                return;
        }
 
-       state = State::IDLE;
-
        OnNfsFileOpen(st->st_size);
 }
 
 void
 NfsFileReader::OnNfsCallback(unsigned status, void *data) noexcept
 {
-       switch (state) {
+       switch (std::exchange(state, State::IDLE)) {
        case State::INITIAL:
        case State::DEFER:
        case State::MOUNT:
@@ -234,7 +239,6 @@
                break;
 
        case State::READ:
-               state = State::IDLE;
                OnNfsFileRead(data, status);
                break;
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/pcm/Order.cxx 
new/mpd-0.21.23/src/pcm/Order.cxx
--- old/mpd-0.21.22/src/pcm/Order.cxx   2020-04-02 17:48:56.000000000 +0200
+++ new/mpd-0.21.23/src/pcm/Order.cxx   2020-04-23 17:46:20.000000000 +0200
@@ -21,6 +21,28 @@
 #include "PcmBuffer.hxx"
 #include "util/ConstBuffer.hxx"
 
+
+/*
+ * According to:
+ *  - https://xiph.org/flac/format.html#frame_header
+ *  - https://github.com/nu774/qaac/wiki/Multichannel--handling
+ * the source channel order (after decoding, e.g., flac, alac) is for
+ *  - 1ch:            mono
+ *  - 2ch:            left, right
+ *  - 3ch:            left, right, center
+ *  - 4ch:            front left, front right, back left, back right
+ *  - 5ch:            front left, front right, front center, back/surround 
left, back/surround right
+ *  - 6ch (aka 5.1):  front left, front right, front center, LFE, 
back/surround left, back/surround right
+ *  - 7ch:            front left, front right, front center, LFE, back center, 
side left, side right
+ *  - 8ch: (aka 7.1): front left, front right, front center, LFE, back left, 
back right, side left, side right
+ *
+ * The ALSA default channel map is (see /usr/share/alsa/pcm/surround71.conf):
+ *  - front left, front right, back left, back right, front center, LFE,  side 
left, side right
+ *
+ * Hence, in case of the following source channel orders 3ch, 5ch, 6ch (aka
+ * 5.1), 7ch and 8ch the channel order has to be adapted
+ */
+
 template<typename V>
 struct TwoPointers {
        V *dest;
@@ -44,11 +66,33 @@
                return *this;
        }
 
+       TwoPointers<V> &ToAlsa50() noexcept {
+               *dest++ = src[0]; // front left
+               *dest++ = src[1]; // front right
+               *dest++ = src[3]; // surround left
+               *dest++ = src[4]; // surround right
+               *dest++ = src[2]; // front center
+               src += 5;
+               return *this;
+       }
+
        TwoPointers<V> &ToAlsa51() noexcept {
                return CopyTwo() // left+right
                        .SwapTwoPairs(); // center, LFE, surround left+right
        }
 
+       TwoPointers<V> &ToAlsa70() noexcept {
+               *dest++ = src[0]; // front left
+               *dest++ = src[1]; // front right
+               *dest++ = src[5]; // side left
+               *dest++ = src[6]; // side right
+               *dest++ = src[2]; // front center
+               *dest++ = src[3]; // LFE
+               *dest++ = src[4]; // back center
+               src += 7;
+               return *this;
+       }
+
        TwoPointers<V> &ToAlsa71() noexcept {
                return ToAlsa51()
                        .CopyTwo(); // side left+right
@@ -57,6 +101,24 @@
 
 template<typename V>
 static void
+ToAlsaChannelOrder50(V *dest, const V *src, size_t n) noexcept
+{
+       TwoPointers<V> p{dest, src};
+       for (size_t i = 0; i != n; ++i)
+               p.ToAlsa50();
+}
+
+template<typename V>
+static inline ConstBuffer<V>
+ToAlsaChannelOrder50(PcmBuffer &buffer, ConstBuffer<V> src) noexcept
+{
+       auto dest = buffer.GetT<V>(src.size);
+       ToAlsaChannelOrder50(dest, src.data, src.size / 5);
+       return { dest, src.size };
+}
+
+template<typename V>
+static void
 ToAlsaChannelOrder51(V *dest, const V *src, size_t n) noexcept
 {
        TwoPointers<V> p{dest, src};
@@ -75,6 +137,24 @@
 
 template<typename V>
 static void
+ToAlsaChannelOrder70(V *dest, const V *src, size_t n) noexcept
+{
+       TwoPointers<V> p{dest, src};
+       for (size_t i = 0; i != n; ++i)
+               p.ToAlsa70();
+}
+
+template<typename V>
+static inline ConstBuffer<V>
+ToAlsaChannelOrder70(PcmBuffer &buffer, ConstBuffer<V> src) noexcept
+{
+       auto dest = buffer.GetT<V>(src.size);
+       ToAlsaChannelOrder70(dest, src.data, src.size / 7);
+       return { dest, src.size };
+}
+
+template<typename V>
+static void
 ToAlsaChannelOrder71(V *dest, const V *src, size_t n) noexcept
 {
        TwoPointers<V> p{dest, src};
@@ -97,9 +177,15 @@
                    unsigned channels) noexcept
 {
        switch (channels) {
+       case 5: // 5.0
+               return ToAlsaChannelOrder50(buffer, src);
+
        case 6: // 5.1
                return ToAlsaChannelOrder51(buffer, src);
 
+       case 7: // 7.0
+               return ToAlsaChannelOrder70(buffer, src);
+
        case 8: // 7.1
                return ToAlsaChannelOrder71(buffer, src);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/player/CrossFade.cxx 
new/mpd-0.21.23/src/player/CrossFade.cxx
--- old/mpd-0.21.22/src/player/CrossFade.cxx    2020-04-02 17:48:56.000000000 
+0200
+++ new/mpd-0.21.23/src/player/CrossFade.cxx    2020-04-23 17:46:20.000000000 
+0200
@@ -62,7 +62,7 @@
                        ++ramp_list;
 
                /* Check for exact match. */
-               if (db == required_db) {
+               if (db >= required_db) {
                        return duration;
                }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/player/Thread.cxx 
new/mpd-0.21.23/src/player/Thread.cxx
--- old/mpd-0.21.22/src/player/Thread.cxx       2020-04-02 17:48:56.000000000 
+0200
+++ new/mpd-0.21.23/src/player/Thread.cxx       2020-04-23 17:46:20.000000000 
+0200
@@ -964,6 +964,12 @@
        if (border_pause) {
                paused = true;
                pc.listener.OnBorderPause();
+
+               /* drain all outputs to guarantee the current song is
+                  really being played to the end; without this, the
+                  Pause() call would drop all ring buffers */
+               pc.outputs.Drain();
+
                pc.outputs.Pause();
                idle_add(IDLE_PLAYER);
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/storage/plugins/CurlStorage.cxx 
new/mpd-0.21.23/src/storage/plugins/CurlStorage.cxx
--- old/mpd-0.21.22/src/storage/plugins/CurlStorage.cxx 2020-04-02 
17:48:56.000000000 +0200
+++ new/mpd-0.21.23/src/storage/plugins/CurlStorage.cxx 2020-04-23 
17:46:20.000000000 +0200
@@ -402,7 +402,7 @@
                        break;
 
                case State::HREF:
-                       response.href.assign(s, len);
+                       response.href.append(s, len);
                        break;
 
                case State::STATUS:
@@ -482,7 +482,7 @@
 public:
        HttpListDirectoryOperation(CurlGlobal &curl, const char *uri)
                :PropfindOperation(curl, uri, 1),
-                base_path(UriPathOrSlash(uri)) {}
+                base_path(CurlUnescape(GetEasy(), UriPathOrSlash(uri))) {}
 
        std::unique_ptr<StorageDirectoryReader> Perform() {
                DeferStart();
@@ -507,8 +507,7 @@
 
                /* kludge: ignoring case in this comparison to avoid
                   false negatives if the web server uses a different
-                  case in hex digits in escaped characters; TODO:
-                  implement properly */
+                  case */
                path = StringAfterPrefixIgnoreCase(path, base_path.c_str());
                if (path == nullptr || *path == 0)
                        return nullptr;
@@ -531,11 +530,12 @@
                if (r.status != 200)
                        return;
 
-               const auto escaped_name = HrefToEscapedName(r.href.c_str());
-               if (escaped_name.IsNull())
+               std::string href = CurlUnescape(GetEasy(), r.href.c_str());
+               const auto name = HrefToEscapedName(href.c_str());
+               if (name.IsNull())
                        return;
 
-               entries.emplace_front(CurlUnescape(GetEasy(), escaped_name));
+               entries.emplace_front(std::string(name.data, name.size));
 
                auto &info = entries.front().info;
                info = StorageFileInfo(r.collection
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/tag/Fallback.hxx 
new/mpd-0.21.23/src/tag/Fallback.hxx
--- old/mpd-0.21.22/src/tag/Fallback.hxx        2020-04-02 17:48:56.000000000 
+0200
+++ new/mpd-0.21.23/src/tag/Fallback.hxx        2020-04-23 17:46:20.000000000 
+0200
@@ -45,6 +45,10 @@
                   "AlbumArtist"/"ArtistSort" was found */
                return f(TAG_ARTIST);
 
+       if (type == TAG_ALBUM_SORT)
+               /* fall back to "Album" if no "AlbumSort" was found */
+               return f(TAG_ALBUM);
+
        return false;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/util/Math.hxx 
new/mpd-0.21.23/src/util/Math.hxx
--- old/mpd-0.21.22/src/util/Math.hxx   2020-04-02 17:48:56.000000000 +0200
+++ new/mpd-0.21.23/src/util/Math.hxx   2020-04-23 17:46:20.000000000 +0200
@@ -30,11 +30,16 @@
 #ifndef MATH_HXX
 #define MATH_HXX
 
+#include <cmath>
+
+/*
+ * C99 math can be optionally omitted with gcc's libstdc++.
+ * Use boost if unavailable.
+ */
 #if (defined(__GLIBCPP__) || defined(__GLIBCXX__)) && 
!defined(_GLIBCXX_USE_C99_MATH)
 #include <boost/math/special_functions/round.hpp>
 using boost::math::lround;
 #else
-#include <cmath>
 using std::lround;
 #endif
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.22/src/zeroconf/AvahiPoll.cxx 
new/mpd-0.21.23/src/zeroconf/AvahiPoll.cxx
--- old/mpd-0.21.22/src/zeroconf/AvahiPoll.cxx  2020-04-02 17:48:56.000000000 
+0200
+++ new/mpd-0.21.23/src/zeroconf/AvahiPoll.cxx  2020-04-23 17:46:20.000000000 
+0200
@@ -26,9 +26,7 @@
 FromAvahiWatchEvent(AvahiWatchEvent e)
 {
        return (e & AVAHI_WATCH_IN ? SocketMonitor::READ : 0) |
-               (e & AVAHI_WATCH_OUT ? SocketMonitor::WRITE : 0) |
-               (e & AVAHI_WATCH_ERR ? SocketMonitor::ERROR : 0) |
-               (e & AVAHI_WATCH_HUP ? SocketMonitor::HANGUP : 0);
+               (e & AVAHI_WATCH_OUT ? SocketMonitor::WRITE : 0);
 }
 
 static AvahiWatchEvent


Reply via email to