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