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 -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 ---- - 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(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 -+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 +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 ++ + #include + ++#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 > actionParams{ ++ { "ObjectID", objectId }, ++ { "BrowseFlag", "BrowseDirectChildren" }, ++ { "Filter", "*" }, ++ { "SortCriteria", "" }, ++ { "StartingIndex", StringFormat<32>("%u", offset).c_str() }, ++ { "RequestedCount", StringFormat<32>("%u", count).c_str() } ++ }; ++ std::vector > 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 > actionParams{ ++ { "ContainerID", objectId }, ++ { "SearchCriteria", ss }, ++ { "Filter", "*" }, ++ { "SortCriteria", "" }, ++ { "StartingIndex", ++ StringFormat<32>("%u", offset).c_str() }, ++ { "RequestedCount", "0" } ++ }; ++ std::vector > 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 > actionParams{ ++ { "ObjectID", objectId }, { "BrowseFlag", "BrowseMetadata" }, ++ { "Filter", "*" }, { "SortCriteria", "" }, ++ { "StartingIndex", "0" }, { "RequestedCount", "1" } ++ }; ++ std::vector > 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 + +-#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 ++ + 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 + 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 > 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 + #include ++#ifdef USING_PUPNP + #include ++#endif + + #include + +@@ -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 + + #include +@@ -37,4 +38,5 @@ struct UpnpIxmlDeleter { + typedef std::unique_ptr UniqueIxmlDocument; + typedef std::unique_ptr 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 + + #include +@@ -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()