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