Browse Source

mpd: switch to using libnpupnp

Removed iconv const patch. After discussing with upstream. it turns out
that libiconv-full in OpenWrt is broken.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
lilik-openwrt-22.03
Rosen Penev 4 years ago
parent
commit
cd498507e2
No known key found for this signature in database GPG Key ID: 36D31CFA845F0E3B
4 changed files with 439 additions and 57 deletions
  1. +3
    -3
      sound/mpd/Makefile
  2. +0
    -3
      sound/mpd/patches/010-iconv.patch
  3. +0
    -51
      sound/mpd/patches/020-iconv-const.patch
  4. +436
    -0
      sound/mpd/patches/020-npupnp.patch

+ 3
- 3
sound/mpd/Makefile View File

@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=mpd PKG_NAME:=mpd
PKG_VERSION:=0.21.25 PKG_VERSION:=0.21.25
PKG_RELEASE:=4
PKG_RELEASE:=5
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=https://www.musicpd.org/download/mpd/0.21/ PKG_SOURCE_URL:=https://www.musicpd.org/download/mpd/0.21/
@ -47,7 +47,7 @@ endef
define Package/mpd-full define Package/mpd-full
$(call Package/mpd/Default) $(call Package/mpd/Default)
TITLE+= (full) 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 +BUILD_PATENTED:libffmpeg +!BUILD_PATENTED:libmad
PROVIDES:=mpd PROVIDES:=mpd
VARIANT:=full VARIANT:=full
@ -169,7 +169,7 @@ MESON_ARGS += \
ifeq ($(BUILD_VARIANT),full) ifeq ($(BUILD_VARIANT),full)
MESON_ARGS += \ MESON_ARGS += \
-Dupnp=enabled \
-Dupnp=npupnp \
-Dmms=enabled \ -Dmms=enabled \
-Dsoundcloud=enabled \ -Dsoundcloud=enabled \
-Dffmpeg=$(if $(CONFIG_BUILD_PATENTED),en,dis)abled \ -Dffmpeg=$(if $(CONFIG_BUILD_PATENTED),en,dis)abled \


+ 0
- 3
sound/mpd/patches/010-iconv.patch View File

@ -41,6 +41,3 @@ index bd6e30944..132e15b89 100644
if not have_iconv and get_option('iconv').enabled() if not have_iconv and get_option('iconv').enabled()
error('iconv() not available') error('iconv() not available')
endif endif
--
2.17.1

+ 0
- 51
sound/mpd/patches/020-iconv-const.patch View File

@ -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

+ 436
- 0
sound/mpd/patches/020-npupnp.patch View File

@ -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()

Loading…
Cancel
Save