gerbera: use npupnp 12574/head
authorRosen Penev <rosenp@gmail.com>
Mon, 22 Jun 2020 04:05:43 +0000 (21:05 -0700)
committerRosen Penev <rosenp@gmail.com>
Mon, 22 Jun 2020 21:37:47 +0000 (14:37 -0700)
This is on track to replace libupnp in the next version. Since libupnp
is not building with GCC10, do this now.

Also backported needed header patch.

Replace other patches with the upstream versions.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
multimedia/gerbera/Makefile
multimedia/gerbera/patches/010-iconv.patch
multimedia/gerbera/patches/020-pid.patch
multimedia/gerbera/patches/030-unistd.patch [new file with mode: 0644]
multimedia/gerbera/patches/040-npupnp.patch [new file with mode: 0644]

index f5039c125343540426b128d2252f279363bd1e97..851464c9cf705292f35673a800d3328180297676 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=gerbera
 PKG_VERSION:=1.5.0
-PKG_RELEASE:=7
+PKG_RELEASE:=8
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_SOURCE_URL:=https://codeload.github.com/gerbera/gerbera/tar.gz/v$(PKG_VERSION)?
@@ -29,7 +29,7 @@ include $(INCLUDE_DIR)/nls.mk
 define Package/gerbera
   SECTION:=multimedia
   CATEGORY:=Multimedia
-  DEPENDS:=+file +libupnp +libsqlite3 +libexif +libuuid +libfmt $(ICONV_DEPENDS)
+  DEPENDS:=+file +libnpupnp +libsqlite3 +libexif +libuuid +libfmt $(ICONV_DEPENDS)
   TITLE:=A free media server
   URL:=https://gerbera.io
   USERID:=gerbera:gerbera
@@ -64,7 +64,11 @@ CMAKE_OPTIONS += \
        -DWITH_DEBUG=OFF \
        -DWITH_TESTS=OFF
 
-TARGET_CFLAGS += -ffunction-sections -fdata-sections -flto
+TARGET_CFLAGS += \
+       -ffunction-sections \
+       -fdata-sections \
+       -flto \
+       -I$(STAGING_DIR)/usr/include/npupnp/upnp
 TARGET_LDFLAGS += -Wl,--gc-sections,--as-needed
 
 define Package/gerbera/install
index e93746d332ac90c66534f34a581c550f3306bb6b..9145f76fd91e88be810adcd53f631a8f56c0c0e8 100644 (file)
@@ -1,3 +1,18 @@
+From 77cae5ff9b8dff22bfebac905f1579562609dd35 Mon Sep 17 00:00:00 2001
+From: Rosen Penev <rosenp@gmail.com>
+Date: Mon, 4 May 2020 12:44:34 -0700
+Subject: [PATCH] remove iconv casting
+
+iconv_t is sometimes a pointer and other times an int. Remove casting
+to make it work with the latter.
+
+Signed-off-by: Rosen Penev <rosenp@gmail.com>
+---
+ src/util/string_converter.cc | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/src/util/string_converter.cc b/src/util/string_converter.cc
+index 272787ad..e1724b39 100644
 --- a/src/util/string_converter.cc
 +++ b/src/util/string_converter.cc
 @@ -41,15 +41,15 @@ StringConverter::StringConverter(const std::string& from, const std::string& to)
@@ -6,8 +21,8 @@
      cd = iconv_open(to.c_str(), from.c_str());
 -    if (cd == reinterpret_cast<iconv_t>(-1)) {
 -        cd = static_cast<iconv_t>(nullptr);
-+    if (cd == (iconv_t)(-1)) {
-+        cd = (iconv_t)(nullptr);
++    if (!cd) {
++        cd = {};
          throw_std_runtime_error(std::string("iconv: ") + strerror(errno));
      }
  }
@@ -15,7 +30,7 @@
  StringConverter::~StringConverter()
  {
 -    if (cd != static_cast<iconv_t>(nullptr))
-+    if (cd != (iconv_t)(nullptr))
++    if (cd)
          iconv_close(cd);
  }
  
index 23c5885112fc76ca71dbcff2bdd1b427553e177f..7ce75c70b1ca3d3bb98870dbed00da10f81ea35f 100644 (file)
@@ -1,3 +1,20 @@
+From 59d37af2d6afd3d0ab6e8c5f3ea099435150c349 Mon Sep 17 00:00:00 2001
+From: Rosen Penev <rosenp@gmail.com>
+Date: Tue, 2 Jun 2020 15:55:25 -0700
+Subject: [PATCH] add missing unistd header
+
+Error with pid_t.
+
+Found with musl + libcxx.
+
+Signed-off-by: Rosen Penev <rosenp@gmail.com>
+---
+ src/util/process.h          | 2 ++
+ src/util/process_executor.h | 2 ++
+ 2 files changed, 4 insertions(+)
+
+diff --git a/src/util/process.h b/src/util/process.h
+index e79e016c..8778aa34 100644
 --- a/src/util/process.h
 +++ b/src/util/process.h
 @@ -35,6 +35,8 @@
@@ -9,6 +26,8 @@
  // forward declaration
  class Config;
  
+diff --git a/src/util/process_executor.h b/src/util/process_executor.h
+index eaccf451..2a724087 100644
 --- a/src/util/process_executor.h
 +++ b/src/util/process_executor.h
 @@ -35,6 +35,8 @@
diff --git a/multimedia/gerbera/patches/030-unistd.patch b/multimedia/gerbera/patches/030-unistd.patch
new file mode 100644 (file)
index 0000000..5b50f03
--- /dev/null
@@ -0,0 +1,74 @@
+From 89b289cde29c731f995642a341dc5fd3b47ec7a0 Mon Sep 17 00:00:00 2001
+From: Jean-Francois Dockes <jf@dockes.org>
+Date: Mon, 4 May 2020 16:32:23 +0200
+Subject: [PATCH] The access() system call needs unistd.h, at least on Focal
+
+---
+ src/file_request_handler.cc         | 2 +-
+ src/iohandler/io_handler_chainer.cc | 2 +-
+ src/serve_request_handler.cc        | 2 +-
+ src/util/upnp_quirks.cc             | 2 +-
+ 4 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/src/file_request_handler.cc b/src/file_request_handler.cc
+index e8579b06..cfa3eaed 100644
+--- a/src/file_request_handler.cc
++++ b/src/file_request_handler.cc
+@@ -30,9 +30,9 @@
+ /// \file file_request_handler.cc
+ #include "file_request_handler.h" // API
+-
+ #include <filesystem>
+ #include <sys/stat.h>
++#include <unistd.h>
+ #include <utility>
+ #include "config/config_manager.h"
+diff --git a/src/iohandler/io_handler_chainer.cc b/src/iohandler/io_handler_chainer.cc
+index e8701cd7..beaa9d03 100644
+--- a/src/iohandler/io_handler_chainer.cc
++++ b/src/iohandler/io_handler_chainer.cc
+@@ -30,8 +30,8 @@
+ /// \file io_handler_chainer.cc
+ #include "io_handler_chainer.h" // API
+-
+ #include <cstdlib>
++#include <unistd.h>
+ #include "exceptions.h"
+diff --git a/src/serve_request_handler.cc b/src/serve_request_handler.cc
+index 8eaf46af..210140a3 100644
+--- a/src/serve_request_handler.cc
++++ b/src/serve_request_handler.cc
+@@ -30,8 +30,8 @@
+ /// \file serve_request_handler.cc
+ #include "serve_request_handler.h"
+-
+ #include <sys/stat.h>
++#include <unistd.h>
+ #include <utility>
+ #include "config/config_manager.h"
+diff --git a/src/util/upnp_quirks.cc b/src/util/upnp_quirks.cc
+index df137370..e6f510b4 100644
+--- a/src/util/upnp_quirks.cc
++++ b/src/util/upnp_quirks.cc
+@@ -24,13 +24,13 @@
+ /// \file upnp_quirks.cc
+ #include "upnp_quirks.h" // API
+-
+ #include "cds_objects.h"
+ #include "config/config_manager.h"
+ #include "server.h"
+ #include "util/tools.h"
+ #include "util/upnp_clients.h"
+ #include "util/upnp_headers.h"
++#include <unistd.h>
+ Quirks::Quirks(std::shared_ptr<Config> config, const struct sockaddr_storage* addr, const std::string& userAgent)
+     : config(std::move(config))
diff --git a/multimedia/gerbera/patches/040-npupnp.patch b/multimedia/gerbera/patches/040-npupnp.patch
new file mode 100644 (file)
index 0000000..b82a4db
--- /dev/null
@@ -0,0 +1,485 @@
+From 2ebccbb993dca41674de295f2d513abd568f971a Mon Sep 17 00:00:00 2001
+From: Jean-Francois Dockes <jf@dockes.org>
+Date: Fri, 13 Mar 2020 09:19:04 +0100
+Subject: [PATCH] Quick changes for working with NPUPNP
+
+---
+ CMakeLists.txt                           | 12 +++++-------
+ src/action_request.cc                    | 11 +++++++++++
+ src/device_description_handler.cc        |  4 ++++
+ src/file_request_handler.cc              |  4 ++++
+ src/iohandler/file_io_handler.cc         |  2 ++
+ src/iohandler/io_handler.cc              |  2 ++
+ src/iohandler/mem_io_handler.cc          |  2 ++
+ src/serve_request_handler.cc             |  9 ++++++++-
+ src/server.cc                            |  8 ++++++++
+ src/transcoding/transcode_ext_handler.cc |  2 ++
+ src/upnp_cds.cc                          | 12 +++++++++++-
+ src/upnp_cm.cc                           | 11 +++++++++++
+ src/upnp_mrreg.cc                        | 10 +++++++++-
+ src/url_request_handler.cc               |  6 ++++++
+ src/util/upnp_clients.cc                 | 12 ++++++++++++
+ src/util/upnp_headers.cc                 | 14 +++++++++++++-
+ src/util/upnp_headers.h                  |  2 ++
+ src/web/web_request_handler.cc           |  4 ++++
+ 18 files changed, 116 insertions(+), 11 deletions(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 46f2ca5c..b51300d9 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -293,13 +293,11 @@ if (LFS_FOUND)
+     target_link_libraries(gerbera ${LFS_LIBRARIES})
+ endif()
+-find_package (LibUpnp REQUIRED)
+-include_directories(${UPNP_INCLUDE_DIRS})
+-target_link_libraries (gerbera ${UPNP_LIBRARIES})
+-
+-if (UPNP_VERSION_STRING VERSION_LESS "1.12.1")
+-    message(FATAL_ERROR "gerbera requires libupnp 1.12.1 or above.")
+-endif()
++####  Hard-coded NPUPNP defs for now, just for testing
++add_definitions(-DUSING_NPUPNP)
++include_directories(/usr/include/npupnp/upnp)
++target_link_libraries (gerbera -lnpupnp)
++set (UPNP_HAS_IPV6 1)
+ if (NOT UPNP_HAS_IPV6)
+     message(FATAL_ERROR "Gerbera requires libupnp with IPv6 support.")
+diff --git a/src/action_request.cc b/src/action_request.cc
+index 3aa4a991..29be6aaf 100644
+--- a/src/action_request.cc
++++ b/src/action_request.cc
+@@ -65,11 +65,17 @@ std::string ActionRequest::getServiceID() const
+ std::unique_ptr<pugi::xml_document> ActionRequest::getRequest() const
+ {
++#if !defined(USING_NPUPNP)
+     DOMString cxml = ixmlPrintDocument(UpnpActionRequest_get_ActionRequest(upnp_request));
++#endif
+     auto request = std::make_unique<pugi::xml_document>();
++#if defined(USING_NPUPNP)
++    auto ret = request->load_string(upnp_request->xmlAction.c_str());
++#else
+     auto ret = request->load_string(cxml);
+     ixmlFreeDOMString(cxml);
++#endif
+     if (ret.status != pugi::xml_parse_status::status_ok)
+         throw_std_runtime_error("Unable to parse ixml");
+@@ -94,6 +100,7 @@ void ActionRequest::update()
+         std::string xml = buf.str();
+         log_debug("ActionRequest::update(): {}", xml.c_str());
++#if !defined(USING_NPUPNP)
+         IXML_Document* result = nullptr;
+         int err = ixmlParseBufferEx(xml.c_str(), &result);
+@@ -105,6 +112,10 @@ void ActionRequest::update()
+             UpnpActionRequest_set_ActionResult(upnp_request, result);
+             UpnpActionRequest_set_ErrCode(upnp_request, errCode);
+         }
++#else
++              UpnpActionRequest_set_xmlResponse(upnp_request, xml);
++              UpnpActionRequest_set_ErrCode(upnp_request, errCode);
++#endif
+     } else {
+         // ok, here there can be two cases
+         // either the function below already did set an error code,
+diff --git a/src/device_description_handler.cc b/src/device_description_handler.cc
+index 6aca745e..cf2e8015 100644
+--- a/src/device_description_handler.cc
++++ b/src/device_description_handler.cc
+@@ -45,7 +45,11 @@ void DeviceDescriptionHandler::getInfo(const char* filename, UpnpFileInfo* info)
+ {
+     // We should be able to do the generation here, but libupnp doesnt support the request cookies yet
+     UpnpFileInfo_set_FileLength(info, -1);
++#if defined(USING_NPUPNP)
+     UpnpFileInfo_set_ContentType(info, "application/xml");
++#else
++    UpnpFileInfo_set_ContentType(info, ixmlCloneDOMString("application/xml"));
++#endif
+     UpnpFileInfo_set_IsReadable(info, 1);
+     UpnpFileInfo_set_IsDirectory(info, 0);
+ }
+diff --git a/src/file_request_handler.cc b/src/file_request_handler.cc
+index e8579b06..615f7e85 100644
+--- a/src/file_request_handler.cc
++++ b/src/file_request_handler.cc
+@@ -238,7 +238,11 @@ void FileRequestHandler::getInfo(const char* filename, UpnpFileInfo* info)
+     UpnpFileInfo_set_LastModified(info, statbuf.st_mtime);
+     UpnpFileInfo_set_IsDirectory(info, S_ISDIR(statbuf.st_mode));
++#if defined(USING_NPUPNP)
++    UpnpFileInfo_set_ContentType(info, mimeType);
++#else
+     UpnpFileInfo_set_ContentType(info, ixmlCloneDOMString(mimeType.c_str()));
++#endif
+     headers->writeHeaders(info);
+diff --git a/src/iohandler/file_io_handler.cc b/src/iohandler/file_io_handler.cc
+index 7e239250..ab5155ec 100644
+--- a/src/iohandler/file_io_handler.cc
++++ b/src/iohandler/file_io_handler.cc
+@@ -32,7 +32,9 @@
+ #include "file_io_handler.h" // API
+ #include <cstdio>
++#ifndef USING_NPUPNP
+ #include <ixml.h>
++#endif
+ #include <utility>
+ #include "cds_objects.h"
+diff --git a/src/iohandler/io_handler.cc b/src/iohandler/io_handler.cc
+index f9789425..75a36130 100644
+--- a/src/iohandler/io_handler.cc
++++ b/src/iohandler/io_handler.cc
+@@ -31,7 +31,9 @@
+ #include "io_handler.h" // API
++#ifndef USING_NPUPNP
+ #include <ixml.h>
++#endif
+ #include <unistd.h>
+ #include "server.h"
+diff --git a/src/iohandler/mem_io_handler.cc b/src/iohandler/mem_io_handler.cc
+index 5574a16d..2916fd12 100644
+--- a/src/iohandler/mem_io_handler.cc
++++ b/src/iohandler/mem_io_handler.cc
+@@ -35,7 +35,9 @@
+ #include <cstdlib>
+ #include <cstring>
+ #include <ctime>
++#ifndef USING_NPUPNP
+ #include <ixml.h>
++#endif
+ #include <sys/stat.h>
+ #include <sys/types.h>
+ #include <unistd.h>
+diff --git a/src/serve_request_handler.cc b/src/serve_request_handler.cc
+index 8eaf46af..b9bd7b25 100644
+--- a/src/serve_request_handler.cc
++++ b/src/serve_request_handler.cc
+@@ -94,7 +94,11 @@ void ServeRequestHandler::getInfo(const char* filename, UpnpFileInfo* info)
+             UpnpFileInfo_set_IsReadable(info, 0);
+         }
++#if defined(USING_NPUPNP)
++        UpnpFileInfo_set_ContentType(info, mimetype);
++#else
+         UpnpFileInfo_set_ContentType(info, ixmlCloneDOMString(mimetype.c_str()));
++#endif
+     } else {
+         throw_std_runtime_error("Not a regular file: " + path);
+     }
+@@ -157,8 +161,11 @@ std::unique_ptr<IOHandler> ServeRequestHandler::open(const char* filename,
+             info->is_readable = 0;
+         }
+-
++#if defined(USING_NPUPNP)
++        info->content_type = mimetype;
++#else
+         info->content_type = ixmlCloneDOMString(mimetype.c_str());
++#endif
+         */
+     } else {
+         throw_std_runtime_error("Not a regular file: " + path);
+diff --git a/src/server.cc b/src/server.cc
+index 913a4913..7cbabc71 100644
+--- a/src/server.cc
++++ b/src/server.cc
+@@ -398,9 +398,17 @@ int Server::handleUpnpClientEvent(Upnp_EventType eventType, const void* event)
+     case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
+     case UPNP_DISCOVERY_SEARCH_RESULT: {
+         auto d_event = reinterpret_cast<const UpnpDiscovery*>(event);
++#if defined(USING_NPUPNP)
++        const char* userAgent = UpnpDiscovery_get_Os_cstr(d_event);
++#else
+         const char* userAgent = UpnpString_get_String(UpnpDiscovery_get_Os(d_event));
++#endif
+         const struct sockaddr_storage* destAddr = UpnpDiscovery_get_DestAddr(d_event);
++#if defined(USING_NPUPNP)
++        const char* location = UpnpDiscovery_get_Location_cstr(d_event);
++#else
+         const char* location = UpnpString_get_String(UpnpDiscovery_get_Location(d_event));
++#endif
+         Clients::addClientByDiscovery(destAddr, userAgent, location);
+         break;
+diff --git a/src/transcoding/transcode_ext_handler.cc b/src/transcoding/transcode_ext_handler.cc
+index 4dad0e3f..412c1370 100644
+--- a/src/transcoding/transcode_ext_handler.cc
++++ b/src/transcoding/transcode_ext_handler.cc
+@@ -37,7 +37,9 @@
+ #include <cstring>
+ #include <fcntl.h>
+ #include <filesystem>
++#ifndef USING_NPUPNP
+ #include <ixml.h>
++#endif
+ #include <sys/stat.h>
+ #include <sys/types.h>
+ #include <unistd.h>
+diff --git a/src/upnp_cds.cc b/src/upnp_cds.cc
+index 6491fa78..a758655c 100644
+--- a/src/upnp_cds.cc
++++ b/src/upnp_cds.cc
+@@ -284,6 +284,7 @@ void ContentDirectoryService::processSubscriptionRequest(const std::unique_ptr<S
+     propset->print(buf, "", 0);
+     std::string xml = buf.str();
++#if !defined(USING_NPUPNP)
+     IXML_Document* event = nullptr;
+     int err = ixmlParseBufferEx(xml.c_str(), &event);
+     if (err != IXML_SUCCESS) {
+@@ -295,6 +296,11 @@ void ContentDirectoryService::processSubscriptionRequest(const std::unique_ptr<S
+         DESC_CDS_SERVICE_ID, event, request->getSubscriptionID().c_str());
+     ixmlDocument_free(event);
++#else
++    UpnpAcceptSubscriptionXML(
++              deviceHandle, config->getOption(CFG_SERVER_UDN).c_str(),
++        DESC_CDS_SERVICE_ID, xml, request->getSubscriptionID().c_str());
++#endif
+     log_debug("end");
+ }
+@@ -313,6 +319,7 @@ void ContentDirectoryService::sendSubscriptionUpdate(const std::string& containe
+     propset->print(buf, "", 0);
+     std::string xml = buf.str();
++#if !defined(USING_NPUPNP)
+     IXML_Document* event = nullptr;
+     int err = ixmlParseBufferEx(xml.c_str(), &event);
+     if (err != IXML_SUCCESS) {
+@@ -323,8 +330,11 @@ void ContentDirectoryService::sendSubscriptionUpdate(const std::string& containe
+     UpnpNotifyExt(deviceHandle,
+         config->getOption(CFG_SERVER_UDN).c_str(),
+         DESC_CDS_SERVICE_ID, event);
+-
+     ixmlDocument_free(event);
++#else
++      UpnpNotifyXML(deviceHandle, config->getOption(CFG_SERVER_UDN).c_str(),
++                                DESC_CDS_SERVICE_ID, xml);
++#endif
+     log_debug("end");
+ }
+diff --git a/src/upnp_cm.cc b/src/upnp_cm.cc
+index aa608480..33f86bd2 100644
+--- a/src/upnp_cm.cc
++++ b/src/upnp_cm.cc
+@@ -127,6 +127,7 @@ void ConnectionManagerService::processSubscriptionRequest(const std::unique_ptr<
+     propset->print(buf, "", 0);
+     std::string xml = buf.str();
++#if !defined(USING_NPUPNP)
+     IXML_Document* event = nullptr;
+     int err = ixmlParseBufferEx(xml.c_str(), &event);
+     if (err != IXML_SUCCESS) {
+@@ -138,6 +139,11 @@ void ConnectionManagerService::processSubscriptionRequest(const std::unique_ptr<
+         DESC_CM_SERVICE_ID, event, request->getSubscriptionID().c_str());
+     ixmlDocument_free(event);
++#else
++    UpnpAcceptSubscriptionXML(
++              deviceHandle, config->getOption(CFG_SERVER_UDN).c_str(),
++              DESC_CM_SERVICE_ID, xml, request->getSubscriptionID().c_str());
++#endif
+ }
+ void ConnectionManagerService::sendSubscriptionUpdate(const std::string& sourceProtocol_CSV)
+@@ -150,6 +156,7 @@ void ConnectionManagerService::sendSubscriptionUpdate(const std::string& sourceP
+     propset->print(buf, "", 0);
+     std::string xml = buf.str();
++#if !defined(USING_NPUPNP)
+     IXML_Document* event = nullptr;
+     int err = ixmlParseBufferEx(xml.c_str(), &event);
+     if (err != IXML_SUCCESS) {
+@@ -162,4 +169,8 @@ void ConnectionManagerService::sendSubscriptionUpdate(const std::string& sourceP
+         DESC_CM_SERVICE_ID, event);
+     ixmlDocument_free(event);
++#else
++    UpnpNotifyXML(deviceHandle, config->getOption(CFG_SERVER_UDN).c_str(),
++                                DESC_CM_SERVICE_ID, xml);
++#endif
+ }
+diff --git a/src/upnp_mrreg.cc b/src/upnp_mrreg.cc
+index 16eefaed..f993f452 100644
+--- a/src/upnp_mrreg.cc
++++ b/src/upnp_mrreg.cc
+@@ -34,7 +34,9 @@
+ #include <utility>
+ #include "config/config_manager.h"
+-#include "ixml.h"
++#ifndef USING_NPUPNP
++#include <ixml.h>
++#endif
+ #include "server.h"
+ #include "storage/storage.h"
+ #include "upnp_xml.h"
+@@ -120,6 +122,7 @@ void MRRegistrarService::processSubscriptionRequest(const std::unique_ptr<Subscr
+     propset->print(buf, "", 0);
+     std::string xml = buf.str();
++#if !defined(USING_NPUPNP)
+     IXML_Document* event = nullptr;
+     int err = ixmlParseBufferEx(xml.c_str(), &event);
+     if (err != IXML_SUCCESS) {
+@@ -131,6 +134,11 @@ void MRRegistrarService::processSubscriptionRequest(const std::unique_ptr<Subscr
+         DESC_MRREG_SERVICE_ID, event, request->getSubscriptionID().c_str());
+     ixmlDocument_free(event);
++#else
++    UpnpAcceptSubscriptionXML(
++              deviceHandle, config->getOption(CFG_SERVER_UDN).c_str(),
++              DESC_MRREG_SERVICE_ID, xml, request->getSubscriptionID().c_str());
++#endif
+ }
+ // TODO: FIXME
+diff --git a/src/url_request_handler.cc b/src/url_request_handler.cc
+index f2a99c94..66af027b 100644
+--- a/src/url_request_handler.cc
++++ b/src/url_request_handler.cc
+@@ -32,7 +32,9 @@
+ #ifdef HAVE_CURL
+ #include "url_request_handler.h" // API
++#ifndef USING_NPUPNP
+ #include <ixml.h>
++#endif
+ #include <utility>
+ #include "config/config_manager.h"
+@@ -138,7 +140,11 @@ void URLRequestHandler::getInfo(const char* filename, UpnpFileInfo* info)
+     //            ixmlCloneDOMString(header.c_str()));
+     //    }
++#if defined(USING_NPUPNP)
++    UpnpFileInfo_set_ContentType(info, mimeType);
++#else
+     UpnpFileInfo_set_ContentType(info, ixmlCloneDOMString(mimeType.c_str()));
++#endif
+     log_debug("web_get_info(): end");
+     /// \todo transcoding for get_info
+diff --git a/src/util/upnp_clients.cc b/src/util/upnp_clients.cc
+index ab02b58d..7bc85d77 100644
+--- a/src/util/upnp_clients.cc
++++ b/src/util/upnp_clients.cc
+@@ -203,6 +203,15 @@ bool Clients::getInfoByType(const std::string& match, ClientMatchType type, cons
+ bool Clients::downloadDescription(const std::string& location, std::unique_ptr<pugi::xml_document>& xml)
+ {
++#if defined(USING_NPUPNP)
++      std::string description, ct;
++      int errCode = UpnpDownloadUrlItem(location, description, ct);
++    if (errCode != UPNP_E_SUCCESS) {
++        log_debug("Error obtaining client description from {} -- error = {}", location, errCode);
++        return false;
++    }
++      const char *cxml = description.c_str();
++#else
+     IXML_Document* descDoc = nullptr;
+     int errCode = UpnpDownloadXmlDoc(location.c_str(), &descDoc);
+     if (errCode != UPNP_E_SUCCESS) {
+@@ -211,12 +220,15 @@ bool Clients::downloadDescription(const std::string& location, std::unique_ptr<p
+     }
+     DOMString cxml = ixmlPrintDocument(descDoc);
++#endif
+     xml = std::make_unique<pugi::xml_document>();
+     auto ret = xml->load_string(cxml);
++#if !defined(USING_NPUPNP)
+     ixmlFreeDOMString(cxml);
+     ixmlDocument_free(descDoc);
++#endif
+     if (ret.status != pugi::xml_parse_status::status_ok) {
+         log_debug("Unable to parse xml client description from {}", location);
+         return false;
+diff --git a/src/util/upnp_headers.cc b/src/util/upnp_headers.cc
+index c05cffe6..19ba88ca 100644
+--- a/src/util/upnp_headers.cc
++++ b/src/util/upnp_headers.cc
+@@ -96,18 +96,29 @@ void Headers::writeHeaders(UpnpFileInfo* fileInfo) const
+     if (headers == nullptr)
+         return;
++#if defined(USING_NPUPNP)
++    for (auto iter : *headers) {
++              fileInfo->response_headers.push_back(iter);
++      }
++#else
+     auto head = const_cast<UpnpListHead*>(UpnpFileInfo_get_ExtraHeadersList(fileInfo));
+     for (auto iter : *headers) {
+         UpnpExtraHeaders* h = UpnpExtraHeaders_new();
+         UpnpExtraHeaders_set_resp(h, formatHeader(iter, false).c_str());
+         UpnpListInsert(head, UpnpListEnd(head), const_cast<UpnpListHead*>(UpnpExtraHeaders_get_node(h)));
+     }
++#endif
+ }
+ std::unique_ptr<std::map<std::string, std::string>> Headers::readHeaders(UpnpFileInfo* fileInfo)
+ {
+     auto ret = std::make_unique<std::map<std::string, std::string>>();
++#if defined(USING_NPUPNP)
++      for (const auto& entry : fileInfo->request_headers) {
++        ret->insert(entry);
++      }
++#else
+     auto head = const_cast<UpnpListHead*>(UpnpFileInfo_get_ExtraHeadersList(fileInfo));
+     UpnpListIter pos;
+     for (pos = UpnpListBegin(head); pos != UpnpListEnd(head); pos = UpnpListNext(head, pos)) {
+@@ -116,6 +127,7 @@ std::unique_ptr<std::map<std::string, std::string>> Headers::readHeaders(UpnpFil
+         auto add = parseHeader(header);
+         ret->insert(add);
+     }
+-
++#endif
++      
+     return ret;
+ }
+diff --git a/src/util/upnp_headers.h b/src/util/upnp_headers.h
+index 9677d6e4..dd839236 100644
+--- a/src/util/upnp_headers.h
++++ b/src/util/upnp_headers.h
+@@ -26,7 +26,9 @@
+ #ifndef GERBERA_HEADERS_H
+ #define GERBERA_HEADERS_H
++#if !defined(USING_NPUPNP)
+ #include <ExtraHeaders.h>
++#endif
+ #include <map>
+ #include <memory>
+ #include <upnp.h>
+diff --git a/src/web/web_request_handler.cc b/src/web/web_request_handler.cc
+index 71fc9fd5..2ca6601b 100644
+--- a/src/web/web_request_handler.cc
++++ b/src/web/web_request_handler.cc
+@@ -120,7 +120,11 @@ void WebRequestHandler::getInfo(const char* filename, UpnpFileInfo* info)
+     contentType = mimetype + "; charset=" + DEFAULT_INTERNAL_CHARSET;
++#if defined(USING_NPUPNP)
++    UpnpFileInfo_set_ContentType(info, contentType);
++#else
+     UpnpFileInfo_set_ContentType(info, ixmlCloneDOMString(contentType.c_str()));
++#endif
+     Headers headers;
+     headers.addHeader(std::string { "Cache-Control" }, std::string { "no-cache, must-revalidate" });
+     headers.writeHeaders(info);