]> git.sesse.net Git - vlc/blob - modules/control/dbus.c
Remove _GNU_SOURCE and string.h too
[vlc] / modules / control / dbus.c
1 /*****************************************************************************
2  * dbus.c : D-Bus control interface
3  *****************************************************************************
4  * Copyright (C) 2006 Rafaël Carré
5  * $Id$
6  *
7  * Authors:    Rafaël Carré <funman at videolanorg>
8  *             Mirsal Ennaime <mirsal dot ennaime at gmail dot com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*
26  * D-Bus Specification:
27  *      http://dbus.freedesktop.org/doc/dbus-specification.html
28  * D-Bus low-level C API (libdbus)
29  *      http://dbus.freedesktop.org/doc/dbus/api/html/index.html
30  *  extract:
31     "If you use this low-level API directly, you're signing up for some pain."
32  * MPRIS Specification (still drafting on June, 25 of 2007):
33  *      http://wiki.xmms2.xmms.se/index.php/Media_Player_Interfaces
34  */
35
36 /*****************************************************************************
37  * Preamble
38  *****************************************************************************/
39
40 #include <dbus/dbus.h>
41 #include <stdio.h>
42
43 #include "dbus.h"
44
45 #include <vlc/vlc.h>
46 #include <vlc_aout.h>
47 #include <vlc_interface.h>
48 #include <vlc_meta.h>
49 #include <vlc_input.h>
50 #include <vlc_playlist.h>
51
52 /*****************************************************************************
53  * Local prototypes.
54  *****************************************************************************/
55
56 static int  Open    ( vlc_object_t * );
57 static void Close   ( vlc_object_t * );
58 static void Run     ( intf_thread_t * );
59
60 static int TrackChange( vlc_object_t *p_this, const char *psz_var,
61                     vlc_value_t oldval, vlc_value_t newval, void *p_data );
62
63 static int GetInputMeta ( input_item_t *p_input, 
64                     DBusMessageIter *args);
65
66 struct intf_sys_t
67 {
68     DBusConnection *p_conn;
69 };
70
71 /*****************************************************************************
72  * Module descriptor
73  *****************************************************************************/
74
75 vlc_module_begin();
76     set_shortname( _("dbus"));
77     set_category( CAT_INTERFACE );
78     set_subcategory( SUBCAT_INTERFACE_CONTROL );
79     set_description( _("D-Bus control interface") );
80     set_capability( "interface", 0 );
81     set_callbacks( Open, Close );
82 vlc_module_end();
83
84 /*****************************************************************************
85  * Methods
86  *****************************************************************************/
87 #if 0
88 DBUS_METHOD( PlaylistExport_XSPF )
89 { /*export playlist to an xspf file */
90
91   /* reads the filename to export to */
92   /* returns the status as int32:
93    *    0 : success
94    *    1 : error
95    *    2 : playlist empty
96    */
97     REPLY_INIT;
98     OUT_ARGUMENTS;
99
100     DBusError error; 
101     dbus_error_init( &error );
102
103     char *psz_file;
104     dbus_int32_t i_ret;
105
106     dbus_message_get_args( p_from, &error,
107             DBUS_TYPE_STRING, &psz_file,
108             DBUS_TYPE_INVALID );
109
110     if( dbus_error_is_set( &error ) )
111     {
112         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s\n",
113                 error.message );
114         dbus_error_free( &error );
115         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
116     }
117
118     playlist_t *p_playlist = pl_Yield( (vlc_object_t*) p_this );
119
120     if( ( !playlist_IsEmpty( p_playlist ) ) &&
121             ( p_playlist->p_root_category->i_children > 0 ) )
122     {
123         if( playlist_Export( p_playlist, psz_file,
124                          p_playlist->p_root_category->pp_children[0],
125                          "export-xspf" ) == VLC_SUCCESS )
126             i_ret = 0;
127         else
128             i_ret = 1;
129     }
130     else
131         i_ret = 2;
132
133     pl_Release( ((vlc_object_t*) p_this ) );
134
135     ADD_INT32( &i_ret );
136     REPLY_SEND;
137 }
138 #endif
139
140 /* Player */
141
142 DBUS_METHOD( Quit )
143 { /* exits vlc */
144     REPLY_INIT;
145     playlist_t *p_playlist = pl_Yield( (vlc_object_t*) p_this );
146     playlist_Stop( p_playlist );
147     pl_Release( ((vlc_object_t*) p_this) );
148     vlc_object_kill(((vlc_object_t*)p_this)->p_libvlc);
149     REPLY_SEND;
150 }
151
152 DBUS_METHOD( PositionGet )
153 { /* returns position as an int in the range [0;1000] */
154     REPLY_INIT;
155     OUT_ARGUMENTS;
156     vlc_value_t position;
157     dbus_int32_t i_pos;
158
159     playlist_t *p_playlist = pl_Yield( ((vlc_object_t*) p_this) );
160     input_thread_t *p_input = p_playlist->p_input;
161
162     if( !p_input )
163         i_pos = 0;
164     else
165     {
166         var_Get( p_input, "position", &position );
167         i_pos = position.f_float * 1000 ;
168     }
169     pl_Release( ((vlc_object_t*) p_this) );
170     ADD_INT32( &i_pos );
171     REPLY_SEND;
172 }
173
174 DBUS_METHOD( PositionSet )
175 { /* set position from an int in the range [0;1000] */
176
177     REPLY_INIT;
178     vlc_value_t position;
179     playlist_t* p_playlist = NULL;
180     dbus_int32_t i_pos;
181
182     DBusError error;
183     dbus_error_init( &error );
184
185     dbus_message_get_args( p_from, &error,
186             DBUS_TYPE_INT32, &i_pos,
187             DBUS_TYPE_INVALID );
188
189     if( dbus_error_is_set( &error ) )
190     {
191         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s\n",
192                 error.message );
193         dbus_error_free( &error );
194         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
195     }
196     p_playlist = pl_Yield( ((vlc_object_t*) p_this) );
197     input_thread_t *p_input = p_playlist->p_input;
198
199     if( p_input )
200     {
201         position.f_float = ((float)i_pos) / 1000;
202         var_Set( p_input, "position", position );
203     }
204     pl_Release( ((vlc_object_t*) p_this) );
205     REPLY_SEND;
206 }
207
208 DBUS_METHOD( VolumeGet )
209 { /* returns volume in percentage */
210     REPLY_INIT;
211     OUT_ARGUMENTS;
212     dbus_int32_t i_dbus_vol;
213     audio_volume_t i_vol;
214     /* 2nd argument of aout_VolumeGet is int32 */
215     aout_VolumeGet( (vlc_object_t*) p_this, &i_vol );
216     i_dbus_vol = ( 100 * i_vol ) / AOUT_VOLUME_MAX;
217     ADD_INT32( &i_dbus_vol );
218     REPLY_SEND;
219 }
220
221 DBUS_METHOD( VolumeSet )
222 { /* set volume in percentage */
223     REPLY_INIT;
224
225     DBusError error;
226     dbus_error_init( &error );
227
228     dbus_int32_t i_dbus_vol;
229     audio_volume_t i_vol;
230
231     dbus_message_get_args( p_from, &error,
232             DBUS_TYPE_INT32, &i_dbus_vol,
233             DBUS_TYPE_INVALID );
234
235     if( dbus_error_is_set( &error ) )
236     {
237         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s\n",
238                 error.message );
239         dbus_error_free( &error );
240         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
241     }
242
243     i_vol = ( AOUT_VOLUME_MAX / 100 ) *i_dbus_vol;
244     aout_VolumeSet( (vlc_object_t*) p_this, i_vol );
245
246     REPLY_SEND;
247 }
248
249 DBUS_METHOD( Next )
250 { /* next playlist item */
251     REPLY_INIT;
252     playlist_t *p_playlist = pl_Yield( ((vlc_object_t*) p_this) );
253     playlist_Next( p_playlist );
254     pl_Release( ((vlc_object_t*) p_this) );
255     REPLY_SEND;
256 }
257
258 DBUS_METHOD( Prev )
259 { /* previous playlist item */
260     REPLY_INIT;
261     playlist_t *p_playlist = pl_Yield( ((vlc_object_t*) p_this) );
262     playlist_Prev( p_playlist );
263     pl_Release( ((vlc_object_t*) p_this) );
264     REPLY_SEND;
265 }
266
267 DBUS_METHOD( Stop )
268 { /* stop playing */
269     REPLY_INIT;
270     playlist_t *p_playlist = pl_Yield( ((vlc_object_t*) p_this) );
271     playlist_Stop( p_playlist );
272     pl_Release( ((vlc_object_t*) p_this) );
273     REPLY_SEND;
274 }
275
276 DBUS_METHOD( GetStatus )
277 { /* returns an int: 0=playing 1=paused 2=stopped */
278     REPLY_INIT;
279     OUT_ARGUMENTS;
280
281     dbus_int32_t i_status;
282     vlc_value_t val;
283
284     playlist_t *p_playlist = pl_Yield( (vlc_object_t*) p_this );
285     input_thread_t *p_input = p_playlist->p_input;
286
287     i_status = 2;
288     if( p_input )
289     {
290         var_Get( p_input, "state", &val );
291         if( val.i_int == PAUSE_S )
292             i_status = 1;
293         else if( val.i_int == PLAYING_S )
294             i_status = 0;
295     }
296
297     pl_Release( p_playlist );
298
299     ADD_INT32( &i_status );
300     REPLY_SEND;
301 }
302
303 DBUS_METHOD( Pause )
304 {
305     REPLY_INIT;
306     playlist_t *p_playlist = pl_Yield( (vlc_object_t*) p_this );
307     playlist_Pause( p_playlist );
308     pl_Release( p_playlist );
309     REPLY_SEND;
310 }
311
312 DBUS_METHOD( Play )
313 {
314     REPLY_INIT;
315     playlist_t *p_playlist = pl_Yield( (vlc_object_t*) p_this );
316     playlist_Play( p_playlist );
317     pl_Release( p_playlist );
318     REPLY_SEND;
319 }
320
321 DBUS_METHOD( Disconnect )
322 {
323     REPLY_INIT;
324     DBusError error;
325     int i;
326     dbus_error_init( &error );
327     i = dbus_bus_release_name( p_conn, "org.mpris.vlc", &error );
328     if( ( i == -1 ) && ( dbus_error_is_set( &error ) ) )
329     {
330         msg_Err( (vlc_object_t*) p_this, "D-Bus disconnection failed : %s\n",
331             error.message );
332         dbus_error_free( &error );
333     }
334     REPLY_SEND;
335 }
336
337 DBUS_METHOD( GetCurrentMetadata )
338 {
339     REPLY_INIT;
340     OUT_ARGUMENTS;
341     playlist_t* p_playlist = pl_Yield( (vlc_object_t*) p_this );
342
343     GetInputMeta( p_playlist->status.p_item->p_input, &args );
344
345     pl_Release( p_playlist );
346     REPLY_SEND;
347 }
348
349 /* Media Player information */
350
351 DBUS_METHOD( Identity )
352 {
353     REPLY_INIT;
354     OUT_ARGUMENTS;
355     char *psz_identity = malloc( strlen( PACKAGE ) + strlen( VERSION ) + 1 );
356     sprintf( psz_identity, "%s %s", PACKAGE, VERSION );
357     ADD_STRING( &psz_identity );
358     free( psz_identity );
359     REPLY_SEND;
360 }
361
362 /* TrackList */
363
364 DBUS_METHOD( AddTrack )
365 { /* add the string to the playlist, and play it if the boolean is true */
366     REPLY_INIT;
367
368     DBusError error;
369     dbus_error_init( &error );
370     playlist_t* p_playlist = NULL;
371
372     char *psz_mrl;
373     dbus_bool_t b_play;
374
375     dbus_message_get_args( p_from, &error,
376             DBUS_TYPE_STRING, &psz_mrl,
377             DBUS_TYPE_BOOLEAN, &b_play,
378             DBUS_TYPE_INVALID );
379
380     if( dbus_error_is_set( &error ) )
381     {
382         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s\n",
383                 error.message );
384         dbus_error_free( &error );
385         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
386     }
387
388     p_playlist = pl_Yield( (vlc_object_t*) p_this );
389     playlist_Add( p_playlist, psz_mrl, NULL, PLAYLIST_APPEND |
390             ( ( b_play == TRUE ) ? PLAYLIST_GO : 0 ) ,
391             PLAYLIST_END, VLC_TRUE, VLC_FALSE );
392     pl_Release( p_playlist );
393
394     REPLY_SEND;
395 }
396
397 DBUS_METHOD( GetCurrentTrack )
398 {
399     REPLY_INIT;
400     OUT_ARGUMENTS;
401     dbus_int32_t i_position = 0;
402     playlist_t *p_playlist = pl_Yield( (vlc_object_t*) p_this );
403     playlist_item_t* p_tested_item = p_playlist->p_root_onelevel;
404
405     while ( p_tested_item->p_input->i_id !=
406                     p_playlist->status.p_item->p_input->i_id )
407     {
408         i_position++;
409         TEST_NEXT;
410     }
411
412     pl_Release( p_playlist );
413
414     ADD_INT32( &i_position );
415     REPLY_SEND;
416 }
417
418 DBUS_METHOD( GetMetadata )
419 {
420     REPLY_INIT;
421     OUT_ARGUMENTS;
422     DBusError error;
423     dbus_error_init( &error );
424
425     dbus_int32_t i_position, i_count = 0;
426
427     playlist_t *p_playlist = pl_Yield( (vlc_object_t*) p_this );
428     playlist_item_t* p_tested_item = p_playlist->p_root_onelevel;
429
430     dbus_message_get_args( p_from, &error,
431             DBUS_TYPE_INT32, &i_position,
432             DBUS_TYPE_INVALID );
433
434     if( dbus_error_is_set( &error ) )
435     {
436         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s\n",
437                 error.message );
438         dbus_error_free( &error );
439         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
440     }
441
442     while ( i_count < i_position ) 
443     {
444         i_count++;
445         TEST_NEXT;
446     }
447
448     GetInputMeta ( p_tested_item->p_input, &args );
449
450     pl_Release( p_playlist );
451     REPLY_SEND;
452 }
453
454 DBUS_METHOD( GetLength )
455 {
456     REPLY_INIT;
457     OUT_ARGUMENTS;
458
459     dbus_int32_t i_elements = 0;
460     playlist_t *p_playlist = pl_Yield( (vlc_object_t*) p_this );
461     playlist_item_t* p_tested_item = p_playlist->p_root_onelevel;
462     playlist_item_t* p_last_item = playlist_GetLastLeaf( p_playlist,
463                     p_playlist->p_root_onelevel ); 
464
465     while ( p_tested_item->p_input->i_id != p_last_item->p_input->i_id )
466     {
467         i_elements++;
468         TEST_NEXT;
469     }
470
471     pl_Release( p_playlist );
472
473     ADD_INT32( &i_elements );
474     REPLY_SEND;
475 }
476
477 DBUS_METHOD( DelTrack )
478 {
479     REPLY_INIT;
480
481     DBusError error;
482     dbus_error_init( &error );
483
484     dbus_int32_t i_position, i_count = 0;
485     playlist_t *p_playlist = pl_Yield( (vlc_object_t*) p_this );
486     playlist_item_t* p_tested_item = p_playlist->p_root_onelevel;
487
488     dbus_message_get_args( p_from, &error,
489             DBUS_TYPE_INT32, &i_position,
490             DBUS_TYPE_INVALID );
491
492     if( dbus_error_is_set( &error ) )
493     {
494         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s\n",
495                 error.message );
496         dbus_error_free( &error );
497         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
498     }
499
500     while ( i_count < i_position ) 
501     {
502         i_count++;
503         TEST_NEXT;
504     }
505
506     PL_LOCK; 
507     playlist_DeleteFromInput( p_playlist,
508         p_tested_item->p_input->i_id,
509         VLC_TRUE );
510     PL_UNLOCK;
511
512     pl_Release( p_playlist );
513
514     REPLY_SEND;
515 }
516
517 DBUS_METHOD( Loop )
518 {
519     REPLY_INIT;
520     OUT_ARGUMENTS;
521
522     DBusError error;
523     dbus_bool_t b_loop;
524     vlc_value_t val;
525     playlist_t* p_playlist = NULL;
526
527     dbus_error_init( &error );
528     dbus_message_get_args( p_from, &error,
529             DBUS_TYPE_BOOLEAN, &b_loop,
530             DBUS_TYPE_INVALID );
531
532     if( dbus_error_is_set( &error ) )
533     {
534         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s\n",
535                 error.message );
536         dbus_error_free( &error );
537         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
538     }
539
540     val.b_bool = ( b_loop == TRUE ) ? VLC_TRUE : VLC_FALSE ;
541     p_playlist = pl_Yield( (vlc_object_t*) p_this );
542     var_Set ( p_playlist, "loop", val );
543     pl_Release( ((vlc_object_t*) p_this) );
544
545     REPLY_SEND;
546 }
547
548 DBUS_METHOD( Repeat )
549 {
550     REPLY_INIT;
551     OUT_ARGUMENTS;
552
553     DBusError error;
554     dbus_bool_t b_repeat;
555     vlc_value_t val;
556     playlist_t* p_playlist = NULL;
557
558     dbus_error_init( &error );
559     dbus_message_get_args( p_from, &error,
560             DBUS_TYPE_BOOLEAN, &b_repeat,
561             DBUS_TYPE_INVALID );
562
563     if( dbus_error_is_set( &error ) )
564     {
565         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s\n",
566                 error.message );
567         dbus_error_free( &error );
568         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
569     }
570
571     val.b_bool = ( b_repeat == TRUE ) ? VLC_TRUE : VLC_FALSE ;
572
573     p_playlist = pl_Yield( (vlc_object_t*) p_this );
574     var_Set ( p_playlist, "repeat", val );
575     pl_Release( ((vlc_object_t*) p_this) );
576
577     REPLY_SEND;
578 }
579
580 DBUS_METHOD( Random )
581 {
582     REPLY_INIT;
583     OUT_ARGUMENTS;
584
585     DBusError error;
586     dbus_bool_t b_random;
587     vlc_value_t val;
588     playlist_t* p_playlist = NULL;
589     
590     dbus_error_init( &error );
591     dbus_message_get_args( p_from, &error,
592             DBUS_TYPE_BOOLEAN, &b_random,
593             DBUS_TYPE_INVALID );
594     
595     if( dbus_error_is_set( &error ) )
596     {
597         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s\n",
598                 error.message );
599         dbus_error_free( &error );
600         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
601     }
602
603     val.b_bool = ( b_random == TRUE ) ? VLC_TRUE : VLC_FALSE ;
604     
605     p_playlist = pl_Yield( (vlc_object_t*) p_this );
606     var_Set ( p_playlist, "random", val );
607     pl_Release( ((vlc_object_t*) p_this) );
608
609     REPLY_SEND;
610 }
611 /*****************************************************************************
612  * Introspection method
613  *****************************************************************************/
614
615 DBUS_METHOD( handle_introspect_root )
616 { /* handles introspection of root object */
617     REPLY_INIT;
618     OUT_ARGUMENTS;
619     ADD_STRING( &psz_introspection_xml_data_root );
620     REPLY_SEND;
621 }
622
623 DBUS_METHOD( handle_introspect_player )
624 {
625     REPLY_INIT;
626     OUT_ARGUMENTS;
627     ADD_STRING( &psz_introspection_xml_data_player );
628     REPLY_SEND;
629 }
630
631 DBUS_METHOD( handle_introspect_tracklist )
632 {
633     REPLY_INIT;
634     OUT_ARGUMENTS;
635     ADD_STRING( &psz_introspection_xml_data_tracklist );
636     REPLY_SEND;
637 }
638
639 /*****************************************************************************
640  * handle_*: answer to incoming messages
641  *****************************************************************************/
642
643 #define METHOD_FUNC( method, function ) \
644     else if( dbus_message_is_method_call( p_from, VLC_DBUS_INTERFACE, method ) )\
645         return function( p_conn, p_from, p_this )
646
647 DBUS_METHOD( handle_root )
648 {
649
650     if( dbus_message_is_method_call( p_from,
651                 DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
652         return handle_introspect_root( p_conn, p_from, p_this );
653
654     /* here D-Bus method's names are associated to an handler */
655
656     METHOD_FUNC( "Identity",                Identity );
657
658     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
659 }
660
661
662 DBUS_METHOD( handle_player )
663 {
664     if( dbus_message_is_method_call( p_from,
665                 DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
666     return handle_introspect_player( p_conn, p_from, p_this );
667
668     /* here D-Bus method's names are associated to an handler */
669
670     METHOD_FUNC( "Prev",                    Prev );
671     METHOD_FUNC( "Next",                    Next );
672     METHOD_FUNC( "Quit",                    Quit );
673     METHOD_FUNC( "Stop",                    Stop );
674     METHOD_FUNC( "Play",                    Play );
675     METHOD_FUNC( "Pause",                   Pause );
676     METHOD_FUNC( "Repeat",                  Repeat );
677     METHOD_FUNC( "Disconnect",              Disconnect );
678     METHOD_FUNC( "VolumeSet",               VolumeSet );
679     METHOD_FUNC( "VolumeGet",               VolumeGet );
680     METHOD_FUNC( "PositionSet",             PositionSet );
681     METHOD_FUNC( "PositionGet",             PositionGet );
682     METHOD_FUNC( "GetStatus",               GetStatus );
683     METHOD_FUNC( "GetMetadata",             GetCurrentMetadata );
684
685     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
686 }
687
688 DBUS_METHOD( handle_tracklist )
689 {
690     if( dbus_message_is_method_call( p_from,
691                 DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
692     return handle_introspect_tracklist( p_conn, p_from, p_this );
693
694     /* here D-Bus method's names are associated to an handler */
695
696     METHOD_FUNC( "GetMetadata",             GetMetadata );
697     METHOD_FUNC( "GetCurrentTrack",         GetCurrentTrack );
698     METHOD_FUNC( "GetLength",               GetLength );
699     METHOD_FUNC( "AddTrack",                AddTrack );
700     METHOD_FUNC( "DelTrack",                DelTrack );
701     METHOD_FUNC( "Loop",                    Loop );
702     METHOD_FUNC( "Random",                  Random );
703
704     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
705 }
706
707 /*****************************************************************************
708  * Open: initialize interface
709  *****************************************************************************/
710
711 static int Open( vlc_object_t *p_this )
712 { /* initialisation of the connection */
713     intf_thread_t   *p_intf = (intf_thread_t*)p_this;
714     intf_sys_t      *p_sys  = malloc( sizeof( intf_sys_t ) );
715     playlist_t      *p_playlist;
716     DBusConnection  *p_conn;
717     DBusError       error;
718
719     if( !p_sys )
720         return VLC_ENOMEM;
721
722     dbus_threads_init_default();
723
724     dbus_error_init( &error );
725
726     /* connect to the session bus */
727     p_conn = dbus_bus_get( DBUS_BUS_SESSION, &error );
728     if( !p_conn )
729     {
730         msg_Err( p_this, "Failed to connect to the D-Bus session daemon: %s",
731                 error.message );
732         dbus_error_free( &error );
733         free( p_sys );
734         return VLC_EGENERIC;
735     }
736
737     /* register a well-known name on the bus */
738     dbus_bus_request_name( p_conn, "org.mpris.vlc", 0, &error );
739     if( dbus_error_is_set( &error ) )
740     {
741         msg_Err( p_this, "Error requesting org.mpris.vlc service:"                " %s\n", error.message );
742         dbus_error_free( &error );
743         free( p_sys );
744         return VLC_EGENERIC;
745     }
746
747     /* we register the objects */
748     dbus_connection_register_object_path( p_conn, VLC_DBUS_ROOT_PATH,
749             &vlc_dbus_root_vtable, p_this );
750     dbus_connection_register_object_path( p_conn, VLC_DBUS_PLAYER_PATH,
751             &vlc_dbus_player_vtable, p_this );
752     dbus_connection_register_object_path( p_conn, VLC_DBUS_TRACKLIST_PATH,
753             &vlc_dbus_tracklist_vtable, p_this );
754
755     dbus_connection_flush( p_conn );
756
757     p_playlist = pl_Yield( p_intf );
758     PL_LOCK;
759     var_AddCallback( p_playlist, "playlist-current", TrackChange, p_intf );
760     PL_UNLOCK;
761     pl_Release( p_playlist );
762
763     p_intf->pf_run = Run;
764     p_intf->p_sys = p_sys;
765     p_sys->p_conn = p_conn;
766
767     return VLC_SUCCESS;
768 }
769
770 /*****************************************************************************
771  * Close: destroy interface
772  *****************************************************************************/
773
774 static void Close   ( vlc_object_t *p_this )
775 {
776     intf_thread_t   *p_intf     = (intf_thread_t*) p_this;
777     playlist_t      *p_playlist = pl_Yield( p_intf );;
778
779     PL_LOCK;
780     var_DelCallback( p_playlist, "playlist-current", TrackChange, p_intf );
781     PL_UNLOCK;
782     pl_Release( p_playlist );
783
784     dbus_connection_unref( p_intf->p_sys->p_conn );
785
786     free( p_intf->p_sys );
787 }
788
789 /*****************************************************************************
790  * Run: main loop
791  *****************************************************************************/
792
793 static void Run          ( intf_thread_t *p_intf )
794 {
795     while( !p_intf->b_die )
796     {
797         msleep( INTF_IDLE_SLEEP );
798         dbus_connection_read_write_dispatch( p_intf->p_sys->p_conn, 0 );
799     }
800 }
801
802 /*****************************************************************************
803  * TrackChange: Playlist item change callback
804  *****************************************************************************/
805
806 DBUS_SIGNAL( TrackChangeSignal )
807 { /* emit the metadata of the new item */
808     SIGNAL_INIT( "TrackChange" );
809     OUT_ARGUMENTS;
810
811     input_thread_t *p_input = (input_thread_t*) p_data;
812     GetInputMeta ( input_GetItem(p_input), &args );
813
814     SIGNAL_SEND;
815 }
816
817 static int TrackChange( vlc_object_t *p_this, const char *psz_var,
818             vlc_value_t oldval, vlc_value_t newval, void *p_data )
819 {
820     intf_thread_t       *p_intf     = ( intf_thread_t* ) p_data;
821     intf_sys_t          *p_sys      = p_intf->p_sys;
822     playlist_t          *p_playlist;
823     input_thread_t      *p_input    = NULL;
824     (void)p_this; (void)psz_var; (void)oldval; (void)newval;
825
826     p_playlist = pl_Yield( p_intf );
827     PL_LOCK;
828     p_input = p_playlist->p_input;
829
830     if( !p_input )
831     {
832         PL_UNLOCK;
833         pl_Release( p_playlist );
834         return VLC_SUCCESS;
835     }
836
837     vlc_object_yield( p_input );
838     PL_UNLOCK;
839     pl_Release( p_playlist );
840
841     TrackChangeSignal( p_sys->p_conn, p_input );
842
843     vlc_object_release( p_input );
844     return VLC_SUCCESS;
845 }
846
847 /*****************************************************************************
848  * GetInputMeta: Fill a DBusMessage with the given input item metadata
849  *****************************************************************************/
850
851 #define ADD_META( entry, type, data ) \
852     if( data ) { \
853         dbus_message_iter_open_container( &dict, DBUS_TYPE_DICT_ENTRY, \
854                 NULL, &dict_entry ); \
855         dbus_message_iter_append_basic( &dict_entry, DBUS_TYPE_STRING, \
856                 &ppsz_meta_items[entry] ); \
857         dbus_message_iter_open_container( &dict_entry, DBUS_TYPE_VARIANT, \
858                 type##_AS_STRING, &variant ); \
859         dbus_message_iter_append_basic( &variant, \
860                 type, \
861                 & data ); \
862         dbus_message_iter_close_container( &dict_entry, &variant ); \
863         dbus_message_iter_close_container( &dict, &dict_entry ); }
864
865 #define ADD_VLC_META_STRING( entry, item ) \
866     { \
867         char * psz = input_item_Get##item( p_input );\
868         ADD_META( entry, DBUS_TYPE_STRING, \
869                   psz ); \
870         free( psz ); \
871     }
872
873 static int GetInputMeta( input_item_t* p_input,
874                         DBusMessageIter *args )
875 { /*FIXME: Works only for already read metadata. */
876
877     DBusMessageIter dict, dict_entry, variant;
878     /* We need the track length to be expressed in seconds
879      * instead of milliseconds */
880     dbus_int64_t i_length = (p_input->i_duration / 1000);
881
882
883     const char* ppsz_meta_items[] = 
884     {
885     "title", "artist", "genre", "copyright", "album", "tracknum",
886     "description", "rating", "date", "setting", "url", "language",
887     "nowplaying", "publisher", "encodedby", "arturl", "trackid",
888     "status", "URI", "length", "video-codec", "audio-codec",
889     "video-bitrate", "audio-bitrate", "audio-samplerate"
890     };
891
892     dbus_message_iter_open_container( args, DBUS_TYPE_ARRAY, "{sv}", &dict );
893
894     ADD_VLC_META_STRING( 0,  Title );
895     ADD_VLC_META_STRING( 1,  Artist );
896     ADD_VLC_META_STRING( 2,  Genre );
897     ADD_VLC_META_STRING( 3,  Copyright );
898     ADD_VLC_META_STRING( 4,  Album );
899     ADD_VLC_META_STRING( 5,  TrackNum );
900     ADD_VLC_META_STRING( 6,  Description );
901     ADD_VLC_META_STRING( 7,  Rating );
902     ADD_VLC_META_STRING( 8,  Date );
903     ADD_VLC_META_STRING( 9,  Setting );
904     ADD_VLC_META_STRING( 10, URL );
905     ADD_VLC_META_STRING( 11, Language );
906     ADD_VLC_META_STRING( 12, NowPlaying );
907     ADD_VLC_META_STRING( 13, Publisher );
908     ADD_VLC_META_STRING( 14, EncodedBy );
909     ADD_VLC_META_STRING( 15, ArtURL );
910     ADD_VLC_META_STRING( 16, TrackID ); 
911
912     ADD_META( 17, DBUS_TYPE_INT32, p_input->p_meta->i_status );
913     ADD_META( 18, DBUS_TYPE_STRING, p_input->psz_uri );
914     ADD_META( 19, DBUS_TYPE_INT64, i_length );
915
916     dbus_message_iter_close_container( args, &dict );
917     return VLC_SUCCESS;
918 }
919
920 #undef ADD_META
921 #undef ADD_VLC_META_STRING