]> git.sesse.net Git - vlc/blob - modules/control/dbus/dbus_player.c
dbus: Fix code style and add missing decref on error path
[vlc] / modules / control / dbus / dbus_player.c
1 /*****************************************************************************
2  * dbus_player.c : dbus control module (mpris v1.0) - /Player object
3  *****************************************************************************
4  * Copyright © 2006-2011 Rafaël Carré
5  * Copyright © 2007-2011 Mirsal Ennaime
6  * Copyright © 2009-2011 The VideoLAN team
7  * Copyright © 2013      Alex Merry
8  * $Id$
9  *
10  * Authors:    Mirsal Ennaime <mirsal at mirsal fr>
11  *             Rafaël Carré <funman at videolanorg>
12  *             Alex Merry <dev at randomguy3 me uk>
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc_common.h>
34 #include <vlc_playlist.h>
35 #include <vlc_interface.h>
36
37 #include <math.h>
38
39 #include "dbus_player.h"
40 #include "dbus_common.h"
41
42 static void MarshalLoopStatus ( intf_thread_t *, DBusMessageIter * );
43
44 DBUS_METHOD( Position )
45 { /* returns position in microseconds */
46     REPLY_INIT;
47     OUT_ARGUMENTS;
48     DBusMessageIter v;
49     dbus_int64_t i_pos;
50
51     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "x", &v ) )
52         return DBUS_HANDLER_RESULT_NEED_MEMORY;
53
54     input_thread_t *p_input = playlist_CurrentInput( PL );
55
56     if( !p_input )
57         i_pos = 0;
58
59     else
60     {
61         i_pos = var_GetTime( p_input, "time" );
62         vlc_object_release( p_input );
63     }
64
65     if( !dbus_message_iter_append_basic( &v, DBUS_TYPE_INT64, &i_pos ) )
66         return DBUS_HANDLER_RESULT_NEED_MEMORY;
67
68     if( !dbus_message_iter_close_container( &args, &v ) )
69         return DBUS_HANDLER_RESULT_NEED_MEMORY;
70
71     REPLY_SEND;
72 }
73
74 DBUS_METHOD( SetPosition )
75 { /* set position in microseconds */
76
77     REPLY_INIT;
78     dbus_int64_t i_pos;
79     vlc_value_t position;
80     char *psz_trackid, *psz_dbus_trackid;
81     input_item_t *p_item;
82
83     DBusError error;
84     dbus_error_init( &error );
85
86     dbus_message_get_args( p_from, &error,
87             DBUS_TYPE_OBJECT_PATH, &psz_dbus_trackid,
88             DBUS_TYPE_INT64, &i_pos,
89             DBUS_TYPE_INVALID );
90
91     if( dbus_error_is_set( &error ) )
92     {
93         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
94                 error.message );
95         dbus_error_free( &error );
96         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
97     }
98
99     input_thread_t *p_input = playlist_CurrentInput( PL );
100
101     if( p_input )
102     {
103         if( ( p_item = input_GetItem( p_input ) ) )
104         {
105             if( -1 == asprintf( &psz_trackid,
106                                 MPRIS_TRACKID_FORMAT,
107                                 p_item->i_id ) )
108             {
109                 vlc_object_release( p_input );
110                 return DBUS_HANDLER_RESULT_NEED_MEMORY;
111             }
112
113             if( !strcmp( psz_trackid, psz_dbus_trackid ) )
114             {
115                 position.i_time = (mtime_t) i_pos;
116                 var_Set( p_input, "time", position );
117             }
118             free( psz_trackid );
119         }
120
121         vlc_object_release( p_input );
122     }
123
124
125     REPLY_SEND;
126 }
127
128 DBUS_METHOD( Seek )
129 {
130     REPLY_INIT;
131     dbus_int64_t i_step;
132     vlc_value_t  newpos;
133     mtime_t      i_pos;
134
135     DBusError error;
136     dbus_error_init( &error );
137
138     dbus_message_get_args( p_from, &error,
139             DBUS_TYPE_INT64, &i_step,
140             DBUS_TYPE_INVALID );
141
142     if( dbus_error_is_set( &error ) )
143     {
144         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
145                 error.message );
146         dbus_error_free( &error );
147         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
148     }
149
150     input_thread_t *p_input = playlist_CurrentInput( PL );
151     if( p_input && var_GetBool( p_input, "can-seek" ) )
152     {
153         i_pos = var_GetTime( p_input, "time" );
154         newpos.i_time = (mtime_t) i_step + i_pos;
155
156         if( newpos.i_time < 0 )
157             newpos.i_time = 0;
158
159         var_Set( p_input, "time", newpos );
160     }
161
162     if( p_input )
163         vlc_object_release( p_input );
164
165     REPLY_SEND;
166 }
167
168 static void
169 MarshalVolume( intf_thread_t *p_intf, DBusMessageIter *container )
170 {
171     float f_vol = playlist_VolumeGet( p_intf->p_sys->p_playlist );
172     if( f_vol < 0.f )
173         f_vol = 1.f; /* ? */
174
175     double d_vol = f_vol;
176     dbus_message_iter_append_basic( container, DBUS_TYPE_DOUBLE, &d_vol );
177 }
178
179 DBUS_METHOD( VolumeGet )
180 {
181     REPLY_INIT;
182     OUT_ARGUMENTS;
183
184     DBusMessageIter v;
185
186     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "d", &v ) )
187         return DBUS_HANDLER_RESULT_NEED_MEMORY;
188
189     MarshalVolume( p_this, &v );
190
191     if( !dbus_message_iter_close_container( &args, &v ) )
192         return DBUS_HANDLER_RESULT_NEED_MEMORY;
193
194     REPLY_SEND;
195 }
196
197 DBUS_METHOD( VolumeSet )
198 {
199     REPLY_INIT;
200     double d_dbus_vol;
201
202     if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &d_dbus_vol ) )
203         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
204
205     d_dbus_vol *= AOUT_VOLUME_DEFAULT;
206     if( d_dbus_vol < 0. )
207         d_dbus_vol = 0.;
208     playlist_VolumeSet( PL, d_dbus_vol );
209
210     REPLY_SEND;
211 }
212
213 DBUS_METHOD( Next )
214 { /* next playlist item */
215     REPLY_INIT;
216     playlist_Next( PL );
217     REPLY_SEND;
218 }
219
220 DBUS_METHOD( Prev )
221 { /* previous playlist item */
222     REPLY_INIT;
223     playlist_Prev( PL );
224     REPLY_SEND;
225 }
226
227 DBUS_METHOD( Stop )
228 { /* stop playing */
229     REPLY_INIT;
230     playlist_Stop( PL );
231     REPLY_SEND;
232 }
233
234 DBUS_METHOD( Play )
235 {
236     REPLY_INIT;
237     input_thread_t *p_input =  playlist_CurrentInput( PL );
238
239     if( !p_input || var_GetInteger( p_input, "state" ) != PLAYING_S )
240         playlist_Play( PL );
241
242     if( p_input )
243         vlc_object_release( p_input );
244
245     REPLY_SEND;
246 }
247
248 DBUS_METHOD( Pause )
249 {
250     REPLY_INIT;
251     input_thread_t *p_input = playlist_CurrentInput( PL );
252
253     if( p_input && var_GetInteger(p_input, "state") == PLAYING_S )
254         playlist_Pause( PL );
255
256     if( p_input )
257         vlc_object_release( p_input );
258
259     REPLY_SEND;
260 }
261
262 DBUS_METHOD( PlayPause )
263 {
264     REPLY_INIT;
265     input_thread_t *p_input = playlist_CurrentInput( PL );
266
267     if( p_input && var_GetInteger(p_input, "state") == PLAYING_S )
268         playlist_Pause( PL );
269     else
270         playlist_Play( PL );
271
272     if( p_input )
273         vlc_object_release( p_input );
274
275     REPLY_SEND;
276 }
277
278 DBUS_METHOD( OpenUri )
279 {
280     REPLY_INIT;
281
282     char *psz_mrl;
283     DBusError error;
284     dbus_error_init( &error );
285
286     dbus_message_get_args( p_from, &error,
287             DBUS_TYPE_STRING, &psz_mrl,
288             DBUS_TYPE_INVALID );
289
290     if( dbus_error_is_set( &error ) )
291     {
292         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
293                 error.message );
294         dbus_error_free( &error );
295         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
296     }
297
298     playlist_Add( PL, psz_mrl, NULL,
299                   PLAYLIST_APPEND | PLAYLIST_GO,
300                   PLAYLIST_END, true, false );
301
302     REPLY_SEND;
303 }
304
305 static void
306 MarshalCanPlay( intf_thread_t *p_intf, DBusMessageIter *container )
307 {
308     playlist_t *p_playlist = p_intf->p_sys->p_playlist;
309
310     PL_LOCK;
311     dbus_bool_t b_can_play = playlist_CurrentSize( p_playlist ) > 0;
312     PL_UNLOCK;
313
314     dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN, &b_can_play );
315 }
316
317 DBUS_METHOD( CanPlay )
318 {
319     REPLY_INIT;
320     OUT_ARGUMENTS;
321
322     DBusMessageIter v;
323
324     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "b", &v ) )
325         return DBUS_HANDLER_RESULT_NEED_MEMORY;
326
327     MarshalCanPlay( p_this, &v );
328
329     if( !dbus_message_iter_close_container( &args, &v ) )
330         return DBUS_HANDLER_RESULT_NEED_MEMORY;
331
332     REPLY_SEND;
333 }
334
335 static void
336 MarshalCanPause( intf_thread_t *p_intf, DBusMessageIter *container )
337 {
338     dbus_bool_t b_can_pause = FALSE;
339     input_thread_t *p_input;
340     p_input = playlist_CurrentInput( p_intf->p_sys->p_playlist );
341
342     if( p_input )
343     {
344         b_can_pause = var_GetBool( p_input, "can-pause" );
345         vlc_object_release( p_input );
346     }
347
348     dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
349                                     &b_can_pause );
350 }
351
352 DBUS_METHOD( CanPause )
353 {
354     REPLY_INIT;
355     OUT_ARGUMENTS;
356
357     DBusMessageIter v;
358
359     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "b", &v ) )
360         return DBUS_HANDLER_RESULT_NEED_MEMORY;
361
362     MarshalCanPause( p_this, &v );
363
364     if( !dbus_message_iter_close_container( &args, &v ) )
365         return DBUS_HANDLER_RESULT_NEED_MEMORY;
366
367     REPLY_SEND;
368 }
369
370 DBUS_METHOD( CanControl )
371 {
372     VLC_UNUSED( p_this );
373
374     REPLY_INIT;
375     OUT_ARGUMENTS;
376
377     DBusMessageIter v;
378     dbus_bool_t b_can_control = TRUE;
379
380     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT,
381                                            "b", &v ) )
382         return DBUS_HANDLER_RESULT_NEED_MEMORY;
383
384     if( !dbus_message_iter_append_basic( &v, DBUS_TYPE_BOOLEAN,
385                                          &b_can_control ) )
386         return DBUS_HANDLER_RESULT_NEED_MEMORY;
387
388     if( !dbus_message_iter_close_container( &args, &v ) )
389         return DBUS_HANDLER_RESULT_NEED_MEMORY;
390
391     REPLY_SEND;
392 }
393
394 static void
395 MarshalCanSeek( intf_thread_t *p_intf, DBusMessageIter *container )
396 {
397     dbus_bool_t b_can_seek = FALSE;
398     input_thread_t *p_input;
399     p_input = playlist_CurrentInput( p_intf->p_sys->p_playlist );
400
401     if( p_input )
402     {
403         b_can_seek = var_GetBool( p_input, "can-seek" );
404         vlc_object_release( p_input );
405     }
406
407     dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN, &b_can_seek );
408 }
409
410 DBUS_METHOD( CanSeek )
411 {
412     REPLY_INIT;
413     OUT_ARGUMENTS;
414
415     DBusMessageIter v;
416
417     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "b", &v ) )
418         return DBUS_HANDLER_RESULT_NEED_MEMORY;
419
420     MarshalCanSeek( p_this, &v );
421
422     if( !dbus_message_iter_close_container( &args, &v ) )
423         return DBUS_HANDLER_RESULT_NEED_MEMORY;
424
425     REPLY_SEND;
426 }
427
428 static void
429 MarshalShuffle( intf_thread_t *p_intf, DBusMessageIter *container )
430 {
431     dbus_bool_t b_shuffle = var_GetBool( p_intf->p_sys->p_playlist, "random" );
432     dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN, &b_shuffle );
433 }
434
435 DBUS_METHOD( ShuffleGet )
436 {
437     REPLY_INIT;
438     OUT_ARGUMENTS;
439
440     DBusMessageIter v;
441
442     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "b", &v ) )
443         return DBUS_HANDLER_RESULT_NEED_MEMORY;
444
445     MarshalShuffle( p_this, &v );
446
447     if( !dbus_message_iter_close_container( &args, &v ) )
448         return DBUS_HANDLER_RESULT_NEED_MEMORY;
449
450     REPLY_SEND;
451 }
452
453 DBUS_METHOD( ShuffleSet )
454 {
455     REPLY_INIT;
456     dbus_bool_t b_shuffle;
457
458     if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &b_shuffle ) )
459         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
460
461     var_SetBool( PL, "random", ( b_shuffle == TRUE ) );
462
463     REPLY_SEND;
464 }
465
466 static void
467 MarshalPlaybackStatus( intf_thread_t *p_intf, DBusMessageIter *container )
468 {
469     input_thread_t *p_input;
470     const char *psz_playback_status;
471
472     if( ( p_input = playlist_CurrentInput( p_intf->p_sys->p_playlist ) ) )
473     {
474         switch( var_GetInteger( p_input, "state" ) )
475         {
476             case OPENING_S:
477             case PLAYING_S:
478                 psz_playback_status = PLAYBACK_STATUS_PLAYING;
479                 break;
480             case PAUSE_S:
481                 psz_playback_status = PLAYBACK_STATUS_PAUSED;
482                 break;
483             default:
484                 psz_playback_status = PLAYBACK_STATUS_STOPPED;
485         }
486
487         vlc_object_release( (vlc_object_t*) p_input );
488     }
489     else
490         psz_playback_status = PLAYBACK_STATUS_STOPPED;
491
492     dbus_message_iter_append_basic( container, DBUS_TYPE_STRING,
493                                     &psz_playback_status );
494 }
495
496 DBUS_METHOD( PlaybackStatus )
497 {
498     REPLY_INIT;
499     OUT_ARGUMENTS;
500
501     DBusMessageIter v;
502
503     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "s", &v ) )
504         return DBUS_HANDLER_RESULT_NEED_MEMORY;
505
506     MarshalPlaybackStatus( p_this, &v );
507
508     if( !dbus_message_iter_close_container( &args, &v ) )
509         return DBUS_HANDLER_RESULT_NEED_MEMORY;
510
511     REPLY_SEND;
512 }
513
514 static void
515 MarshalRate( intf_thread_t *p_intf, DBusMessageIter *container )
516 {
517     double d_rate;
518     input_thread_t *p_input;
519     if( ( p_input = playlist_CurrentInput( p_intf->p_sys->p_playlist ) ) )
520     {
521         d_rate = var_GetFloat( p_input, "rate" );
522         vlc_object_release( (vlc_object_t*) p_input );
523     }
524     else
525         d_rate = 1.0;
526
527     dbus_message_iter_append_basic( container, DBUS_TYPE_DOUBLE, &d_rate );
528 }
529
530 DBUS_METHOD( RateGet )
531 {
532     REPLY_INIT;
533     OUT_ARGUMENTS;
534
535     DBusMessageIter v;
536
537     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "d", &v ) )
538         return DBUS_HANDLER_RESULT_NEED_MEMORY;
539
540     MarshalRate( p_this, &v );
541
542     if( !dbus_message_iter_close_container( &args, &v ) )
543         return DBUS_HANDLER_RESULT_NEED_MEMORY;
544
545     REPLY_SEND;
546 }
547
548 DBUS_METHOD( RateSet )
549 {
550     REPLY_INIT;
551
552     double d_rate;
553
554     if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &d_rate ) )
555         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
556
557     input_thread_t *p_input;
558     if( ( p_input = playlist_CurrentInput( PL ) ) )
559     {
560         var_SetFloat( p_input, "rate", (float) d_rate );
561         vlc_object_release( (vlc_object_t*) p_input );
562     }
563     else
564         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
565
566     REPLY_SEND;
567 }
568
569 DBUS_METHOD( MinimumRate )
570 {
571     VLC_UNUSED( p_this );
572
573     REPLY_INIT;
574     OUT_ARGUMENTS;
575
576     DBusMessageIter v;
577     double d_min_rate = (double) INPUT_RATE_MIN / INPUT_RATE_DEFAULT;
578
579     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "d", &v ) )
580         return DBUS_HANDLER_RESULT_NEED_MEMORY;
581
582     if( !dbus_message_iter_append_basic( &v, DBUS_TYPE_DOUBLE, &d_min_rate ) )
583         return DBUS_HANDLER_RESULT_NEED_MEMORY;
584
585     if( !dbus_message_iter_close_container( &args, &v ) )
586         return DBUS_HANDLER_RESULT_NEED_MEMORY;
587
588     REPLY_SEND;
589 }
590
591 DBUS_METHOD( MaximumRate )
592 {
593     VLC_UNUSED( p_this );
594
595     REPLY_INIT;
596     OUT_ARGUMENTS;
597
598     DBusMessageIter v;
599     double d_max_rate = (double) INPUT_RATE_MAX / INPUT_RATE_DEFAULT;
600
601     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "d", &v ) )
602         return DBUS_HANDLER_RESULT_NEED_MEMORY;
603
604     if( !dbus_message_iter_append_basic( &v, DBUS_TYPE_DOUBLE, &d_max_rate ) )
605         return DBUS_HANDLER_RESULT_NEED_MEMORY;
606
607     if( !dbus_message_iter_close_container( &args, &v ) )
608         return DBUS_HANDLER_RESULT_NEED_MEMORY;
609
610     REPLY_SEND;
611 }
612
613 static void
614 MarshalLoopStatus( intf_thread_t *p_intf, DBusMessageIter *container )
615 {
616     const char *psz_loop_status;
617
618     if( var_GetBool( p_intf->p_sys->p_playlist, "repeat" ) )
619         psz_loop_status = LOOP_STATUS_TRACK;
620
621     else if( var_GetBool( p_intf->p_sys->p_playlist, "loop" ) )
622         psz_loop_status = LOOP_STATUS_PLAYLIST;
623
624     else
625         psz_loop_status = LOOP_STATUS_NONE;
626
627     dbus_message_iter_append_basic( container, DBUS_TYPE_STRING,
628                                     &psz_loop_status );
629 }
630
631 DBUS_METHOD( LoopStatusGet )
632 {
633     REPLY_INIT;
634     OUT_ARGUMENTS;
635
636     DBusMessageIter v;
637
638     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "s", &v ) )
639         return DBUS_HANDLER_RESULT_NEED_MEMORY;
640
641     MarshalLoopStatus( p_this, &v );
642
643     if( !dbus_message_iter_close_container( &args, &v ) )
644         return DBUS_HANDLER_RESULT_NEED_MEMORY;
645
646     REPLY_SEND;
647 }
648
649 DBUS_METHOD( LoopStatusSet )
650 {
651     REPLY_INIT;
652     char *psz_loop_status;
653
654     if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &psz_loop_status ) )
655         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
656
657     if( !strcmp( psz_loop_status, LOOP_STATUS_NONE ) )
658     {
659         var_SetBool( PL, "loop",   FALSE );
660         var_SetBool( PL, "repeat", FALSE );
661     }
662     else if( !strcmp( psz_loop_status, LOOP_STATUS_TRACK ) )
663     {
664         var_SetBool( PL, "loop",   FALSE );
665         var_SetBool( PL, "repeat", TRUE  );
666     }
667     else if( !strcmp( psz_loop_status, LOOP_STATUS_PLAYLIST ) )
668     {
669         var_SetBool( PL, "loop",   TRUE );
670         var_SetBool( PL, "repeat", FALSE  );
671     }
672     else
673         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
674
675     REPLY_SEND;
676 }
677
678 static int
679 MarshalMetadata( intf_thread_t *p_intf, DBusMessageIter *container )
680 {
681     DBusMessageIter a;
682     input_thread_t *p_input = NULL;
683     input_item_t   *p_item  = NULL;
684
685     if( ( p_input = playlist_CurrentInput( p_intf->p_sys->p_playlist ) ) )
686     {
687         p_item = input_GetItem( p_input );
688
689         if( p_item )
690         {
691             int result = GetInputMeta( p_item, container );
692
693             if (result != VLC_SUCCESS)
694             {
695                 vlc_object_release( (vlc_object_t*) p_input );
696                 return result;
697             }
698         }
699
700         vlc_object_release( (vlc_object_t*) p_input );
701     }
702
703     if (!p_item)
704     {
705         // avoid breaking the type marshalling
706         if( !dbus_message_iter_open_container( container, DBUS_TYPE_ARRAY, "{sv}", &a ) ||
707               !dbus_message_iter_close_container( container, &a ) )
708             return VLC_ENOMEM;
709     }
710
711     return VLC_SUCCESS;
712 }
713
714 DBUS_METHOD( Metadata )
715 {
716     REPLY_INIT;
717     OUT_ARGUMENTS;
718
719     DBusMessageIter v;
720
721     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT,
722                                            "a{sv}", &v ) )
723         return DBUS_HANDLER_RESULT_NEED_MEMORY;
724
725     if( MarshalMetadata( p_this, &v ) != VLC_SUCCESS ||
726         !dbus_message_iter_close_container( &args, &v ) ) {
727         return DBUS_HANDLER_RESULT_NEED_MEMORY;
728     }
729
730     REPLY_SEND;
731 }
732
733 /******************************************************************************
734  * Seeked: non-linear playback signal
735  *****************************************************************************/
736 DBUS_SIGNAL( SeekedSignal )
737 {
738     SIGNAL_INIT( DBUS_MPRIS_PLAYER_INTERFACE,
739                  DBUS_MPRIS_OBJECT_PATH,
740                  "Seeked" );
741
742     OUT_ARGUMENTS;
743
744     dbus_int64_t i_pos = 0;
745     intf_thread_t *p_intf = (intf_thread_t*) p_data;
746     input_thread_t *p_input = playlist_CurrentInput( p_intf->p_sys->p_playlist );
747
748     if( p_input )
749     {
750         i_pos = var_GetTime( p_input, "time" );
751         vlc_object_release( p_input );
752     }
753
754     ADD_INT64( &i_pos );
755     SIGNAL_SEND;
756 }
757
758 #define PROPERTY_MAPPING_BEGIN if( 0 ) {}
759 #define PROPERTY_FUNC( interface, property, function ) \
760     else if( !strcmp( psz_interface_name, interface ) && \
761              !strcmp( psz_property_name,  property ) ) \
762         return function( p_conn, p_from, p_this );
763 #define PROPERTY_MAPPING_END return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
764
765 DBUS_METHOD( GetProperty )
766 {
767     DBusError error;
768
769     char *psz_interface_name = NULL;
770     char *psz_property_name  = NULL;
771
772     dbus_error_init( &error );
773     dbus_message_get_args( p_from, &error,
774             DBUS_TYPE_STRING, &psz_interface_name,
775             DBUS_TYPE_STRING, &psz_property_name,
776             DBUS_TYPE_INVALID );
777
778     if( dbus_error_is_set( &error ) )
779     {
780         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
781                                          error.message );
782         dbus_error_free( &error );
783         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
784     }
785
786     msg_Dbg( (vlc_object_t*) p_this, "Getting property %s",
787                                      psz_property_name );
788
789     PROPERTY_MAPPING_BEGIN
790     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Metadata", Metadata )
791     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Position", Position )
792     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "PlaybackStatus", PlaybackStatus )
793     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "LoopStatus", LoopStatusGet )
794     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Shuffle", ShuffleGet )
795     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Volume", VolumeGet )
796     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Rate", RateGet )
797     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "MinimumRate", MinimumRate )
798     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "MaximumRate", MaximumRate )
799     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "CanControl", CanControl )
800     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "CanPlay", CanPlay )
801     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "CanPause", CanPause )
802     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "CanSeek", CanSeek )
803     PROPERTY_MAPPING_END
804 }
805
806 DBUS_METHOD( SetProperty )
807 {
808     DBusError error;
809
810     char *psz_interface_name = NULL;
811     char *psz_property_name  = NULL;
812
813     dbus_error_init( &error );
814     dbus_message_get_args( p_from, &error,
815             DBUS_TYPE_STRING, &psz_interface_name,
816             DBUS_TYPE_STRING, &psz_property_name,
817             DBUS_TYPE_INVALID );
818
819     if( dbus_error_is_set( &error ) )
820     {
821         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
822                                          error.message );
823         dbus_error_free( &error );
824         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
825     }
826
827     PROPERTY_MAPPING_BEGIN
828     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "LoopStatus", LoopStatusSet )
829     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Shuffle",    ShuffleSet )
830     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Volume",     VolumeSet )
831     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Rate",       RateSet )
832     PROPERTY_MAPPING_END
833 }
834
835 #undef PROPERTY_MAPPING_BEGIN
836 #undef PROPERTY_GET_FUNC
837 #undef PROPERTY_MAPPING_END
838
839 #define METHOD_FUNC( interface, method, function ) \
840     else if( dbus_message_is_method_call( p_from, interface, method ) )\
841         return function( p_conn, p_from, p_this )
842
843 DBusHandlerResult
844 handle_player ( DBusConnection *p_conn, DBusMessage *p_from, void *p_this )
845 {
846     if(0);
847     METHOD_FUNC( DBUS_INTERFACE_PROPERTIES,   "Get",        GetProperty );
848     METHOD_FUNC( DBUS_INTERFACE_PROPERTIES,   "Set",        SetProperty );
849 /*  METHOD_FUNC( DBUS_INTERFACE_PROPERTIES,   "GetAll",     GetAllProperties );*/
850
851     /* here D-Bus method names are associated to an handler */
852
853     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Previous",     Prev );
854     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Next",         Next );
855     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Stop",         Stop );
856     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Seek",         Seek );
857     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Play",         Play );
858     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Pause",        Pause );
859     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "PlayPause",    PlayPause );
860     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "OpenUri",      OpenUri );
861     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "SetPosition",  SetPosition );
862
863     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
864 }
865
866 #undef METHOD_FUNC
867
868 /*****************************************************************************
869  * SeekedEmit: Emits the Seeked signal
870  *****************************************************************************/
871 int SeekedEmit( intf_thread_t * p_intf )
872 {
873     if( p_intf->p_sys->b_dead )
874         return VLC_SUCCESS;
875
876     SeekedSignal( p_intf->p_sys->p_conn, p_intf );
877     return VLC_SUCCESS;
878 }
879
880 /**
881  * PropertiesChangedSignal() synthetizes and sends the
882  * org.freedesktop.DBus.Properties.PropertiesChanged signal
883  */
884 static DBusHandlerResult
885 PropertiesChangedSignal( intf_thread_t    *p_intf,
886                          vlc_dictionary_t *p_changed_properties )
887 {
888     DBusConnection  *p_conn = p_intf->p_sys->p_conn;
889     DBusMessageIter changed_properties, invalidated_properties, entry, variant;
890     const char *psz_interface_name = DBUS_MPRIS_PLAYER_INTERFACE;
891     char **ppsz_properties = NULL;
892     int i_properties = 0;
893
894     SIGNAL_INIT( DBUS_INTERFACE_PROPERTIES,
895                  DBUS_MPRIS_OBJECT_PATH,
896                  "PropertiesChanged" );
897
898     OUT_ARGUMENTS;
899     ADD_STRING( &psz_interface_name );
900     dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "{sv}",
901                                       &changed_properties );
902
903     i_properties = vlc_dictionary_keys_count( p_changed_properties );
904     ppsz_properties = vlc_dictionary_all_keys( p_changed_properties );
905
906     for( int i = 0; i < i_properties; i++ )
907     {
908         dbus_message_iter_open_container( &changed_properties,
909                                           DBUS_TYPE_DICT_ENTRY, NULL,
910                                           &entry );
911
912         dbus_message_iter_append_basic( &entry, DBUS_TYPE_STRING,
913                                         &ppsz_properties[i] );
914
915         if( !strcmp( ppsz_properties[i], "Metadata" ) )
916         {
917             dbus_message_iter_open_container( &entry,
918                                               DBUS_TYPE_VARIANT, "a{sv}",
919                                               &variant );
920             MarshalMetadata( p_intf, &variant );
921             dbus_message_iter_close_container( &entry, &variant );
922         }
923         else if( !strcmp( ppsz_properties[i], "PlaybackStatus" ) )
924         {
925             dbus_message_iter_open_container( &entry,
926                                               DBUS_TYPE_VARIANT, "s",
927                                               &variant );
928             MarshalPlaybackStatus( p_intf, &variant );
929             dbus_message_iter_close_container( &entry, &variant );
930         }
931         else if( !strcmp( ppsz_properties[i], "LoopStatus" ) )
932         {
933             dbus_message_iter_open_container( &entry,
934                                               DBUS_TYPE_VARIANT, "s",
935                                               &variant );
936             MarshalLoopStatus( p_intf, &variant );
937             dbus_message_iter_close_container( &entry, &variant );
938         }
939         else if( !strcmp( ppsz_properties[i], "Rate" ) )
940         {
941             dbus_message_iter_open_container( &entry,
942                                               DBUS_TYPE_VARIANT, "d",
943                                               &variant );
944             MarshalRate( p_intf, &variant );
945             dbus_message_iter_close_container( &entry, &variant );
946         }
947         else if( !strcmp( ppsz_properties[i], "Shuffle" ) )
948         {
949             dbus_message_iter_open_container( &entry,
950                                               DBUS_TYPE_VARIANT, "b",
951                                               &variant );
952             MarshalShuffle( p_intf, &variant );
953             dbus_message_iter_close_container( &entry, &variant );
954         }
955         else if( !strcmp( ppsz_properties[i], "Volume" ) )
956         {
957             dbus_message_iter_open_container( &entry,
958                                               DBUS_TYPE_VARIANT, "d",
959                                               &variant );
960             MarshalVolume( p_intf, &variant );
961             dbus_message_iter_close_container( &entry, &variant );
962         }
963         else if( !strcmp( ppsz_properties[i], "CanSeek" ) )
964         {
965             dbus_message_iter_open_container( &entry,
966                                               DBUS_TYPE_VARIANT, "b",
967                                               &variant );
968             MarshalCanSeek( p_intf, &variant );
969             dbus_message_iter_close_container( &entry, &variant );
970         }
971         else if( !strcmp( ppsz_properties[i], "CanPlay" ) )
972         {
973             dbus_message_iter_open_container( &entry,
974                                               DBUS_TYPE_VARIANT, "b",
975                                               &variant );
976             MarshalCanPlay( p_intf, &variant );
977             dbus_message_iter_close_container( &entry, &variant );
978         }
979         else if( !strcmp( ppsz_properties[i], "CanPause" ) )
980         {
981             dbus_message_iter_open_container( &entry,
982                                               DBUS_TYPE_VARIANT, "b",
983                                               &variant );
984             MarshalCanPause( p_intf, &variant );
985             dbus_message_iter_close_container( &entry, &variant );
986         }
987         dbus_message_iter_close_container( &changed_properties, &entry );
988         free( ppsz_properties[i] );
989     }
990
991     dbus_message_iter_close_container( &args, &changed_properties );
992     dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "s",
993                                       &invalidated_properties );
994     dbus_message_iter_close_container( &args, &invalidated_properties );
995     free( ppsz_properties );
996
997     SIGNAL_SEND;
998 }
999
1000 /*****************************************************************************
1001  * PropertiesChangedEmit: Emits the Seeked signal
1002  *****************************************************************************/
1003 int PlayerPropertiesChangedEmit( intf_thread_t    * p_intf,
1004                                  vlc_dictionary_t * p_changed_properties )
1005 {
1006     if( p_intf->p_sys->b_dead )
1007         return VLC_SUCCESS;
1008
1009     PropertiesChangedSignal( p_intf, p_changed_properties );
1010     return VLC_SUCCESS;
1011 }