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