diff --git a/sound/mpd/Makefile b/sound/mpd/Makefile
index b9d1e520d..be62a1dc2 100644
--- a/sound/mpd/Makefile
+++ b/sound/mpd/Makefile
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=mpd
 PKG_VERSION:=0.21.25
-PKG_RELEASE:=4
+PKG_RELEASE:=5
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
 PKG_SOURCE_URL:=https://www.musicpd.org/download/mpd/0.21/
@@ -47,7 +47,7 @@ endef
 define Package/mpd-full
 $(call Package/mpd/Default)
   TITLE+= (full)
-  DEPENDS+= +AUDIO_SUPPORT:pulseaudio-daemon +libvorbis +libmms +libupnp +libshout +yajl \
+  DEPENDS+= +AUDIO_SUPPORT:pulseaudio-daemon +libvorbis +libmms +libnpupnp +libshout +yajl \
             +BUILD_PATENTED:libffmpeg +!BUILD_PATENTED:libmad
   PROVIDES:=mpd
   VARIANT:=full
@@ -85,7 +85,7 @@ endef
 define Package/mpd-avahi-service
 $(call Package/mpd/Default)
   TITLE+= (Avahi service)
-  DEPENDS+=+avahi-daemon
+  DEPENDS+=+avahi-dbus-daemon
 endef
 
 define Package/mpd-avahi-service/description
@@ -169,7 +169,7 @@ MESON_ARGS += \
 ifeq ($(BUILD_VARIANT),full)
 
   MESON_ARGS += \
-	-Dupnp=enabled \
+	-Dupnp=npupnp \
 	-Dmms=enabled \
 	-Dsoundcloud=enabled \
 	-Dffmpeg=$(if $(CONFIG_BUILD_PATENTED),en,dis)abled \
diff --git a/sound/mpd/patches/010-iconv.patch b/sound/mpd/patches/010-iconv.patch
index c7dad5fd5..81adf1ba7 100644
--- a/sound/mpd/patches/010-iconv.patch
+++ b/sound/mpd/patches/010-iconv.patch
@@ -41,6 +41,3 @@ index bd6e30944..132e15b89 100644
    if not have_iconv and get_option('iconv').enabled()
      error('iconv() not available')
    endif
--- 
-2.17.1
-
diff --git a/sound/mpd/patches/020-iconv-const.patch b/sound/mpd/patches/020-iconv-const.patch
deleted file mode 100644
index 82f19dd55..000000000
--- a/sound/mpd/patches/020-iconv-const.patch
+++ /dev/null
@@ -1,51 +0,0 @@
-From c2da1d47eeaf83d3683555b965a16654561f14b3 Mon Sep 17 00:00:00 2001
-From: Rosen Penev <rosenp@gmail.com>
-Date: Thu, 30 Jul 2020 16:27:02 -0700
-Subject: [PATCH] icu: fix compilation with const char iconv
-
-libiconv uses const char. Test for it and use it properly to fix
-compilation.
-
-Signed-off-by: Rosen Penev <rosenp@gmail.com>
----
- src/lib/icu/Converter.cxx |  2 +-
- src/lib/icu/meson.build   | 10 ++++++++++
- 2 files changed, 11 insertions(+), 1 deletion(-)
-
-diff --git a/src/lib/icu/Converter.cxx b/src/lib/icu/Converter.cxx
-index b03543a82..4c459e57e 100644
---- a/src/lib/icu/Converter.cxx
-+++ b/src/lib/icu/Converter.cxx
-@@ -83,7 +83,7 @@ DoConvert(iconv_t conv, const char *src)
- {
- 	// TODO: dynamic buffer?
- 	char buffer[4096];
--	char *in = const_cast<char *>(src);
-+	ICONV_CONST char *in = (ICONV_CONST char *)(src);
- 	char *out = buffer;
- 	size_t in_left = strlen(src);
- 	size_t out_left = sizeof(buffer);
-diff --git a/src/lib/icu/meson.build b/src/lib/icu/meson.build
-index 132e15b89..ac7d1b72a 100644
---- a/src/lib/icu/meson.build
-+++ b/src/lib/icu/meson.build
-@@ -30,6 +30,16 @@ elif not get_option('iconv').disabled()
-     have_iconv = true
-     conf.set('HAVE_ICONV', have_iconv)
-   endif
-+  if have_iconv
-+    iconvconsttest = '''#include <iconv.h>
-+size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
-+'''
-+    if c_compiler.compiles(iconvconsttest, dependencies : libiconv)
-+      conf.set('ICONV_CONST', '')
-+    else
-+      conf.set('ICONV_CONST', 'const')
-+    endif
-+  endif
-   if not have_iconv and get_option('iconv').enabled()
-     error('iconv() not available')
-   endif
--- 
-2.17.1
-
diff --git a/sound/mpd/patches/020-npupnp.patch b/sound/mpd/patches/020-npupnp.patch
new file mode 100644
index 000000000..02d255673
--- /dev/null
+++ b/sound/mpd/patches/020-npupnp.patch
@@ -0,0 +1,436 @@
+From 61df54155a3cb1846e6bf15e4f007ec8d623de63 Mon Sep 17 00:00:00 2001
+From: Jean-Francois Dockes <jf@dockes.org>
+Date: Sun, 23 Aug 2020 14:22:21 +0200
+Subject: [PATCH] Modification to use npupnp instead of pupnp when the upnp
+ meson option is set
+
+---
+ meson_options.txt                             |   5 +-
+ .../plugins/upnp/ContentDirectoryService.cxx  | 101 ++++++++++++++++++
+ src/lib/upnp/Action.hxx                       |   2 +
+ src/lib/upnp/ClientInit.cxx                   |  12 +--
+ src/lib/upnp/Compat.hxx                       |   4 +-
+ src/lib/upnp/ContentDirectoryService.cxx      |  25 +++++
+ src/lib/upnp/Init.cxx                         |   4 +
+ src/lib/upnp/UniqueIxml.hxx                   |   2 +
+ src/lib/upnp/ixmlwrap.cxx                     |   4 +
+ src/lib/upnp/ixmlwrap.hxx                     |   2 +
+ src/lib/upnp/meson.build                      |  20 +++-
+ 11 files changed, 170 insertions(+), 11 deletions(-)
+
+diff --git a/meson_options.txt b/meson_options.txt
+index d17ac1ca8..da90ccfd8 100644
+--- a/meson_options.txt
++++ b/meson_options.txt
+@@ -54,7 +54,10 @@ option('dsd', type: 'boolean', value: true, description: 'Support the DSD audio
+ #
+ 
+ option('database', type: 'boolean', value: true, description: 'enable support for the music database')
+-option('upnp', type: 'feature', description: 'UPnP client support')
++option('upnp', type: 'combo',
++       choices: ['auto', 'pupnp', 'npupnp', 'disabled'],
++       value: 'auto',
++       description: 'UPnP client support')
+ option('libmpdclient', type: 'feature', description: 'libmpdclient support (for the proxy database plugin)')
+ 
+ #
+diff --git a/src/db/plugins/upnp/ContentDirectoryService.cxx b/src/db/plugins/upnp/ContentDirectoryService.cxx
+index 99893d89d..29d58ca23 100644
+--- a/src/db/plugins/upnp/ContentDirectoryService.cxx
++++ b/src/db/plugins/upnp/ContentDirectoryService.cxx
+@@ -18,7 +18,10 @@
+  */
+ 
+ #include "lib/upnp/ContentDirectoryService.hxx"
++#include "config.h"
++#ifdef USING_PUPNP
+ #include "lib/upnp/ixmlwrap.hxx"
++#endif
+ #include "lib/upnp/UniqueIxml.hxx"
+ #include "lib/upnp/Action.hxx"
+ #include "Directory.hxx"
+@@ -28,8 +31,11 @@
+ #include "util/ScopeExit.hxx"
+ #include "util/StringFormat.hxx"
+ 
++#include <algorithm>
++
+ #include <stdio.h>
+ 
++#ifdef USING_PUPNP
+ static void
+ ReadResultTag(UPnPDirContent &dirbuf, IXML_Document *response)
+ {
+@@ -39,6 +45,7 @@ ReadResultTag(UPnPDirContent &dirbuf, IXML_Document *response)
+ 
+ 	dirbuf.Parse(p);
+ }
++#endif
+ 
+ inline void
+ ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
+@@ -47,6 +54,7 @@ ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
+ 				      unsigned &didreadp,
+ 				      unsigned &totalp) const
+ {
++#ifdef USING_PUPNP
+ 	// Some devices require an empty SortCriteria, else bad params
+ 	IXML_Document *request =
+ 		MakeActionHelper("Browse", m_serviceType.c_str(),
+@@ -82,6 +90,37 @@ ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
+ 		totalp = ParseUnsigned(value);
+ 
+ 	ReadResultTag(dirbuf, response);
++#else
++	std::vector<std::pair<std::string, std::string> > actionParams{
++		{ "ObjectID", objectId },
++		{ "BrowseFlag", "BrowseDirectChildren" },
++		{ "Filter", "*" },
++		{ "SortCriteria", "" },
++		{ "StartingIndex", StringFormat<32>("%u", offset).c_str() },
++		{ "RequestedCount", StringFormat<32>("%u", count).c_str() }
++	};
++	std::vector<std::pair<std::string, std::string> > responseData;
++	int errcode;
++	std::string errdesc;
++	int code =
++		UpnpSendAction(hdl, "", m_actionURL, m_serviceType, "Browse",
++			       actionParams, responseData, &errcode, errdesc);
++	if (code != UPNP_E_SUCCESS)
++		throw FormatRuntimeError("UpnpSendAction() failed: %s",
++					 UpnpGetErrorMessage(code));
++	const char *p = "";
++	didreadp = 0;
++	for (const auto &entry : responseData) {
++		if (entry.first == "Result") {
++			p = entry.second.c_str();
++		} else if (entry.first == "TotalMatches") {
++			totalp = ParseUnsigned(entry.second.c_str());
++		} else if (entry.first == "NumberReturned") {
++			didreadp = ParseUnsigned(entry.second.c_str());
++		}
++	}
++	dirbuf.Parse(p);
++#endif
+ }
+ 
+ UPnPDirContent
+@@ -110,6 +149,7 @@ ContentDirectoryService::search(UpnpClient_Handle hdl,
+ 	unsigned offset = 0, total = -1, count;
+ 
+ 	do {
++#ifdef USING_PUPNP
+ 		UniqueIxmlDocument request(MakeActionHelper("Search", m_serviceType.c_str(),
+ 							    "ContainerID", objectId,
+ 							    "SearchCriteria", ss,
+@@ -147,6 +187,39 @@ ContentDirectoryService::search(UpnpClient_Handle hdl,
+ 			total = ParseUnsigned(value);
+ 
+ 		ReadResultTag(dirbuf, response.get());
++#else
++		std::vector<std::pair<std::string, std::string> > actionParams{
++			{ "ContainerID", objectId },
++			{ "SearchCriteria", ss },
++			{ "Filter", "*" },
++			{ "SortCriteria", "" },
++			{ "StartingIndex",
++			  StringFormat<32>("%u", offset).c_str() },
++			{ "RequestedCount", "0" }
++		};
++		std::vector<std::pair<std::string, std::string> > responseData;
++		int errcode;
++		std::string errdesc;
++		int code = UpnpSendAction(hdl, "", m_actionURL, m_serviceType,
++					  "Search", actionParams, responseData,
++					  &errcode, errdesc);
++		if (code != UPNP_E_SUCCESS)
++			throw FormatRuntimeError("UpnpSendAction() failed: %s",
++						 UpnpGetErrorMessage(code));
++		const char *p = "";
++		count = 0;
++		for (const auto &entry : responseData) {
++			if (entry.first == "Result") {
++				p = entry.second.c_str();
++			} else if (entry.first == "TotalMatches") {
++				total = ParseUnsigned(entry.second.c_str());
++			} else if (entry.first == "NumberReturned") {
++				count = ParseUnsigned(entry.second.c_str());
++				offset += count;
++			}
++		}
++		dirbuf.Parse(p);
++#endif
+ 	} while (count > 0 && offset < total);
+ 
+ 	return dirbuf;
+@@ -156,6 +229,7 @@ UPnPDirContent
+ ContentDirectoryService::getMetadata(UpnpClient_Handle hdl,
+ 				     const char *objectId) const
+ {
++#ifdef USING_PUPNP
+ 	// Create request
+ 	UniqueIxmlDocument request(MakeActionHelper("Browse", m_serviceType.c_str(),
+ 						    "ObjectID", objectId,
+@@ -179,4 +253,31 @@ ContentDirectoryService::getMetadata(UpnpClient_Handle hdl,
+ 	UPnPDirContent dirbuf;
+ 	ReadResultTag(dirbuf, response.get());
+ 	return dirbuf;
++#else
++	std::vector<std::pair<std::string, std::string> > actionParams{
++		{ "ObjectID", objectId }, { "BrowseFlag", "BrowseMetadata" },
++		{ "Filter", "*" },	  { "SortCriteria", "" },
++		{ "StartingIndex", "0" }, { "RequestedCount", "1" }
++	};
++	std::vector<std::pair<std::string, std::string> > responseData;
++	int errcode;
++	std::string errdesc;
++	int code =
++		UpnpSendAction(hdl, "", m_actionURL, m_serviceType, "Browse",
++			       actionParams, responseData, &errcode, errdesc);
++	if (code != UPNP_E_SUCCESS)
++		throw FormatRuntimeError("UpnpSendAction() failed: %s",
++					 UpnpGetErrorMessage(code));
++	const char *p = "";
++	for (const auto &entry : responseData) {
++		if (entry.first == "Result") {
++			p = entry.second.c_str();
++			break;
++		}
++	}
++
++	UPnPDirContent dirbuf;
++	dirbuf.Parse(p);
++	return dirbuf;
++#endif
+ }
+diff --git a/src/lib/upnp/Action.hxx b/src/lib/upnp/Action.hxx
+index 49ed75198..4ecf4cb06 100644
+--- a/src/lib/upnp/Action.hxx
++++ b/src/lib/upnp/Action.hxx
+@@ -38,6 +38,7 @@ CountNameValuePairs(gcc_unused const char *name, gcc_unused const char *value,
+ 	return 1 + CountNameValuePairs(args...);
+ }
+ 
++#ifdef USING_PUPNP
+ /**
+  * A wrapper for UpnpMakeAction() that counts the number of name/value
+  * pairs and adds the nullptr sentinel.
+@@ -52,5 +53,6 @@ MakeActionHelper(const char *action_name, const char *service_type,
+ 			      args...,
+ 			      nullptr, nullptr);
+ }
++#endif
+ 
+ #endif
+diff --git a/src/lib/upnp/ClientInit.cxx b/src/lib/upnp/ClientInit.cxx
+index 23ba9cade..54b677fa2 100644
+--- a/src/lib/upnp/ClientInit.cxx
++++ b/src/lib/upnp/ClientInit.cxx
+@@ -31,14 +31,12 @@ static Mutex upnp_client_init_mutex;
+ static unsigned upnp_client_ref;
+ static UpnpClient_Handle upnp_client_handle;
+ 
+-static int
+-UpnpClientCallback(Upnp_EventType et,
+-#if UPNP_VERSION >= 10800
+-		   const
++static int UpnpClientCallback(Upnp_EventType et,
++#if 1
++			      const
+ #endif
+-		   void *evp,
+-		   void *cookie) noexcept
+-{
++			      void *evp,
++			      void *cookie) noexcept {
+ 	if (cookie == nullptr)
+ 		/* this is the cookie passed to UpnpRegisterClient();
+ 		   but can this ever happen?  Will libupnp ever invoke
+diff --git a/src/lib/upnp/Compat.hxx b/src/lib/upnp/Compat.hxx
+index 7fba1d83b..b9a4d7cf3 100644
+--- a/src/lib/upnp/Compat.hxx
++++ b/src/lib/upnp/Compat.hxx
+@@ -22,14 +22,14 @@
+ 
+ #include <upnp.h>
+ 
+-#if UPNP_VERSION < 10800
++#if 0
+ /* emulate the libupnp 1.8 API with older versions */
+ 
+ using UpnpDiscovery = Upnp_Discovery;
+ 
+ #endif
+ 
+-#if UPNP_VERSION < 10624
++#if 0
+ #include "util/Compiler.h"
+ 
+ gcc_pure
+diff --git a/src/lib/upnp/ContentDirectoryService.cxx b/src/lib/upnp/ContentDirectoryService.cxx
+index ae514c717..eed28b41a 100644
+--- a/src/lib/upnp/ContentDirectoryService.cxx
++++ b/src/lib/upnp/ContentDirectoryService.cxx
+@@ -17,15 +17,21 @@
+  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+  */
+ 
++#include "config.h"
++
+ #include "ContentDirectoryService.hxx"
+ #include "UniqueIxml.hxx"
+ #include "Device.hxx"
++#ifdef USING_PUPNP
+ #include "ixmlwrap.hxx"
++#endif
+ #include "Action.hxx"
+ #include "util/UriUtil.hxx"
+ #include "util/RuntimeError.hxx"
+ #include "util/SplitString.hxx"
+ 
++#include <algorithm>
++
+ ContentDirectoryService::ContentDirectoryService(const UPnPDevice &device,
+ 						 const UPnPService &service) noexcept
+ 	:m_actionURL(uri_apply_base(service.controlURL, device.URLBase)),
+@@ -51,6 +57,7 @@ ContentDirectoryService::~ContentDirectoryService() noexcept
+ std::forward_list<std::string>
+ ContentDirectoryService::getSearchCapabilities(UpnpClient_Handle hdl) const
+ {
++#ifdef USING_PUPNP
+ 	UniqueIxmlDocument request(UpnpMakeAction("GetSearchCapabilities", m_serviceType.c_str(),
+ 						  0,
+ 						  nullptr, nullptr));
+@@ -69,6 +76,24 @@ ContentDirectoryService::getSearchCapabilities(UpnpClient_Handle hdl) const
+ 
+ 	const char *s = ixmlwrap::getFirstElementValue(response.get(),
+ 						       "SearchCaps");
++#else
++	std::vector<std::pair<std::string, std::string> > responseData;
++	int errcode;
++	std::string errdesc;
++	auto code = UpnpSendAction(hdl, "", m_actionURL, m_serviceType,
++				   "GetSearchCapabilities", {}, responseData,
++				   &errcode, errdesc);
++	if (code != UPNP_E_SUCCESS)
++		throw FormatRuntimeError("UpnpSendAction() failed: %s",
++					 UpnpGetErrorMessage(code));
++	const char *s{ nullptr };
++	for (auto &entry : responseData) {
++		if (entry.first == "SearchCaps") {
++			s = entry.second.c_str();
++			break;
++		}
++	}
++#endif
+ 	if (s == nullptr || *s == 0)
+ 		/* we could just "return {}" here, but GCC 5 doesn't
+ 		   understand that */
+diff --git a/src/lib/upnp/Init.cxx b/src/lib/upnp/Init.cxx
+index 7ad4d565a..10510402a 100644
+--- a/src/lib/upnp/Init.cxx
++++ b/src/lib/upnp/Init.cxx
+@@ -23,7 +23,9 @@
+ 
+ #include <upnp.h>
+ #include <upnptools.h>
++#ifdef USING_PUPNP
+ #include <ixml.h>
++#endif
+ 
+ #include <assert.h>
+ 
+@@ -44,8 +46,10 @@ DoInit()
+ 
+ 	UpnpSetMaxContentLength(2000*1024);
+ 
++#ifdef USING_PUPNP
+ 	// Servers sometimes make error (e.g.: minidlna returns bad utf-8)
+ 	ixmlRelaxParser(1);
++#endif
+ }
+ 
+ void
+diff --git a/src/lib/upnp/UniqueIxml.hxx b/src/lib/upnp/UniqueIxml.hxx
+index 2ff2afa62..8a0ea0a1f 100644
+--- a/src/lib/upnp/UniqueIxml.hxx
++++ b/src/lib/upnp/UniqueIxml.hxx
+@@ -20,6 +20,7 @@
+ #ifndef MPD_UPNP_UNIQUE_XML_HXX
+ #define MPD_UPNP_UNIQUE_XML_HXX
+ 
++#ifdef USING_PUPNP
+ #include <ixml.h>
+ 
+ #include <memory>
+@@ -37,4 +38,5 @@ struct UpnpIxmlDeleter {
+ typedef std::unique_ptr<IXML_Document, UpnpIxmlDeleter> UniqueIxmlDocument;
+ typedef std::unique_ptr<IXML_NodeList, UpnpIxmlDeleter> UniqueIxmlNodeList;
+ 
++#endif /* USING_PUPNP */
+ #endif
+diff --git a/src/lib/upnp/ixmlwrap.cxx b/src/lib/upnp/ixmlwrap.cxx
+index 4e44f35a6..c7798e557 100644
+--- a/src/lib/upnp/ixmlwrap.cxx
++++ b/src/lib/upnp/ixmlwrap.cxx
+@@ -15,6 +15,9 @@
+  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  */
+ 
++#include "config.h"
++
++#ifdef USING_PUPNP
+ #include "ixmlwrap.hxx"
+ #include "UniqueIxml.hxx"
+ 
+@@ -39,3 +42,4 @@ getFirstElementValue(IXML_Document *doc, const char *name) noexcept
+ }
+ 
+ }
++#endif
+diff --git a/src/lib/upnp/ixmlwrap.hxx b/src/lib/upnp/ixmlwrap.hxx
+index 6713d59bd..4b01801f7 100644
+--- a/src/lib/upnp/ixmlwrap.hxx
++++ b/src/lib/upnp/ixmlwrap.hxx
+@@ -17,6 +17,7 @@
+ #ifndef _IXMLWRAP_H_INCLUDED_
+ #define _IXMLWRAP_H_INCLUDED_
+ 
++#ifdef USING_PUPNP
+ #include <ixml.h>
+ 
+ #include <string>
+@@ -32,4 +33,5 @@ namespace ixmlwrap {
+ 
+ }
+ 
++#endif /* USING_PUPNP */
+ #endif /* _IXMLWRAP_H_INCLUDED_ */
+diff --git a/src/lib/upnp/meson.build b/src/lib/upnp/meson.build
+index 9e16f7319..bdc248e6c 100644
+--- a/src/lib/upnp/meson.build
++++ b/src/lib/upnp/meson.build
+@@ -1,4 +1,22 @@
+-upnp_dep = dependency('libupnp', required: get_option('upnp'))
++upnp_option = get_option('upnp')
++
++if upnp_option == 'auto'
++  upnp_dep = dependency('libupnp', version: '>= 1.8', required: false)
++  conf.set('USING_PUPNP', upnp_dep.found())
++  if not upnp_dep.found()
++    upnp_dep = dependency('libnpupnp', version: '>= 1.8', required: false)
++  endif
++elif upnp_option == 'pupnp'
++  upnp_dep = dependency('libupnp', version: '>= 1.8', required: true)
++  conf.set('USING_PUPNP', true)
++elif upnp_option == 'npupnp'
++  upnp_dep = dependency('libnpupnp', required: true)
++  conf.set('USING_PUPNP', false)
++elif upnp_option == 'disabled'
++  upnp_dep = dependency('', required: false)
++  subdir_done()
++endif
++
+ conf.set('ENABLE_UPNP', upnp_dep.found())
+ if not upnp_dep.found()
+   subdir_done()