Arduino DLNA Server
Loading...
Searching...
No Matches
DLNADevice.h
Go to the documentation of this file.
1#pragma once
2
3#include <functional>
4
5#include "basic/Printf.h"
6#include "basic/Url.h"
8#include "dlna/Schedule.h"
14#include "http/Http.h"
16
17namespace tiny_dlna {
18
38template <typename ClientType>
39class DLNADevice : public IDevice {
40 public:
42 // distribute initial subscription active flag to subscription manager
44 }
46 bool begin(DLNADeviceInfo& device, IUDPService& udp,
47 IHttpServer& server) override {
48 DlnaLogger.log(DlnaLogLevel::Info, "DLNADevice::begin");
49 server.setReference(this);
50 p_server = &server;
51 p_udp = &udp;
52 setDeviceInfo(device);
54
55 // check base url
56 const char* baseUrl = device.getBaseURL();
57 DlnaLogger.log(DlnaLogLevel::Info, "base URL: %s", baseUrl);
58
59 if (StrView(device.getBaseURL()).contains("localhost")) {
60 DlnaLogger.log(DlnaLogLevel::Error, "invalid base address: %s", baseUrl);
61 return false;
62 }
63
64 // setup device
65 device.setupServices(server, udp);
66
67 // ensure services reflect the current subscriptions-active flag
68 // (some callers rely on subscriptions being disabled by default)
70
71 // setup web server
72 if (!setupDLNAServer(server)) {
73 DlnaLogger.log(DlnaLogLevel::Error, "setupDLNAServer failed");
74 return false;
75 }
76
77 // start web server
78 Url url{baseUrl};
79 if (!p_server->begin()) {
80 DlnaLogger.log(DlnaLogLevel::Error, "Server failed");
81 return false;
82 }
83
84 // setup UDP
85 if (!p_udp->begin(DLNABroadcastAddress)) {
86 DlnaLogger.log(DlnaLogLevel::Error, "UDP begin failed");
87 return false;
88 }
89
90 // setup scheduler
91 if (!setupScheduler()) {
92 DlnaLogger.log(DlnaLogLevel::Error, "Scheduler failed");
93 return false;
94 }
95 // initialize scheduling timers so the scheduled tasks run immediately
96 uint64_t now = millis();
97 // set next timeouts to now so the first loop triggers the tasks
100
101 is_active = true;
102 DlnaLogger.log(DlnaLogLevel::Info, "Device successfully started");
103 return true;
104 }
105
107 return subscription_mgr;
108 }
109
111 void end() override {
112 DlnaLogger.log(DlnaLogLevel::Info, "DLNADevice::end");
113 p_server->end();
114
115 // send 3 bye messages
117 bye->repeat_ms = 800;
118 scheduler.add(bye);
119
120 // execute scheduler for 2 seconds
121 uint64_t end = millis() + 2000;
122 while (millis() < end) {
124 }
125
126 // end subscription manager
128
129 is_active = false;
130 }
131
134 bool loop(int loopAction = RUN_ALL) override {
135 if (!is_active) return false;
136 DlnaLogger.log(DlnaLogLevel::Debug, "loop");
137 // Platform-specific periodic diagnostics (e.g. ESP32 memory logging)
139 bool rc = false;
140
141 // handle server requests
142 if (loopAction & RUN_SERVER) {
143 rc = loopServer();
144 }
145
146 // Use millisecond-based intervals for scheduling so callers can set
147 // real-time intervals instead of loop-counts.
148 uint64_t now = millis();
149 if ((loopAction & RUN_UDP) && isSchedulerActive() &&
151 int count = loopUDPMessages();
152 if (count > 0) rc = true;
153 // schedule next run
155 }
156
157 // deliver any queued subscription notifications (if enabled)
158 if ((loopAction & RUN_SUBSCRIPTIONS) && isSubscriptionsActive() &&
160 int count = loopPublishSubscriptions();
161 if (count > 0) rc = true;
162 // schedule next run
164 }
165
166 // be nice, if we have other tasks
167 if (!rc) delay(DLNA_LOOP_DELAY_MS);
168 return true;
169 }
170
172 int loopPublishSubscriptions() { return subscription_mgr.publish(); }
173
175 bool loopServer() override {
176 DlnaLogger.log(DlnaLogLevel::Debug, "loopServer");
177 if (!is_active) return false;
178 bool rc = p_server->doLoop();
179 DlnaLogger.log(DlnaLogLevel::Debug, "server %s", rc ? "true" : "false");
180 return rc;
181 }
182
185 // process UDP requests
186 DlnaLogger.log(DlnaLogLevel::Debug, "loopUDPMessages");
187 RequestData req = p_udp->receive();
188 if (req) {
189 Schedule* schedule = parser.parse(*p_device_info, req);
190 if (schedule != nullptr) {
191 scheduler.add(schedule);
192 }
193 }
194
195 // execute scheduled udp replys
196 return scheduler.execute(*p_udp);
197 }
198
200 DLNAServiceInfo& getService(const char* id) override {
201 return p_device_info->getService(id);
202 }
203
205 DLNAServiceInfo& getServiceByAbbrev(const char* abbrev) override {
206 return p_device_info->getServiceByAbbrev(abbrev);
207 }
208
212 DLNAServiceInfo* getServiceByEventPath(const char* requestPath) override {
213 DlnaLogger.log(DlnaLogLevel::Debug, "getServiceByEventPath");
214 if (p_device_info == nullptr || requestPath == nullptr) return nullptr;
216 if (StrView(s.event_sub_url).equals(requestPath)) {
217 return &s;
218 }
219 }
220 return nullptr;
221 }
222
224 void addChange(const char* serviceAbbrev,
225 std::function<size_t(Print&, void*)> changeWriter,
226 void* ref) override {
227 DlnaLogger.log(DlnaLogLevel::Debug, "addChange");
228 auto& mgr = getSubscriptionMgr();
229 DLNAServiceInfo& serviceInfo = getServiceByAbbrev(serviceAbbrev);
230 if (!serviceInfo) {
231 DlnaLogger.log(DlnaLogLevel::Warning,
232 "addChange: No service info available for %s",
233 serviceAbbrev);
234 return;
235 }
236 mgr.addChange(serviceInfo, changeWriter, ref);
237 }
238
241
243 void setSchedulerActive(bool flag) override { scheduler.setActive(flag); }
244
246 bool isSchedulerActive() override { return scheduler.isActive(); }
247
250 void setPostAliveRepeatMs(uint32_t ms) override { post_alive_repeat_ms = ms; }
251
253 void setSubscriptionsActive(bool flag) override {
255 if (p_device_info != nullptr) {
257 }
259 }
260
262 bool isSubscriptionsActive() const override {
264 }
265
267 static void parseActionRequest(IHttpServer* server, const char* requestPath,
269 ActionRequest& action) {
270 DlnaLogger.log(DlnaLogLevel::Info, "parseActionRequest");
271 auto start = millis();
273 xp.setExpandEncoded(true);
274
275 Str outNodeName;
276 Vector<Str> outPath;
277 Str outText;
278 Str outAttributes;
279 bool is_attribute = false;
280 bool is_action = false;
281 Str actionName;
282 char buffer[XML_PARSER_BUFFER_SIZE];
283 Client& client = server->client();
284
285 while (true) {
286 size_t len = client.readBytes(buffer, sizeof(buffer));
287 if (len == 0) break;
288 xp.write((const uint8_t*)buffer, len);
289
290 while (xp.parse(outNodeName, outPath, outText, outAttributes)) {
291 if (is_attribute) {
292 const char* argName = outNodeName.c_str();
293 action.addArgument(argName, outText.c_str());
294 continue;
295 }
296 if (is_action) {
297 is_action = false;
298 is_attribute = true;
299 action.setAction(outNodeName.c_str());
300 DlnaLogger.log(DlnaLogLevel::Info, "action: %s", action.getAction());
301 continue;
302 }
303 // skip SOAP envelope wrappers
304 if (outNodeName.equals("s:Envelope") || outNodeName.equals("Body")) {
305 continue;
306 }
307 if (outNodeName.equals("s:Body")) {
308 is_action = true;
309 }
310 }
311 }
312 xp.end();
313 DlnaLogger.log(DlnaLogLevel::Info, "Parse took %d ms", millis() - start);
314 }
315
324 static size_t printReplyXML(
325 Print& out, const char* replyName, const char* serviceId,
326 std::function<size_t(Print&, void*)> valuesWriter = nullptr,
327 void* ref = nullptr) {
328 DlnaLogger.log(DlnaLogLevel::Debug, "printReplyXML");
329 XMLPrinter xp(out);
330 size_t result = 0;
331 result += xp.printNodeBegin(
332 "s:Envelope",
333 "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\n");
334 result += xp.printNodeBegin("s:Body");
335 result +=
336 xp.printf("<u:%s xmlns:u=\"urn:schemas-upnp-org:service:%s:1\">\n",
337 replyName, serviceId);
338
339 // e.g.<u:return>Stop,Pause,Next,Seek</u:return> for
340 // QueryStateVariableResponse
341 if (valuesWriter) {
342 result += valuesWriter(out, ref);
343 }
344
345 result += xp.printf("</u:%s>\n", replyName);
346 result += xp.printNodeEnd("s:Body");
347 result += xp.printNodeEnd("s:Envelope");
348 return result;
349 }
354 static size_t replyGetProtocolInfo(Print& out, const char* source = "",
355 const char* sink = "") {
356 DlnaLogger.log(DlnaLogLevel::Debug, "replyGetProtocolInfo");
357 return printReplyXML(out, "GetProtocolInfoResponse", "ConnectionManager",
358 [source, sink](Print& o, void* ref) -> size_t {
359 (void)ref;
360 size_t written = 0;
361 written += o.print("<Source>");
362 written += o.print(StrView(source).c_str());
363 written += o.print("</Source>");
364 written += o.print("<Sink>");
365 written += o.print(StrView(sink).c_str());
366 written += o.print("</Sink>");
367 return written;
368 });
369 }
370
371 static size_t replyGetCurrentConnectionIDs(Print& out, const char* ids) {
372 DlnaLogger.log(DlnaLogLevel::Debug, "replyGetCurrentConnectionIDs");
373 return printReplyXML(out, "GetCurrentConnectionIDsResponse",
374 "ConnectionManager",
375 [ids](Print& o, void* ref) -> size_t {
376 (void)ref;
377 size_t written = 0;
378 // UPnP spec uses "CurrentConnectionIDs" as the
379 // response element name
380 written += o.print("<CurrentConnectionIDs>");
381 written += o.print(StrView(ids ? ids : "0").c_str());
382 written += o.print("</CurrentConnectionIDs>");
383 return written;
384 });
385 }
386
387 static size_t replyGetCurrentConnectionInfo(Print& out,
388 const char* protocolInfo,
389 const char* connectionID,
390 const char* direction) {
391 DlnaLogger.log(DlnaLogLevel::Debug, "handleSubscription");
392 return printReplyXML(
393 out, "GetCurrentConnectionInfoResponse", "ConnectionManager",
394 [protocolInfo, connectionID, direction](Print& o, void* ref) -> size_t {
395 (void)ref;
396 size_t written = 0;
397 // Write directly to out to avoid using a fixed-size intermediate
398 // buffer.
399 written += o.print("<RcsID>0</RcsID>");
400 written += o.print("<AVTransportID>0</AVTransportID>");
401 written += o.print("<ProtocolInfo>");
402 written += o.print(StrView(protocolInfo).c_str());
403 written += o.print("</ProtocolInfo>");
404 written += o.print("<PeerConnectionManager></PeerConnectionManager>");
405 written += o.print("<PeerConnectionID>");
406 written += o.print(StrView(connectionID).c_str());
407 written += o.print("</PeerConnectionID>");
408 written += o.print("<Direction>");
409 written += o.print(StrView(direction).c_str());
410 written += o.print("</Direction>");
411 written += o.print("<Status>OK</Status>");
412 return written;
413 });
414 }
415
417 static bool handleSubscription(IHttpServer* server, const char* requestPath,
419 bool& is_subscribe) {
420 DlnaLogger.log(DlnaLogLevel::Debug, "handleSubscription");
421 // logic separated and easier to test.
422 is_subscribe = false;
423 HttpRequestHeader& req = server->requestHeader();
424 if (req.method() == T_SUBSCRIBE) {
425 is_subscribe = true;
426 return handleSubscribe(server, requestPath, hl);
427 }
428 if (req.method() == T_UNSUBSCRIBE) {
429 return handleUnsubscribe(server, requestPath, hl);
430 }
431
432 // default reply OK for other methods
433 server->replyError(501, "Unsupported Method");
434 return false;
435 }
436
438 void setReference(void* ref) override { reference = ref; }
439
441 void* getReference() override { return reference; }
442
443 void logStatus() {
444 DlnaLogger.log(DlnaLogLevel::Info,
445 "Subscriptions: active=%d pending=%d / Scheduler: size=%d "
446 "active = %s",
447 subscription_mgr.subscriptionsCount(),
448 subscription_mgr.pendingCount(), scheduler.size(),
449 isSchedulerActive() ? "true" : "false");
450#ifdef ESP32
451 DlnaLogger.log(DlnaLogLevel::Info, "Memory: freeHeap=%u freePsram=%u",
452 (unsigned)ESP.getFreeHeap(), (unsigned)ESP.getFreePsram());
453#endif
454 }
455
456 protected:
457 bool is_active = false;
464 IUDPService* p_udp = nullptr;
471 void* reference = nullptr;
472
474 DlnaLogger.log(DlnaLogLevel::Debug, "setDeviceInfo");
475 p_device_info = &device;
477 }
478
481
483 uint32_t getSchedulerIntervalMs() const {
484 return (uint32_t)scheduler_interval_ms;
485 }
486
488 void setSubscriptionsIntervalMs(uint32_t ms) {
490 }
491
493 uint32_t getSubscriptionsIntervalMs() const {
494 return (uint32_t)subscriptions_interval_ms;
495 }
496
500 void logScheduledStatus(bool runImmediately = false) {
501 static uint64_t last_mem_log = 0;
502 const uint64_t MEM_LOG_INTERVAL_MS = 10000;
503 uint64_t now = millis();
504 if (runImmediately ||
505 (uint64_t)(now - last_mem_log) >= MEM_LOG_INTERVAL_MS) {
506 // update timestamp for next interval on all platforms
507 last_mem_log = now;
508 logStatus();
509 }
510 }
511
514 bool setupParser() {
515 DlnaLogger.log(DlnaLogLevel::Debug, "setupParser");
516 parser.addMSearchST("upnp:rootdevice");
517 parser.addMSearchST("ssdp:all");
520 return true;
521 }
522
525 DlnaLogger.log(DlnaLogLevel::Debug, "setupScheduler");
526 // schedule post alive messages: Usually repeated 2 times (because UDP
527 // messages might be lost)
528 PostAliveSchedule* postAlive =
530 PostAliveSchedule* postAlive1 =
532 postAlive1->time = millis() + 100;
533 scheduler.add(postAlive);
534 scheduler.add(postAlive1);
535 return true;
536 }
537
540 DlnaLogger.log(DlnaLogLevel::Debug, "validateServiceInfo");
541 bool has_error = false;
542
543 if (!service.scpd_url || !*service.scpd_url) {
544 DlnaLogger.log(DlnaLogLevel::Error, "Service missing scpd_url");
545 has_error = true;
546 }
547 if (!service.control_url || !*service.control_url) {
548 DlnaLogger.log(DlnaLogLevel::Error, "Service missing control_url");
549 has_error = true;
550 }
551 if (!service.event_sub_url || !*service.event_sub_url) {
552 DlnaLogger.log(DlnaLogLevel::Error, "Service missing event_sub_url");
553 has_error = true;
554 }
555 if (!service.scp_cb) {
556 DlnaLogger.log(DlnaLogLevel::Error, "Service missing scp_cb for %s",
557 service.scpd_url ? service.scpd_url : "(null)");
558 has_error = true;
559 }
560 if (!service.control_cb) {
561 DlnaLogger.log(DlnaLogLevel::Error, "Service missing control_cb for %s",
562 service.control_url ? service.control_url : "(null)");
563 has_error = true;
564 }
565 if (!service.event_sub_cb) {
566 DlnaLogger.log(DlnaLogLevel::Error, "Service missing event_sub_cb for %s",
567 service.event_sub_url ? service.event_sub_url : "(null)");
568 has_error = true;
569 }
570
571 if (has_error) {
572 DlnaLogger.log(DlnaLogLevel::Error,
573 "Service validation failed - missing URLs/callbacks");
574 }
575
576 return !has_error;
577 }
578
580 virtual bool setupDLNAServer(IHttpServer& srv) {
581 DlnaLogger.log(DlnaLogLevel::Debug, "setupDLNAServer");
582 char buffer[DLNA_MAX_URL_LEN] = {0};
583 StrView url(buffer, DLNA_MAX_URL_LEN);
584
585 // add device url to server
586 const char* device_path = p_device_info->getDeviceURL().path();
587 const char* prefix = p_device_info->getBaseURL();
588
589 DlnaLogger.log(DlnaLogLevel::Info, "Setting up device path: %s",
590 device_path);
591 void* ref[] = {p_device_info};
592
593 if (!StrView(device_path).isEmpty()) {
594 p_server->rewrite("/", device_path);
595 p_server->rewrite("/dlna/device.xml", device_path);
596 p_server->rewrite("/device.xml", device_path);
597 p_server->rewrite("/index.html", device_path);
598 p_server->on(device_path, T_GET, deviceXMLCallback, ref, 1);
599 }
600
601 // Register icon and privide favicon.ico
602 Icon icon = p_device_info->getIcon();
603 if (icon.icon_data != nullptr) {
604 char tmp[DLNA_MAX_URL_LEN];
605 // const char* icon_path = url.buildPath(prefix, icon.icon_url);
606 p_server->on(icon.icon_url, T_GET, icon.mime,
607 (const uint8_t*)icon.icon_data, icon.icon_size);
608 p_server->on("/favicon.ico", T_GET, icon.mime,
609 (const uint8_t*)icon.icon_data, icon.icon_size);
610 }
611
612 for (DLNAServiceInfo& service : p_device_info->getServices()) {
613 // Validate service before registering
614 if (!validateServiceInfo(service)) {
615 DlnaLogger.log(
617 "Skipping service registration due to validation failure");
618 continue;
619 }
620
621 p_server->on(service.scpd_url, T_GET, service.scp_cb);
622 p_server->on(service.control_url, T_POST, service.control_cb);
623 p_server->on(service.event_sub_url, T_SUBSCRIBE, service.event_sub_cb);
624 p_server->on(service.event_sub_url, T_UNSUBSCRIBE, service.event_sub_cb);
625 p_server->on(service.event_sub_url, T_POST, service.event_sub_cb);
626 }
627
628 return true;
629 }
630
632 static void deviceXMLCallback(IHttpServer* server, const char* requestPath,
634 DlnaLogger.log(DlnaLogLevel::Debug, "deviceXMLCallback");
635
636 DLNADeviceInfo* device_xml = (DLNADeviceInfo*)(hl->context[0]);
637 assert(device_xml != nullptr);
638 if (device_xml != nullptr) {
639 DlnaLogger.log(DlnaLogLevel::Info, "reply %s", "DeviceXML");
640 // Use server->reply with a callback so the Content-Length is computed
641 // and headers are written correctly before streaming the body.
642 server->reply(
643 "text/xml",
644 [](Print& out, void* ref) -> size_t {
645 return ((DLNADeviceInfo*)ref)->print(out, ref);
646 },
647 200, "SUCCESS", device_xml);
648 } else {
649 DlnaLogger.log(DlnaLogLevel::Error, "DLNADevice is null");
650 server->replyNotFound();
651 }
652 }
653
655 static bool handleSubscribe(IHttpServer* server, const char* requestPath,
657 DlnaLogger.log(DlnaLogLevel::Debug, "handleSubscribe");
658 auto* device = static_cast<IDevice*>(server->getReference());
659 assert(device != nullptr);
660 DLNAServiceInfo* svc = device->getServiceByEventPath(requestPath);
661 assert(svc != nullptr);
662
663 // Delegate all HTTP processing to SubscriptionMgrDevice
664 return device->getSubscriptionMgr().processSubscribeRequest(*server, *svc);
665 }
666
668 static bool handleUnsubscribe(IHttpServer* server, const char* requestPath,
670 DlnaLogger.log(DlnaLogLevel::Debug, "handleUnsubscribe");
671 auto* device = static_cast<IDevice*>(server->getReference());
672 assert(device != nullptr);
673 DLNAServiceInfo* svc = device->getServiceByEventPath(requestPath);
674 assert(svc != nullptr);
675
676 // Delegate all HTTP processing to SubscriptionMgrDevice
677 return device->getSubscriptionMgr().processUnsubscribeRequest(*server,
678 *svc);
679 }
680};
681
682} // namespace tiny_dlna
Represents a request to invoke a remote DLNA service action.
Definition: Action.h:104
void addArgument(Argument arg)
Definition: Action.h:113
void setAction(const char *act)
Definition: Action.h:155
const char * getAction()
Definition: Action.h:157
Device Attributes and generation of XML using urn:schemas-upnp-org:device-1-0. We could just return a...
Definition: DLNADeviceInfo.h:25
Vector< DLNAServiceInfo > & getServices()
Provides all service definitions.
Definition: DLNADeviceInfo.h:203
Icon getIcon(int idx=0)
Provides the item at indix.
Definition: DLNADeviceInfo.h:228
DLNAServiceInfo & getService(const char *id)
Finds a service definition by name.
Definition: DLNADeviceInfo.h:181
void setSubscriptionActive(bool flag)
Definition: DLNADeviceInfo.h:248
const char * getUDN()
Provide the udn uuid.
Definition: DLNADeviceInfo.h:88
const char * getBaseURL()
Provides the base url.
Definition: DLNADeviceInfo.h:118
Url & getDeviceURL()
This method returns base url/device.xml.
Definition: DLNADeviceInfo.h:129
virtual void setupServices(IHttpServer &server, IUDPService &udp)
to be implemented by subclasses
Definition: DLNADeviceInfo.h:278
DLNAServiceInfo & getServiceByAbbrev(const char *abbrev)
Finds a service definition by name.
Definition: DLNADeviceInfo.h:191
const char * getDeviceType()
Definition: DLNADeviceInfo.h:82
Translates DLNA UDP Requests to Schedule so that we can schedule a reply.
Definition: DLNADeviceRequestParser.h:15
Schedule * parse(DLNADeviceInfo &device, RequestData &req)
Definition: DLNADeviceRequestParser.h:20
void addMSearchST(const char *accept)
Definition: DLNADeviceRequestParser.h:18
Setup of a Basic DLNA Device service. The device registers itself to the network and answers to the D...
Definition: DLNADevice.h:39
void * reference
Definition: DLNADevice.h:471
void setSchedulerIntervalMs(uint32_t ms)
Set scheduler interval in milliseconds.
Definition: DLNADevice.h:480
uint64_t next_subscriptions_timeout_ms
Definition: DLNADevice.h:470
int loopUDPMessages()
Process incoming UDP and execute scheduled replies.
Definition: DLNADevice.h:184
void * getReference() override
Gets the reference pointer.
Definition: DLNADevice.h:441
bool is_active
Definition: DLNADevice.h:457
void setDeviceInfo(DLNADeviceInfo &device)
Definition: DLNADevice.h:473
static bool handleUnsubscribe(IHttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl)
Handle UNSUBSCRIBE requests.
Definition: DLNADevice.h:668
uint64_t subscriptions_interval_ms
Definition: DLNADevice.h:467
void end() override
Stops the processing and releases the resources.
Definition: DLNADevice.h:111
void setReference(void *ref) override
Sets a reference pointer that can be used to associate application.
Definition: DLNADevice.h:438
void setSubscriptionsIntervalMs(uint32_t ms)
Set subscription publish interval in milliseconds.
Definition: DLNADevice.h:488
DLNAServiceInfo * getServiceByEventPath(const char *requestPath) override
Definition: DLNADevice.h:212
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:324
uint32_t getSchedulerIntervalMs() const
Get scheduler interval in milliseconds.
Definition: DLNADevice.h:483
DLNAServiceInfo & getServiceByAbbrev(const char *abbrev) override
Get Service by subscription ns abbrev.
Definition: DLNADevice.h:205
bool setupScheduler()
Schedule PostAlive messages.
Definition: DLNADevice.h:524
uint64_t next_scheduler_timeout_ms
Definition: DLNADevice.h:469
IUDPService * p_udp
Definition: DLNADevice.h:464
void logScheduledStatus(bool runImmediately=false)
Definition: DLNADevice.h:500
bool begin(DLNADeviceInfo &device, IUDPService &udp, IHttpServer &server) override
start the
Definition: DLNADevice.h:46
int loopPublishSubscriptions()
Publish pending subscription notifications.
Definition: DLNADevice.h:172
static size_t replyGetCurrentConnectionInfo(Print &out, const char *protocolInfo, const char *connectionID, const char *direction)
Definition: DLNADevice.h:387
IHttpServer * p_server
Definition: DLNADevice.h:465
Scheduler scheduler
Definition: DLNADevice.h:460
uint32_t post_alive_repeat_ms
Definition: DLNADevice.h:459
static bool handleSubscription(IHttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl, bool &is_subscribe)
Static handler for SUBSCRIBE/UNSUBSCRIBE requests on service event URLs.
Definition: DLNADevice.h:417
static bool handleSubscribe(IHttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl)
Handle SUBSCRIBE requests.
Definition: DLNADevice.h:655
DLNAServiceInfo & getService(const char *id) override
Provide addess to the service information.
Definition: DLNADevice.h:200
bool loop(int loopAction=RUN_ALL) override
Definition: DLNADevice.h:134
DLNADeviceInfo * p_device_info
Definition: DLNADevice.h:463
bool validateServiceInfo(const DLNAServiceInfo &service)
Validates that all required service URLs and callbacks are defined.
Definition: DLNADevice.h:539
void setPostAliveRepeatMs(uint32_t ms) override
Definition: DLNADevice.h:250
DLNADeviceRequestParser parser
Definition: DLNADevice.h:462
static size_t replyGetProtocolInfo(Print &out, const char *source="", const char *sink="")
Definition: DLNADevice.h:354
SubscriptionMgrDevice< ClientType > subscription_mgr
Definition: DLNADevice.h:461
void logStatus()
Definition: DLNADevice.h:443
virtual bool setupDLNAServer(IHttpServer &srv)
set up Web Server to handle Service Addresses
Definition: DLNADevice.h:580
static void parseActionRequest(IHttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl, ActionRequest &action)
Parses the SOAP content of a DLNA action request.
Definition: DLNADevice.h:267
uint32_t getSubscriptionsIntervalMs() const
Get subscription publish interval in milliseconds.
Definition: DLNADevice.h:493
bool setupParser()
Definition: DLNADevice.h:514
DLNADeviceInfo & getDeviceInfo() override
Provides the device.
Definition: DLNADevice.h:240
bool isSchedulerActive() override
Checks if the scheduler is active.
Definition: DLNADevice.h:246
bool loopServer() override
Process http server loop.
Definition: DLNADevice.h:175
ISubscriptionMgrDevice & getSubscriptionMgr() override
Get subscription manager for event handling.
Definition: DLNADevice.h:106
static size_t replyGetCurrentConnectionIDs(Print &out, const char *ids)
Definition: DLNADevice.h:371
void setSubscriptionsActive(bool flag) override
Enable or disable subscription notifications: call before begin.
Definition: DLNADevice.h:253
uint64_t scheduler_interval_ms
Definition: DLNADevice.h:466
static void deviceXMLCallback(IHttpServer *server, const char *requestPath, HttpRequestHandlerLine *hl)
callback to provide device XML
Definition: DLNADevice.h:632
bool isSubscriptionsActive() const override
Check if subscription notifications are active.
Definition: DLNADevice.h:262
void setSchedulerActive(bool flag) override
We can activate/deactivate the scheduler.
Definition: DLNADevice.h:243
DLNADevice()
Definition: DLNADevice.h:41
bool is_subscriptions_active
Definition: DLNADevice.h:458
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:224
Attributes needed for the DLNA Service Definition.
Definition: DLNAServiceInfo.h:18
http_callback control_cb
Definition: DLNAServiceInfo.h:44
http_callback scp_cb
Definition: DLNAServiceInfo.h:43
Str event_sub_url
Definition: DLNAServiceInfo.h:41
Str scpd_url
Definition: DLNAServiceInfo.h:39
http_callback event_sub_cb
Definition: DLNAServiceInfo.h:45
Str control_url
Definition: DLNAServiceInfo.h:40
TinyMethodID method()
Definition: HttpHeader.h:219
Used to register and process callbacks.
Definition: HttpRequestHandlerLine.h:15
void ** context
Definition: HttpRequestHandlerLine.h:40
Reading and writing of Http Requests.
Definition: HttpHeader.h:358
Abstract interface for DLNA device functionality.
Definition: IDevice.h:30
Abstract interface for HTTP server functionality.
Definition: IHttpServer.h:30
virtual bool begin()=0
Start the HTTP server.
virtual void * getReference()=0
Get user reference pointer.
virtual bool doLoop()=0
Process server loop.
virtual void replyNotFound()=0
Send 404 Not Found response.
virtual void end()=0
Stop the HTTP server.
virtual void on(const char *url, TinyMethodID method, web_callback_fn fn, void *ctx[]=nullptr, int ctxCount=0)=0
Register callback for HTTP request with context.
virtual void setReference(void *reference)=0
Set user reference pointer.
virtual Client & client()=0
Get reference to current client.
virtual void replyError(int err, const char *msg="Internal Server Error")=0
Send error response with status code.
virtual HttpRequestHeader & requestHeader()=0
Get reference to request header.
virtual void reply(const char *contentType, Stream &inputStream, int size, int status=200, const char *msg=SUCCESS)=0
Send response from input stream with known size.
virtual void rewrite(const char *from, const char *to)=0
Add URL rewrite rule.
Abstract interface for UPnP event subscription management.
Definition: ISubscriptionMgrDevice.h:27
virtual void setSubscriptionsActive(bool flag)=0
Enable/disable subscription processing.
virtual void end()=0
Cleanup and stop subscription manager.
Abstract Interface for UDP API.
Definition: IUDPService.h:33
virtual RequestData receive()=0
Receive incoming UDP data and peer information.
virtual bool begin(int port)=0
Initialize UDP service on specified port.
Information about the icon.
Definition: Icon.h:10
const char * icon_url
Definition: Icon.h:16
int icon_size
Definition: Icon.h:18
const char * mime
Definition: Icon.h:12
uint8_t * icon_data
Definition: Icon.h:17
Send out PostAlive messages: Repeated every 5 seconds.
Definition: Schedule.h:218
Send out ByeBye message.
Definition: Schedule.h:290
Scheduler which processes all due Schedules (to send out UDP replies)
Definition: Scheduler.h:15
int execute(IUDPService &udp)
Execute all due schedules.
Definition: Scheduler.h:30
void setActive(bool flag)
Definition: Scheduler.h:81
bool isActive()
Definition: Scheduler.h:83
int size()
Number of queued schedules.
Definition: Scheduler.h:79
void add(Schedule *schedule)
Add a schedule to the scheduler.
Definition: Scheduler.h:18
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 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
bool equals(const char *other) const
Exact string equality with C-string.
Definition: Str.h:167
const char * c_str() const
C-string pointer to internal buffer.
Definition: Str.h:88
Manages UPnP event subscriptions and queued notifications for a DLNA device.
Definition: SubscriptionMgrDevice.h:90
URL parser which breaks a full url string up into its individual parts.
Definition: Url.h:18
const char * path()
Definition: Url.h:40
Lightweight wrapper around std::vector with Arduino-friendly helpers and a pluggable allocator.
Definition: Vector.h:39
Helper class that implements a Print interface to accumulate XML data and then parse it using XMLPars...
Definition: XMLParserPrint.h:16
size_t write(uint8_t ch) override
Writes a single byte to the buffer (Print interface)
Definition: XMLParserPrint.h:32
void setExpandEncoded(bool flag)
Forwards expand-entities setting to the underlying XMLParser.
Definition: XMLParserPrint.h:48
void end()
Resets the internal buffer.
Definition: XMLParserPrint.h:87
bool parse(Str &outNodeName, Vector< Str > &outPath, Str &outText, Str &outAttributes)
Parses the accumulated XML data and returns results via output parameters.
Definition: XMLParserPrint.h:59
#define DLNA_MAX_URL_LEN
app-wide max URL length
Definition: dlna_config.h:45
#define XML_PARSER_BUFFER_SIZE
Define XML parse buffer size.
Definition: dlna_config.h:25
#define DLNA_LOOP_DELAY_MS
Define delay in ms for main DLNA loop.
Definition: dlna_config.h:5
#define DLNA_RUN_SCHEDULER_EVERY_MS
Define scheduler run interval in ms.
Definition: dlna_config.h:10
#define DLNA_RUN_SUBSCRIPTIONS_EVERY_MS
Define subscription publish interval in ms.
Definition: dlna_config.h:15
Definition: Allocator.h:13
@ RUN_UDP
Definition: IDevice.h:18
@ RUN_SERVER
Definition: IDevice.h:18
@ RUN_ALL
Definition: IDevice.h:18
@ RUN_SUBSCRIPTIONS
Definition: IDevice.h:18
@ T_UNSUBSCRIBE
Definition: HttpHeader.h:46
@ T_SUBSCRIBE
Definition: HttpHeader.h:47
@ T_GET
Definition: HttpHeader.h:37
@ T_POST
Definition: HttpHeader.h:39
Provides information of the received UDP which consists of the (xml) data and the peer address and po...
Definition: IUDPService.h:22
An individual Schedule (to send out UDP messages)
Definition: Schedule.h:18
uint64_t time
Definition: Schedule.h:21
uint32_t repeat_ms
Definition: Schedule.h:23
Functions to efficiently output XML. XML data contains a lot of redundancy so it is more memory effic...
Definition: XMLPrinter.h:56
size_t printNodeBegin(const char *node, const char *attributes=nullptr, const char *ns=nullptr)
Prints the beginning of an XML node.
Definition: XMLPrinter.h:314
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:248
size_t printNodeEnd(const char *node, const char *ns=nullptr)
Prints the end of an XML node.
Definition: XMLPrinter.h:352