DBus: do not assume AOUT_VOLUME_DEFAULT = AOUT_VOLUME_MAX / 4
[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     if( d_dbus_vol > 1. )
205         d_dbus_vol = 1.;
206     else if( d_dbus_vol < 0. )
207         d_dbus_vol = 0.;
208
209     double d_vol = d_dbus_vol * AOUT_VOLUME_MAX;
210     audio_volume_t i_vol = round( d_vol );
211     aout_VolumeSet( PL, i_vol );
212
213     REPLY_SEND;
214 }
215
216 DBUS_METHOD( Next )
217 { /* next playlist item */
218     REPLY_INIT;
219     playlist_Next( PL );
220     REPLY_SEND;
221 }
222
223 DBUS_METHOD( Prev )
224 { /* previous playlist item */
225     REPLY_INIT;
226     playlist_Prev( PL );
227     REPLY_SEND;
228 }
229
230 DBUS_METHOD( Stop )
231 { /* stop playing */
232     REPLY_INIT;
233     playlist_Stop( PL );
234     REPLY_SEND;
235 }
236
237 DBUS_METHOD( Play )
238 {
239     REPLY_INIT;
240     input_thread_t *p_input =  playlist_CurrentInput( PL );
241
242     if( !p_input || var_GetInteger( p_input, "state" ) != PLAYING_S )
243         playlist_Play( PL );
244
245     if( p_input )
246         vlc_object_release( p_input );
247
248     REPLY_SEND;
249 }
250
251 DBUS_METHOD( Pause )
252 {
253     REPLY_INIT;
254     input_thread_t *p_input = playlist_CurrentInput( PL );
255
256     if( p_input && var_GetInteger(p_input, "state") == PLAYING_S )
257         playlist_Pause( PL );
258
259     if( p_input )
260         vlc_object_release( p_input );
261
262     REPLY_SEND;
263 }
264
265 DBUS_METHOD( PlayPause )
266 {
267     REPLY_INIT;
268     input_thread_t *p_input = playlist_CurrentInput( PL );
269
270     if( p_input && var_GetInteger(p_input, "state") == PLAYING_S )
271         playlist_Pause( PL );
272     else
273         playlist_Play( PL );
274
275     if( p_input )
276         vlc_object_release( p_input );
277
278     REPLY_SEND;
279 }
280
281 DBUS_METHOD( OpenUri )
282 {
283     REPLY_INIT;
284
285     char *psz_mrl;
286     DBusError error;
287     dbus_error_init( &error );
288
289     dbus_message_get_args( p_from, &error,
290             DBUS_TYPE_STRING, &psz_mrl,
291             DBUS_TYPE_INVALID );
292
293     if( dbus_error_is_set( &error ) )
294     {
295         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
296                 error.message );
297         dbus_error_free( &error );
298         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
299     }
300
301     playlist_Add( PL, psz_mrl, NULL,
302                   PLAYLIST_APPEND | PLAYLIST_GO,
303                   PLAYLIST_END, true, false );
304
305     REPLY_SEND;
306 }
307
308 static void
309 MarshalCanPlay( intf_thread_t *p_intf, DBusMessageIter *container )
310 {
311     playlist_t *p_playlist = p_intf->p_sys->p_playlist;
312
313     PL_LOCK;
314     dbus_bool_t b_can_play = playlist_CurrentSize( p_playlist );
315     PL_UNLOCK;
316
317     dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN, &b_can_play );
318 }
319
320 DBUS_METHOD( CanPlay )
321 {
322     REPLY_INIT;
323     OUT_ARGUMENTS;
324
325     DBusMessageIter v;
326
327     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "b", &v ) )
328         return DBUS_HANDLER_RESULT_NEED_MEMORY;
329
330     MarshalCanPlay( p_this, &v );
331
332     if( !dbus_message_iter_close_container( &args, &v ) )
333         return DBUS_HANDLER_RESULT_NEED_MEMORY;
334
335     REPLY_SEND;
336 }
337
338 static void
339 MarshalCanPause( intf_thread_t *p_intf, DBusMessageIter *container )
340 {
341     dbus_bool_t b_can_pause = FALSE;
342     input_thread_t *p_input;
343     p_input = playlist_CurrentInput( p_intf->p_sys->p_playlist );
344
345     if( p_input )
346     {
347         b_can_pause = var_GetBool( p_input, "can-pause" );
348         vlc_object_release( p_input );
349     }
350
351     dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
352                                     &b_can_pause );
353 }
354
355 DBUS_METHOD( CanPause )
356 {
357     REPLY_INIT;
358     OUT_ARGUMENTS;
359
360     DBusMessageIter v;
361
362     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "b", &v ) )
363         return DBUS_HANDLER_RESULT_NEED_MEMORY;
364
365     MarshalCanPause( p_this, &v );
366
367     if( !dbus_message_iter_close_container( &args, &v ) )
368         return DBUS_HANDLER_RESULT_NEED_MEMORY;
369
370     REPLY_SEND;
371 }
372
373 DBUS_METHOD( CanControl )
374 {
375     VLC_UNUSED( p_this );
376
377     REPLY_INIT;
378     OUT_ARGUMENTS;
379
380     DBusMessageIter v;
381     dbus_bool_t b_can_control = TRUE;
382
383     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT,
384                                            "b", &v ) )
385         return DBUS_HANDLER_RESULT_NEED_MEMORY;
386
387     if( !dbus_message_iter_append_basic( &v, DBUS_TYPE_BOOLEAN,
388                                          &b_can_control ) )
389         return DBUS_HANDLER_RESULT_NEED_MEMORY;
390
391     if( !dbus_message_iter_close_container( &args, &v ) )
392         return DBUS_HANDLER_RESULT_NEED_MEMORY;
393
394     REPLY_SEND;
395 }
396
397 static void
398 MarshalCanSeek( intf_thread_t *p_intf, DBusMessageIter *container )
399 {
400     dbus_bool_t b_can_seek = FALSE;
401     input_thread_t *p_input;
402     p_input = playlist_CurrentInput( p_intf->p_sys->p_playlist );
403
404     if( p_input )
405     {
406         b_can_seek = var_GetBool( p_input, "can-seek" );
407         vlc_object_release( p_input );
408     }
409
410     dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN, &b_can_seek );
411 }
412
413 DBUS_METHOD( CanSeek )
414 {
415     REPLY_INIT;
416     OUT_ARGUMENTS;
417
418     DBusMessageIter v;
419
420     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "b", &v ) )
421         return DBUS_HANDLER_RESULT_NEED_MEMORY;
422
423     MarshalCanSeek( p_this, &v );
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 = 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 DBUS_METHOD( Metadata )
679 {
680     REPLY_INIT;
681     OUT_ARGUMENTS;
682
683     DBusMessageIter v, a;
684     playlist_t *p_playlist = PL;
685
686     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT,
687                                            "a{sv}", &v ) )
688         return DBUS_HANDLER_RESULT_NEED_MEMORY;
689
690     PL_LOCK;
691     playlist_item_t* p_item =  playlist_CurrentPlayingItem( p_playlist );
692
693     if( p_item )
694         GetInputMeta( p_item->p_input, &v );
695
696     PL_UNLOCK;
697
698     if( ( !p_item &&
699         ( !dbus_message_iter_open_container( &v, DBUS_TYPE_ARRAY, "{sv}", &a ) ||
700           !dbus_message_iter_close_container( &v, &a ) ) ) ||
701
702         !dbus_message_iter_close_container( &args, &v ) ) {
703         return DBUS_HANDLER_RESULT_NEED_MEMORY;
704     }
705
706     REPLY_SEND;
707 }
708
709 /******************************************************************************
710  * Seeked: non-linear playback signal
711  *****************************************************************************/
712 DBUS_SIGNAL( SeekedSignal )
713 {
714     SIGNAL_INIT( DBUS_MPRIS_PLAYER_INTERFACE,
715                  DBUS_MPRIS_OBJECT_PATH,
716                  "Seeked" );
717
718     OUT_ARGUMENTS;
719
720     dbus_int64_t i_pos = 0;
721     intf_thread_t *p_intf = (intf_thread_t*) p_data;
722     input_thread_t *p_input = playlist_CurrentInput( p_intf->p_sys->p_playlist );
723
724     if( p_input )
725     {
726         i_pos = var_GetTime( p_input, "time" );
727         vlc_object_release( p_input );
728     }
729
730     ADD_INT64( &i_pos );
731     SIGNAL_SEND;
732 }
733
734 #define PROPERTY_MAPPING_BEGIN if( 0 ) {}
735 #define PROPERTY_FUNC( interface, property, function ) \
736     else if( !strcmp( psz_interface_name, interface ) && \
737              !strcmp( psz_property_name,  property ) ) \
738         return function( p_conn, p_from, p_this );
739 #define PROPERTY_MAPPING_END return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
740
741 DBUS_METHOD( GetProperty )
742 {
743     DBusError error;
744
745     char *psz_interface_name = NULL;
746     char *psz_property_name  = NULL;
747
748     dbus_error_init( &error );
749     dbus_message_get_args( p_from, &error,
750             DBUS_TYPE_STRING, &psz_interface_name,
751             DBUS_TYPE_STRING, &psz_property_name,
752             DBUS_TYPE_INVALID );
753
754     if( dbus_error_is_set( &error ) )
755     {
756         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
757                                          error.message );
758         dbus_error_free( &error );
759         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
760     }
761
762     msg_Dbg( (vlc_object_t*) p_this, "Getting property %s",
763                                      psz_property_name );
764
765     PROPERTY_MAPPING_BEGIN
766     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Metadata", Metadata )
767     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Position", Position )
768     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "PlaybackStatus", PlaybackStatus )
769     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "LoopStatus", LoopStatusGet )
770     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Shuffle", ShuffleGet )
771     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Volume", VolumeGet )
772     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Rate", RateGet )
773     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "MinimumRate", MinimumRate )
774     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "MaximumRate", MaximumRate )
775     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "CanControl", CanControl )
776     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "CanPlay", CanPlay )
777     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "CanPause", CanPause )
778     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "CanSeek", CanSeek )
779     PROPERTY_MAPPING_END
780 }
781
782 DBUS_METHOD( SetProperty )
783 {
784     DBusError error;
785
786     char *psz_interface_name = NULL;
787     char *psz_property_name  = NULL;
788
789     dbus_error_init( &error );
790     dbus_message_get_args( p_from, &error,
791             DBUS_TYPE_STRING, &psz_interface_name,
792             DBUS_TYPE_STRING, &psz_property_name,
793             DBUS_TYPE_INVALID );
794
795     if( dbus_error_is_set( &error ) )
796     {
797         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
798                                          error.message );
799         dbus_error_free( &error );
800         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
801     }
802
803     PROPERTY_MAPPING_BEGIN
804     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "LoopStatus", LoopStatusSet )
805     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Shuffle",    ShuffleSet )
806     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Volume",     VolumeSet )
807     PROPERTY_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Rate",       RateSet )
808     PROPERTY_MAPPING_END
809 }
810
811 #undef PROPERTY_MAPPING_BEGIN
812 #undef PROPERTY_GET_FUNC
813 #undef PROPERTY_MAPPING_END
814
815 #define METHOD_FUNC( interface, method, function ) \
816     else if( dbus_message_is_method_call( p_from, interface, method ) )\
817         return function( p_conn, p_from, p_this )
818
819 DBusHandlerResult
820 handle_player ( DBusConnection *p_conn, DBusMessage *p_from, void *p_this )
821 {
822     if(0);
823     METHOD_FUNC( DBUS_INTERFACE_PROPERTIES,   "Get",        GetProperty );
824     METHOD_FUNC( DBUS_INTERFACE_PROPERTIES,   "Set",        SetProperty );
825 /*  METHOD_FUNC( DBUS_INTERFACE_PROPERTIES,   "GetAll",     GetAllProperties );*/
826
827     /* here D-Bus method names are associated to an handler */
828
829     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Previous",     Prev );
830     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Next",         Next );
831     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Stop",         Stop );
832     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Seek",         Seek );
833     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Play",         Play );
834     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Pause",        Pause );
835     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "PlayPause",    PlayPause );
836     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "OpenUri",      OpenUri );
837     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "SetPosition",  SetPosition );
838
839     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
840 }
841
842 #undef METHOD_FUNC
843
844 /*****************************************************************************
845  * SeekedEmit: Emits the Seeked signal
846  *****************************************************************************/
847 int SeekedEmit( intf_thread_t * p_intf )
848 {
849     if( p_intf->p_sys->b_dead )
850         return VLC_SUCCESS;
851
852     SeekedSignal( p_intf->p_sys->p_conn, p_intf );
853     return VLC_SUCCESS;
854 }
855
856 /**
857  * PropertiesChangedSignal() synthetizes and sends the
858  * org.freedesktop.DBus.Properties.PropertiesChanged signal
859  */
860 static DBusHandlerResult
861 PropertiesChangedSignal( intf_thread_t    *p_intf,
862                          vlc_dictionary_t *p_changed_properties )
863 {
864     DBusConnection  *p_conn = p_intf->p_sys->p_conn;
865     DBusMessageIter changed_properties, invalidated_properties, entry, variant;
866     const char *psz_interface_name = DBUS_MPRIS_PLAYER_INTERFACE;
867     char **ppsz_properties = NULL;
868     int i_properties = 0;
869
870     SIGNAL_INIT( DBUS_INTERFACE_PROPERTIES,
871                  DBUS_MPRIS_OBJECT_PATH,
872                  "PropertiesChanged" );
873
874     OUT_ARGUMENTS;
875     ADD_STRING( &psz_interface_name );
876     dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "{sv}",
877                                       &changed_properties );
878
879     i_properties = vlc_dictionary_keys_count( p_changed_properties );
880     ppsz_properties = vlc_dictionary_all_keys( p_changed_properties );
881
882     for( int i = 0; i < i_properties; i++ )
883     {
884         dbus_message_iter_open_container( &changed_properties,
885                                           DBUS_TYPE_DICT_ENTRY, NULL,
886                                           &entry );
887
888         dbus_message_iter_append_basic( &entry, DBUS_TYPE_STRING,
889                                         &ppsz_properties[i] );
890
891         if( !strcmp( ppsz_properties[i], "Metadata" ) )
892         {
893             input_thread_t *p_input;
894             p_input = playlist_CurrentInput( p_intf->p_sys->p_playlist );
895
896             dbus_message_iter_open_container( &entry,
897                                               DBUS_TYPE_VARIANT, "a{sv}",
898                                               &variant );
899
900             if( p_input )
901             {
902                 input_item_t *p_item = input_GetItem( p_input );
903                 GetInputMeta( p_item, &variant );
904                 vlc_object_release( p_input );
905             }
906
907             dbus_message_iter_close_container( &entry, &variant );
908         }
909         else if( !strcmp( ppsz_properties[i], "PlaybackStatus" ) )
910         {
911             dbus_message_iter_open_container( &entry,
912                                               DBUS_TYPE_VARIANT, "s",
913                                               &variant );
914             MarshalPlaybackStatus( p_intf, &variant );
915             dbus_message_iter_close_container( &entry, &variant );
916         }
917         else if( !strcmp( ppsz_properties[i], "LoopStatus" ) )
918         {
919             dbus_message_iter_open_container( &entry,
920                                               DBUS_TYPE_VARIANT, "s",
921                                               &variant );
922             MarshalLoopStatus( p_intf, &variant );
923             dbus_message_iter_close_container( &entry, &variant );
924         }
925         else if( !strcmp( ppsz_properties[i], "Rate" ) )
926         {
927             dbus_message_iter_open_container( &entry,
928                                               DBUS_TYPE_VARIANT, "d",
929                                               &variant );
930             MarshalRate( p_intf, &variant );
931             dbus_message_iter_close_container( &entry, &variant );
932         }
933         else if( !strcmp( ppsz_properties[i], "Shuffle" ) )
934         {
935             dbus_message_iter_open_container( &entry,
936                                               DBUS_TYPE_VARIANT, "b",
937                                               &variant );
938             MarshalShuffle( p_intf, &variant );
939             dbus_message_iter_close_container( &entry, &variant );
940         }
941         else if( !strcmp( ppsz_properties[i], "Volume" ) )
942         {
943             dbus_message_iter_open_container( &entry,
944                                               DBUS_TYPE_VARIANT, "d",
945                                               &variant );
946             MarshalVolume( p_intf, &variant );
947             dbus_message_iter_close_container( &entry, &variant );
948         }
949         else if( !strcmp( ppsz_properties[i], "CanSeek" ) )
950         {
951             dbus_message_iter_open_container( &entry,
952                                               DBUS_TYPE_VARIANT, "b",
953                                               &variant );
954             MarshalCanSeek( p_intf, &variant );
955             dbus_message_iter_close_container( &entry, &variant );
956         }
957         else if( !strcmp( ppsz_properties[i], "CanPlay" ) )
958         {
959             dbus_message_iter_open_container( &entry,
960                                               DBUS_TYPE_VARIANT, "b",
961                                               &variant );
962             MarshalCanPlay( p_intf, &variant );
963             dbus_message_iter_close_container( &entry, &variant );
964         }
965         else if( !strcmp( ppsz_properties[i], "CanPause" ) )
966         {
967             dbus_message_iter_open_container( &entry,
968                                               DBUS_TYPE_VARIANT, "b",
969                                               &variant );
970             MarshalCanPause( p_intf, &variant );
971             dbus_message_iter_close_container( &entry, &variant );
972         }
973         dbus_message_iter_close_container( &changed_properties, &entry );
974         free( ppsz_properties[i] );
975     }
976
977     dbus_message_iter_close_container( &args, &changed_properties );
978     dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "s",
979                                       &invalidated_properties );
980     dbus_message_iter_close_container( &args, &invalidated_properties );
981     free( ppsz_properties );
982
983     SIGNAL_SEND;
984 }
985
986 /*****************************************************************************
987  * PropertiesChangedEmit: Emits the Seeked signal
988  *****************************************************************************/
989 int PlayerPropertiesChangedEmit( intf_thread_t    * p_intf,
990                                  vlc_dictionary_t * p_changed_properties )
991 {
992     if( p_intf->p_sys->b_dead )
993         return VLC_SUCCESS;
994
995     PropertiesChangedSignal( p_intf, p_changed_properties );
996     return VLC_SUCCESS;
997 }