Switch to unified view

a/doc/libupnpp-ctl.txt b/doc/libupnpp-ctl.txt
1
= Libupnpp for Control Points
1
= Libupnpp for Control Points
2
2
3
Libupnpp is a C++ wrapper for libupnp, a.k.a Portable UPnP, which is a
3
Libupnpp is a C++ wrapper for link:http://pupnp.sourceforge.net/[libupnp],
4
direct descendant of the Open Source SDK released by Intel in support of
4
a.k.a Portable UPnP, which is a direct descendant of the Open Source SDK
5
UPnP development.
5
released by Intel in support of UPnP development.
6
6
7
The Control Point side of libupnpp allows a C++ program to discover
7
Libupnpp can be used to implement UPnP devices and services, or Control
8
Points.
9
10
The Control Point side of libupnpp, which is documented here, allows a C++
8
devices, and exchange commands and status with them.
11
program to discover UPnP devices, and exchange commands and status with
12
them.
9
13
10
The library has a number of predefined modules for controlling specific
14
The library has a number of predefined modules for controlling specific
11
AVTransport or OpenHome audio services, and it is relatively easy to add
15
AVTransport or OpenHome audio services, and it is relatively easy to add
12
modules for other services externally (the internal modules have no more
16
modules for other services externally (the internal modules have no more
13
access to library internals than an external module would).
17
access to library internals than an external module would).
14
18
15
Limitations:
19
Limitations:
16
20
17
- The underlying libupnp only supports a single IP interface.
21
- The underlying libupnp only supports a single IP interface.
18
 The libupnpp methods are blocking, it is supposed that you will be using
22
- The libupnpp methods are blocking. Multithreading will be needed to
19
  threads to achieve any needed parallelism in your program.
23
  achieve parallelism in your program (in any case the underlying libupnp
24
  uses threads, so multithreading support is a requirement).
25
26
link:refdoc/html/index.html[Reference documentation (doxygen)]
20
27
21
== The Library object
28
== The Library object
22
29
23
The library is represented by a global singleton with a number of utility
30
The library is represented by a global singleton with a number of utility
24
methods, mostly related to setting parameters for the underlying libupnp
31
methods, mostly related to setting parameters for the underlying libupnp
...
...
61
In libupnpp, the content of the main description document for a given
68
In libupnpp, the content of the main description document for a given
62
device is provided by a
69
device is provided by a
63
link:refdoc/html/classUPnPClient_1_1UPnPDeviceDesc.html[UPnPClient::UPnPDeviceDesc]
70
link:refdoc/html/classUPnPClient_1_1UPnPDeviceDesc.html[UPnPClient::UPnPDeviceDesc]
64
object.
71
object.
65
72
66
If you are mostly using the devices and services predefined in the library,
73
When using the devices and services predefined by the library, this is
67
this is largely an opaque structure, which you will get through the
74
largely an opaque structure, which you will get through the discovery
68
discovery interface, and pass to an actual device constructor.
75
interface, and pass to a Device or Service constructor.
69
76
70
== Devices
77
== Devices
71
78
72
UPnP device are entities which can contain other, embedded devices, and
79
UPnP devices are entities which can contain other, embedded devices, and
73
services.
80
services.
74
81
75
Embedded devices are quite rare, and in my experience badly supported by
82
Embedded devices are quite rare, and in my experience badly supported by
76
typical control points.
83
common control points.
77
84
78
In general, the service is the interesting entity, and the wise approach is
85
In general, the service is the interesting entity, and the wise approach is
79
the Pythonic "quacks like a duck" one: if a device has the service you
86
the Pythonic "quacks like a duck" one: if a device has the service you
80
need, you can use it.
87
need, you can use it.
81
88
82
For example the predefined 'MediaRenderer' class in libupnpp does not even
89
For example the predefined 'MediaRenderer' class in libupnpp does not even
83
bother to verify its own type when built from a description: it just
90
bother to verify its own type when built from a description: it just
84
provides methods to query and retrieve handles to interesting services
91
provides methods to query and retrieve handles to interesting services
85
usually found in a Media Renderer (both OpenHome and UPnP AV). In most
92
usually found in a Media Renderer (both OpenHome and UPnP AV). In most
86
cases, not all services will be available, and the caller will compose an "a
93
cases, not all services will be available, and the caller will compose an "a
87
la carte" object to serve its need (e.g. using either UPnP AV Rendering
94
la carte" object to serve its needs (e.g. using either UPnP AV Rendering
88
Control or OpenHome Volume for controlling volume, depending on
95
Control or OpenHome Volume for controlling volume, depending on
89
availability).
96
availability).
90
97
91
As another example, the 'myrdcvolume' program from the libupnpp samples
98
As another example, the 'myrdcvolume' program from the libupnpp samples
92
shows how to implement a service interface without using the predefined
99
shows how to implement a service interface without using the predefined
...
...
95
the appropriate service
102
the appropriate service
96
(i.e. 'urn:schemas-upnp-org:service:RenderingControl'), and action
103
(i.e. 'urn:schemas-upnp-org:service:RenderingControl'), and action
97
('Volume').
104
('Volume').
98
105
99
The library predefines two device classes, for Media Server devices and
106
The library predefines two device classes, for Media Server devices and
100
Media Renderer ones. In both cases the only use for the class is to retrieve
107
Media Renderer ones. Both are convenience classes with utility code to
101
handles to the underlying services.
108
build the underlying service objects and retrieve handles for them.
102
109
103
110
104
== Services
111
== Services
105
112
106
Most UPnP functionality is provided through services, which are end points
113
Most UPnP functionality is provided through services, which are end points
...
...
110
(some of which also work with video). You will usually not need to bother
117
(some of which also work with video). You will usually not need to bother
111
constructing the service interface objects: rather you will let the device
118
constructing the service interface objects: rather you will let the device
112
classes do it and return a handle (but there is nothing to prevent you from
119
classes do it and return a handle (but there is nothing to prevent you from
113
building the service objects directly).
120
building the service objects directly).
114
121
115
It also has helper functions for helping with the independant implementation
122
There are two possible approaches for accessing a service which does not
116
of a service interface. 
123
have a predefined interface class in the library:
124
125
- Use the library helper functions for implementing a specific service
126
  interface, by deriving from the base
127
  link:refdoc/html/classUPnPClient_1_1Service.html[Service] class.
128
- Use the xref:TypedService[TypedService] generic string-based interface
129
  class.
130
  
117
131
118
== Predefined Service classes
132
== Predefined Service classes
119
133
120
* link:refdoc/html/classUPnPClient_1_1RenderingControl.html[UPnP AV
134
* link:refdoc/html/classUPnPClient_1_1RenderingControl.html[UPnP AV
121
  Rendering Control] 
135
  Rendering Control] 
...
...
132
146
133
The role of most methods in these classes is to marshal the input data into
147
The role of most methods in these classes is to marshal the input data into
134
SOAP format, perform the SOAP call, then marshal and return the output
148
SOAP format, perform the SOAP call, then marshal and return the output
135
data. They are all synchronous.
149
data. They are all synchronous.
136
150
151
[[TypedService]]
152
== String based interface
153
154
The link:refdoc/html/classUPnPClient_1_1TypedService.html[TypedService]
155
class provides access to the actions in a service through a simple
156
string-based interface.
157
158
The user only needs specify an action name and a list of arguments to call
159
an action. The class uses the service description retrieved from the
160
device to generate the actual SOAP call. Any returned data is provided
161
through a C++ name-value map.
162
163
The class also has an associated
164
link:refdoc/html/namespaceUPnPClient.html#ad3edfb36acb86cb98961233b127fc3df[helper
165
function] which provides a simplified interface to discovery.
166
167
While the class is less convenient to use than one customized to a single
168
service, which can provide full encoding/decoding between SOAP data and a
169
natural C++ interface, it avoids having to write the corresponding code. It
170
was mostly implemented as a convenient interface for the SWIG module, but
171
it can probably have other uses.
172
173
174
== Eventing
175
176
UPnP services can report changes in their state to Control Points through
177
events. In practise, the Control Point implements an internal HTTP server
178
to which the services connect to report events.
179
180
Event reporting is not active by default and needs to be activated by the
181
Control Point by 'subscribing' to the service.
182
183
Users of Service classes can receive asynchronous events by calling the
184
link:refdoc/html/classUPnPClient_1_1Service.html#a2d9aad17b90587f8c6a3791944edcdde[installReporter()]
185
method, to specify what functions should be called when an event arrives.
186
187
NOTE: The event functions are called from a separate thread
188
and some synchronization will usually be required.
189
190
Some details of event handling in libupnpp have changed as of version
191
0.16.
192
193
== Event handling in version 0.15 and before
194
195
Services implemented by the library always subscribe to events. This
196
happens in the object constructor, by a call to the class derived
197
registerCallback() method. Example:
198
199
----
200
avtransport.hxx:
201
202
class AVTransport : public Service {
203
   ...
204
    AVTransport(const UPnPDeviceDesc& device,
205
                const UPnPServiceDesc& service)
206
        : Service(device, service) {
207
        registerCallback();
208
    }
209
...
210
211
avtransport.cxx:
212
213
void AVTransport::registerCallback()
214
{
215
    Service::registerCallback(bind(&AVTransport::evtCallback, this, _1));
216
}
217
----
218
219
'Service::registerCallback()' performs the UPnP subscription and takes note
220
of the function to call when an event arrive.
221
222
This means that a subscription (needing a network exchange) is performed
223
each time a Service object is built, even if events are not actually needed
224
by the user.
225
226
The Service base class destructor erases the callback hook and cancels the
227
event subscription.
228
229
=== Event handling for version 0.16 and later
230
231
As of version 0.16 of the library, the event subscription is only performed
232
if and when 'installReporter()' is called. If you don't need events, you
233
will not incur their overhead.
234
235
== Logging
236
237
Both 'libupnp' and 'libupnpp' have configurable error and debug logging.
238
239
=== libupnp logging
240
241
The log from 'libupnp' is very detailed and mostly useful for low level
242
debugging of UPnP issues. The logging functions in 'libupnp' are
243
conditionnally compiled, and may not be enabled for your distribution (you
244
can check UPNP_HAVE_DEBUG in 'include/upnp/upnpconfig.h').
245
246
If the 'libupnp' logging functions are enabled, you can control them
247
through the
248
link:refdoc/html/classUPnPP_1_1LibUPnP.html#afb21929cea7859786d93dec1086563bc[LibUPnP::setLogFileName()]
249
and 'LibUPnP::setLogLevel()' methods.
250
251
=== libupnpp logging
252
253
'libupnpp' logging is distinct from the 'libupnp' functions, and always
254
enabled, at a configurable level of verbosity.
255
256
The log is initialized by a call to
257
link:refdoc/html/classLogger.html[Logger::getTheLog()]. The
258
verbosity level can be adjusted through 'setLogLevel()', and macros are
259
used to emit the actual messages. The printing is based on the C++ iostreams.
260
261
See libupnpp/log.h for more details.
262
263
Exemple:
264
265
----
266
    if (Logger::getTheLog(logfilename) == 0) {
267
        cerr << "Can't initialize log" << endl;
268
        return 1;
269
    }
270
    Logger::getTheLog("")->setLogLevel(Logger::LLINF);
271
272
    ...
273
274
    LOGINF("Message at level INFO, it outputs some value: " << value);
275
----
276
277
Of course you can use the 'LOGXX' macros in your own code.
278
279
137
== Implementing a Service class
280
== Implementing a Service class
138
281
282
If you want to access a service for which no predefined class exists in
283
libupnpp, you need to define its interface yourself, by deriving the
284
'libupnpp' link:refdoc/html/classUPnPClient_1_1Service.html[Service] class.
285
286
The methods in the base class and in the helper modules make it very easy
287
to write the derived class.
288
289
NOTE: libupnpp has no provision to use the service description XML document
290
to define the service client methods. However, the device side has a script
291
to turn a service description into an implementation device-side skeleton.
292
293
The derived class main constructor will take Device and Service description
294
structures are arguments and will need to call the base class
295
constructor. Example:
296
297
----
298
class OHPlaylist : public Service {
299
public:
300
301
    OHPlaylist(const UPnPDeviceDesc& device, const UPnPServiceDesc& service)
302
        : Service(device, service) {
303
    }
304
    ...
305
----
306
307
If there are initialization steps which are specific to the service type,
308
they should be done inside the 'serviceInit()' method, which 
309
should be called from the constructor (see below for a more detailed
310
description). Most services don't need 'serviceInit()', so an empty
311
implementation is provided by the base class.
312
313
Action methods are then just ordinary methods, which will call the base
314
class methods to perform the networky things.
315
316
Example of an action setting a value:
317
318
----
319
int RenderingControl::setMute(bool mute, const string& channel)
320
{
321
    SoapOutgoing args(getServiceType(), "SetMute");
322
    args("InstanceID", "0")("Channel", channel)
323
    ("DesiredMute", SoapHelp::i2s(mute?1:0));
324
    SoapIncoming data;
325
    return runAction(args, data);
326
}
327
----
328
329
The link:refdoc/html/classUPnPP_1_1SoapOutgoing.html[SoapOutgoing]
330
constructor takes a service type and action name arguments. Its 'operator ()'
331
accepts additional named string arguments.
332
333
The
334
link:refdoc/html/classUPnPClient_1_1Service.html#a7eee43639eff25893117ab52b0b036db[Service::runAction()]
335
method performs the SOAP call and provides any resulting data in a
336
link:refdoc/html/classUPnPP_1_1SoapIncoming.html[SoapIncoming] object, from
337
which named values can be easily extracted. There is no return data in the
338
above example, see below for an action using 'SoapIncoming::get()' to
339
extract data.
340
341
Example of an action retrieving a value (note there is nothing to prevent
342
an action to both set and retrieve data).
343
344
----
345
bool RenderingControl::getMute(const string& channel)
346
{
347
    SoapOutgoing args(getServiceType(), "GetMute");
348
    args("InstanceID", "0")("Channel", channel);
349
    SoapIncoming data;
350
    int ret = runAction(args, data);
351
    if (ret != UPNP_E_SUCCESS) {
352
        return false;
353
    }
354
    bool mute;
355
    if (!data.get("CurrentMute", &mute)) {
356
        LOGERR("RenderingControl:getMute: missing CurrentMute in response"
357
               << endl);
358
        return false;
359
    }
360
    return mute;
361
}
362
----
363
364
There are utility methods in the base class for actions which either
365
transport no data, or send or receive a single value:
366
link:refdoc/html/classUPnPClient_1_1Service.html#a9ec23e2f36c2bbdefaac4991d80d6063[runTrivialAction()],
367
link:refdoc/html/classUPnPClient_1_1Service.html#a7cde71d714f07a6bb655760238e52e25[runSimpleAction()],
368
link:refdoc/html/classUPnPClient_1_1Service.html#a1de907ba9604a20aaf3611e71ded445d[runSimpleGet()]
369
370
371
=== Methods which may need reimplementation
372
373
----
374
virtual bool UPnPClient::Service::serviceTypeMatch(const std::string& tp)=0;  
375
----
376
377
This is only needed for library version 0.16 and later. It is used by the
378
base class to find a matching service description in the device description
379
service list, which is done when calling
380
link:refdoc/html/classUPnPClient_1_1Service.html#afb13c0cc50b44c9c62e024961cf23b75[initFromDescription()].
381
382
The latter method is useful for building an object in two phases, first an
383
empty constructor, then initialization from the device description.
384
385
Derived classes compare the service types in the list with their own type
386
string.
387
388
----
389
virtual bool UPnPClient::Service::serviceInit(const UPnPDeviceDesc& device,
390
                                          const UPnPServiceDesc& service);
391
----
392
393
This is the part of the initialization specific to the service type. When
394
it is called, the Service class is fully initialized. Most services
395
don't need to do anything in there. An example of use would be the
396
Rendering Control service calling the device to retrieve the range of
397
volume control values.
398
399
An empty implementation is provided by the base class.
400
401
The method is called from
402
link:refdoc/html/classUPnPClient_1_1Service.html#afb13c0cc50b44c9c62e024961cf23b75[initFromDescription()],
403
and, if it does anything, it should be called from the non-empty derived class
404
constructor too.
405
139
== Eventing
406
=== Eventing
140
407
141
== Logging
408
Derived service classes can define a
409
link:refdoc/html/classUPnPClient_1_1Service.html#ac4ba122d2fe124eff620c62cbf5ac1a1[registerCallBack()]
410
method to register a function to be called when an event arrives. 
411
'registerCallBack()' will be called by 'Service::installReporter()' when
412
the user register their interest in events. In turn, 'registerCallback()'
413
should call
414
link:refdoc/html/classUPnPClient_1_1Service.html#a8b8580b88b4fbfc1de18a14d7811169d[Service::registerCallBack(evtCBFunc)]
415
to register their actual callback routine.
416
417
Callback functions can be any 'std::function' taking appropriate arguments,
418
usually a member function of the service object.