summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Guiraud <christophe.guiraud@intel.com>2013-06-21 11:25:49 +0200
committerrmerlino <regis.merlino@intel.com>2013-12-12 14:49:11 +0100
commit13951f33b7a854364a05b7b38893261822cd0e83 (patch)
tree6af12062356f5b531e597dd2d232101b5318ccb7
parent13b04ba9dd121b8ccc29ea5f0a61188280922091 (diff)
downloaddleyna-server-13951f33b7a854364a05b7b38893261822cd0e83.tar.gz
[Device] Add Energy Management features
- Add a Wake method to DBus MediaDevice interface, this method can be invoked to wake-up a sleeping device by sending the appropriate WOL magic packet. Information to be used for the magic packet formatting will be retrieved from the device context. - Add a DLS_INTERFACE_PROP_SLEEPING boolean property to DBus MediaDevice interface, this property reflects the sleeping state of the MediaServer. The property is not present if the Energy Management service isn't supported by the device embedding the MediaServer. The DLS_INTERFACE_PROP_SLEEPING property is updated based on the EM service NetworkInterfaceInfo evented state variable. The DLS_INTERFACE_PROP_SLEEPING property is set to FALSE by default at the device construction. NetworkInterfaceInfo information are XML encoded, relevant information are parsed with the help of libxml2. dleyna-server has now a direct dependency on libxml2. a new xml-util.c file with its header provides libxml2 helpers. XML extracted information are stored into the matching device context. The matching device context is selected based on the interface ip address and the device uuid. A device is considered as in sleeping state if its network interface is up. - Add a DLS_INTERFACE_PROP_ROOT_UDN string property, if present this property contains the UDN of the root device embedding a MediaServer sub-device. - Update the device contruction to allow the usage of a MediaServer even if it is sub-device, in the same as way if it was the root device from the application layer perpective. We ask now to be notified for all upnp:rootdevice and we filter those who are MediaServer or have a sub device of this type. (recursive lookup in the device child hierarchy if any). Only the first MediaServer device found will be considered. we also retrieve the Energy Management service proxy from the root device if it is available and else we use the first one that we found by doing a recursive lookup in the device child hierarchy. we use it to be notified of its NetworkInterfaceInfo evented state variable changes. - As we have now to handle multiple device proxies (CDS, EMS), we use now a struct dls_service_t to gather cds and ems services related information (GUPnPServiceProxy *proxy, gboolean subscribed, guint timeout_id) in the device context. - Add the Wake Method to the python test application. - Documentation updated. Signed-off-by: Christophe Guiraud <christophe.guiraud@intel.com>
-rw-r--r--configure.ac1
-rw-r--r--doc/server/dbus/API.txt12
-rw-r--r--libdleyna/server/Makefile.am10
-rw-r--r--libdleyna/server/device.c769
-rw-r--r--libdleyna/server/device.h37
-rw-r--r--libdleyna/server/interface.h3
-rw-r--r--libdleyna/server/props.c29
-rw-r--r--libdleyna/server/props.h8
-rw-r--r--libdleyna/server/server.c14
-rw-r--r--libdleyna/server/task.c13
-rw-r--r--libdleyna/server/task.h7
-rw-r--r--libdleyna/server/upnp.c147
-rw-r--r--libdleyna/server/upnp.h8
-rw-r--r--libdleyna/server/xml-util.c133
-rw-r--r--libdleyna/server/xml-util.h35
-rw-r--r--test/dbus/mediaconsole.py3
16 files changed, 1006 insertions, 223 deletions
diff --git a/configure.ac b/configure.ac
index 355f516..539aa43 100644
--- a/configure.ac
+++ b/configure.ac
@@ -43,6 +43,7 @@ PKG_CHECK_MODULES([GUPNP], [gupnp-1.0 >= 0.20.3])
PKG_CHECK_MODULES([GUPNPAV], [gupnp-av-1.0 >= 0.11.5])
PKG_CHECK_MODULES([GUPNPDLNA], [gupnp-dlna-2.0 >= 0.9.4])
PKG_CHECK_MODULES([SOUP], [libsoup-2.4 >= 2.28.2])
+PKG_CHECK_MODULES([LIBXML], [libxml-2.0])
# Checks for header files.
AC_CHECK_HEADERS([stdlib.h string.h syslog.h])
diff --git a/doc/server/dbus/API.txt b/doc/server/dbus/API.txt
index 0804691..2943378 100644
--- a/doc/server/dbus/API.txt
+++ b/doc/server/dbus/API.txt
@@ -204,6 +204,9 @@ below:
|------------------------------------------------------------------------------|
| UDN | s | m | The Unique Device Name of the server. |
|------------------------------------------------------------------------------|
+| RootUDN | s | o | The Unique Device Name of the root |
+| | | | device, if the server is a sub-device. |
+|------------------------------------------------------------------------------|
| FriendlyName | s | m | The friendly name of the media server. |
-------------------------------------------------------------------------------|
| IconURL | s | o | A URL pointing to an icon that |
@@ -265,7 +268,9 @@ below:
| SystemUpdateID | u | m | An integer value that is incremenented |
| | | | every time changes are made to the DMS. |
|------------------------------------------------------------------------------|
-
+| Sleeping | b | o | An boolean value which represents the |
+| | | | server sleeping state. |
+|------------------------------------------------------------------------------|
(* where m/o indicates whether the property is optional or mandatory )
(1) A value of -1 for the srs-rt-retention-period capability denotes an
infinite retention period.
@@ -350,6 +355,7 @@ Both RequestedMimeType and Resolution parameters are currently
reserved for future use and should be set as an empty string.
BrowseObjects(as ObjectPath, as Filter) -> aa{sv}
+
This method returns properties of all media objects specified by the first
parameter. The list of properties to return is specified by the second
parameter.
@@ -375,6 +381,10 @@ The purposes of this method are:
retrieve a subset of an object's properties. Browse is likely to be more
efficient than GetAll in such cases.
+Wake() -> void
+
+Sends a magic packet to the server to wake it up if it is in sleeping state.
+
Signals:
---------
diff --git a/libdleyna/server/Makefile.am b/libdleyna/server/Makefile.am
index 0c8a6d8..020b41c 100644
--- a/libdleyna/server/Makefile.am
+++ b/libdleyna/server/Makefile.am
@@ -8,6 +8,7 @@ AM_CFLAGS = $(GLIB_CFLAGS) \
$(GUPNPAV_CFLAGS) \
$(GUPNPDLNA_CFLAGS) \
$(SOUP_CFLAGS) \
+ $(LIBXML_CFLAGS) \
-include config.h
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
@@ -31,7 +32,8 @@ libdleyna_server_1_0_la_SOURCES = $(libdleyna_serverinc_HEADERS) \
search.c \
sort.c \
task.c \
- upnp.c
+ upnp.c \
+ xml-util.c
libdleyna_server_1_0_la_LIBADD = $(GLIB_LIBS) \
$(GIO_LIBS) \
@@ -40,7 +42,8 @@ libdleyna_server_1_0_la_LIBADD = $(GLIB_LIBS) \
$(GUPNP_LIBS) \
$(GUPNPAV_LIBS) \
$(GUPNPDLNA_LIBS) \
- $(SOUP_LIBS)
+ $(SOUP_LIBS) \
+ $(LIBXML_LIBS)
MAINTAINERCLEANFILES = Makefile.in \
aclocal.m4 \
@@ -66,7 +69,8 @@ EXTRA_DIST = $(sysconf_DATA) \
server.h \
sort.h \
task.h \
- upnp.h
+ upnp.h \
+ xml-util.h
CLEANFILES = dleyna-server-service.conf
DISTCLEANFILES = dleyna-server-service.conf
diff --git a/libdleyna/server/device.c b/libdleyna/server/device.c
index 86045f2..d5d5bf8 100644
--- a/libdleyna/server/device.c
+++ b/libdleyna/server/device.c
@@ -36,12 +36,17 @@
#include "interface.h"
#include "path.h"
#include "server.h"
+#include "xml-util.h"
#define DLS_SYSTEM_UPDATE_VAR "SystemUpdateID"
#define DLS_CONTAINER_UPDATE_VAR "ContainerUpdateIDs"
#define DLS_LAST_CHANGE_VAR "LastChange"
+#define DLS_NETWORK_INTERFACE_INFO_VAR "NetworkInterfaceInfo"
#define DLS_DMS_DEVICE_TYPE "urn:schemas-upnp-org:device:MediaServer:"
-
+#define DLS_CONTENT_DIRECTORY_SERVICE_TYPE \
+ "urn:schemas-upnp-org:service:ContentDirectory"
+#define DLS_ENERGY_MANAGEMENT_SERVICE_TYPE \
+ "urn:schemas-upnp-org:service:EnergyManagement:1"
#define DLS_UPLOAD_STATUS_IN_PROGRESS "IN_PROGRESS"
#define DLS_UPLOAD_STATUS_CANCELLED "CANCELLED"
#define DLS_UPLOAD_STATUS_ERROR "ERROR"
@@ -122,6 +127,10 @@ static void prv_last_change_cb(GUPnPServiceProxy *proxy,
const char *variable,
GValue *value,
gpointer user_data);
+static void prv_network_interface_info_cb(GUPnPServiceProxy *proxy,
+ const char *variable,
+ GValue *value,
+ gpointer user_data);
static void prv_upload_delete(gpointer up);
static void prv_upload_job_delete(gpointer up);
static void prv_get_sr_token_for_props(GUPnPServiceProxy *proxy,
@@ -135,6 +144,8 @@ static GUPnPServiceProxyAction *prv_browse_objects_begin_action_cb(
GUPnPServiceProxy *proxy,
gboolean *failed);
+static void prv_free_network_if_info(dls_network_if_info_t *info);
+
static void prv_object_builder_delete(void *dob)
{
dls_device_object_builder_t *builder = dob;
@@ -163,32 +174,45 @@ static void prv_count_data_new(dls_async_task_t *cb_data,
static void prv_context_unsubscribe(dls_device_context_t *ctx)
{
- if (ctx->timeout_id) {
- (void) g_source_remove(ctx->timeout_id);
- ctx->timeout_id = 0;
+ if (ctx->cds.timeout_id) {
+ (void) g_source_remove(ctx->cds.timeout_id);
+ ctx->cds.timeout_id = 0;
}
- if (ctx->subscribed) {
- gupnp_service_proxy_remove_notify(
- ctx->service_proxy,
- DLS_SYSTEM_UPDATE_VAR,
- prv_system_update_cb,
- ctx->device);
- gupnp_service_proxy_remove_notify(
- ctx->service_proxy,
- DLS_CONTAINER_UPDATE_VAR,
- prv_container_update_cb,
- ctx->device);
+ if (ctx->ems.timeout_id) {
+ (void) g_source_remove(ctx->ems.timeout_id);
+ ctx->ems.timeout_id = 0;
+ }
+
+ if (ctx->cds.subscribed) {
+ gupnp_service_proxy_remove_notify(ctx->cds.proxy,
+ DLS_SYSTEM_UPDATE_VAR,
+ prv_system_update_cb,
+ ctx->device);
+ gupnp_service_proxy_remove_notify(ctx->cds.proxy,
+ DLS_CONTAINER_UPDATE_VAR,
+ prv_container_update_cb,
+ ctx->device);
+ gupnp_service_proxy_remove_notify(ctx->cds.proxy,
+ DLS_LAST_CHANGE_VAR,
+ prv_last_change_cb,
+ ctx->device);
+
+ gupnp_service_proxy_set_subscribed(ctx->cds.proxy, FALSE);
+
+ ctx->cds.subscribed = FALSE;
+ }
+
+ if (ctx->ems.subscribed) {
gupnp_service_proxy_remove_notify(
- ctx->service_proxy,
- DLS_LAST_CHANGE_VAR,
- prv_last_change_cb,
- ctx->device);
+ ctx->ems.proxy,
+ DLS_NETWORK_INTERFACE_INFO_VAR,
+ prv_network_interface_info_cb,
+ ctx->device);
- gupnp_service_proxy_set_subscribed(ctx->service_proxy,
- FALSE);
+ gupnp_service_proxy_set_subscribed(ctx->ems.proxy, FALSE);
- ctx->subscribed = FALSE;
+ ctx->ems.subscribed = FALSE;
}
}
@@ -199,35 +223,94 @@ static void prv_context_delete(gpointer context)
if (ctx) {
prv_context_unsubscribe(ctx);
+ if (ctx->device_info)
+ g_object_unref(ctx->device_info);
+
if (ctx->device_proxy)
g_object_unref(ctx->device_proxy);
- if (ctx->service_proxy)
- g_object_unref(ctx->service_proxy);
+ prv_free_network_if_info(ctx->network_if_info);
+
+ if (ctx->cds.proxy)
+ g_object_unref(ctx->cds.proxy);
+
+ if (ctx->ems.proxy)
+ g_object_unref(ctx->ems.proxy);
g_free(ctx->ip_address);
g_free(ctx);
}
}
+static GUPnPServiceInfo *prv_lookup_em_service(GUPnPDeviceInfo *device_info)
+{
+ GList *child_devices;
+ GList *next;
+ GUPnPDeviceInfo *child_info = NULL;
+ GUPnPServiceInfo *service_info = NULL;
+
+ child_devices = gupnp_device_info_list_devices(device_info);
+
+ next = child_devices;
+ while (next != NULL) {
+ child_info = (GUPnPDeviceInfo *)next->data;
+
+ service_info = gupnp_device_info_get_service(child_info,
+ DLS_ENERGY_MANAGEMENT_SERVICE_TYPE);
+
+ if (service_info != NULL)
+ break;
+
+ service_info = prv_lookup_em_service(child_info);
+
+ if (service_info != NULL)
+ break;
+
+ next = g_list_next(next);
+ }
+
+ g_list_free_full(child_devices, g_object_unref);
+
+ return service_info;
+}
+
static void prv_context_new(const gchar *ip_address,
GUPnPDeviceProxy *proxy,
+ GUPnPDeviceInfo *device_info,
dls_device_t *device,
dls_device_context_t **context)
{
- const gchar *service_type =
- "urn:schemas-upnp-org:service:ContentDirectory";
dls_device_context_t *ctx = g_new(dls_device_context_t, 1);
ctx->ip_address = g_strdup(ip_address);
ctx->device_proxy = proxy;
+ ctx->device_info = device_info;
+
ctx->device = device;
+ ctx->cds.subscribed = FALSE;
+ ctx->cds.timeout_id = 0;
+ ctx->ems.subscribed = FALSE;
+ ctx->ems.timeout_id = 0;
+
+ ctx->network_if_info = NULL;
+
g_object_ref(proxy);
- ctx->service_proxy = (GUPnPServiceProxy *)
- gupnp_device_info_get_service((GUPnPDeviceInfo *)proxy,
- service_type);
- ctx->subscribed = FALSE;
- ctx->timeout_id = 0;
+ g_object_ref(device_info);
+
+ ctx->cds.proxy = (GUPnPServiceProxy *)
+ gupnp_device_info_get_service(
+ device_info,
+ DLS_CONTENT_DIRECTORY_SERVICE_TYPE);
+
+ ctx->ems.proxy = (GUPnPServiceProxy *)
+ gupnp_device_info_get_service(
+ (GUPnPDeviceInfo *)proxy,
+ DLS_ENERGY_MANAGEMENT_SERVICE_TYPE);
+
+ if (ctx->ems.proxy == NULL)
+ ctx->ems.proxy = (GUPnPServiceProxy *)
+ prv_lookup_em_service(
+ (GUPnPDeviceInfo *)proxy);
*context = ctx;
}
@@ -459,6 +542,254 @@ on_error:
g_error_free(error);
}
+static void prv_free_network_if_info(dls_network_if_info_t *info)
+{
+ if (info != NULL) {
+ g_free(info->mac_address);
+ g_free(info->device_uuid);
+ g_free(info->network_if_mode);
+ g_free(info->wake_on_pattern);
+ g_free(info->wake_transport);
+ g_list_free_full(info->ip_addresses, g_free);
+
+ g_free(info);
+ }
+}
+
+static dls_network_if_info_t *prv_get_network_if_info(xmlNode *device_if_node)
+{
+ dls_network_if_info_t *info = NULL;
+ GList *ipv4_addresses;
+ GList *ipv6_addresses;
+
+ info = g_new0(dls_network_if_info_t, 1);
+
+ ipv4_addresses = xml_util_get_child_string_list_content_by_name(
+ device_if_node,
+ "NetworkInterface",
+ "AssociatedIpAddresses",
+ "Ipv4", NULL);
+
+ ipv6_addresses = xml_util_get_child_string_list_content_by_name(
+ device_if_node,
+ "NetworkInterface",
+ "AssociatedIpAddresses",
+ "Ipv6", NULL);
+
+ info->ip_addresses = g_list_concat(ipv4_addresses, ipv6_addresses);
+
+ info->device_uuid = xml_util_get_child_string_content_by_name(
+ device_if_node,
+ "DeviceUUID", NULL);
+
+ info->mac_address = xml_util_get_child_string_content_by_name(
+ device_if_node,
+ "NetworkInterface",
+ "MacAddress", NULL);
+
+ info->network_if_mode = xml_util_get_child_string_content_by_name(
+ device_if_node,
+ "NetworkInterface",
+ "NetworkInterfaceMode"
+ , NULL);
+
+ info->wake_on_pattern = xml_util_get_child_string_content_by_name(
+ device_if_node,
+ "NetworkInterface",
+ "WakeOnPattern", NULL);
+
+ info->wake_transport = xml_util_get_child_string_content_by_name(
+ device_if_node,
+ "NetworkInterface",
+ "WakeSupportedTransport", NULL);
+
+ if ((info->device_uuid == NULL || strlen(info->device_uuid) > 70) ||
+ (info->mac_address == NULL || strlen(info->mac_address) != 17) ||
+ (info->network_if_mode == NULL) || (info->ip_addresses == NULL) ||
+ (info->wake_on_pattern == NULL) || (info->wake_transport == NULL))
+ goto on_error;
+
+ return info;
+
+on_error:
+ prv_free_network_if_info(info);
+
+ return NULL;
+}
+
+static GList *prv_network_if_info_decode(const gchar *info)
+{
+ xmlDoc *doc;
+ xmlNode *node;
+ GList *info_list = NULL;
+ dls_network_if_info_t *if_info;
+
+ DLEYNA_LOG_DEBUG("Enter");
+
+ DLEYNA_LOG_DEBUG_NL();
+ DLEYNA_LOG_DEBUG("NetworkInterfaceInfo XML: %s", info);
+ DLEYNA_LOG_DEBUG_NL();
+
+ doc = xmlParseMemory(info, strlen(info) + 1);
+ if (doc == NULL) {
+ DLEYNA_LOG_WARNING("XML: invalid document");
+
+ goto on_exit;
+ }
+
+ node = xmlDocGetRootElement(doc);
+ if (node == NULL) {
+ DLEYNA_LOG_WARNING("XML: empty document");
+
+ goto on_exit;
+ }
+
+ if (node->name == NULL) {
+ DLEYNA_LOG_WARNING("XML: empty document name");
+
+ goto on_exit;
+ }
+
+ if (strcmp((char *)node->name, "NetworkInterfaceInfo")) {
+ DLEYNA_LOG_WARNING("XML: invalid document name");
+
+ goto on_exit;
+ }
+
+ for (node = node->children; node; node = node->next) {
+ if (node->name != NULL &&
+ !strcmp((char *)node->name, "DeviceInterface")) {
+ if_info = prv_get_network_if_info(node);
+
+ if (if_info != NULL)
+ info_list = g_list_prepend(info_list, if_info);
+ }
+ }
+
+on_exit:
+ DLEYNA_LOG_DEBUG("Exit");
+
+ if (doc != NULL)
+ xmlFreeDoc(doc);
+
+ return info_list;
+}
+
+static gboolean prv_lookup_device_ctx_network_if_info(dls_device_context_t *ctx,
+ dls_network_if_info_t *info,
+ gboolean *sleeping)
+{
+ gboolean found = FALSE;
+ const gchar *udn;
+ gchar *ip_address;
+ GList *next;
+
+ next = info->ip_addresses;
+ while (next != NULL) {
+ ip_address = (gchar *)next->data;
+ if (!strcmp(ctx->ip_address, ip_address)) {
+ udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *)
+ ctx->device_proxy);
+ if (!strcmp(info->device_uuid, udn)) {
+ found = TRUE;
+ if (!strcmp(info->network_if_mode, "IP-up"))
+ *sleeping = FALSE;
+ else
+ *sleeping = TRUE;
+ }
+ }
+
+ if (found)
+ break;
+
+ next = g_list_next(next);
+ }
+
+ return found;
+}
+
+static gboolean prv_get_device_sleeping_state(dls_device_t *device,
+ const gchar *network_if_info_xml,
+ gboolean *sleeping)
+{
+ dls_network_if_info_t *info;
+ GList *info_list;
+ GList *next;
+ unsigned int i;
+ dls_device_context_t *ctx;
+ gboolean found = FALSE;
+
+ info_list = prv_network_if_info_decode(network_if_info_xml);
+ if (info_list == NULL)
+ goto on_exit;
+
+ next = info_list;
+ while (next != NULL) {
+ info = (dls_network_if_info_t *)next->data;
+ for (i = 0; i < device->contexts->len; ++i) {
+ ctx = g_ptr_array_index(device->contexts, i);
+ found = prv_lookup_device_ctx_network_if_info(ctx,
+ info,
+ sleeping);
+ if (found)
+ break;
+ }
+
+ next = g_list_next(next);
+
+ if (found) {
+ prv_free_network_if_info(ctx->network_if_info);
+
+ ctx->network_if_info = info;
+
+ info_list = g_list_remove(info_list, info);
+
+ break;
+ }
+ }
+
+ g_list_free_full(info_list, (GDestroyNotify)prv_free_network_if_info);
+
+on_exit:
+
+ return found;
+}
+
+static void prv_network_interface_info_cb(GUPnPServiceProxy *proxy,
+ const char *variable,
+ GValue *value,
+ gpointer user_data)
+{
+ dls_device_t *device = user_data;
+ GVariantBuilder *array;
+ GVariant *val;
+ gboolean sleeping;
+
+ if (prv_get_device_sleeping_state(device,
+ g_value_get_string(value),
+ &sleeping)) {
+ device->sleeping = sleeping;
+
+ array = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ g_variant_builder_add(array, "{sv}",
+ DLS_INTERFACE_PROP_SLEEPING,
+ g_variant_new_boolean(sleeping));
+ val = g_variant_new("(s@a{sv}as)",
+ DLEYNA_SERVER_INTERFACE_MEDIA_DEVICE,
+ g_variant_builder_end(array),
+ NULL);
+
+ (void) dls_server_get_connector()->notify(device->connection,
+ device->path,
+ DLS_INTERFACE_PROPERTIES,
+ DLS_INTERFACE_PROPERTIES_CHANGED,
+ val,
+ NULL);
+
+ g_variant_builder_unref(array);
+ }
+}
+
static void prv_build_container_update_array(const gchar *root_path,
const gchar *value,
GVariantBuilder *builder)
@@ -599,49 +930,82 @@ static void prv_system_update_cb(GUPnPServiceProxy *proxy,
g_variant_builder_unref(array);
}
-static gboolean prv_re_enable_subscription(gpointer user_data)
+static gboolean prv_re_enable_cd_subscription(gpointer user_data)
{
dls_device_context_t *context = user_data;
- context->timeout_id = 0;
+ context->cds.timeout_id = 0;
return FALSE;
}
-static void prv_subscription_lost_cb(GUPnPServiceProxy *proxy,
+static void prv_cd_subscription_lost_cb(GUPnPServiceProxy *proxy,
const GError *reason,
gpointer user_data)
{
dls_device_context_t *context = user_data;
- if (!context->timeout_id) {
- gupnp_service_proxy_set_subscribed(context->service_proxy,
- TRUE);
- context->timeout_id = g_timeout_add_seconds(
+ if (!context->cds.timeout_id) {
+ gupnp_service_proxy_set_subscribed(context->cds.proxy, TRUE);
+ context->cds.timeout_id = g_timeout_add_seconds(
10,
- prv_re_enable_subscription,
+ prv_re_enable_cd_subscription,
context);
} else {
- g_source_remove(context->timeout_id);
- gupnp_service_proxy_remove_notify(context->service_proxy,
+ g_source_remove(context->cds.timeout_id);
+ gupnp_service_proxy_remove_notify(context->cds.proxy,
DLS_SYSTEM_UPDATE_VAR,
prv_system_update_cb,
context->device);
- gupnp_service_proxy_remove_notify(context->service_proxy,
+ gupnp_service_proxy_remove_notify(context->cds.proxy,
DLS_CONTAINER_UPDATE_VAR,
prv_container_update_cb,
context->device);
- gupnp_service_proxy_remove_notify(context->service_proxy,
+ gupnp_service_proxy_remove_notify(context->cds.proxy,
DLS_LAST_CHANGE_VAR,
prv_last_change_cb,
context->device);
- context->timeout_id = 0;
- context->subscribed = FALSE;
+ context->cds.timeout_id = 0;
+ context->cds.subscribed = FALSE;
+ }
+}
+
+static gboolean prv_re_enable_em_subscription(gpointer user_data)
+{
+ dls_device_context_t *context = user_data;
+
+ context->cds.timeout_id = 0;
+
+ return FALSE;
+}
+
+static void prv_em_subscription_lost_cb(GUPnPServiceProxy *proxy,
+ const GError *reason,
+ gpointer user_data)
+{
+ dls_device_context_t *context = user_data;
+
+ if (!context->ems.timeout_id) {
+ gupnp_service_proxy_set_subscribed(context->ems.proxy, TRUE);
+ context->ems.timeout_id = g_timeout_add_seconds(
+ 10,
+ prv_re_enable_em_subscription,
+ context);
+ } else {
+ g_source_remove(context->ems.timeout_id);
+ gupnp_service_proxy_remove_notify(
+ context->ems.proxy,
+ DLS_NETWORK_INTERFACE_INFO_VAR,
+ prv_network_interface_info_cb,
+ context->device);
+
+ context->ems.timeout_id = 0;
+ context->ems.subscribed = FALSE;
}
}
-void dls_device_subscribe_to_contents_change(dls_device_t *device)
+void dls_device_subscribe_to_service_changes(dls_device_t *device)
{
dls_device_context_t *context;
@@ -650,31 +1014,47 @@ void dls_device_subscribe_to_contents_change(dls_device_t *device)
DLEYNA_LOG_DEBUG("Subscribe for events on context: %s",
context->ip_address);
- gupnp_service_proxy_add_notify(context->service_proxy,
- DLS_SYSTEM_UPDATE_VAR,
- G_TYPE_UINT,
- prv_system_update_cb,
- device);
-
- gupnp_service_proxy_add_notify(context->service_proxy,
- DLS_CONTAINER_UPDATE_VAR,
- G_TYPE_STRING,
- prv_container_update_cb,
- device);
+ if (context->cds.proxy) {
+ gupnp_service_proxy_add_notify(context->cds.proxy,
+ DLS_SYSTEM_UPDATE_VAR,
+ G_TYPE_UINT,
+ prv_system_update_cb,
+ device);
+
+ gupnp_service_proxy_add_notify(context->cds.proxy,
+ DLS_CONTAINER_UPDATE_VAR,
+ G_TYPE_STRING,
+ prv_container_update_cb,
+ device);
+
+ gupnp_service_proxy_add_notify(context->cds.proxy,
+ DLS_LAST_CHANGE_VAR,
+ G_TYPE_STRING,
+ prv_last_change_cb,
+ device);
+
+ context->cds.subscribed = TRUE;
+ gupnp_service_proxy_set_subscribed(context->cds.proxy, TRUE);
+
+ g_signal_connect(context->cds.proxy, "subscription-lost",
+ G_CALLBACK(prv_cd_subscription_lost_cb),
+ context);
+ }
- gupnp_service_proxy_add_notify(context->service_proxy,
- DLS_LAST_CHANGE_VAR,
- G_TYPE_STRING,
- prv_last_change_cb,
- device);
+ if (context->ems.proxy) {
+ gupnp_service_proxy_add_notify(context->ems.proxy,
+ DLS_NETWORK_INTERFACE_INFO_VAR,
+ G_TYPE_STRING,
+ prv_network_interface_info_cb,
+ device);
- context->subscribed = TRUE;
- gupnp_service_proxy_set_subscribed(context->service_proxy, TRUE);
+ context->ems.subscribed = TRUE;
+ gupnp_service_proxy_set_subscribed(context->ems.proxy, TRUE);
- g_signal_connect(context->service_proxy,
- "subscription-lost",
- G_CALLBACK(prv_subscription_lost_cb),
- context);
+ g_signal_connect(context->ems.proxy, "subscription-lost",
+ G_CALLBACK(prv_em_subscription_lost_cb),
+ context);
+ }
}
static void prv_feature_list_add_feature(gchar *root_path,
@@ -1039,7 +1419,7 @@ static GUPnPServiceProxyAction *prv_subscribe(dleyna_service_task_t *task,
device = (dls_device_t *)dleyna_service_task_get_user_data(task);
device->construct_step++;
- dls_device_subscribe_to_contents_change(device);
+ dls_device_subscribe_to_service_changes(device);
*failed = FALSE;
@@ -1141,7 +1521,7 @@ void dls_device_construct(
priv_t->vtable = dispatch_table;
priv_t->property_map = property_map;
- s_proxy = context->service_proxy;
+ s_proxy = context->cds.proxy;
if (dev->construct_step < 1)
dleyna_service_task_add(queue_id, prv_get_search_capabilities,
@@ -1179,6 +1559,7 @@ void dls_device_construct(
dls_device_t *dls_device_new(
dleyna_connector_id_t connection,
GUPnPDeviceProxy *proxy,
+ GUPnPDeviceInfo *device_info,
const gchar *ip_address,
const dleyna_connector_dispatch_cb_t *dispatch_table,
GHashTable *property_map,
@@ -1200,7 +1581,8 @@ dls_device_t *dls_device_new(
dev->contexts = g_ptr_array_new_with_free_func(prv_context_delete);
dev->path = new_path;
- context = dls_device_append_new_context(dev, ip_address, proxy);
+ context = dls_device_append_new_context(dev, ip_address,
+ proxy, device_info);
dls_device_construct(dev, context, connection, dispatch_table,
property_map, queue_id);
@@ -1209,12 +1591,13 @@ dls_device_t *dls_device_new(
}
dls_device_context_t *dls_device_append_new_context(dls_device_t *device,
- const gchar *ip_address,
- GUPnPDeviceProxy *proxy)
+ const gchar *ip_address,
+ GUPnPDeviceProxy *proxy,
+ GUPnPDeviceInfo *device_info)
{
dls_device_context_t *context;
- prv_context_new(ip_address, proxy, device, &context);
+ prv_context_new(ip_address, proxy, device_info, device, &context);
g_ptr_array_add(device->contexts, context);
return context;
@@ -1495,8 +1878,13 @@ void dls_device_get_children(dls_client_t *client,
context = dls_device_get_context(task->target.device, client);
+ cb_data->proxy = context->cds.proxy;
+
+ g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)),
+ (gpointer *)&cb_data->proxy);
+
cb_data->action =
- gupnp_service_proxy_begin_action(context->service_proxy,
+ gupnp_service_proxy_begin_action(cb_data->proxy,
"Browse",
prv_get_children_cb,
cb_data,
@@ -1517,11 +1905,6 @@ void dls_device_get_children(dls_client_t *client,
sort_by,
NULL);
- cb_data->proxy = context->service_proxy;
-
- g_object_add_weak_pointer((G_OBJECT(context->service_proxy)),
- (gpointer *)&cb_data->proxy);
-
cb_data->cancel_id = g_cancellable_connect(
cb_data->cancellable,
G_CALLBACK(dls_async_task_cancelled_cb),
@@ -1645,7 +2028,7 @@ static void prv_get_all(GUPnPDIDLLiteParser *parser,
}
}
-static gboolean prv_subscribed(const dls_device_t *device)
+static gboolean prv_cds_subscribed(const dls_device_t *device)
{
dls_device_context_t *context;
unsigned int i;
@@ -1653,7 +2036,7 @@ static gboolean prv_subscribed(const dls_device_t *device)
for (i = 0; i < device->contexts->len; ++i) {
context = g_ptr_array_index(device->contexts, i);
- if (context->subscribed) {
+ if (context->cds.subscribed) {
subscribed = TRUE;
break;
}
@@ -1712,7 +2095,7 @@ static void prv_get_system_update_id_for_prop(GUPnPServiceProxy *proxy,
DLEYNA_LOG_DEBUG("Enter");
- if (prv_subscribed(device)) {
+ if (prv_cds_subscribed(device)) {
suid = device->system_update_id;
cb_data->task.result = g_variant_ref_sink(
@@ -1805,7 +2188,7 @@ static void prv_get_system_update_id_for_props(GUPnPServiceProxy *proxy,
DLEYNA_LOG_DEBUG("Enter");
- if (prv_subscribed(device)) {
+ if (prv_cds_subscribed(device)) {
suid = device->system_update_id;
cb_task_data = &cb_data->ut.get_all;
@@ -2135,6 +2518,7 @@ static void prv_get_all_ms2spec_props_cb(GUPnPServiceProxy *proxy,
goto no_complete;
} else if (cb_data->task.type == DLS_TASK_GET_ALL_PROPS &&
cb_task_data->device_object) {
+
prv_get_system_update_id_for_props(proxy,
cb_data->task.target.device,
cb_data);
@@ -2193,7 +2577,7 @@ static void prv_get_all_ms2spec_props(dls_device_context_t *context,
}
cb_data->action = gupnp_service_proxy_begin_action(
- context->service_proxy, "Browse",
+ context->cds.proxy, "Browse",
prv_get_all_ms2spec_props_cb, cb_data,
"ObjectID", G_TYPE_STRING, task->target.id,
"BrowseFlag", G_TYPE_STRING, "BrowseMetadata",
@@ -2203,9 +2587,9 @@ static void prv_get_all_ms2spec_props(dls_device_context_t *context,
"SortCriteria", G_TYPE_STRING,
"", NULL);
- cb_data->proxy = context->service_proxy;
+ cb_data->proxy = context->cds.proxy;
- g_object_add_weak_pointer((G_OBJECT(context->service_proxy)),
+ g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)),
(gpointer *)&cb_data->proxy);
cb_data->cancel_id = g_cancellable_connect(
@@ -2246,15 +2630,16 @@ void dls_device_get_all_props(dls_client_t *client,
if (!strcmp(task_data->interface_name,
DLEYNA_SERVER_INTERFACE_MEDIA_DEVICE)) {
if (root_object) {
- dls_props_add_device(
- (GUPnPDeviceInfo *)context->device_proxy,
- task->target.device,
- cb_task_data->vb);
-
+ dls_props_add_device((GUPnPDeviceInfo *)
+ context->device_proxy,
+ context->device_info,
+ context->ems.proxy,
+ task->target.device,
+ cb_task_data->vb);
prv_get_system_update_id_for_props(
- context->service_proxy,
- task->target.device,
- cb_data);
+ context->cds.proxy,
+ task->target.device,
+ cb_data);
} else {
cb_data->error =
g_error_new(DLEYNA_SERVER_ERROR,
@@ -2269,11 +2654,12 @@ void dls_device_get_all_props(dls_client_t *client,
prv_get_all_ms2spec_props(context, cb_data);
} else {
if (root_object)
- dls_props_add_device(
- (GUPnPDeviceInfo *)context->device_proxy,
- task->target.device,
- cb_task_data->vb);
-
+ dls_props_add_device((GUPnPDeviceInfo *)
+ context->device_proxy,
+ context->device_info,
+ context->ems.proxy,
+ task->target.device,
+ cb_task_data->vb);
prv_get_all_ms2spec_props(context, cb_data);
}
@@ -2599,8 +2985,13 @@ static void prv_get_ms2spec_prop(dls_device_context_t *context,
goto on_error;
}
+ cb_data->proxy = context->cds.proxy;
+
+ g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)),
+ (gpointer *)&cb_data->proxy);
+
cb_data->action = gupnp_service_proxy_begin_action(
- context->service_proxy, "Browse",
+ cb_data->proxy, "Browse",
prv_get_ms2spec_prop_cb,
cb_data,
"ObjectID", G_TYPE_STRING, cb_data->task.target.id,
@@ -2613,11 +3004,6 @@ static void prv_get_ms2spec_prop(dls_device_context_t *context,
"",
NULL);
- cb_data->proxy = context->service_proxy;
-
- g_object_add_weak_pointer((G_OBJECT(context->service_proxy)),
- (gpointer *)&cb_data->proxy);
-
cb_data->cancel_id = g_cancellable_connect(
cb_data->cancellable,
G_CALLBACK(dls_async_task_cancelled_cb),
@@ -2656,23 +3042,25 @@ void dls_device_get_prop(dls_client_t *client,
task_data->prop_name,
DLS_INTERFACE_PROP_ESV_SYSTEM_UPDATE_ID)) {
prv_get_system_update_id_for_prop(
- context->service_proxy,
+ context->cds.proxy,
task->target.device,
cb_data);
} else if (!strcmp(
task_data->prop_name,
DLS_INTERFACE_PROP_SV_SERVICE_RESET_TOKEN)) {
prv_get_sr_token_for_prop(
- context->service_proxy,
+ context->cds.proxy,
task->target.device,
cb_data);
} else {
cb_data->task.result =
dls_props_get_device_prop(
- (GUPnPDeviceInfo *)
- context->device_proxy,
- task->target.device,
- task_data->prop_name);
+ (GUPnPDeviceInfo *)
+ context->device_proxy,
+ context->device_info,
+ context->ems.proxy,
+ task->target.device,
+ task_data->prop_name);
if (!cb_data->task.result)
cb_data->error = g_error_new(
@@ -2702,7 +3090,7 @@ void dls_device_get_prop(dls_client_t *client,
task_data->prop_name,
DLS_INTERFACE_PROP_ESV_SYSTEM_UPDATE_ID)) {
prv_get_system_update_id_for_prop(
- context->service_proxy,
+ context->cds.proxy,
task->target.device,
cb_data);
complete = TRUE;
@@ -2710,17 +3098,20 @@ void dls_device_get_prop(dls_client_t *client,
task_data->prop_name,
DLS_INTERFACE_PROP_SV_SERVICE_RESET_TOKEN)) {
prv_get_sr_token_for_prop(
- context->service_proxy,
+ context->cds.proxy,
task->target.device,
cb_data);
complete = TRUE;
} else {
cb_data->task.result =
- dls_props_get_device_prop(
+ dls_props_get_device_prop(
(GUPnPDeviceInfo *)
context->device_proxy,
+ context->device_info,
+ context->ems.proxy,
task->target.device,
task_data->prop_name);
+
if (cb_data->task.result) {
(void) g_idle_add(
dls_async_task_complete,
@@ -2919,8 +3310,13 @@ void dls_device_search(dls_client_t *client,
context = dls_device_get_context(task->target.device, client);
+ cb_data->proxy = context->cds.proxy;
+
+ g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)),
+ (gpointer *)&cb_data->proxy);
+
cb_data->action = gupnp_service_proxy_begin_action(
- context->service_proxy, "Search",
+ cb_data->proxy, "Search",
prv_search_cb,
cb_data,
"ContainerID", G_TYPE_STRING, task->target.id,
@@ -2931,11 +3327,6 @@ void dls_device_search(dls_client_t *client,
"SortCriteria", G_TYPE_STRING, sort_by,
NULL);
- cb_data->proxy = context->service_proxy;
-
- g_object_add_weak_pointer((G_OBJECT(context->service_proxy)),
- (gpointer *)&cb_data->proxy);
-
cb_data->cancel_id = g_cancellable_connect(
cb_data->cancellable,
G_CALLBACK(dls_async_task_cancelled_cb),
@@ -3383,7 +3774,7 @@ void dls_device_browse_objects(dls_client_t *client, dls_task_t *task)
dleyna_task_queue_set_user_data(queue_id, task);
context = dls_device_get_context(task->target.device, client);
- cb_data->proxy = context->service_proxy;
+ cb_data->proxy = context->cds.proxy;
cb_task_data = &cb_data->ut.browse_objects;
cb_task_data->queue_id = queue_id;
@@ -3391,7 +3782,7 @@ void dls_device_browse_objects(dls_client_t *client, dls_task_t *task)
cb_task_data->objects_id = objs;
cb_task_data->object_count = length;
- g_object_add_weak_pointer((G_OBJECT(context->service_proxy)),
+ g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)),
(gpointer *)&cb_data->proxy);
cb_data->cancel_id = g_cancellable_connect(
@@ -3428,8 +3819,13 @@ void dls_device_get_resource(dls_client_t *client,
cb_task_data->prop_func = G_CALLBACK(prv_get_resource);
cb_task_data->device_object = FALSE;
+ cb_data->proxy = context->cds.proxy;
+
+ g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)),
+ (gpointer *)&cb_data->proxy);
+
cb_data->action = gupnp_service_proxy_begin_action(
- context->service_proxy, "Browse",
+ cb_data->proxy, "Browse",
prv_get_all_ms2spec_props_cb, cb_data,
"ObjectID", G_TYPE_STRING, task->target.id,
"BrowseFlag", G_TYPE_STRING, "BrowseMetadata",
@@ -3439,11 +3835,6 @@ void dls_device_get_resource(dls_client_t *client,
"SortCriteria", G_TYPE_STRING,
"", NULL);
- cb_data->proxy = context->service_proxy;
-
- g_object_add_weak_pointer((G_OBJECT(context->service_proxy)),
- (gpointer *)&cb_data->proxy);
-
cb_data->cancel_id = g_cancellable_connect(
cb_data->cancellable,
G_CALLBACK(dls_async_task_cancelled_cb),
@@ -4127,18 +4518,18 @@ void dls_device_upload(dls_client_t *client,
DLEYNA_LOG_DEBUG("DIDL: %s", didl);
DLEYNA_LOG_DEBUG_NL();
+ cb_data->proxy = context->cds.proxy;
+
+ g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)),
+ (gpointer *)&cb_data->proxy);
+
cb_data->action = gupnp_service_proxy_begin_action(
- context->service_proxy, "CreateObject",
+ cb_data->proxy, "CreateObject",
prv_create_object_upload_cb, cb_data,
"ContainerID", G_TYPE_STRING, parent_id,
"Elements", G_TYPE_STRING, didl,
NULL);
- cb_data->proxy = context->service_proxy;
-
- g_object_add_weak_pointer((G_OBJECT(context->service_proxy)),
- (gpointer *)&cb_data->proxy);
-
cb_data->cancel_id = g_cancellable_connect(
cb_data->cancellable,
G_CALLBACK(dls_async_task_cancelled_cb),
@@ -4280,17 +4671,17 @@ void dls_device_delete_object(dls_client_t *client,
context = dls_device_get_context(task->target.device, client);
+ cb_data->proxy = context->cds.proxy;
+
+ g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)),
+ (gpointer *)&cb_data->proxy);
+
cb_data->action = gupnp_service_proxy_begin_action(
- context->service_proxy, "DestroyObject",
+ cb_data->proxy, "DestroyObject",
prv_destroy_object_cb, cb_data,
"ObjectID", G_TYPE_STRING, task->target.id,
NULL);
- cb_data->proxy = context->service_proxy;
-
- g_object_add_weak_pointer((G_OBJECT(context->service_proxy)),
- (gpointer *)&cb_data->proxy);
-
cb_data->cancel_id = g_cancellable_connect(cb_data->cancellable,
G_CALLBACK(dls_async_task_cancelled_cb),
cb_data, NULL);
@@ -4322,18 +4713,18 @@ void dls_device_create_container(dls_client_t *client,
DLEYNA_LOG_DEBUG("DIDL: %s", didl);
+ cb_data->proxy = context->cds.proxy;
+
+ g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)),
+ (gpointer *)&cb_data->proxy);
+
cb_data->action = gupnp_service_proxy_begin_action(
- context->service_proxy, "CreateObject",
+ cb_data->proxy, "CreateObject",
prv_create_container_cb, cb_data,
"ContainerID", G_TYPE_STRING, parent_id,
"Elements", G_TYPE_STRING, didl,
NULL);
- cb_data->proxy = context->service_proxy;
-
- g_object_add_weak_pointer((G_OBJECT(context->service_proxy)),
- (gpointer *)&cb_data->proxy);
-
cb_data->cancel_id = g_cancellable_connect(
cb_data->cancellable,
G_CALLBACK(dls_async_task_cancelled_cb),
@@ -4670,8 +5061,13 @@ void dls_device_update_object(dls_client_t *client,
context = dls_device_get_context(task->target.device, client);
+ cb_data->proxy = context->cds.proxy;
+
+ g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)),
+ (gpointer *)&cb_data->proxy);
+
cb_data->action = gupnp_service_proxy_begin_action(
- context->service_proxy, "Browse",
+ cb_data->proxy, "Browse",
prv_update_object_browse_cb, cb_data,
"ObjectID", G_TYPE_STRING, task->target.id,
"BrowseFlag", G_TYPE_STRING, "BrowseMetadata",
@@ -4681,11 +5077,6 @@ void dls_device_update_object(dls_client_t *client,
"SortCriteria", G_TYPE_STRING,
"", NULL);
- cb_data->proxy = context->service_proxy;
-
- g_object_add_weak_pointer((G_OBJECT(context->service_proxy)),
- (gpointer *)&cb_data->proxy);
-
cb_data->cancel_id = g_cancellable_connect(cb_data->cancellable,
G_CALLBACK(dls_async_task_cancelled_cb),
cb_data, NULL);
@@ -4750,8 +5141,13 @@ void dls_device_get_object_metadata(dls_client_t *client,
context = dls_device_get_context(task->target.device, client);
+ cb_data->proxy = context->cds.proxy;
+
+ g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)),
+ (gpointer *)&cb_data->proxy);
+
cb_data->action = gupnp_service_proxy_begin_action(
- context->service_proxy, "Browse",
+ cb_data->proxy, "Browse",
prv_get_object_metadata_cb, cb_data,
"ObjectID", G_TYPE_STRING, task->target.id,
"BrowseFlag", G_TYPE_STRING, "BrowseMetadata",
@@ -4761,11 +5157,6 @@ void dls_device_get_object_metadata(dls_client_t *client,
"SortCriteria", G_TYPE_STRING, "",
NULL);
- cb_data->proxy = context->service_proxy;
-
- g_object_add_weak_pointer((G_OBJECT(context->service_proxy)),
- (gpointer *)&cb_data->proxy);
-
cb_data->cancel_id = g_cancellable_connect(cb_data->cancellable,
G_CALLBACK(dls_async_task_cancelled_cb),
cb_data, NULL);
@@ -4852,18 +5243,18 @@ void dls_device_create_reference(dls_client_t *client,
context = dls_device_get_context(task->target.device, client);
+ cb_data->proxy = context->cds.proxy;
+
+ g_object_add_weak_pointer((G_OBJECT(context->cds.proxy)),
+ (gpointer *)&cb_data->proxy);
+
cb_data->action = gupnp_service_proxy_begin_action(
- context->service_proxy, "CreateReference",
+ cb_data->proxy, "CreateReference",
prv_create_reference_cb, cb_data,
"ContainerID", G_TYPE_STRING, task->target.id,
"ObjectID", G_TYPE_STRING, i_id,
NULL);
- cb_data->proxy = context->service_proxy;
-
- g_object_add_weak_pointer((G_OBJECT(context->service_proxy)),
- (gpointer *)&cb_data->proxy);
-
cb_data->cancel_id = g_cancellable_connect(
cb_data->cancellable,
G_CALLBACK(dls_async_task_cancelled_cb),
@@ -4949,7 +5340,6 @@ out:
void dls_device_get_icon(dls_client_t *client,
dls_task_t *task)
{
- GUPnPDeviceInfo *info;
dls_device_context_t *context;
dls_async_task_t *cb_data = (dls_async_task_t *)task;
dls_device_t *device = task->target.device;
@@ -4962,9 +5352,9 @@ void dls_device_get_icon(dls_client_t *client,
}
context = dls_device_get_context(device, client);
- info = (GUPnPDeviceInfo *)context->device_proxy;
- url = gupnp_device_info_get_icon_url(info, NULL, -1, -1, -1, FALSE,
+ url = gupnp_device_info_get_icon_url(context->device_info,
+ NULL, -1, -1, -1, FALSE,
&device->icon.mime_type, NULL,
NULL, NULL);
if (url == NULL) {
@@ -5008,3 +5398,46 @@ end:
(void) g_idle_add(dls_async_task_complete, cb_data);
}
+
+void dls_device_wake(dls_client_t *client, dls_task_t *task)
+{
+ dls_device_context_t *context;
+ dls_async_task_t *cb_data = (dls_async_task_t *)task;
+ dls_device_t *device = task->target.device;
+ dls_network_if_info_t *info;
+ GList *next;
+
+ DLEYNA_LOG_DEBUG("Enter");
+
+ context = dls_device_get_context(device, client);
+
+ if ((context->ems.proxy == NULL) ||
+ (context->network_if_info == NULL)) {
+ cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
+ DLEYNA_ERROR_NOT_SUPPORTED,
+ "WOL is not supported");
+ goto end;
+ }
+
+ info = context->network_if_info;
+
+ DLEYNA_LOG_DEBUG("MacAddress = %s", info->mac_address);
+ DLEYNA_LOG_DEBUG("DeviceUUID = %s", info->device_uuid);
+ DLEYNA_LOG_DEBUG("NetworkInterfaceMode = %s", info->network_if_mode);
+ DLEYNA_LOG_DEBUG("WakeOnPattern = %s", info->wake_on_pattern);
+ DLEYNA_LOG_DEBUG("WakeSupportedTransport = %s", info->wake_transport);
+
+ next = info->ip_addresses;
+ while (next != NULL) {
+ DLEYNA_LOG_DEBUG("IpAddress = %s", (gchar *)next->data);
+
+ next = g_list_next(next);
+ }
+
+ DLEYNA_LOG_DEBUG("context IpAddress = %s", context->ip_address);
+
+end:
+ (void) g_idle_add(dls_async_task_complete, cb_data);
+
+ DLEYNA_LOG_DEBUG("Exit");
+}
diff --git a/libdleyna/server/device.h b/libdleyna/server/device.h
index 6771464..891351c 100644
--- a/libdleyna/server/device.h
+++ b/libdleyna/server/device.h
@@ -32,13 +32,32 @@
#include "client.h"
#include "props.h"
+typedef struct dls_network_if_info_t_ dls_network_if_info_t;
+struct dls_network_if_info_t_ {
+ gchar *system_name;
+ gchar *mac_address;
+ gchar *device_uuid;
+ gchar *network_if_mode;
+ gchar *wake_on_pattern;
+ gchar *wake_transport;
+ GList *ip_addresses;
+};
+
+typedef struct dls_service_t_ dls_service_t;
+struct dls_service_t_ {
+ GUPnPServiceProxy *proxy;
+ gboolean subscribed;
+ guint timeout_id;
+};
+
struct dls_device_context_t_ {
gchar *ip_address;
GUPnPDeviceProxy *device_proxy;
- GUPnPServiceProxy *service_proxy;
+ GUPnPDeviceInfo *device_info;
dls_device_t *device;
- gboolean subscribed;
- guint timeout_id;
+ dls_service_t cds;
+ dls_service_t ems;
+ dls_network_if_info_t *network_if_info;
};
typedef struct dls_device_icon_t_ dls_device_icon_t;
@@ -66,11 +85,13 @@ struct dls_device_t_ {
gboolean has_last_change;
guint construct_step;
dls_device_icon_t icon;
+ gboolean sleeping;
};
dls_device_context_t *dls_device_append_new_context(dls_device_t *device,
- const gchar *ip_address,
- GUPnPDeviceProxy *proxy);
+ const gchar *ip_address,
+ GUPnPDeviceProxy *proxy,
+ GUPnPDeviceInfo *device_info);
void dls_device_delete(void *device);
void dls_device_unsubscribe(void *device);
@@ -86,6 +107,7 @@ void dls_device_construct(
dls_device_t *dls_device_new(
dleyna_connector_id_t connection,
GUPnPDeviceProxy *proxy,
+ GUPnPDeviceInfo *device_info,
const gchar *ip_address,
const dleyna_connector_dispatch_cb_t *dispatch_table,
GHashTable *filter_map,
@@ -120,7 +142,7 @@ void dls_device_get_resource(dls_client_t *client,
dls_task_t *task,
const gchar *upnp_filter);
-void dls_device_subscribe_to_contents_change(dls_device_t *device);
+void dls_device_subscribe_to_service_changes(dls_device_t *device);
void dls_device_upload(dls_client_t *client,
dls_task_t *task, const gchar *parent_id);
@@ -152,4 +174,7 @@ void dls_device_create_reference(dls_client_t *client,
void dls_device_get_icon(dls_client_t *client,
dls_task_t *task);
+void dls_device_wake(dls_client_t *client,
+ dls_task_t *task);
+
#endif /* DLS_DEVICE_H__ */
diff --git a/libdleyna/server/interface.h b/libdleyna/server/interface.h
index 3a2a6a4..f955db2 100644
--- a/libdleyna/server/interface.h
+++ b/libdleyna/server/interface.h
@@ -85,6 +85,7 @@ enum dls_interface_type_ {
/* Device Properties */
#define DLS_INTERFACE_PROP_LOCATION "Location"
#define DLS_INTERFACE_PROP_UDN "UDN"
+#define DLS_INTERFACE_PROP_ROOT_UDN "RootUDN"
#define DLS_INTERFACE_PROP_DEVICE_TYPE "DeviceType"
#define DLS_INTERFACE_PROP_FRIENDLY_NAME "FriendlyName"
#define DLS_INTERFACE_PROP_MANUFACTURER "Manufacturer"
@@ -96,6 +97,7 @@ enum dls_interface_type_ {
#define DLS_INTERFACE_PROP_SERIAL_NUMBER "SerialNumber"
#define DLS_INTERFACE_PROP_PRESENTATION_URL "PresentationURL"
#define DLS_INTERFACE_PROP_ICON_URL "IconURL"
+#define DLS_INTERFACE_PROP_SLEEPING "Sleeping"
#define DLS_INTERFACE_PROP_SV_DLNA_CAPABILITIES "DLNACaps"
#define DLS_INTERFACE_PROP_SV_SEARCH_CAPABILITIES "SearchCaps"
#define DLS_INTERFACE_PROP_SV_SORT_CAPABILITIES "SortCaps"
@@ -215,6 +217,7 @@ enum dls_interface_type_ {
#define DLS_INTERFACE_ICON_BYTES "Bytes"
#define DLS_INTERFACE_MIME_TYPE "MimeType"
#define DLS_INTERFACE_REQ_MIME_TYPE "RequestedMimeType"
+#define DLS_INTERFACE_WAKE "Wake"
#define DLS_INTERFACE_GET_METADATA "GetMetaData"
#define DLS_INTERFACE_METADATA "MetaData"
diff --git a/libdleyna/server/props.c b/libdleyna/server/props.c
index c63ce30..4196e68 100644
--- a/libdleyna/server/props.c
+++ b/libdleyna/server/props.c
@@ -715,7 +715,9 @@ static GVariant *prv_get_artists_prop(GList *list)
return g_variant_builder_end(&vb);
}
-void dls_props_add_device(GUPnPDeviceInfo *proxy,
+void dls_props_add_device(GUPnPDeviceInfo *root_proxy,
+ GUPnPDeviceInfo *proxy,
+ GUPnPServiceProxy *ems_proxy,
const dls_device_t *device,
GVariantBuilder *vb)
{
@@ -729,6 +731,10 @@ void dls_props_add_device(GUPnPDeviceInfo *proxy,
prv_add_string_prop(vb, DLS_INTERFACE_PROP_UDN,
gupnp_device_info_get_udn(proxy));
+ if (proxy != root_proxy)
+ prv_add_string_prop(vb, DLS_INTERFACE_PROP_ROOT_UDN,
+ gupnp_device_info_get_udn(root_proxy));
+
prv_add_string_prop(vb, DLS_INTERFACE_PROP_DEVICE_TYPE,
gupnp_device_info_get_device_type(proxy));
@@ -802,9 +808,15 @@ void dls_props_add_device(GUPnPDeviceInfo *proxy,
g_variant_builder_add(vb, "{sv}",
DLS_INTERFACE_PROP_SV_FEATURE_LIST,
device->feature_list);
+
+ if (ems_proxy != NULL)
+ prv_add_bool_prop(vb, DLS_INTERFACE_PROP_SLEEPING,
+ device->sleeping);
}
-GVariant *dls_props_get_device_prop(GUPnPDeviceInfo *proxy,
+GVariant *dls_props_get_device_prop(GUPnPDeviceInfo *root_proxy,
+ GUPnPDeviceInfo *proxy,
+ GUPnPServiceProxy *ems_proxy,
const dls_device_t *device,
const gchar *prop)
{
@@ -818,6 +830,9 @@ GVariant *dls_props_get_device_prop(GUPnPDeviceInfo *proxy,
str = gupnp_device_info_get_location(proxy);
} else if (!strcmp(DLS_INTERFACE_PROP_UDN, prop)) {
str = gupnp_device_info_get_udn(proxy);
+ } else if (!strcmp(DLS_INTERFACE_PROP_ROOT_UDN, prop)) {
+ if (proxy != root_proxy)
+ str = gupnp_device_info_get_udn(root_proxy);
} else if (!strcmp(DLS_INTERFACE_PROP_DEVICE_TYPE, prop)) {
str = gupnp_device_info_get_device_type(proxy);
} else if (!strcmp(DLS_INTERFACE_PROP_FRIENDLY_NAME, prop)) {
@@ -900,6 +915,16 @@ GVariant *dls_props_get_device_prop(GUPnPDeviceInfo *proxy,
DLEYNA_LOG_DEBUG("Prop %s = %s", prop, copy);
#endif
}
+ } else if (!strcmp(DLS_INTERFACE_PROP_SLEEPING, prop)) {
+ if (ems_proxy != NULL) {
+ retval = g_variant_ref_sink(
+ g_variant_new_boolean(device->sleeping));
+ }
+
+#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop,
+ device->sleeping ? "TRUE":"FALSE");
+#endif
}
if (!retval) {
diff --git a/libdleyna/server/props.h b/libdleyna/server/props.h
index 72cff1b..41f66b0 100644
--- a/libdleyna/server/props.h
+++ b/libdleyna/server/props.h
@@ -93,11 +93,15 @@ gboolean dls_props_parse_update_filter(GHashTable *filter_map,
dls_upnp_prop_mask *mask,
gchar **upnp_filter);
-void dls_props_add_device(GUPnPDeviceInfo *proxy,
+void dls_props_add_device(GUPnPDeviceInfo *root_proxy,
+ GUPnPDeviceInfo *proxy,
+ GUPnPServiceProxy *ems_proxy,
const dls_device_t *device,
GVariantBuilder *vb);
-GVariant *dls_props_get_device_prop(GUPnPDeviceInfo *proxy,
+GVariant *dls_props_get_device_prop(GUPnPDeviceInfo *root_proxy,
+ GUPnPDeviceInfo *proxy,
+ GUPnPServiceProxy *ems_proxy,
const dls_device_t *device,
const gchar *prop);
diff --git a/libdleyna/server/server.c b/libdleyna/server/server.c
index 5a30500..5367252 100644
--- a/libdleyna/server/server.c
+++ b/libdleyna/server/server.c
@@ -439,6 +439,8 @@ static const gchar g_server_introspection[] =
" </method>"
" <method name='"DLS_INTERFACE_CANCEL"'>"
" </method>"
+ " <method name='"DLS_INTERFACE_WAKE"'>"
+ " </method>"
" <method name='"DLS_INTERFACE_GET_ICON"'>"
" <arg type='s' name='"DLS_INTERFACE_REQ_MIME_TYPE"'"
" direction='in'/>"
@@ -483,6 +485,8 @@ static const gchar g_server_introspection[] =
" access='read'/>"
" <property type='s' name='"DLS_INTERFACE_PROP_ICON_URL"'"
" access='read'/>"
+ " <property type='b' name='"DLS_INTERFACE_PROP_SLEEPING"'"
+ " access='read'/>"
" <property type='a{sv}'name='"
DLS_INTERFACE_PROP_SV_DLNA_CAPABILITIES"'"
" access='read'/>"
@@ -547,7 +551,7 @@ static void prv_process_sync_task(dls_task_t *task)
dls_task_complete(task);
break;
case DLS_TASK_GET_SERVERS:
- task->result = dls_upnp_get_server_ids(g_context.upnp);
+ task->result = dls_upnp_get_device_ids(g_context.upnp);
dls_task_complete(task);
break;
case DLS_TASK_RESCAN:
@@ -699,6 +703,10 @@ static void prv_process_async_task(dls_task_t *task)
dls_upnp_get_icon(g_context.upnp, client, task,
prv_async_task_complete);
break;
+ case DLS_TASK_WAKE:
+ dls_upnp_wake(g_context.upnp, client, task,
+ prv_async_task_complete);
+ break;
default:
break;
}
@@ -934,7 +942,7 @@ gboolean dls_server_get_object_info(const gchar *object_path,
}
*device = dls_device_from_path(*root_path,
- dls_upnp_get_server_udn_map(g_context.upnp));
+ dls_upnp_get_device_udn_map(g_context.upnp));
if (*device == NULL) {
DLEYNA_LOG_WARNING("Cannot locate device for %s", *root_path);
@@ -1185,6 +1193,8 @@ static void prv_device_method_call(dleyna_connector_id_t conn,
} else if (!strcmp(method, DLS_INTERFACE_BROWSE_OBJECTS)) {
task = dls_task_browse_objects_new(invocation, object,
parameters, &error);
+ } else if (!strcmp(method, DLS_INTERFACE_WAKE)) {
+ task = dls_task_wake_new(invocation, object, &error);
} else if (!strcmp(method, DLS_INTERFACE_CANCEL)) {
task = NULL;
diff --git a/libdleyna/server/task.c b/libdleyna/server/task.c
index 1ad4108..312efc0 100644
--- a/libdleyna/server/task.c
+++ b/libdleyna/server/task.c
@@ -97,6 +97,8 @@ static void prv_delete(dls_task_t *task)
g_free(task->ut.get_icon.resolution);
g_free(task->ut.get_icon.mime_type);
break;
+ case DLS_TASK_WAKE:
+ break;
default:
break;
}
@@ -658,6 +660,17 @@ finished:
return task;
}
+dls_task_t *dls_task_wake_new(dleyna_connector_msg_id_t invocation,
+ const gchar *path, GError **error)
+{
+ dls_task_t *task;
+
+ task = prv_m2spec_task_new(DLS_TASK_WAKE, invocation, path,
+ NULL, error, FALSE);
+
+ return task;
+}
+
void dls_task_complete(dls_task_t *task)
{
GVariant *variant = NULL;
diff --git a/libdleyna/server/task.h b/libdleyna/server/task.h
index a06b3e2..6642e8d 100644
--- a/libdleyna/server/task.h
+++ b/libdleyna/server/task.h
@@ -57,7 +57,8 @@ enum dls_task_type_t_ {
DLS_TASK_GET_ICON,
DLS_TASK_MANAGER_GET_ALL_PROPS,
DLS_TASK_MANAGER_GET_PROP,
- DLS_TASK_MANAGER_SET_PROP
+ DLS_TASK_MANAGER_SET_PROP,
+ DLS_TASK_WAKE
};
typedef enum dls_task_type_t_ dls_task_type_t;
@@ -309,6 +310,10 @@ dls_task_t *dls_task_manager_set_prop_new(dleyna_connector_msg_id_t invocation,
GVariant *parameters,
GError **error);
+dls_task_t *dls_task_wake_new(dleyna_connector_msg_id_t invocation,
+ const gchar *path,
+ GError **error);
+
void dls_task_cancel(dls_task_t *task);
void dls_task_complete(dls_task_t *task);
diff --git a/libdleyna/server/upnp.c b/libdleyna/server/upnp.c
index 68338e6..7301e61 100644
--- a/libdleyna/server/upnp.c
+++ b/libdleyna/server/upnp.c
@@ -38,6 +38,8 @@
#include "sort.h"
#include "upnp.h"
+#define DLS_DMS_DEVICE_TYPE "urn:schemas-upnp-org:device:MediaServer:"
+
struct dls_upnp_t_ {
dleyna_connector_id_t connection;
const dleyna_connector_dispatch_cb_t *interface_info;
@@ -47,8 +49,8 @@ struct dls_upnp_t_ {
dls_upnp_callback_t lost_server;
GUPnPContextManager *context_manager;
void *user_data;
- GHashTable *server_udn_map;
- GHashTable *server_uc_map;
+ GHashTable *device_udn_map;
+ GHashTable *device_uc_map;
guint counter;
};
@@ -84,13 +86,13 @@ static void prv_device_chain_end(gboolean cancelled, gpointer data)
goto on_clear;
DLEYNA_LOG_DEBUG("Notify new server available: %s", device->path);
- g_hash_table_insert(priv_t->upnp->server_udn_map, g_strdup(priv_t->udn),
+ g_hash_table_insert(priv_t->upnp->device_udn_map, g_strdup(priv_t->udn),
device);
priv_t->upnp->found_server(device->path, priv_t->upnp->user_data);
on_clear:
- g_hash_table_remove(priv_t->upnp->server_uc_map, priv_t->udn);
+ g_hash_table_remove(priv_t->upnp->device_uc_map, priv_t->udn);
if (cancelled)
dls_device_delete(device);
@@ -106,7 +108,7 @@ static void prv_device_context_switch_end(gboolean cancelled, gpointer data)
DLEYNA_LOG_DEBUG("Enter");
- g_hash_table_remove(priv_t->upnp->server_uc_map, priv_t->udn);
+ g_hash_table_remove(priv_t->upnp->device_uc_map, priv_t->udn);
prv_device_new_free(priv_t);
DLEYNA_LOG_DEBUG("Exit");
@@ -146,10 +148,49 @@ static void prv_update_device_context(prv_device_new_ct_t *priv_t,
priv_t->queue_id = queue_id;
priv_t->device = device;
- g_hash_table_insert(upnp->server_uc_map, g_strdup(udn), priv_t);
+ g_hash_table_insert(upnp->device_uc_map, g_strdup(udn), priv_t);
+}
+
+static GUPnPDeviceInfo *prv_lookup_dms_child_device(GUPnPDeviceInfo *proxy)
+{
+ GList *child_devices;
+ GList *next;
+ const gchar *device_type;
+ GUPnPDeviceInfo *info = NULL;
+ GUPnPDeviceInfo *child_info = NULL;
+
+ child_devices = gupnp_device_info_list_device_types(proxy);
+
+ next = child_devices;
+ while (next != NULL) {
+ device_type = (gchar *)next->data;
+
+ child_info = gupnp_device_info_get_device(proxy, device_type);
+
+ if (g_str_has_prefix(device_type, DLS_DMS_DEVICE_TYPE)) {
+ break;
+ } else {
+ info = prv_lookup_dms_child_device(child_info);
+
+ g_object_unref(child_info);
+ child_info = NULL;
+
+ if (info != NULL) {
+ child_info = info;
+
+ break;
+ }
+ }
+
+ next = g_list_next(next);
+ }
+
+ g_list_free_full(child_devices, (GDestroyNotify)g_free);
+
+ return child_info;
}
-static void prv_server_available_cb(GUPnPControlPoint *cp,
+static void prv_device_available_cb(GUPnPControlPoint *cp,
GUPnPDeviceProxy *proxy,
gpointer user_data)
{
@@ -161,8 +202,11 @@ static void prv_server_available_cb(GUPnPControlPoint *cp,
const dleyna_task_queue_key_t *queue_id;
unsigned int i;
prv_device_new_ct_t *priv_t;
+ GUPnPDeviceInfo *device_proxy = (GUPnPDeviceInfo *)proxy;
+ GUPnPDeviceInfo *device_info = NULL;
+ const gchar *device_type;
- udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *)proxy);
+ udn = gupnp_device_info_get_udn(device_proxy);
ip_address = gupnp_context_get_host_ip(
gupnp_control_point_get_context(cp));
@@ -173,10 +217,21 @@ static void prv_server_available_cb(GUPnPControlPoint *cp,
DLEYNA_LOG_DEBUG("UDN %s", udn);
DLEYNA_LOG_DEBUG("IP Address %s", ip_address);
- device = g_hash_table_lookup(upnp->server_udn_map, udn);
+ device_type = gupnp_device_info_get_device_type(device_proxy);
+
+ if (!g_str_has_prefix(device_type, DLS_DMS_DEVICE_TYPE)) {
+ device_info = prv_lookup_dms_child_device(device_proxy);
+
+ if (device_info == NULL)
+ goto on_error;
+ } else {
+ device_info = device_proxy;
+ }
+
+ device = g_hash_table_lookup(upnp->device_udn_map, udn);
if (!device) {
- priv_t = g_hash_table_lookup(upnp->server_uc_map, udn);
+ priv_t = g_hash_table_lookup(upnp->device_uc_map, udn);
if (priv_t)
device = priv_t->device;
@@ -188,7 +243,10 @@ static void prv_server_available_cb(GUPnPControlPoint *cp,
queue_id = prv_create_device_queue(&priv_t);
- device = dls_device_new(upnp->connection, proxy, ip_address,
+ device = dls_device_new(upnp->connection,
+ proxy,
+ device_info,
+ ip_address,
upnp->interface_info,
upnp->property_map, upnp->counter,
queue_id);
@@ -208,8 +266,10 @@ static void prv_server_available_cb(GUPnPControlPoint *cp,
if (i == device->contexts->len) {
DLEYNA_LOG_DEBUG("Adding Context");
- (void) dls_device_append_new_context(device, ip_address,
- proxy);
+ (void) dls_device_append_new_context(device,
+ ip_address,
+ proxy,
+ device_info);
}
DLEYNA_LOG_DEBUG_NL();
@@ -220,17 +280,17 @@ on_error:
return;
}
-static gboolean prv_subscribe_to_contents_change(gpointer user_data)
+static gboolean prv_subscribe_to_service_changes(gpointer user_data)
{
dls_device_t *device = user_data;
device->timeout_id = 0;
- dls_device_subscribe_to_contents_change(device);
+ dls_device_subscribe_to_service_changes(device);
return FALSE;
}
-static void prv_server_unavailable_cb(GUPnPControlPoint *cp,
+static void prv_device_unavailable_cb(GUPnPControlPoint *cp,
GUPnPDeviceProxy *proxy,
gpointer user_data)
{
@@ -259,10 +319,10 @@ static void prv_server_unavailable_cb(GUPnPControlPoint *cp,
DLEYNA_LOG_DEBUG("UDN %s", udn);
DLEYNA_LOG_DEBUG("IP Address %s", ip_address);
- device = g_hash_table_lookup(upnp->server_udn_map, udn);
+ device = g_hash_table_lookup(upnp->device_udn_map, udn);
if (!device) {
- priv_t = g_hash_table_lookup(upnp->server_uc_map, udn);
+ priv_t = g_hash_table_lookup(upnp->device_uc_map, udn);
if (priv_t) {
device = priv_t->device;
@@ -284,7 +344,7 @@ static void prv_server_unavailable_cb(GUPnPControlPoint *cp,
if (i >= device->contexts->len)
goto on_error;
- subscribed = context->subscribed;
+ subscribed = (context->cds.subscribed || context->ems.subscribed);
if (under_construction)
construction_ctx = !strcmp(context->ip_address,
priv_t->ip_address);
@@ -295,7 +355,7 @@ static void prv_server_unavailable_cb(GUPnPControlPoint *cp,
if (!under_construction) {
DLEYNA_LOG_DEBUG("Last Context lost. Delete device");
upnp->lost_server(device->path, upnp->user_data);
- g_hash_table_remove(upnp->server_udn_map, udn);
+ g_hash_table_remove(upnp->device_udn_map, udn);
} else {
DLEYNA_LOG_WARNING(
"Device under construction. Cancelling");
@@ -307,7 +367,7 @@ static void prv_server_unavailable_cb(GUPnPControlPoint *cp,
"Device under construction. Switching context");
/* Cancel previous contruction task chain */
- g_hash_table_remove(priv_t->upnp->server_uc_map, priv_t->udn);
+ g_hash_table_remove(priv_t->upnp->device_uc_map, priv_t->udn);
dleyna_task_queue_set_finally(priv_t->queue_id,
prv_device_context_switch_end);
dleyna_task_processor_cancel_queue(priv_t->queue_id);
@@ -330,7 +390,7 @@ static void prv_server_unavailable_cb(GUPnPControlPoint *cp,
DLEYNA_LOG_DEBUG("Subscribe on new context");
device->timeout_id = g_timeout_add_seconds(1,
- prv_subscribe_to_contents_change,
+ prv_subscribe_to_service_changes,
device);
}
@@ -351,13 +411,13 @@ static void prv_on_context_available(GUPnPContextManager *context_manager,
cp = gupnp_control_point_new(
context,
- "urn:schemas-upnp-org:device:MediaServer:1");
+ "upnp:rootdevice");
g_signal_connect(cp, "device-proxy-available",
- G_CALLBACK(prv_server_available_cb), upnp);
+ G_CALLBACK(prv_device_available_cb), upnp);
g_signal_connect(cp, "device-proxy-unavailable",
- G_CALLBACK(prv_server_unavailable_cb), upnp);
+ G_CALLBACK(prv_device_unavailable_cb), upnp);
gssdp_resource_browser_set_active(GSSDP_RESOURCE_BROWSER(cp), TRUE);
gupnp_context_manager_manage_control_point(upnp->context_manager, cp);
@@ -378,11 +438,11 @@ dls_upnp_t *dls_upnp_new(dleyna_connector_id_t connection,
upnp->found_server = found_server;
upnp->lost_server = lost_server;
- upnp->server_udn_map = g_hash_table_new_full(g_str_hash, g_str_equal,
+ upnp->device_udn_map = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free,
dls_device_delete);
- upnp->server_uc_map = g_hash_table_new_full(g_str_hash, g_str_equal,
+ upnp->device_uc_map = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, NULL);
dls_prop_maps_new(&upnp->property_map, &upnp->filter_map);
@@ -402,13 +462,13 @@ void dls_upnp_delete(dls_upnp_t *upnp)
g_object_unref(upnp->context_manager);
g_hash_table_unref(upnp->property_map);
g_hash_table_unref(upnp->filter_map);
- g_hash_table_unref(upnp->server_udn_map);
- g_hash_table_unref(upnp->server_uc_map);
+ g_hash_table_unref(upnp->device_udn_map);
+ g_hash_table_unref(upnp->device_uc_map);
g_free(upnp);
}
}
-GVariant *dls_upnp_get_server_ids(dls_upnp_t *upnp)
+GVariant *dls_upnp_get_device_ids(dls_upnp_t *upnp)
{
GVariantBuilder vb;
GHashTableIter iter;
@@ -420,7 +480,7 @@ GVariant *dls_upnp_get_server_ids(dls_upnp_t *upnp)
g_variant_builder_init(&vb, G_VARIANT_TYPE("ao"));
- g_hash_table_iter_init(&iter, upnp->server_udn_map);
+ g_hash_table_iter_init(&iter, upnp->device_udn_map);
while (g_hash_table_iter_next(&iter, NULL, &value)) {
device = value;
DLEYNA_LOG_DEBUG("Have device %s", device->path);
@@ -434,9 +494,9 @@ GVariant *dls_upnp_get_server_ids(dls_upnp_t *upnp)
return retval;
}
-GHashTable *dls_upnp_get_server_udn_map(dls_upnp_t *upnp)
+GHashTable *dls_upnp_get_device_udn_map(dls_upnp_t *upnp)
{
- return upnp->server_udn_map;
+ return upnp->device_udn_map;
}
void dls_upnp_get_children(dls_upnp_t *upnp, dls_client_t *client,
@@ -1088,6 +1148,21 @@ void dls_upnp_get_icon(dls_upnp_t *upnp, dls_client_t *client,
DLEYNA_LOG_DEBUG("Exit");
}
+void dls_upnp_wake(dls_upnp_t *upnp, dls_client_t *client,
+ dls_task_t *task,
+ dls_upnp_task_complete_t cb)
+{
+ dls_async_task_t *cb_data = (dls_async_task_t *)task;
+
+ DLEYNA_LOG_DEBUG("Enter");
+
+ cb_data->cb = cb;
+
+ dls_device_wake(client, task);
+
+ DLEYNA_LOG_DEBUG("Exit");
+}
+
void dls_upnp_unsubscribe(dls_upnp_t *upnp)
{
GHashTableIter iter;
@@ -1096,7 +1171,7 @@ void dls_upnp_unsubscribe(dls_upnp_t *upnp)
DLEYNA_LOG_DEBUG("Enter");
- g_hash_table_iter_init(&iter, upnp->server_udn_map);
+ g_hash_table_iter_init(&iter, upnp->device_udn_map);
while (g_hash_table_iter_next(&iter, NULL, &value)) {
device = value;
dls_device_unsubscribe(device);
@@ -1131,11 +1206,11 @@ gboolean dls_upnp_device_context_exist(dls_device_t *device,
goto on_exit;
/* Check if the device still exist */
- result = g_hash_table_find(upnp->server_udn_map, prv_device_find,
+ result = g_hash_table_find(upnp->device_udn_map, prv_device_find,
device);
if (result == NULL)
- if (g_hash_table_find(upnp->server_uc_map, prv_device_uc_find,
+ if (g_hash_table_find(upnp->device_uc_map, prv_device_uc_find,
device) == NULL)
goto on_exit;
diff --git a/libdleyna/server/upnp.h b/libdleyna/server/upnp.h
index 08441c6..b2d9ba1 100644
--- a/libdleyna/server/upnp.h
+++ b/libdleyna/server/upnp.h
@@ -39,9 +39,9 @@ dls_upnp_t *dls_upnp_new(dleyna_connector_id_t connection,
void dls_upnp_delete(dls_upnp_t *upnp);
-GVariant *dls_upnp_get_server_ids(dls_upnp_t *upnp);
+GVariant *dls_upnp_get_device_ids(dls_upnp_t *upnp);
-GHashTable *dls_upnp_get_server_udn_map(dls_upnp_t *upnp);
+GHashTable *dls_upnp_get_device_udn_map(dls_upnp_t *upnp);
void dls_upnp_get_children(dls_upnp_t *upnp, dls_client_t *client,
dls_task_t *task,
@@ -109,6 +109,10 @@ void dls_upnp_get_icon(dls_upnp_t *upnp, dls_client_t *client,
dls_task_t *task,
dls_upnp_task_complete_t cb);
+void dls_upnp_wake(dls_upnp_t *upnp, dls_client_t *client,
+ dls_task_t *task,
+ dls_upnp_task_complete_t cb);
+
void dls_upnp_unsubscribe(dls_upnp_t *upnp);
gboolean dls_upnp_device_context_exist(dls_device_t *device,
diff --git a/libdleyna/server/xml-util.c b/libdleyna/server/xml-util.c
new file mode 100644
index 0000000..f6ddf6a
--- /dev/null
+++ b/libdleyna/server/xml-util.c
@@ -0,0 +1,133 @@
+/*
+ * dLeyna
+ *
+ * Copyright (C) 2012-2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Christophe Guiraud <christophe.guiraud@intel.com>
+ *
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "xml-util.h"
+
+static xmlNode *prv_get_child_node(xmlNode *node, va_list args)
+{
+ const gchar *name;
+
+ name = va_arg(args, const gchar *);
+ while (name != NULL) {
+ node = node->children;
+ while (node != NULL) {
+ if (node->name != NULL &&
+ !strcmp(name, (char *)node->name))
+ break;
+
+ node = node->next;
+ }
+
+ if (node == NULL)
+ break;
+
+ name = va_arg(args, const gchar *);
+ }
+
+ return node;
+}
+
+static GList *prv_get_children_list(xmlNode *node, const gchar *name)
+{
+ GList *child_list = NULL;
+
+ node = node->children;
+ while (node != NULL) {
+ if (node->name != NULL &&
+ !strcmp(name, (char *)node->name))
+ child_list = g_list_prepend(child_list, node);
+
+ node = node->next;
+ }
+
+ return child_list;
+}
+
+GList *xml_util_get_child_string_list_content_by_name(xmlNode *node, ...)
+{
+ xmlChar *content;
+ va_list args;
+ GList *child_list = NULL;
+ GList *next;
+ GList *str_list = NULL;
+ xmlNode *child_list_node;
+ xmlNode *child_node;
+
+ va_start(args, node);
+
+ child_node = prv_get_child_node(node, args);
+
+ va_end(args);
+
+ if (child_node != NULL) {
+ child_list = prv_get_children_list(child_node->parent,
+ (const gchar *)child_node->name);
+ next = child_list;
+ while (next) {
+ child_list_node = (xmlNode *)next->data;
+
+ content = xmlNodeGetContent(child_list_node);
+
+ if (content != NULL) {
+ str_list = g_list_prepend(str_list,
+ g_strdup((gchar *)content));
+
+ xmlFree(content);
+ }
+
+ next = g_list_next(next);
+ }
+
+ g_list_free(child_list);
+ }
+
+ return str_list;
+}
+
+gchar *xml_util_get_child_string_content_by_name(xmlNode *node, ...)
+{
+ xmlChar *content;
+ va_list args;
+ gchar *str = NULL;
+ xmlNode *child_node;
+
+ va_start(args, node);
+
+ child_node = prv_get_child_node(node, args);
+
+ va_end(args);
+
+ if (child_node != NULL) {
+ content = xmlNodeGetContent(child_node);
+
+ if (content != NULL) {
+ str = g_strdup((gchar *)content);
+
+ xmlFree(content);
+ }
+ }
+
+ return str;
+}
diff --git a/libdleyna/server/xml-util.h b/libdleyna/server/xml-util.h
new file mode 100644
index 0000000..d5c72f4
--- /dev/null
+++ b/libdleyna/server/xml-util.h
@@ -0,0 +1,35 @@
+/*
+ * dLeyna
+ *
+ * Copyright (C) 2012-2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Christophe Guiraud <christophe.guiraud@intel.com>
+ *
+ */
+
+
+#ifndef DLS_XML_UTIL_H__
+#define DLS_XML_UTIL_H__
+
+#include <glib.h>
+#include <stdarg.h>
+#include <libxml/tree.h>
+
+GList *xml_util_get_child_string_list_content_by_name(xmlNode *node, ...);
+
+gchar *xml_util_get_child_string_content_by_name(xmlNode *node, ...);
+
+#endif /* DLS_XML_UTIL_H__ */
diff --git a/test/dbus/mediaconsole.py b/test/dbus/mediaconsole.py
index d54bb84..887c1f1 100644
--- a/test/dbus/mediaconsole.py
+++ b/test/dbus/mediaconsole.py
@@ -191,6 +191,9 @@ class Device(Container):
bytes, mime = self._deviceIF.GetIcon(mime_type, resolution)
print "Icon mime type: " + mime
+ def wake(self):
+ return self._deviceIF.Wake()
+
class UPNP(object):
def __init__(self):