]> git.sesse.net Git - vlc/blob - src/control/media_list_player.c
921d3f84f7802ed70ba328501e63f97fe8e0ab3a
[vlc] / src / control / media_list_player.c
1 /*****************************************************************************
2  * media_list_player.c: libvlc new API media_list player functions
3  *****************************************************************************
4  * Copyright (C) 2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23 #include "libvlc_internal.h"
24 #include <vlc/libvlc.h>
25 #include "media_list_path.h"
26
27 /*
28  * Private functions
29  */
30
31 /**************************************************************************
32  *       get_next_index (private)
33  *
34  * Simple next item fetcher.
35  **************************************************************************/
36 static libvlc_media_list_path_t
37 get_next_path( libvlc_media_list_player_t * p_mlp )
38 {
39         /* We are entered with libvlc_media_list_lock( p_mlp->p_list ) */
40         libvlc_media_list_path_t ret;
41         libvlc_media_list_t * p_parent_of_playing_item;
42         libvlc_media_list_t * p_sublist_of_playing_item;
43     p_sublist_of_playing_item = libvlc_media_list_sublist_at_path(
44                             p_mlp->p_mlist,
45                             p_mlp->current_playing_item_path );
46     
47     /* If item just gained a sublist just play it */
48     if( p_sublist_of_playing_item )
49     {
50         libvlc_media_list_release( p_sublist_of_playing_item );
51         return libvlc_media_list_path_copy_by_appending( p_mlp->current_playing_item_path, 0 );
52     }
53
54     /* Try to catch next element */
55     p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(
56                             p_mlp->p_mlist,
57                             p_mlp->current_playing_item_path );
58
59     int deepness = libvlc_media_list_path_deepness( p_mlp->current_playing_item_path );
60     if( deepness < 1 || !p_parent_of_playing_item )
61         return NULL;
62
63     ret = libvlc_media_list_path_copy( p_mlp->current_playing_item_path );
64
65         while( ret[deepness-1] >= libvlc_media_list_count( p_parent_of_playing_item, NULL ) )
66         {
67         deepness--;
68         if( deepness <= 0 )
69         {
70             free( ret );
71             libvlc_media_list_release( p_parent_of_playing_item );
72             return NULL;
73         }
74         ret[deepness] = -1;
75         ret[deepness-1]++;
76         p_parent_of_playing_item  = libvlc_media_list_parentlist_at_path(
77                                         p_mlp->p_mlist,
78                                         ret );
79     }
80     libvlc_media_list_release( p_parent_of_playing_item );
81         return ret;
82 }
83
84 /**************************************************************************
85  *       media_instance_reached_end (private) (Event Callback)
86  **************************************************************************/
87 static void 
88 media_instance_reached_end( const libvlc_event_t * p_event,
89                             void * p_user_data )
90 {
91         libvlc_media_list_player_t * p_mlp = p_user_data;
92         libvlc_media_instance_t * p_mi = p_event->p_obj;
93     libvlc_media_descriptor_t *p_md, * p_current_md;
94
95     p_md = libvlc_media_instance_get_media_descriptor( p_mi, NULL );
96     /* XXX: need if p_mlp->p_current_playing_index is beyond */
97     p_current_md = libvlc_media_list_item_at_path(
98                         p_mlp->p_mlist,
99                         p_mlp->current_playing_item_path );
100         if( p_md != p_current_md )
101         {
102                 msg_Warn( p_mlp->p_libvlc_instance->p_libvlc_int,
103                                   "We are not sync-ed with the media instance" );
104         libvlc_media_descriptor_release( p_md );
105         libvlc_media_descriptor_release( p_current_md );
106                 return;
107         }
108     libvlc_media_descriptor_release( p_md );
109     libvlc_media_descriptor_release( p_current_md );
110         libvlc_media_list_player_next( p_mlp, NULL );
111 }
112
113 /**************************************************************************
114  *       playlist_item_deleted (private) (Event Callback)
115  **************************************************************************/
116 static void 
117 mlist_item_deleted( const libvlc_event_t * p_event, void * p_user_data )
118 {
119     libvlc_media_descriptor_t * p_current_md;    
120         libvlc_media_list_player_t * p_mlp = p_user_data;
121         libvlc_media_list_t * p_emitting_mlist = p_event->p_obj;
122     /* XXX: need if p_mlp->p_current_playing_index is beyond */
123     p_current_md = libvlc_media_list_item_at_path(
124                         p_mlp->p_mlist,
125                         p_mlp->current_playing_item_path );
126
127         if( p_event->u.media_list_item_deleted.item == p_current_md &&
128             p_emitting_mlist == p_mlp->p_mlist )
129         {
130                 /* We are playing this item, we choose to stop */
131                 libvlc_media_list_player_stop( p_mlp, NULL );
132         }
133 }
134
135 /**************************************************************************
136  *       install_playlist_observer (private)
137  **************************************************************************/
138 static void
139 install_playlist_observer( libvlc_media_list_player_t * p_mlp )
140 {
141         libvlc_event_attach( libvlc_media_list_event_manager( p_mlp->p_mlist, NULL ),
142             libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp, NULL );
143 }
144
145 /**************************************************************************
146  *       uninstall_playlist_observer (private)
147  **************************************************************************/
148 static void
149 uninstall_playlist_observer( libvlc_media_list_player_t * p_mlp )
150 {
151     libvlc_event_detach( libvlc_media_list_event_manager( p_mlp->p_mlist, NULL ),
152             libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp, NULL );
153 }
154
155 /**************************************************************************
156  *       install_media_instance_observer (private)
157  **************************************************************************/
158 static void
159 install_media_instance_observer( libvlc_media_list_player_t * p_mlp )
160 {
161         libvlc_event_attach( libvlc_media_instance_event_manager( p_mlp->p_mi, NULL ),
162                          libvlc_MediaInstanceReachedEnd,
163                                               media_instance_reached_end, p_mlp, NULL );
164 }
165
166
167 /**************************************************************************
168  *       uninstall_media_instance_observer (private)
169  **************************************************************************/
170 static void
171 uninstall_media_instance_observer( libvlc_media_list_player_t * p_mlp )
172 {
173         libvlc_event_detach( libvlc_media_instance_event_manager( p_mlp->p_mi, NULL ),
174                          libvlc_MediaInstanceReachedEnd,
175                                              media_instance_reached_end, p_mlp, NULL );
176 }
177
178 /**************************************************************************
179  *       Stop (Public)
180  **************************************************************************/
181 static vlc_bool_t
182 libvlc_media_list_player_is_playing( libvlc_media_list_player_t * p_mlp,
183                                     libvlc_exception_t * p_e )
184 {
185     //libvlc_exception_raise( p_e, "Unimplemented" );
186     return 1;
187 }
188
189 /**************************************************************************
190  *       set_current_playing_item (private)
191  *
192  * Playlist lock should be held
193  **************************************************************************/
194 static void
195 set_current_playing_item( libvlc_media_list_player_t * p_mlp,
196                           libvlc_media_list_path_t path,
197                           libvlc_exception_t * p_e )
198 {
199         libvlc_media_descriptor_t * p_md;
200         
201         p_md = libvlc_media_list_item_at_path( p_mlp->p_mlist, path );
202         if( !p_md )
203         {
204                 if( !libvlc_exception_raised( p_e ) )
205                         libvlc_exception_raise( p_e, "Can't obtain a media" );
206                 return;
207         }
208     
209     vlc_mutex_lock( &p_mlp->object_lock );
210         
211     free( p_mlp->current_playing_item_path );
212     p_mlp->current_playing_item_path = path;
213
214         /* We are not interested in getting media_descriptor stop event now */
215         uninstall_media_instance_observer( p_mlp );
216     if( p_md->p_subitems && libvlc_media_list_count( p_md->p_subitems, NULL ) > 0 )
217     {
218         libvlc_media_descriptor_t * p_submd;
219         p_submd = libvlc_media_list_item_at_index( p_md->p_subitems, 0, NULL );
220         libvlc_media_instance_set_media_descriptor( p_mlp->p_mi, p_submd, NULL );
221         libvlc_media_descriptor_release( p_submd );
222     }
223     else
224         libvlc_media_instance_set_media_descriptor( p_mlp->p_mi, p_md, NULL );
225 //      wait_playing_state(); /* If we want to be synchronous */
226         install_media_instance_observer( p_mlp );
227
228     vlc_mutex_unlock( &p_mlp->object_lock );
229
230         libvlc_media_list_unlock( p_mlp->p_mlist );             
231         
232         libvlc_media_descriptor_release( p_md ); /* for libvlc_media_list_item_at_index */
233 }
234
235 /*
236  * Public libvlc functions
237  */
238
239 /**************************************************************************
240  *         new (Public)
241  **************************************************************************/
242 libvlc_media_list_player_t *
243 libvlc_media_list_player_new( libvlc_instance_t * p_instance,
244                               libvlc_exception_t * p_e )
245 {
246     (void)p_e;
247     libvlc_media_list_player_t * p_mlp;
248     p_mlp = malloc(sizeof(libvlc_media_list_player_t));
249         p_mlp->current_playing_item_path = NULL;
250     p_mlp->p_mi = NULL;
251     p_mlp->p_mlist = NULL;
252     vlc_mutex_init( p_instance->p_libvlc_int, &p_mlp->object_lock );
253     p_mlp->p_event_manager = libvlc_event_manager_new( p_mlp,
254                                                        p_instance,
255                                                        p_e );
256     libvlc_event_manager_register_event_type( p_mlp->p_event_manager,
257             libvlc_MediaListPlayerNextItemSet, p_e );
258     libvlc_event_manager_register_event_type( p_mlp->p_event_manager,
259             libvlc_MediaListPlayerNextItemSet, p_e );
260
261         return p_mlp;
262 }
263
264 /**************************************************************************
265  *         release (Public)
266  **************************************************************************/
267 void libvlc_media_list_player_release( libvlc_media_list_player_t * p_mlp )
268 {
269     free(p_mlp);
270 }
271
272 /**************************************************************************
273  *        set_media_instance (Public)
274  **************************************************************************/
275 void libvlc_media_list_player_set_media_instance(
276                                      libvlc_media_list_player_t * p_mlp,
277                                      libvlc_media_instance_t * p_mi,
278                                      libvlc_exception_t * p_e )
279 {
280     vlc_mutex_lock( &p_mlp->object_lock );
281
282         if( p_mlp->p_mi )
283         {
284                 uninstall_media_instance_observer( p_mlp );
285                 libvlc_media_instance_release( p_mlp->p_mi );
286         }
287         libvlc_media_instance_retain( p_mi );
288         p_mlp->p_mi = p_mi;
289
290     install_media_instance_observer( p_mlp );
291
292     vlc_mutex_unlock( &p_mlp->object_lock );
293 }
294
295 /**************************************************************************
296  *       set_media_list (Public)
297  **************************************************************************/
298 void libvlc_media_list_player_set_media_list(
299                                      libvlc_media_list_player_t * p_mlp,
300                                      libvlc_media_list_t * p_mlist,
301                                      libvlc_exception_t * p_e )
302 {
303     vlc_mutex_lock( &p_mlp->object_lock );
304     
305         if( libvlc_media_list_player_is_playing( p_mlp, p_e ) )
306     {
307         libvlc_media_instance_stop( p_mlp->p_mi, p_e );
308         /* Don't bother if there was an error. */
309         libvlc_exception_clear( p_e );
310     }
311
312         if( p_mlp->p_mlist )
313         {
314                 uninstall_playlist_observer( p_mlp );
315                 libvlc_media_list_release( p_mlp->p_mlist );
316         }
317         libvlc_media_list_retain( p_mlist );
318         p_mlp->p_mlist = p_mlist;
319     
320         install_playlist_observer( p_mlp );
321
322     vlc_mutex_unlock( &p_mlp->object_lock );
323 }
324
325 /**************************************************************************
326  *        Play (Public)
327  **************************************************************************/
328 void libvlc_media_list_player_play( libvlc_media_list_player_t * p_mlp,
329                                   libvlc_exception_t * p_e )
330 {
331     if( !p_mlp->current_playing_item_path )
332     {
333         libvlc_media_list_player_next( p_mlp, p_e );
334         return; /* Will set to play */
335     }
336
337         libvlc_media_instance_play( p_mlp->p_mi, p_e );
338 }
339
340 /**************************************************************************
341  *        Play item at index (Public)
342  **************************************************************************/
343 void libvlc_media_list_player_play_item_at_index(
344                         libvlc_media_list_player_t * p_mlp,
345                         int i_index,
346                         libvlc_exception_t * p_e )
347 {
348         set_current_playing_item( p_mlp, libvlc_media_list_path_with_root_index(i_index), p_e );
349
350         if( libvlc_exception_raised( p_e ) )
351                 return;
352
353     /* Send the next item event */
354     libvlc_event_t event;
355     event.type = libvlc_MediaListPlayerNextItemSet;
356     libvlc_event_send( p_mlp->p_event_manager, &event );
357
358         libvlc_media_instance_play( p_mlp->p_mi, p_e );
359 }
360
361 /**************************************************************************
362  *        Play item (Public)
363  **************************************************************************/
364 void libvlc_media_list_player_play_item(
365                         libvlc_media_list_player_t * p_mlp,
366                         libvlc_media_descriptor_t * p_md,
367                         libvlc_exception_t * p_e )
368 {
369         libvlc_media_list_path_t path = libvlc_media_list_path_of_item( p_mlp->p_mlist, p_md );
370     if( !path )
371     {
372         libvlc_exception_raise( p_e, "No such item in media list" );
373         return;
374     }
375         set_current_playing_item( p_mlp, path, p_e );
376
377         if( libvlc_exception_raised( p_e ) )
378                 return;
379
380         libvlc_media_instance_play( p_mlp->p_mi, p_e );
381 }
382
383 /**************************************************************************
384  *       Stop (Public)
385  **************************************************************************/
386 void libvlc_media_list_player_stop( libvlc_media_list_player_t * p_mlp,
387                                     libvlc_exception_t * p_e )
388 {
389         libvlc_media_instance_stop( p_mlp->p_mi, p_e );
390
391     vlc_mutex_lock( &p_mlp->object_lock );
392         p_mlp->current_playing_item_path = NULL;
393     vlc_mutex_unlock( &p_mlp->object_lock );
394 }
395
396 /**************************************************************************
397  *       Next (Public)
398  **************************************************************************/
399 void libvlc_media_list_player_next( libvlc_media_list_player_t * p_mlp,
400                                     libvlc_exception_t * p_e )
401 {       
402         libvlc_media_list_path_t path;
403         
404         libvlc_media_list_lock( p_mlp->p_mlist );
405
406         path = get_next_path( p_mlp );
407
408         if( !path )
409         {
410                 libvlc_media_list_unlock( p_mlp->p_mlist );
411                 libvlc_exception_raise( p_e, "No more element to play" );
412                 libvlc_media_list_player_stop( p_mlp, p_e );
413                 return;
414         }
415
416         set_current_playing_item( p_mlp, path, p_e );
417         
418     libvlc_media_instance_play( p_mlp->p_mi, p_e );
419
420     libvlc_media_list_unlock( p_mlp->p_mlist );
421
422     /* Send the next item event */
423     libvlc_event_t event;
424     event.type = libvlc_MediaListPlayerNextItemSet;
425     libvlc_event_send( p_mlp->p_event_manager, &event);
426 }