]> git.sesse.net Git - vlc/blob - src/control/media_list_player.c
media_list_player: Don't fetch stop event from media player in media_list_player_stop.
[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
44     if ( !p_mlp->current_playing_item_path )
45     {
46         p_mlp->current_playing_item_path = libvlc_media_list_path_empty();
47     }
48     
49     p_sublist_of_playing_item = libvlc_media_list_sublist_at_path(
50                             p_mlp->p_mlist,
51                             p_mlp->current_playing_item_path );
52  
53     /* If item just gained a sublist just play it */
54     if( p_sublist_of_playing_item )
55     {
56         libvlc_media_list_release( p_sublist_of_playing_item );
57         return libvlc_media_list_path_copy_by_appending( p_mlp->current_playing_item_path, 0 );
58     }
59
60     /* Try to catch next element */
61     p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(
62                             p_mlp->p_mlist,
63                             p_mlp->current_playing_item_path );
64
65     int deepness = libvlc_media_list_path_deepness( p_mlp->current_playing_item_path );
66     if( deepness < 1 || !p_parent_of_playing_item )
67         return NULL;
68
69     ret = libvlc_media_list_path_copy( p_mlp->current_playing_item_path );
70
71     while( ret[deepness-1] >= libvlc_media_list_count( p_parent_of_playing_item, NULL ) )
72     {
73         deepness--;
74         if( deepness <= 0 )
75         {
76             free( ret );
77             libvlc_media_list_release( p_parent_of_playing_item );
78             return NULL;
79         }
80         ret[deepness] = -1;
81         ret[deepness-1]++;
82         p_parent_of_playing_item  = libvlc_media_list_parentlist_at_path(
83                                         p_mlp->p_mlist,
84                                         ret );
85     }
86     libvlc_media_list_release( p_parent_of_playing_item );
87     return ret;
88 }
89
90 /**************************************************************************
91  *       media_player_reached_end (private) (Event Callback)
92  **************************************************************************/
93 static void
94 media_player_reached_end( const libvlc_event_t * p_event,
95                             void * p_user_data )
96 {
97     libvlc_media_list_player_t * p_mlp = p_user_data;
98     libvlc_media_player_t * p_mi = p_event->p_obj;
99     libvlc_media_t *p_md, * p_current_md;
100
101     p_md = libvlc_media_player_get_media( p_mi, NULL );
102     /* XXX: need if p_mlp->p_current_playing_index is beyond */
103     p_current_md = libvlc_media_list_item_at_path(
104                         p_mlp->p_mlist,
105                         p_mlp->current_playing_item_path );
106     if( p_md != p_current_md )
107     {
108         msg_Warn( p_mlp->p_libvlc_instance->p_libvlc_int,
109                   "We are not sync-ed with the media instance" );
110         libvlc_media_release( p_md );
111         libvlc_media_release( p_current_md );
112         return;
113     }
114     libvlc_media_release( p_md );
115     libvlc_media_release( p_current_md );
116     libvlc_media_list_player_next( p_mlp, NULL );
117 }
118
119 /**************************************************************************
120  *       playlist_item_deleted (private) (Event Callback)
121  **************************************************************************/
122 static void
123 mlist_item_deleted( const libvlc_event_t * p_event, void * p_user_data )
124 {
125     libvlc_media_t * p_current_md;
126     libvlc_media_list_player_t * p_mlp = p_user_data;
127     libvlc_media_list_t * p_emitting_mlist = p_event->p_obj;
128     /* XXX: need if p_mlp->p_current_playing_index is beyond */
129     p_current_md = libvlc_media_list_item_at_path(
130                         p_mlp->p_mlist,
131                         p_mlp->current_playing_item_path );
132
133     if( p_event->u.media_list_item_deleted.item == p_current_md &&
134         p_emitting_mlist == p_mlp->p_mlist )
135     {
136         /* We are playing this item, we choose to stop */
137         libvlc_media_list_player_stop( p_mlp, NULL );
138     }
139 }
140
141 /**************************************************************************
142  *       install_playlist_observer (private)
143  **************************************************************************/
144 static void
145 install_playlist_observer( libvlc_media_list_player_t * p_mlp )
146 {
147     libvlc_event_attach( libvlc_media_list_event_manager( p_mlp->p_mlist, NULL ),
148             libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp, NULL );
149 }
150
151 /**************************************************************************
152  *       uninstall_playlist_observer (private)
153  **************************************************************************/
154 static void
155 uninstall_playlist_observer( libvlc_media_list_player_t * p_mlp )
156 {
157     if ( !p_mlp->p_mlist )
158     {
159         return;
160     }
161
162     libvlc_event_detach( libvlc_media_list_event_manager( p_mlp->p_mlist, NULL ),
163             libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp, NULL );
164 }
165
166 /**************************************************************************
167  *       install_media_player_observer (private)
168  **************************************************************************/
169 static void
170 install_media_player_observer( libvlc_media_list_player_t * p_mlp )
171 {
172     libvlc_event_attach( libvlc_media_player_event_manager( p_mlp->p_mi, NULL ),
173                          libvlc_MediaPlayerEndReached,
174                           media_player_reached_end, p_mlp, NULL );
175 }
176
177
178 /**************************************************************************
179  *       uninstall_media_player_observer (private)
180  **************************************************************************/
181 static void
182 uninstall_media_player_observer( libvlc_media_list_player_t * p_mlp )
183 {
184     if ( !p_mlp->p_mi )
185     {
186         return;
187     }
188
189     libvlc_event_detach( libvlc_media_player_event_manager( p_mlp->p_mi, NULL ),
190                          libvlc_MediaPlayerEndReached,
191                          media_player_reached_end, p_mlp, NULL );
192 }
193
194 /**************************************************************************
195  *       set_current_playing_item (private)
196  *
197  * Playlist lock should be held
198  **************************************************************************/
199 static void
200 set_current_playing_item( libvlc_media_list_player_t * p_mlp,
201                           libvlc_media_list_path_t path,
202                           libvlc_exception_t * p_e )
203 {
204     VLC_UNUSED(p_e);
205
206     libvlc_media_t * p_md;
207     
208     p_md = libvlc_media_list_item_at_path( p_mlp->p_mlist, path ); 
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     if( !p_md )
215     {
216         vlc_mutex_unlock( &p_mlp->object_lock );
217         return;
218     }
219
220     /* We are not interested in getting media stop event now */
221     uninstall_media_player_observer( p_mlp );
222
223     if ( !p_mlp->p_mi )
224     {
225         p_mlp->p_mi = libvlc_media_player_new_from_media(p_md, p_e);
226     }
227     
228     if( p_md->p_subitems && libvlc_media_list_count( p_md->p_subitems, NULL ) > 0 )
229     {
230         libvlc_media_t * p_submd;
231         p_submd = libvlc_media_list_item_at_index( p_md->p_subitems, 0, NULL );
232         libvlc_media_player_set_media( p_mlp->p_mi, p_submd, NULL );
233         libvlc_media_release( p_submd );
234     }
235     else
236         libvlc_media_player_set_media( p_mlp->p_mi, p_md, NULL );
237 //    wait_playing_state(); /* If we want to be synchronous */
238     install_media_player_observer( p_mlp );
239
240     vlc_mutex_unlock( &p_mlp->object_lock );
241
242     libvlc_media_release( p_md ); /* for libvlc_media_list_item_at_index */
243 }
244
245 /*
246  * Public libvlc functions
247  */
248
249 /**************************************************************************
250  *         new (Public)
251  **************************************************************************/
252 libvlc_media_list_player_t *
253 libvlc_media_list_player_new( libvlc_instance_t * p_instance,
254                               libvlc_exception_t * p_e )
255 {
256     (void)p_e;
257     libvlc_media_list_player_t * p_mlp;
258     p_mlp = malloc(sizeof(libvlc_media_list_player_t));
259     p_mlp->current_playing_item_path = NULL;
260     p_mlp->p_mi = NULL;
261     p_mlp->p_mlist = NULL;
262     vlc_mutex_init( &p_mlp->object_lock );
263     p_mlp->p_event_manager = libvlc_event_manager_new( p_mlp,
264                                                        p_instance,
265                                                        p_e );
266     libvlc_event_manager_register_event_type( p_mlp->p_event_manager,
267             libvlc_MediaListPlayerNextItemSet, p_e );
268
269     return p_mlp;
270 }
271
272 /**************************************************************************
273  *         release (Public)
274  **************************************************************************/
275 void libvlc_media_list_player_release( libvlc_media_list_player_t * p_mlp )
276 {
277     free(p_mlp);
278 }
279
280 /**************************************************************************
281  *        set_media_player (Public)
282  **************************************************************************/
283 void libvlc_media_list_player_set_media_player(
284                                      libvlc_media_list_player_t * p_mlp,
285                                      libvlc_media_player_t * p_mi,
286                                      libvlc_exception_t * p_e )
287 {
288     VLC_UNUSED(p_e);
289
290     vlc_mutex_lock( &p_mlp->object_lock );
291
292     if( p_mlp->p_mi )
293     {
294         uninstall_media_player_observer( p_mlp );
295         libvlc_media_player_release( p_mlp->p_mi );
296     }
297     libvlc_media_player_retain( p_mi );
298     p_mlp->p_mi = p_mi;
299
300     install_media_player_observer( p_mlp );
301
302     vlc_mutex_unlock( &p_mlp->object_lock );
303 }
304
305 /**************************************************************************
306  *       set_media_list (Public)
307  **************************************************************************/
308 void libvlc_media_list_player_set_media_list(
309                                      libvlc_media_list_player_t * p_mlp,
310                                      libvlc_media_list_t * p_mlist,
311                                      libvlc_exception_t * p_e )
312 {
313     vlc_mutex_lock( &p_mlp->object_lock );
314  
315     if( libvlc_media_list_player_is_playing( p_mlp, p_e ) )
316     {
317         libvlc_media_player_stop( p_mlp->p_mi, p_e );
318         /* Don't bother if there was an error. */
319         libvlc_exception_clear( p_e );
320     }
321
322     if( p_mlp->p_mlist )
323     {
324         uninstall_playlist_observer( p_mlp );
325         libvlc_media_list_release( p_mlp->p_mlist );
326     }
327     libvlc_media_list_retain( p_mlist );
328     p_mlp->p_mlist = p_mlist;
329  
330     install_playlist_observer( p_mlp );
331
332     vlc_mutex_unlock( &p_mlp->object_lock );
333 }
334
335 /**************************************************************************
336  *        Play (Public)
337  **************************************************************************/
338 void libvlc_media_list_player_play( libvlc_media_list_player_t * p_mlp,
339                                   libvlc_exception_t * p_e )
340 {
341     if( !p_mlp->current_playing_item_path )
342     {
343         libvlc_media_list_player_next( p_mlp, p_e );
344         return; /* Will set to play */
345     }
346
347     libvlc_media_player_play( p_mlp->p_mi, p_e );
348 }
349
350
351 /**************************************************************************
352  *        Pause (Public)
353  **************************************************************************/
354 void libvlc_media_list_player_pause( libvlc_media_list_player_t * p_mlp,
355                                      libvlc_exception_t * p_e )
356 {
357     if( !p_mlp->p_mi )
358         return;
359     libvlc_media_player_pause( p_mlp->p_mi, p_e );
360 }
361
362 /**************************************************************************
363  *        is_playing (Public)
364  **************************************************************************/
365 int
366 libvlc_media_list_player_is_playing( libvlc_media_list_player_t * p_mlp,
367                                      libvlc_exception_t * p_e )
368 {
369     libvlc_state_t state = libvlc_media_player_get_state( p_mlp->p_mi, p_e );
370     return (state == libvlc_Opening) || (state == libvlc_Buffering) ||
371            (state == libvlc_Forward) || (state == libvlc_Backward) ||
372            (state == libvlc_Playing);
373 }
374
375 /**************************************************************************
376  *        State (Public)
377  **************************************************************************/
378 libvlc_state_t
379 libvlc_media_list_player_get_state( libvlc_media_list_player_t * p_mlp,
380                                     libvlc_exception_t * p_e )
381 {
382     if( !p_mlp->p_mi )
383         return libvlc_Ended;
384     return libvlc_media_player_get_state( p_mlp->p_mi, p_e );
385 }
386
387 /**************************************************************************
388  *        Play item at index (Public)
389  **************************************************************************/
390 void libvlc_media_list_player_play_item_at_index(
391                         libvlc_media_list_player_t * p_mlp,
392                         int i_index,
393                         libvlc_exception_t * p_e )
394 {
395     set_current_playing_item( p_mlp, libvlc_media_list_path_with_root_index(i_index), p_e );
396
397     if( libvlc_exception_raised( p_e ) )
398         return;
399
400     /* Send the next item event */
401     libvlc_event_t event;
402     event.type = libvlc_MediaListPlayerNextItemSet;
403     libvlc_event_send( p_mlp->p_event_manager, &event );
404
405     libvlc_media_player_play( p_mlp->p_mi, p_e );
406 }
407
408 /**************************************************************************
409  *        Play item (Public)
410  **************************************************************************/
411 void libvlc_media_list_player_play_item(
412                         libvlc_media_list_player_t * p_mlp,
413                         libvlc_media_t * p_md,
414                         libvlc_exception_t * p_e )
415 {
416     libvlc_media_list_path_t path = libvlc_media_list_path_of_item( p_mlp->p_mlist, p_md );
417     if( !path )
418     {
419         libvlc_exception_raise( p_e, "No such item in media list" );
420         return;
421     }
422     set_current_playing_item( p_mlp, path, p_e );
423
424     if( libvlc_exception_raised( p_e ) )
425         return;
426
427     libvlc_media_player_play( p_mlp->p_mi, p_e );
428 }
429
430 /**************************************************************************
431  *       Stop (Public)
432  **************************************************************************/
433 void libvlc_media_list_player_stop( libvlc_media_list_player_t * p_mlp,
434                                     libvlc_exception_t * p_e )
435 {
436     if ( p_mlp->p_mi )
437     {
438         /* We are not interested in getting media stop event now */
439         uninstall_media_player_observer( p_mlp );
440         libvlc_media_player_stop( p_mlp->p_mi, p_e );
441         install_media_player_observer( p_mlp );
442     }
443
444     vlc_mutex_lock( &p_mlp->object_lock );
445     free( p_mlp->current_playing_item_path );
446     p_mlp->current_playing_item_path = NULL;
447     vlc_mutex_unlock( &p_mlp->object_lock );
448 }
449
450 /**************************************************************************
451  *       Next (Public)
452  **************************************************************************/
453 void libvlc_media_list_player_next( libvlc_media_list_player_t * p_mlp,
454                                     libvlc_exception_t * p_e )
455 {
456     libvlc_media_list_path_t path;
457
458     if (! p_mlp->p_mlist )
459     {
460         libvlc_exception_raise( p_e, "No more element to play" );
461         return;
462     }
463
464     libvlc_media_list_lock( p_mlp->p_mlist );
465
466     path = get_next_path( p_mlp );
467
468     if( !path )
469     {
470         libvlc_media_list_unlock( p_mlp->p_mlist );
471         libvlc_exception_raise( p_e, "No more element to play" );
472         libvlc_media_list_player_stop( p_mlp, p_e );
473         return;
474     }
475
476     set_current_playing_item( p_mlp, path, p_e );
477
478     libvlc_media_player_play( p_mlp->p_mi, p_e );
479
480     libvlc_media_list_unlock( p_mlp->p_mlist );
481
482     /* Send the next item event */
483     libvlc_event_t event;
484     event.type = libvlc_MediaListPlayerNextItemSet;
485     libvlc_event_send( p_mlp->p_event_manager, &event);
486 }