qml: fix scrollbar in NetworkHomeDisplay
[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  *
9  * Authors:    Mirsal Ennaime <mirsal at mirsal fr>
10  *             Rafaël Carré <funman at videolanorg>
11  *             Alex Merry <dev at randomguy3 me uk>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_interface.h>
34
35 #include <math.h>
36
37 #include "dbus_player.h"
38 #include "dbus_common.h"
39
40 static int
41 MarshalPosition( intf_thread_t *p_intf, DBusMessageIter *container )
42 {
43     /* returns time in microseconds */
44     dbus_int64_t i_pos;
45
46     vlc_player_t *player = vlc_playlist_GetPlayer(p_intf->p_sys->playlist);
47     vlc_player_Lock(player);
48     i_pos = vlc_player_GetTime(player);
49     vlc_player_Unlock(player);
50     i_pos = i_pos == VLC_TICK_INVALID ? 0 : US_FROM_VLC_TICK(i_pos);
51
52     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_INT64, &i_pos ) )
53         return VLC_ENOMEM;
54
55     return VLC_SUCCESS;
56 }
57
58 DBUS_METHOD( SetPosition )
59 { /* set time in microseconds */
60
61     REPLY_INIT;
62     dbus_int64_t i_pos;
63     const char *psz_trackid;
64     ssize_t i_item_id;
65     size_t i_id;
66
67     DBusError error;
68     dbus_error_init( &error );
69
70     dbus_message_get_args( p_from, &error,
71             DBUS_TYPE_OBJECT_PATH, &psz_trackid,
72             DBUS_TYPE_INT64, &i_pos,
73             DBUS_TYPE_INVALID );
74
75     if( dbus_error_is_set( &error ) )
76     {
77         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
78                 error.message );
79         dbus_error_free( &error );
80         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
81     }
82
83     if( sscanf( psz_trackid, MPRIS_TRACKID_FORMAT, &i_id ) < 1 )
84         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
85
86     vlc_playlist_t *playlist = PL;
87     vlc_playlist_Lock(playlist);
88     i_item_id = vlc_playlist_GetCurrentIndex( playlist );
89     if (i_item_id != -1 && (size_t)i_item_id == i_id)
90     {
91         vlc_player_t *player = vlc_playlist_GetPlayer(playlist);
92         vlc_player_SetTime(player, VLC_TICK_FROM_US(i_pos));
93     }
94     vlc_playlist_Unlock(playlist);
95
96     REPLY_SEND;
97 }
98
99 DBUS_METHOD( Seek )
100 {
101     REPLY_INIT;
102     dbus_int64_t i_step;
103
104     DBusError error;
105     dbus_error_init( &error );
106
107     dbus_message_get_args( p_from, &error,
108             DBUS_TYPE_INT64, &i_step,
109             DBUS_TYPE_INVALID );
110
111     if( dbus_error_is_set( &error ) )
112     {
113         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
114                 error.message );
115         dbus_error_free( &error );
116         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
117     }
118
119     vlc_player_t *player = vlc_playlist_GetPlayer(PL);
120     vlc_player_Lock(player);
121     vlc_player_JumpTime(player, VLC_TICK_FROM_US(i_step));
122     vlc_player_Unlock(player);
123
124     REPLY_SEND;
125 }
126
127 static int
128 MarshalVolume( intf_thread_t *p_intf, DBusMessageIter *container )
129 {
130     vlc_player_t *player = vlc_playlist_GetPlayer(p_intf->p_sys->playlist);
131     double vol = vlc_player_aout_GetVolume(player);
132     if( vol < .0f )
133         vol = .0f;
134
135     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_DOUBLE, &vol ) )
136         return VLC_ENOMEM;
137
138     return VLC_SUCCESS;
139 }
140
141 DBUS_METHOD( VolumeSet )
142 {
143     REPLY_INIT;
144     double d_dbus_vol;
145
146     if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &d_dbus_vol ) )
147         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
148
149     vlc_player_t *player = vlc_playlist_GetPlayer(PL);
150     vlc_player_aout_SetVolume(player, fmaxf(d_dbus_vol, .0f));
151
152     REPLY_SEND;
153 }
154
155 DBUS_METHOD( Next )
156 { /* next playlist item */
157     REPLY_INIT;
158     vlc_playlist_t *playlist = PL;
159     vlc_playlist_Lock(playlist);
160     vlc_playlist_Next(playlist);
161     vlc_playlist_Unlock(playlist);
162     REPLY_SEND;
163 }
164
165 DBUS_METHOD( Prev )
166 { /* previous playlist item */
167     REPLY_INIT;
168     vlc_playlist_t *playlist = PL;
169     vlc_playlist_Lock(playlist);
170     vlc_playlist_Prev(playlist);
171     vlc_playlist_Unlock(playlist);
172     REPLY_SEND;
173 }
174
175 DBUS_METHOD( Stop )
176 { /* stop playing */
177     REPLY_INIT;
178     vlc_playlist_t *playlist = PL;
179     vlc_playlist_Lock(playlist);
180     vlc_playlist_Stop(playlist);
181     vlc_playlist_Unlock(playlist);
182     REPLY_SEND;
183 }
184
185 DBUS_METHOD( Play )
186 {
187     REPLY_INIT;
188     vlc_player_t *player = vlc_playlist_GetPlayer(PL);
189     vlc_player_Lock(player);
190     if (vlc_player_IsPaused(player))
191         vlc_player_Resume(player);
192     else
193         vlc_player_Start(player);
194     vlc_player_Unlock(player);
195     REPLY_SEND;
196 }
197
198 DBUS_METHOD( Pause )
199 {
200     REPLY_INIT;
201     vlc_playlist_t *playlist = PL;
202     vlc_playlist_Lock(playlist);
203     vlc_playlist_Pause(playlist);
204     vlc_playlist_Unlock(playlist);
205     REPLY_SEND;
206 }
207
208 DBUS_METHOD( PlayPause )
209 {
210     REPLY_INIT;
211     vlc_player_t *player = vlc_playlist_GetPlayer(PL);
212     vlc_player_Lock(player);
213     vlc_player_TogglePause(player);
214     vlc_player_Unlock(player);
215     REPLY_SEND;
216 }
217
218 DBUS_METHOD( OpenUri )
219 {
220     REPLY_INIT;
221
222     char *psz_mrl;
223     DBusError error;
224     dbus_error_init( &error );
225
226     dbus_message_get_args( p_from, &error,
227             DBUS_TYPE_STRING, &psz_mrl,
228             DBUS_TYPE_INVALID );
229
230     if( dbus_error_is_set( &error ) )
231     {
232         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
233                 error.message );
234         dbus_error_free( &error );
235         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
236     }
237
238     input_item_t *item = input_item_New(psz_mrl, NULL);
239     if (!item)
240         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
241
242     vlc_playlist_t *playlist = PL;
243     vlc_playlist_Lock(playlist);
244     size_t count = vlc_playlist_Count(playlist);
245     vlc_playlist_InsertOne(playlist, count, item);
246     vlc_playlist_PlayAt(playlist, count);
247     vlc_playlist_Unlock(playlist);
248
249     input_item_Release(item);
250
251     REPLY_SEND;
252 }
253
254 static int
255 MarshalCanGoNext( intf_thread_t *p_intf, DBusMessageIter *container )
256 {
257     vlc_playlist_t *playlist = p_intf->p_sys->playlist;
258     vlc_playlist_Lock(playlist);
259     size_t count = vlc_playlist_Count(playlist);
260     ssize_t index = vlc_playlist_GetCurrentIndex(playlist);
261     enum vlc_playlist_playback_repeat repeat_mode =
262         vlc_playlist_GetPlaybackRepeat(playlist);
263     vlc_playlist_Unlock(playlist);
264
265     dbus_bool_t b_can_go_next =
266         count != 0 &&
267         ((index != -1 && (size_t)index < count - 1) ||
268          repeat_mode != VLC_PLAYLIST_PLAYBACK_REPEAT_NONE);
269
270     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
271                                          &b_can_go_next ) )
272         return VLC_ENOMEM;
273
274     return VLC_SUCCESS;
275 }
276
277 static int
278 MarshalCanGoPrevious( intf_thread_t *p_intf, DBusMessageIter *container )
279 {
280     vlc_playlist_t *playlist = p_intf->p_sys->playlist;
281     vlc_playlist_Lock(playlist);
282     size_t count = vlc_playlist_Count(playlist);
283     ssize_t index = vlc_playlist_GetCurrentIndex(playlist);
284     enum vlc_playlist_playback_repeat repeat_mode =
285         vlc_playlist_GetPlaybackRepeat(playlist);
286     vlc_playlist_Unlock(playlist);
287
288     dbus_bool_t b_can_go_previous =
289         count != 0 &&
290         (index > 0 || repeat_mode != VLC_PLAYLIST_PLAYBACK_REPEAT_NONE);
291
292     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
293                                          &b_can_go_previous ) )
294         return VLC_ENOMEM;
295
296     return VLC_SUCCESS;
297 }
298
299 static int
300 MarshalCanPlay( intf_thread_t *p_intf, DBusMessageIter *container )
301 {
302     vlc_playlist_t *playlist = p_intf->p_sys->playlist;
303     vlc_playlist_Lock(playlist);
304     dbus_bool_t b_can_play = vlc_playlist_Count(playlist) != 0;
305     vlc_playlist_Unlock(playlist);
306
307     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
308                                          &b_can_play ) )
309         return VLC_ENOMEM;
310
311     return VLC_SUCCESS;
312 }
313
314 static int
315 MarshalCanPause( intf_thread_t *p_intf, DBusMessageIter *container )
316 {
317     vlc_player_t *player = vlc_playlist_GetPlayer(p_intf->p_sys->playlist);
318     vlc_player_Lock(player);
319     dbus_bool_t b_can_pause = vlc_player_CanPause(player);
320     vlc_player_Unlock(player);
321
322     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
323                                          &b_can_pause ) )
324         return VLC_ENOMEM;
325
326     return VLC_SUCCESS;
327 }
328
329 static int
330 MarshalCanControl( intf_thread_t *p_intf, DBusMessageIter *container )
331 {
332     VLC_UNUSED( p_intf );
333     dbus_bool_t b_can_control = TRUE;
334
335     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
336                                          &b_can_control ) )
337         return VLC_ENOMEM;
338
339     return VLC_SUCCESS;
340 }
341
342 static int
343 MarshalCanSeek( intf_thread_t *p_intf, DBusMessageIter *container )
344 {
345     vlc_player_t *player = vlc_playlist_GetPlayer(p_intf->p_sys->playlist);
346     vlc_player_Lock(player);
347     dbus_bool_t b_can_seek = vlc_player_CanSeek(player);
348     vlc_player_Unlock(player);
349
350     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
351                                          &b_can_seek ) )
352         return VLC_ENOMEM;
353
354     return VLC_SUCCESS;
355 }
356
357 static int
358 MarshalShuffle( intf_thread_t *p_intf, DBusMessageIter *container )
359 {
360     vlc_playlist_t *playlist = p_intf->p_sys->playlist;
361     vlc_playlist_Lock(playlist);
362     enum vlc_playlist_playback_order order_mode =
363         vlc_playlist_GetPlaybackOrder(playlist);
364     vlc_playlist_Unlock(playlist);
365
366     dbus_bool_t b_shuffle = order_mode == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM;
367     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN,
368                                          &b_shuffle ))
369         return VLC_ENOMEM;
370
371     return VLC_SUCCESS;
372 }
373
374 DBUS_METHOD( ShuffleSet )
375 {
376     REPLY_INIT;
377     dbus_bool_t b_shuffle;
378
379     if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &b_shuffle ) )
380         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
381
382     vlc_playlist_t *playlist = PL;
383     vlc_playlist_Lock(playlist);
384     vlc_playlist_SetPlaybackOrder(playlist, b_shuffle == TRUE
385             ? VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM
386             : VLC_PLAYLIST_PLAYBACK_ORDER_NORMAL);
387     vlc_playlist_Unlock(playlist);
388
389     REPLY_SEND;
390 }
391
392 static int
393 MarshalPlaybackStatus( intf_thread_t *p_intf, DBusMessageIter *container )
394 {
395     vlc_player_t *player = vlc_playlist_GetPlayer(p_intf->p_sys->playlist);
396     vlc_player_Lock(player);
397     enum vlc_player_state state = vlc_player_GetState(player);
398     vlc_player_Unlock(player);
399
400     const char *psz_playback_status;
401     switch (state)
402     {
403         case VLC_PLAYER_STATE_STARTED:
404         case VLC_PLAYER_STATE_PLAYING:
405             psz_playback_status = PLAYBACK_STATUS_PLAYING;
406             break;
407         case VLC_PLAYER_STATE_PAUSED:
408             psz_playback_status = PLAYBACK_STATUS_PAUSED;
409             break;
410         default:
411             psz_playback_status = PLAYBACK_STATUS_STOPPED;
412     }
413
414     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_STRING,
415                                          &psz_playback_status ) )
416         return VLC_ENOMEM;
417
418     return VLC_SUCCESS;
419 }
420
421 static int
422 MarshalRate( intf_thread_t *p_intf, DBusMessageIter *container )
423 {
424     vlc_player_t *player = vlc_playlist_GetPlayer(p_intf->p_sys->playlist);
425     vlc_player_Lock(player);
426     double d_rate = vlc_player_GetRate(player);
427     vlc_player_Unlock(player);
428
429     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_DOUBLE,
430                                          &d_rate ) )
431         return VLC_ENOMEM;
432
433     return VLC_SUCCESS;
434 }
435
436 DBUS_METHOD( RateSet )
437 {
438     REPLY_INIT;
439
440     double d_rate;
441
442     if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &d_rate ) )
443         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
444
445     vlc_player_t *player = vlc_playlist_GetPlayer(PL);
446     vlc_player_Lock(player);
447     vlc_player_ChangeRate(player, d_rate);
448     vlc_player_Unlock(player);
449
450     REPLY_SEND;
451 }
452
453 static int
454 MarshalMinimumRate( intf_thread_t *p_intf, DBusMessageIter *container )
455 {
456     VLC_UNUSED( p_intf );
457     double d_min_rate = INPUT_RATE_MIN;
458
459     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_DOUBLE, &d_min_rate ) )
460         return VLC_ENOMEM;
461
462     return VLC_SUCCESS;
463 }
464
465 static int
466 MarshalMaximumRate( intf_thread_t *p_intf, DBusMessageIter *container )
467 {
468     VLC_UNUSED( p_intf );
469     double d_max_rate = INPUT_RATE_MAX;
470
471     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_DOUBLE, &d_max_rate ) )
472         return VLC_ENOMEM;
473
474     return VLC_SUCCESS;
475 }
476
477 static int
478 MarshalLoopStatus( intf_thread_t *p_intf, DBusMessageIter *container )
479 {
480     vlc_playlist_t *playlist = p_intf->p_sys->playlist;
481     vlc_playlist_Lock(playlist);
482     enum vlc_playlist_playback_repeat repeat_mode =
483         vlc_playlist_GetPlaybackRepeat(playlist);
484     vlc_playlist_Unlock(playlist);
485
486     const char *psz_loop_status;
487     switch (repeat_mode)
488     {
489         case VLC_PLAYLIST_PLAYBACK_REPEAT_ALL:
490             psz_loop_status = LOOP_STATUS_PLAYLIST;
491             break;
492         case VLC_PLAYLIST_PLAYBACK_REPEAT_CURRENT:
493             psz_loop_status = LOOP_STATUS_TRACK;
494             break;
495         case VLC_PLAYLIST_PLAYBACK_REPEAT_NONE:
496             psz_loop_status = LOOP_STATUS_NONE;
497             break;
498         default:
499             vlc_assert_unreachable();
500     }
501
502     if( !dbus_message_iter_append_basic( container, DBUS_TYPE_STRING,
503                                          &psz_loop_status ) )
504         return VLC_ENOMEM;
505
506     return VLC_SUCCESS;
507 }
508
509 DBUS_METHOD( LoopStatusSet )
510 {
511     REPLY_INIT;
512     char *psz_loop_status;
513
514     if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &psz_loop_status ) )
515         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
516
517     enum vlc_playlist_playback_repeat repeat_mode;
518     if (!strcmp(psz_loop_status, LOOP_STATUS_NONE))
519         repeat_mode = VLC_PLAYLIST_PLAYBACK_REPEAT_NONE;
520     else if (!strcmp(psz_loop_status, LOOP_STATUS_TRACK))
521         repeat_mode = VLC_PLAYLIST_PLAYBACK_REPEAT_CURRENT;
522     else if (!strcmp(psz_loop_status, LOOP_STATUS_PLAYLIST))
523         repeat_mode = VLC_PLAYLIST_PLAYBACK_REPEAT_ALL;
524     else
525         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
526
527     vlc_playlist_t *playlist = PL;
528     vlc_playlist_Lock(playlist);
529     vlc_playlist_SetPlaybackRepeat(playlist, repeat_mode);
530     vlc_playlist_Unlock(playlist);
531
532     REPLY_SEND;
533 }
534
535 static int
536 MarshalMetadata( intf_thread_t *p_intf, DBusMessageIter *container )
537 {
538     int result = VLC_SUCCESS;
539     vlc_playlist_t *playlist = p_intf->p_sys->playlist;
540     vlc_playlist_Lock(playlist);
541     ssize_t id = vlc_playlist_GetCurrentIndex(playlist);
542     if(id != -1)
543     {
544         vlc_playlist_item_t *plitem = vlc_playlist_Get(playlist, id);
545         result = GetInputMeta(playlist, plitem, container);
546     }
547     else
548     {   // avoid breaking the type marshalling
549         DBusMessageIter a;
550         if( !dbus_message_iter_open_container( container, DBUS_TYPE_ARRAY,
551                                                "{sv}", &a ) ||
552             !dbus_message_iter_close_container( container, &a ) )
553             result = VLC_ENOMEM;
554     }
555     vlc_playlist_Unlock(playlist);
556     return result;
557 }
558
559
560 /******************************************************************************
561  * Seeked: non-linear playback signal
562  *****************************************************************************/
563 DBUS_SIGNAL( SeekedSignal )
564 {
565     SIGNAL_INIT( DBUS_MPRIS_PLAYER_INTERFACE,
566                  DBUS_MPRIS_OBJECT_PATH,
567                  "Seeked" );
568
569     OUT_ARGUMENTS;
570
571     dbus_int64_t i_pos = 0;
572     intf_thread_t *p_intf = (intf_thread_t*) p_data;
573     vlc_player_t *player = vlc_playlist_GetPlayer(p_intf->p_sys->playlist);
574     vlc_player_Lock(player);
575     i_pos = vlc_player_GetTime(player);
576     vlc_player_Unlock(player);
577     i_pos = i_pos == VLC_TICK_INVALID ? 0 : US_FROM_VLC_TICK(i_pos);
578
579     ADD_INT64( &i_pos );
580     SIGNAL_SEND;
581 }
582
583 #define PROPERTY_MAPPING_BEGIN
584 #define PROPERTY_GET_FUNC( prop, signature ) \
585     if( !strcmp( psz_property_name,  #prop ) ) { \
586         if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, signature, &v ) ) \
587             return DBUS_HANDLER_RESULT_NEED_MEMORY; \
588         if( VLC_SUCCESS != Marshal##prop( p_this, &v ) ) { \
589             dbus_message_iter_abandon_container( &args, &v ); \
590             return DBUS_HANDLER_RESULT_NEED_MEMORY; \
591         } \
592         if( !dbus_message_iter_close_container( &args, &v ) ) \
593             return DBUS_HANDLER_RESULT_NEED_MEMORY; \
594     } else
595 #define PROPERTY_SET_FUNC( prop ) \
596     if( !strcmp( psz_property_name,  #prop ) ) \
597         return prop##Set( p_conn, p_from, p_this ); \
598     else
599 #define PROPERTY_MAPPING_END return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
600
601 DBUS_METHOD( GetProperty )
602 {
603     DBusError error;
604
605     char *psz_interface_name = NULL;
606     char *psz_property_name  = NULL;
607
608     dbus_error_init( &error );
609     dbus_message_get_args( p_from, &error,
610             DBUS_TYPE_STRING, &psz_interface_name,
611             DBUS_TYPE_STRING, &psz_property_name,
612             DBUS_TYPE_INVALID );
613
614     if( dbus_error_is_set( &error ) )
615     {
616         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
617                                          error.message );
618         dbus_error_free( &error );
619         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
620     }
621
622     msg_Dbg( (vlc_object_t*) p_this, "Getting property %s",
623                                      psz_property_name );
624
625     if( strcmp( psz_interface_name, DBUS_MPRIS_PLAYER_INTERFACE ) ) {
626         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
627     }
628
629     REPLY_INIT;
630     OUT_ARGUMENTS;
631     DBusMessageIter v;
632
633     PROPERTY_MAPPING_BEGIN
634     PROPERTY_GET_FUNC( Metadata,       "a{sv}" )
635     PROPERTY_GET_FUNC( Position,       "x" )
636     PROPERTY_GET_FUNC( PlaybackStatus, "s" )
637     PROPERTY_GET_FUNC( LoopStatus,     "s" )
638     PROPERTY_GET_FUNC( Shuffle,        "b" )
639     PROPERTY_GET_FUNC( Volume,         "d" )
640     PROPERTY_GET_FUNC( Rate,           "d" )
641     PROPERTY_GET_FUNC( MinimumRate,    "d" )
642     PROPERTY_GET_FUNC( MaximumRate,    "d" )
643     PROPERTY_GET_FUNC( CanControl,     "b" )
644     PROPERTY_GET_FUNC( CanPlay,        "b" )
645     PROPERTY_GET_FUNC( CanGoNext,      "b" )
646     PROPERTY_GET_FUNC( CanGoPrevious,  "b" )
647     PROPERTY_GET_FUNC( CanPause,       "b" )
648     PROPERTY_GET_FUNC( CanSeek,        "b" )
649     PROPERTY_MAPPING_END
650
651     REPLY_SEND;
652 }
653
654 DBUS_METHOD( SetProperty )
655 {
656     DBusError error;
657
658     char *psz_interface_name = NULL;
659     char *psz_property_name  = NULL;
660
661     dbus_error_init( &error );
662     dbus_message_get_args( p_from, &error,
663             DBUS_TYPE_STRING, &psz_interface_name,
664             DBUS_TYPE_STRING, &psz_property_name,
665             DBUS_TYPE_INVALID );
666
667     if( dbus_error_is_set( &error ) )
668     {
669         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
670                                          error.message );
671         dbus_error_free( &error );
672         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
673     }
674
675     PROPERTY_MAPPING_BEGIN
676     PROPERTY_SET_FUNC( LoopStatus )
677     PROPERTY_SET_FUNC( Shuffle )
678     PROPERTY_SET_FUNC( Volume )
679     PROPERTY_SET_FUNC( Rate )
680     PROPERTY_MAPPING_END
681 }
682
683 #undef PROPERTY_MAPPING_BEGIN
684 #undef PROPERTY_GET_FUNC
685 #undef PROPERTY_SET_FUNC
686 #undef PROPERTY_MAPPING_END
687
688 #define ADD_PROPERTY( prop, signature ) \
689     if( VLC_SUCCESS != AddProperty( (intf_thread_t*) p_this, \
690                 &dict, #prop, signature, Marshal##prop ) ) { \
691         dbus_message_iter_abandon_container( &args, &dict ); \
692         return VLC_ENOMEM; \
693     }
694
695 DBUS_METHOD( GetAllProperties )
696 {
697     REPLY_INIT;
698     OUT_ARGUMENTS;
699
700     DBusError error;
701     DBusMessageIter dict;
702
703     char *const psz_interface_name = NULL;
704
705     dbus_error_init( &error );
706     dbus_message_get_args( p_from, &error,
707             DBUS_TYPE_STRING, &psz_interface_name,
708             DBUS_TYPE_INVALID );
709
710     if( dbus_error_is_set( &error ) )
711     {
712         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
713                                          error.message );
714         dbus_error_free( &error );
715         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
716     }
717
718     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "{sv}", &dict ) )
719         return DBUS_HANDLER_RESULT_NEED_MEMORY;
720
721     ADD_PROPERTY ( Metadata,       "a{sv}" );
722     ADD_PROPERTY ( Position,       "x"     );
723     ADD_PROPERTY ( PlaybackStatus, "s"     );
724     ADD_PROPERTY ( LoopStatus,     "s"     );
725     ADD_PROPERTY ( Shuffle,        "b"     );
726     ADD_PROPERTY ( Volume,         "d"     );
727     ADD_PROPERTY ( Rate,           "d"     );
728     ADD_PROPERTY ( MinimumRate,    "d"     );
729     ADD_PROPERTY ( MaximumRate,    "d"     );
730     ADD_PROPERTY ( CanControl,     "b"     );
731     ADD_PROPERTY ( CanPlay,        "b"     );
732     ADD_PROPERTY ( CanGoNext,      "b"     );
733     ADD_PROPERTY ( CanGoPrevious,  "b"     );
734     ADD_PROPERTY ( CanPause,       "b"     );
735     ADD_PROPERTY ( CanSeek,        "b"     );
736
737     if( !dbus_message_iter_close_container( &args, &dict ))
738         return DBUS_HANDLER_RESULT_NEED_MEMORY;
739
740     REPLY_SEND;
741 }
742
743 #undef ADD_PROPERTY
744
745 #define METHOD_FUNC( interface, method, function ) \
746     else if( dbus_message_is_method_call( p_from, interface, method ) )\
747         return function( p_conn, p_from, p_this )
748
749 DBusHandlerResult
750 handle_player ( DBusConnection *p_conn, DBusMessage *p_from, void *p_this )
751 {
752     if(0);
753     METHOD_FUNC( DBUS_INTERFACE_PROPERTIES,   "Get",        GetProperty );
754     METHOD_FUNC( DBUS_INTERFACE_PROPERTIES,   "Set",        SetProperty );
755     METHOD_FUNC( DBUS_INTERFACE_PROPERTIES,   "GetAll",     GetAllProperties );
756
757     /* here D-Bus method names are associated to an handler */
758
759     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Previous",     Prev );
760     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Next",         Next );
761     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Stop",         Stop );
762     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Seek",         Seek );
763     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Play",         Play );
764     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Pause",        Pause );
765     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "PlayPause",    PlayPause );
766     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "OpenUri",      OpenUri );
767     METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "SetPosition",  SetPosition );
768
769     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
770 }
771
772 #undef METHOD_FUNC
773
774 /*****************************************************************************
775  * SeekedEmit: Emits the Seeked signal
776  *****************************************************************************/
777 int SeekedEmit( intf_thread_t * p_intf )
778 {
779     if( p_intf->p_sys->b_dead )
780         return VLC_SUCCESS;
781
782     SeekedSignal( p_intf->p_sys->p_conn, p_intf );
783     return VLC_SUCCESS;
784 }
785
786 #define PROPERTY_MAPPING_BEGIN if( 0 ) {}
787 #define PROPERTY_ENTRY( prop, signature ) \
788     else if( !strcmp( ppsz_properties[i], #prop ) ) \
789     { \
790         if( VLC_SUCCESS != AddProperty( (intf_thread_t*) p_intf, \
791                     &changed_properties, #prop, signature, Marshal##prop ) ) \
792             { \
793                 for( ; ppsz_properties[i]; ++i ) free( ppsz_properties[i] ); \
794                 free( ppsz_properties ); \
795                 dbus_message_iter_abandon_container( &args, &changed_properties ); \
796                 return DBUS_HANDLER_RESULT_NEED_MEMORY; \
797             } \
798     }
799 #define PROPERTY_MAPPING_END else \
800     { \
801         for( ; ppsz_properties[i]; ++i ) free( ppsz_properties[i] ); \
802         free( ppsz_properties ); \
803         dbus_message_iter_abandon_container( &args, &changed_properties ); \
804         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; \
805     }
806
807 /**
808  * PropertiesChangedSignal() synthetizes and sends the
809  * org.freedesktop.DBus.Properties.PropertiesChanged signal
810  */
811 static DBusHandlerResult
812 PropertiesChangedSignal( intf_thread_t    *p_intf,
813                          vlc_dictionary_t *p_changed_properties )
814 {
815     DBusConnection  *p_conn = p_intf->p_sys->p_conn;
816     DBusMessageIter changed_properties, invalidated_properties;
817     const char *psz_interface_name = DBUS_MPRIS_PLAYER_INTERFACE;
818     char **ppsz_properties = NULL;
819
820     SIGNAL_INIT( DBUS_INTERFACE_PROPERTIES,
821                  DBUS_MPRIS_OBJECT_PATH,
822                  "PropertiesChanged" );
823
824     OUT_ARGUMENTS;
825     ADD_STRING( &psz_interface_name );
826
827     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "{sv}",
828                                            &changed_properties ) )
829         return DBUS_HANDLER_RESULT_NEED_MEMORY;
830
831     ppsz_properties = vlc_dictionary_all_keys( p_changed_properties );
832
833     if( unlikely(!ppsz_properties) )
834     {
835         dbus_message_iter_abandon_container( &args, &changed_properties );
836         return DBUS_HANDLER_RESULT_NEED_MEMORY;
837     }
838
839     for( int i = 0; ppsz_properties[i]; i++ )
840     {
841         PROPERTY_MAPPING_BEGIN
842         PROPERTY_ENTRY( Metadata,       "a{sv}" )
843         PROPERTY_ENTRY( PlaybackStatus, "s"     )
844         PROPERTY_ENTRY( LoopStatus,     "s"     )
845         PROPERTY_ENTRY( Rate,           "d"     )
846         PROPERTY_ENTRY( Shuffle,        "b"     )
847         PROPERTY_ENTRY( Volume,         "d"     )
848         PROPERTY_ENTRY( CanSeek,        "b"     )
849         PROPERTY_ENTRY( CanPlay,        "b"     )
850         PROPERTY_ENTRY( CanPause,       "b"     )
851         PROPERTY_MAPPING_END
852
853         free( ppsz_properties[i] );
854     }
855
856     free( ppsz_properties );
857
858     if( !dbus_message_iter_close_container( &args, &changed_properties ) )
859         return DBUS_HANDLER_RESULT_NEED_MEMORY;
860
861     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "s",
862                                            &invalidated_properties ) )
863         return DBUS_HANDLER_RESULT_NEED_MEMORY;
864
865     if( !dbus_message_iter_close_container( &args, &invalidated_properties ) )
866         return DBUS_HANDLER_RESULT_NEED_MEMORY;
867
868     SIGNAL_SEND;
869 }
870
871 #undef PROPERTY_MAPPING_BEGIN
872 #undef PROPERTY_ADD
873 #undef PROPERTY_MAPPING_END
874
875 /*****************************************************************************
876  * PropertiesChangedEmit: Emits the Seeked signal
877  *****************************************************************************/
878 int PlayerPropertiesChangedEmit( intf_thread_t    * p_intf,
879                                  vlc_dictionary_t * p_changed_properties )
880 {
881     if( p_intf->p_sys->b_dead )
882         return VLC_SUCCESS;
883
884     PropertiesChangedSignal( p_intf, p_changed_properties );
885     return VLC_SUCCESS;
886 }