75bb35864045a5f9000085d16b5ff2dc56bbd2d4
[profile/ivi/dLeyna.git] / dleyna-renderer / libdleyna / renderer / server.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
24 #include <signal.h>
25 #include <stdbool.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <syslog.h>
31 #include <sys/signalfd.h>
32
33 #include <libdleyna/core/connector.h>
34 #include <libdleyna/core/control-point.h>
35 #include <libdleyna/core/error.h>
36 #include <libdleyna/core/log.h>
37 #include <libdleyna/core/task-processor.h>
38
39 #include "async.h"
40 #include "control-point-renderer.h"
41 #include "device.h"
42 #include "prop-defs.h"
43 #include "server.h"
44 #include "upnp.h"
45
46 #ifdef UA_PREFIX
47         #define DLR_PRG_NAME UA_PREFIX " dLeyna/" VERSION
48 #else
49         #define DLR_PRG_NAME "dLeyna/" VERSION
50 #endif
51
52 #define DLR_INTERFACE_GET_VERSION "GetVersion"
53 #define DLR_INTERFACE_GET_SERVERS "GetServers"
54 #define DLR_INTERFACE_RELEASE "Release"
55
56 #define DLR_INTERFACE_FOUND_SERVER "FoundServer"
57 #define DLR_INTERFACE_LOST_SERVER "LostServer"
58
59 #define DLR_INTERFACE_HOST_FILE "HostFile"
60 #define DLR_INTERFACE_REMOVE_FILE "RemoveFile"
61
62 #define DLR_INTERFACE_VERSION "Version"
63 #define DLR_INTERFACE_SERVERS "Servers"
64
65 #define DLR_INTERFACE_PATH "Path"
66 #define DLR_INTERFACE_URI "Uri"
67 #define DLR_INTERFACE_ID "Id"
68
69 #define DLR_INTERFACE_CHANGED_PROPERTIES "changed_properties"
70 #define DLR_INTERFACE_INVALIDATED_PROPERTIES "invalidated_properties"
71 #define DLR_INTERFACE_GET "Get"
72 #define DLR_INTERFACE_GET_ALL "GetAll"
73 #define DLR_INTERFACE_SET "Set"
74 #define DLR_INTERFACE_INTERFACE_NAME "interface_name"
75 #define DLR_INTERFACE_PROPERTY_NAME "property_name"
76 #define DLR_INTERFACE_PROPERTIES_VALUE "properties"
77 #define DLR_INTERFACE_VALUE "value"
78 #define DLR_INTERFACE_OFFSET "offset"
79 #define DLR_INTERFACE_POSITION "position"
80 #define DLR_INTERFACE_TRACKID "trackid"
81 #define DLR_INTERFACE_TRACK_NUMBER "TrackNumber"
82
83 #define DLR_INTERFACE_RAISE "Raise"
84 #define DLR_INTERFACE_QUIT "Quit"
85 #define DLR_INTERFACE_PLAY "Play"
86 #define DLR_INTERFACE_PLAY_PAUSE "PlayPause"
87 #define DLR_INTERFACE_NEXT "Next"
88 #define DLR_INTERFACE_PREVIOUS "Previous"
89 #define DLR_INTERFACE_PAUSE "Pause"
90 #define DLR_INTERFACE_STOP "Stop"
91 #define DLR_INTERFACE_OPEN_URI "OpenUri"
92 #define DLR_INTERFACE_SEEK "Seek"
93 #define DLR_INTERFACE_SET_POSITION "SetPosition"
94 #define DLR_INTERFACE_GOTO_TRACK "GotoTrack"
95
96 #define DLR_INTERFACE_CANCEL "Cancel"
97
98 typedef struct dlr_context_t_ dlr_context_t;
99 struct dlr_context_t_ {
100         guint dlr_id;
101         dleyna_connector_id_t connection;
102         guint watchers;
103         dleyna_task_processor_t *processor;
104         const dleyna_connector_t *connector;
105         dlr_upnp_t *upnp;
106         dleyna_settings_t *settings;
107 };
108
109 static dlr_context_t g_context;
110
111 static const gchar g_root_introspection[] =
112         "<node>"
113         "  <interface name='"DLEYNA_SERVER_INTERFACE_MANAGER"'>"
114         "    <method name='"DLR_INTERFACE_GET_VERSION"'>"
115         "      <arg type='s' name='"DLR_INTERFACE_VERSION"'"
116         "           direction='out'/>"
117         "    </method>"
118         "    <method name='"DLR_INTERFACE_RELEASE"'>"
119         "    </method>"
120         "    <method name='"DLR_INTERFACE_GET_SERVERS"'>"
121         "      <arg type='as' name='"DLR_INTERFACE_SERVERS"'"
122         "           direction='out'/>"
123         "    </method>"
124         "    <signal name='"DLR_INTERFACE_FOUND_SERVER"'>"
125         "      <arg type='s' name='"DLR_INTERFACE_PATH"'/>"
126         "    </signal>"
127         "    <signal name='"DLR_INTERFACE_LOST_SERVER"'>"
128         "      <arg type='s' name='"DLR_INTERFACE_PATH"'/>"
129         "    </signal>"
130         "  </interface>"
131         "</node>";
132
133 static const gchar g_server_introspection[] =
134         "<node>"
135         "  <interface name='"DLR_INTERFACE_PROPERTIES"'>"
136         "    <method name='"DLR_INTERFACE_GET"'>"
137         "      <arg type='s' name='"DLR_INTERFACE_INTERFACE_NAME"'"
138         "           direction='in'/>"
139         "      <arg type='s' name='"DLR_INTERFACE_PROPERTY_NAME"'"
140         "           direction='in'/>"
141         "      <arg type='v' name='"DLR_INTERFACE_VALUE"'"
142         "           direction='out'/>"
143         "    </method>"
144         "    <method name='"DLR_INTERFACE_GET_ALL"'>"
145         "      <arg type='s' name='"DLR_INTERFACE_INTERFACE_NAME"'"
146         "           direction='in'/>"
147         "      <arg type='a{sv}' name='"DLR_INTERFACE_PROPERTIES_VALUE"'"
148         "           direction='out'/>"
149         "    </method>"
150         "    <method name='"DLR_INTERFACE_SET"'>"
151         "      <arg type='s' name='"DLR_INTERFACE_INTERFACE_NAME"'"
152         "           direction='in'/>"
153         "      <arg type='s' name='"DLR_INTERFACE_PROPERTY_NAME"'"
154         "           direction='in'/>"
155         "      <arg type='v' name='"DLR_INTERFACE_VALUE"'"
156         "           direction='in'/>"
157         "    </method>"
158         "    <signal name='"DLR_INTERFACE_PROPERTIES_CHANGED"'>"
159         "      <arg type='s' name='"DLR_INTERFACE_INTERFACE_NAME"'/>"
160         "      <arg type='a{sv}' name='"DLR_INTERFACE_CHANGED_PROPERTIES"'/>"
161         "      <arg type='as' name='"DLR_INTERFACE_INVALIDATED_PROPERTIES"'/>"
162         "    </signal>"
163         "  </interface>"
164         "  <interface name='"DLR_INTERFACE_SERVER"'>"
165         "    <method name='"DLR_INTERFACE_RAISE"'>"
166         "    </method>"
167         "    <method name='"DLR_INTERFACE_QUIT"'>"
168         "    </method>"
169         "    <property type='b' name='"DLR_INTERFACE_PROP_CAN_QUIT"'"
170         "       access='read'/>"
171         "    <property type='b' name='"DLR_INTERFACE_PROP_CAN_RAISE"'"
172         "       access='read'/>"
173         "    <property type='b' name='"DLR_INTERFACE_PROP_CAN_SET_FULLSCREEN"'"
174         "       access='read'/>"
175         "    <property type='b' name='"DLR_INTERFACE_PROP_HAS_TRACK_LIST"'"
176         "       access='read'/>"
177         "    <property type='s' name='"DLR_INTERFACE_PROP_IDENTITY"'"
178         "       access='read'/>"
179         "    <property type='as' name='"DLR_INTERFACE_PROP_SUPPORTED_URIS"'"
180         "       access='read'/>"
181         "    <property type='as' name='"DLR_INTERFACE_PROP_SUPPORTED_MIME"'"
182         "       access='read'/>"
183         "  </interface>"
184         "  <interface name='"DLR_INTERFACE_PLAYER"'>"
185         "    <method name='"DLR_INTERFACE_PLAY"'>"
186         "    </method>"
187         "    <method name='"DLR_INTERFACE_PAUSE"'>"
188         "    </method>"
189         "    <method name='"DLR_INTERFACE_PLAY_PAUSE"'>"
190         "    </method>"
191         "    <method name='"DLR_INTERFACE_STOP"'>"
192         "    </method>"
193         "    <method name='"DLR_INTERFACE_NEXT"'>"
194         "    </method>"
195         "    <method name='"DLR_INTERFACE_PREVIOUS"'>"
196         "    </method>"
197         "    <method name='"DLR_INTERFACE_OPEN_URI"'>"
198         "      <arg type='s' name='"DLR_INTERFACE_URI"'"
199         "           direction='in'/>"
200         "    </method>"
201         "    <method name='"DLR_INTERFACE_SEEK"'>"
202         "      <arg type='x' name='"DLR_INTERFACE_OFFSET"'"
203         "           direction='in'/>"
204         "    </method>"
205         "    <method name='"DLR_INTERFACE_SET_POSITION"'>"
206         "      <arg type='o' name='"DLR_INTERFACE_TRACKID"'"
207         "           direction='in'/>"
208         "      <arg type='x' name='"DLR_INTERFACE_POSITION"'"
209         "           direction='in'/>"
210         "    </method>"
211         "    <method name='"DLR_INTERFACE_GOTO_TRACK"'>"
212         "      <arg type='u' name='"DLR_INTERFACE_TRACK_NUMBER"'"
213         "           direction='in'/>"
214         "    </method>"
215         "    <property type='s' name='"DLR_INTERFACE_PROP_PLAYBACK_STATUS"'"
216         "       access='read'/>"
217         "    <property type='d' name='"DLR_INTERFACE_PROP_RATE"'"
218         "       access='readwrite'/>"
219         "    <property type='d' name='"DLR_INTERFACE_PROP_MINIMUM_RATE"'"
220         "       access='read'/>"
221         "    <property type='d' name='"DLR_INTERFACE_PROP_MAXIMUM_RATE"'"
222         "       access='read'/>"
223         "    <property type='ad'"
224         "       name='"DLR_INTERFACE_PROP_TRANSPORT_PLAY_SPEEDS"'"
225         "       access='read'/>"
226         "    <property type='d' name='"DLR_INTERFACE_PROP_VOLUME"'"
227         "       access='readwrite'/>"
228         "    <property type='b' name='"DLR_INTERFACE_PROP_CAN_PLAY"'"
229         "       access='read'/>"
230         "    <property type='b' name='"DLR_INTERFACE_PROP_CAN_SEEK"'"
231         "       access='read'/>"
232         "    <property type='b' name='"DLR_INTERFACE_PROP_CAN_CONTROL"'"
233         "       access='read'/>"
234         "    <property type='b' name='"DLR_INTERFACE_PROP_CAN_PAUSE"'"
235         "       access='read'/>"
236         "    <property type='b' name='"DLR_INTERFACE_PROP_CAN_NEXT"'"
237         "       access='read'/>"
238         "    <property type='b' name='"DLR_INTERFACE_PROP_CAN_PREVIOUS"'"
239         "       access='read'/>"
240         "    <property type='x' name='"DLR_INTERFACE_PROP_POSITION"'"
241         "       access='read'/>"
242         "    <property type='a{sv}' name='"DLR_INTERFACE_PROP_METADATA"'"
243         "       access='read'/>"
244         "    <property type='u' name='"DLR_INTERFACE_PROP_CURRENT_TRACK"'"
245         "       access='read'/>"
246         "    <property type='u' name='"DLR_INTERFACE_PROP_NUMBER_OF_TRACKS"'"
247         "       access='read'/>"
248         "  </interface>"
249         "  <interface name='"DLEYNA_INTERFACE_PUSH_HOST"'>"
250         "    <method name='"DLR_INTERFACE_HOST_FILE"'>"
251         "      <arg type='s' name='"DLR_INTERFACE_PATH"'"
252         "           direction='in'/>"
253         "      <arg type='s' name='"DLR_INTERFACE_URI"'"
254         "           direction='out'/>"
255         "    </method>"
256         "    <method name='"DLR_INTERFACE_REMOVE_FILE"'>"
257         "      <arg type='s' name='"DLR_INTERFACE_PATH"'"
258         "           direction='in'/>"
259         "    </method>"
260         "  </interface>"
261         "  <interface name='"DLEYNA_SERVER_INTERFACE_RENDERER_DEVICE"'>"
262         "    <method name='"DLR_INTERFACE_CANCEL"'>"
263         "    </method>"
264         "    <property type='s' name='"DLR_INTERFACE_PROP_DEVICE_TYPE"'"
265         "       access='read'/>"
266         "    <property type='s' name='"DLR_INTERFACE_PROP_UDN"'"
267         "       access='read'/>"
268         "    <property type='s' name='"DLR_INTERFACE_PROP_FRIENDLY_NAME"'"
269         "       access='read'/>"
270         "    <property type='s' name='"DLR_INTERFACE_PROP_ICON_URL"'"
271         "       access='read'/>"
272         "    <property type='s' name='"DLR_INTERFACE_PROP_MANUFACTURER"'"
273         "       access='read'/>"
274         "    <property type='s' name='"DLR_INTERFACE_PROP_MANUFACTURER_URL"'"
275         "       access='read'/>"
276         "    <property type='s' name='"DLR_INTERFACE_PROP_MODEL_DESCRIPTION"'"
277         "       access='read'/>"
278         "    <property type='s' name='"DLR_INTERFACE_PROP_MODEL_NAME"'"
279         "       access='read'/>"
280         "    <property type='s' name='"DLR_INTERFACE_PROP_MODEL_NUMBER"'"
281         "       access='read'/>"
282         "    <property type='s' name='"DLR_INTERFACE_PROP_SERIAL_NUMBER"'"
283         "       access='read'/>"
284         "    <property type='s' name='"DLR_INTERFACE_PROP_PRESENTATION_URL"'"
285         "       access='read'/>"
286         "    <property type='s' name='"DLR_INTERFACE_PROP_PROTOCOL_INFO"'"
287         "       access='read'/>"
288         "  </interface>"
289         "</node>";
290
291 static void prv_process_task(dleyna_task_atom_t *task, gpointer user_data);
292
293 static void prv_dlr_method_call(dleyna_connector_id_t conn,
294                                 const gchar *sender,
295                                 const gchar *object,
296                                 const gchar *interface,
297                                 const gchar *method,
298                                 GVariant *parameters,
299                                 dleyna_connector_msg_id_t invocation);
300
301 static void prv_dlr_device_method_call(dleyna_connector_id_t conn,
302                                        const gchar *sender,
303                                        const gchar *object,
304                                        const gchar *interface,
305                                        const gchar *method,
306                                        GVariant *parameters,
307                                        dleyna_connector_msg_id_t invocation);
308
309 static void prv_props_method_call(dleyna_connector_id_t conn,
310                                   const gchar *sender,
311                                   const gchar *object,
312                                   const gchar *interface,
313                                   const gchar *method,
314                                   GVariant *parameters,
315                                   dleyna_connector_msg_id_t invocation);
316
317 static void prv_dlr_player_method_call(dleyna_connector_id_t conn,
318                                        const gchar *sender,
319                                        const gchar *object,
320                                        const gchar *interface,
321                                        const gchar *method,
322                                        GVariant *parameters,
323                                        dleyna_connector_msg_id_t invocation);
324
325 static void prv_dlr_push_host_method_call(dleyna_connector_id_t conn,
326                                           const gchar *sender,
327                                           const gchar *object,
328                                           const gchar *interface,
329                                           const gchar *method,
330                                           GVariant *parameters,
331                                           dleyna_connector_msg_id_t invocation);
332
333 static void prv_renderer_device_method_call(
334                                         dleyna_connector_id_t conn,
335                                         const gchar *sender,
336                                         const gchar *object,
337                                         const gchar *interface,
338                                         const gchar *method,
339                                         GVariant *parameters,
340                                         dleyna_connector_msg_id_t invocation);
341
342 static const dleyna_connector_dispatch_cb_t g_root_vtables[1] = {
343         prv_dlr_method_call
344 };
345
346 static const dleyna_connector_dispatch_cb_t
347                                 g_server_vtables[DLR_INTERFACE_INFO_MAX] = {
348         /* MUST be in the exact same order as g_msu_server_introspection */
349         prv_props_method_call,
350         prv_dlr_device_method_call,
351         prv_dlr_player_method_call,
352         prv_dlr_push_host_method_call,
353         prv_renderer_device_method_call
354 };
355
356 const dleyna_connector_t *dlr_renderer_get_connector(void)
357 {
358         return g_context.connector;
359 }
360
361 dleyna_task_processor_t *dlr_renderer_service_get_task_processor(void)
362 {
363         return g_context.processor;
364 }
365
366 dlr_upnp_t *dlr_renderer_service_get_upnp(void)
367 {
368         return g_context.upnp;
369 }
370
371 static void prv_process_sync_task(dlr_task_t *task)
372 {
373         GError *error;
374
375         switch (task->type) {
376         case DLR_TASK_GET_VERSION:
377                 dlr_task_complete(task);
378                 dleyna_task_queue_task_completed(task->atom.queue_id);
379                 break;
380         case DLR_TASK_GET_SERVERS:
381                 task->result = dlr_upnp_get_server_ids(g_context.upnp);
382                 dlr_task_complete(task);
383                 dleyna_task_queue_task_completed(task->atom.queue_id);
384                 break;
385         case DLR_TASK_RAISE:
386         case DLR_TASK_QUIT:
387                 error = g_error_new(DLEYNA_SERVER_ERROR,
388                                     DLEYNA_ERROR_NOT_SUPPORTED,
389                                     "Command not supported.");
390                 dlr_task_fail(task, error);
391                 dleyna_task_queue_task_completed(task->atom.queue_id);
392                 g_error_free(error);
393                 break;
394         default:
395                 break;
396         }
397 }
398
399 static void prv_async_task_complete(dlr_task_t *task, GError *error)
400 {
401         DLEYNA_LOG_DEBUG("Enter");
402
403         if (error) {
404                 dlr_task_fail(task, error);
405                 g_error_free(error);
406         } else {
407                 dlr_task_complete(task);
408         }
409
410         dleyna_task_queue_task_completed(task->atom.queue_id);
411
412         DLEYNA_LOG_DEBUG("Exit");
413 }
414
415 static void prv_process_async_task(dlr_task_t *task)
416 {
417         dlr_async_task_t *async_task = (dlr_async_task_t *)task;
418
419         DLEYNA_LOG_DEBUG("Enter");
420
421         async_task->cancellable = g_cancellable_new();
422
423         switch (task->type) {
424         case DLR_TASK_GET_PROP:
425                 dlr_upnp_get_prop(g_context.upnp, task,
426                                   prv_async_task_complete);
427                 break;
428         case DLR_TASK_GET_ALL_PROPS:
429                 dlr_upnp_get_all_props(g_context.upnp, task,
430                                        prv_async_task_complete);
431                 break;
432         case DLR_TASK_SET_PROP:
433                 dlr_upnp_set_prop(g_context.upnp, task,
434                                   prv_async_task_complete);
435                 break;
436         case DLR_TASK_PLAY:
437                 dlr_upnp_play(g_context.upnp, task,
438                               prv_async_task_complete);
439                 break;
440         case DLR_TASK_PAUSE:
441                 dlr_upnp_pause(g_context.upnp, task,
442                                prv_async_task_complete);
443                 break;
444         case DLR_TASK_PLAY_PAUSE:
445                 dlr_upnp_play_pause(g_context.upnp, task,
446                                     prv_async_task_complete);
447                 break;
448         case DLR_TASK_STOP:
449                 dlr_upnp_stop(g_context.upnp, task,
450                               prv_async_task_complete);
451                 break;
452         case DLR_TASK_NEXT:
453                 dlr_upnp_next(g_context.upnp, task,
454                               prv_async_task_complete);
455                 break;
456         case DLR_TASK_PREVIOUS:
457                 dlr_upnp_previous(g_context.upnp, task,
458                                   prv_async_task_complete);
459                 break;
460         case DLR_TASK_OPEN_URI:
461                 dlr_upnp_open_uri(g_context.upnp, task,
462                                   prv_async_task_complete);
463                 break;
464         case DLR_TASK_SEEK:
465                 dlr_upnp_seek(g_context.upnp, task,
466                               prv_async_task_complete);
467                 break;
468         case DLR_TASK_SET_POSITION:
469                 dlr_upnp_set_position(g_context.upnp, task,
470                                       prv_async_task_complete);
471                 break;
472         case DLR_TASK_GOTO_TRACK:
473                 dlr_upnp_goto_track(g_context.upnp, task,
474                                     prv_async_task_complete);
475                 break;
476         case DLR_TASK_HOST_URI:
477                 dlr_upnp_host_uri(g_context.upnp, task,
478                                   prv_async_task_complete);
479                 break;
480         case DLR_TASK_REMOVE_URI:
481                 dlr_upnp_remove_uri(g_context.upnp, task,
482                                     prv_async_task_complete);
483                 break;
484         default:
485                 break;
486         }
487
488         DLEYNA_LOG_DEBUG("Exit");
489 }
490
491 static void prv_process_task(dleyna_task_atom_t *task, gpointer user_data)
492 {
493         dlr_task_t *client_task = (dlr_task_t *)task;
494
495         if (client_task->synchronous)
496                 prv_process_sync_task(client_task);
497         else
498                 prv_process_async_task(client_task);
499 }
500
501 static void prv_cancel_task(dleyna_task_atom_t *task, gpointer user_data)
502 {
503         dlr_task_cancel((dlr_task_t *)task);
504 }
505
506 static void prv_delete_task(dleyna_task_atom_t *task, gpointer user_data)
507 {
508         dlr_task_delete((dlr_task_t *)task);
509 }
510
511 static void prv_remove_client(const gchar *name)
512 {
513         dleyna_task_processor_remove_queues_for_source(g_context.processor,
514                                                        name);
515
516         dlr_upnp_lost_client(g_context.upnp, name);
517
518         g_context.watchers--;
519         if (g_context.watchers == 0)
520                 if (!dleyna_settings_is_never_quit(g_context.settings))
521                         dleyna_task_processor_set_quitting(g_context.processor);
522 }
523
524 static void prv_lost_client(const gchar *name)
525 {
526         DLEYNA_LOG_INFO("Client %s lost", name);
527         prv_remove_client(name);
528 }
529
530 static void prv_control_point_initialize(const dleyna_connector_t *connector,
531                                          dleyna_task_processor_t *processor,
532                                          dleyna_settings_t *settings)
533 {
534         memset(&g_context, 0, sizeof(g_context));
535
536         g_context.processor = processor;
537         g_context.settings = settings;
538         g_context.connector = connector;
539         g_context.connector->set_client_lost_cb(prv_lost_client);
540
541         g_set_prgname(DLR_PRG_NAME);
542 }
543
544 static void prv_control_point_stop_service(void)
545 {
546         dlr_upnp_unsubscribe(g_context.upnp);
547
548         if (g_context.upnp)
549                 dlr_upnp_delete(g_context.upnp);
550
551         if (g_context.connection) {
552                 if (g_context.dlr_id)
553                         g_context.connector->unpublish_object(
554                                                         g_context.connection,
555                                                         g_context.dlr_id);
556         }
557 }
558
559 static void prv_control_point_free(void)
560 {
561 }
562
563 static void prv_add_task(dlr_task_t *task, const gchar *source,
564                          const gchar *sink)
565 {
566         const dleyna_task_queue_key_t *queue_id;
567
568         if (g_context.connector->watch_client(source))
569                 g_context.watchers++;
570
571         queue_id = dleyna_task_processor_lookup_queue(g_context.processor,
572                                                       source, sink);
573         if (!queue_id)
574                 queue_id = dleyna_task_processor_add_queue(
575                                         g_context.processor,
576                                         source,
577                                         sink,
578                                         DLEYNA_TASK_QUEUE_FLAG_AUTO_START,
579                                         prv_process_task,
580                                         prv_cancel_task,
581                                         prv_delete_task);
582
583         dleyna_task_queue_add_task(queue_id, &task->atom);
584 }
585
586 static void prv_dlr_method_call(dleyna_connector_id_t conn,
587                                 const gchar *sender, const gchar *object,
588                                 const gchar *interface,
589                                 const gchar *method, GVariant *parameters,
590                                 dleyna_connector_msg_id_t invocation)
591 {
592         dlr_task_t *task;
593
594         DLEYNA_LOG_INFO("Calling %s method", method);
595
596         if (!strcmp(method, DLR_INTERFACE_RELEASE)) {
597                 g_context.connector->unwatch_client(sender);
598                 prv_remove_client(sender);
599                 g_context.connector->return_response(invocation, NULL);
600         } else {
601                 if (!strcmp(method, DLR_INTERFACE_GET_VERSION))
602                         task = dlr_task_get_version_new(invocation);
603                 else if (!strcmp(method, DLR_INTERFACE_GET_SERVERS))
604                         task = dlr_task_get_servers_new(invocation);
605                 else
606                         goto finished;
607
608                 prv_add_task(task, sender, DLR_RENDERER_SINK);
609         }
610
611 finished:
612
613         return;
614 }
615
616 static const gchar *prv_get_device_id(const gchar *object, GError **error)
617 {
618         dlr_device_t *device;
619
620         device = dlr_device_from_path(object,
621                                 dlr_upnp_get_server_udn_map(g_context.upnp));
622
623
624         if (!device) {
625                 DLEYNA_LOG_WARNING("Cannot locate device for %s", object);
626
627                 *error = g_error_new(DLEYNA_SERVER_ERROR,
628                                      DLEYNA_ERROR_OBJECT_NOT_FOUND,
629                                      "Cannot locate device corresponding to the specified path");
630                 goto on_error;
631         }
632
633         return device->path;
634
635 on_error:
636
637         return NULL;
638 }
639
640 static void prv_props_method_call(dleyna_connector_id_t conn,
641                                   const gchar *sender,
642                                   const gchar *object,
643                                   const gchar *interface,
644                                   const gchar *method,
645                                   GVariant *parameters,
646                                   dleyna_connector_msg_id_t invocation)
647 {
648         dlr_task_t *task;
649         const gchar *device_id;
650         GError *error = NULL;
651
652         device_id = prv_get_device_id(object, &error);
653         if (!device_id) {
654                 g_context.connector->return_error(invocation, error);
655                 g_error_free(error);
656
657                 goto finished;
658         }
659
660         if (!strcmp(method, DLR_INTERFACE_GET_ALL))
661                 task = dlr_task_get_props_new(invocation, object, parameters);
662         else if (!strcmp(method, DLR_INTERFACE_GET))
663                 task = dlr_task_get_prop_new(invocation, object, parameters);
664         else if (!strcmp(method, DLR_INTERFACE_SET))
665                 task = dlr_task_set_prop_new(invocation, object, parameters);
666         else
667                 goto finished;
668
669         prv_add_task(task, sender, device_id);
670
671 finished:
672
673         return;
674 }
675
676 static void prv_dlr_device_method_call(dleyna_connector_id_t conn,
677                                        const gchar *sender,
678                                        const gchar *object,
679                                        const gchar *interface,
680                                        const gchar *method,
681                                        GVariant *parameters,
682                                        dleyna_connector_msg_id_t invocation)
683 {
684         dlr_task_t *task;
685         const gchar *device_id;
686         GError *error = NULL;
687
688         device_id = prv_get_device_id(object, &error);
689         if (!device_id) {
690                 g_context.connector->return_error(invocation, error);
691                 g_error_free(error);
692
693                 goto finished;
694         }
695
696         if (!strcmp(method, DLR_INTERFACE_RAISE))
697                 task = dlr_task_raise_new(invocation);
698         else if (!strcmp(method, DLR_INTERFACE_QUIT))
699                 task = dlr_task_quit_new(invocation);
700         else
701                 goto finished;
702
703         prv_add_task(task, sender, device_id);
704
705 finished:
706
707         return;
708 }
709
710 static void prv_dlr_player_method_call(dleyna_connector_id_t conn,
711                                        const gchar *sender,
712                                        const gchar *object,
713                                        const gchar *interface,
714                                        const gchar *method,
715                                        GVariant *parameters,
716                                        dleyna_connector_msg_id_t invocation)
717 {
718         dlr_task_t *task;
719         const gchar *device_id;
720         GError *error = NULL;
721
722         device_id = prv_get_device_id(object, &error);
723         if (!device_id) {
724                 g_context.connector->return_error(invocation, error);
725                 g_error_free(error);
726
727                 goto finished;
728         }
729
730         if (!strcmp(method, DLR_INTERFACE_PLAY))
731                 task = dlr_task_play_new(invocation, object);
732         else if (!strcmp(method, DLR_INTERFACE_PAUSE))
733                 task = dlr_task_pause_new(invocation, object);
734         else if (!strcmp(method, DLR_INTERFACE_PLAY_PAUSE))
735                 task = dlr_task_play_pause_new(invocation, object);
736         else if (!strcmp(method, DLR_INTERFACE_STOP))
737                 task = dlr_task_stop_new(invocation, object);
738         else if (!strcmp(method, DLR_INTERFACE_NEXT))
739                 task = dlr_task_next_new(invocation, object);
740         else if (!strcmp(method, DLR_INTERFACE_PREVIOUS))
741                 task = dlr_task_previous_new(invocation, object);
742         else if (!strcmp(method, DLR_INTERFACE_OPEN_URI))
743                 task = dlr_task_open_uri_new(invocation, object, parameters);
744         else if (!strcmp(method, DLR_INTERFACE_SEEK))
745                 task = dlr_task_seek_new(invocation, object, parameters);
746         else if (!strcmp(method, DLR_INTERFACE_SET_POSITION))
747                 task = dlr_task_set_position_new(invocation, object,
748                                                  parameters);
749         else if (!strcmp(method, DLR_INTERFACE_GOTO_TRACK))
750                 task = dlr_task_goto_track_new(invocation, object, parameters);
751         else
752                 goto finished;
753
754         prv_add_task(task, sender, device_id);
755
756 finished:
757
758         return;
759 }
760
761 static void prv_dlr_push_host_method_call(dleyna_connector_id_t conn,
762                                           const gchar *sender,
763                                           const gchar *object,
764                                           const gchar *interface,
765                                           const gchar *method,
766                                           GVariant *parameters,
767                                           dleyna_connector_msg_id_t invocation)
768 {
769         dlr_task_t *task;
770         const gchar *device_id;
771         GError *error = NULL;
772
773         device_id = prv_get_device_id(object, &error);
774         if (!device_id) {
775                 g_context.connector->return_error(invocation, error);
776                 g_error_free(error);
777
778                 goto on_error;
779         }
780
781         if (!strcmp(method, DLR_INTERFACE_HOST_FILE))
782                 task = dlr_task_host_uri_new(invocation, object, sender,
783                                              parameters);
784         else if (!strcmp(method, DLR_INTERFACE_REMOVE_FILE))
785                 task = dlr_task_remove_uri_new(invocation, object, sender,
786                                                parameters);
787         else
788                 goto on_error;
789
790         prv_add_task(task, sender, device_id);
791
792 on_error:
793
794         return;
795 }
796
797 static void prv_renderer_device_method_call(
798                                         dleyna_connector_id_t conn,
799                                         const gchar *sender,
800                                         const gchar *object,
801                                         const gchar *interface,
802                                         const gchar *method,
803                                         GVariant *parameters,
804                                         dleyna_connector_msg_id_t invocation)
805 {
806         const gchar *device_id = NULL;
807         GError *error = NULL;
808         const dleyna_task_queue_key_t *queue_id;
809
810         device_id = prv_get_device_id(object, &error);
811         if (!device_id) {
812                 g_context.connector->return_error(invocation, error);
813                 g_error_free(error);
814
815                 goto finished;
816         }
817
818         if (!strcmp(method, DLR_INTERFACE_CANCEL)) {
819                 queue_id = dleyna_task_processor_lookup_queue(
820                                                         g_context.processor,
821                                                         sender, device_id);
822                 if (queue_id)
823                         dleyna_task_processor_cancel_queue(queue_id);
824
825                 g_context.connector->return_response(invocation, NULL);
826         }
827
828 finished:
829
830                 return;
831 }
832
833 static void prv_found_media_server(const gchar *path)
834 {
835         DLEYNA_LOG_INFO("New media server %s", path);
836
837         (void) g_context.connector->notify(g_context.connection,
838                                            DLEYNA_SERVER_OBJECT,
839                                            DLEYNA_SERVER_INTERFACE_MANAGER,
840                                            DLR_INTERFACE_FOUND_SERVER,
841                                            g_variant_new("(s)", path),
842                                            NULL);
843 }
844
845 static void prv_lost_media_server(const gchar *path)
846 {
847         DLEYNA_LOG_INFO("Lost %s", path);
848
849         (void) g_context.connector->notify(g_context.connection,
850                                            DLEYNA_SERVER_OBJECT,
851                                            DLEYNA_SERVER_INTERFACE_MANAGER,
852                                            DLR_INTERFACE_LOST_SERVER,
853                                            g_variant_new("(s)", path),
854                                            NULL);
855
856         dleyna_task_processor_remove_queues_for_sink(g_context.processor, path);
857 }
858
859 static gboolean prv_control_point_start_service(
860                                         dleyna_connector_id_t connection)
861 {
862         gboolean retval = TRUE;
863
864         g_context.connection = connection;
865
866         g_context.dlr_id = g_context.connector->publish_object(
867                                                         connection,
868                                                         DLEYNA_SERVER_OBJECT,
869                                                         TRUE,
870                                                         0,
871                                                         g_root_vtables);
872
873         if (!g_context.dlr_id) {
874                 retval = FALSE;
875                 goto out;
876         } else {
877                 g_context.upnp = dlr_upnp_new(connection,
878                                              g_server_vtables,
879                                              prv_found_media_server,
880                                              prv_lost_media_server);
881         }
882
883 out:
884
885         return retval;
886 }
887
888 static const gchar *prv_control_point_server_name(void)
889 {
890         return DLEYNA_SERVER_NAME;
891 }
892
893 static const gchar *prv_control_point_server_introspection(void)
894 {
895         return g_server_introspection;
896 }
897
898 static const gchar *prv_control_point_root_introspection(void)
899 {
900         return g_root_introspection;
901 }
902
903 static const dleyna_control_point_t g_control_point = {
904         prv_control_point_initialize,
905         prv_control_point_free,
906         prv_control_point_server_name,
907         prv_control_point_server_introspection,
908         prv_control_point_root_introspection,
909         prv_control_point_start_service,
910         prv_control_point_stop_service
911 };
912
913 const dleyna_control_point_t *dleyna_control_point_get_renderer(void)
914 {
915         return &g_control_point;
916 }
917