Classes | Typedefs

Device Model
[HUPnP Core]

This page explains the concept of HUPnP Device Model, which is the logical object hierarchy of HUPnP representing the UPnP Device Architecture. More...

Classes

class  HAction
 A class that represents a UPnP action found in a UPnP service. More...
class  HActionArgument
 A class that represents an argument for a UPnP action invocation. More...
class  HActionArguments
 A storage class for HActionArgument instances. More...
class  HActionSetup
 This class is used to specify information that is required to setup an HAction. More...
class  HActionsSetupData
 This class is used to specify information that is required to setup the HActions of an HService. More...
class  HAsyncOp
 This class is used to identify an asynchronous operation and detail information of it. More...
class  HDevice
 An abstract base class that represents a UPnP device hosted by the HUPnP library. More...
class  HDeviceProxy
 A class that is used at client-side to represent a UPnP device. More...
class  HDeviceSetup
 This class is used to specify information that is required to setup an HDevice. More...
class  HDevicesSetupData
 This class is used to specify information that can be used to setup multiple HDevice instances. More...
class  HExecArgs
 This class is used to specify information used to control the execution of an asynchronous operation and the notification of its completion. More...
class  HReadableStateVariable
 Class that provides read-only access to a state variable. More...
class  HService
 An abstract base class that represents a UPnP service hosted by an HDevice. More...
class  HServiceProxy
 A class that is used at client-side to represent a service found in a UPnP device. More...
class  HServiceSetup
 This class is used to specify information that is required to setup an HService. More...
class  HServicesSetupData
 This class is used to specify information that can be used to setup multiple HService instances. More...
class  HStateVariable
 Class that represents a UPnP state variable. More...
class  HStateVariableEvent
 A class used to transfer HStateVariable event information. More...
class  HStateVariablesSetupData
 This class is used to specify information that is required to setup the HStateVariables of an HService. More...
class  HWritableStateVariable
 Class that provides write access to a state variable. More...
class  HStateVariableLocker
 A class that enables locking an HWritableStateVariable for exclusive access. More...

Typedefs

typedef Functor< int,
H_TYPELIST_2(const
Herqq::Upnp::HActionArguments
&, Herqq::Upnp::HActionArguments *) 
HActionInvoke )
typedef Functor< bool,
H_TYPELIST_1(HAsyncOp)> 
HActionInvokeCallback
typedef QList< HService * > HServices
typedef QList< HServiceProxy * > HServiceProxies
typedef QList< HDevice * > HDevices
typedef QList< HDeviceProxy * > HDeviceProxies
typedef QList< HStateVariable * > HStateVariables
typedef QList< HAction * > HActions

Detailed Description

A few notes about the design

The main four components of the UPnP device model are a device (Herqq::Upnp::HDevice), a service (Herqq::Upnp::HService), a state variable (Herqq::Upnp::HStateVariable) and an action (Herqq::Upnp::HAction). These four components form a type of a tree in which devices and services are contained by devices, and state variables and actions are contained by services. This is called the device tree. A device tree has a root device, which is a UPnP device that has no parent, but may contain other UPnP devices. These contained devices are called embedded devices.

The purpose of the other classes part of the device model is to support the initialization and use of the four core classes.

API differences between client and server sides

The HUPnP device model is largely the same at the server and client sides. That is, whether you are writing a custom UPnP device or trying to interact with a UPnP device found in the network, you will be interacting with the HUPnP device model similarly. The most notable difference is that whereas at server side you will be interacting with classes derived directly from the main four components (HDevice, HService, HAction and HStateVariable), at client side you will be interacting with devices and services derived from Herqq::Upnp::HDeviceProxy and Herqq::Upnp::HServiceProxy respectively.

The HDeviceProxy is an HDevice and the HServiceProxy is an HService. They both provide some additional methods not found in their base classes, but otherwise their usage is identical. The reason the client side introduces the proxy classes is tied to the very nature of client-server architecture; the server side usually contains the business logic, whereas the client side only invokes it. Put in HUPnP terms, a server side HDevice often contains code that is undesired at client-side and vice versa. Furthermore, the model is clearer when the design makes the difference explicit and as such the model clearly separates the different code bases of server-side and client-side.

The lifetime and ownership of objects

Every HDevice has the ownership of all of its embedded devices, services, actions and state variables and the ownership is never released. This means that every HDevice always manages the memory used by the objects it owns. Hence, the owner of a root HDevice ultimately has the ownership of an entire device tree. This is very important to notice; the lifetime of every object contained by the root device depends of the lifetime of the root device. Or in other words, when a root device is deleted, every embedded device, service, state variable and action underneath it are deleted as well. Furthermore, every root HDevice is always owned by HUPnP and the ownership is never released. Because of this you should never call delete to any of the components of the device model that is setup by HUPnP. This will result in undefined behavior.

Note:
There are situations where you may want to instruct HUPnP to delete an HDevice. For instance, when a UPnP device is removed from the network you may want your HControlPoint instance to remove the device that is no longer available. This can be done through the HControlPoint interface. But note, HUPnP never deletes an HDevice without an explicit request from a user.

Usage

The device model is location independent, which in essence means that the device model is almost always used the same way. That is, if you have a pointer to any of the core components of the device model, you use the object the same way regardless of whether you got the pointer directly or indirectly from a Herqq::Upnp::HDeviceHost or a Herqq::Upnp::HControlPoint. There is one exception to the rule and it will be discussed in the section concerning the state variables.

Basic use is about interacting with already created objects that comprise the device model. To get started you need to initialize either a device host or a control point and retrieve a list of root devices from it. See Device Hosting for more information about device hosts and control points. Once you have a root device you can interact with any of its embedded devices, services, state variables and actions until:

See the corresponding classes for more information concerning their use.

Note:
By default, HControlPoint keeps the state of the state variables up-to-date. That is, using default configuration an HControlPoint automatically subscribes to events the UPnP services expose. In such a case the state of a device tree at control point side reflects the state of the corresponding device tree at device host side as accurately as the device host keeps sending events.

However, if you wish to implement and host your own UPnP device, things get more involved. See Tutorial for Building a UPnP Device to get you started on building your own UPnP devices.

About State Variables

UPnP Device Architecture does not specify a mechanism for changing the value of a state variable from a control point. Certainly the value of a state variable may be changeable, but that and the method how it is done depends of the service type in which the state variable is defined.

As described previously, HUPnP uses the same device model everywhere. This means that the same fundamental core classes are used both at the server and client sides. Perhaps the most significant benefit of this is that it provides uniform API regardless of the type of use. In turn, uniform API calls for simplicity and re-usability, since there is only one class structure to be learned and used on both server and client side programming.

However, the lack of a standardized method for manipulating the values of state variables means that the client and server-side cannot use an exactly symmetrical API. This is because on server-side you have to have read-write access to the state variables, whereas on client-side you have to have read-only access to the state variables. In HUPnP this is abstracted to Herqq::Upnp::HWritableStateVariable and Herqq::Upnp::HReadableStateVariable classes. On device host side the dynamic type of every Herqq::Upnp::HStateVariable is HWritableStateVariable and on control point side the type is HReadableStateVariable.

See also:
Device Hosting

Typedef Documentation

typedef Functor<int, H_TYPELIST_2( const Herqq::Upnp::HActionArguments&, Herqq::Upnp::HActionArguments*) HActionInvoke)

This is a type definition for a callable entity that is used for HAction invocation.

You can create HActionInvoke objects using normal functions, functors and member functions that follow the signature of

qint32 function(const Herqq::Upnp::HActionArguments& inArgs, Herqq::Upnp::HActionArguments* outArgs = 0);

The following example demonstrates how you can instantiate the HActionInvoke for a normal function, functor and a member function.

 #include <HActionInvoke>
 #include <HUpnpCore/HActionArguments>
 #include <HUpnpCore/HActionArguments>

 #include "myclass.h" // your code that contains declaration for MyClass

 namespace
 {
 qint32 freefun(
      const Herqq::Upnp::HActionArguments& inArgs,
      Herqq::Upnp::HActionArguments* outArgs)
 {
     return 0;
 }

 class MyFunctor
 {
 public:
     qint32 operator()(
         const Herqq::Upnp::HActionArguments& inArgs,
         Herqq::Upnp::HActionArguments* outArgs)
     {
         return 0;
     }
 };
 }

 qint32 MyClass::memfun(
      const Herqq::Upnp::HActionArguments& inArgs,
      Herqq::Upnp::HActionArguments* outArgs = 0)
 {
 }

 void MyClass::example()
 {
     Herqq::Upnp::HActionInvoke usingFreeFunction(freefun);

     MyFunctor myfunc;
     Herqq::Upnp::HActionInvoke usingFunctor(myfunc);

     Herqq::Upnp::HActionInvoke usingMemberFunction(this, &MyClass::memfun);
 }

You can test if the object can be invoked simply by issuing if (actionInvokeObject) { ... }

typedef Functor<bool, H_TYPELIST_1(HAsyncOp)> HActionInvokeCallback

This is a type definition for a callable entity that is used as a callback for signaling the completion of an HAction invocation.

You can create HActionInvokeCallback objects using normal functions, functors and member functions that follow the signature of

bool function(HAsyncOp);

Parameters

  • The first parameter is a type of an "ID" of the asynchronous action invocation.
  • The second parameter is the return value of the action invocation.
  • The third parameter specifies the output arguments of the action invocation, which may be empty.

Return value

The return value indicates if the invoked HAction should emit an HAction::invokeComplete() or HAction::invokeFailed() signal depending on the outcome of the invocation after the callback has returned.

  • true indicates that the HAction should sent the corresponding event.

The following example demonstrates how you can instantiate the HActionInvokeCallback for a normal function, functor and a member function.

 #include <HUpnpCore/HAction>

 #include "myclass.h" // your code that contains declaration for MyClass

 namespace
 {
 bool freefun(HAsyncOp)
 {
     return true;
 }

 class MyFunctor
 {
 public:
     bool operator()(HAsyncOp)
     {
         return true;
     }
 };
 }

 bool MyClass::memfun(HAsyncOp)
 {
     return true;
 }

 void MyClass::example()
 {
     Herqq::Upnp::HActionInvokeCallback usingFreeFunction(freefun);

     MyFunctor myfunc;
     Herqq::Upnp::HActionInvokeCallback usingFunctor(myfunc);

     Herqq::Upnp::HActionInvokeCallback usingMemberFunction(this, &MyClass::memfun);
 }

You can test if the object can be invoked simply by issuing if (actionInvokeCallbackObject) { ... }

typedef QList<HService*> HServices

This is a type definition for a collection of pointers to Herqq::Upnp::HService instances.

See also:
HService
typedef QList<HServiceProxy*> HServiceProxies

This is a type definition for a collection of pointers to Herqq::Upnp::HServiceProxy instances.

See also:
HServiceProxy
typedef QList<HDevice*> HDevices

This is a type definition for a collection of pointers to Herqq::Upnp::HDevice instances.

See also:
HDevice
typedef QList<HDeviceProxy*> HDeviceProxies

This is a type definition for a collection of pointers to Herqq::Upnp::HDeviceProxy instances.

See also:
HDeviceProxy
typedef QList<HStateVariable*> HStateVariables

This is a type definition for a collection of pointers to Herqq::Upnp::HStateVariable instances.

See also:
HStateVariable
typedef QList<HAction*> HActions

This is a type definition for a collection of pointers to Herqq::Upnp::HAction instances.

See also:
HAction