1 /*****************************************************************************
2 * dbus-tracklist.c : dbus control module (mpris v2.1) - TrackList interface
3 *****************************************************************************
4 * Copyright © 2006-2011 Rafaël Carré
5 * Copyright © 2007-2011 Mirsal Ennaime
6 * Copyright © 2009-2011 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>
36 #include "dbus_tracklist.h"
37 #include "dbus_common.h"
39 DBUS_METHOD( AddTrack )
40 { /* add the string to the playlist, and play it if the boolean is true */
44 dbus_error_init( &error );
46 char *psz_mrl, *psz_aftertrack;
49 dbus_message_get_args( p_from, &error,
50 DBUS_TYPE_STRING, &psz_mrl,
51 DBUS_TYPE_OBJECT_PATH, &psz_aftertrack,
52 DBUS_TYPE_BOOLEAN, &b_play,
55 if( dbus_error_is_set( &error ) )
57 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
59 dbus_error_free( &error );
60 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
63 #warning psz_aftertrack is not used
64 playlist_Add( PL, psz_mrl, NULL, PLAYLIST_APPEND |
65 ( ( b_play == TRUE ) ? PLAYLIST_GO : 0 ) ,
66 PLAYLIST_END, true, false );
71 DBUS_METHOD( GetTracksMetadata )
77 const char *psz_track_id = NULL;
79 playlist_t *p_playlist = PL;
80 input_item_t *p_input = NULL;
82 DBusMessageIter in_args, track_ids, meta;
83 dbus_message_iter_init( p_from, &in_args );
85 if( DBUS_TYPE_ARRAY != dbus_message_iter_get_arg_type( &in_args ) )
87 msg_Err( (vlc_object_t*) p_this, "Invalid arguments" );
88 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
91 dbus_message_iter_recurse( &in_args, &track_ids );
92 dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "a{sv}", &meta );
94 while( DBUS_TYPE_OBJECT_PATH ==
95 dbus_message_iter_get_arg_type( &track_ids ) )
97 dbus_message_iter_get_basic( &track_ids, &psz_track_id );
99 if( 1 != sscanf( psz_track_id, MPRIS_TRACKID_FORMAT, &i_track_id ) )
101 msg_Err( (vlc_object_t*) p_this, "Invalid track id: %s",
107 for( int i = 0; i < playlist_CurrentSize( p_playlist ); i++ )
109 p_input = p_playlist->current.p_elems[i]->p_input;
111 if( i_track_id == p_input->i_id )
113 GetInputMeta( p_input, &meta );
119 dbus_message_iter_next( &track_ids );
122 dbus_message_iter_close_container( &args, &meta );
131 const char *psz_track_id = NULL;
132 playlist_t *p_playlist = PL;
135 dbus_error_init( &error );
137 dbus_message_get_args( p_from, &error,
138 DBUS_TYPE_OBJECT_PATH, &psz_track_id,
141 if( dbus_error_is_set( &error ) )
143 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
145 dbus_error_free( &error );
146 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
149 if( 1 != sscanf( psz_track_id, MPRIS_TRACKID_FORMAT, &i_track_id ) )
151 msg_Err( (vlc_object_t*) p_this, "Invalid track id %s", psz_track_id );
152 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
157 for( int i = 0; i < playlist_CurrentSize( p_playlist ); i++ )
159 if( i_track_id == p_playlist->current.p_elems[i]->p_input->i_id )
161 playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, true,
162 p_playlist->current.p_elems[i]->p_parent,
163 p_playlist->current.p_elems[i] );
172 DBUS_METHOD( RemoveTrack )
177 dbus_error_init( &error );
181 playlist_t *p_playlist = PL;
182 input_item_t *p_input = NULL;
184 dbus_message_get_args( p_from, &error,
185 DBUS_TYPE_OBJECT_PATH, &psz_id,
188 if( dbus_error_is_set( &error ) )
190 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
192 dbus_error_free( &error );
193 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
196 if( 1 != sscanf( psz_id, MPRIS_TRACKID_FORMAT, &i_id ) )
198 msg_Err( (vlc_object_t*) p_this, "Invalid track id: %s", psz_id );
199 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
204 for( i = 0; i < playlist_CurrentSize( p_playlist ); i++ )
206 p_input = p_playlist->current.p_elems[i]->p_input;
208 if( i_id == p_input->i_id )
210 playlist_DeleteFromInput( p_playlist, p_input, true );
219 DBUS_METHOD( Tracks )
220 { /* Tracks property */
221 VLC_UNUSED( p_this );
226 DBusMessageIter tracks, v;
227 char *psz_track_id = NULL;
228 playlist_t *p_playlist = PL;
229 input_item_t *p_input = NULL;
231 dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "ao", &v );
232 dbus_message_iter_open_container( &v, DBUS_TYPE_ARRAY, "o", &tracks );
236 for( int i = 0; i < playlist_CurrentSize( p_playlist ); i++ )
238 p_input = p_playlist->current.p_elems[i]->p_input;
240 if( ( -1 == asprintf( &psz_track_id,
241 MPRIS_TRACKID_FORMAT,
243 !dbus_message_iter_append_basic( &tracks,
244 DBUS_TYPE_OBJECT_PATH,
248 dbus_message_iter_abandon_container( &v, &tracks );
249 dbus_message_iter_abandon_container( &args, &v );
250 return DBUS_HANDLER_RESULT_NEED_MEMORY;
253 free( psz_track_id );
258 if( !dbus_message_iter_close_container( &v, &tracks ) ||
259 !dbus_message_iter_close_container( &args, &v ) )
260 return DBUS_HANDLER_RESULT_NEED_MEMORY;
265 DBUS_METHOD( CanEditTracks )
266 { /* CanEditTracks property */
267 VLC_UNUSED( p_this );
272 const dbus_bool_t b_ret = TRUE;
274 if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, "b", &v ) )
275 return DBUS_HANDLER_RESULT_NEED_MEMORY;
277 if( !dbus_message_iter_append_basic( &v, DBUS_TYPE_BOOLEAN, &b_ret ) )
279 dbus_message_iter_abandon_container( &args, &v );
280 return DBUS_HANDLER_RESULT_NEED_MEMORY;
283 if( !dbus_message_iter_close_container( &args, &v ) )
285 dbus_message_iter_abandon_container( &args, &v );
286 return DBUS_HANDLER_RESULT_NEED_MEMORY;
292 #define PROPERTY_MAPPING_BEGIN if( 0 ) {}
293 #define PROPERTY_FUNC( interface, property, function ) \
294 else if( !strcmp( psz_interface_name, interface ) && \
295 !strcmp( psz_property_name, property ) ) \
296 return function( p_conn, p_from, p_this );
297 #define PROPERTY_MAPPING_END return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
299 DBUS_METHOD( GetProperty )
303 char *psz_interface_name = NULL;
304 char *psz_property_name = NULL;
306 dbus_error_init( &error );
307 dbus_message_get_args( p_from, &error,
308 DBUS_TYPE_STRING, &psz_interface_name,
309 DBUS_TYPE_STRING, &psz_property_name,
312 if( dbus_error_is_set( &error ) )
314 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
316 dbus_error_free( &error );
317 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
320 msg_Dbg( (vlc_object_t*) p_this, "Getting property %s",
323 PROPERTY_MAPPING_BEGIN
324 PROPERTY_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "Tracks", Tracks )
325 PROPERTY_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "CanEditTracks",
330 #undef PROPERTY_MAPPING_BEGIN
331 #undef PROPERTY_GET_FUNC
332 #undef PROPERTY_MAPPING_END
334 #define METHOD_FUNC( interface, method, function ) \
335 else if( dbus_message_is_method_call( p_from, interface, method ) )\
336 return function( p_conn, p_from, p_this )
339 handle_tracklist ( DBusConnection *p_conn, DBusMessage *p_from, void *p_this )
343 METHOD_FUNC( DBUS_INTERFACE_PROPERTIES, "Get", GetProperty );
345 /* here D-Bus method names are associated to an handler */
347 METHOD_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "GoTo", GoTo );
348 METHOD_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "AddTrack", AddTrack );
349 METHOD_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "RemoveTrack", RemoveTrack );
350 METHOD_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "GetTracksMetadata",
353 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
359 * PropertiesChangedSignal: synthetizes and sends the
360 * org.freedesktop.DBus.Properties.PropertiesChanged signal
362 static DBusHandlerResult
363 PropertiesChangedSignal( intf_thread_t *p_intf,
364 vlc_dictionary_t *p_changed_properties )
366 DBusConnection *p_conn = p_intf->p_sys->p_conn;
367 DBusMessageIter changed_properties, invalidated_properties, entry, variant;
368 const char *psz_interface_name = DBUS_MPRIS_TRACKLIST_INTERFACE;
369 char **ppsz_properties = NULL;
370 int i_properties = 0;
372 SIGNAL_INIT( DBUS_INTERFACE_PROPERTIES,
373 DBUS_MPRIS_OBJECT_PATH,
374 "PropertiesChanged" );
377 ADD_STRING( &psz_interface_name );
378 dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "{sv}",
379 &changed_properties );
381 dbus_message_iter_close_container( &args, &changed_properties );
383 dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "s",
384 &invalidated_properties );
386 i_properties = vlc_dictionary_keys_count( p_changed_properties );
387 ppsz_properties = vlc_dictionary_all_keys( p_changed_properties );
389 for( int i = 0; i < i_properties; i++ )
390 if( !strcmp( ppsz_properties[i], "Tracks" ) )
391 dbus_message_iter_append_basic( &invalidated_properties,
393 &ppsz_properties[i] );
395 dbus_message_iter_close_container( &args, &invalidated_properties );
400 * TrackListPropertiesChangedEmit: Emits the
401 * org.freedesktop.DBus.Properties.PropertiesChanged signal
403 int TrackListPropertiesChangedEmit( intf_thread_t * p_intf,
404 vlc_dictionary_t * p_changed_properties )
406 if( p_intf->p_sys->b_dead )
409 PropertiesChangedSignal( p_intf, p_changed_properties );