Reorganize the dbus control module code
[vlc.git] / modules / control / dbus / dbus_tracklist.c
1 /*****************************************************************************
2  * dbus-tracklist.c : dbus control module (mpris v1.0) - /TrackList object
3  *****************************************************************************
4  * Copyright © 2006-2008 Rafaël Carré
5  * Copyright © 2007-2010 Mirsal Ennaime
6  * Copyright © 2009-2010 The VideoLAN team
7  * $Id$
8  *
9  * Authors:    Mirsal ENNAIME <mirsal dot ennaime at gmail dot com>
10  *
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.
15  *
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.
20  *
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  *****************************************************************************/
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <vlc_common.h>
31 #include <vlc_playlist.h>
32
33 #include <assert.h>
34
35 #include "dbus_tracklist.h"
36 #include "dbus_common.h"
37
38
39 const char* psz_tracklist_introspection_xml =
40 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
41 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
42 "<node>"
43 "  <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
44 "    <method name=\"Introspect\">\n"
45 "      <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
46 "    </method>\n"
47 "  </interface>\n"
48 "  <interface name=\"org.freedesktop.MediaPlayer\">\n"
49 "    <method name=\"AddTrack\">\n"
50 "      <arg type=\"s\" direction=\"in\" />\n"
51 "      <arg type=\"b\" direction=\"in\" />\n"
52 "      <arg type=\"i\" direction=\"out\" />\n"
53 "    </method>\n"
54 "    <method name=\"DelTrack\">\n"
55 "      <arg type=\"i\" direction=\"in\" />\n"
56 "    </method>\n"
57 "    <method name=\"GetMetadata\">\n"
58 "      <arg type=\"i\" direction=\"in\" />\n"
59 "      <arg type=\"a{sv}\" direction=\"out\" />\n"
60 "    </method>\n"
61 "    <method name=\"GetCurrentTrack\">\n"
62 "      <arg type=\"i\" direction=\"out\" />\n"
63 "    </method>\n"
64 "    <method name=\"GetLength\">\n"
65 "      <arg type=#include <vlc_common.h>\"i\" direction=\"out\" />\n"
66 "    </method>\n"
67 "    <method name=\"SetLoop\">\n"
68 "      <arg type=\"b\" direction=\"in\" />\n"
69 "    </method>\n"
70 "    <method name=\"SetRandom\">\n"
71 "      <arg type=\"b\" direction=\"in\" />\n"
72 "    </method>\n"
73 "    <signal name=\"TrackListChange\">\n"
74 "      <arg type=\"i\" />\n"
75 "    </signal>\n"
76 "  </interface>\n"
77 "</node>\n"
78 ;
79
80 DBUS_METHOD( AddTrack )
81 { /* add the string to the playlist, and play it if the boolean is true */
82     REPLY_INIT;
83     OUT_ARGUMENTS;
84
85     DBusError error;
86     dbus_error_init( &error );
87
88     char *psz_mrl;
89     dbus_bool_t b_play;
90
91     dbus_message_get_args( p_from, &error,
92             DBUS_TYPE_STRING, &psz_mrl,
93             DBUS_TYPE_BOOLEAN, &b_play,
94             DBUS_TYPE_INVALID );
95
96     if( dbus_error_is_set( &error ) )
97     {
98         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
99                 error.message );
100         dbus_error_free( &error );
101         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
102     }
103
104     playlist_Add( PL, psz_mrl, NULL, PLAYLIST_APPEND |
105             ( ( b_play == TRUE ) ? PLAYLIST_GO : 0 ) ,
106             PLAYLIST_END, true, false );
107
108     dbus_int32_t i_success = 0;
109     ADD_INT32( &i_success );
110
111     REPLY_SEND;
112 }
113
114 DBUS_METHOD( GetCurrentTrack )
115 {
116     REPLY_INIT;
117     OUT_ARGUMENTS;
118
119     playlist_t *p_playlist = PL;
120
121     PL_LOCK;
122     dbus_int32_t i_position = PL->i_current_index;
123     PL_UNLOCK;
124
125     ADD_INT32( &i_position );
126     REPLY_SEND;
127 }
128
129 DBUS_METHOD( GetMetadata )
130 {
131     REPLY_INIT;
132     OUT_ARGUMENTS;
133     DBusError error;
134     dbus_error_init( &error );
135
136     dbus_int32_t i_position;
137     playlist_t *p_playlist = PL;
138
139     dbus_message_get_args( p_from, &error,
140            DBUS_TYPE_INT32, &i_position,
141            DBUS_TYPE_INVALID );
142
143     if( dbus_error_is_set( &error ) )
144     {
145         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
146                 error.message );
147         dbus_error_free( &error );
148         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
149     }
150
151     PL_LOCK;
152     if( i_position < p_playlist->current.i_size )
153     {
154         GetInputMeta( p_playlist->current.p_elems[i_position]->p_input, &args );
155     }
156
157     PL_UNLOCK;
158     REPLY_SEND;
159 }
160
161 DBUS_METHOD( GetLength )
162 {
163     REPLY_INIT;
164     OUT_ARGUMENTS;
165     playlist_t *p_playlist = PL;
166
167     PL_LOCK;
168     dbus_int32_t i_elements = PL->current.i_size;
169     PL_UNLOCK;
170
171     ADD_INT32( &i_elements );
172     REPLY_SEND;
173 }
174
175 DBUS_METHOD( DelTrack )
176 {
177     REPLY_INIT;
178
179     DBusError error;
180     dbus_error_init( &error );
181
182     dbus_int32_t i_position;
183     playlist_t *p_playlist = PL;
184
185     dbus_message_get_args( p_from, &error,
186             DBUS_TYPE_INT32, &i_position,
187             DBUS_TYPE_INVALID );
188
189     if( dbus_error_is_set( &error ) )
190     {
191         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
192                 error.message );
193         dbus_error_free( &error );
194         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
195     }
196
197     PL_LOCK;
198     if( i_position < p_playlist->current.i_size )
199     {
200         playlist_DeleteFromInput( p_playlist,
201             p_playlist->current.p_elems[i_position]->p_input,
202             pl_Locked );
203     }
204     PL_UNLOCK;
205
206     REPLY_SEND;
207 }
208
209 DBUS_METHOD( SetLoop )
210 {
211     REPLY_INIT;
212     OUT_ARGUMENTS;
213
214     DBusError error;
215     dbus_bool_t b_loop;
216
217     dbus_error_init( &error );
218     dbus_message_get_args( p_from, &error,
219             DBUS_TYPE_BOOLEAN, &b_loop,
220             DBUS_TYPE_INVALID );
221
222     if( dbus_error_is_set( &error ) )
223     {
224         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
225                 error.message );
226         dbus_error_free( &error );
227         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
228     }
229
230     var_SetBool( PL, "loop", ( b_loop == TRUE ) );
231
232     REPLY_SEND;
233 }
234
235 DBUS_METHOD( SetRandom )
236 {
237     REPLY_INIT;
238     OUT_ARGUMENTS;
239
240     DBusError error;
241     dbus_bool_t b_random;
242
243     dbus_error_init( &error );
244     dbus_message_get_args( p_from, &error,
245             DBUS_TYPE_BOOLEAN, &b_random,
246             DBUS_TYPE_INVALID );
247
248     if( dbus_error_is_set( &error ) )
249     {
250         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
251                 error.message );
252         dbus_error_free( &error );
253         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
254     }
255
256     var_SetBool( PL, "random", ( b_random == TRUE ) );
257
258     REPLY_SEND;
259 }
260
261 /******************************************************************************
262  * TrackListChange: tracklist order / length change signal
263  *****************************************************************************/
264 DBUS_SIGNAL( TrackListChangeSignal )
265 { /* emit the new tracklist lengh */
266     SIGNAL_INIT( DBUS_MPRIS_TRACKLIST_INTERFACE,
267                  DBUS_MPRIS_TRACKLIST_PATH,
268                  "TrackListChange");
269
270     OUT_ARGUMENTS;
271
272     playlist_t *p_playlist = ((intf_thread_t*)p_data)->p_sys->p_playlist;
273     PL_LOCK;
274     dbus_int32_t i_elements = p_playlist->current.i_size;
275     PL_UNLOCK;
276
277     ADD_INT32( &i_elements );
278     SIGNAL_SEND;
279 }
280
281 DBUS_METHOD( handle_introspect_tracklist )
282 {
283     VLC_UNUSED(p_this);
284     REPLY_INIT;
285     OUT_ARGUMENTS;
286     ADD_STRING( &psz_tracklist_introspection_xml );
287     REPLY_SEND;
288 }
289
290 #define METHOD_FUNC( interface, method, function ) \
291     else if( dbus_message_is_method_call( p_from, interface, method ) )\
292         return function( p_conn, p_from, p_this )
293
294 DBusHandlerResult
295 handle_tracklist ( DBusConnection *p_conn, DBusMessage *p_from, void *p_this )
296 {
297     if( dbus_message_is_method_call( p_from,
298                 DBUS_INTERFACE_INTROSPECTABLE, "Introspect" ) )
299     return handle_introspect_tracklist( p_conn, p_from, p_this );
300
301     /* here D-Bus method names are associated to an handler */
302
303     METHOD_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "GetMetadata",     GetMetadata );
304     METHOD_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "GetCurrentTrack", GetCurrentTrack );
305     METHOD_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "GetLength",       GetLength );
306     METHOD_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "AddTrack",        AddTrack );
307     METHOD_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "DelTrack",        DelTrack );
308     METHOD_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "SetLoop",         SetLoop );
309     METHOD_FUNC( DBUS_MPRIS_TRACKLIST_INTERFACE, "SetRandom",       SetRandom );
310
311     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
312 }
313
314 /*****************************************************************************
315  * TrackListChangeEmit: Emits the TrackListChange signal
316  *****************************************************************************/
317 /* FIXME: It is not called on tracklist reordering */
318 int TrackListChangeEmit( intf_thread_t *p_intf, int signal, int i_node )
319 {
320     // "playlist-item-append"
321     if( signal == SIGNAL_PLAYLIST_ITEM_APPEND )
322     {
323         /* don't signal when items are added/removed in p_category */
324         playlist_t *p_playlist = p_intf->p_sys->p_playlist;
325         PL_LOCK;
326         playlist_item_t *p_item = playlist_ItemGetById( p_playlist, i_node );
327         assert( p_item );
328         while( p_item->p_parent )
329             p_item = p_item->p_parent;
330         if( p_item == p_playlist->p_root_category )
331         {
332             PL_UNLOCK;
333             return VLC_SUCCESS;
334         }
335         PL_UNLOCK;
336     }
337
338     if( p_intf->p_sys->b_dead )
339         return VLC_SUCCESS;
340
341     UpdateCaps( p_intf );
342     TrackListChangeSignal( p_intf->p_sys->p_conn, p_intf );
343     return VLC_SUCCESS;
344 }
345
346 #undef METHOD_FUNC