Arduino DLNA Server
Loading...
Searching...
No Matches
DLNAMediaRenderer.h
Go to the documentation of this file.
1#pragma once
2#include <cctype>
3#include <cstring>
4
6#include "basic/Str.h"
10
11namespace tiny_dlna {
32
62 public:
63 // event handler: (event, reference to MediaRenderer)
64 typedef void (*MediaEventHandler)(MediaEvent event,
65 DLNAMediaRenderer& renderer);
66
75 // Constructor
76 DlnaLogger.log(DlnaLogLevel::Info, "MediaRenderer::MediaRenderer");
79 setFriendlyName("ArduinoMediaRenderer");
80 setManufacturer("TinyDLNA");
81 setModelName("TinyDLNA");
82 setModelNumber("1.0");
83 setBaseURL("http://localhost:44757");
84 setupRules();
85 }
86
94 setHttpServer(server);
95 setUdpService(udp);
96 }
97
98 // Start the underlying DLNA device using the stored server/udp
99 bool begin() { return dlna_device.begin(*this, *p_udp_member, *p_server); }
100
102 void end() {
103 if (is_active) stop();
105 }
106
108 bool loop() { return dlna_device.loop(); }
109
111 void setHttpServer(HttpServer& server) {
112 p_server = &server;
113 // prepare handler context and register each service via helpers
114 ref_ctx[0] = this;
115 setupServicesImpl(&server);
116 }
117
120
122 bool isActive() { return is_active; }
123
125 void setActive(bool active) {
126 DlnaLogger.log(DlnaLogLevel::Info, "Set active: %s",
127 active ? "true" : "false");
128 is_active = active;
129 if (active) {
130 start_time = millis();
131 } else {
132 // accumulate time
133 time_sum += millis() - start_time;
134 start_time = 0;
135 }
136 // reflect state in transport_state so deferred writer can read it
137 transport_state = active ? "PLAYING" : "PAUSED_PLAYBACK";
138 (void)transport_state; // value used by writer via ref
139 {
140 auto writer = [](Print& out, void* ref) -> size_t {
141 auto self = (DLNAMediaRenderer*)ref;
142 size_t written = 0;
143 written += out.print("<TransportState val=\"");
144 written += out.print(self->transport_state.c_str());
145 written += out.print("\"/>");
146 return written;
147 };
148 addChange("AVT", writer);
149 }
150 }
151
153 const char* getMime() {
154 // Prefer explicit MIME from DIDL if available
155 if (!current_mime.isEmpty()) return current_mime.c_str();
156 return nullptr;
157 }
158
161
163 uint8_t getVolume() { return current_volume; }
164
166 void setVolume(uint8_t vol) {
167 current_volume = vol;
168 (void)current_volume; // value used by writer via ref
169 {
170 auto writer = [](Print& out, void* ref) -> size_t {
171 auto self = (DLNAMediaRenderer*)ref;
172 size_t written = 0;
173 written += out.print("<Volume val=\"");
174 written += out.print(self->current_volume);
175 written += out.print("\"/>");
176 return written;
177 };
178 addChange("RCS", writer);
179 }
181 }
182
184 bool isMuted() { return is_muted; }
185
187 void setMuted(bool m) {
188 is_muted = m;
189 (void)is_muted; // value used by writer via ref
190 {
191 auto writer = [](Print& out, void* ref) -> size_t {
192 auto self = (DLNAMediaRenderer*)ref;
193 size_t written = 0;
194 written += out.print("<Mute val=\"");
195 written += out.print(self->is_muted ? 1 : 0);
196 written += out.print("\"/>");
197 return written;
198 };
199 addChange("RCS", writer);
200 }
202 }
203
204 // Access current URI
205 const char* getCurrentUri() { return current_uri.c_str(); }
206
208 const char* getTransportState() { return transport_state.c_str(); }
209
212
214 bool play() {
215 setActive(true);
216 return true;
217 }
218
220 bool play(const char* urlStr) {
221 if (urlStr == nullptr) return false;
222 DlnaLogger.log(DlnaLogLevel::Info, "play URL: %s", urlStr);
223 // store URI
224 current_uri.set(urlStr);
225 // notify handler about the new URI and play
226 if (event_cb) {
229 }
230 is_active = true;
231 start_time = millis();
232 time_sum = 0;
233
234 // ensure transport_state reflects playing for subscribers
235 transport_state = "PLAYING";
236 (void)current_uri; // writer will fetch it from ref
237 {
238 auto writer = [](Print& out, void* ref) -> size_t {
239 auto self = (DLNAMediaRenderer*)ref;
240 size_t written = 0;
241 written += out.print("<CurrentTrackURI val=\"");
242 written += out.print(self->current_uri.c_str());
243 written += out.print("\"/>\n");
244 written += out.print("<TransportState val=\"");
245 written += out.print(self->transport_state.c_str());
246 written += out.print("\"/>");
247 return written;
248 };
249 addChange("AVT", writer);
250 }
251
252 return true;
253 }
254
256 bool setPlaybackURL(const char* urlStr) {
257 if (urlStr == nullptr) return false;
258 DlnaLogger.log(DlnaLogLevel::Info, "setPlaybackURL URL: %s", urlStr);
259 // store URI
260 current_uri = Str(urlStr);
261 // notify handler about the new URI and play
262 if (event_cb) {
264 }
265
266 (void)current_uri; // writer will fetch it from ref
267 {
268 auto writer = [](Print& out, void* ref) -> size_t {
269 auto self = (DLNAMediaRenderer*)ref;
270 size_t written = 0;
271 written += out.print("<CurrentTrackURI val=\"");
272 written += out.print(self->current_uri.c_str());
273 written += out.print("\"/>\n");
274 return written;
275 };
276 addChange("AVT", writer);
277 }
278
279 return true;
280 }
281
283 bool stop() {
284 DlnaLogger.log(DlnaLogLevel::Info, "Stop playback");
285 is_active = false;
286 start_time = 0;
287 time_sum = 0;
288 // notify handler about the stop
290 // reflect stopped state
291 transport_state = "STOPPED";
292 auto writer = [](Print& out, void* ref) -> size_t {
293 auto self = (DLNAMediaRenderer*)ref;
294 size_t written = 0;
295 written += out.print("<TransportState val=\"");
296 written += out.print(self->getTransportState());
297 written += out.print("\"/>");
298 return written;
299 };
300 addChange("AVT", writer);
301 return true;
302 }
303
313 DlnaLogger.log(DlnaLogLevel::Info, "Playback completed");
314 transport_state = "STOPPED";
315 is_active = false;
316 start_time = 0;
317 time_sum = 0;
318 // notify application handler about the stop
320 auto writer = [](Print& out, void* ref) -> size_t {
321 auto self = (DLNAMediaRenderer*)ref;
322 size_t written = 0;
323 written += out.print("<TransportState val=\"");
324 written += out.print(self->transport_state.c_str());
325 written += out.print("\"/>");
326 written += out.print("<CurrentPlayMode val=\"NORMAL\"/>");
327 written += out.print("<CurrentTrackURI val=\"\"/>");
328 written += out.print("<RelativeTimePosition val=\"00:00:00\"/>");
329 written += out.print("<CurrentTransportActions val=\"Play\"/>");
330 return written;
331 };
332 addChange("AVT", writer);
333 }
334
337 unsigned long posMs = (millis() - start_time) + time_sum;
338 return static_cast<size_t>(posMs / 1000);
339 }
340
343 auto writer = [](Print& out, void* ref) -> size_t {
344 auto self = (DLNAMediaRenderer*)ref;
345 size_t written = 0;
346 // format hh:mm:ss by printing parts
347 int h = static_cast<int>(self->getRelativeTimePositionSec() / 3600);
348 int m =
349 static_cast<int>((self->getRelativeTimePositionSec() % 3600) / 60);
350 int s = static_cast<int>(self->getRelativeTimePositionSec() % 60);
351 written += out.print("<RelativeTimePosition val=\"");
352 // print two-digit hour
353 if (h < 10) written += out.print('0');
354 written += out.print(h);
355 written += out.print(':');
356 if (m < 10) written += out.print('0');
357 written += out.print(m);
358 written += out.print(':');
359 if (s < 10) written += out.print('0');
360 written += out.print(s);
361 written += out.print("\"/>");
362 return written;
363 };
364 addChange("AVT", writer);
365 }
366
369 if (is_active) {
370 return "Pause,Stop";
371 } else {
372 return "Play,Stop";
373 }
374 }
376 void setCustomActionRule(const char* suffix,
377 bool (*handler)(DLNAMediaRenderer*, ActionRequest&,
378 HttpServer&)) {
379 for (size_t i = 0; i < rules.size(); ++i) {
380 if (StrView(rules[i].suffix).equals(suffix)) {
381 rules[i].handler = handler;
382 return;
383 }
384 }
385 rules.push_back({suffix, handler});
386 }
387
388 protected:
392 uint8_t current_volume = 50;
393 bool is_muted = false;
394 unsigned long start_time = 0;
395 unsigned long time_sum = 0;
396 // Current transport state string (e.g. "STOPPED", "PLAYING",
397 // "PAUSED_PLAYBACK")
398 tiny_dlna::Str transport_state = "NO_MEDIA_PRESENT";
399 const char* st = "urn:schemas-upnp-org:device:MediaRenderer:1";
400 const char* usn = "uuid:09349455-2941-4cf7-9847-1dd5ab210e97";
401
402 // internal DLNA device instance owned by this MediaRenderer
406 // reusable context pointer array for HttpServer handlers (contains `this`)
407 void* ref_ctx[1] = {nullptr};
409
411 void addChange(const char* serviceAbbrev,
412 std::function<size_t(Print&, void*)> changeWriter) {
413 dlna_device.addChange(serviceAbbrev, changeWriter, this);
414 }
415
418 void publishAVT() {
419 // Transport state will be built by the writer from the instance (ref)
420 {
421 auto writer = [](Print& out, void* ref) -> size_t {
422 auto self = (DLNAMediaRenderer*)ref;
423 StrPrint tmp;
424 tmp.printf("<TransportState val=\"%s\"/>",
425 self->transport_state.c_str());
426 if (!self->current_uri.isEmpty()) {
427 tmp.printf("<CurrentTrackURI val=\"%s\"/>",
428 self->current_uri.c_str());
429 }
430 tmp.printf(
431 "<RelativeTimePosition val=\"%02d:%02d:%02d\"/>",
432 static_cast<int>(self->getRelativeTimePositionSec() / 3600),
433 static_cast<int>((self->getRelativeTimePositionSec() % 3600) / 60),
434 static_cast<int>(self->getRelativeTimePositionSec() % 60));
435 tmp.printf("<CurrentTransportActions val=\"%s\"/>",
436 self->getCurrentTransportActions());
437 return out.print(tmp.c_str());
438 };
439 addChange("AVT", writer);
440 }
441 }
442
444 void publishRCS() {
445 auto writer = [](Print& out, void* ref) -> size_t {
446 auto self = (DLNAMediaRenderer*)ref;
447 StrPrint tmp;
448 tmp.printf("<Volume val=\"%d\"/>", self->current_volume);
449 tmp.printf("<Mute val=\"%d\"/>", self->is_muted ? 1 : 0);
450 return out.print(tmp.c_str());
451 };
452 addChange("RCS", writer);
453 }
454
456 void publishCMS() {
457 // Minimal information: list of current connection IDs. Use "0" as default
458 // when no active connection is present.
459 {
460 auto writer = [](Print& out, void* ref) -> size_t {
461 (void)ref;
462 return out.print("<CurrentConnectionIDs>0</CurrentConnectionIDs>");
463 };
464 addChange("CMS", writer);
465 }
466 }
467
469 void setMime(const char* mime) {
470 if (mime) {
471 current_mime = mime;
473 }
474 }
475
478 void setMimeFromDIDL(const char* didl) {
479 if (!didl) return;
480 // Convenience helper: extract protocolInfo attribute from a tag and
481 // return the contentFormat (3rd token) portion, e.g. from
482 // protocolInfo="http-get:*:audio/mpeg:*" -> "audio/mpeg".
483 char mimeBuf[64] = {0};
485 didl, "<res", "protocolInfo=", 3, mimeBuf, sizeof(mimeBuf))) {
486 setMime(mimeBuf);
487 }
488 }
489
490 // Static descriptor callbacks: print the SCPD XML for each service
491 static void transportDescrCB(HttpServer* server, const char* requestPath,
493 server->reply("text/xml", [](Print& out) {
495 d.printDescr(out);
496 });
497 }
498
499 static void connmgrDescrCB(HttpServer* server, const char* requestPath,
501 server->reply("text/xml", [](Print& out) {
503 d.printDescr(out);
504 });
505 }
506
507 static void controlDescrCB(HttpServer* server, const char* requestPath,
509 server->reply("text/xml", [](Print& out) {
511 d.printDescr(out);
512 });
513 }
514
515 // Generic control callback: parse SOAP action and dispatch to instance
516 static void controlCB(HttpServer* server, const char* requestPath,
518 ActionRequest action;
519 DLNADevice::parseActionRequest(server, requestPath, hl, action);
520
521 DLNAMediaRenderer* mr = nullptr;
522 if (hl && hl->context[0]) mr = (DLNAMediaRenderer*)hl->context[0];
523
524 if (mr) {
525 if (mr->processAction(action, *server)) return;
526 }
527
528 server->replyNotFound();
529 }
530
533 const char* requestPath,
535 DLNADevice::eventSubscriptionHandler(server, requestPath, hl);
537 if (device) {
538 StrView request_path_str(requestPath);
539 if (request_path_str.contains("/AVT/"))
540 device->publishAVT();
541 else if (request_path_str.contains("/RC/"))
542 device->publishRCS();
543 else if (request_path_str.contains("/CM/"))
544 device->publishCMS();
545 }
546 }
547
548 // Setup and register individual services
550 DLNAServiceInfo avt;
551 // Use static descriptor callback and control handler
552 avt.setup("urn:schemas-upnp-org:service:AVTransport:1",
553 "urn:upnp-org:serviceId:AVTransport", "/AVT/service.xml",
555 &DLNAMediaRenderer::controlCB, "/AVT/event",
556 [](HttpServer* server, const char* requestPath,
557 HttpRequestHandlerLine* hl) { server->replyOK(); });
559 // register URLs on the provided server so SCPD, control and event
560 // subscription endpoints are available immediately
561 server->on(avt.scpd_url, T_GET, avt.scp_cb, ref_ctx, 1);
562 server->on(avt.control_url, T_POST, avt.control_cb, ref_ctx, 1);
564 ref_ctx, 1);
565 server->on(avt.event_sub_url, T_UNSUBSCRIBE,
567 server->on(avt.event_sub_url, T_POST,
569
570 addService(avt);
571 }
572
575 cm.setup(
576 "urn:schemas-upnp-org:service:ConnectionManager:1",
577 "urn:upnp-org:serviceId:ConnectionManager", "/CM/service.xml",
578 &DLNAMediaRenderer::connmgrDescrCB, "/CM/control",
579 [](HttpServer* server, const char* requestPath,
580 HttpRequestHandlerLine* hl) { server->replyOK(); },
581 "/CM/event",
582 [](HttpServer* server, const char* requestPath,
583 HttpRequestHandlerLine* hl) { server->replyOK(); });
585
586 server->on(cm.scpd_url, T_GET, cm.scp_cb, ref_ctx, 1);
587 server->on(cm.control_url, T_POST, cm.control_cb, ref_ctx, 1);
589 1);
590 server->on(cm.event_sub_url, T_UNSUBSCRIBE,
592 server->on(cm.event_sub_url, T_POST,
594
595 addService(cm);
596 }
597
600 rc.setup("urn:schemas-upnp-org:service:RenderingControl:1",
601 "urn:upnp-org:serviceId:RenderingControl", "/RC/service.xml",
602 &DLNAMediaRenderer::controlDescrCB, "/RC/control",
603 &DLNAMediaRenderer::controlCB, "/RC/event",
604 [](HttpServer* server, const char* requestPath,
605 HttpRequestHandlerLine* hl) { server->replyOK(); });
607 server->on(rc.scpd_url, T_GET, rc.scp_cb, ref_ctx, 1);
608 server->on(rc.control_url, T_POST, rc.control_cb, ref_ctx, 1);
610 1);
611 server->on(rc.event_sub_url, T_UNSUBSCRIBE,
613 server->on(rc.event_sub_url, T_POST,
615
616 addService(rc);
617 }
618
621 DlnaLogger.log(DlnaLogLevel::Info, "MediaRenderer::setupServices");
622 // register the individual services and register their endpoints on the
623 // provided HttpServer
624 setupTransportService(server);
627 }
628
630 static int printReplyXML(Print& out, const char* replyName,
631 const char* serviceId,
632 const char* values = nullptr) {
633 XMLPrinter xp(out);
634 size_t result = 0;
635 result += xp.printNodeBegin(
636 "s:Envelope", "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"");
637 result += xp.printNodeBegin("s:Body");
638 result += xp.printf("<u:%s xmlns:u=\"urn:schemas-upnp-org:service:%s:1\">",
639 replyName, serviceId);
640
641 // e.g.<u:return>Stop,Pause,Next,Seek</u:return> for
642 // QueryStateVariableResponse
643 if (values) {
644 result += xp.printf("%s", values);
645 }
646
647 result += xp.printf("</u:%s>", replyName);
648 result += xp.printNodeEnd("s:Body");
649 result += xp.printNodeEnd("s:Envelope");
650 return result;
651 }
652
653 // Static reply helper methods for SOAP actions
654 static size_t replyPlay(Print& out) {
655 return DLNAMediaRenderer::printReplyXML(out, "PlayResponse", "AVTransport");
656 }
657 static size_t replyPause(Print& out) {
658 return DLNAMediaRenderer::printReplyXML(out, "PauseResponse",
659 "AVTransport");
660 }
661 static size_t replyStop(Print& out) {
662 return DLNAMediaRenderer::printReplyXML(out, "StopResponse", "AVTransport");
663 }
664 static size_t replySetAVTransportURI(Print& out) {
665 return DLNAMediaRenderer::printReplyXML(out, "SetAVTransportURIResponse",
666 "AVTransport");
667 }
668 static size_t replySetVolume(Print& out) {
669 return DLNAMediaRenderer::printReplyXML(out, "SetVolumeResponse",
670 "RenderingControl");
671 }
672 static size_t replySetMute(Print& out) {
673 return DLNAMediaRenderer::printReplyXML(out, "SetMuteResponse",
674 "RenderingControl");
675 }
676 // Static reply helper for GetMute
677 static size_t replyGetMute(Print& out, bool isMuted) {
678 StrPrint values;
679 values.printf("<CurrentMute>%d</CurrentMute>", isMuted ? 1 : 0);
680 return DLNAMediaRenderer::printReplyXML(out, "GetMuteResponse",
681 "RenderingControl", values.c_str());
682 }
683
684 // Static reply helper for GetVolume
685 static size_t replyGetVolume(Print& out, uint8_t volume) {
686 StrPrint values;
687 values.printf("<CurrentVolume>%d</CurrentVolume>", volume);
688 return DLNAMediaRenderer::printReplyXML(out, "GetVolumeResponse",
689 "RenderingControl", values.c_str());
690 }
691
699 bool processAction(ActionRequest& action, HttpServer& server) {
700 DlnaLogger.log(DlnaLogLevel::Info, "DLNAMediaRenderer::processAction: %s",
701 action.action);
702 StrView action_str(action.action);
703 if (action_str.isEmpty()) {
704 DlnaLogger.log(DlnaLogLevel::Error, "Empty action received");
705 server.replyError(400, "Invalid Action");
706 return false;
707 }
708
709 for (const auto& rule : rules) {
710 if (action_str.endsWith(rule.suffix)) {
711 return rule.handler(this, action, server);
712 }
713 }
714 DlnaLogger.log(DlnaLogLevel::Error, "Unsupported action: %s",
715 action.action);
716 server.replyError(400, "Invalid Action");
717 return false;
718 }
719
721 void setupRules() {
722 rules.push_back({"Play", [](DLNAMediaRenderer* self, ActionRequest& action,
723 HttpServer& server) {
724 self->setActive(true);
725 NullPrint nop;
726 server.reply("text/xml",
729 return true;
730 }});
731 rules.push_back({"Pause", [](DLNAMediaRenderer* self, ActionRequest& action,
732 HttpServer& server) {
733 self->setActive(false);
734 NullPrint nop;
735 server.reply("text/xml",
738 return true;
739 }});
740 rules.push_back({"Stop", [](DLNAMediaRenderer* self, ActionRequest& action,
741 HttpServer& server) {
742 self->setActive(false);
743 NullPrint nop;
744 server.reply("text/xml",
747 return true;
748 }});
749 rules.push_back({"GetCurrentTransportActions",
750 [](DLNAMediaRenderer* self, ActionRequest& action,
751 HttpServer& server) {
752 StrPrint returnValue;
753 returnValue.printf("<u:return>%s</u:return>",
757 xml, "QueryStateVariableResponse", "AVTransport",
758 returnValue.c_str());
759 server.reply("text/xml", xml.c_str(), xml.length());
760 return true;
761 }});
762 rules.push_back(
763 {"SetAVTransportURI", [](DLNAMediaRenderer* self, ActionRequest& action,
764 HttpServer& server) {
765 const char* uri = action.getArgumentValue("CurrentURI");
766 if (uri && *uri) {
767 self->setPlaybackURL(uri);
768 NullPrint nop;
769 server.reply("text/xml",
772 return true;
773 } else {
776 "SetAVTransportURI called with invalid SOAP payload");
777 server.replyError(400, "Invalid Action");
778 return false;
779 }
780 }});
781 rules.push_back(
782 {"SetVolume", [](DLNAMediaRenderer* self, ActionRequest& action,
783 HttpServer& server) {
784 int desiredVolume = action.getArgumentIntValue("DesiredVolume");
785 self->setVolume((uint8_t)desiredVolume);
786 NullPrint nop;
787 server.reply("text/xml", DLNAMediaRenderer::replySetVolume(nop),
789 return true;
790 }});
791 rules.push_back(
792 {"SetMute", [](DLNAMediaRenderer* self, ActionRequest& action,
793 HttpServer& server) {
794 bool desiredMute = action.getArgumentIntValue("DesiredMute") != 0;
795 self->setMuted(desiredMute);
796 NullPrint nop;
797 server.reply("text/xml", DLNAMediaRenderer::replySetMute(nop),
799 return true;
800 }});
801 // Add GetMute rule
802 rules.push_back({"GetMute", [](DLNAMediaRenderer* self,
803 ActionRequest& action, HttpServer& server) {
804 StrPrint str;
806 server.reply("text/xml", str.c_str());
807 return true;
808 }});
809 // Add GetVolume rule
810 rules.push_back(
811 {"GetVolume", [](DLNAMediaRenderer* self, ActionRequest& action,
812 HttpServer& server) {
813 StrPrint str;
815 server.reply("text/xml", str.c_str());
816 return true;
817 }});
818 }
819};
820
821} // namespace tiny_dlna
Represents a request to invoke a remote DLNA service action.
Definition: Action.h:109
const char * action
Definition: Action.h:159
Device Attributes and generation of XML using urn:schemas-upnp-org:device-1-0. We could just return a...
Definition: DLNADeviceInfo.h:27
void setDeviceType(const char *st)
Definition: DLNADeviceInfo.h:48
void addService(DLNAServiceInfo s)
Adds a service definition.
Definition: DLNADeviceInfo.h:143
void setModelName(const char *name)
Definition: DLNADeviceInfo.h:131
void setSerialNumber(const char *sn)
Definition: DLNADeviceInfo.h:135
void setManufacturer(const char *man)
Definition: DLNADeviceInfo.h:125
void setFriendlyName(const char *name)
Definition: DLNADeviceInfo.h:123
XMLPrinter xml
Definition: DLNADeviceInfo.h:215
bool is_active
Definition: DLNADeviceInfo.h:214
void setModelNumber(const char *number)
Definition: DLNADeviceInfo.h:133
void setBaseURL(const char *url)
Defines the base url.
Definition: DLNADeviceInfo.h:59
Setup of a Basic DLNA Device service. The device registers itself to the network and answers to the D...
Definition: DLNADevice.h:27
void end()
Stops the processing and releases the resources.
Definition: DLNADevice.h:85
void addChange(const char *serviceAbbrev, std::function< size_t(Print &, void *)> changeWriter, void *ref)
Definition: DLNADevice.h:156
bool begin(DLNADeviceInfo &device, IUDPService &udp, HttpServer &server)
start the
Definition: DLNADevice.h:30
static void parseActionRequest(HttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl, ActionRequest &action)
Parses the SOAP content of a DLNA action request.
Definition: DLNADevice.h:275
static void eventSubscriptionHandler(HttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl)
Static handler for SUBSCRIBE/UNSUBSCRIBE requests on service event URLs.
Definition: DLNADevice.h:189
bool loop()
call this method in the Arduino loop as often as possible
Definition: DLNADevice.h:104
ConnectionManager service descriptor (SCPD) generator.
Definition: DLNAMediaRendererDescr.h:559
size_t printDescr(Print &out) override
Definition: DLNAMediaRendererDescr.h:561
RenderingControl service descriptor (SCPD) generator.
Definition: DLNAMediaRendererDescr.h:450
size_t printDescr(Print &out) override
Definition: DLNAMediaRendererDescr.h:452
AVTransport service descriptor (SCPD) generator.
Definition: DLNAMediaRendererDescr.h:18
size_t printDescr(Print &out) override
Definition: DLNAMediaRendererDescr.h:20
MediaRenderer DLNA Device.
Definition: DLNAMediaRenderer.h:61
static void eventSubscriptionHandler(HttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl)
After the subscription we publish all relevant properties.
Definition: DLNAMediaRenderer.h:532
static size_t replyGetVolume(Print &out, uint8_t volume)
Definition: DLNAMediaRenderer.h:685
DLNAMediaRenderer(HttpServer &server, IUDPService &udp)
Recommended constructor Construct a MediaRenderer bound to an HttpServer and IUDPService....
Definition: DLNAMediaRenderer.h:92
bool isActive()
Query whether renderer is active (playing)
Definition: DLNAMediaRenderer.h:122
IUDPService * p_udp_member
Definition: DLNAMediaRenderer.h:405
MediaEventHandler event_cb
Definition: DLNAMediaRenderer.h:391
static size_t replySetVolume(Print &out)
Definition: DLNAMediaRenderer.h:668
void setupTransportService(HttpServer *server)
Definition: DLNAMediaRenderer.h:549
bool begin()
Override to initialize the device.
Definition: DLNAMediaRenderer.h:99
void publishCMS()
Publish a minimal ConnectionManager state (CurrentConnectionIDs)
Definition: DLNAMediaRenderer.h:456
const char * getCurrentUri()
Definition: DLNAMediaRenderer.h:205
const char * getTransportState()
Get textual transport state.
Definition: DLNAMediaRenderer.h:208
void setMimeFromDIDL(const char *didl)
Definition: DLNAMediaRenderer.h:478
static size_t replyPlay(Print &out)
Definition: DLNAMediaRenderer.h:654
void setActive(bool active)
Set the active state (used by transport callbacks)
Definition: DLNAMediaRenderer.h:125
static void connmgrDescrCB(HttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl)
Definition: DLNAMediaRenderer.h:499
void setHttpServer(HttpServer &server)
Set the http server instance the MediaRenderer should use.
Definition: DLNAMediaRenderer.h:111
static void controlDescrCB(HttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl)
Definition: DLNAMediaRenderer.h:507
void setupRules()
Setup the action handling rules.
Definition: DLNAMediaRenderer.h:721
void setMediaEventHandler(MediaEventHandler cb)
Register application event handler.
Definition: DLNAMediaRenderer.h:160
DLNADevice & device()
Provides access to the internal DLNA device instance.
Definition: DLNAMediaRenderer.h:211
const char * getMime()
Provides the mime from the DIDL or nullptr.
Definition: DLNAMediaRenderer.h:153
bool setPlaybackURL(const char *urlStr)
Defines the actual url to play.
Definition: DLNAMediaRenderer.h:256
static size_t replyGetMute(Print &out, bool isMuted)
Definition: DLNAMediaRenderer.h:677
void publishGetRelativeTimePositionSec()
Publish the RelativeTimePosition property.
Definition: DLNAMediaRenderer.h:342
Vector< ActionRule > rules
Definition: DLNAMediaRenderer.h:408
static size_t replyPause(Print &out)
Definition: DLNAMediaRenderer.h:657
void addChange(const char *serviceAbbrev, std::function< size_t(Print &, void *)> changeWriter)
serviceAbbrev: AVT, RCS, CMS
Definition: DLNAMediaRenderer.h:411
static int printReplyXML(Print &out, const char *replyName, const char *serviceId, const char *values=nullptr)
Builds a standard SOAP reply envelope.
Definition: DLNAMediaRenderer.h:630
tiny_dlna::Str transport_state
Definition: DLNAMediaRenderer.h:398
void setUdpService(IUDPService &udp)
Set the UDP service instance the MediaRenderer should use.
Definition: DLNAMediaRenderer.h:119
void * ref_ctx[1]
Definition: DLNAMediaRenderer.h:407
const char * getCurrentTransportActions()
Get a csv of the valid actions.
Definition: DLNAMediaRenderer.h:368
void setupServicesImpl(HttpServer *server)
Register all services (called when HTTP server is set)
Definition: DLNAMediaRenderer.h:620
tiny_dlna::Str current_uri
Definition: DLNAMediaRenderer.h:389
bool processAction(ActionRequest &action, HttpServer &server)
Process parsed SOAP ActionRequest and dispatch to appropriate handler.
Definition: DLNAMediaRenderer.h:699
tiny_dlna::Str current_mime
Definition: DLNAMediaRenderer.h:390
HttpServer * p_server
Definition: DLNAMediaRenderer.h:404
bool stop()
Stop playback.
Definition: DLNAMediaRenderer.h:283
static size_t replySetAVTransportURI(Print &out)
Definition: DLNAMediaRenderer.h:664
void publishRCS()
Publish the current RenderingControl state (Volume, Mute)
Definition: DLNAMediaRenderer.h:444
const char * st
Definition: DLNAMediaRenderer.h:399
bool is_muted
Definition: DLNAMediaRenderer.h:393
static void transportDescrCB(HttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl)
Definition: DLNAMediaRenderer.h:491
static void controlCB(HttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl)
Definition: DLNAMediaRenderer.h:516
void setCustomActionRule(const char *suffix, bool(*handler)(DLNAMediaRenderer *, ActionRequest &, HttpServer &))
Defines a custom action rule for the media renderer.
Definition: DLNAMediaRenderer.h:376
unsigned long time_sum
Definition: DLNAMediaRenderer.h:395
const char * usn
Definition: DLNAMediaRenderer.h:400
void setupConnectionManagerService(HttpServer *server)
Definition: DLNAMediaRenderer.h:573
unsigned long start_time
Definition: DLNAMediaRenderer.h:394
DLNAMediaRenderer()
Default constructor.
Definition: DLNAMediaRenderer.h:74
static size_t replySetMute(Print &out)
Definition: DLNAMediaRenderer.h:672
void setMime(const char *mime)
Set MIME explicitly (used when DIDL-Lite metadata provides protocolInfo)
Definition: DLNAMediaRenderer.h:469
uint8_t current_volume
Definition: DLNAMediaRenderer.h:392
void(* MediaEventHandler)(MediaEvent event, DLNAMediaRenderer &renderer)
Definition: DLNAMediaRenderer.h:64
uint8_t getVolume()
Get current volume (0-255)
Definition: DLNAMediaRenderer.h:163
bool isMuted()
Query mute state.
Definition: DLNAMediaRenderer.h:184
bool loop()
Call this from Arduino loop()
Definition: DLNAMediaRenderer.h:108
bool play()
Start playback: same as setActive(true)
Definition: DLNAMediaRenderer.h:214
DLNADevice dlna_device
Definition: DLNAMediaRenderer.h:403
void setupRenderingControlService(HttpServer *server)
Definition: DLNAMediaRenderer.h:598
void setVolume(uint8_t vol)
Set volume and publish event.
Definition: DLNAMediaRenderer.h:166
size_t getRelativeTimePositionSec()
Get estimated playback position (seconds)
Definition: DLNAMediaRenderer.h:336
static size_t replyStop(Print &out)
Definition: DLNAMediaRenderer.h:661
void setPlaybackCompleted()
Notify the renderer that playback completed.
Definition: DLNAMediaRenderer.h:312
void setMuted(bool m)
Set mute state and publish event.
Definition: DLNAMediaRenderer.h:187
bool play(const char *urlStr)
Start playback of a network resource (returns true on success)
Definition: DLNAMediaRenderer.h:220
void end()
Stops processing and releases resources.
Definition: DLNAMediaRenderer.h:102
void publishAVT()
Definition: DLNAMediaRenderer.h:418
Attributes needed for the DLNA Service Definition.
Definition: DLNAServiceInfo.h:16
const char * scpd_url
Definition: DLNAServiceInfo.h:35
http_callback control_cb
Definition: DLNAServiceInfo.h:40
http_callback scp_cb
Definition: DLNAServiceInfo.h:39
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)
Definition: DLNAServiceInfo.h:19
const char * control_url
Definition: DLNAServiceInfo.h:36
const char * subscription_namespace_abbrev
Definition: DLNAServiceInfo.h:49
const char * event_sub_url
Definition: DLNAServiceInfo.h:37
Used to register and process callbacks.
Definition: HttpRequestHandlerLine.h:19
void ** context
Definition: HttpRequestHandlerLine.h:39
A Simple Header only implementation of Http Server that allows the registration of callback functions...
Definition: HttpServer.h:25
void on(const char *url, TinyMethodID method, web_callback_fn fn, void *ctx[]=nullptr, int ctxCount=0)
register a generic handler
Definition: HttpServer.h:90
void replyOK()
write OK reply with 200 SUCCESS
Definition: HttpServer.h:380
void reply(const char *contentType, Stream &inputStream, int size, int status=200, const char *msg=SUCCESS)
write reply - copies data from input stream with header size
Definition: HttpServer.h:296
void replyError(int err, const char *msg="Internal Server Error")
Definition: HttpServer.h:388
void replyNotFound()
write 404 reply
Definition: HttpServer.h:383
Abstract Interface for UDP API.
Definition: IUDPService.h:33
void log(DlnaLogLevel current_level, const char *fmt...)
Print log message.
Definition: Logger.h:40
Class with does not do any output: it can be used to determine the length of the output.
Definition: NullPrint.h:12
Print to a dynamic string.
Definition: StrPrint.h:13
const char * c_str()
Definition: StrPrint.h:39
size_t printf(const char *fmt,...)
Definition: StrPrint.h:49
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 bool endsWith(const char *str)
checks if the string ends with the indicated substring
Definition: StrView.h:191
virtual void set(const char *alt)
assigs a value
Definition: StrView.h:44
virtual bool contains(const char *str)
checks if the string contains a substring
Definition: StrView.h:284
String implementation which keeps the data on the heap. We grow the allocated memory only if the copy...
Definition: Str.h:22
const char * c_str() const
Definition: Str.h:186
Vector implementation which provides the most important methods as defined by std::vector....
Definition: Vector.h:19
static bool extractAttributeToken(const char *xml, const char *tagName, const char *attrName, int n, char *outBuf, size_t bufSize)
Extract the nth (1-based) colon-separated token from an attribute value located on the first occurren...
Definition: XMLAttributeParser.h:132
Definition: AllocationTracker.h:9
MediaEvent
Events emitted by the MediaRenderer to notify the application about playback and rendering control ch...
Definition: DLNAMediaRenderer.h:31
@ T_UNSUBSCRIBE
Definition: HttpHeader.h:46
@ T_SUBSCRIBE
Definition: HttpHeader.h:47
@ T_GET
Definition: HttpHeader.h:37
@ T_POST
Definition: HttpHeader.h:39
LoggerClass DlnaLogger
Definition: Logger.cpp:5
Functions to efficiently output XML. XML data contains a lot of redundancy so it is more memory effic...
Definition: XMLPrinter.h:55
size_t printNodeBegin(const char *node, const char *attributes=nullptr, const char *ns=nullptr)
Prints the beginning of an XML node.
Definition: XMLPrinter.h:249
size_t printf(const char *fmt,...)
printf-style helper that formats into an internal buffer and writes to the configured Print output.
Definition: XMLPrinter.h:183
size_t printNodeEnd(const char *node, const char *ns=nullptr)
Prints the end of an XML node.
Definition: XMLPrinter.h:287