From a85455fb3fd3d59f1709c6f524f70eb7f91fd132 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Tue, 27 Sep 2016 22:04:46 +0200
Subject: [PATCH 01/10] configure.ac: prepare for 0.19.20

---
 NEWS         | 2 ++
 configure.ac | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index 9da6019ba..9867367e3 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,5 @@
+ver 0.19.20 (not yet released)
+
 ver 0.19.19 (2016/08/23)
 * decoder
   - ffmpeg: bug fix for FFmpeg 3.1 support
diff --git a/configure.ac b/configure.ac
index e4764c923..8adaa4c23 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@ AC_INIT(mpd, 0.19.19, musicpd-dev-team@lists.sourceforge.net)
 
 VERSION_MAJOR=0
 VERSION_MINOR=19
-VERSION_REVISION=19
+VERSION_REVISION=20
 VERSION_EXTRA=0
 
 AC_CONFIG_SRCDIR([src/Main.cxx])

From 7c251fe19013d17f5ecd65361a560d433c0c19ef Mon Sep 17 00:00:00 2001
From: dennisschagt <dennisschagt@gmail.com>
Date: Sat, 8 Oct 2016 00:36:28 +0200
Subject: [PATCH 02/10] Fix comment in mpdconf.example ("can setting can" ->
 "setting can")

---
 doc/mpdconf.example | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doc/mpdconf.example b/doc/mpdconf.example
index 21d4b4165..9b3a6280f 100644
--- a/doc/mpdconf.example
+++ b/doc/mpdconf.example
@@ -164,7 +164,7 @@
 # Permissions #################################################################
 #
 # If this setting is set, MPD will require password authorization. The password
-# can setting can be specified multiple times for different password profiles.
+# setting can be specified multiple times for different password profiles.
 #
 #password                        "password@read,add,control,admin"
 #

From 06682bd2a95692153327b483a06ffa709a842e6b Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sun, 4 Sep 2016 12:56:17 +0200
Subject: [PATCH 03/10] tag/Item: remove "packed" attribute, add static_assert
 on alignment instead

The "packed" attribute triggers a clang 4.0 warning, and it's not
necessary.  All we want is correct allocation of this
dynamically-sized struct.
---
 src/tag/TagItem.hxx | 5 +++--
 src/tag/TagPool.cxx | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/tag/TagItem.hxx b/src/tag/TagItem.hxx
index 489ecde3a..86c9646ef 100644
--- a/src/tag/TagItem.hxx
+++ b/src/tag/TagItem.hxx
@@ -21,7 +21,6 @@
 #define MPD_TAG_ITEM_HXX
 
 #include "TagType.h"
-#include "Compiler.h"
 
 /**
  * One tag value.  It is a mapping of #TagType to am arbitrary string
@@ -40,6 +39,8 @@ struct TagItem {
 	TagItem() = default;
 	TagItem(const TagItem &other) = delete;
 	TagItem &operator=(const TagItem &other) = delete;
-} gcc_packed;
+};
+
+static_assert(alignof(TagItem) == 1, "Unexpected alignment");
 
 #endif
diff --git a/src/tag/TagPool.cxx b/src/tag/TagPool.cxx
index 16f44f46e..22dc2a05d 100644
--- a/src/tag/TagPool.cxx
+++ b/src/tag/TagPool.cxx
@@ -50,7 +50,7 @@ struct TagPoolSlot {
 
 	static TagPoolSlot *Create(TagPoolSlot *_next, TagType type,
 				   const char *value, size_t length);
-} gcc_packed;
+};
 
 TagPoolSlot *
 TagPoolSlot::Create(TagPoolSlot *_next, TagType type,

From 9c1c180ae03917f0209146961b6ef3336b48b519 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Wed, 26 Oct 2016 18:26:01 +0200
Subject: [PATCH 04/10] tag/Item: declare value[] to have only one element

By declaring the variable-length array to have a nominal size of 1,
struct TagPoolSlot shrinks from 24 bytes to 16 bytes, because "ref"
and "item" now both fit in one machine word.
---
 src/tag/TagItem.hxx | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/tag/TagItem.hxx b/src/tag/TagItem.hxx
index 86c9646ef..ebea73ac1 100644
--- a/src/tag/TagItem.hxx
+++ b/src/tag/TagItem.hxx
@@ -34,13 +34,14 @@ struct TagItem {
 	/**
 	 * the value of this tag; this is a variable length string
 	 */
-	char value[sizeof(long) - sizeof(type)];
+	char value[1];
 
 	TagItem() = default;
 	TagItem(const TagItem &other) = delete;
 	TagItem &operator=(const TagItem &other) = delete;
 };
 
+static_assert(sizeof(TagItem) == 2, "Unexpected size");
 static_assert(alignof(TagItem) == 1, "Unexpected alignment");
 
 #endif

From 77a9940461f96a608b1f564f810b146980e63c4d Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Wed, 26 Oct 2016 18:06:56 +0200
Subject: [PATCH 05/10] decoder/ffmpeg: ignore empty packets

An empty packet would be a command for avcodec_send_packet() to
finalize the codec.

Fixes https://bugs.musicpd.org/view.php?id=4588
---
 NEWS                                        | 2 ++
 src/decoder/plugins/FfmpegDecoderPlugin.cxx | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index 9867367e3..c873cbc2f 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,6 @@
 ver 0.19.20 (not yet released)
+* decoder
+  - ffmpeg: ignore empty packets
 
 ver 0.19.19 (2016/08/23)
 * decoder
diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
index e27ec797f..fc287328a 100644
--- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx
+++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
@@ -643,7 +643,7 @@ FfmpegDecode(Decoder &decoder, InputStream &input,
 			/* end of file */
 			break;
 
-		if (packet.stream_index == audio_stream) {
+		if (packet.size > 0 && packet.stream_index == audio_stream) {
 			cmd = ffmpeg_send_packet(decoder, input,
 						 packet,
 						 *codec_context,

From 1ee0e29974a150c39c66db868f5f5f157422c4d4 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Thu, 27 Oct 2016 17:12:24 +0200
Subject: [PATCH 06/10] storage/Composite: fix documentation typo

---
 src/storage/CompositeStorage.hxx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/storage/CompositeStorage.hxx b/src/storage/CompositeStorage.hxx
index c3695c79d..350cca55d 100644
--- a/src/storage/CompositeStorage.hxx
+++ b/src/storage/CompositeStorage.hxx
@@ -45,7 +45,7 @@ class CompositeStorage final : public Storage {
 	 */
 	struct Directory {
 		/**
-		 * The #Storage mounted n this virtual directory.  All
+		 * The #Storage mounted in this virtual directory.  All
 		 * "leaf" Directory instances must have a #Storage.
 		 * Other Directory instances may have one, and child
 		 * mounts will be "mixed" in.

From e1a8dcfcc8d08a0426154fed457be1abec2abfa3 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Thu, 27 Oct 2016 19:55:08 +0200
Subject: [PATCH 07/10] storage/Composite: add FindStorage() API documentation

---
 src/storage/CompositeStorage.hxx | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/storage/CompositeStorage.hxx b/src/storage/CompositeStorage.hxx
index 350cca55d..3ae53738d 100644
--- a/src/storage/CompositeStorage.hxx
+++ b/src/storage/CompositeStorage.hxx
@@ -155,6 +155,14 @@ private:
 		}
 	}
 
+	/**
+	 * Follow the given URI path, and find the outermost directory
+	 * which is a #Storage mount point.  If there are no mounts,
+	 * it returns the root directory (with a nullptr "storage"
+	 * attribute, of course).  FindResult::uri contains the
+	 * remaining unused part of the URI (may be empty if all of
+	 * the URI was used).
+	 */
 	gcc_pure
 	FindResult FindStorage(const char *uri) const;
 	FindResult FindStorage(const char *uri, Error &error) const;

From f9a64d24bfe8ff262bbf32fd75615153f697f774 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Thu, 27 Oct 2016 19:45:36 +0200
Subject: [PATCH 08/10] storage/Composite: eliminate the second FindStorage()
 overload

It was used in a wrong way, which did not deal with errors
consistently.  And if that's wrong, there is no need for FindStorage()
at all - let's remove it and the confusion around it.
---
 src/storage/CompositeStorage.cxx | 18 ++++++------------
 src/storage/CompositeStorage.hxx |  1 -
 2 files changed, 6 insertions(+), 13 deletions(-)

diff --git a/src/storage/CompositeStorage.cxx b/src/storage/CompositeStorage.cxx
index ce9c1e8b1..9e0a45f42 100644
--- a/src/storage/CompositeStorage.cxx
+++ b/src/storage/CompositeStorage.cxx
@@ -265,22 +265,13 @@ CompositeStorage::FindStorage(const char *uri) const
 	return result;
 }
 
-CompositeStorage::FindResult
-CompositeStorage::FindStorage(const char *uri, Error &error) const
-{
-	auto result = FindStorage(uri);
-	if (result.directory == nullptr)
-		error.Set(composite_domain, "No such directory");
-	return result;
-}
-
 bool
 CompositeStorage::GetInfo(const char *uri, bool follow, FileInfo &info,
 			  Error &error)
 {
 	const ScopeLock protect(mutex);
 
-	auto f = FindStorage(uri, error);
+	auto f = FindStorage(uri);
 	if (f.directory->storage != nullptr &&
 	    f.directory->storage->GetInfo(f.uri, follow, info, error))
 		return true;
@@ -295,6 +286,7 @@ CompositeStorage::GetInfo(const char *uri, bool follow, FileInfo &info,
 		return true;
 	}
 
+	error.Set(composite_domain, "No such directory");
 	return false;
 }
 
@@ -304,13 +296,15 @@ CompositeStorage::OpenDirectory(const char *uri,
 {
 	const ScopeLock protect(mutex);
 
-	auto f = FindStorage(uri, error);
+	auto f = FindStorage(uri);
 	const Directory *directory = f.directory->Find(f.uri);
 	if (directory == nullptr || directory->children.empty()) {
 		/* no virtual directories here */
 
-		if (f.directory->storage == nullptr)
+		if (f.directory->storage == nullptr) {
+			error.Set(composite_domain, "No such directory");
 			return nullptr;
+		}
 
 		return f.directory->storage->OpenDirectory(f.uri, error);
 	}
diff --git a/src/storage/CompositeStorage.hxx b/src/storage/CompositeStorage.hxx
index 3ae53738d..afe60e22e 100644
--- a/src/storage/CompositeStorage.hxx
+++ b/src/storage/CompositeStorage.hxx
@@ -165,7 +165,6 @@ private:
 	 */
 	gcc_pure
 	FindResult FindStorage(const char *uri) const;
-	FindResult FindStorage(const char *uri, Error &error) const;
 
 	const char *MapToRelativeUTF8(const Directory &directory,
 				      const char *uri) const;

From 11ba44870ba9aadfdbccc8aa42186e360c3d6444 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Thu, 27 Oct 2016 20:25:12 +0200
Subject: [PATCH 09/10] decoder/sidplay: simplify seek loop

---
 src/decoder/plugins/SidplayDecoderPlugin.cxx | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/src/decoder/plugins/SidplayDecoderPlugin.cxx b/src/decoder/plugins/SidplayDecoderPlugin.cxx
index db4070bfb..794a5dab8 100644
--- a/src/decoder/plugins/SidplayDecoderPlugin.cxx
+++ b/src/decoder/plugins/SidplayDecoderPlugin.cxx
@@ -376,12 +376,9 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
 			}
 
 			/* ignore data until target time is reached */
-			while(data_time<target_time) {
-				nbytes=player.play(buffer, ARRAY_SIZE(buffer));
-				if(nbytes==0)
-					break;
+			while (data_time < target_time &&
+			       player.play(buffer, ARRAY_SIZE(buffer)) > 0)
 				data_time = player.time();
-			}
 
 			decoder_command_finished(decoder);
 		}

From 49c04ccfc7fc326c3128d116a43bcad5fff6077d Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Thu, 27 Oct 2016 20:24:16 +0200
Subject: [PATCH 10/10] decoder/sidplay: fix playback speed with libsidplayfp

https://bugs.musicpd.org/view.php?id=4577
---
 NEWS                                         |  1 +
 src/decoder/plugins/SidplayDecoderPlugin.cxx | 13 ++++++++++---
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/NEWS b/NEWS
index c873cbc2f..0f11eea76 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
 ver 0.19.20 (not yet released)
 * decoder
   - ffmpeg: ignore empty packets
+  - sidplay: fix playback speed with libsidplayfp
 
 ver 0.19.19 (2016/08/23)
 * decoder
diff --git a/src/decoder/plugins/SidplayDecoderPlugin.cxx b/src/decoder/plugins/SidplayDecoderPlugin.cxx
index 794a5dab8..8793a41b2 100644
--- a/src/decoder/plugins/SidplayDecoderPlugin.cxx
+++ b/src/decoder/plugins/SidplayDecoderPlugin.cxx
@@ -354,12 +354,19 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
 	DecoderCommand cmd;
 	do {
 		short buffer[4096];
-		size_t nbytes;
 
-		nbytes = player.play(buffer, ARRAY_SIZE(buffer));
-		if (nbytes == 0)
+		const auto result = player.play(buffer, ARRAY_SIZE(buffer));
+		if (result <= 0)
 			break;
 
+#ifdef HAVE_SIDPLAYFP
+		/* libsidplayfp returns the number of samples */
+		const size_t nbytes = result * sizeof(buffer[0]);
+#else
+		/* libsidplay2 returns the number of bytes */
+		const size_t nbytes = result;
+#endif
+
 		decoder_timestamp(decoder, (double)player.time() / timebase);
 
 		cmd = decoder_data(decoder, nullptr, buffer, nbytes, 0);