summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2020-04-23 17:54:22 +0200
committerMax Kellermann <max@musicpd.org>2020-04-23 18:01:23 +0200
commit0b3acc3eec1688d58120921b2dc58ae64851354c (patch)
treeefa25cb96e9e8bd10b5a04d2e087e9a993929b5f
parent6979be008cb334ca08fc031ecb86a723bf656381 (diff)
parent6c240f667c391f678dd916d0a1d7e9b149557240 (diff)
Merge tag 'v0.21.23'
release v0.21.23
-rw-r--r--NEWS18
-rw-r--r--android/AndroidManifest.xml4
-rw-r--r--src/decoder/plugins/GmeDecoderPlugin.cxx6
-rw-r--r--src/event/PollGroupWinSelect.cxx4
-rw-r--r--src/event/SocketMonitor.cxx19
-rw-r--r--src/event/SocketMonitor.hxx4
-rw-r--r--src/fs/NarrowPath.hxx5
-rw-r--r--src/lib/icu/CaseFold.cxx27
-rw-r--r--src/lib/icu/CaseFold.hxx2
-rw-r--r--src/lib/icu/Collate.cxx2
-rw-r--r--src/lib/icu/Compare.cxx50
-rw-r--r--src/lib/icu/Compare.hxx14
-rw-r--r--src/lib/nfs/Connection.cxx7
-rw-r--r--src/lib/nfs/FileReader.cxx20
-rw-r--r--src/pcm/Order.cxx86
-rw-r--r--src/player/CrossFade.cxx2
-rw-r--r--src/player/Thread.cxx6
-rw-r--r--src/storage/plugins/CurlStorage.cxx14
-rw-r--r--src/tag/Fallback.hxx4
-rw-r--r--src/zeroconf/AvahiPoll.cxx4
20 files changed, 238 insertions, 60 deletions
diff --git a/NEWS b/NEWS
index 14e2c93b2..2de064501 100644
--- a/NEWS
+++ b/NEWS
@@ -36,6 +36,24 @@ ver 0.22 (not yet released)
* switch to C++17
- GCC 7 or clang 4 (or newer) recommended
+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 --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index 4dcdba4fd..64d0802b1 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -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 --git a/src/decoder/plugins/GmeDecoderPlugin.cxx b/src/decoder/plugins/GmeDecoderPlugin.cxx
index 4fb6af43e..ee8fc2a48 100644
--- a/src/decoder/plugins/GmeDecoderPlugin.cxx
+++ b/src/decoder/plugins/GmeDecoderPlugin.cxx
@@ -187,7 +187,11 @@ gme_file_decode(DecoderClient &client, Path path_fs)
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 --git a/src/event/PollGroupWinSelect.cxx b/src/event/PollGroupWinSelect.cxx
index b415298dc..a03c60cb7 100644
--- a/src/event/PollGroupWinSelect.cxx
+++ b/src/event/PollGroupWinSelect.cxx
@@ -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 --git a/src/event/SocketMonitor.cxx b/src/event/SocketMonitor.cxx
index 28bef0afd..018f7330e 100644
--- a/src/event/SocketMonitor.cxx
+++ b/src/event/SocketMonitor.cxx
@@ -23,6 +23,10 @@
#include <cassert>
#include <utility>
+#ifdef USE_EPOLL
+#include <cerrno>
+#endif
+
void
SocketMonitor::Dispatch(unsigned flags) noexcept
{
@@ -81,6 +85,21 @@ SocketMonitor::Schedule(unsigned flags) noexcept
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 --git a/src/event/SocketMonitor.hxx b/src/event/SocketMonitor.hxx
index 321b36b72..bb1e84354 100644
--- a/src/event/SocketMonitor.hxx
+++ b/src/event/SocketMonitor.hxx
@@ -108,7 +108,7 @@ public:
}
bool ScheduleRead() noexcept {
- return Schedule(GetScheduledFlags() | READ | HANGUP | ERROR);
+ return Schedule(GetScheduledFlags() | READ);
}
bool ScheduleWrite() noexcept {
@@ -116,7 +116,7 @@ public:
}
void CancelRead() noexcept {
- Schedule(GetScheduledFlags() & ~(READ|HANGUP|ERROR));
+ Schedule(GetScheduledFlags() & ~READ);
}
void CancelWrite() noexcept {
diff --git a/src/fs/NarrowPath.hxx b/src/fs/NarrowPath.hxx
index c0e15ea23..eab404111 100644
--- a/src/fs/NarrowPath.hxx
+++ b/src/fs/NarrowPath.hxx
@@ -90,6 +90,11 @@ public:
constexpr
#endif
operator Path() const noexcept {
+#ifdef _UNICODE
+ if (value.IsNull())
+ return nullptr;
+#endif
+
return value;
}
};
diff --git a/src/lib/icu/CaseFold.cxx b/src/lib/icu/CaseFold.cxx
index 74a0462a2..a2640263b 100644
--- a/src/lib/icu/CaseFold.cxx
+++ b/src/lib/icu/CaseFold.cxx
@@ -34,12 +34,6 @@
#include <algorithm>
#endif
-#ifdef _WIN32
-#include "Win32.hxx"
-#include <windows.h>
-#endif
-
-#include <cassert>
#include <memory>
#include <string.h>
@@ -65,27 +59,6 @@ try {
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]);
- int result = LCMapStringEx(LOCALE_NAME_INVARIANT,
- LCMAP_SORTKEY|LINGUISTIC_IGNORECASE,
- u.c_str(), -1, buffer.get(), size,
- nullptr, nullptr, 0);
- if (result <= 0)
- return AllocatedString<>::Duplicate(src);
-
- return WideCharToMultiByte(CP_UTF8,
- {buffer.get(), size_t(result - 1)});
-
#else
#error not implemented
#endif
diff --git a/src/lib/icu/CaseFold.hxx b/src/lib/icu/CaseFold.hxx
index ba91262d8..99cb9ae0b 100644
--- a/src/lib/icu/CaseFold.hxx
+++ b/src/lib/icu/CaseFold.hxx
@@ -22,7 +22,7 @@
#include "config.h"
-#if defined(HAVE_ICU) || defined(_WIN32)
+#ifdef HAVE_ICU
#define HAVE_ICU_CASE_FOLD
#include <string_view>
diff --git a/src/lib/icu/Collate.cxx b/src/lib/icu/Collate.cxx
index a91e4e122..72ba06336 100644
--- a/src/lib/icu/Collate.cxx
+++ b/src/lib/icu/Collate.cxx
@@ -108,7 +108,7 @@ IcuCollate(std::string_view a, std::string_view b) noexcept
}
auto result = CompareStringEx(LOCALE_NAME_INVARIANT,
- LINGUISTIC_IGNORECASE,
+ NORM_IGNORECASE,
wa.c_str(), -1,
wb.c_str(), -1,
nullptr, nullptr, 0);
diff --git a/src/lib/icu/Compare.cxx b/src/lib/icu/Compare.cxx
index 1fde0a637..f802f2d0a 100644
--- a/src/lib/icu/Compare.cxx
+++ b/src/lib/icu/Compare.cxx
@@ -22,11 +22,27 @@
#include "util/StringAPI.hxx"
#include "config.h"
+#ifdef _WIN32
+#include "Win32.hxx"
+#include <windows.h>
+#endif
+
#ifdef HAVE_ICU_CASE_FOLD
IcuCompare::IcuCompare(std::string_view _needle) noexcept
:needle(IcuCaseFold(_needle)) {}
+#elif defined(_WIN32)
+
+IcuCompare::IcuCompare(std::string_view _needle) noexcept
+ :needle(nullptr)
+{
+ try {
+ needle = MultiByteToWideChar(CP_UTF8, _needle);
+ } catch (...) {
+ }
+}
+
#else
IcuCompare::IcuCompare(std::string_view _needle) noexcept
@@ -39,6 +55,22 @@ IcuCompare::operator==(const char *haystack) const noexcept
{
#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 StringIsEqualIgnoreCase(haystack, needle.c_str());
#endif
@@ -50,6 +82,24 @@ IcuCompare::IsIn(const char *haystack) const noexcept
#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 --git a/src/lib/icu/Compare.hxx b/src/lib/icu/Compare.hxx
index 832e7949c..cec58ab70 100644
--- a/src/lib/icu/Compare.hxx
+++ b/src/lib/icu/Compare.hxx
@@ -25,13 +25,23 @@
#include <string_view>
+#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) {}
@@ -40,12 +50,12 @@ public:
IcuCompare(const IcuCompare &src) noexcept
:needle(src
- ? AllocatedString<>::Duplicate(src.needle)
+ ? src.needle.Clone()
: nullptr) {}
IcuCompare &operator=(const IcuCompare &src) noexcept {
needle = src
- ? AllocatedString<>::Duplicate(src.needle)
+ ? src.needle.Clone()
: nullptr;
return *this;
}
diff --git a/src/lib/nfs/Connection.cxx b/src/lib/nfs/Connection.cxx
index c1dc8d18d..f853b40eb 100644
--- a/src/lib/nfs/Connection.cxx
+++ b/src/lib/nfs/Connection.cxx
@@ -191,7 +191,9 @@ static constexpr int
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 @@ NfsConnection::ScheduleSocket() noexcept
SocketMonitor::Open(_fd);
}
- SocketMonitor::Schedule(libnfs_to_events(which_events)
- | SocketMonitor::HANGUP);
+ SocketMonitor::Schedule(libnfs_to_events(which_events));
}
inline int
diff --git a/src/lib/nfs/FileReader.cxx b/src/lib/nfs/FileReader.cxx
index 6e66bfa71..5307a33ff 100644
--- a/src/lib/nfs/FileReader.cxx
+++ b/src/lib/nfs/FileReader.cxx
@@ -180,7 +180,6 @@ NfsFileReader::OnNfsConnectionDisconnected(std::exception_ptr e) noexcept
inline void
NfsFileReader::OpenCallback(nfsfh *_fh) noexcept
{
- assert(state == State::OPEN);
assert(connection != nullptr);
assert(_fh != nullptr);
@@ -197,27 +196,33 @@ NfsFileReader::OpenCallback(nfsfh *_fh) noexcept
}
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 @@ NfsFileReader::OnNfsCallback(unsigned status, void *data) noexcept
break;
case State::READ:
- state = State::IDLE;
OnNfsFileRead(data, status);
break;
}
diff --git a/src/pcm/Order.cxx b/src/pcm/Order.cxx
index b181dd75c..abdf2d88d 100644
--- a/src/pcm/Order.cxx
+++ b/src/pcm/Order.cxx
@@ -21,6 +21,28 @@
#include "Buffer.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 @@ struct TwoPointers {
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 @@ struct TwoPointers {
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 @@ ToAlsaChannelOrder51(PcmBuffer &buffer, ConstBuffer<V> src) noexcept
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 @@ ToAlsaChannelOrderT(PcmBuffer &buffer, ConstBuffer<V> src,
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 --git a/src/player/CrossFade.cxx b/src/player/CrossFade.cxx
index e5611f97c..7c9ece160 100644
--- a/src/player/CrossFade.cxx
+++ b/src/player/CrossFade.cxx
@@ -62,7 +62,7 @@ mixramp_interpolate(const char *ramp_list, float required_db) noexcept
++ramp_list;
/* Check for exact match. */
- if (db == required_db) {
+ if (db >= required_db) {
return duration;
}
diff --git a/src/player/Thread.cxx b/src/player/Thread.cxx
index d790fbb3f..704eee05e 100644
--- a/src/player/Thread.cxx
+++ b/src/player/Thread.cxx
@@ -967,6 +967,12 @@ Player::SongBorder() noexcept
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 --git a/src/storage/plugins/CurlStorage.cxx b/src/storage/plugins/CurlStorage.cxx
index d2fc24150..356fa8b58 100644
--- a/src/storage/plugins/CurlStorage.cxx
+++ b/src/storage/plugins/CurlStorage.cxx
@@ -394,7 +394,7 @@ private:
break;
case State::HREF:
- response.href.assign(s, len);
+ response.href.append(s, len);
break;
case State::STATUS:
@@ -474,7 +474,7 @@ class HttpListDirectoryOperation final : public PropfindOperation {
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();
@@ -499,8 +499,7 @@ private:
/* 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.empty())
return nullptr;
@@ -523,11 +522,12 @@ protected:
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 --git a/src/tag/Fallback.hxx b/src/tag/Fallback.hxx
index 9690c1684..a3ee48bd1 100644
--- a/src/tag/Fallback.hxx
+++ b/src/tag/Fallback.hxx
@@ -45,6 +45,10 @@ ApplyTagFallback(TagType type, F &&f) noexcept
"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 --git a/src/zeroconf/AvahiPoll.cxx b/src/zeroconf/AvahiPoll.cxx
index 3c1111e49..2edec9da6 100644
--- a/src/zeroconf/AvahiPoll.cxx
+++ b/src/zeroconf/AvahiPoll.cxx
@@ -26,9 +26,7 @@ static unsigned
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