4 * Copyright (C) 2012-2013 Intel Corporation. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU Lesser General Public License,
8 * version 2.1, as published by the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
19 * Mark Ryan <mark.d.ryan@intel.com>
25 #include <libgssdp/gssdp-resource-browser.h>
26 #include <libgupnp/gupnp-context-manager.h>
27 #include <libgupnp/gupnp-error.h>
29 #include <libdleyna/core/error.h>
30 #include <libdleyna/core/log.h>
31 #include <libdleyna/core/service-task.h>
35 #include "host-service.h"
36 #include "prop-defs.h"
40 dleyna_connector_id_t connection;
41 const dleyna_connector_dispatch_cb_t *interface_info;
42 dlr_upnp_callback_t found_server;
43 dlr_upnp_callback_t lost_server;
44 GUPnPContextManager *context_manager;
46 GHashTable *server_udn_map;
47 GHashTable *server_uc_map;
49 dlr_host_service_t *host_service;
52 /* Private structure used in service task */
53 typedef struct prv_device_new_ct_t_ prv_device_new_ct_t;
54 struct prv_device_new_ct_t_ {
59 const dleyna_task_queue_key_t *queue_id;
62 static void prv_device_new_free(prv_device_new_ct_t *priv_t)
66 g_free(priv_t->ip_address);
71 static void prv_device_chain_end(gboolean cancelled, gpointer data)
74 prv_device_new_ct_t *priv_t = (prv_device_new_ct_t *)data;
76 DLEYNA_LOG_DEBUG("Enter");
78 device = priv_t->device;
83 DLEYNA_LOG_DEBUG("Notify new server available: %s", device->path);
84 g_hash_table_insert(priv_t->upnp->server_udn_map, g_strdup(priv_t->udn),
86 priv_t->upnp->found_server(device->path);
90 g_hash_table_remove(priv_t->upnp->server_uc_map, priv_t->udn);
91 prv_device_new_free(priv_t);
94 dlr_device_delete(device);
96 DLEYNA_LOG_DEBUG("Exit");
97 DLEYNA_LOG_DEBUG_NL();
100 static void prv_device_context_switch_end(gboolean cancelled, gpointer data)
102 prv_device_new_ct_t *priv_t = (prv_device_new_ct_t *)data;
104 DLEYNA_LOG_DEBUG("Enter");
106 prv_device_new_free(priv_t);
108 DLEYNA_LOG_DEBUG("Exit");
111 static const dleyna_task_queue_key_t *prv_create_device_queue(
112 prv_device_new_ct_t **priv_t)
114 const dleyna_task_queue_key_t *queue_id;
116 *priv_t = g_new0(prv_device_new_ct_t, 1);
118 queue_id = dleyna_task_processor_add_queue(
119 dlr_renderer_service_get_task_processor(),
120 dleyna_service_task_create_source(),
122 DLEYNA_TASK_QUEUE_FLAG_AUTO_REMOVE,
123 dleyna_service_task_process_cb,
124 dleyna_service_task_cancel_cb,
125 dleyna_service_task_delete_cb);
126 dleyna_task_queue_set_finally(queue_id, prv_device_chain_end);
127 dleyna_task_queue_set_user_data(queue_id, *priv_t);
133 static void prv_update_device_context(prv_device_new_ct_t *priv_t,
134 dlr_upnp_t *upnp, const char *udn,
135 dlr_device_t *device,
136 const gchar *ip_address,
137 const dleyna_task_queue_key_t *queue_id)
140 priv_t->udn = g_strdup(udn);
141 priv_t->ip_address = g_strdup(ip_address);
142 priv_t->queue_id = queue_id;
143 priv_t->device = device;
145 g_hash_table_insert(upnp->server_uc_map, g_strdup(udn), priv_t);
148 static void prv_server_available_cb(GUPnPControlPoint *cp,
149 GUPnPDeviceProxy *proxy,
152 dlr_upnp_t *upnp = user_data;
154 dlr_device_t *device;
155 const gchar *ip_address;
156 dlr_device_context_t *context;
157 const dleyna_task_queue_key_t *queue_id;
159 prv_device_new_ct_t *priv_t;
161 DLEYNA_LOG_DEBUG("Enter");
163 udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *)proxy);
165 ip_address = gupnp_context_get_host_ip(
166 gupnp_control_point_get_context(cp));
168 if (!udn || !ip_address)
171 DLEYNA_LOG_DEBUG("UDN %s", udn);
172 DLEYNA_LOG_DEBUG("IP Address %s", ip_address);
174 device = g_hash_table_lookup(upnp->server_udn_map, udn);
177 priv_t = g_hash_table_lookup(upnp->server_uc_map, udn);
180 device = priv_t->device;
184 DLEYNA_LOG_DEBUG("Device not found. Adding");
186 queue_id = prv_create_device_queue(&priv_t);
188 device = dlr_device_new(upnp->connection, proxy, ip_address,
190 upnp->interface_info,
193 prv_update_device_context(priv_t, upnp, udn, device, ip_address,
198 DLEYNA_LOG_DEBUG("Device Found");
200 for (i = 0; i < device->contexts->len; ++i) {
201 context = g_ptr_array_index(device->contexts, i);
202 if (!strcmp(context->ip_address, ip_address))
206 if (i == device->contexts->len) {
207 DLEYNA_LOG_DEBUG("Adding Context");
208 dlr_device_append_new_context(device, ip_address,
215 DLEYNA_LOG_DEBUG("Exit");
216 DLEYNA_LOG_DEBUG_NL();
221 static gboolean prv_subscribe_to_service_changes(gpointer user_data)
223 dlr_device_t *device = user_data;
225 device->timeout_id = 0;
226 dlr_device_subscribe_to_service_changes(device);
231 static void prv_server_unavailable_cb(GUPnPControlPoint *cp,
232 GUPnPDeviceProxy *proxy,
235 dlr_upnp_t *upnp = user_data;
237 dlr_device_t *device;
238 const gchar *ip_address;
240 dlr_device_context_t *context;
242 gboolean under_construction = FALSE;
243 prv_device_new_ct_t *priv_t;
244 gboolean construction_ctx = FALSE;
245 const dleyna_task_queue_key_t *queue_id;
247 DLEYNA_LOG_DEBUG("Enter");
249 udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *)proxy);
251 ip_address = gupnp_context_get_host_ip(
252 gupnp_control_point_get_context(cp));
254 if (!udn || !ip_address)
257 DLEYNA_LOG_DEBUG("UDN %s", udn);
258 DLEYNA_LOG_DEBUG("IP Address %s", ip_address);
260 device = g_hash_table_lookup(upnp->server_udn_map, udn);
263 priv_t = g_hash_table_lookup(upnp->server_uc_map, udn);
266 device = priv_t->device;
267 under_construction = TRUE;
272 DLEYNA_LOG_WARNING("Device not found. Ignoring");
276 for (i = 0; i < device->contexts->len; ++i) {
277 context = g_ptr_array_index(device->contexts, i);
278 if (!strcmp(context->ip_address, ip_address))
282 if (i < device->contexts->len) {
283 subscribed = (context->subscribed_av || context->subscribed_cm);
285 if (under_construction)
286 construction_ctx = !strcmp(context->ip_address,
289 (void) g_ptr_array_remove_index(device->contexts, i);
291 if (device->contexts->len == 0) {
292 if (!under_construction) {
294 "Last Context lost. Delete device");
296 upnp->lost_server(device->path);
297 g_hash_table_remove(upnp->server_udn_map, udn);
300 "Device under construction. Cancelling");
302 dleyna_task_processor_cancel_queue(
305 } else if (under_construction && construction_ctx) {
307 "Device under construction. Switching context");
309 /* Cancel previous contruction task chain */
310 g_hash_table_remove(priv_t->upnp->server_uc_map,
312 dleyna_task_queue_set_finally(
314 prv_device_context_switch_end);
315 dleyna_task_processor_cancel_queue(priv_t->queue_id);
317 /* Create a new construction task chain */
318 context = dlr_device_get_context(device);
319 queue_id = prv_create_device_queue(&priv_t);
320 prv_update_device_context(priv_t, upnp, udn, device,
324 /* Start tasks from current construction step */
325 dlr_device_construct(device, context, upnp->connection,
326 upnp->interface_info, queue_id);
327 } else if (subscribed && !device->timeout_id) {
328 DLEYNA_LOG_DEBUG("Subscribe on new context");
330 device->timeout_id = g_timeout_add_seconds(1,
331 prv_subscribe_to_service_changes,
341 static void prv_on_context_available(GUPnPContextManager *context_manager,
342 GUPnPContext *context,
345 dlr_upnp_t *upnp = user_data;
346 GUPnPControlPoint *cp;
348 cp = gupnp_control_point_new(
350 "urn:schemas-upnp-org:device:MediaRenderer:1");
352 g_signal_connect(cp, "device-proxy-available",
353 G_CALLBACK(prv_server_available_cb), upnp);
355 g_signal_connect(cp, "device-proxy-unavailable",
356 G_CALLBACK(prv_server_unavailable_cb), upnp);
358 gssdp_resource_browser_set_active(GSSDP_RESOURCE_BROWSER(cp), TRUE);
359 gupnp_context_manager_manage_control_point(upnp->context_manager, cp);
363 dlr_upnp_t *dlr_upnp_new(dleyna_connector_id_t connection,
364 const dleyna_connector_dispatch_cb_t *dispatch_table,
365 dlr_upnp_callback_t found_server,
366 dlr_upnp_callback_t lost_server)
368 dlr_upnp_t *upnp = g_new0(dlr_upnp_t, 1);
370 upnp->connection = connection;
371 upnp->interface_info = dispatch_table;
372 upnp->found_server = found_server;
373 upnp->lost_server = lost_server;
375 upnp->server_udn_map = g_hash_table_new_full(g_str_hash, g_str_equal,
379 upnp->server_uc_map = g_hash_table_new_full(g_str_hash, g_str_equal,
382 upnp->context_manager = gupnp_context_manager_create(0);
384 g_signal_connect(upnp->context_manager, "context-available",
385 G_CALLBACK(prv_on_context_available),
388 dlr_host_service_new(&upnp->host_service);
393 void dlr_upnp_delete(dlr_upnp_t *upnp)
396 dlr_host_service_delete(upnp->host_service);
397 g_object_unref(upnp->context_manager);
398 g_hash_table_unref(upnp->server_udn_map);
399 g_hash_table_unref(upnp->server_uc_map);
405 GVariant *dlr_upnp_get_server_ids(dlr_upnp_t *upnp)
410 dlr_device_t *device;
412 DLEYNA_LOG_DEBUG("Enter");
414 g_variant_builder_init(&vb, G_VARIANT_TYPE("ao"));
415 g_hash_table_iter_init(&iter, upnp->server_udn_map);
417 while (g_hash_table_iter_next(&iter, NULL, &value)) {
419 g_variant_builder_add(&vb, "o", device->path);
422 DLEYNA_LOG_DEBUG("Exit");
424 return g_variant_ref_sink(g_variant_builder_end(&vb));
427 GHashTable *dlr_upnp_get_server_udn_map(dlr_upnp_t *upnp)
429 return upnp->server_udn_map;
433 void dlr_upnp_set_prop(dlr_upnp_t *upnp, dlr_task_t *task,
434 dlr_upnp_task_complete_t cb)
436 dlr_device_t *device;
437 dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
439 device = dlr_device_from_path(task->path, upnp->server_udn_map);
443 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
444 DLEYNA_ERROR_OBJECT_NOT_FOUND,
445 "Cannot locate a device for the specified object");
447 (void) g_idle_add(dlr_async_task_complete, cb_data);
449 dlr_device_set_prop(device, task, cb);
453 void dlr_upnp_get_prop(dlr_upnp_t *upnp, dlr_task_t *task,
454 dlr_upnp_task_complete_t cb)
456 dlr_device_t *device;
457 dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
459 DLEYNA_LOG_DEBUG("Enter");
461 DLEYNA_LOG_DEBUG("Path: %s", task->path);
462 DLEYNA_LOG_DEBUG("Interface %s", task->ut.get_prop.interface_name);
463 DLEYNA_LOG_DEBUG("Prop.%s", task->ut.get_prop.prop_name);
465 device = dlr_device_from_path(task->path, upnp->server_udn_map);
468 DLEYNA_LOG_WARNING("Cannot locate device");
471 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
472 DLEYNA_ERROR_OBJECT_NOT_FOUND,
473 "Cannot locate a device for the specified object");
475 (void) g_idle_add(dlr_async_task_complete, cb_data);
477 dlr_device_get_prop(device, task, cb);
480 DLEYNA_LOG_DEBUG("Exit");
483 void dlr_upnp_get_all_props(dlr_upnp_t *upnp, dlr_task_t *task,
484 dlr_upnp_task_complete_t cb)
486 dlr_device_t *device;
487 dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
489 DLEYNA_LOG_DEBUG("Enter");
491 DLEYNA_LOG_DEBUG("Path: %s", task->path);
492 DLEYNA_LOG_DEBUG("Interface %s", task->ut.get_prop.interface_name);
494 device = dlr_device_from_path(task->path, upnp->server_udn_map);
498 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
499 DLEYNA_ERROR_OBJECT_NOT_FOUND,
500 "Cannot locate a device for the specified object");
502 (void) g_idle_add(dlr_async_task_complete, cb_data);
504 dlr_device_get_all_props(device, task, cb);
507 DLEYNA_LOG_DEBUG("Exit");
510 void dlr_upnp_play(dlr_upnp_t *upnp, dlr_task_t *task,
511 dlr_upnp_task_complete_t cb)
513 dlr_device_t *device;
514 dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
516 DLEYNA_LOG_DEBUG("Enter");
518 device = dlr_device_from_path(task->path, upnp->server_udn_map);
522 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
523 DLEYNA_ERROR_OBJECT_NOT_FOUND,
524 "Cannot locate a device for the specified object");
526 (void) g_idle_add(dlr_async_task_complete, cb_data);
528 dlr_device_play(device, task, cb);
531 DLEYNA_LOG_DEBUG("Exit");
534 void dlr_upnp_pause(dlr_upnp_t *upnp, dlr_task_t *task,
535 dlr_upnp_task_complete_t cb)
537 dlr_device_t *device;
538 dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
540 DLEYNA_LOG_DEBUG("Enter");
542 device = dlr_device_from_path(task->path, upnp->server_udn_map);
546 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
547 DLEYNA_ERROR_OBJECT_NOT_FOUND,
548 "Cannot locate a device for the specified object");
550 (void) g_idle_add(dlr_async_task_complete, cb_data);
552 dlr_device_pause(device, task, cb);
555 DLEYNA_LOG_DEBUG("Exit");
558 void dlr_upnp_play_pause(dlr_upnp_t *upnp, dlr_task_t *task,
559 dlr_upnp_task_complete_t cb)
561 dlr_device_t *device;
562 dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
564 DLEYNA_LOG_DEBUG("Enter");
566 device = dlr_device_from_path(task->path, upnp->server_udn_map);
570 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
571 DLEYNA_ERROR_OBJECT_NOT_FOUND,
572 "Cannot locate a device for the specified object");
574 (void) g_idle_add(dlr_async_task_complete, cb_data);
576 dlr_device_play_pause(device, task, cb);
579 DLEYNA_LOG_DEBUG("Exit");
582 void dlr_upnp_stop(dlr_upnp_t *upnp, dlr_task_t *task,
583 dlr_upnp_task_complete_t cb)
585 dlr_device_t *device;
586 dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
588 DLEYNA_LOG_DEBUG("Enter");
590 device = dlr_device_from_path(task->path, upnp->server_udn_map);
594 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
595 DLEYNA_ERROR_OBJECT_NOT_FOUND,
596 "Cannot locate a device for the specified object");
598 (void) g_idle_add(dlr_async_task_complete, cb_data);
600 dlr_device_stop(device, task, cb);
603 DLEYNA_LOG_DEBUG("Exit");
606 void dlr_upnp_next(dlr_upnp_t *upnp, dlr_task_t *task,
607 dlr_upnp_task_complete_t cb)
609 dlr_device_t *device;
610 dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
612 DLEYNA_LOG_DEBUG("Enter");
614 device = dlr_device_from_path(task->path, upnp->server_udn_map);
618 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
619 DLEYNA_ERROR_OBJECT_NOT_FOUND,
620 "Cannot locate a device for the specified object");
622 (void) g_idle_add(dlr_async_task_complete, cb_data);
624 dlr_device_next(device, task, cb);
627 DLEYNA_LOG_DEBUG("Exit");
630 void dlr_upnp_previous(dlr_upnp_t *upnp, dlr_task_t *task,
631 dlr_upnp_task_complete_t cb)
633 dlr_device_t *device;
634 dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
636 DLEYNA_LOG_DEBUG("Enter");
638 device = dlr_device_from_path(task->path, upnp->server_udn_map);
642 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
643 DLEYNA_ERROR_OBJECT_NOT_FOUND,
644 "Cannot locate a device for the specified object");
646 (void) g_idle_add(dlr_async_task_complete, cb_data);
648 dlr_device_previous(device, task, cb);
651 DLEYNA_LOG_DEBUG("Exit");
654 void dlr_upnp_open_uri(dlr_upnp_t *upnp, dlr_task_t *task,
655 dlr_upnp_task_complete_t cb)
657 dlr_device_t *device;
658 dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
660 DLEYNA_LOG_DEBUG("Enter");
662 device = dlr_device_from_path(task->path, upnp->server_udn_map);
666 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
667 DLEYNA_ERROR_OBJECT_NOT_FOUND,
668 "Cannot locate a device for the specified object");
670 (void) g_idle_add(dlr_async_task_complete, cb_data);
672 dlr_device_open_uri(device, task, cb);
675 DLEYNA_LOG_DEBUG("Exit");
678 void dlr_upnp_seek(dlr_upnp_t *upnp, dlr_task_t *task,
679 dlr_upnp_task_complete_t cb)
681 dlr_device_t *device;
682 dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
684 DLEYNA_LOG_DEBUG("Enter");
686 device = dlr_device_from_path(task->path, upnp->server_udn_map);
690 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
691 DLEYNA_ERROR_OBJECT_NOT_FOUND,
692 "Cannot locate a device for the specified object");
694 (void) g_idle_add(dlr_async_task_complete, cb_data);
696 dlr_device_seek(device, task, cb);
699 DLEYNA_LOG_DEBUG("Exit");
702 void dlr_upnp_set_position(dlr_upnp_t *upnp, dlr_task_t *task,
703 dlr_upnp_task_complete_t cb)
705 dlr_device_t *device;
706 dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
708 DLEYNA_LOG_DEBUG("Enter");
710 device = dlr_device_from_path(task->path, upnp->server_udn_map);
714 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
715 DLEYNA_ERROR_OBJECT_NOT_FOUND,
716 "Cannot locate a device for the specified object");
718 (void) g_idle_add(dlr_async_task_complete, cb_data);
720 dlr_device_set_position(device, task, cb);
723 DLEYNA_LOG_DEBUG("Exit");
726 void dlr_upnp_goto_track(dlr_upnp_t *upnp, dlr_task_t *task,
727 dlr_upnp_task_complete_t cb)
729 dlr_device_t *device;
730 dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
732 DLEYNA_LOG_DEBUG("Enter");
734 device = dlr_device_from_path(task->path, upnp->server_udn_map);
738 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
739 DLEYNA_ERROR_OBJECT_NOT_FOUND,
740 "Cannot locate a device for the specified object");
742 (void) g_idle_add(dlr_async_task_complete, cb_data);
744 dlr_device_goto_track(device, task, cb);
747 DLEYNA_LOG_DEBUG("Exit");
750 void dlr_upnp_host_uri(dlr_upnp_t *upnp, dlr_task_t *task,
751 dlr_upnp_task_complete_t cb)
753 dlr_device_t *device;
754 dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
756 DLEYNA_LOG_DEBUG("Enter");
758 device = dlr_device_from_path(task->path, upnp->server_udn_map);
762 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
763 DLEYNA_ERROR_OBJECT_NOT_FOUND,
764 "Cannot locate a device for the specified object");
766 (void) g_idle_add(dlr_async_task_complete, cb_data);
768 dlr_device_host_uri(device, task, upnp->host_service, cb);
771 DLEYNA_LOG_DEBUG("Exit");
774 void dlr_upnp_remove_uri(dlr_upnp_t *upnp, dlr_task_t *task,
775 dlr_upnp_task_complete_t cb)
777 dlr_device_t *device;
778 dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
780 DLEYNA_LOG_DEBUG("Enter");
782 device = dlr_device_from_path(task->path, upnp->server_udn_map);
786 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
787 DLEYNA_ERROR_OBJECT_NOT_FOUND,
788 "Cannot locate a device for the specified object");
790 (void) g_idle_add(dlr_async_task_complete, cb_data);
792 dlr_device_remove_uri(device, task, upnp->host_service, cb);
795 DLEYNA_LOG_DEBUG("Exit");
798 void dlr_upnp_get_icon(dlr_upnp_t *upnp, dlr_task_t *task,
799 dlr_upnp_task_complete_t cb)
801 dlr_device_t *device;
802 dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
804 DLEYNA_LOG_DEBUG("Enter");
806 device = dlr_device_from_path(task->path, upnp->server_udn_map);
809 DLEYNA_LOG_WARNING("Cannot locate device");
812 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
813 DLEYNA_ERROR_OBJECT_NOT_FOUND,
814 "Cannot locate a device for the specified object");
816 (void) g_idle_add(dlr_async_task_complete, cb_data);
818 dlr_device_get_icon(device, task, cb);
821 DLEYNA_LOG_DEBUG("Exit");
824 void dlr_upnp_lost_client(dlr_upnp_t *upnp, const gchar *client_name)
826 dlr_host_service_lost_client(upnp->host_service, client_name);
829 void dlr_upnp_unsubscribe(dlr_upnp_t *upnp)
832 dlr_device_t *device;
834 DLEYNA_LOG_DEBUG("Enter");
836 g_hash_table_iter_init(&iter, upnp->server_udn_map);
837 while (g_hash_table_iter_next(&iter, NULL, (gpointer *)&device))
838 dlr_device_unsubscribe(device);
840 DLEYNA_LOG_DEBUG("Exit");
843 void dlr_upnp_rescan(dlr_upnp_t *upnp)
845 DLEYNA_LOG_DEBUG("re-scanning control points");
847 gupnp_context_manager_rescan_control_points(upnp->context_manager);
850 GUPnPContextManager *dlr_upnp_get_context_manager(dlr_upnp_t *upnp)
852 return upnp->context_manager;