Update dLeyna to v0.2.1
[profile/ivi/dLeyna.git] / dleyna-renderer / libdleyna / renderer / upnp.c
1 /*
2  * dLeyna
3  *
4  * Copyright (C) 2012-2013 Intel Corporation. All rights reserved.
5  *
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.
9  *
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
13  * for more details.
14  *
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.
18  *
19  * Mark Ryan <mark.d.ryan@intel.com>
20  *
21  */
22
23 #include <string.h>
24
25 #include <libgssdp/gssdp-resource-browser.h>
26 #include <libgupnp/gupnp-context-manager.h>
27 #include <libgupnp/gupnp-error.h>
28
29 #include <libdleyna/core/error.h>
30 #include <libdleyna/core/log.h>
31 #include <libdleyna/core/service-task.h>
32
33 #include "async.h"
34 #include "device.h"
35 #include "host-service.h"
36 #include "prop-defs.h"
37 #include "upnp.h"
38
39 struct dlr_upnp_t_ {
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;
45         void *user_data;
46         GHashTable *server_udn_map;
47         GHashTable *server_uc_map;
48         guint counter;
49         dlr_host_service_t *host_service;
50 };
51
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_ {
55         dlr_upnp_t *upnp;
56         char *udn;
57         gchar *ip_address;
58         dlr_device_t *device;
59         const dleyna_task_queue_key_t *queue_id;
60 };
61
62 static void prv_device_new_free(prv_device_new_ct_t *priv_t)
63 {
64         if (priv_t) {
65                 g_free(priv_t->udn);
66                 g_free(priv_t->ip_address);
67                 g_free(priv_t);
68         }
69 }
70
71 static void prv_device_chain_end(gboolean cancelled, gpointer data)
72 {
73         dlr_device_t *device;
74         prv_device_new_ct_t *priv_t = (prv_device_new_ct_t *)data;
75
76         DLEYNA_LOG_DEBUG("Enter");
77
78         device = priv_t->device;
79
80         if (cancelled)
81                 goto on_clear;
82
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),
85                             device);
86         priv_t->upnp->found_server(device->path);
87
88 on_clear:
89
90         g_hash_table_remove(priv_t->upnp->server_uc_map, priv_t->udn);
91         prv_device_new_free(priv_t);
92
93         if (cancelled)
94                 dlr_device_delete(device);
95
96         DLEYNA_LOG_DEBUG("Exit");
97         DLEYNA_LOG_DEBUG_NL();
98 }
99
100 static void prv_device_context_switch_end(gboolean cancelled, gpointer data)
101 {
102         prv_device_new_ct_t *priv_t = (prv_device_new_ct_t *)data;
103
104         DLEYNA_LOG_DEBUG("Enter");
105
106         prv_device_new_free(priv_t);
107
108         DLEYNA_LOG_DEBUG("Exit");
109 }
110
111 static const dleyna_task_queue_key_t *prv_create_device_queue(
112                                                 prv_device_new_ct_t **priv_t)
113 {
114         const dleyna_task_queue_key_t *queue_id;
115
116         *priv_t = g_new0(prv_device_new_ct_t, 1);
117
118         queue_id = dleyna_task_processor_add_queue(
119                         dlr_renderer_service_get_task_processor(),
120                         dleyna_service_task_create_source(),
121                         DLR_RENDERER_SINK,
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);
128
129
130         return queue_id;
131 }
132
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)
138 {
139         priv_t->upnp = upnp;
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;
144
145         g_hash_table_insert(upnp->server_uc_map, g_strdup(udn), priv_t);
146 }
147
148 static void prv_server_available_cb(GUPnPControlPoint *cp,
149                                     GUPnPDeviceProxy *proxy,
150                                     gpointer user_data)
151 {
152         dlr_upnp_t *upnp = user_data;
153         const char *udn;
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;
158         unsigned int i;
159         prv_device_new_ct_t *priv_t;
160
161         DLEYNA_LOG_DEBUG("Enter");
162
163         udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *)proxy);
164
165         ip_address = gupnp_context_get_host_ip(
166                 gupnp_control_point_get_context(cp));
167
168         if (!udn || !ip_address)
169                 goto on_error;
170
171         DLEYNA_LOG_DEBUG("UDN %s", udn);
172         DLEYNA_LOG_DEBUG("IP Address %s", ip_address);
173
174         device = g_hash_table_lookup(upnp->server_udn_map, udn);
175
176         if (!device) {
177                 priv_t = g_hash_table_lookup(upnp->server_uc_map, udn);
178
179                 if (priv_t)
180                         device = priv_t->device;
181         }
182
183         if (!device) {
184                 DLEYNA_LOG_DEBUG("Device not found. Adding");
185
186                 queue_id = prv_create_device_queue(&priv_t);
187
188                 device = dlr_device_new(upnp->connection, proxy, ip_address,
189                                         upnp->counter,
190                                         upnp->interface_info,
191                                         queue_id);
192
193                 prv_update_device_context(priv_t, upnp, udn, device, ip_address,
194                                           queue_id);
195
196                 upnp->counter++;
197         } else {
198                 DLEYNA_LOG_DEBUG("Device Found");
199
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))
203                                 break;
204                 }
205
206                 if (i == device->contexts->len) {
207                         DLEYNA_LOG_DEBUG("Adding Context");
208                         dlr_device_append_new_context(device, ip_address,
209                                                       proxy);
210                 }
211         }
212
213 on_error:
214
215         DLEYNA_LOG_DEBUG("Exit");
216         DLEYNA_LOG_DEBUG_NL();
217
218         return;
219 }
220
221 static gboolean prv_subscribe_to_service_changes(gpointer user_data)
222 {
223         dlr_device_t *device = user_data;
224
225         device->timeout_id = 0;
226         dlr_device_subscribe_to_service_changes(device);
227
228         return FALSE;
229 }
230
231 static void prv_server_unavailable_cb(GUPnPControlPoint *cp,
232                                       GUPnPDeviceProxy *proxy,
233                                       gpointer user_data)
234 {
235         dlr_upnp_t *upnp = user_data;
236         const char *udn;
237         dlr_device_t *device;
238         const gchar *ip_address;
239         unsigned int i;
240         dlr_device_context_t *context;
241         gboolean subscribed;
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;
246
247         DLEYNA_LOG_DEBUG("Enter");
248
249         udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *)proxy);
250
251         ip_address = gupnp_context_get_host_ip(
252                 gupnp_control_point_get_context(cp));
253
254         if (!udn || !ip_address)
255                 goto on_error;
256
257         DLEYNA_LOG_DEBUG("UDN %s", udn);
258         DLEYNA_LOG_DEBUG("IP Address %s", ip_address);
259
260         device = g_hash_table_lookup(upnp->server_udn_map, udn);
261
262         if (!device) {
263                 priv_t = g_hash_table_lookup(upnp->server_uc_map, udn);
264
265                 if (priv_t) {
266                         device = priv_t->device;
267                         under_construction = TRUE;
268                 }
269         }
270
271         if (!device) {
272                 DLEYNA_LOG_WARNING("Device not found. Ignoring");
273                 goto on_error;
274         }
275
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))
279                         break;
280         }
281
282         if (i < device->contexts->len) {
283                 subscribed = (context->subscribed_av || context->subscribed_cm);
284
285                 if (under_construction)
286                         construction_ctx = !strcmp(context->ip_address,
287                                                    priv_t->ip_address);
288
289                 (void) g_ptr_array_remove_index(device->contexts, i);
290
291                 if (device->contexts->len == 0) {
292                         if (!under_construction) {
293                                 DLEYNA_LOG_DEBUG(
294                                         "Last Context lost. Delete device");
295
296                                 upnp->lost_server(device->path);
297                                 g_hash_table_remove(upnp->server_udn_map, udn);
298                         } else {
299                                 DLEYNA_LOG_WARNING(
300                                        "Device under construction. Cancelling");
301
302                                 dleyna_task_processor_cancel_queue(
303                                                         priv_t->queue_id);
304                         }
305                 } else if (under_construction && construction_ctx) {
306                         DLEYNA_LOG_WARNING(
307                                 "Device under construction. Switching context");
308
309                         /* Cancel previous contruction task chain */
310                         g_hash_table_remove(priv_t->upnp->server_uc_map,
311                                             priv_t->udn);
312                         dleyna_task_queue_set_finally(
313                                                 priv_t->queue_id,
314                                                 prv_device_context_switch_end);
315                         dleyna_task_processor_cancel_queue(priv_t->queue_id);
316
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,
321                                                   context->ip_address,
322                                                   queue_id);
323
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");
329
330                         device->timeout_id = g_timeout_add_seconds(1,
331                                         prv_subscribe_to_service_changes,
332                                         device);
333                 }
334         }
335
336 on_error:
337
338         return;
339 }
340
341 static void prv_on_context_available(GUPnPContextManager *context_manager,
342                                      GUPnPContext *context,
343                                      gpointer user_data)
344 {
345         dlr_upnp_t *upnp = user_data;
346         GUPnPControlPoint *cp;
347
348         cp = gupnp_control_point_new(
349                 context,
350                 "urn:schemas-upnp-org:device:MediaRenderer:1");
351
352         g_signal_connect(cp, "device-proxy-available",
353                          G_CALLBACK(prv_server_available_cb), upnp);
354
355         g_signal_connect(cp, "device-proxy-unavailable",
356                          G_CALLBACK(prv_server_unavailable_cb), upnp);
357
358         gssdp_resource_browser_set_active(GSSDP_RESOURCE_BROWSER(cp), TRUE);
359         gupnp_context_manager_manage_control_point(upnp->context_manager, cp);
360         g_object_unref(cp);
361 }
362
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)
367 {
368         dlr_upnp_t *upnp = g_new0(dlr_upnp_t, 1);
369
370         upnp->connection = connection;
371         upnp->interface_info = dispatch_table;
372         upnp->found_server = found_server;
373         upnp->lost_server = lost_server;
374
375         upnp->server_udn_map = g_hash_table_new_full(g_str_hash, g_str_equal,
376                                                      g_free,
377                                                      dlr_device_delete);
378
379         upnp->server_uc_map = g_hash_table_new_full(g_str_hash, g_str_equal,
380                                                     g_free, NULL);
381
382         upnp->context_manager = gupnp_context_manager_create(0);
383
384         g_signal_connect(upnp->context_manager, "context-available",
385                          G_CALLBACK(prv_on_context_available),
386                          upnp);
387
388         dlr_host_service_new(&upnp->host_service);
389
390         return upnp;
391 }
392
393 void dlr_upnp_delete(dlr_upnp_t *upnp)
394 {
395         if (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);
400
401                 g_free(upnp);
402         }
403 }
404
405 GVariant *dlr_upnp_get_server_ids(dlr_upnp_t *upnp)
406 {
407         GVariantBuilder vb;
408         GHashTableIter iter;
409         gpointer value;
410         dlr_device_t *device;
411
412         DLEYNA_LOG_DEBUG("Enter");
413
414         g_variant_builder_init(&vb, G_VARIANT_TYPE("ao"));
415         g_hash_table_iter_init(&iter, upnp->server_udn_map);
416
417         while (g_hash_table_iter_next(&iter, NULL, &value)) {
418                 device = value;
419                 g_variant_builder_add(&vb, "o", device->path);
420         }
421
422         DLEYNA_LOG_DEBUG("Exit");
423
424         return g_variant_ref_sink(g_variant_builder_end(&vb));
425 }
426
427 GHashTable *dlr_upnp_get_server_udn_map(dlr_upnp_t *upnp)
428 {
429         return upnp->server_udn_map;
430 }
431
432
433 void dlr_upnp_set_prop(dlr_upnp_t *upnp, dlr_task_t *task,
434                        dlr_upnp_task_complete_t cb)
435 {
436         dlr_device_t *device;
437         dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
438
439         device = dlr_device_from_path(task->path, upnp->server_udn_map);
440
441         if (!device) {
442                 cb_data->cb = cb;
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");
446
447                 (void) g_idle_add(dlr_async_task_complete, cb_data);
448         } else {
449                 dlr_device_set_prop(device, task, cb);
450         }
451 }
452
453 void dlr_upnp_get_prop(dlr_upnp_t *upnp, dlr_task_t *task,
454                        dlr_upnp_task_complete_t cb)
455 {
456         dlr_device_t *device;
457         dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
458
459         DLEYNA_LOG_DEBUG("Enter");
460
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);
464
465         device = dlr_device_from_path(task->path, upnp->server_udn_map);
466
467         if (!device) {
468                 DLEYNA_LOG_WARNING("Cannot locate device");
469
470                 cb_data->cb = cb;
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");
474
475                 (void) g_idle_add(dlr_async_task_complete, cb_data);
476         } else {
477                 dlr_device_get_prop(device, task, cb);
478         }
479
480         DLEYNA_LOG_DEBUG("Exit");
481 }
482
483 void dlr_upnp_get_all_props(dlr_upnp_t *upnp, dlr_task_t *task,
484                             dlr_upnp_task_complete_t cb)
485 {
486         dlr_device_t *device;
487         dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
488
489         DLEYNA_LOG_DEBUG("Enter");
490
491         DLEYNA_LOG_DEBUG("Path: %s", task->path);
492         DLEYNA_LOG_DEBUG("Interface %s", task->ut.get_prop.interface_name);
493
494         device = dlr_device_from_path(task->path, upnp->server_udn_map);
495
496         if (!device) {
497                 cb_data->cb = cb;
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");
501
502                 (void) g_idle_add(dlr_async_task_complete, cb_data);
503         } else {
504                 dlr_device_get_all_props(device, task, cb);
505         }
506
507         DLEYNA_LOG_DEBUG("Exit");
508 }
509
510 void dlr_upnp_play(dlr_upnp_t *upnp, dlr_task_t *task,
511                    dlr_upnp_task_complete_t cb)
512 {
513         dlr_device_t *device;
514         dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
515
516         DLEYNA_LOG_DEBUG("Enter");
517
518         device = dlr_device_from_path(task->path, upnp->server_udn_map);
519
520         if (!device) {
521                 cb_data->cb = cb;
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");
525
526                 (void) g_idle_add(dlr_async_task_complete, cb_data);
527         } else {
528                 dlr_device_play(device, task, cb);
529         }
530
531         DLEYNA_LOG_DEBUG("Exit");
532 }
533
534 void dlr_upnp_pause(dlr_upnp_t *upnp, dlr_task_t *task,
535                     dlr_upnp_task_complete_t cb)
536 {
537         dlr_device_t *device;
538         dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
539
540         DLEYNA_LOG_DEBUG("Enter");
541
542         device = dlr_device_from_path(task->path, upnp->server_udn_map);
543
544         if (!device) {
545                 cb_data->cb = cb;
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");
549
550                 (void) g_idle_add(dlr_async_task_complete, cb_data);
551         } else {
552                 dlr_device_pause(device, task, cb);
553         }
554
555         DLEYNA_LOG_DEBUG("Exit");
556 }
557
558 void dlr_upnp_play_pause(dlr_upnp_t *upnp, dlr_task_t *task,
559                          dlr_upnp_task_complete_t cb)
560 {
561         dlr_device_t *device;
562         dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
563
564         DLEYNA_LOG_DEBUG("Enter");
565
566         device = dlr_device_from_path(task->path, upnp->server_udn_map);
567
568         if (!device) {
569                 cb_data->cb = cb;
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");
573
574                 (void) g_idle_add(dlr_async_task_complete, cb_data);
575         } else {
576                 dlr_device_play_pause(device, task, cb);
577         }
578
579         DLEYNA_LOG_DEBUG("Exit");
580 }
581
582 void dlr_upnp_stop(dlr_upnp_t *upnp, dlr_task_t *task,
583                    dlr_upnp_task_complete_t cb)
584 {
585         dlr_device_t *device;
586         dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
587
588         DLEYNA_LOG_DEBUG("Enter");
589
590         device = dlr_device_from_path(task->path, upnp->server_udn_map);
591
592         if (!device) {
593                 cb_data->cb = cb;
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");
597
598                 (void) g_idle_add(dlr_async_task_complete, cb_data);
599         } else {
600                 dlr_device_stop(device, task, cb);
601         }
602
603         DLEYNA_LOG_DEBUG("Exit");
604 }
605
606 void dlr_upnp_next(dlr_upnp_t *upnp, dlr_task_t *task,
607                    dlr_upnp_task_complete_t cb)
608 {
609         dlr_device_t *device;
610         dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
611
612         DLEYNA_LOG_DEBUG("Enter");
613
614         device = dlr_device_from_path(task->path, upnp->server_udn_map);
615
616         if (!device) {
617                 cb_data->cb = cb;
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");
621
622                 (void) g_idle_add(dlr_async_task_complete, cb_data);
623         } else {
624                 dlr_device_next(device, task, cb);
625         }
626
627         DLEYNA_LOG_DEBUG("Exit");
628 }
629
630 void dlr_upnp_previous(dlr_upnp_t *upnp, dlr_task_t *task,
631                        dlr_upnp_task_complete_t cb)
632 {
633         dlr_device_t *device;
634         dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
635
636         DLEYNA_LOG_DEBUG("Enter");
637
638         device = dlr_device_from_path(task->path, upnp->server_udn_map);
639
640         if (!device) {
641                 cb_data->cb = cb;
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");
645
646                 (void) g_idle_add(dlr_async_task_complete, cb_data);
647         } else {
648                 dlr_device_previous(device, task, cb);
649         }
650
651         DLEYNA_LOG_DEBUG("Exit");
652 }
653
654 void dlr_upnp_open_uri(dlr_upnp_t *upnp, dlr_task_t *task,
655                        dlr_upnp_task_complete_t cb)
656 {
657         dlr_device_t *device;
658         dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
659
660         DLEYNA_LOG_DEBUG("Enter");
661
662         device = dlr_device_from_path(task->path, upnp->server_udn_map);
663
664         if (!device) {
665                 cb_data->cb = cb;
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");
669
670                 (void) g_idle_add(dlr_async_task_complete, cb_data);
671         } else {
672                 dlr_device_open_uri(device, task, cb);
673         }
674
675         DLEYNA_LOG_DEBUG("Exit");
676 }
677
678 void dlr_upnp_seek(dlr_upnp_t *upnp, dlr_task_t *task,
679                    dlr_upnp_task_complete_t cb)
680 {
681         dlr_device_t *device;
682         dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
683
684         DLEYNA_LOG_DEBUG("Enter");
685
686         device = dlr_device_from_path(task->path, upnp->server_udn_map);
687
688         if (!device) {
689                 cb_data->cb = cb;
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");
693
694                 (void) g_idle_add(dlr_async_task_complete, cb_data);
695         } else {
696                 dlr_device_seek(device, task, cb);
697         }
698
699         DLEYNA_LOG_DEBUG("Exit");
700 }
701
702 void dlr_upnp_set_position(dlr_upnp_t *upnp, dlr_task_t *task,
703                            dlr_upnp_task_complete_t cb)
704 {
705         dlr_device_t *device;
706         dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
707
708         DLEYNA_LOG_DEBUG("Enter");
709
710         device = dlr_device_from_path(task->path, upnp->server_udn_map);
711
712         if (!device) {
713                 cb_data->cb = cb;
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");
717
718                 (void) g_idle_add(dlr_async_task_complete, cb_data);
719         } else {
720                 dlr_device_set_position(device, task, cb);
721         }
722
723         DLEYNA_LOG_DEBUG("Exit");
724 }
725
726 void dlr_upnp_goto_track(dlr_upnp_t *upnp, dlr_task_t *task,
727                          dlr_upnp_task_complete_t cb)
728 {
729         dlr_device_t *device;
730         dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
731
732         DLEYNA_LOG_DEBUG("Enter");
733
734         device = dlr_device_from_path(task->path, upnp->server_udn_map);
735
736         if (!device) {
737                 cb_data->cb = cb;
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");
741
742                 (void) g_idle_add(dlr_async_task_complete, cb_data);
743         } else {
744                 dlr_device_goto_track(device, task, cb);
745         }
746
747         DLEYNA_LOG_DEBUG("Exit");
748 }
749
750 void dlr_upnp_host_uri(dlr_upnp_t *upnp, dlr_task_t *task,
751                        dlr_upnp_task_complete_t cb)
752 {
753         dlr_device_t *device;
754         dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
755
756         DLEYNA_LOG_DEBUG("Enter");
757
758         device = dlr_device_from_path(task->path, upnp->server_udn_map);
759
760         if (!device) {
761                 cb_data->cb = cb;
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");
765
766                 (void) g_idle_add(dlr_async_task_complete, cb_data);
767         } else {
768                 dlr_device_host_uri(device, task, upnp->host_service, cb);
769         }
770
771         DLEYNA_LOG_DEBUG("Exit");
772 }
773
774 void dlr_upnp_remove_uri(dlr_upnp_t *upnp, dlr_task_t *task,
775                          dlr_upnp_task_complete_t cb)
776 {
777         dlr_device_t *device;
778         dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
779
780         DLEYNA_LOG_DEBUG("Enter");
781
782         device = dlr_device_from_path(task->path, upnp->server_udn_map);
783
784         if (!device) {
785                 cb_data->cb = cb;
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");
789
790                 (void) g_idle_add(dlr_async_task_complete, cb_data);
791         } else {
792                 dlr_device_remove_uri(device, task, upnp->host_service, cb);
793         }
794
795         DLEYNA_LOG_DEBUG("Exit");
796 }
797
798 void dlr_upnp_get_icon(dlr_upnp_t *upnp, dlr_task_t *task,
799                        dlr_upnp_task_complete_t cb)
800 {
801         dlr_device_t *device;
802         dlr_async_task_t *cb_data = (dlr_async_task_t *)task;
803
804         DLEYNA_LOG_DEBUG("Enter");
805
806         device = dlr_device_from_path(task->path, upnp->server_udn_map);
807
808         if (!device) {
809                 DLEYNA_LOG_WARNING("Cannot locate device");
810
811                 cb_data->cb = cb;
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");
815
816                 (void) g_idle_add(dlr_async_task_complete, cb_data);
817         } else {
818                 dlr_device_get_icon(device, task, cb);
819         }
820
821         DLEYNA_LOG_DEBUG("Exit");
822 }
823
824 void dlr_upnp_lost_client(dlr_upnp_t *upnp, const gchar *client_name)
825 {
826         dlr_host_service_lost_client(upnp->host_service, client_name);
827 }
828
829 void dlr_upnp_unsubscribe(dlr_upnp_t *upnp)
830 {
831         GHashTableIter iter;
832         dlr_device_t *device;
833
834         DLEYNA_LOG_DEBUG("Enter");
835
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);
839
840         DLEYNA_LOG_DEBUG("Exit");
841 }
842
843 void dlr_upnp_rescan(dlr_upnp_t *upnp)
844 {
845         DLEYNA_LOG_DEBUG("re-scanning control points");
846
847         gupnp_context_manager_rescan_control_points(upnp->context_manager);
848 }
849
850 GUPnPContextManager *dlr_upnp_get_context_manager(dlr_upnp_t *upnp)
851 {
852         return upnp->context_manager;
853 }