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