Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
d7475767
Commit
d7475767
authored
May 19, 2021
by
Max Kellermann
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'npu' of
git://github.com/neheb/MPD
parents
d9578f64
e9606268
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
167 additions
and
13 deletions
+167
-13
NEWS
NEWS
+1
-0
meson_options.txt
meson_options.txt
+4
-1
ContentDirectoryService.cxx
src/db/plugins/upnp/ContentDirectoryService.cxx
+93
-1
Action.hxx
src/lib/upnp/Action.hxx
+2
-0
ContentDirectoryService.cxx
src/lib/upnp/ContentDirectoryService.cxx
+30
-4
Init.cxx
src/lib/upnp/Init.cxx
+5
-1
UniqueIxml.hxx
src/lib/upnp/UniqueIxml.hxx
+4
-2
ixmlwrap.cxx
src/lib/upnp/ixmlwrap.cxx
+6
-2
ixmlwrap.hxx
src/lib/upnp/ixmlwrap.hxx
+3
-1
meson.build
src/lib/upnp/meson.build
+19
-1
No files found.
NEWS
View file @
d7475767
...
...
@@ -6,6 +6,7 @@ ver 0.23 (not yet released)
- proxy: require MPD 0.20 or later
- proxy: require libmpdclient 2.11 or later
- proxy: split search into chunks to avoid exceeding the output buffer
- upnp: support libnpupnp instead of libupnp
* output
- pipewire: new plugin
- snapcast: new plugin
...
...
meson_options.txt
View file @
d7475767
...
...
@@ -62,7 +62,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)')
#
...
...
src/db/plugins/upnp/ContentDirectoryService.cxx
View file @
d7475767
...
...
@@ -18,7 +18,10 @@
*/
#include "lib/upnp/ContentDirectoryService.hxx"
#include "lib/upnp/ixmlwrap.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"
...
...
@@ -27,6 +30,9 @@
#include "util/ScopeExit.hxx"
#include "util/StringFormat.hxx"
#include <algorithm>
#ifdef USING_PUPNP
static
void
ReadResultTag
(
UPnPDirContent
&
dirbuf
,
IXML_Document
*
response
)
{
...
...
@@ -36,6 +42,7 @@ ReadResultTag(UPnPDirContent &dirbuf, IXML_Document *response)
dirbuf
.
Parse
(
p
);
}
#endif
inline
void
ContentDirectoryService
::
readDirSlice
(
UpnpClient_Handle
hdl
,
...
...
@@ -44,6 +51,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
(),
...
...
@@ -79,6 +87,35 @@ 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
...
...
@@ -107,6 +144,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
,
...
...
@@ -144,6 +182,36 @@ 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
;
...
...
@@ -153,6 +221,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
,
...
...
@@ -176,4 +245,27 @@ 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
();
}
}
UPnPDirContent
dirbuf
;
dirbuf
.
Parse
(
p
);
return
dirbuf
;
#endif
}
src/lib/upnp/Action.hxx
View file @
d7475767
...
...
@@ -38,6 +38,7 @@ CountNameValuePairs([[maybe_unused]] const char *name, [[maybe_unused]] const ch
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
src/lib/upnp/ContentDirectoryService.cxx
View file @
d7475767
...
...
@@ -17,13 +17,21 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "ContentDirectoryService.hxx"
#include "UniqueIxml.hxx"
#include "Device.hxx"
#include "ixmlwrap.hxx"
#include "util/UriRelative.hxx"
#include "util/RuntimeError.hxx"
#include "UniqueIxml.hxx"
#ifdef USING_PUPNP
# include "ixmlwrap.hxx"
#endif
#include "Action.hxx"
#include "util/IterableSplitString.hxx"
#include "util/RuntimeError.hxx"
#include "util/UriRelative.hxx"
#include "util/UriUtil.hxx"
#include <algorithm>
#include <upnptools.h>
...
...
@@ -50,6 +58,7 @@ ContentDirectoryService::~ContentDirectoryService() noexcept = default;
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
));
...
...
@@ -68,6 +77,23 @@ 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
();
}
}
#endif
if
(
s
==
nullptr
||
*
s
==
0
)
return
{};
...
...
src/lib/upnp/Init.cxx
View file @
d7475767
...
...
@@ -23,7 +23,9 @@
#include "util/RuntimeError.hxx"
#include <upnptools.h>
#include <ixml.h>
#ifdef USING_PUPNP
# include <ixml.h>
#endif
#include <cassert>
...
...
@@ -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
...
...
src/lib/upnp/UniqueIxml.hxx
View file @
d7475767
...
...
@@ -20,9 +20,10 @@
#ifndef MPD_UPNP_UNIQUE_XML_HXX
#define MPD_UPNP_UNIQUE_XML_HXX
#include <ixml.h>
#ifdef USING_PUPNP
# include <ixml.h>
#include <memory>
#
include <memory>
struct
UpnpIxmlDeleter
{
void
operator
()(
IXML_Document
*
doc
)
noexcept
{
...
...
@@ -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
src/lib/upnp/ixmlwrap.cxx
View file @
d7475767
...
...
@@ -15,8 +15,11 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "ixmlwrap.hxx"
#include "UniqueIxml.hxx"
#include "config.h"
#ifdef USING_PUPNP
# include "ixmlwrap.hxx"
# include "UniqueIxml.hxx"
namespace
ixmlwrap
{
...
...
@@ -39,3 +42,4 @@ getFirstElementValue(IXML_Document *doc, const char *name) noexcept
}
}
// namespace ixmlwrap
#endif
src/lib/upnp/ixmlwrap.hxx
View file @
d7475767
...
...
@@ -17,7 +17,8 @@
#ifndef _IXMLWRAP_H_INCLUDED_
#define _IXMLWRAP_H_INCLUDED_
#include <ixml.h>
#ifdef USING_PUPNP
# include <ixml.h>
namespace
ixmlwrap
{
/**
...
...
@@ -30,4 +31,5 @@ namespace ixmlwrap {
}
#endif
/* USING_PUPNP */
#endif
/* _IXMLWRAP_H_INCLUDED_ */
src/lib/upnp/meson.build
View file @
d7475767
upnp_dep = dependency('libupnp', version: '>= 1.8', 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()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment