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#include <functional>
5
7#include "basic/Printf.h"
8#include "basic/Str.h"
14
15namespace tiny_dlna {
33
69template <typename ClientType>
71 public:
72 using HttpClient = ClientType;
74 // event handler: (event, reference to MediaRenderer)
75 typedef void (*MediaEventHandler)(MediaEvent event,
76 DLNAMediaRenderer& renderer);
77
86 // Constructor
87 DlnaLogger.log(DlnaLogLevel::Info, "MediaRenderer::MediaRenderer");
88 setUDN(usn);
89 setSerialNumber("1.0");
91 setFriendlyName("ArduinoMediaRenderer");
92 setManufacturer("TinyDLNA");
93 setModelName("TinyDLNA");
94 setModelNumber("1.0");
95 setBaseURL("http://localhost:44757");
96 setupRules();
98 }
99
107 setHttpServer(server);
108 setUdpService(udp);
109 }
110
112 bool begin() { return dlna_device.begin(*this, *p_udp_member, *p_server); }
113
115 void end() {
116 if (is_active) stop();
118 }
119
121 bool loop(int loopAction = RUN_ALL) { return dlna_device.loop(loopAction); }
122
125 p_server = &server;
126 // prepare handler context and register each service via helpers
127 server.setReference(this);
128 setupServicesImpl(&server);
129 }
130
133
136 possiblePlaybackStorageMedia = v ? v : "";
137 }
138
142 }
143
145 void setPossibleRecordStorageMedia(const char* v) {
146 possibleRecordStorageMedia = v ? v : "";
147 }
148
150 const char* getPossibleRecordStorageMedia() const {
152 }
153
155 void setPossibleRecordQualityModes(const char* v) {
156 possibleRecordQualityModes = v ? v : "";
157 }
158
160 const char* getPossibleRecordQualityModes() const {
162 }
163
165 void setPlayMode(const char* v) { currentPlayMode = v ? v : "NORMAL"; }
166
168 const char* getPlayMode() const { return currentPlayMode; }
169
171 bool isActive() { return is_active; }
172
174 void setActive(bool active) {
175 DlnaLogger.log(DlnaLogLevel::Info, "Set active: %s",
176 active ? "true" : "false");
177 is_active = active;
178 if (active) {
179 start_time = millis();
180 } else {
181 // accumulate time
182 time_sum += millis() - start_time;
183 start_time = 0;
184 }
185 // reflect state in transport_state so deferred writer can read it
186 transport_state = active ? "PLAYING" : "PAUSED_PLAYBACK";
187 struct StateWriter {
188 static size_t write(Print& out, void* ref) {
189 auto self = (DLNAMediaRenderer*)ref;
190 size_t written = 0;
191
192 written += out.print("<TransportState val=\"");
193 written += out.print(self->getTransportState());
194 written += out.print("\"/>");
195 written += out.print("<CurrentTransportActions val=\"");
196 written += out.print(self->getCurrentTransportActions());
197 written += out.print("\"/>");
198
199 return written;
200 }
201 };
202 addChange("AVT", StateWriter::write);
203 }
204
206 const char* getMime() {
207 // Prefer explicit MIME from DIDL if available
208 if (!current_mime.isEmpty()) return current_mime.c_str();
209 return nullptr;
210 }
211
214
216 uint8_t getVolume() { return current_volume; }
217
219 void setVolume(uint8_t vol) {
220 current_volume = vol;
221 (void)current_volume; // value used by writer via ref
222 auto writer = [](Print& out, void* ref) -> size_t {
223 auto self = (DLNAMediaRenderer*)ref;
224 size_t written = 0;
225 written += out.print("<Volume val=\"");
226 written += out.print(self->current_volume);
227 written += out.print("\" channel=\"Master\"/>");
228 return written;
229 };
230 addChange("RCS", writer);
231 }
232
234 bool isMuted() { return getVolume() == 0; }
235
237 void setMuted(bool mute) {
238 if (mute) {
239 // store current volume and set to 0
241 current_volume = 0;
242 } else {
243 // restore previous volume
245 }
246 auto writer = [](Print& out, void* ref) -> size_t {
247 auto self = (DLNAMediaRenderer*)ref;
248 size_t written = 0;
249 written += out.print("<Mute val=\"");
250 written += out.print(self->isMuted() ? 1 : 0);
251 written += out.print("\" channel=\"Master\"/>");
252 return written;
253 };
254 addChange("RCS", writer);
255 }
256
258 const char* getCurrentUri() { return current_uri.c_str(); }
259
262
264 const char* getTransportState() { return transport_state.c_str(); }
265
268
270 void setSubscriptionsActive(bool flag) {
272 }
273
276
278 bool play() {
279 setActive(true);
280 return true;
281 }
282
284 bool play(const char* urlStr) {
285 if (urlStr == nullptr) return false;
286 DlnaLogger.log(DlnaLogLevel::Info, "play URL: %s", urlStr);
287 // store URI
288 current_uri.set(urlStr);
289 // notify handler about the new URI; do not dispatch PLAY here — action
290 // handlers will dispatch media events explicitly.
291 is_active = true;
292
293 // ensure transport_state reflects playing for subscribers
294 transport_state = "PLAYING";
295 (void)current_uri; // writer will fetch it from ref
296 auto writer = [](Print& out, void* ref) -> size_t {
297 auto self = (DLNAMediaRenderer*)ref;
298 size_t written = 0;
299 written += out.print("<CurrentTrack val=\"1\"/>\n");
300 written += out.print("<CurrentTrackURI val=\"");
301 written += out.print(self->current_uri.c_str());
302 written += out.println("\"/>");
303 written += out.print("<CurrentTrackMetadata val=\"");
304 written += out.print(self->current_uri_metadata.c_str());
305 written += out.println("\"/>");
306 written += out.print("<TransportState val=\"");
307 written += out.print(self->transport_state.c_str());
308 written += out.print("\"/>");
309 written += out.print("<CurrentTransportActions val=\"");
310 written += out.print(self->transport_actions.c_str());
311 written += out.print("\"/>");
312 return written;
313 };
314 addChange("AVT", writer);
315
316 return true;
317 }
318
320 bool setPlaybackURL(const char* urlStr) {
321 if (urlStr == nullptr) return false;
322 DlnaLogger.log(DlnaLogLevel::Info, "setPlaybackURL URL: %s", urlStr);
323 // store URI
324 current_uri = Str(urlStr);
325 // Do not notify application here; event notifications are emitted
326 // from the SOAP action handlers (processAction*).
327 auto writer = [](Print& out, void* ref) -> size_t {
328 auto self = (DLNAMediaRenderer*)ref;
329 size_t written = 0;
330 written += out.print("<AVTransportURI val=\"");
331 written += out.print(self->current_uri.c_str());
332 written += out.println("\"/>");
333
334 written += out.print("<AVTransportURIMetaData val=\"");
335 written += out.print(self->current_uri_metadata.c_str());
336 written += out.println("\"/>");
337
338 written += out.print("<NumberOfTracks val=\"1\"/>\n");
339 return written;
340 };
341 addChange("AVT", writer);
342
343 return true;
344 }
345
347 bool stop() {
348 DlnaLogger.log(DlnaLogLevel::Info, "Stop playback");
349 is_active = false;
350 start_time = 0;
351 time_sum = 0;
352 // reflect stopped state
353 transport_state = "STOPPED";
354 auto writer = [](Print& out, void* ref) -> size_t {
355 auto self = (DLNAMediaRenderer*)ref;
356 size_t written = 0;
357 written += out.print("<TransportState val=\"");
358 written += out.print(self->getTransportState());
359 written += out.print("\"/>");
360 written += out.print("<CurrentTransportActions val=\"");
361 written += out.print(self->getCurrentTransportActions());
362 written += out.print("\"/>");
363 return written;
364 };
365 addChange("AVT", writer);
366 return true;
367 }
368
378 DlnaLogger.log(DlnaLogLevel::Info, "Playback completed");
379 transport_state = "STOPPED";
380 is_active = false;
381 start_time = 0;
382 time_sum = 0;
383 // Do not notify application here; event notifications are emitted
384 // from the SOAP action handlers (processAction*).
385 auto writer = [](Print& out, void* ref) -> size_t {
386 auto self = (DLNAMediaRenderer*)ref;
387 size_t written = 0;
388 written += out.print("<TransportState val=\"");
389 written += out.print(self->transport_state.c_str());
390 written += out.print("\"/>");
391 written += out.print("<CurrentPlayMode val=\"NORMAL\"/>");
392 written += out.print("<CurrentTrackURI val=\"\"/>");
393 written += out.print("<RelativeTimePosition val=\"00:00:00\"/>");
394 written += out.print("<CurrentTransportActions val=\"Play\"/>");
395 return written;
396 };
397 addChange("AVT", writer);
398 }
399
402 unsigned long posMs = (millis() - start_time) + time_sum;
403 return static_cast<size_t>(posMs / 1000);
404 }
405
408 auto writer = [](Print& out, void* ref) -> size_t {
409 auto self = (DLNAMediaRenderer*)ref;
410 size_t written = 0;
411 // format hh:mm:ss by printing parts
412 int h = static_cast<int>(self->getRelativeTimePositionSec() / 3600);
413 int m =
414 static_cast<int>((self->getRelativeTimePositionSec() % 3600) / 60);
415 int s = static_cast<int>(self->getRelativeTimePositionSec() % 60);
416 written += out.print("<RelativeTimePosition val=\"");
417 // print two-digit hour
418 if (h < 10) written += out.print('0');
419 written += out.print(h);
420 written += out.print(':');
421 if (m < 10) written += out.print('0');
422 written += out.print(m);
423 written += out.print(':');
424 if (s < 10) written += out.print('0');
425 written += out.print(s);
426 written += out.print("\"/>");
427 return written;
428 };
429 addChange("AVT", writer);
430 }
431
434 if (current_uri.isEmpty()) {
435 return "SetAVTransportURI";
436 }
437 if (is_active) {
438 return "Pause,Stop";
439 } else {
440 return "Play";
441 }
442 }
444 void setCustomActionRule(const char* suffix,
445 bool (*handler)(DLNAMediaRenderer*, ActionRequest&,
446 IHttpServer&)) {
447 for (size_t i = 0; i < rules.size(); ++i) {
448 if (StrView(rules[i].suffix).equals(suffix)) {
449 rules[i].handler = handler;
450 return;
451 }
452 }
453 rules.push_back({suffix, handler});
454 }
455
457 void setConnectionID(const char* id) { connectionID = id; }
458
460 const char* getConnectionID() { return connectionID; }
461
467 void setProtocols(const char* source, const char* sink = "") {
468 sourceProto = source;
469 sinkProto = sink;
470 // publish protocol info change to ConnectionManager subscribers
471 // Build writer that will use live state from the device at publish time
472 auto writer = [](Print& out, void* ref) -> size_t {
473 auto self = (DLNAMediaRenderer*)ref;
474 size_t result = 0;
475 result += out.print("<SourceProtocolInfo val=\"");
476 result += out.print(StrView(self->getSourceProtocols()).c_str());
477 result += out.println("\"/>");
478 result += out.print("<SinkProtocolInfo val=\"");
479 result += out.print(StrView(self->getSinkProtocols()).c_str());
480 result += out.println("\"/>");
481 return result;
482 };
483 addChange("CMS", writer);
484 }
485
487 const char* getSourceProtocols() { return sourceProto; }
488
490 const char* getSinkProtocols() { return sinkProto; }
491
494
497
500
503
506
509
510 protected:
512 struct ActionRule {
513 const char* suffix;
515 };
516
521 uint8_t current_volume = 50;
522 uint8_t muted_volume = 0;
523 unsigned long start_time = 0;
524 unsigned long time_sum = 0;
525 // Current state (e.g. "STOPPED", "PLAYING","PAUSED_PLAYBACK")
527 const char* st = "urn:schemas-upnp-org:device:MediaRenderer:1";
528 const char* usn = "uuid:09349455-2941-4cf7-9847-1dd5ab210e97";
532 const char* connectionID = "0";
533 const char* sourceProto = "";
535 const char* possiblePlaybackStorageMedia = "NETWORK";
536 const char* possibleRecordStorageMedia = "NONE";
537 const char* possibleRecordQualityModes = "NOT_IMPLEMENTED";
538 const char* currentPlayMode = "NORMAL";
540
541 // Descriptor instances so callers can customise the SCPD output per device
548
549 // Note: descriptor printing is performed inline in the descriptor
550 // callbacks below using non-capturing lambdas passed to
551 // IHttpServer::reply. That avoids heap buffering while keeping the
552 // callsites concise. The old static helper functions were removed.
553
555 void addChange(const char* serviceAbbrev,
556 std::function<size_t(Print&, void*)> changeWriter) {
557 dlna_device.addChange(serviceAbbrev, changeWriter, this);
558 }
559
562 void publishAVT() {
563 // Transport state will be built by the writer from the instance (ref)
564 auto writer = [](Print& out, void* ref) -> size_t {
565 auto self = (DLNAMediaRenderer*)ref;
566 Printf outf{out};
567 size_t written = 0;
568 written += outf.printf("<TransportState val=\"%s\"/>",
569 self->transport_state.c_str());
570 if (!self->current_uri.isEmpty()) {
571 written += outf.printf("<CurrentTrackURI val=\"%s\"/>",
572 self->current_uri.c_str());
573 }
574 written += outf.printf(
575 "<RelativeTimePosition val=\"%02d:%02d:%02d\"/>",
576 static_cast<int>(self->getRelativeTimePositionSec() / 3600),
577 static_cast<int>((self->getRelativeTimePositionSec() % 3600) / 60),
578 static_cast<int>(self->getRelativeTimePositionSec() % 60));
579 written += outf.printf("<CurrentTransportActions val=\"%s\"/>",
580 self->getCurrentTransportActions());
581 return written;
582 };
583 addChange("AVT", writer);
584 }
585
587 void publishRCS() {
588 auto writer = [](Print& out, void* ref) -> size_t {
589 auto self = (DLNAMediaRenderer*)ref;
590 Printf outf{out};
591 size_t written = 0;
592 written += outf.printf("<Volume val=\"%d\" channel=\"Master\"/>", self->current_volume);
593 written += out.println();
594 written += outf.printf("<Mute val=\"%d\" channel=\"Master\"/>", self->isMuted() ? 1 : 0);
595 written += out.println();
596 return written;
597 };
598 addChange("RCS", writer);
599 }
600
602 void publishCMS() {
603 auto writer = [](Print& out, void* ref) -> size_t {
605 Printf printer{out};
606 return printer.printf("<CurrentConnectionIDs>%s</CurrentConnectionIDs>");
607 };
608 addChange("CMS", writer);
609 }
610
612 void setMime(const char* mime) {
613 if (mime) {
614 current_mime = mime;
615 DlnaLogger.log(DlnaLogLevel::Info, "Set mime: %s", current_mime.c_str());
616 }
617 }
618
621 void setMimeFromDIDL(const char* didl) {
622 if (!didl) return;
623 // Convenience helper: extract protocolInfo attribute from a tag and
624 // return the contentFormat (3rd token) portion, e.g. from
625 // protocolInfo="http-get:*:audio/mpeg:*" -> "audio/mpeg".
626 char mimeBuf[256] = {0};
628 didl, "<res", "protocolInfo=", 3, mimeBuf, sizeof(mimeBuf))) {
629 setMime(mimeBuf);
630 }
631 }
632
633 // Static descriptor callbacks: print the SCPD XML for each service
634 static void transportDescrCB(IClientHandler& client, IHttpServer* server, const char* requestPath,
636 DLNAMediaRenderer* self = getRenderer(server);
637 if (self) {
638 client.reply(
639 "text/xml",
640 [](Print& out, void* ref) -> size_t {
641 size_t result = 0;
642 auto self = static_cast<DLNAMediaRenderer*>(ref);
643 if (self) result += self->getTransportDescr().printDescr(out);
644 return result;
645 },
646 200, nullptr, self);
647 } else {
648 DlnaLogger.log(DlnaLogLevel::Error,
649 "transportDescrCB: renderer instance not found for %s",
650 requestPath);
651 client.replyNotFound();
652 }
653 }
654
655 static void connmgrDescrCB(IClientHandler& client, IHttpServer* server, const char* requestPath,
657 DLNAMediaRenderer* self = getRenderer(server);
658 if (self) {
659 client.reply(
660 "text/xml",
661 [](Print& out, void* ref) -> size_t {
662 size_t result = 0;
663 auto self = static_cast<DLNAMediaRenderer*>(ref);
664 if (self) result += self->getConnectionMgrDescr().printDescr(out);
665 return result;
666 },
667 200, nullptr, self);
668 } else {
669 DlnaLogger.log(DlnaLogLevel::Error,
670 "connmgrDescrCB: renderer instance not found for %s",
671 requestPath);
672 client.replyNotFound();
673 }
674 }
675
676 static void controlDescrCB(IClientHandler& client, IHttpServer* server, const char* requestPath,
678 DLNAMediaRenderer* self = getRenderer(server);
679 if (self) {
680 client.reply(
681 "text/xml",
682 [](Print& out, void* ref) -> size_t {
683 size_t result = 0;
684 auto self = static_cast<DLNAMediaRenderer*>(ref);
685 if (self) result += self->getControlDescr().printDescr(out);
686 return result;
687 },
688 200, nullptr, self);
689 } else {
690 DlnaLogger.log(DlnaLogLevel::Error,
691 "controlDescrCB: renderer instance not found for %s",
692 requestPath);
693 client.replyNotFound();
694 }
695 }
696
697 // Generic control callback: parse SOAP action and dispatch to instance
698 static void controlCB(IClientHandler& client, IHttpServer* server, const char* requestPath,
700 ActionRequest action;
701 DeviceType::parseActionRequest(server, client, requestPath, hl, action);
702
703 DLNAMediaRenderer* self = getRenderer(server);
704
705 // Log incoming SOAPAction header and parsed action for debugging
706 const char* soapHdr = client.requestHeader().get("SOAPACTION");
707 DlnaLogger.log(DlnaLogLevel::Debug, "controlCB: SOAPAction=%s, action=%s",
708 StrView(soapHdr).c_str(),
709 StrView(action.getAction()).c_str());
710
711 if (self) {
712 if (self->processAction(action, *server, client)) return;
713 }
714 client.replyNotFound();
715 }
716
719 auto* p_device = static_cast<IDevice*>(server->getReference());
720 if (p_device == nullptr) return nullptr;
721 return static_cast<DLNAMediaRenderer*>(p_device->getReference());
722 }
723
726 const char* requestPath,
728 bool is_subscribe = false;
729 DeviceType::handleSubscription(server, &client, requestPath, hl, is_subscribe);
730 if (is_subscribe) {
731 DLNAMediaRenderer* self = getRenderer(server);
732 assert(self != nullptr);
733 StrView request_path_str(requestPath);
734 if (request_path_str.contains("/AVT/"))
735 self->publishAVT();
736 else if (request_path_str.contains("/RC/"))
737 self->publishRCS();
738 else if (request_path_str.contains("/CM/"))
739 self->publishCMS();
740 }
741 }
742
743 // Setup and register individual services
745 DLNAServiceInfo avt;
746 // Use static descriptor callback and control handler
747 avt.setup("urn:schemas-upnp-org:service:AVTransport:1",
748 "urn:upnp-org:serviceId:AVTransport", "/AVT/service.xml",
753
754 addService(avt);
755 }
756
759 cm.setup("urn:schemas-upnp-org:service:ConnectionManager:1",
760 "urn:upnp-org:serviceId:ConnectionManager", "/CM/service.xml",
761 &DLNAMediaRenderer::connmgrDescrCB, "/CM/control",
765
766 addService(cm);
767 }
768
771 rc.setup("urn:schemas-upnp-org:service:RenderingControl:1",
772 "urn:upnp-org:serviceId:RenderingControl", "/RC/service.xml",
773 &DLNAMediaRenderer::controlDescrCB, "/RC/control",
777
778 addService(rc);
779 }
780
783 DlnaLogger.log(DlnaLogLevel::Info, "MediaRenderer::setupServices");
784 // register the individual services and register their endpoints on the
785 // provided HTTP server
786 setupTransportService(server);
789 }
790
798 bool processAction(ActionRequest& action, IHttpServer& server, IClientHandler& client) {
799 DlnaLogger.log(DlnaLogLevel::Info, "DLNAMediaRenderer::processAction: %s",
800 action.getAction());
801 auto& action_str = action.getActionStr();
802 if (action_str.isEmpty()) {
803 DlnaLogger.log(DlnaLogLevel::Error, "Empty action received");
804 client.replyError(400, "Invalid Action");
805 return false;
806 }
807
808 for (const auto& rule : rules) {
809 if (action_str.endsWith(rule.suffix)) {
810 return rule.handler(this, action, server, client);
811 }
812 }
813 DlnaLogger.log(DlnaLogLevel::Error, "Unsupported action: %s",
814 action.getAction());
815 client.replyError(400, "Invalid Action");
816 return false;
817 }
818
819 // Per-action handlers (match MediaServer pattern)
822 client.reply(
823 "text/xml",
824 [](Print& out, void* ref) -> size_t {
825 (void)ref;
826 return DeviceType::printReplyXML(out, "PlayResponse", "AVTransport");
827 },
828 200, nullptr, this);
829 // setActive(true);
830 play();
831 return true;
832 }
833
835 client.reply(
836 "text/xml",
837 [](Print& out, void* ref) -> size_t {
839 out, "ListPresetsResponse", "AVTransport",
840 [](Print& o, void* /*innerRef*/) -> size_t {
841 size_t written = 0;
842 written += o.print("<CurrentPresetNameList>FactoryDefault</CurrentPresetNameList>");
843 return written;
844 },
845 nullptr);
846 },
847 200, nullptr, this);
848 return true;
849 }
850
853 client.reply(
854 "text/xml",
855 [](Print& out, void* ref) -> size_t {
856 (void)ref;
857 return DeviceType::printReplyXML(out, "PauseResponse", "AVTransport");
858 },
859 200, nullptr, this);
860 setActive(false);
861 return true;
862 }
863
865 // use stop() to ensure state reset and application callback are invoked
867 client.reply(
868 "text/xml",
869 [](Print& out, void* ref) -> size_t {
870 (void)ref;
871 return DeviceType::printReplyXML(out, "StopResponse", "AVTransport");
872 },
873 200, nullptr, this);
874 stop();
875 return true;
876 }
877
879 IHttpServer& server, IClientHandler& client) {
880 client.reply(
881 "text/xml",
882 [](Print& out, void* ref) -> size_t {
883 // Stream reply directly: delegate to printReplyXML which will
884 // write headers and invoke the inner writer with the same ref.
886 out, "GetCurrentTransportActionsResponse", "AVTransport",
887 [](Print& o, void* innerRef) -> size_t {
888 size_t written = 0;
889 auto self = (DLNAMediaRenderer*)innerRef;
890 written += o.print("<Actions>");
891 written += o.print(self->getCurrentTransportActions());
892 written += o.print("</Actions>");
893 return written;
894 },
895 ref);
896 },
897 200, nullptr, this);
898 return true;
899 }
900
901 // ConnectionManager: GetProtocolInfo
903 IHttpServer& server, IClientHandler& client) {
904 client.reply(
905 "text/xml",
906 [](Print& out, void* ref) -> size_t {
907 auto self = (DLNAMediaRenderer*)ref;
909 out, self->getSourceProtocols(), self->getSinkProtocols());
910 },
911 200, nullptr, this);
912 return true;
913 }
914
915 // ConnectionManager: GetCurrentConnectionIDs
917 IHttpServer& server, IClientHandler& client) {
918 client.reply(
919 "text/xml",
920 [](Print& out, void* ref) -> size_t {
921 auto self = (DLNAMediaRenderer*)ref;
923 out, self->getConnectionID());
924 },
925 200, nullptr, this);
926 return true;
927 }
928
929 // ConnectionManager: GetCurrentConnectionInfo
931 IHttpServer& server, IClientHandler& client) {
932 client.reply(
933 "text/xml",
934 [](Print& out, void* ref) -> size_t {
935 auto self = (DLNAMediaRenderer*)ref;
937 out, self->getSinkProtocols(), self->getConnectionID(), "Input");
938 },
939 200, nullptr, this);
940 return true;
941 }
942
943 // AVTransport: GetDeviceCapabilities
945 IHttpServer& server, IClientHandler& client) {
946 client.reply(
947 "text/xml",
948 [](Print& out, void* ref) -> size_t {
950 out, "GetDeviceCapabilitiesResponse", "AVTransport",
951 [](Print& o, void* innerRef) -> size_t {
952 auto self = (DLNAMediaRenderer*)innerRef;
953 size_t written = 0;
954 written += o.print("<PlayMedia>");
955 written += o.print(
956 StrView(self->getPossiblePlaybackStorageMedia()).c_str());
957 written += o.print("</PlayMedia>");
958 written += o.print("<RecMedia>");
959 written += o.print(
960 StrView(self->getPossibleRecordStorageMedia()).c_str());
961 written += o.print("</RecMedia>");
962 written += o.print("<RecQualityModes>");
963 written += o.print(
964 StrView(self->getPossibleRecordQualityModes()).c_str());
965 written += o.print("</RecQualityModes>");
966 return written;
967 },
968 ref);
969 },
970 200, nullptr, this);
971 return true;
972 }
973
974 // AVTransport: GetTransportInfo
976 IHttpServer& server, IClientHandler& client) {
977 client.reply(
978 "text/xml",
979 [](Print& out, void* ref) -> size_t {
981 out, "GetTransportInfoResponse", "AVTransport",
982 [](Print& o, void* innerRef) -> size_t {
983 auto self = (DLNAMediaRenderer*)innerRef;
984 size_t written = 0;
985 // CurrentTransportState
986 written += o.print("<CurrentTransportState>");
987 written += o.print(self->getTransportState());
988 written += o.print("</CurrentTransportState>");
989
990 // CurrentTransportStatus - return OK by default
991 written += o.print(
992 "<CurrentTransportStatus>OK</CurrentTransportStatus>");
993
994 // CurrentSpeed - simple renderer: report "1"
995 written += o.print("<CurrentSpeed>1</CurrentSpeed>");
996 return written;
997 },
998 ref);
999 },
1000 200, nullptr, this);
1001 return true;
1002 }
1003
1004 // AVTransport: GetPositionInfo
1006 IHttpServer& server, IClientHandler& client) {
1007 client.reply(
1008 "text/xml",
1009 [](Print& out, void* ref) -> size_t {
1011 out, "GetPositionInfoResponse", "AVTransport",
1012 [](Print& o, void* innerRef) -> size_t {
1013 auto self = (DLNAMediaRenderer*)innerRef;
1014 size_t written = 0;
1015 const bool hasUri = self->getCurrentUri() && *self->getCurrentUri();
1016
1017 // Track (1 if URI present, else 0)
1018 written += o.print("<Track>");
1019 written += o.print(hasUri ? 1 : 0);
1020 written += o.print("</Track>");
1021
1022 // TrackDuration (unknown -> 00:00:00)
1023 written += o.print("<TrackDuration>00:00:00</TrackDuration>");
1024
1025 // TrackMetaData (DIDL-Lite or empty)
1026 written += o.print("<TrackMetaData>");
1027 written += o.print(StrView(self->getCurrentUriMetadata()).c_str());
1028 written += o.print("</TrackMetaData>");
1029
1030 // TrackURI
1031 written += o.print("<TrackURI>");
1032 written += o.print(StrView(self->getCurrentUri()).c_str());
1033 written += o.print("</TrackURI>");
1034
1035 // RelTime (hh:mm:ss based on getRelativeTimePositionSec)
1036 unsigned long secs = self->getRelativeTimePositionSec();
1037 int h = static_cast<int>(secs / 3600);
1038 int m = static_cast<int>((secs % 3600) / 60);
1039 int s = static_cast<int>(secs % 60);
1040 written += o.print("<RelTime>");
1041 if (h < 10) written += o.print('0');
1042 written += o.print(h);
1043 written += o.print(':');
1044 if (m < 10) written += o.print('0');
1045 written += o.print(m);
1046 written += o.print(':');
1047 if (s < 10) written += o.print('0');
1048 written += o.print(s);
1049 written += o.print("</RelTime>");
1050
1051 // AbsTime (unknown -> 00:00:00)
1052 written += o.print("<AbsTime>00:00:00</AbsTime>");
1053
1054 // RelCount, AbsCount (unknown -> 2147483647)
1055 written += o.print("<RelCount>2147483647</RelCount>");
1056 written += o.print("<AbsCount>2147483647</AbsCount>");
1057
1058 return written;
1059 },
1060 ref);
1061 },
1062 200, nullptr, this);
1063 return true;
1064 }
1065
1066 // AVTransport: GetTransportSettings
1068 IHttpServer& server, IClientHandler& client) {
1069 client.reply(
1070 "text/xml",
1071 [](Print& out, void* ref) -> size_t {
1073 out, "GetTransportSettingsResponse", "AVTransport",
1074 [](Print& o, void* innerRef) -> size_t {
1075 auto self = (DLNAMediaRenderer*)innerRef;
1076 size_t written = 0;
1077 // PlayMode: report configured play mode
1078 written += o.print("<PlayMode>");
1079 written += o.print(StrView(self->getPlayMode()).c_str());
1080 written += o.print("</PlayMode>");
1081
1082 // RecQualityMode: single value - report NOT_IMPLEMENTED by
1083 // default
1084 written += o.print("<RecQualityMode>");
1085 written += o.print("NOT_IMPLEMENTED");
1086 written += o.print("</RecQualityMode>");
1087 return written;
1088 },
1089 ref);
1090 },
1091 200, nullptr, this);
1092 return true;
1093 }
1094
1095 // AVTransport: GetMediaInfo
1097 client.reply(
1098 "text/xml",
1099 [](Print& out, void* ref) -> size_t {
1101 out, "GetMediaInfoResponse", "AVTransport",
1102 [](Print& o, void* innerRef) -> size_t {
1103 auto self = (DLNAMediaRenderer*)innerRef;
1104 size_t written = 0;
1105 // NrTracks: simple heuristic - 1 if a URI is present, 0
1106 // otherwise
1107 written += o.print("<NrTracks>");
1108 written += o.print(
1109 self->getCurrentUri() && *self->getCurrentUri() ? 1 : 0);
1110 written += o.print("</NrTracks>");
1111
1112 // MediaDuration: unknown here -> empty string
1113 written += o.print("<MediaDuration></MediaDuration>");
1114
1115 // CurrentURI and CurrentURIMetaData
1116 written += o.print("<CurrentURI>");
1117 written += o.print(StrView(self->getCurrentUri()).c_str());
1118 written += o.print("</CurrentURI>");
1119 written += o.print("<CurrentURIMetaData>");
1120 written +=
1121 o.print(StrView(self->getCurrentUriMetadata()).c_str());
1122 written += o.print("</CurrentURIMetaData>");
1123
1124 // NextURI and NextURIMetaData: not supported -> empty
1125 written += o.print("<NextURI>NOT_IMPLEMENTED</NextURI>");
1126 written += o.print(
1127 "<NextURIMetaData>NOT_IMPLEMENTED</NextURIMetaData>");
1128
1129 // PlayMedium / RecordMedium / WriteStatus: use configured
1130 // defaults
1131 written += o.print("<PlayMedium>");
1132 written += o.print(
1133 StrView(self->getPossiblePlaybackStorageMedia()).c_str());
1134 written += o.print("</PlayMedium>");
1135
1136 written += o.print("<RecordMedium>");
1137 written += o.print(
1138 StrView(self->getPossibleRecordStorageMedia()).c_str());
1139 written += o.print("</RecordMedium>");
1140
1141 written +=
1142 o.print("<WriteStatus>NOT_IMPLEMENTED</WriteStatus>");
1143
1144 return written;
1145 },
1146 ref);
1147 },
1148 200, nullptr, this);
1149 return true;
1150 }
1151
1153 IHttpServer& server, IClientHandler& client) {
1154 const char* uri = action.getArgumentValue("CurrentURI");
1155 current_uri_metadata = action.getArgumentValue("CurrentURIMetaData");
1156 if (uri && *uri) {
1157 setPlaybackURL(uri);
1159 client.reply(
1160 "text/xml",
1161 [](Print& out, void* ref) -> size_t {
1162 (void)ref;
1163 return DeviceType::printReplyXML(out, "SetAVTransportURIResponse",
1164 "AVTransport");
1165 },
1166 200, nullptr, this);
1167 return true;
1168 } else {
1169 DlnaLogger.log(DlnaLogLevel::Warning,
1170 "SetAVTransportURI called with invalid SOAP payload");
1171 client.replyError(400, "Invalid Action");
1172 return false;
1173 }
1174 }
1175
1177 int desiredVolume = action.getArgumentIntValue("DesiredVolume");
1178 setVolume((uint8_t)desiredVolume);
1180 client.reply(
1181 "text/xml",
1182 [](Print& out, void* ref) -> size_t {
1183 (void)ref;
1184 return DeviceType::printReplyXML(out, "SetVolumeResponse",
1185 "RenderingControl");
1186 },
1187 200, nullptr, this);
1188 return true;
1189 }
1190
1192 bool desiredMute = action.getArgumentIntValue("DesiredMute") != 0;
1193 setMuted(desiredMute);
1195 client.reply(
1196 "text/xml",
1197 [](Print& out, void* ref) -> size_t {
1198 (void)ref;
1199 return DeviceType::printReplyXML(out, "SetMuteResponse",
1200 "RenderingControl");
1201 },
1202 200, nullptr, this);
1203 return true;
1204 }
1205
1207 client.reply(
1208 "text/xml",
1209 [](Print& out, void* ref) -> size_t {
1211 out, "GetMuteResponse", "RenderingControl",
1212 [](Print& o, void* innerRef) -> size_t {
1213 auto self = (DLNAMediaRenderer*)innerRef;
1214 size_t written = 0;
1215 written += o.print("<CurrentMute>");
1216 written += o.print(self->isMuted() ? 1 : 0);
1217 written += o.print("</CurrentMute>");
1218 return written;
1219 },
1220 ref);
1221 },
1222 200, nullptr, this);
1223 return true;
1224 }
1225
1227 client.reply(
1228 "text/xml",
1229 [](Print& out, void* ref) -> size_t {
1231 out, "GetVolumeResponse", "RenderingControl",
1232 [](Print& o, void* innerRef) -> size_t {
1233 auto self = (DLNAMediaRenderer*)innerRef;
1234 DlnaLogger.log(DlnaLogLevel::Debug, "GetVolume: %d",
1235 self->getVolume());
1236 size_t written = 0;
1237 written += o.print("<CurrentVolume>");
1238 written += o.print((int)self->getVolume());
1239 written += o.print("</CurrentVolume>");
1240 return written;
1241 },
1242 ref);
1243 },
1244 200, nullptr, this);
1245 return true;
1246 }
1247
1249 void setupRules() {
1250 rules.push_back({"ListPresets", [](DLNAMediaRenderer* self, ActionRequest& action, IHttpServer& server, IClientHandler& client) {
1251 return self->processActionListPresets(action, server, client);
1252 }});
1253 rules.push_back({"Play", [](DLNAMediaRenderer* self, ActionRequest& action, IHttpServer& server, IClientHandler& client) {
1254 return self->processActionPlay(action, server, client);
1255 }});
1256 rules.push_back({"Pause", [](DLNAMediaRenderer* self, ActionRequest& action, IHttpServer& server, IClientHandler& client) {
1257 return self->processActionPause(action, server, client);
1258 }});
1259 rules.push_back({"Stop", [](DLNAMediaRenderer* self, ActionRequest& action, IHttpServer& server, IClientHandler& client) {
1260 return self->processActionStop(action, server, client);
1261 }});
1262 rules.push_back({"GetCurrentTransportActions", [](DLNAMediaRenderer* self, ActionRequest& action, IHttpServer& server, IClientHandler& client) {
1263 return self->processActionGetCurrentTransportActions(action, server, client);
1264 }});
1265 rules.push_back({"GetTransportInfo", [](DLNAMediaRenderer* self, ActionRequest& action, IHttpServer& server, IClientHandler& client) {
1266 return self->processActionGetTransportInfo(action, server, client);
1267 }});
1268 rules.push_back({"GetTransportSettings", [](DLNAMediaRenderer* self, ActionRequest& action, IHttpServer& server, IClientHandler& client) {
1269 return self->processActionGetTransportSettings(action, server, client);
1270 }});
1271 rules.push_back({"GetPositionInfo", [](DLNAMediaRenderer* self, ActionRequest& action, IHttpServer& server, IClientHandler& client) {
1272 return self->processActionGetPositionInfo(action, server, client);
1273 }});
1274 rules.push_back({"GetMediaInfo", [](DLNAMediaRenderer* self, ActionRequest& action, IHttpServer& server, IClientHandler& client) {
1275 return self->processActionGetMediaInfo(action, server, client);
1276 }});
1277 rules.push_back({"GetDeviceCapabilities", [](DLNAMediaRenderer* self, ActionRequest& action, IHttpServer& server, IClientHandler& client) {
1278 return self->processActionGetDeviceCapabilities(action, server, client);
1279 }});
1280 rules.push_back({"SetAVTransportURI", [](DLNAMediaRenderer* self, ActionRequest& action, IHttpServer& server, IClientHandler& client) {
1281 return self->processActionSetAVTransportURI(action, server, client);
1282 }});
1283 rules.push_back({"SetVolume", [](DLNAMediaRenderer* self, ActionRequest& action, IHttpServer& server, IClientHandler& client) {
1284 return self->processActionSetVolume(action, server, client);
1285 }});
1286 rules.push_back({"SetMute", [](DLNAMediaRenderer* self, ActionRequest& action, IHttpServer& server, IClientHandler& client) {
1287 return self->processActionSetMute(action, server, client);
1288 }});
1289 rules.push_back({"GetMute", [](DLNAMediaRenderer* self, ActionRequest& action, IHttpServer& server, IClientHandler& client) {
1290 return self->processActionGetMute(action, server, client);
1291 }});
1292 rules.push_back({"GetVolume", [](DLNAMediaRenderer* self, ActionRequest& action, IHttpServer& server, IClientHandler& client) {
1293 return self->processActionGetVolume(action, server, client);
1294 }});
1295 // ConnectionManager rules
1296 rules.push_back(
1297 {"GetProtocolInfo", [](DLNAMediaRenderer* self, ActionRequest& action,
1298 IHttpServer& server, IClientHandler& client) {
1299 return self->processActionGetProtocolInfo(action, server, client);
1300 }});
1301 rules.push_back({"GetCurrentConnectionIDs",
1302 [](DLNAMediaRenderer* self, ActionRequest& action,
1303 IHttpServer& server, IClientHandler& client) {
1305 action, server, client);
1306 }});
1307 rules.push_back({"GetCurrentConnectionInfo",
1308 [](DLNAMediaRenderer* self, ActionRequest& action,
1309 IHttpServer& server, IClientHandler& client) {
1311 action, server, client);
1312 }});
1313 }
1314};
1315
1316} // namespace tiny_dlna
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 setModelName(const char *name)
Definition: DLNADeviceInfo.h:166
void setSerialNumber(const char *sn)
Definition: DLNADeviceInfo.h:170
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
bool is_active
Definition: DLNADeviceInfo.h:283
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 size_t printReplyXML(Print &out, const char *replyName, const char *serviceId, std::function< size_t(Print &, void *)> valuesWriter=nullptr, void *ref=nullptr)
Builds a standard SOAP reply envelope.
Definition: DLNADevice.h:334
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
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
ConnectionManager service descriptor (SCPD) generator.
Definition: DLNAMediaRendererDescr.h:596
RenderingControl service descriptor (SCPD) generator.
Definition: DLNAMediaRendererDescr.h:402
AVTransport service descriptor (SCPD) generator.
Definition: DLNAMediaRendererDescr.h:19
MediaRenderer DLNA Device.
Definition: DLNAMediaRenderer.h:70
DLNADescr & getControlDescr()
Get the control SCPD descriptor reference.
Definition: DLNAMediaRenderer.h:502
void setPlaybackCompleted()
Notify the renderer that playback completed.
Definition: DLNAMediaRenderer.h:377
bool processActionGetPositionInfo(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Definition: DLNAMediaRenderer.h:1005
void setPossibleRecordStorageMedia(const char *v)
Set possible record storage media (comma-separated list)
Definition: DLNAMediaRenderer.h:145
void setMimeFromDIDL(const char *didl)
Definition: DLNAMediaRenderer.h:621
void setPlayMode(const char *v)
Set current play mode (e.g. NORMAL, REPEAT_ALL, INTRO)
Definition: DLNAMediaRenderer.h:165
size_t getRelativeTimePositionSec()
Get estimated playback position (seconds)
Definition: DLNAMediaRenderer.h:401
void(* MediaEventHandler)(MediaEvent event, DLNAMediaRenderer &renderer)
Definition: DLNAMediaRenderer.h:75
const char * connectionID
Definition: DLNAMediaRenderer.h:532
static void transportDescrCB(IClientHandler &client, IHttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl)
Definition: DLNAMediaRenderer.h:634
void setMime(const char *mime)
Set MIME explicitly (used when DIDL-Lite metadata provides protocolInfo)
Definition: DLNAMediaRenderer.h:612
static void controlDescrCB(IClientHandler &client, IHttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl)
Definition: DLNAMediaRenderer.h:676
void publishAVT()
Definition: DLNAMediaRenderer.h:562
DLNADescr * p_transportDescr
Definition: DLNAMediaRenderer.h:543
DLNAMediaRenderer()
Default constructor.
Definition: DLNAMediaRenderer.h:85
void setUdpService(IUDPService &udp)
Set the UDP service instance the MediaRenderer should use.
Definition: DLNAMediaRenderer.h:132
DLNAMediaRenderer(IHttpServer &server, IUDPService &udp)
Recommended constructor Construct a MediaRenderer bound to an HTTP server and IUDPService....
Definition: DLNAMediaRenderer.h:105
void setMediaEventHandler(MediaEventHandler cb)
Register application event handler.
Definition: DLNAMediaRenderer.h:213
tiny_dlna::Str current_mime
Definition: DLNAMediaRenderer.h:518
static void eventSubscriptionHandler(IClientHandler &client, IHttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl)
After the subscription we publish all relevant properties.
Definition: DLNAMediaRenderer.h:725
const char * getCurrentTransportActions()
Get a csv of the valid actions.
Definition: DLNAMediaRenderer.h:433
void addChange(const char *serviceAbbrev, std::function< size_t(Print &, void *)> changeWriter)
serviceAbbrev: AVT, RCS, CMS
Definition: DLNAMediaRenderer.h:555
void publishRCS()
Publish the current RenderingControl state (Volume, Mute)
Definition: DLNAMediaRenderer.h:587
const char * st
Definition: DLNAMediaRenderer.h:527
uint8_t getVolume()
Get current volume (0-100)
Definition: DLNAMediaRenderer.h:216
bool processActionGetProtocolInfo(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Definition: DLNAMediaRenderer.h:902
bool processActionGetTransportInfo(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Definition: DLNAMediaRenderer.h:975
bool play()
Start playback: same as setActive(true)
Definition: DLNAMediaRenderer.h:278
void setActive(bool active)
Set the active state (used by transport callbacks)
Definition: DLNAMediaRenderer.h:174
void setMuted(bool mute)
Set mute state and publish event.
Definition: DLNAMediaRenderer.h:237
DLNAMediaRendererConnectionMgrDescr default_connmgr_desc
Definition: DLNAMediaRenderer.h:546
bool setPlaybackURL(const char *urlStr)
Defines the actual url to play.
Definition: DLNAMediaRenderer.h:320
void setConnectionMgrDescr(DLNADescr &d)
Set the ConnectionManager SCPD descriptor (non-owning reference).
Definition: DLNAMediaRenderer.h:505
tiny_dlna::Str transport_state
Definition: DLNAMediaRenderer.h:526
bool processActionPause(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Definition: DLNAMediaRenderer.h:851
DLNADescr & getConnectionMgrDescr()
Get the ConnectionManager SCPD descriptor reference.
Definition: DLNAMediaRenderer.h:508
const char * sourceProto
Definition: DLNAMediaRenderer.h:533
const char * currentPlayMode
Definition: DLNAMediaRenderer.h:538
bool processActionSetAVTransportURI(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Definition: DLNAMediaRenderer.h:1152
uint8_t current_volume
Definition: DLNAMediaRenderer.h:521
bool processActionGetCurrentConnectionInfo(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Definition: DLNAMediaRenderer.h:930
bool processActionSetMute(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Definition: DLNAMediaRenderer.h:1191
tiny_dlna::Str current_uri
Definition: DLNAMediaRenderer.h:517
void setCustomActionRule(const char *suffix, bool(*handler)(DLNAMediaRenderer *, ActionRequest &, IHttpServer &))
Defines a custom action rule for the media renderer.
Definition: DLNAMediaRenderer.h:444
void setupServicesImpl(IHttpServer *server)
Register all services (called when HTTP server is set)
Definition: DLNAMediaRenderer.h:782
const char * getTransportState()
Get textual transport state.
Definition: DLNAMediaRenderer.h:264
const char * getCurrentUri()
Access current URI.
Definition: DLNAMediaRenderer.h:258
const char * getCurrentUriMetadata()
Access the metadata as string.
Definition: DLNAMediaRenderer.h:261
bool processActionPlay(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Definition: DLNAMediaRenderer.h:820
bool play(const char *urlStr)
Start playback of a network resource (returns true on success)
Definition: DLNAMediaRenderer.h:284
void setTransportDescr(DLNADescr &d)
Set the transport SCPD descriptor (non-owning reference).
Definition: DLNAMediaRenderer.h:493
const char * getConnectionID()
Return the currently configured ConnectionID.
Definition: DLNAMediaRenderer.h:460
bool loop(int loopAction=RUN_ALL)
Call this from Arduino loop()
Definition: DLNAMediaRenderer.h:121
const char * sinkProto
Definition: DLNAMediaRenderer.h:534
Vector< ActionRule > rules
Definition: DLNAMediaRenderer.h:539
bool processActionGetCurrentTransportActions(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Definition: DLNAMediaRenderer.h:878
const char * getSinkProtocols()
Get the current sink ProtocolInfo string.
Definition: DLNAMediaRenderer.h:490
bool processActionListPresets(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Definition: DLNAMediaRenderer.h:834
void publishCMS()
Publish a minimal ConnectionManager state (CurrentConnectionIDs)
Definition: DLNAMediaRenderer.h:602
bool begin()
Start the underlying DLNA device using the stored server/udp.
Definition: DLNAMediaRenderer.h:112
IUDPService * p_udp_member
Definition: DLNAMediaRenderer.h:531
IDevice & device()
Provides access to the internal DLNA device instance.
Definition: DLNAMediaRenderer.h:267
DLNAMediaRendererTransportDescr default_transport_desc
Definition: DLNAMediaRenderer.h:542
const char * getSourceProtocols()
Get the current source ProtocolInfo string.
Definition: DLNAMediaRenderer.h:487
DLNADescr * p_connmgrDescr
Definition: DLNAMediaRenderer.h:547
void setupConnectionManagerService(IHttpServer *server)
Definition: DLNAMediaRenderer.h:757
DeviceType dlna_device
Definition: DLNAMediaRenderer.h:529
bool stop()
Stop playback.
Definition: DLNAMediaRenderer.h:347
const char * getMime()
Provides the mime from the DIDL or nullptr.
Definition: DLNAMediaRenderer.h:206
bool processActionGetCurrentConnectionIDs(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Definition: DLNAMediaRenderer.h:916
DLNAMediaRendererControlDescr default_control_desc
Definition: DLNAMediaRenderer.h:544
const char * getPossibleRecordQualityModes() const
Get possible record quality modes.
Definition: DLNAMediaRenderer.h:160
bool processActionGetDeviceCapabilities(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Definition: DLNAMediaRenderer.h:944
bool isSubscriptionsActive()
Query whether subscription notifications are active.
Definition: DLNAMediaRenderer.h:275
tiny_dlna::Str current_uri_metadata
Definition: DLNAMediaRenderer.h:519
void setConnectionID(const char *id)
Set the active ConnectionID for the connection manager.
Definition: DLNAMediaRenderer.h:457
bool processActionGetTransportSettings(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Definition: DLNAMediaRenderer.h:1067
bool processActionSetVolume(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Definition: DLNAMediaRenderer.h:1176
const char * possiblePlaybackStorageMedia
Definition: DLNAMediaRenderer.h:535
ClientType HttpClient
Definition: DLNAMediaRenderer.h:72
const char * getPossiblePlaybackStorageMedia() const
Get possible playback storage media.
Definition: DLNAMediaRenderer.h:140
void setProtocols(const char *source, const char *sink="")
Define the source protocol info: use csv Default is http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN,...
Definition: DLNAMediaRenderer.h:467
uint8_t muted_volume
Definition: DLNAMediaRenderer.h:522
bool processActionGetMute(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Definition: DLNAMediaRenderer.h:1206
void setVolume(uint8_t vol)
Set volume and publish event (0-100)
Definition: DLNAMediaRenderer.h:219
bool processAction(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Process parsed SOAP ActionRequest and dispatch to appropriate handler.
Definition: DLNAMediaRenderer.h:798
bool processActionStop(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Definition: DLNAMediaRenderer.h:864
const char * usn
Definition: DLNAMediaRenderer.h:528
void setSubscriptionsActive(bool flag)
Enable/disable subscription notifications.
Definition: DLNAMediaRenderer.h:270
void setHttpServer(IHttpServer &server)
Set the http server instance the MediaRenderer should use.
Definition: DLNAMediaRenderer.h:124
const char * possibleRecordQualityModes
Definition: DLNAMediaRenderer.h:537
void setControlDescr(DLNADescr &d)
Set the control SCPD descriptor (non-owning reference).
Definition: DLNAMediaRenderer.h:499
unsigned long start_time
Definition: DLNAMediaRenderer.h:523
IHttpServer * p_server
Definition: DLNAMediaRenderer.h:530
void setupTransportService(IHttpServer *server)
Definition: DLNAMediaRenderer.h:744
unsigned long time_sum
Definition: DLNAMediaRenderer.h:524
void setupRules()
Setup the action handling rules.
Definition: DLNAMediaRenderer.h:1249
void publishGetRelativeTimePositionSec()
Publish the RelativeTimePosition property.
Definition: DLNAMediaRenderer.h:407
bool processActionGetMediaInfo(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Definition: DLNAMediaRenderer.h:1096
const char * getPlayMode() const
Get current play mode.
Definition: DLNAMediaRenderer.h:168
bool isMuted()
Query mute state.
Definition: DLNAMediaRenderer.h:234
bool processActionGetVolume(ActionRequest &action, IHttpServer &server, IClientHandler &client)
Definition: DLNAMediaRenderer.h:1226
void end()
Stops processing and releases resources.
Definition: DLNAMediaRenderer.h:115
const char * possibleRecordStorageMedia
Definition: DLNAMediaRenderer.h:536
bool isActive()
Query whether renderer is active (playing)
Definition: DLNAMediaRenderer.h:171
DLNADescr & getTransportDescr()
Get the transport SCPD descriptor reference.
Definition: DLNAMediaRenderer.h:496
const char * getPossibleRecordStorageMedia() const
Get possible record storage media.
Definition: DLNAMediaRenderer.h:150
static void connmgrDescrCB(IClientHandler &client, IHttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl)
Definition: DLNAMediaRenderer.h:655
DLNADescr * p_controlDescr
Definition: DLNAMediaRenderer.h:545
static DLNAMediaRenderer * getRenderer(IHttpServer *server)
Determine the Renderer with the help of the server.
Definition: DLNAMediaRenderer.h:718
void setPossiblePlaybackStorageMedia(const char *v)
Set possible playback storage media (comma-separated list)
Definition: DLNAMediaRenderer.h:135
void setPossibleRecordQualityModes(const char *v)
Set possible record quality modes (comma-separated list)
Definition: DLNAMediaRenderer.h:155
void setupRenderingControlService(IHttpServer *server)
Definition: DLNAMediaRenderer.h:769
MediaEventHandler event_cb
Definition: DLNAMediaRenderer.h:520
static void controlCB(IClientHandler &client, IHttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl)
Definition: DLNAMediaRenderer.h:698
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
const char * get(const char *key)
Definition: HttpHeader.h:161
Used to register and process callbacks.
Definition: HttpRequestHandlerLine.h:12
Definition: IHttpServer.h:19
virtual HttpRequestHeader & requestHeader()=0
virtual void replyNotFound()=0
virtual void reply(const char *contentType, Stream &inputStream, int size, int status=200, const char *msg=SUCCESS)=0
virtual void replyError(int err, const char *msg="Internal Server Error")=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
virtual void setReference(void *reference)=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
size_t printf(const char *fmt,...)
Definition: Printf.h:16
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 const char * c_str()
provides the string value as const char*
Definition: StrView.h:376
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
bool isEmpty() const
True if empty.
Definition: Str.h:54
void set(const char *v)
Assign from C-string (nullptr -> empty)
Definition: Str.h:120
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
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
#define DLNA_PROTOCOL_AUDIO
All possible audio protocols.
Definition: dlna_config.h:154
Definition: Allocator.h:13
MediaEvent
Events emitted by the MediaRenderer to notify the application will receive the event along with a ref...
Definition: DLNAMediaRenderer.h:32
@ RUN_ALL
Definition: IDevice.h:18
void(* http_callback)(IClientHandler &client, IHttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl)
Definition: DLNAServiceInfo.h:11
Individual action rule for handling specific actions.
Definition: DLNAMediaRenderer.h:512
const char * suffix
Definition: DLNAMediaRenderer.h:513
bool(* handler)(DLNAMediaRenderer *, ActionRequest &, IHttpServer &, IClientHandler &)
Definition: DLNAMediaRenderer.h:514