1 /*****************************************************************************
2 * dbus-player.h : dbus control module (mpris v1.0) - /Player object
3 *****************************************************************************
4 * Copyright © 2006-2008 Rafaël Carré
5 * Copyright © 2007-2010 Mirsal Ennaime
6 * Copyright © 2009-2010 The VideoLAN team
9 * Authors: Mirsal Ennaime <mirsal at mirsal fr>
10 * Rafaël Carré <funman at videolanorg>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_playlist.h>
33 #include <vlc_interface.h>
38 #include "dbus_player.h"
39 #include "dbus_common.h"
41 static int MarshalStatus ( intf_thread_t *, DBusMessageIter * );
43 /* XML data to answer org.freedesktop.DBus.Introspectable.Introspect requests */
44 static const char* psz_player_introspection_xml =
45 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
46 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
48 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
49 " <method name=\"Introspect\">\n"
50 " <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
53 " <interface name=\"org.freedesktop.MediaPlayer\">\n"
54 " <method name=\"GetStatus\">\n"
55 " <arg type=\"(iiii)\" direction=\"out\" />\n"
57 " <method name=\"Prev\">\n"
59 " <method name=\"Next\">\n"
61 " <method name=\"Stop\">\n"
63 " <method name=\"Play\">\n"
65 " <method name=\"Pause\">\n"
67 " <method name=\"Repeat\">\n"
68 " <arg type=\"b\" direction=\"in\" />\n"
70 " <method name=\"VolumeSet\">\n"
71 " <arg type=\"i\" direction=\"in\" />\n"
73 " <method name=\"VolumeGet\">\n"
74 " <arg type=\"i\" direction=\"out\" />\n"
76 " <method name=\"PositionSet\">\n"
77 " <arg type=\"i\" direction=\"in\" />\n"
79 " <method name=\"PositionGet\">\n"
80 " <arg type=\"i\" direction=\"out\" />\n"
82 " <method name=\"GetMetadata\">\n"
83 " <arg type=\"a{sv}\" direction=\"out\" />\n"
85 " <method name=\"GetCaps\">\n"
86 " <arg type=\"i\" direction=\"out\" />\n"
88 " <signal name=\"TrackChange\">\n"
89 " <arg type=\"a{sv}\"/>\n"
91 " <signal name=\"StatusChange\">\n"
92 " <arg type=\"(iiii)\"/>\n"
94 " <signal name=\"CapsChange\">\n"
95 " <arg type=\"i\"/>\n"
101 DBUS_METHOD( PositionGet )
102 { /* returns position in milliseconds */
107 input_thread_t *p_input = playlist_CurrentInput( PL );
113 i_pos = var_GetTime( p_input, "time" ) / 1000;
114 vlc_object_release( p_input );
120 DBUS_METHOD( PositionSet )
121 { /* set position in milliseconds */
124 vlc_value_t position;
128 dbus_error_init( &error );
130 dbus_message_get_args( p_from, &error,
131 DBUS_TYPE_INT32, &i_pos,
134 if( dbus_error_is_set( &error ) )
136 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
138 dbus_error_free( &error );
139 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
141 input_thread_t *p_input = playlist_CurrentInput( PL );
145 position.i_time = ((mtime_t)i_pos) * 1000;
146 var_Set( p_input, "time", position );
147 vlc_object_release( p_input );
152 DBUS_METHOD( VolumeGet )
153 { /* returns volume in percentage */
156 dbus_int32_t i_dbus_vol;
157 audio_volume_t i_vol;
159 /* 2nd argument of aout_VolumeGet is int32 */
160 aout_VolumeGet( PL, &i_vol );
162 double f_vol = 100. * i_vol / AOUT_VOLUME_MAX;
163 i_dbus_vol = round( f_vol );
164 ADD_INT32( &i_dbus_vol );
168 DBUS_METHOD( VolumeSet )
169 { /* set volume in percentage */
173 dbus_error_init( &error );
175 dbus_int32_t i_dbus_vol;
176 audio_volume_t i_vol;
178 dbus_message_get_args( p_from, &error,
179 DBUS_TYPE_INT32, &i_dbus_vol,
182 if( dbus_error_is_set( &error ) )
184 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
186 dbus_error_free( &error );
187 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
190 double f_vol = AOUT_VOLUME_MAX * i_dbus_vol / 100.;
191 i_vol = round( f_vol );
192 aout_VolumeSet( PL, i_vol );
197 { /* next playlist item */
204 { /* previous playlist item */
217 DBUS_METHOD( GetStatus )
218 { /* returns the current status as a struct of 4 ints */
220 First 0 = Playing, 1 = Paused, 2 = Stopped.
221 Second 0 = Playing linearly , 1 = Playing randomly.
222 Third 0 = Go to the next element once the current has finished playing , 1 = Repeat the current element
223 Fourth 0 = Stop playing once the last element has been played, 1 = Never give up playing *
228 MarshalStatus( p_this, &args );
236 playlist_Pause( PL );
244 input_thread_t *p_input = playlist_CurrentInput( PL );
249 input_Control( p_input, INPUT_SET_POSITION, i_pos );
250 vlc_object_release( p_input );
258 DBUS_METHOD( Repeat )
264 dbus_bool_t b_repeat;
266 dbus_error_init( &error );
267 dbus_message_get_args( p_from, &error,
268 DBUS_TYPE_BOOLEAN, &b_repeat,
271 if( dbus_error_is_set( &error ) )
273 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
275 dbus_error_free( &error );
276 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
279 var_SetBool( PL, "repeat", ( b_repeat == TRUE ) );
284 DBUS_METHOD( GetCurrentMetadata )
288 playlist_t *p_playlist = PL;
291 playlist_item_t* p_item = playlist_CurrentPlayingItem( p_playlist );
293 GetInputMeta( p_item->p_input, &args );
298 DBUS_METHOD( GetCaps )
303 ADD_INT32( &INTF->p_sys->i_caps );
308 /*****************************************************************************
309 * StatusChange: Player status change signal
310 *****************************************************************************/
312 DBUS_SIGNAL( StatusChangeSignal )
313 { /* send the updated status info on the bus */
314 SIGNAL_INIT( DBUS_MPRIS_PLAYER_INTERFACE,
315 DBUS_MPRIS_PLAYER_PATH,
320 /* we're called from a callback of input_thread_t, so it can not be
321 * destroyed before we return */
322 MarshalStatus( (intf_thread_t*) p_data, &args );
327 /*****************************************************************************
328 * TrackChange: Playlist item change callback
329 *****************************************************************************/
331 DBUS_SIGNAL( TrackChangeSignal )
332 { /* emit the metadata of the new item */
333 SIGNAL_INIT( DBUS_MPRIS_PLAYER_INTERFACE,
334 DBUS_MPRIS_PLAYER_PATH,
339 input_item_t *p_item = (input_item_t*) p_data;
340 GetInputMeta ( p_item, &args );
345 /******************************************************************************
346 * CapsChange: player capabilities change signal
347 *****************************************************************************/
348 DBUS_SIGNAL( CapsChangeSignal )
350 SIGNAL_INIT( DBUS_MPRIS_PLAYER_INTERFACE,
351 DBUS_MPRIS_PLAYER_PATH,
356 ADD_INT32( &((intf_thread_t*)p_data)->p_sys->i_caps );
360 DBUS_METHOD( handle_introspect_player )
365 ADD_STRING( &psz_player_introspection_xml );
369 #define METHOD_FUNC( interface, method, function ) \
370 else if( dbus_message_is_method_call( p_from, interface, method ) )\
371 return function( p_conn, p_from, p_this )
374 handle_player ( DBusConnection *p_conn, DBusMessage *p_from, void *p_this )
376 if( dbus_message_is_method_call( p_from,
377 DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
378 return handle_introspect_player( p_conn, p_from, p_this );
380 /* here D-Bus method names are associated to an handler */
382 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Prev", Prev );
383 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Next", Next );
384 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Stop", Stop );
385 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Play", Play );
386 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Pause", Pause );
387 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Repeat", Repeat );
388 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "VolumeSet", VolumeSet );
389 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "VolumeGet", VolumeGet );
390 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "PositionSet", PositionSet );
391 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "PositionGet", PositionGet );
392 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "GetStatus", GetStatus );
393 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "GetMetadata", GetCurrentMetadata );
394 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "GetCaps", GetCaps );
396 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
401 /*****************************************************************************
402 * StatusChangeEmit: Emits the StatusChange signal
403 *****************************************************************************/
404 int StatusChangeEmit( intf_thread_t * p_intf )
406 if( p_intf->p_sys->b_dead )
409 UpdateCaps( p_intf );
410 StatusChangeSignal( p_intf->p_sys->p_conn, p_intf );
414 /*****************************************************************************
415 * CapsChangeEmit: Emits the CapsChange signal
416 *****************************************************************************/
417 int CapsChangeEmit( intf_thread_t * p_intf )
419 if( p_intf->p_sys->b_dead )
422 CapsChangeSignal( p_intf->p_sys->p_conn, p_intf );
426 /*****************************************************************************
427 * TrackChangeEmit: Emits the TrackChange signal
428 *****************************************************************************/
429 int TrackChangeEmit( intf_thread_t * p_intf, input_item_t* p_item )
431 if( p_intf->p_sys->b_dead )
434 UpdateCaps( p_intf );
435 TrackChangeSignal( p_intf->p_sys->p_conn, p_item );
439 /*****************************************************************************
440 * MarshalStatus: Fill a DBusMessage with the current player status
441 *****************************************************************************/
443 static int MarshalStatus( intf_thread_t* p_intf, DBusMessageIter* args )
444 { /* This is NOT the right way to do that, it would be better to sore
445 the status information in p_sys and update it on change, thus
446 avoiding a long lock */
448 DBusMessageIter status;
449 dbus_int32_t i_state, i_random, i_repeat, i_loop;
450 playlist_t* p_playlist = p_intf->p_sys->p_playlist;
452 vlc_mutex_lock( &p_intf->p_sys->lock );
453 i_state = p_intf->p_sys->i_playing_state;
454 vlc_mutex_unlock( &p_intf->p_sys->lock );
456 i_random = var_CreateGetBool( p_playlist, "random" );
458 i_repeat = var_CreateGetBool( p_playlist, "repeat" );
460 i_loop = var_CreateGetBool( p_playlist, "loop" );
462 dbus_message_iter_open_container( args, DBUS_TYPE_STRUCT, NULL, &status );
463 dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_state );
464 dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_random );
465 dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_repeat );
466 dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_loop );
467 dbus_message_iter_close_container( args, &status );