1 /*****************************************************************************
2 * dbus.c : D-Bus control interface
3 *****************************************************************************
4 * Copyright (C) 2006 Rafaël Carré
7 * Author: Rafaël Carré <funman at videolanorg>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
25 * D-Bus Specification:
26 * http://dbus.freedesktop.org/doc/dbus-specification.html
27 * D-Bus low-level C API (libdbus)
28 * http://dbus.freedesktop.org/doc/dbus/api/html/index.html
35 * macros to read incoming arguments
37 * explore different possible types (arrays..)
39 * what must we do if org.videolan.vlc already exist on the bus ?
40 * ( there is more than one vlc instance )
43 /*****************************************************************************
45 *****************************************************************************/
47 #include <dbus/dbus.h>
56 #include <vlc_interface.h>
58 #include <vlc_input.h>
59 #include <vlc_playlist.h>
61 /*****************************************************************************
63 *****************************************************************************/
65 static int Open ( vlc_object_t * );
66 static void Close ( vlc_object_t * );
67 static void Run ( intf_thread_t * );
70 static int TrackChange( vlc_object_t *p_this, const char *psz_var,
71 vlc_value_t oldval, vlc_value_t newval, void *p_data );
75 DBusConnection *p_conn;
78 /*****************************************************************************
80 *****************************************************************************/
83 set_shortname( _("dbus"));
84 set_category( CAT_INTERFACE );
85 set_subcategory( SUBCAT_INTERFACE_CONTROL );
86 set_description( _("D-Bus control interface") );
87 set_capability( "interface", 0 );
88 set_callbacks( Open, Close );
91 /*****************************************************************************
93 *****************************************************************************/
95 DBUS_METHOD( PlaylistExport_XSPF )
96 { /*export playlist to an xspf file */
98 /* reads the filename to export to */
99 /* returns the status as int32:
108 dbus_error_init( &error );
113 dbus_message_get_args( p_from, &error,
114 DBUS_TYPE_STRING, &psz_file,
117 if( dbus_error_is_set( &error ) )
119 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s\n",
121 dbus_error_free( &error );
122 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
125 playlist_t *p_playlist = pl_Yield( (vlc_object_t*) p_this );
127 if( ( !playlist_IsEmpty( p_playlist ) ) &&
128 ( p_playlist->p_root_category->i_children > 0 ) )
130 if( playlist_Export( p_playlist, psz_file,
131 p_playlist->p_root_category->pp_children[0],
132 "export-xspf" ) == VLC_SUCCESS )
140 pl_Release( ((vlc_object_t*) p_this ) );
152 playlist_t *p_playlist = pl_Yield( (vlc_object_t*) p_this );
153 playlist_Stop( p_playlist );
154 pl_Release( ((vlc_object_t*) p_this) );
155 ((vlc_object_t*)p_this)->p_libvlc->b_die = VLC_TRUE;
159 DBUS_METHOD( PositionGet )
160 { /* returns position as an int in the range [0;1000] */
163 vlc_value_t position;
166 playlist_t *p_playlist = pl_Yield( ((vlc_object_t*) p_this) );
167 input_thread_t *p_input = p_playlist->p_input;
173 var_Get( p_input, "position", &position );
174 i_pos = position.f_float * 1000 ;
177 pl_Release( ((vlc_object_t*) p_this) );
181 DBUS_METHOD( PositionSet )
182 { /* set position from an int in the range [0;1000] */
185 vlc_value_t position;
189 dbus_error_init( &error );
191 dbus_message_get_args( p_from, &error,
192 DBUS_TYPE_INT32, &i_pos,
195 if( dbus_error_is_set( &error ) )
197 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s\n",
199 dbus_error_free( &error );
200 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
202 playlist_t *p_playlist = pl_Yield( ((vlc_object_t*) p_this) );
203 input_thread_t *p_input = p_playlist->p_input;
207 position.f_float = ((float)i_pos) / 1000;
208 var_Set( p_input, "position", position );
210 pl_Release( ((vlc_object_t*) p_this) );
214 DBUS_METHOD( VolumeGet )
215 { /* returns volume in percentage */
218 dbus_int32_t i_dbus_vol;
219 audio_volume_t i_vol;
220 /* 2nd argument of aout_VolumeGet is int32 */
221 aout_VolumeGet( (vlc_object_t*) p_this, &i_vol );
222 i_dbus_vol = ( 100 * i_vol ) / AOUT_VOLUME_MAX;
223 ADD_INT32( &i_dbus_vol );
227 DBUS_METHOD( VolumeSet )
228 { /* set volume in percentage */
232 dbus_error_init( &error );
234 dbus_int32_t i_dbus_vol;
235 audio_volume_t i_vol;
237 dbus_message_get_args( p_from, &error,
238 DBUS_TYPE_INT32, &i_dbus_vol,
241 if( dbus_error_is_set( &error ) )
243 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s\n",
245 dbus_error_free( &error );
246 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
249 i_vol = ( AOUT_VOLUME_MAX / 100 ) *i_dbus_vol;
250 aout_VolumeSet( (vlc_object_t*) p_this, i_vol );
256 { /* next playlist item */
258 playlist_t *p_playlist = pl_Yield( ((vlc_object_t*) p_this) );
259 playlist_Next( p_playlist );
260 pl_Release( ((vlc_object_t*) p_this) );
265 { /* previous playlist item */
267 playlist_t *p_playlist = pl_Yield( ((vlc_object_t*) p_this) );
268 playlist_Prev( p_playlist );
269 pl_Release( ((vlc_object_t*) p_this) );
276 playlist_t *p_playlist = pl_Yield( ((vlc_object_t*) p_this) );
277 playlist_Stop( p_playlist );
278 pl_Release( ((vlc_object_t*) p_this) );
282 DBUS_METHOD( GetStatus )
283 { /* returns an int: 0=playing 1=paused 2=stopped */
287 dbus_int32_t i_status;
290 playlist_t *p_playlist = pl_Yield( (vlc_object_t*) p_this );
291 input_thread_t *p_input = p_playlist->p_input;
296 var_Get( p_input, "state", &val );
297 if( val.i_int == PAUSE_S )
299 else if( val.i_int == PLAYING_S )
303 pl_Release( p_playlist );
305 ADD_INT32( &i_status );
312 playlist_t *p_playlist = pl_Yield( (vlc_object_t*) p_this );
313 playlist_Pause( p_playlist );
314 pl_Release( p_playlist );
321 playlist_t *p_playlist = pl_Yield( (vlc_object_t*) p_this );
322 playlist_Play( p_playlist );
323 pl_Release( p_playlist );
327 /* Media Player information */
329 DBUS_METHOD( Identity )
333 char *psz_identity = malloc( strlen( PACKAGE ) + strlen( VERSION ) + 1 );
334 sprintf( psz_identity, "%s %s", PACKAGE, VERSION );
335 ADD_STRING( &psz_identity );
336 free( psz_identity );
342 DBUS_METHOD( AddTrack )
343 { /* add the string to the playlist, and play it if the boolean is true */
347 dbus_error_init( &error );
352 dbus_message_get_args( p_from, &error,
353 DBUS_TYPE_STRING, &psz_mrl,
354 DBUS_TYPE_BOOLEAN, &b_play,
357 if( dbus_error_is_set( &error ) )
359 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s\n",
361 dbus_error_free( &error );
362 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
365 playlist_t *p_playlist = pl_Yield( (vlc_object_t*) p_this );
366 playlist_Add( p_playlist, psz_mrl, NULL, PLAYLIST_APPEND |
367 ( ( b_play == TRUE ) ? PLAYLIST_GO : 0 ) , PLAYLIST_END, VLC_TRUE );
368 pl_Release( p_playlist );
373 DBUS_METHOD( GetCurrentTrack )
377 dbus_int32_t i_position = 0;
378 //TODO get position of playing element
379 ADD_INT32( &i_position );
383 DBUS_METHOD( GetMetadata )
384 { //TODO reads int, returns a{sv}
388 dbus_error_init( &error );
390 dbus_int32_t i_position;
392 dbus_message_get_args( p_from, &error,
393 DBUS_TYPE_INT32, &i_position,
396 if( dbus_error_is_set( &error ) )
398 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s\n",
400 dbus_error_free( &error );
401 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
409 DBUS_METHOD( GetLength )
413 dbus_int32_t i_elements = 0;
414 //TODO: return number of elements in playlist
415 ADD_INT32( &i_elements );
419 DBUS_METHOD( DelTrack )
424 dbus_error_init( &error );
426 dbus_int32_t i_position;
428 dbus_message_get_args( p_from, &error,
429 DBUS_TYPE_INT32, &i_position,
432 if( dbus_error_is_set( &error ) )
434 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s\n",
436 dbus_error_free( &error );
437 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
440 //TODO delete the element
445 /*****************************************************************************
446 * Introspection method
447 *****************************************************************************/
449 DBUS_METHOD( handle_introspect_root )
450 { /* handles introspection of /org/videolan/vlc */
453 ADD_STRING( &psz_introspection_xml_data_root );
457 DBUS_METHOD( handle_introspect_player )
461 ADD_STRING( &psz_introspection_xml_data_player );
465 DBUS_METHOD( handle_introspect_tracklist )
469 ADD_STRING( &psz_introspection_xml_data_tracklist );
473 /*****************************************************************************
474 * handle_*: answer to incoming messages
475 *****************************************************************************/
477 #define METHOD_FUNC( method, function ) \
478 else if( dbus_message_is_method_call( p_from, VLC_DBUS_INTERFACE, method ) )\
479 return function( p_conn, p_from, p_this )
481 DBUS_METHOD( handle_root )
484 if( dbus_message_is_method_call( p_from,
485 DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
486 return handle_introspect_root( p_conn, p_from, p_this );
488 /* here D-Bus method's names are associated to an handler */
490 METHOD_FUNC( "Identity", Identity );
492 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
496 DBUS_METHOD( handle_player )
498 if( dbus_message_is_method_call( p_from,
499 DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
500 return handle_introspect_player( p_conn, p_from, p_this );
502 /* here D-Bus method's names are associated to an handler */
504 METHOD_FUNC( "Prev", Prev );
505 METHOD_FUNC( "Next", Next );
506 METHOD_FUNC( "Quit", Quit );
507 METHOD_FUNC( "Stop", Stop );
508 METHOD_FUNC( "Play", Play );
509 METHOD_FUNC( "Pause", Pause );
510 METHOD_FUNC( "VolumeSet", VolumeSet );
511 METHOD_FUNC( "VolumeGet", VolumeGet );
512 METHOD_FUNC( "PositionSet", PositionSet );
513 METHOD_FUNC( "PositionGet", PositionGet );
514 METHOD_FUNC( "GetStatus", GetStatus );
516 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
519 DBUS_METHOD( handle_tracklist )
521 if( dbus_message_is_method_call( p_from,
522 DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
523 return handle_introspect_tracklist( p_conn, p_from, p_this );
525 /* here D-Bus method's names are associated to an handler */
527 METHOD_FUNC( "GetMetadata", GetMetadata );
528 METHOD_FUNC( "GetCurrentTrack", GetCurrentTrack );
529 METHOD_FUNC( "GetLength", GetLength );
530 METHOD_FUNC( "AddTrack", AddTrack );
531 METHOD_FUNC( "DelTrack", DelTrack );
533 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
536 /*****************************************************************************
537 * Open: initialize interface
538 *****************************************************************************/
540 static int Open( vlc_object_t *p_this )
541 { /* initialisation of the connection */
542 intf_thread_t *p_intf = (intf_thread_t*)p_this;
543 intf_sys_t *p_sys = malloc( sizeof( intf_sys_t ) );
544 playlist_t *p_playlist;
545 DBusConnection *p_conn;
551 dbus_threads_init_default();
553 dbus_error_init( &error );
555 /* connect to the session bus */
556 p_conn = dbus_bus_get( DBUS_BUS_SESSION, &error );
559 msg_Err( p_this, "Failed to connect to the D-Bus session daemon: %s",
561 dbus_error_free( &error );
566 /* register a well-known name on the bus */
567 dbus_bus_request_name( p_conn, "org.freedesktop.MediaPlayer", 0, &error );
568 if( dbus_error_is_set( &error ) )
570 msg_Err( p_this, "Error requesting org.freedesktop.MediaPlayer service:" " %s\n", error.message );
571 dbus_error_free( &error );
576 /* we unregister the object /, registered by libvlc */
577 dbus_connection_unregister_object_path( p_conn, "/" );
579 /* we register the objects */
580 dbus_connection_register_object_path( p_conn, VLC_DBUS_ROOT_PATH,
581 &vlc_dbus_root_vtable, p_this );
582 dbus_connection_register_object_path( p_conn, VLC_DBUS_PLAYER_PATH,
583 &vlc_dbus_player_vtable, p_this );
584 dbus_connection_register_object_path( p_conn, VLC_DBUS_TRACKLIST_PATH,
585 &vlc_dbus_tracklist_vtable, p_this );
587 dbus_connection_flush( p_conn );
589 p_playlist = pl_Yield( p_intf );
591 var_AddCallback( p_playlist, "playlist-current", TrackChange, p_intf );
593 pl_Release( p_playlist );
595 p_intf->pf_run = Run;
596 p_intf->p_sys = p_sys;
597 p_sys->p_conn = p_conn;
602 /*****************************************************************************
603 * Close: destroy interface
604 *****************************************************************************/
606 static void Close ( vlc_object_t *p_this )
608 intf_thread_t *p_intf = (intf_thread_t*) p_this;
609 playlist_t *p_playlist = pl_Yield( p_intf );;
612 var_DelCallback( p_playlist, "playlist-current", TrackChange, p_intf );
614 pl_Release( p_playlist );
616 dbus_connection_unref( p_intf->p_sys->p_conn );
618 free( p_intf->p_sys );
621 /*****************************************************************************
623 *****************************************************************************/
625 static void Run ( intf_thread_t *p_intf )
627 while( !p_intf->b_die )
629 msleep( INTF_IDLE_SLEEP );
630 dbus_connection_read_write_dispatch( p_intf->p_sys->p_conn, 0 );
634 /*****************************************************************************
635 * TrackChange: Playlist item change callback
636 *****************************************************************************/
638 DBUS_SIGNAL( TrackChangeSignal )
639 { /* emit the name of the new item */
640 SIGNAL_INIT( "TrackChange" );
643 input_thread_t *p_input = (input_thread_t*) p_data;
644 ADD_STRING( &input_GetItem(p_input)->psz_name );
649 static int TrackChange( vlc_object_t *p_this, const char *psz_var,
650 vlc_value_t oldval, vlc_value_t newval, void *p_data )
652 intf_thread_t *p_intf = ( intf_thread_t* ) p_data;
653 intf_sys_t *p_sys = p_intf->p_sys;
654 playlist_t *p_playlist;
655 input_thread_t *p_input = NULL;
656 (void)p_this; (void)psz_var; (void)oldval; (void)newval;
658 p_playlist = pl_Yield( p_intf );
660 p_input = p_playlist->p_input;
665 pl_Release( p_playlist );
669 vlc_object_yield( p_input );
671 pl_Release( p_playlist );
673 TrackChangeSignal( p_sys->p_conn, p_input );
675 vlc_object_release( p_input );