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 dot ennaime at gmail dot com>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
30 #include <vlc_common.h>
31 #include <vlc_playlist.h>
32 #include <vlc_interface.h>
37 #include "dbus_player.h"
38 #include "dbus_common.h"
40 static int MarshalStatus ( intf_thread_t *, DBusMessageIter * );
42 /* XML data to answer org.freedesktop.DBus.Introspectable.Introspect requests */
43 static const char* psz_player_introspection_xml =
44 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
45 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
47 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
48 " <method name=\"Introspect\">\n"
49 " <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
52 " <interface name=\"org.freedesktop.MediaPlayer\">\n"
53 " <method name=\"GetStatus\">\n"
54 " <arg type=\"(iiii)\" direction=\"out\" />\n"
56 " <method name=\"Prev\">\n"
58 " <method name=\"Next\">\n"
60 " <method name=\"Stop\">\n"
62 " <method name=\"Play\">\n"
64 " <method name=\"Pause\">\n"
66 " <method name=\"Repeat\">\n"
67 " <arg type=\"b\" direction=\"in\" />\n"
69 " <method name=\"VolumeSet\">\n"
70 " <arg type=\"i\" direction=\"in\" />\n"
72 " <method name=\"VolumeGet\">\n"
73 " <arg type=\"i\" direction=\"out\" />\n"
75 " <method name=\"PositionSet\">\n"
76 " <arg type=\"i\" direction=\"in\" />\n"
78 " <method name=\"PositionGet\">\n"
79 " <arg type=\"i\" direction=\"out\" />\n"
81 " <method name=\"GetMetadata\">\n"
82 " <arg type=\"a{sv}\" direction=\"out\" />\n"
84 " <method name=\"GetCaps\">\n"
85 " <arg type=\"i\" direction=\"out\" />\n"
87 " <signal name=\"TrackChange\">\n"
88 " <arg type=\"a{sv}\"/>\n"
90 " <signal name=\"StatusChange\">\n"
91 " <arg type=\"(iiii)\"/>\n"
93 " <signal name=\"CapsChange\">\n"
94 " <arg type=\"i\"/>\n"
100 DBUS_METHOD( PositionGet )
101 { /* returns position in milliseconds */
106 input_thread_t *p_input = playlist_CurrentInput( PL );
112 i_pos = var_GetTime( p_input, "time" ) / 1000;
113 vlc_object_release( p_input );
119 DBUS_METHOD( PositionSet )
120 { /* set position in milliseconds */
123 vlc_value_t position;
127 dbus_error_init( &error );
129 dbus_message_get_args( p_from, &error,
130 DBUS_TYPE_INT32, &i_pos,
133 if( dbus_error_is_set( &error ) )
135 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
137 dbus_error_free( &error );
138 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
140 input_thread_t *p_input = playlist_CurrentInput( PL );
144 position.i_time = ((mtime_t)i_pos) * 1000;
145 var_Set( p_input, "time", position );
146 vlc_object_release( p_input );
151 DBUS_METHOD( VolumeGet )
152 { /* returns volume in percentage */
155 dbus_int32_t i_dbus_vol;
156 audio_volume_t i_vol;
158 /* 2nd argument of aout_VolumeGet is int32 */
159 aout_VolumeGet( PL, &i_vol );
161 double f_vol = 100. * i_vol / AOUT_VOLUME_MAX;
162 i_dbus_vol = round( f_vol );
163 ADD_INT32( &i_dbus_vol );
167 DBUS_METHOD( VolumeSet )
168 { /* set volume in percentage */
172 dbus_error_init( &error );
174 dbus_int32_t i_dbus_vol;
175 audio_volume_t i_vol;
177 dbus_message_get_args( p_from, &error,
178 DBUS_TYPE_INT32, &i_dbus_vol,
181 if( dbus_error_is_set( &error ) )
183 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
185 dbus_error_free( &error );
186 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
189 double f_vol = AOUT_VOLUME_MAX * i_dbus_vol / 100.;
190 i_vol = round( f_vol );
191 aout_VolumeSet( PL, i_vol );
196 { /* next playlist item */
203 { /* previous playlist item */
216 DBUS_METHOD( GetStatus )
217 { /* returns the current status as a struct of 4 ints */
219 First 0 = Playing, 1 = Paused, 2 = Stopped.
220 Second 0 = Playing linearly , 1 = Playing randomly.
221 Third 0 = Go to the next element once the current has finished playing , 1 = Repeat the current element
222 Fourth 0 = Stop playing once the last element has been played, 1 = Never give up playing *
227 MarshalStatus( p_this, &args );
235 playlist_Pause( PL );
243 input_thread_t *p_input = playlist_CurrentInput( PL );
248 input_Control( p_input, INPUT_SET_POSITION, i_pos );
249 vlc_object_release( p_input );
257 DBUS_METHOD( Repeat )
263 dbus_bool_t b_repeat;
265 dbus_error_init( &error );
266 dbus_message_get_args( p_from, &error,
267 DBUS_TYPE_BOOLEAN, &b_repeat,
270 if( dbus_error_is_set( &error ) )
272 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
274 dbus_error_free( &error );
275 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
278 var_SetBool( PL, "repeat", ( b_repeat == TRUE ) );
283 DBUS_METHOD( GetCurrentMetadata )
287 playlist_t *p_playlist = PL;
290 playlist_item_t* p_item = playlist_CurrentPlayingItem( p_playlist );
292 GetInputMeta( p_item->p_input, &args );
297 DBUS_METHOD( GetCaps )
302 ADD_INT32( &INTF->p_sys->i_caps );
307 /*****************************************************************************
308 * StatusChange: Player status change signal
309 *****************************************************************************/
311 DBUS_SIGNAL( StatusChangeSignal )
312 { /* send the updated status info on the bus */
313 SIGNAL_INIT( DBUS_MPRIS_PLAYER_INTERFACE,
314 DBUS_MPRIS_PLAYER_PATH,
319 /* we're called from a callback of input_thread_t, so it can not be
320 * destroyed before we return */
321 MarshalStatus( (intf_thread_t*) p_data, &args );
326 /*****************************************************************************
327 * TrackChange: Playlist item change callback
328 *****************************************************************************/
330 DBUS_SIGNAL( TrackChangeSignal )
331 { /* emit the metadata of the new item */
332 SIGNAL_INIT( DBUS_MPRIS_PLAYER_INTERFACE,
333 DBUS_MPRIS_PLAYER_PATH,
338 input_item_t *p_item = (input_item_t*) p_data;
339 GetInputMeta ( p_item, &args );
344 /******************************************************************************
345 * CapsChange: player capabilities change signal
346 *****************************************************************************/
347 DBUS_SIGNAL( CapsChangeSignal )
349 SIGNAL_INIT( DBUS_MPRIS_PLAYER_INTERFACE,
350 DBUS_MPRIS_PLAYER_PATH,
355 ADD_INT32( &((intf_thread_t*)p_data)->p_sys->i_caps );
359 DBUS_METHOD( handle_introspect_player )
364 ADD_STRING( &psz_player_introspection_xml );
368 #define METHOD_FUNC( interface, method, function ) \
369 else if( dbus_message_is_method_call( p_from, interface, method ) )\
370 return function( p_conn, p_from, p_this )
373 handle_player ( DBusConnection *p_conn, DBusMessage *p_from, void *p_this )
375 if( dbus_message_is_method_call( p_from,
376 DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
377 return handle_introspect_player( p_conn, p_from, p_this );
379 /* here D-Bus method names are associated to an handler */
381 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Prev", Prev );
382 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Next", Next );
383 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Stop", Stop );
384 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Play", Play );
385 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Pause", Pause );
386 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "Repeat", Repeat );
387 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "VolumeSet", VolumeSet );
388 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "VolumeGet", VolumeGet );
389 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "PositionSet", PositionSet );
390 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "PositionGet", PositionGet );
391 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "GetStatus", GetStatus );
392 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "GetMetadata", GetCurrentMetadata );
393 METHOD_FUNC( DBUS_MPRIS_PLAYER_INTERFACE, "GetCaps", GetCaps );
395 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
400 /*****************************************************************************
401 * StatusChangeEmit: Emits the StatusChange signal
402 *****************************************************************************/
403 int StatusChangeEmit( intf_thread_t * p_intf )
405 if( p_intf->p_sys->b_dead )
408 UpdateCaps( p_intf );
409 StatusChangeSignal( p_intf->p_sys->p_conn, p_intf );
413 /*****************************************************************************
414 * CapsChangeEmit: Emits the CapsChange signal
415 *****************************************************************************/
416 int CapsChangeEmit( intf_thread_t * p_intf )
418 if( p_intf->p_sys->b_dead )
421 CapsChangeSignal( p_intf->p_sys->p_conn, p_intf );
425 /*****************************************************************************
426 * TrackChangeEmit: Emits the TrackChange signal
427 *****************************************************************************/
428 int TrackChangeEmit( intf_thread_t * p_intf, input_item_t* p_item )
430 if( p_intf->p_sys->b_dead )
433 UpdateCaps( p_intf );
434 TrackChangeSignal( p_intf->p_sys->p_conn, p_item );
438 /*****************************************************************************
439 * MarshalStatus: Fill a DBusMessage with the current player status
440 *****************************************************************************/
442 static int MarshalStatus( intf_thread_t* p_intf, DBusMessageIter* args )
443 { /* This is NOT the right way to do that, it would be better to sore
444 the status information in p_sys and update it on change, thus
445 avoiding a long lock */
447 DBusMessageIter status;
448 dbus_int32_t i_state, i_random, i_repeat, i_loop;
449 playlist_t* p_playlist = p_intf->p_sys->p_playlist;
451 vlc_mutex_lock( &p_intf->p_sys->lock );
452 i_state = p_intf->p_sys->i_playing_state;
453 vlc_mutex_unlock( &p_intf->p_sys->lock );
455 i_random = var_CreateGetBool( p_playlist, "random" );
457 i_repeat = var_CreateGetBool( p_playlist, "repeat" );
459 i_loop = var_CreateGetBool( p_playlist, "loop" );
461 dbus_message_iter_open_container( args, DBUS_TYPE_STRUCT, NULL, &status );
462 dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_state );
463 dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_random );
464 dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_repeat );
465 dbus_message_iter_append_basic( &status, DBUS_TYPE_INT32, &i_loop );
466 dbus_message_iter_close_container( args, &status );