Arduino DLNA Server
Loading...
Searching...
No Matches
DLNAControlPointMediaServer.h
Go to the documentation of this file.
1// Header-only control point helper for MediaServer devices
2#pragma once
3
6
7namespace tiny_dlna {
8
18 public:
19 typedef void (*XMLCallback)(const char* name, const char* test,
20 const char* attributes);
21 typedef void (*NotificationCallback)(void* reference, const char* sid,
22 const char* varName,
23 const char* newValue);
24
37 IUDPService& udp)
38 : p_mgr(&mgr), p_http(&http), p_udp(&udp) {}
39
42
44 void setLocalURL(Url url) { p_mgr->setLocalURL(url); }
45
47 void setLocalURL(IPAddress url, int port=9001, const char* path="") {
48 this->p_mgr->setLocalURL(url, port, path);
49 }
50
58 bool begin(uint32_t minWaitMs = 3000, uint32_t maxWaitMs = 60000) {
59 DlnaLogger.log(
61 "DLNAControlPointMediaServer::begin: device_type_filter='%s'",
63 if (!p_mgr) {
64 DlnaLogger.log(DlnaLogLevel::Error, "mgr instance not set");
65 return false;
66 }
67 if (!p_http) {
68 DlnaLogger.log(DlnaLogLevel::Error, "http instance not set");
69 return false;
70 }
71 if (!p_udp) {
72 DlnaLogger.log(DlnaLogLevel::Error, "udp instance not set");
73 return false;
74 }
75
76 return p_mgr->begin(*p_http, *p_udp, device_type_filter, minWaitMs,
77 maxWaitMs);
78 }
79
81 void setHttp(IHttpRequest& http) { p_http = &http; }
82
84 void setUdp(IUDPService& udp) { p_udp = &udp; }
85
91 // count only devices matching the device_type_filter
92 int count = 0;
93 for (auto& d : p_mgr->getDevices()) {
94 const char* dt = d.getDeviceType();
95 if (!device_type_filter || StrView(dt).contains(device_type_filter))
96 count++;
97 }
98 return count;
99 }
100
105 const ActionReply& getLastReply() const { return last_reply; }
106
112 void setDeviceIndex(int idx) { p_mgr->setDeviceIndex(idx); }
113
114 bool subscribe() { return p_mgr->subscribe(); }
115
116
118 void setNotificationsActive(bool flag) {
120 }
121
124 std::function<void(const char* sid, const char* varName,
125 const char* newValue, void* reference)>
126 cb,
127 void* ref = nullptr) {
130 }
131
138 void setDeviceTypeFilter(const char* filter) {
140 }
141
146 void setReference(void* ref) { reference = ref; }
147
162 bool browse(int startingIndex, int requestedCount, ContentQueryType queryType,
163 XMLCallback XMLCallback, int& numberReturned, int& totalMatches,
164 int& updateID) {
165 // Register item callback
166 this->p_mgr->onResultNode(XMLCallback);
167 // Build and post browse action
168 DLNAServiceInfo& svc =
169 selectService("urn:upnp-org:serviceId:ContentDirectory");
170 if (!svc) return false;
171 ActionRequest& act =
172 createBrowseAction(svc, queryType, startingIndex, requestedCount);
173 p_mgr->addAction(act);
175 if (!last_reply) return false;
176
177 // parse numeric result fields
178 parseNumericFields(last_reply, numberReturned, totalMatches, updateID);
179
180 return true;
181 }
182
197 bool search(int startingIndex, int requestedCount, XMLCallback XMLCallback,
198 int& numberReturned, int& totalMatches, int& updateID,
199 const char* searchCriteria = "", const char* filter = "",
200 const char* sortCriteria = "") {
201 // Register item callback
202 this->p_mgr->onResultNode(XMLCallback);
203
204 DLNAServiceInfo& svc =
205 selectService("urn:upnp-org:serviceId:ContentDirectory");
206 if (!svc) return false;
207
208 ActionRequest& act =
209 createSearchAction(svc, searchCriteria, filter, startingIndex,
210 requestedCount, sortCriteria);
211 p_mgr->addAction(act);
213 if (!last_reply) return false;
214
215 parseNumericFields(last_reply, numberReturned, totalMatches, updateID);
216 return true;
217 }
218
224 DlnaLogger.log(DlnaLogLevel::Debug,
225 "ControlPointMediaServer::getSystemUpdateID");
226 DLNAServiceInfo& svc =
227 selectService("urn:upnp-org:serviceId:ContentDirectory");
228 if (!svc) return -1;
229 ActionRequest act{svc, "GetSystemUpdateID"};
230 p_mgr->addAction(act);
232 if (!last_reply) return -1;
233 const char* v = last_reply.findArgument("Id");
234 if (!v) v = last_reply.findArgument("Id");
235 return v ? atoi(v) : -1;
236 }
237
242 const char* getSearchCapabilities() {
243 DlnaLogger.log(DlnaLogLevel::Debug,
244 "ControlPointMediaServer::getSearchCapabilities");
245 DLNAServiceInfo& svc =
246 selectService("urn:upnp-org:serviceId:ContentDirectory");
247 if (!svc) return nullptr;
248 ActionRequest act{svc, "GetSearchCapabilities"};
249 p_mgr->addAction(act);
251 if (!last_reply) return nullptr;
252 return last_reply.findArgument("SearchCaps");
253 }
254
259 const char* getSortCapabilities() {
260 DlnaLogger.log(DlnaLogLevel::Debug,
261 "ControlPointMediaServer::getSortCapabilities");
262 DLNAServiceInfo& svc =
263 selectService("urn:upnp-org:serviceId:ContentDirectory");
264 if (!svc) return nullptr;
265 ActionRequest act{svc, "GetSortCapabilities"};
266 p_mgr->addAction(act);
268 if (!last_reply) return nullptr;
269 return last_reply.findArgument("SortCaps");
270 }
271
276 const char* getProtocolInfo() {
277 DlnaLogger.log(DlnaLogLevel::Debug,
278 "ControlPointMediaServer::getProtocolInfo");
279 DLNAServiceInfo& svc =
280 selectService("urn:upnp-org:serviceId:ConnectionManager");
281 if (!svc) return nullptr;
282 ActionRequest act{svc, "GetProtocolInfo"};
283 p_mgr->addAction(act);
285 if (!last_reply) return nullptr;
286 return last_reply.findArgument("Source");
287 }
288
293 void setObjectID(const char* id) { object_id = id; }
294
299 const char* getObjectID() const { return object_id; }
300
301 protected:
304 "urn:schemas-upnp-org:device:MediaServer:1";
307 void* reference = nullptr;
308 const char* object_id = "0";
309 // transport references (optional) - must be set before calling begin()
311 IUDPService* p_udp = nullptr;
312
314 static void processNotification(void* reference, const char* sid,
315 const char* varName, const char* newValue) {
316 // Log every notification invocation for debugging/visibility
317 DlnaLogger.log(DlnaLogLevel::Info,
318 "processNotification sid='%s' var='%s' value='%s'",
319 sid ? sid : "(null)", varName ? varName : "(null)",
320 newValue ? newValue : "(null)");
321 }
322
325 DlnaLogger.log(DlnaLogLevel::Debug,
326 "ControlPointMediaServer::selectService: id='%s'", id);
327 // Build list of devices matching the optional filter
329 if (s) return s;
330
331 // fallback: global search
332 return p_mgr->getService(id);
333 }
334
337 ContentQueryType queryType,
338 int startingIndex, int requestedCount) {
339 const char* browseFlag = (queryType == ContentQueryType::BrowseMetadata)
340 ? "BrowseMetadata"
341 : "BrowseDirectChildren";
342 static ActionRequest act{svc, "Browse"};
343 // Use the canonical argument name expected by ContentDirectory: "ObjectID"
344 act.addArgument("ObjectID", object_id);
345 act.addArgument("BrowseFlag", browseFlag);
346 act.addArgument("Filter", "");
347 char buf[32];
348 snprintf(buf, sizeof(buf), "%d", startingIndex);
349 act.addArgument("StartingIndex", buf);
350 snprintf(buf, sizeof(buf), "%d", requestedCount);
351 act.addArgument("RequestedCount", buf);
352 act.addArgument("SortCriteria", "");
353 return act;
354 }
355
358 const char* searchCriteria,
359 const char* filter, int startingIndex,
360 int requestedCount,
361 const char* sortCriteria) {
362 static ActionRequest act{svc, "Search"};
363 act.addArgument("ContainerID", object_id);
364 act.addArgument("SearchCriteria", searchCriteria ? searchCriteria : "");
365 act.addArgument("Filter", filter ? filter : "");
366 char buf[32];
367 snprintf(buf, sizeof(buf), "%d", startingIndex);
368 act.addArgument("StartingIndex", buf);
369 snprintf(buf, sizeof(buf), "%d", requestedCount);
370 act.addArgument("RequestedCount", buf);
371 act.addArgument("SortCriteria", sortCriteria ? sortCriteria : "");
372 return act;
373 }
374
376 void parseNumericFields(ActionReply& reply, int& numberReturned,
377 int& totalMatches, int& updateID) {
378 DlnaLogger.log(DlnaLogLevel::Debug,
379 "ControlPointMediaServer::parseNumericFields");
380 const char* nret = reply.findArgument("NumberReturned");
381 const char* tmatch = reply.findArgument("TotalMatches");
382 const char* uid = reply.findArgument("UpdateID");
383 numberReturned = nret ? atoi(nret) : 0;
384 totalMatches = tmatch ? atoi(tmatch) : 0;
385 updateID = uid ? atoi(uid) : 0;
386 }
387};
388
389} // namespace tiny_dlna
Represents the result of invoking a DLNA service Action.
Definition: Action.h:48
const char * findArgument(const char *name)
Definition: Action.h:70
Represents a request to invoke a remote DLNA service action.
Definition: Action.h:104
Helper class to control/query a MediaServer from a control point.
Definition: DLNAControlPointMediaServer.h:17
ActionRequest & createSearchAction(DLNAServiceInfo &svc, const char *searchCriteria, const char *filter, int startingIndex, int requestedCount, const char *sortCriteria)
Build a Search ActionRequest.
Definition: DLNAControlPointMediaServer.h:357
void * reference
Definition: DLNAControlPointMediaServer.h:307
bool browse(int startingIndex, int requestedCount, ContentQueryType queryType, XMLCallback XMLCallback, int &numberReturned, int &totalMatches, int &updateID)
Browse the given object_id and invoke callback for each returned xml element.
Definition: DLNAControlPointMediaServer.h:162
DLNAControlPointMediaServer()=default
Default constructor.
DLNAServiceInfo & selectService(const char *id)
Select service by id.
Definition: DLNAControlPointMediaServer.h:324
void setLocalURL(Url url)
Defines the local URL for the control point.
Definition: DLNAControlPointMediaServer.h:44
void(* NotificationCallback)(void *reference, const char *sid, const char *varName, const char *newValue)
Definition: DLNAControlPointMediaServer.h:21
const char * getObjectID() const
Return the current object id used for browse.
Definition: DLNAControlPointMediaServer.h:299
DLNAControlPoint * p_mgr
Definition: DLNAControlPointMediaServer.h:302
IUDPService * p_udp
Definition: DLNAControlPointMediaServer.h:311
void setUdp(IUDPService &udp)
Setter for UDP service used for discovery (SSDP)
Definition: DLNAControlPointMediaServer.h:84
void setHttp(IHttpRequest &http)
Setter for the HTTP wrapper used for subscriptions and callbacks.
Definition: DLNAControlPointMediaServer.h:81
const char * getSearchCapabilities()
Get the ContentDirectory SearchCapabilities string.
Definition: DLNAControlPointMediaServer.h:242
void setDLNAControlPoint(DLNAControlPoint &m)
Set the control point manager instance (required before using helper)
Definition: DLNAControlPointMediaServer.h:41
const char * getSortCapabilities()
Get the ContentDirectory SortCapabilities string.
Definition: DLNAControlPointMediaServer.h:259
const char * object_id
Definition: DLNAControlPointMediaServer.h:308
void setLocalURL(IPAddress url, int port=9001, const char *path="")
Defines the local URL for the control point.
Definition: DLNAControlPointMediaServer.h:47
bool begin(uint32_t minWaitMs=3000, uint32_t maxWaitMs=60000)
Begin discovery and processing (forwards to underlying control point)
Definition: DLNAControlPointMediaServer.h:58
const char * device_type_filter_default
Definition: DLNAControlPointMediaServer.h:303
ActionRequest & createBrowseAction(DLNAServiceInfo &svc, ContentQueryType queryType, int startingIndex, int requestedCount)
Build a Browse ActionRequest.
Definition: DLNAControlPointMediaServer.h:336
static void processNotification(void *reference, const char *sid, const char *varName, const char *newValue)
Notification callback: just log for now.
Definition: DLNAControlPointMediaServer.h:314
const char * device_type_filter
Definition: DLNAControlPointMediaServer.h:305
void setDeviceTypeFilter(const char *filter)
Restrict this helper to devices of the given device type.
Definition: DLNAControlPointMediaServer.h:138
bool search(int startingIndex, int requestedCount, XMLCallback XMLCallback, int &numberReturned, int &totalMatches, int &updateID, const char *searchCriteria="", const char *filter="", const char *sortCriteria="")
Search the ContentDirectory using SearchCriteria and invoke callback for each returned xml element.
Definition: DLNAControlPointMediaServer.h:197
void setObjectID(const char *id)
Set the object id used for browse operations (default: "0")
Definition: DLNAControlPointMediaServer.h:293
IHttpRequest * p_http
Definition: DLNAControlPointMediaServer.h:310
int getSystemUpdateID()
Get current SystemUpdateID for the ContentDirectory.
Definition: DLNAControlPointMediaServer.h:223
void setNotificationCallback(std::function< void(const char *sid, const char *varName, const char *newValue, void *reference)> cb, void *ref=nullptr)
Register a callback for notifications and activate subscriptions.
Definition: DLNAControlPointMediaServer.h:123
void setDeviceIndex(int idx)
Select a device by index (0-based) for subsequent actions. By default 0 is used.
Definition: DLNAControlPointMediaServer.h:112
void setNotificationsActive(bool flag)
Subscribe to event notifications: call after selecting the device.
Definition: DLNAControlPointMediaServer.h:118
const ActionReply & getLastReply() const
Return the ActionReply from the last synchronous request.
Definition: DLNAControlPointMediaServer.h:105
const char * getProtocolInfo()
Query ConnectionManager:GetProtocolInfo.
Definition: DLNAControlPointMediaServer.h:276
int getDeviceCount()
Return number of discovered devices known to the control point.
Definition: DLNAControlPointMediaServer.h:90
ActionReply last_reply
Definition: DLNAControlPointMediaServer.h:306
bool subscribe()
Definition: DLNAControlPointMediaServer.h:114
void parseNumericFields(ActionReply &reply, int &numberReturned, int &totalMatches, int &updateID)
Parse numeric result fields from an ActionReply.
Definition: DLNAControlPointMediaServer.h:376
DLNAControlPointMediaServer(DLNAControlPoint &mgr, IHttpRequest &http, IUDPService &udp)
Construct helper with references to control point manager and required transport instances (HTTP for ...
Definition: DLNAControlPointMediaServer.h:36
void setReference(void *ref)
Attach an opaque reference pointer passed to callbacks.
Definition: DLNAControlPointMediaServer.h:146
Lightweight DLNA control point manager.
Definition: DLNAControlPoint.h:61
void setLocalURL(Url url) override
Defines the local url (needed for subscriptions)
Definition: DLNAControlPoint.h:89
DLNAServiceInfo & getService(const char *id) override
Provide addess to the service information.
Definition: DLNAControlPoint.h:361
void setDeviceIndex(int idx) override
Selects the default device by index.
Definition: DLNAControlPoint.h:107
void setEventSubscriptionCallback(std::function< void(const char *sid, const char *varName, const char *newValue, void *reference)> cb, void *ref=nullptr) override
Register a callback that will be invoked for incoming event notification.
Definition: DLNAControlPoint.h:110
void onResultNode(std::function< void(const char *nodeName, const char *text, const char *attributes)> cb) override
Definition: DLNAControlPoint.h:127
DLNADeviceInfo & getDevice() override
Provides the device information of the actually selected device.
Definition: DLNAControlPoint.h:372
Vector< DLNADeviceInfo > & getDevices() override
Get list of all discovered devices.
Definition: DLNAControlPoint.h:414
void setNotificationsActive(bool flag) override
Activate/deactivate subscription notifications.
Definition: DLNAControlPoint.h:519
bool begin(const char *searchTarget="ssdp:all", uint32_t minWaitMs=3000, uint32_t maxWaitMs=60000) override
Start discovery with default HTTP/UDP services.
Definition: DLNAControlPoint.h:133
ActionReply & executeActions(XMLCallback xmlProcessor=nullptr) override
Executes action and parses the reply xml to collect the reply entries. If an XML processor is provide...
Definition: DLNAControlPoint.h:304
ActionRequest & addAction(ActionRequest act) override
Registers a method that will be called.
Definition: DLNAControlPoint.h:290
bool subscribe()
Subscribes to event notifications for all services of the selected device.
Definition: DLNAControlPoint.h:216
DLNAServiceInfo & getService(const char *id)
Finds a service definition by name.
Definition: DLNADeviceInfo.h:183
Attributes needed for the DLNA Service Definition.
Definition: DLNAServiceInfo.h:18
Abstract interface for HTTP client request functionality.
Definition: IHttpRequest.h:21
Abstract Interface for UDP API.
Definition: IUDPService.h:33
A simple wrapper to provide string functions on char*. If the underlying char* is a const we do not a...
Definition: StrView.h:18
URL parser which breaks a full url string up into its individual parts.
Definition: Url.h:18
Definition: Allocator.h:13
ContentQueryType
Type of content query for DLNA browsing/searching.
Definition: DLNACommon.h:36
std::function< void(Client &client, ActionReply &reply)> XMLCallback
Definition: IControlPoint.h:25