]> git.sesse.net Git - vlc/blob - src/control/media_list_player.c
fixes for libvlc medialistplayer_play_item and medialistplayer_play_item_at_index...
[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_instance_reached_end (private) (Event Callback)
92  **************************************************************************/
93 static void
94 media_instance_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_instance_t * p_mi = p_event->p_obj;
99     libvlc_media_descriptor_t *p_md, * p_current_md;
100
101     p_md = libvlc_media_instance_get_media_descriptor( 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_descriptor_release( p_md );
111         libvlc_media_descriptor_release( p_current_md );
112         return;
113     }
114     libvlc_media_descriptor_release( p_md );
115     libvlc_media_descriptor_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_descriptor_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_instance_observer (private)
168  **************************************************************************/
169 static void
170 install_media_instance_observer( libvlc_media_list_player_t * p_mlp )
171 {
172     libvlc_event_attach( libvlc_media_instance_event_manager( p_mlp->p_mi, NULL ),
173                          libvlc_MediaInstanceReachedEnd,
174                           media_instance_reached_end, p_mlp, NULL );
175 }
176
177
178 /**************************************************************************
179  *       uninstall_media_instance_observer (private)
180  **************************************************************************/
181 static void
182 uninstall_media_instance_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_instance_event_manager( p_mlp->p_mi, NULL ),
190                          libvlc_MediaInstanceReachedEnd,
191                          media_instance_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_descriptor_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_descriptor stop event now */
221     uninstall_media_instance_observer( p_mlp );
222
223     if ( !p_mlp->p_mi )
224     {
225         p_mlp->p_mi = libvlc_media_instance_new_from_media_descriptor(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_descriptor_t * p_submd;
231         p_submd = libvlc_media_list_item_at_index( p_md->p_subitems, 0, NULL );
232         libvlc_media_instance_set_media_descriptor( p_mlp->p_mi, p_submd, NULL );
233         libvlc_media_descriptor_release( p_submd );
234     }
235     else
236         libvlc_media_instance_set_media_descriptor( p_mlp->p_mi, p_md, NULL );
237 //    wait_playing_state(); /* If we want to be synchronous */
238     install_media_instance_observer( p_mlp );
239
240     vlc_mutex_unlock( &p_mlp->object_lock );
241
242     libvlc_media_descriptor_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_instance->p_libvlc_int, &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_instance (Public)
282  **************************************************************************/
283 void libvlc_media_list_player_set_media_instance(
284                                      libvlc_media_list_player_t * p_mlp,
285                                      libvlc_media_instance_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_instance_observer( p_mlp );
295         libvlc_media_instance_release( p_mlp->p_mi );
296     }
297     libvlc_media_instance_retain( p_mi );
298     p_mlp->p_mi = p_mi;
299
300     install_media_instance_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_instance_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_instance_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_instance_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_instance_get_state( p_mlp->p_mi, p_e );
370     return (state == libvlc_Opening) || (state == libvlc_Buffering) ||
371            (state == libvlc_Playing);
372 }
373
374 /**************************************************************************
375  *        State (Public)
376  **************************************************************************/
377 libvlc_state_t
378 libvlc_media_list_player_get_state( libvlc_media_list_player_t * p_mlp,
379                                     libvlc_exception_t * p_e )
380 {
381     if( !p_mlp->p_mi )
382         return libvlc_Stopped;
383     return libvlc_media_instance_get_state( p_mlp->p_mi, p_e );
384 }
385
386 /**************************************************************************
387  *        Play item at index (Public)
388  **************************************************************************/
389 void libvlc_media_list_player_play_item_at_index(
390                         libvlc_media_list_player_t * p_mlp,
391                         int i_index,
392                         libvlc_exception_t * p_e )
393 {
394     set_current_playing_item( p_mlp, libvlc_media_list_path_with_root_index(i_index), p_e );
395
396     if( libvlc_exception_raised( p_e ) )
397         return;
398
399     /* Send the next item event */
400     libvlc_event_t event;
401     event.type = libvlc_MediaListPlayerNextItemSet;
402     libvlc_event_send( p_mlp->p_event_manager, &event );
403
404     libvlc_media_instance_play( p_mlp->p_mi, p_e );
405 }
406
407 /**************************************************************************
408  *        Play item (Public)
409  **************************************************************************/
410 void libvlc_media_list_player_play_item(
411                         libvlc_media_list_player_t * p_mlp,
412                         libvlc_media_descriptor_t * p_md,
413                         libvlc_exception_t * p_e )
414 {
415     libvlc_media_list_path_t path = libvlc_media_list_path_of_item( p_mlp->p_mlist, p_md );
416     if( !path )
417     {
418         libvlc_exception_raise( p_e, "No such item in media list" );
419         return;
420     }
421     set_current_playing_item( p_mlp, path, p_e );
422
423     if( libvlc_exception_raised( p_e ) )
424         return;
425
426     libvlc_media_instance_play( p_mlp->p_mi, p_e );
427 }
428
429 /**************************************************************************
430  *       Stop (Public)
431  **************************************************************************/
432 void libvlc_media_list_player_stop( libvlc_media_list_player_t * p_mlp,
433                                     libvlc_exception_t * p_e )
434 {
435     if ( p_mlp->p_mi )
436     {
437         libvlc_media_instance_stop( p_mlp->p_mi, p_e );        
438     }
439
440     vlc_mutex_lock( &p_mlp->object_lock );
441     free( p_mlp->current_playing_item_path );
442     p_mlp->current_playing_item_path = NULL;
443     vlc_mutex_unlock( &p_mlp->object_lock );
444 }
445
446 /**************************************************************************
447  *       Next (Public)
448  **************************************************************************/
449 void libvlc_media_list_player_next( libvlc_media_list_player_t * p_mlp,
450                                     libvlc_exception_t * p_e )
451 {    
452     libvlc_media_list_path_t path;
453
454     if (! p_mlp->p_mlist )
455     {
456         libvlc_exception_raise( p_e, "No more element to play" );
457         return;
458     }
459     
460     libvlc_media_list_lock( p_mlp->p_mlist );
461
462     path = get_next_path( p_mlp );
463
464     if( !path )
465     {
466         libvlc_media_list_unlock( p_mlp->p_mlist );
467         libvlc_exception_raise( p_e, "No more element to play" );
468         libvlc_media_list_player_stop( p_mlp, p_e );
469         return;
470     }
471
472     set_current_playing_item( p_mlp, path, p_e );
473     
474     libvlc_media_instance_play( p_mlp->p_mi, p_e );
475
476     libvlc_media_list_unlock( p_mlp->p_mlist );
477
478     /* Send the next item event */
479     libvlc_event_t event;
480     event.type = libvlc_MediaListPlayerNextItemSet;
481     libvlc_event_send( p_mlp->p_event_manager, &event);
482 }