45template <
typename ClientType>
54 int startingIndex,
int requestedCount,
const char* sortCriteria,
55 int& numberReturned,
int& totalMatches,
int& updateID,
void* reference);
142 auto writer = [](Print& out,
void* ref) ->
size_t {
145 result += out.print(
"<SourceProtocolInfo val=\"");
146 result += out.print(
StrView(self->getSourceProtocols()).c_str());
147 result += out.println(
"\"/>");
148 result += out.print(
"<SinkProtocolInfo val=\"");
149 result += out.print(
StrView(self->getSinkProtocols()).c_str());
150 result += out.println(
"\"/>");
197 for (
size_t i = 0; i <
rules.size(); ++i) {
199 rules[i].handler = handler;
203 rules.push_back({suffix, handler});
241 const char*
st =
"urn:schemas-upnp-org:device:MediaServer:1";
242 const char*
usn =
"uuid:media-server-0000-0000-0000-000000000001";
244 "dc:title,dc:creator,upnp:class,upnp:genre,"
245 "upnp:album,upnp:artist,upnp:albumArtURI";
247 "dc:title,dc:date,upnp:class,upnp:album,upnp:episodeNumber,upnp:"
248 "originalTrackNumber";
264 std::function<
size_t(Print&,
void*)> changeWriter) {
272 auto writer = [](Print& out,
void* ref) ->
size_t {
275 result += out.print(
"<SystemUpdateID val=\"");
276 result += out.print(self->g_stream_updateID);
277 result += out.println(
"\"/>");
288 auto writer = [](Print& out,
void* ref) ->
size_t {
291 result += out.print(
"<SourceProtocolInfo val=\"");
292 result += out.print(
StrView(self->getSourceProtocols()).c_str());
293 result += out.println(
"\"/>");
294 result += out.print(
"<SinkProtocolInfo val=\"");
295 result += out.print(
StrView(self->getSinkProtocols()).c_str());
296 result += out.println(
"\"/>");
297 result += out.print(
"<CurrentConnectionIDs val=\"");
298 result += out.print(
StrView(self->connectionID).
c_str());
299 result += out.println(
"\"/>");
318 assert(self !=
nullptr);
323 [](Print& out,
void* ref) ->
size_t {
344 [](Print& out,
void* ref) ->
size_t {
362 const char* requestPath,
364 bool is_subscribe =
false;
368 assert(self !=
nullptr);
369 StrView request_path_str(requestPath);
370 if (request_path_str.
contains(
"/CD/"))
372 else if (request_path_str.
contains(
"/CM/"))
376 "eventSubscriptionHandler: Unknown request path: %s",
384 cd.
setup(
"urn:schemas-upnp-org:service:ContentDirectory:1",
385 "urn:upnp-org:serviceId:ContentDirectory",
"/CD/service.xml",
399 cm.
setup(
"urn:schemas-upnp-org:service:ConnectionManager:1",
400 "urn:upnp-org:serviceId:ConnectionManager",
"/CM/service.xml",
416 if (action_str.isEmpty()) {
421 for (
const auto& rule :
rules) {
422 if (action_str.endsWith(rule.suffix)) {
423 return rule.handler(client,
this, action, server);
435 int numberReturned = 0;
436 int totalMatches = 0;
451 numberReturned, totalMatches, updateID,
reference_);
462 [](Print& out,
void* ref) ->
size_t {
464 return self->streamActionItems(out,
"BrowseResponse",
465 self->g_stream_startingIndex);
474 int numberReturned = 0;
475 int totalMatches = 0;
490 numberReturned, totalMatches, updateID,
reference_);
501 [](Print& out,
void* ref) ->
size_t {
503 return self->streamActionItems(out,
"SearchResponse",
504 self->g_stream_startingIndex);
515 [](Print& out,
void* ref) ->
size_t {
518 written += self->soapEnvelopeStart(out);
519 written += self->actionResponseStart(
520 out,
"GetSearchCapabilitiesResponse",
521 "urn:schemas-upnp-org:service:ContentDirectory:1");
522 written += out.print(
"<SearchCaps>");
523 written += out.print(
StrView(self->g_search_capabiities).
c_str());
524 written += out.print(
"</SearchCaps>\r\n");
526 self->actionResponseEnd(out,
"GetSearchCapabilitiesResponse");
527 written += self->soapEnvelopeEnd(out);
532 "processActionGetSearchCapabilities (callback)");
541 [](Print& out,
void* ref) ->
size_t {
544 written += self->soapEnvelopeStart(out);
545 written += self->actionResponseStart(
546 out,
"GetSortCapabilitiesResponse",
547 "urn:schemas-upnp-org:service:ContentDirectory:1");
548 written += out.print(
"<SortCaps>");
549 written += out.print(
StrView(self->g_sort_capabilities).
c_str());
550 written += out.print(
"</SortCaps>\r\n");
552 self->actionResponseEnd(out,
"GetSortCapabilitiesResponse");
553 written += self->soapEnvelopeEnd(out);
558 "processActionGetSortCapabilities (callback)");
567 [](Print& out,
void* ref) ->
size_t {
570 written += self->soapEnvelopeStart(out);
571 written += self->actionResponseStart(
572 out,
"GetSystemUpdateIDResponse",
573 "urn:schemas-upnp-org:service:ContentDirectory:1");
575 written +=
static_cast<size_t>(
576 pr.printf(
"<Id>%d</Id>\r\n", self->g_stream_updateID));
577 written += self->actionResponseEnd(out,
"GetSystemUpdateIDResponse");
578 written += self->soapEnvelopeEnd(out);
583 "processActionGetSystemUpdateID (callback): %d",
594 [](Print& out,
void* ref) ->
size_t {
609 [](Print& out,
void* ref) ->
size_t {
628 [](Print& out,
void* ref) ->
size_t {
631 out, self->sourceProto, self->connectionID,
"Output");
640 if (fv.
equals(
"BrowseDirectChildren"))
649 written += out.print(
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n");
650 written += out.print(
651 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" ");
652 written += out.print(
653 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n");
654 written += out.print(
"<s:Body>\r\n");
660 written += out.print(
"</s:Body>\r\n");
661 written += out.print(
"</s:Envelope>\r\n");
666 const char* serviceNS) {
669 return static_cast<size_t>(
670 pr.printf(
"<u:%s xmlns:u=\"%s\">\r\n", responseName, serviceNS));
675 return static_cast<size_t>(pr.printf(
"</u:%s>\r\n", responseName));
684 out, responseName,
"urn:schemas-upnp-org:service:ContentDirectory:1");
687 written += out.println(
"<Result>");
690 written += out.print(
"</Result>\r\n");
694 written +=
static_cast<size_t>(pr.printf(
696 written +=
static_cast<size_t>(pr.printf(
698 written +=
static_cast<size_t>(
707 size_t streamDIDL(Print& out,
int numberReturned,
int startingIndex) {
710 written += out.print(
711 "<DIDL-Lite xmlns:dc=\"http://purl.org/dc/elements/1.1/\" "
712 "xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\" "
713 "xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\">\r\n");
717 written += out.print(
"</DIDL-Lite>\r\n");
732 for (
int i = 0; i < numberReturned; ++i) {
733 int idx = startingIndex + i;
759 const char* nodeName =
762 written +=
static_cast<size_t>(
763 pr.printf(
"<%s id=\"%s\" parentID=\"%s\" restricted=\"%d\">", nodeName,
767 written += out.print(
"<dc:title>");
769 written += out.print(
"</dc:title>\r\n");
770 if (mediaItemClassStr !=
nullptr) {
771 written +=
static_cast<size_t>(
772 pr.printf(
"<upnp:class>%s</upnp:class>\r\n", mediaItemClassStr));
778 written += out.print(
"<upnp:albumArtURI>");
780 written += out.print(
"</upnp:albumArtURI>\r\n");
786 written +=
static_cast<size_t>(
787 pr.printf(
"<res protocolInfo=\"http-get:*:%s:*\">", item.
mimeType));
789 written += out.print(
"<res>");
793 written += out.print(
"</res>\r\n");
796 written +=
static_cast<size_t>(pr.printf(
"</%s>\r\n", nodeName));
805 if (url.startsWith(
"http://")) {
810 if (!
StrView(path).startsWith(
"/")) {
821 return "object.item.audioItem.musicTrack";
823 return "object.item.audioItem.audioBroadcast";
825 return "object.item.videoItem.movie";
827 return "object.item.imageItem.photo";
829 return "object.container";
837 const char* requestPath,
865 if (!server)
return nullptr;
867 if (!dev)
return nullptr;
893 return self->processActionBrowse(action, server, client);
897 return self->processActionSearch(action, server, client);
900 {
"GetSearchCapabilities",
902 return self->processActionGetSearchCapabilities(action, server, client);
905 {
"GetSortCapabilities",
907 return self->processActionGetSortCapabilities(action, server, client);
910 {
"GetSystemUpdateID",
912 return self->processActionGetSystemUpdateID(action, server, client);
918 return self->processActionGetProtocolInfo(action, server, client);
921 {
"GetCurrentConnectionIDs",
923 return self->processActionGetCurrentConnectionIDs(action, server, client);
926 {
"GetCurrentConnectionInfo",
928 return self->processActionGetCurrentConnectionInfo(action, server, client);
Represents a request to invoke a remote DLNA service action.
Definition: Action.h:104
Str & getActionStr()
Definition: Action.h:159
const char * getArgumentValue(const char *name)
Definition: Action.h:128
int getArgumentIntValue(const char *name)
Definition: Action.h:146
const char * getAction()
Definition: Action.h:157
Abstract DLNA Descriptor Generation.
Definition: DLNADescr.h:9
virtual size_t printDescr(Print &out)=0
Device Attributes and generation of XML using urn:schemas-upnp-org:device-1-0. We could just return a...
Definition: DLNADeviceInfo.h:28
void setDeviceType(const char *st)
Definition: DLNADeviceInfo.h:82
void addService(DLNAServiceInfo s)
Adds a service definition.
Definition: DLNADeviceInfo.h:180
void setManufacturerURL(const char *url)
Definition: DLNADeviceInfo.h:162
Str url_str
Definition: DLNADeviceInfo.h:303
void setModelName(const char *name)
Definition: DLNADeviceInfo.h:166
void setSerialNumber(const char *sn)
Definition: DLNADeviceInfo.h:170
const char * getBaseURL()
Provides the base url.
Definition: DLNADeviceInfo.h:120
void setManufacturer(const char *man)
Definition: DLNADeviceInfo.h:160
void setUDN(const char *id)
Define the udn uuid.
Definition: DLNADeviceInfo.h:87
void setFriendlyName(const char *name)
Definition: DLNADeviceInfo.h:158
void setModelNumber(const char *number)
Definition: DLNADeviceInfo.h:168
void setBaseURL(const char *url)
Defines the base url.
Definition: DLNADeviceInfo.h:93
Setup of a Basic DLNA Device service. The device registers itself to the network and answers to the D...
Definition: DLNADevice.h:46
void end() override
Stops the processing and releases the resources.
Definition: DLNADevice.h:118
void setReference(void *ref) override
Sets a reference pointer that can be used to associate application.
Definition: DLNADevice.h:452
static void parseActionRequest(IHttpServer *server, IClientHandler &client, const char *requestPath, HttpRequestHandlerLine *hl, ActionRequest &action)
Parses the SOAP content of a DLNA action request.
Definition: DLNADevice.h:274
bool begin(DLNADeviceInfo &device, IUDPService &udp, IHttpServer &server) override
start the
Definition: DLNADevice.h:53
static size_t replyGetCurrentConnectionInfo(Print &out, const char *protocolInfo, const char *connectionID, const char *direction)
Definition: DLNADevice.h:397
bool loop(int loopAction=RUN_ALL) override
Definition: DLNADevice.h:141
static size_t replyGetProtocolInfo(Print &out, const char *source="", const char *sink="")
Definition: DLNADevice.h:364
void logStatus()
Definition: DLNADevice.h:457
static bool handleSubscription(IHttpServer *server, IClientHandler *client, const char *requestPath, HttpRequestHandlerLine *hl, bool &is_subscribe)
Static handler for SUBSCRIBE/UNSUBSCRIBE requests on service event URLs.
Definition: DLNADevice.h:427
static size_t replyGetCurrentConnectionIDs(Print &out, const char *ids)
Definition: DLNADevice.h:381
void setSubscriptionsActive(bool flag) override
Enable or disable subscription notifications: call before begin.
Definition: DLNADevice.h:260
bool isSubscriptionsActive() const override
Check if subscription notifications are active.
Definition: DLNADevice.h:269
void addChange(const char *serviceAbbrev, std::function< size_t(Print &, void *)> changeWriter, void *ref) override
Record a state variable change for subscription notifications.
Definition: DLNADevice.h:231
ContentDirectory SCPD descriptor for MediaServer.
Definition: DLNAMediaServerDescr.h:160
size_t printDescr(Print &out) override
Emit ContentDirectory SCPD XML.
Definition: DLNAMediaServerDescr.h:170
Attributes needed for the DLNA Service Definition.
Definition: DLNAServiceInfo.h:18
void setup(const char *type, const char *id, const char *scp, http_callback cbScp, const char *control, http_callback cbControl, const char *event, http_callback cbEvent)
Setup all relevant values.
Definition: DLNAServiceInfo.h:23
const char * subscription_namespace_abbrev
Definition: DLNAServiceInfo.h:53
Used to register and process callbacks.
Definition: HttpRequestHandlerLine.h:12
Definition: IHttpServer.h:19
virtual void replyNotFound()=0
virtual void reply(const char *contentType, Stream &inputStream, int size, int status=200, const char *msg=SUCCESS)=0
Abstract interface for DLNA device functionality.
Definition: IDevice.h:30
Abstract interface for HTTP server functionality.
Definition: IHttpServer.h:50
virtual void * getReference()=0
Abstract Interface for UDP API.
Definition: IUDPService.h:33
Printf support with output to Print. This class does not do any heap allocations!
Definition: Printf.h:12
A simple wrapper to provide string functions on char*. If the underlying char* is a const we do not a...
Definition: StrView.h:18
virtual bool isEmpty()
checks if the string is empty
Definition: StrView.h:383
virtual const char * c_str()
provides the string value as const char*
Definition: StrView.h:376
virtual bool equals(const char *str)
checks if the string equals indicated parameter string
Definition: StrView.h:177
virtual bool contains(const char *str)
checks if the string contains a substring
Definition: StrView.h:284
Heap-backed string utility used throughout tiny_dlna.
Definition: Str.h:27
const char * c_str() const
C-string pointer to internal buffer.
Definition: Str.h:88
Lightweight wrapper around std::vector with Arduino-friendly helpers and a pluggable allocator.
Definition: Vector.h:39
#define DLNA_PROTOCOL_AUDIO
All possible audio protocols.
Definition: dlna_config.h:154
Definition: Allocator.h:13
@ RUN_ALL
Definition: IDevice.h:18
ContentQueryType
Type of content query for DLNA browsing/searching.
Definition: DLNACommon.h:36
MediaItemClass
Definition: MediaItem.h:14
void(* http_callback)(IClientHandler &client, IHttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl)
Definition: DLNAServiceInfo.h:11
Print wrapper that escapes & < > " ' while forwarding to an underlying Print. Returns the expanded ou...
Definition: EscapingPrint.h:9