dbus: use pl_CurrentInput()
[vlc.git] / modules / control / dbus / dbus_player.c
1 /*****************************************************************************
2  * dbus_player.c : dbus control module (mpris v2.2) - 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 int
43 MarshalPosition( intf_thread_t *p_intf, DBusMessageIter *container )
44 {
45     /* returns position in microseconds */
46     dbus_int64_t i_pos;
47     input_thread_t *p_input = pl_CurrentInput( p_intf );
48
49     if( !p_input )
50         i_pos = 0;
51
52     else
53     {
54         i_pos = var_GetTime( p_input, "time" );
55         vlc_object_release( p_input );
56     }
57
58     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_INT64, &i_pos ) )
59         return VLC_ENOMEM;
60
61     return VLC_SUCCESS;
62 }
63
64 DBUS_METHOD( SetPosition )
65 { /* set position in microseconds */
66
67     REPLY_INIT;
68     dbus_int64_t i_pos;
69     vlc_value_t position;
70     char *psz_trackid, *psz_dbus_trackid;
71     input_item_t *p_item;
72
73     DBusError error;
74     dbus_error_init( &error );
75
76     dbus_message_get_args( p_from, &error,
77             DBUS_TYPE_OBJECT_PATH, &psz_dbus_trackid,
78             DBUS_TYPE_INT64, &i_pos,
79             DBUS_TYPE_INVALID );
80
81     if( dbus_error_is_set( &error ) )
82     {
83         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
84                 error.message );
85         dbus_error_free( &error );
86         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
87     }
88
89     input_thread_t *p_input = pl_CurrentInput( p_this );
90
91     if( p_input )
92     {
93         if( ( p_item = input_GetItem( p_input ) ) )
94         {
95             if( -1 == asprintf( &psz_trackid,
96                                 MPRIS_TRACKID_FORMAT,
97                                 p_item->i_id ) )
98             {
99                 vlc_object_release( p_input );
100                 return DBUS_HANDLER_RESULT_NEED_MEMORY;
101             }
102
103             if( !strcmp( psz_trackid, psz_dbus_trackid ) )
104             {
105                 position.i_time = (mtime_t) i_pos;
106                 var_Set( p_input, "time", position );
107             }
108             free( psz_trackid );
109         }
110
111         vlc_object_release( p_input );
112     }
113
114
115     REPLY_SEND;
116 }
117
118 DBUS_METHOD( Seek )
119 {
120     REPLY_INIT;
121     dbus_int64_t i_step;
122     vlc_value_t  newpos;
123     mtime_t      i_pos;
124
125     DBusError error;
126     dbus_error_init( &error );
127
128     dbus_message_get_args( p_from, &error,
129             DBUS_TYPE_INT64, &i_step,
130             DBUS_TYPE_INVALID );
131
132     if( dbus_error_is_set( &error ) )
133     {
134         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
135                 error.message );
136         dbus_error_free( &error );
137         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
138     }
139
140     input_thread_t *p_input = pl_CurrentInput( p_this );
141     if( p_input && var_GetBool( p_input, "can-seek" ) )
142     {
143         i_pos = var_GetTime( p_input, "time" );
144         newpos.i_time = (mtime_t) i_step + i_pos;
145
146         if( newpos.i_time < 0 )
147             newpos.i_time = 0;
148
149         var_Set( p_input, "time", newpos );
150     }
151
152     if( p_input )
153         vlc_object_release( p_input );
154
155     REPLY_SEND;
156 }
157
158 static int
159 MarshalVolume( intf_thread_t *p_intf, DBusMessageIter *container )
160 {
161     float f_vol = playlist_VolumeGet( p_intf->p_sys->p_playlist );
162     if( f_vol < 0.f )
163         f_vol = 1.f; /* ? */
164
165     double d_vol = f_vol;
166
167     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_DOUBLE, &d_vol ) )
168         return VLC_ENOMEM;
169
170     return VLC_SUCCESS;
171 }
172
173 DBUS_METHOD( VolumeSet )
174 {
175     REPLY_INIT;
176     double d_dbus_vol;
177
178     if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &d_dbus_vol ) )
179         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
180
181     playlist_VolumeSet( PL, fmaxf( d_dbus_vol, 0.f ) );
182
183     REPLY_SEND;
184 }
185
186 DBUS_METHOD( Next )
187 { /* next playlist item */
188     REPLY_INIT;
189     playlist_Next( PL );
190     REPLY_SEND;
191 }
192
193 DBUS_METHOD( Prev )
194 { /* previous playlist item */
195     REPLY_INIT;
196     playlist_Prev( PL );
197     REPLY_SEND;
198 }
199
200 DBUS_METHOD( Stop )
201 { /* stop playing */
202     REPLY_INIT;
203     playlist_Stop( PL );
204     REPLY_SEND;
205 }
206
207 DBUS_METHOD( Play )
208 {
209     REPLY_INIT;
210     input_thread_t *p_input =  pl_CurrentInput( p_this );
211
212     if( !p_input || var_GetInteger( p_input, "state" ) != PLAYING_S )
213         playlist_Play( PL );
214
215     if( p_input )
216         vlc_object_release( p_input );
217
218     REPLY_SEND;
219 }
220
221 DBUS_METHOD( Pause )
222 {
223     REPLY_INIT;
224     input_thread_t *p_input = pl_CurrentInput( p_this );
225
226     if( p_input && var_GetInteger(p_input, "state") == PLAYING_S )
227         playlist_Pause( PL );
228
229     if( p_input )
230         vlc_object_release( p_input );
231
232     REPLY_SEND;
233 }
234
235 DBUS_METHOD( PlayPause )
236 {
237     REPLY_INIT;
238     input_thread_t *p_input = pl_CurrentInput( p_this );
239
240     if( p_input && var_GetInteger(p_input, "state") == PLAYING_S )
241         playlist_Pause( PL );
242     else
243         playlist_Play( PL );
244
245     if( p_input )
246         vlc_object_release( p_input );
247
248     REPLY_SEND;
249 }
250
251 DBUS_METHOD( OpenUri )
252 {
253     REPLY_INIT;
254
255     char *psz_mrl;
256     DBusError error;
257     dbus_error_init( &error );
258
259     dbus_message_get_args( p_from, &error,
260             DBUS_TYPE_STRING, &psz_mrl,
261             DBUS_TYPE_INVALID );
262
263     if( dbus_error_is_set( &error ) )
264     {
265         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
266                 error.message );
267         dbus_error_free( &error );
268         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
269     }
270
271     playlist_Add( PL, psz_mrl, NULL,
272                   PLAYLIST_APPEND | PLAYLIST_GO,
273                   PLAYLIST_END, true, false );
274
275     REPLY_SEND;
276 }
277
278 static int
279 MarshalCanGoNext( intf_thread_t *p_intf, DBusMessageIter *container )
280 {
281     VLC_UNUSED( p_intf );
282
283     dbus_bool_t b_can_go_next = TRUE;
284
285     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
286                                          &b_can_go_next ) )
287         return VLC_ENOMEM;
288
289     return VLC_SUCCESS;
290 }
291
292 static int
293 MarshalCanGoPrevious( intf_thread_t *p_intf, DBusMessageIter *container )
294 {
295     VLC_UNUSED( p_intf );
296
297     dbus_bool_t b_can_go_previous = TRUE;
298
299     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
300                                          &b_can_go_previous ) )
301         return VLC_ENOMEM;
302
303     return VLC_SUCCESS;
304 }
305
306 static int
307 MarshalCanPlay( intf_thread_t *p_intf, DBusMessageIter *container )
308 {
309     playlist_t *p_playlist = p_intf->p_sys->p_playlist;
310
311     PL_LOCK;
312     dbus_bool_t b_can_play = playlist_CurrentSize( p_playlist ) > 0;
313     PL_UNLOCK;
314
315     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
316                                          &b_can_play ) )
317         return VLC_ENOMEM;
318
319     return VLC_SUCCESS;
320 }
321
322 static int
323 MarshalCanPause( intf_thread_t *p_intf, DBusMessageIter *container )
324 {
325     dbus_bool_t b_can_pause = FALSE;
326     input_thread_t *p_input = pl_CurrentInput( p_intf );
327
328     if( p_input )
329     {
330         b_can_pause = var_GetBool( p_input, "can-pause" );
331         vlc_object_release( p_input );
332     }
333
334     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
335                                          &b_can_pause ) )
336         return VLC_ENOMEM;
337
338     return VLC_SUCCESS;
339 }
340
341 static int
342 MarshalCanControl( intf_thread_t *p_intf, DBusMessageIter *container )
343 {
344     VLC_UNUSED( p_intf );
345     dbus_bool_t b_can_control = TRUE;
346
347     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
348                                          &b_can_control ) )
349         return VLC_ENOMEM;
350
351     return VLC_SUCCESS;
352 }
353
354 static int
355 MarshalCanSeek( intf_thread_t *p_intf, DBusMessageIter *container )
356 {
357     dbus_bool_t b_can_seek = FALSE;
358     input_thread_t *p_input = pl_CurrentInput( p_intf );
359
360     if( p_input )
361     {
362         b_can_seek = var_GetBool( p_input, "can-seek" );
363         vlc_object_release( p_input );
364     }
365
366     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
367                                          &b_can_seek ) )
368         return VLC_ENOMEM;
369
370     return VLC_SUCCESS;
371 }
372
373 static int
374 MarshalShuffle( intf_thread_t *p_intf, DBusMessageIter *container )
375 {
376     dbus_bool_t b_shuffle = var_GetBool( p_intf->p_sys->p_playlist, "random" );
377
378     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
379                                          &b_shuffle ))
380         return VLC_ENOMEM;
381
382     return VLC_SUCCESS;
383 }
384
385 DBUS_METHOD( ShuffleSet )
386 {
387     REPLY_INIT;
388     dbus_bool_t b_shuffle;
389
390     if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &b_shuffle ) )
391         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
392
393     var_SetBool( PL, "random", ( b_shuffle == TRUE ) );
394
395     REPLY_SEND;
396 }
397
398 static int
399 MarshalPlaybackStatus( intf_thread_t *p_intf, DBusMessageIter *container )
400 {
401     input_thread_t *p_input = pl_CurrentInput( p_intf );
402     const char *psz_playback_status;
403
404     if( p_input != NULL )
405     {
406         switch( var_GetInteger( p_input, "state" ) )
407         {
408             case OPENING_S:
409             case PLAYING_S:
410                 psz_playback_status = PLAYBACK_STATUS_PLAYING;
411                 break;
412             case PAUSE_S:
413                 psz_playback_status = PLAYBACK_STATUS_PAUSED;
414                 break;
415             default:
416                 psz_playback_status = PLAYBACK_STATUS_STOPPED;
417         }
418
419         vlc_object_release( (vlc_object_t*) p_input );
420     }
421     else
422         psz_playback_status = PLAYBACK_STATUS_STOPPED;
423
424     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_STRING,
425                                          &psz_playback_status ) )
426         return VLC_ENOMEM;
427
428     return VLC_SUCCESS;
429 }
430
431 static int
432 MarshalRate( intf_thread_t *p_intf, DBusMessageIter *container )
433 {
434     double d_rate;
435     input_thread_t *p_input = pl_CurrentInput( p_intf );
436
437     if( p_input != NULL )
438     {
439         d_rate = var_GetFloat( p_input, "rate" );
440         vlc_object_release( (vlc_object_t*) p_input );
441     }
442     else
443         d_rate = 1.0;
444
445     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_DOUBLE,
446                                          &d_rate ) )
447         return VLC_ENOMEM;
448
449     return VLC_SUCCESS;
450 }
451
452 DBUS_METHOD( RateSet )
453 {
454     REPLY_INIT;
455
456     double d_rate;
457
458     if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &d_rate ) )
459         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
460
461     input_thread_t *p_input = pl_CurrentInput( p_this );
462     if( p_input != NULL )
463     {
464         var_SetFloat( p_input, "rate", (float) d_rate );
465         vlc_object_release( (vlc_object_t*) p_input );
466     }
467     else
468         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
469
470     REPLY_SEND;
471 }
472
473 static int
474 MarshalMinimumRate( intf_thread_t *p_intf, DBusMessageIter *container )
475 {
476     VLC_UNUSED( p_intf );
477     double d_min_rate = (double) INPUT_RATE_MIN / INPUT_RATE_DEFAULT;
478
479     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_DOUBLE, &d_min_rate ) )
480         return VLC_ENOMEM;
481
482     return VLC_SUCCESS;
483 }
484
485 static int
486 MarshalMaximumRate( intf_thread_t *p_intf, DBusMessageIter *container )
487 {
488     VLC_UNUSED( p_intf );
489     double d_max_rate = (double) INPUT_RATE_MAX / INPUT_RATE_DEFAULT;
490
491     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_DOUBLE, &d_max_rate ) )
492         return VLC_ENOMEM;
493
494     return VLC_SUCCESS;
495 }
496
497 static int
498 MarshalLoopStatus( intf_thread_t *p_intf, DBusMessageIter *container )
499 {
500     const char *psz_loop_status;
501
502     if( var_GetBool( p_intf->p_sys->p_playlist, "repeat" ) )
503         psz_loop_status = LOOP_STATUS_TRACK;
504
505     else if( var_GetBool( p_intf->p_sys->p_playlist, "loop" ) )
506         psz_loop_status = LOOP_STATUS_PLAYLIST;
507
508     else
509         psz_loop_status = LOOP_STATUS_NONE;
510
511     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_STRING,
512                                          &psz_loop_status ) )
513         return VLC_ENOMEM;
514
515     return VLC_SUCCESS;
516 }
517
518 DBUS_METHOD( LoopStatusSet )
519 {
520     REPLY_INIT;
521     char *psz_loop_status;
522
523     if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &psz_loop_status ) )
524         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
525
526     if( !strcmp( psz_loop_status, LOOP_STATUS_NONE ) )
527     {
528         var_SetBool( PL, "loop",   FALSE );
529         var_SetBool( PL, "repeat", FALSE );
530     }
531     else if( !strcmp( psz_loop_status, LOOP_STATUS_TRACK ) )
532     {
533         var_SetBool( PL, "loop",   FALSE );
534         var_SetBool( PL, "repeat", TRUE  );
535     }
536     else if( !strcmp( psz_loop_status, LOOP_STATUS_PLAYLIST ) )
537     {
538         var_SetBool( PL, "loop",   TRUE );
539         var_SetBool( PL, "repeat", FALSE  );
540     }
541     else
542         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
543
544     REPLY_SEND;
545 }
546
547 static int
548 MarshalMetadata( intf_thread_t *p_intf, DBusMessageIter *container )
549 {
550     DBusMessageIter a;
551     input_thread_t *p_input = pl_CurrentInput( p_intf );
552     input_item_t   *p_item  = NULL;
553
554     if( p_input != NULL )
555     {
556         p_item = input_GetItem( p_input );
557
558         if( p_item )
559         {
560             int result = GetInputMeta( p_item, container );
561
562             if (result != VLC_SUCCESS)
563             {
564                 vlc_object_release( (vlc_object_t*) p_input );
565                 return result;
566             }
567         }
568
569         vlc_object_release( (vlc_object_t*) p_input );
570     }
571
572     if (!p_item)
573     {
574         // avoid breaking the type marshalling
575         if( !dbus_message_iter_open_container( container, DBUS_TYPE_ARRAY, "{sv}", &a ) ||
576               !dbus_message_iter_close_container( container, &a ) )
577             return VLC_ENOMEM;
578     }
579
580     return VLC_SUCCESS;
581 }
582
583
584 /******************************************************************************
585  * Seeked: non-linear playback signal
586  *****************************************************************************/
587 DBUS_SIGNAL( SeekedSignal )
588 {
589     SIGNAL_INIT( DBUS_MPRIS_PLAYER_INTERFACE,
590                  DBUS_MPRIS_OBJECT_PATH,
591                  "Seeked" );
592
593     OUT_ARGUMENTS;
594
595     dbus_int64_t i_pos = 0;
596     intf_thread_t *p_intf = (intf_thread_t*) p_data;
597     input_thread_t *p_input = pl_CurrentInput( p_intf );
598
599     if( p_input )
600     {
601         i_pos = var_GetTime( p_input, "time" );
602         vlc_object_release( p_input );
603     }
604
605     ADD_INT64( &i_pos );
606     SIGNAL_SEND;
607 }
608
609 #define PROPERTY_MAPPING_BEGIN if( 0 ) {}
610 #define PROPERTY_GET_FUNC( prop, signature ) \
611     else if( !strcmp( psz_property_name,  #prop ) ) { \
612         if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, signature, &v ) ) \
613             return DBUS_HANDLER_RESULT_NEED_MEMORY; \
614         if( VLC_SUCCESS != Marshal##prop( p_this, &v ) ) { \
615             dbus_message_iter_abandon_container( &args, &v ); \
616             return DBUS_HANDLER_RESULT_NEED_MEMORY; \
617         } \
618         if( !dbus_message_iter_close_container( &args, &v ) ) \
619             return DBUS_HANDLER_RESULT_NEED_MEMORY; \
620     }
621 #define PROPERTY_SET_FUNC( prop ) \
622     else if( !strcmp( psz_property_name,  #prop ) ) { \
623         return prop##Set( p_conn, p_from, p_this ); \
624     }
625 #define PROPERTY_MAPPING_END else { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; }
626
627 DBUS_METHOD( GetProperty )
628 {
629     DBusError error;
630
631     char *psz_interface_name = NULL;
632     char *psz_property_name  = NULL;
633
634     dbus_error_init( &error );
635     dbus_message_get_args( p_from, &error,
636             DBUS_TYPE_STRING, &psz_interface_name,
637             DBUS_TYPE_STRING, &psz_property_name,
638             DBUS_TYPE_INVALID );
639
640     if( dbus_error_is_set( &error ) )
641     {
642         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
643                                          error.message );
644         dbus_error_free( &error );
645         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
646     }
647
648     msg_Dbg( (vlc_object_t*) p_this, "Getting property %s",
649                                      psz_property_name );
650
651     if( strcmp( psz_interface_name, DBUS_MPRIS_PLAYER_INTERFACE ) ) {
652         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
653     }
654
655     REPLY_INIT;
656     OUT_ARGUMENTS;
657     DBusMessageIter v;
658
659     PROPERTY_MAPPING_BEGIN
660     PROPERTY_GET_FUNC( Metadata,       "a{sv}" )
661     PROPERTY_GET_FUNC( Position,       "x" )
662     PROPERTY_GET_FUNC( PlaybackStatus, "s" )
663     PROPERTY_GET_FUNC( LoopStatus,     "s" )
664     PROPERTY_GET_FUNC( Shuffle,        "b" )
665     PROPERTY_GET_FUNC( Volume,         "d" )
666     PROPERTY_GET_FUNC( Rate,           "d" )
667     PROPERTY_GET_FUNC( MinimumRate,    "d" )
668     PROPERTY_GET_FUNC( MaximumRate,    "d" )
669     PROPERTY_GET_FUNC( CanControl,     "b" )
670     PROPERTY_GET_FUNC( CanPlay,        "b" )
671     PROPERTY_GET_FUNC( CanGoNext,      "b" )
672     PROPERTY_GET_FUNC( CanGoPrevious,  "b" )
673     PROPERTY_GET_FUNC( CanPause,       "b" )
674     PROPERTY_GET_FUNC( CanSeek,        "b" )
675     PROPERTY_MAPPING_END
676
677     REPLY_SEND;
678 }
679
680 DBUS_METHOD( SetProperty )
681 {
682     DBusError error;
683
684     char *psz_interface_name = NULL;
685     char *psz_property_name  = NULL;
686
687     dbus_error_init( &error );
688     dbus_message_get_args( p_from, &error,
689             DBUS_TYPE_STRING, &psz_interface_name,
690             DBUS_TYPE_STRING, &psz_property_name,
691             DBUS_TYPE_INVALID );
692
693     if( dbus_error_is_set( &error ) )
694     {
695         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
696                                          error.message );
697         dbus_error_free( &error );
698         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
699     }
700
701     PROPERTY_MAPPING_BEGIN
702     PROPERTY_SET_FUNC( LoopStatus )
703     PROPERTY_SET_FUNC( Shuffle )
704     PROPERTY_SET_FUNC( Volume )
705     PROPERTY_SET_FUNC( Rate )
706     PROPERTY_MAPPING_END
707 }
708
709 #undef PROPERTY_MAPPING_BEGIN
710 #undef PROPERTY_GET_FUNC
711 #undef PROPERTY_SET_FUNC
712 #undef PROPERTY_MAPPING_END
713
714 #define ADD_PROPERTY( prop, signature ) \
715     if( VLC_SUCCESS != AddProperty( (intf_thread_t*) p_this, \
716                 &dict, #prop, signature, Marshal##prop ) ) { \
717         dbus_message_iter_abandon_container( &args, &dict ); \
718         return VLC_ENOMEM; \
719     }
720
721 DBUS_METHOD( GetAllProperties )
722 {
723     REPLY_INIT;
724     OUT_ARGUMENTS;
725
726     DBusError error;
727     DBusMessageIter dict;
728
729     char *const psz_interface_name = NULL;
730
731     dbus_error_init( &error );
732     dbus_message_get_args( p_from, &error,
733             DBUS_TYPE_STRING, &psz_interface_name,
734             DBUS_TYPE_INVALID );
735
736     if( dbus_error_is_set( &error ) )
737     {
738         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
739                                          error.message );
740         dbus_error_free( &error );
741         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
742     }
743
744     msg_Dbg( (vlc_object_t*) p_this, "Getting All properties" );
745
746     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "{sv}", &dict ) )
747         return DBUS_HANDLER_RESULT_NEED_MEMORY;
748
749     ADD_PROPERTY ( Metadata,       "a{sv}" );
750     ADD_PROPERTY ( Position,       "x"     );
751     ADD_PROPERTY ( PlaybackStatus, "s"     );
752     ADD_PROPERTY ( LoopStatus,     "s"     );
753     ADD_PROPERTY ( Shuffle,        "b"     );
754     ADD_PROPERTY ( Volume,         "d"     );
755     ADD_PROPERTY ( Rate,           "d"     );
756     ADD_PROPERTY ( MinimumRate,    "d"     );
757     ADD_PROPERTY ( MaximumRate,    "d"     );
758     ADD_PROPERTY ( CanControl,     "b"     );
759     ADD_PROPERTY ( CanPlay,        "b"     );
760     ADD_PROPERTY ( CanGoNext,      "b"     );
761     ADD_PROPERTY ( CanGoPrevious,  "b"     );
762     ADD_PROPERTY ( CanPause,       "b"     );
763     ADD_PROPERTY ( CanSeek,        "b"     );
764
765     if( !dbus_message_iter_close_container( &args, &dict ))
766         return DBUS_HANDLER_RESULT_NEED_MEMORY;
767
768     REPLY_SEND;
769 }
770
771 #undef ADD_PROPERTY
772
773 #define METHOD_FUNC( interface, method, function ) \
774     else if( dbus_message_is_method_call( p_from, interface, method ) )\
775         return function( p_conn, p_from, p_this )
776
777 DBusHandlerResult
778 handle_player ( DBusConnection *p_conn, DBusMessage *p_from, void *p_this )
779 {
780     if(0);
781     METHOD_FUNC( DBUS_INTERFACE_PROPERTIES,   "Get",        GetProperty );
782     METHOD_FUNC( DBUS_INTERFACE_PROPERTIES,   "Set",        SetProperty );
783     METHOD_FUNC( DBUS_INTERFACE_PROPERTIES,   "GetAll",     GetAllProperties );
784
785     /* here D-Bus method names are associated to an handler */
786
787     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Previous",     Prev );
788     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Next",         Next );
789     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Stop",         Stop );
790     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Seek",         Seek );
791     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Play",         Play );
792     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Pause",        Pause );
793     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "PlayPause",    PlayPause );
794     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "OpenUri",      OpenUri );
795     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "SetPosition",  SetPosition );
796
797     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
798 }
799
800 #undef METHOD_FUNC
801
802 /*****************************************************************************
803  * SeekedEmit: Emits the Seeked signal
804  *****************************************************************************/
805 int SeekedEmit( intf_thread_t * p_intf )
806 {
807     if( p_intf->p_sys->b_dead )
808         return VLC_SUCCESS;
809
810     SeekedSignal( p_intf->p_sys->p_conn, p_intf );
811     return VLC_SUCCESS;
812 }
813
814 #define PROPERTY_MAPPING_BEGIN if( 0 ) {}
815 #define PROPERTY_ENTRY( prop, signature ) \
816     else if( !strcmp( ppsz_properties[i], #prop ) ) \
817     { \
818         if( VLC_SUCCESS != AddProperty( (intf_thread_t*) p_intf, \
819                     &changed_properties, #prop, signature, Marshal##prop ) ) \
820             return DBUS_HANDLER_RESULT_NEED_MEMORY; \
821     }
822 #define PROPERTY_MAPPING_END else { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; }
823
824 /**
825  * PropertiesChangedSignal() synthetizes and sends the
826  * org.freedesktop.DBus.Properties.PropertiesChanged signal
827  */
828 static DBusHandlerResult
829 PropertiesChangedSignal( intf_thread_t    *p_intf,
830                          vlc_dictionary_t *p_changed_properties )
831 {
832     DBusConnection  *p_conn = p_intf->p_sys->p_conn;
833     DBusMessageIter changed_properties, invalidated_properties;
834     const char *psz_interface_name = DBUS_MPRIS_PLAYER_INTERFACE;
835     char **ppsz_properties = NULL;
836     int i_properties = 0;
837
838     SIGNAL_INIT( DBUS_INTERFACE_PROPERTIES,
839                  DBUS_MPRIS_OBJECT_PATH,
840                  "PropertiesChanged" );
841
842     OUT_ARGUMENTS;
843     ADD_STRING( &psz_interface_name );
844
845     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "{sv}",
846                                            &changed_properties ) )
847         return DBUS_HANDLER_RESULT_NEED_MEMORY;
848
849     i_properties = vlc_dictionary_keys_count( p_changed_properties );
850     ppsz_properties = vlc_dictionary_all_keys( p_changed_properties );
851
852     if( unlikely(!ppsz_properties) )
853     {
854         dbus_message_iter_abandon_container( &args, &changed_properties );
855         return DBUS_HANDLER_RESULT_NEED_MEMORY;
856     }
857
858     for( int i = 0; i < i_properties; i++ )
859     {
860         PROPERTY_MAPPING_BEGIN
861         PROPERTY_ENTRY( Metadata,       "a{sv}" )
862         PROPERTY_ENTRY( PlaybackStatus, "s"     )
863         PROPERTY_ENTRY( LoopStatus,     "s"     )
864         PROPERTY_ENTRY( Rate,           "d"     )
865         PROPERTY_ENTRY( Shuffle,        "b"     )
866         PROPERTY_ENTRY( Volume,         "d"     )
867         PROPERTY_ENTRY( CanSeek,        "b"     )
868         PROPERTY_ENTRY( CanPlay,        "b"     )
869         PROPERTY_ENTRY( CanPause,       "b"     )
870         PROPERTY_MAPPING_END
871
872         free( ppsz_properties[i] );
873     }
874
875     if( !dbus_message_iter_close_container( &args, &changed_properties ) )
876         return DBUS_HANDLER_RESULT_NEED_MEMORY;
877
878     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "s",
879                                            &invalidated_properties ) )
880         return DBUS_HANDLER_RESULT_NEED_MEMORY;
881
882     if( !dbus_message_iter_close_container( &args, &invalidated_properties ) )
883         return DBUS_HANDLER_RESULT_NEED_MEMORY;
884
885     free( ppsz_properties );
886
887     SIGNAL_SEND;
888 }
889
890 #undef PROPERTY_MAPPING_BEGIN
891 #undef PROPERTY_ADD
892 #undef PROPERTY_MAPPING_END
893
894 /*****************************************************************************
895  * PropertiesChangedEmit: Emits the Seeked signal
896  *****************************************************************************/
897 int PlayerPropertiesChangedEmit( intf_thread_t    * p_intf,
898                                  vlc_dictionary_t * p_changed_properties )
899 {
900     if( p_intf->p_sys->b_dead )
901         return VLC_SUCCESS;
902
903     PropertiesChangedSignal( p_intf, p_changed_properties );
904     return VLC_SUCCESS;
905 }