1 /*****************************************************************************
2 * media_list_player.c: libvlc new API media_list player functions
3 *****************************************************************************
4 * Copyright (C) 2007 the VideoLAN team
7 * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
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.
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.
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"
28 struct libvlc_media_list_player_t
30 libvlc_event_manager_t * p_event_manager;
31 libvlc_instance_t * p_libvlc_instance;
33 vlc_mutex_t object_lock;
34 libvlc_media_list_path_t current_playing_item_path;
35 libvlc_media_t * p_current_playing_item;
36 libvlc_media_list_t * p_mlist;
37 libvlc_media_player_t * p_mi;
44 /**************************************************************************
45 * get_next_index (private)
47 * Simple next item fetcher.
48 **************************************************************************/
49 static libvlc_media_list_path_t
50 get_next_path( libvlc_media_list_player_t * p_mlp )
52 /* We are entered with libvlc_media_list_lock( p_mlp->p_list ) */
53 libvlc_media_list_path_t ret;
54 libvlc_media_list_t * p_parent_of_playing_item;
55 libvlc_media_list_t * p_sublist_of_playing_item;
57 if ( !p_mlp->current_playing_item_path )
59 if( !libvlc_media_list_count( p_mlp->p_mlist, NULL ) )
61 return libvlc_media_list_path_with_root_index(0);
64 p_sublist_of_playing_item = libvlc_media_list_sublist_at_path(
66 p_mlp->current_playing_item_path );
68 /* If item just gained a sublist just play it */
69 if( p_sublist_of_playing_item )
71 libvlc_media_list_release( p_sublist_of_playing_item );
72 return libvlc_media_list_path_copy_by_appending( p_mlp->current_playing_item_path, 0 );
75 /* Try to catch next element */
76 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(
78 p_mlp->current_playing_item_path );
80 int deepness = libvlc_media_list_path_deepness( p_mlp->current_playing_item_path );
81 if( deepness < 1 || !p_parent_of_playing_item )
84 ret = libvlc_media_list_path_copy( p_mlp->current_playing_item_path );
86 while( ret[deepness-1] >= libvlc_media_list_count( p_parent_of_playing_item, NULL ) )
92 libvlc_media_list_release( p_parent_of_playing_item );
97 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(
101 libvlc_media_list_release( p_parent_of_playing_item );
105 /**************************************************************************
106 * media_player_reached_end (private) (Event Callback)
107 **************************************************************************/
109 media_player_reached_end( const libvlc_event_t * p_event,
112 libvlc_media_list_player_t * p_mlp = p_user_data;
113 libvlc_media_player_t * p_mi = p_event->p_obj;
114 libvlc_media_t *p_md, * p_current_md;
116 p_md = libvlc_media_player_get_media( p_mi, NULL );
117 /* XXX: need if p_mlp->p_current_playing_index is beyond */
118 p_current_md = libvlc_media_list_item_at_path(
120 p_mlp->current_playing_item_path );
121 if( p_md != p_current_md )
123 msg_Warn( p_mlp->p_libvlc_instance->p_libvlc_int,
124 "We are not sync-ed with the media instance" );
125 libvlc_media_release( p_md );
126 libvlc_media_release( p_current_md );
129 libvlc_media_release( p_md );
130 libvlc_media_release( p_current_md );
131 libvlc_media_list_player_next( p_mlp, NULL );
134 /**************************************************************************
135 * playlist_item_deleted (private) (Event Callback)
136 **************************************************************************/
138 mlist_item_deleted( const libvlc_event_t * p_event, void * p_user_data )
140 libvlc_media_t * p_current_md;
141 libvlc_media_list_player_t * p_mlp = p_user_data;
142 libvlc_media_list_t * p_emitting_mlist = p_event->p_obj;
143 /* XXX: need if p_mlp->p_current_playing_index is beyond */
144 p_current_md = libvlc_media_list_item_at_path(
146 p_mlp->current_playing_item_path );
148 if( p_event->u.media_list_item_deleted.item == p_current_md &&
149 p_emitting_mlist == p_mlp->p_mlist )
151 /* We are playing this item, we choose to stop */
152 libvlc_media_list_player_stop( p_mlp, NULL );
156 /**************************************************************************
157 * install_playlist_observer (private)
158 **************************************************************************/
160 install_playlist_observer( libvlc_media_list_player_t * p_mlp )
162 libvlc_event_attach( libvlc_media_list_event_manager( p_mlp->p_mlist, NULL ),
163 libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp, NULL );
166 /**************************************************************************
167 * uninstall_playlist_observer (private)
168 **************************************************************************/
170 uninstall_playlist_observer( libvlc_media_list_player_t * p_mlp )
172 if ( !p_mlp->p_mlist )
177 libvlc_event_detach( libvlc_media_list_event_manager( p_mlp->p_mlist, NULL ),
178 libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp, NULL );
181 /**************************************************************************
182 * install_media_player_observer (private)
183 **************************************************************************/
185 install_media_player_observer( libvlc_media_list_player_t * p_mlp )
187 libvlc_event_attach( libvlc_media_player_event_manager( p_mlp->p_mi, NULL ),
188 libvlc_MediaPlayerEndReached,
189 media_player_reached_end, p_mlp, NULL );
193 /**************************************************************************
194 * uninstall_media_player_observer (private)
195 **************************************************************************/
197 uninstall_media_player_observer( libvlc_media_list_player_t * p_mlp )
204 libvlc_event_detach( libvlc_media_player_event_manager( p_mlp->p_mi, NULL ),
205 libvlc_MediaPlayerEndReached,
206 media_player_reached_end, p_mlp, NULL );
209 /**************************************************************************
210 * set_current_playing_item (private)
212 * Playlist lock should be held
213 **************************************************************************/
215 set_current_playing_item( libvlc_media_list_player_t * p_mlp,
216 libvlc_media_list_path_t path,
217 libvlc_exception_t * p_e )
221 libvlc_media_t * p_md;
223 p_md = libvlc_media_list_item_at_path( p_mlp->p_mlist, path );
224 vlc_mutex_lock( &p_mlp->object_lock );
226 if( p_mlp->current_playing_item_path != path )
228 free( p_mlp->current_playing_item_path );
229 p_mlp->current_playing_item_path = path;
234 vlc_mutex_unlock( &p_mlp->object_lock );
238 /* We are not interested in getting media stop event now */
239 uninstall_media_player_observer( p_mlp );
243 p_mlp->p_mi = libvlc_media_player_new_from_media(p_md, p_e);
246 if( p_md->p_subitems && libvlc_media_list_count( p_md->p_subitems, NULL ) > 0 )
248 libvlc_media_t * p_submd;
249 p_submd = libvlc_media_list_item_at_index( p_md->p_subitems, 0, NULL );
250 libvlc_media_player_set_media( p_mlp->p_mi, p_submd, NULL );
251 libvlc_media_release( p_submd );
254 libvlc_media_player_set_media( p_mlp->p_mi, p_md, NULL );
255 // wait_playing_state(); /* If we want to be synchronous */
256 install_media_player_observer( p_mlp );
258 vlc_mutex_unlock( &p_mlp->object_lock );
260 libvlc_media_release( p_md ); /* for libvlc_media_list_item_at_index */
264 * Public libvlc functions
267 /**************************************************************************
269 **************************************************************************/
270 libvlc_media_list_player_t *
271 libvlc_media_list_player_new( libvlc_instance_t * p_instance,
272 libvlc_exception_t * p_e )
275 libvlc_media_list_player_t * p_mlp;
276 p_mlp = malloc(sizeof(libvlc_media_list_player_t));
280 p_mlp->current_playing_item_path = NULL;
282 p_mlp->p_mlist = NULL;
283 vlc_mutex_init( &p_mlp->object_lock );
284 p_mlp->p_event_manager = libvlc_event_manager_new( p_mlp,
287 libvlc_event_manager_register_event_type( p_mlp->p_event_manager,
288 libvlc_MediaListPlayerNextItemSet, p_e );
293 /**************************************************************************
295 **************************************************************************/
296 void libvlc_media_list_player_release( libvlc_media_list_player_t * p_mlp )
301 vlc_mutex_lock( &p_mlp->object_lock );
304 if( p_mlp->i_refcount > 0 )
306 vlc_mutex_unlock( &p_mlp->object_lock );
309 vlc_mutex_unlock( &p_mlp->object_lock );
310 vlc_mutex_destroy( &p_mlp->object_lock );
312 libvlc_event_manager_release( p_mlp->p_event_manager );
313 libvlc_media_player_release( p_mlp->p_mi );
317 uninstall_playlist_observer( p_mlp );
318 libvlc_media_list_release( p_mlp->p_mlist );
321 free( p_mlp->current_playing_item_path );
325 /**************************************************************************
326 * set_media_player (Public)
327 **************************************************************************/
328 void libvlc_media_list_player_set_media_player(
329 libvlc_media_list_player_t * p_mlp,
330 libvlc_media_player_t * p_mi,
331 libvlc_exception_t * p_e )
335 vlc_mutex_lock( &p_mlp->object_lock );
339 uninstall_media_player_observer( p_mlp );
340 libvlc_media_player_release( p_mlp->p_mi );
342 libvlc_media_player_retain( p_mi );
345 install_media_player_observer( p_mlp );
347 vlc_mutex_unlock( &p_mlp->object_lock );
350 /**************************************************************************
351 * set_media_list (Public)
352 **************************************************************************/
353 void libvlc_media_list_player_set_media_list(
354 libvlc_media_list_player_t * p_mlp,
355 libvlc_media_list_t * p_mlist,
356 libvlc_exception_t * p_e )
358 vlc_mutex_lock( &p_mlp->object_lock );
360 if( libvlc_media_list_player_is_playing( p_mlp, p_e ) )
362 libvlc_media_player_stop( p_mlp->p_mi, p_e );
363 /* Don't bother if there was an error. */
364 libvlc_exception_clear( p_e );
369 uninstall_playlist_observer( p_mlp );
370 libvlc_media_list_release( p_mlp->p_mlist );
372 libvlc_media_list_retain( p_mlist );
373 p_mlp->p_mlist = p_mlist;
375 install_playlist_observer( p_mlp );
377 vlc_mutex_unlock( &p_mlp->object_lock );
380 /**************************************************************************
382 **************************************************************************/
383 void libvlc_media_list_player_play( libvlc_media_list_player_t * p_mlp,
384 libvlc_exception_t * p_e )
386 if( !p_mlp->current_playing_item_path )
388 libvlc_media_list_player_next( p_mlp, p_e );
389 return; /* Will set to play */
392 libvlc_media_player_play( p_mlp->p_mi, p_e );
396 /**************************************************************************
398 **************************************************************************/
399 void libvlc_media_list_player_pause( libvlc_media_list_player_t * p_mlp,
400 libvlc_exception_t * p_e )
404 libvlc_media_player_pause( p_mlp->p_mi, p_e );
407 /**************************************************************************
408 * is_playing (Public)
409 **************************************************************************/
411 libvlc_media_list_player_is_playing( libvlc_media_list_player_t * p_mlp,
412 libvlc_exception_t * p_e )
414 libvlc_state_t state = libvlc_media_player_get_state( p_mlp->p_mi, p_e );
415 return (state == libvlc_Opening) || (state == libvlc_Buffering) ||
416 (state == libvlc_Playing);
419 /**************************************************************************
421 **************************************************************************/
423 libvlc_media_list_player_get_state( libvlc_media_list_player_t * p_mlp,
424 libvlc_exception_t * p_e )
428 return libvlc_media_player_get_state( p_mlp->p_mi, p_e );
431 /**************************************************************************
432 * Play item at index (Public)
433 **************************************************************************/
434 void libvlc_media_list_player_play_item_at_index(
435 libvlc_media_list_player_t * p_mlp,
437 libvlc_exception_t * p_e )
439 set_current_playing_item( p_mlp, libvlc_media_list_path_with_root_index(i_index), p_e );
441 if( libvlc_exception_raised( p_e ) )
444 /* Send the next item event */
445 libvlc_event_t event;
446 event.type = libvlc_MediaListPlayerNextItemSet;
447 libvlc_event_send( p_mlp->p_event_manager, &event );
449 libvlc_media_player_play( p_mlp->p_mi, p_e );
452 /**************************************************************************
454 **************************************************************************/
455 void libvlc_media_list_player_play_item(
456 libvlc_media_list_player_t * p_mlp,
457 libvlc_media_t * p_md,
458 libvlc_exception_t * p_e )
460 libvlc_media_list_path_t path = libvlc_media_list_path_of_item( p_mlp->p_mlist, p_md );
463 libvlc_exception_raise( p_e, "No such item in media list" );
466 set_current_playing_item( p_mlp, path, p_e );
468 if( libvlc_exception_raised( p_e ) )
471 libvlc_media_player_play( p_mlp->p_mi, p_e );
474 /**************************************************************************
476 **************************************************************************/
477 void libvlc_media_list_player_stop( libvlc_media_list_player_t * p_mlp,
478 libvlc_exception_t * p_e )
482 /* We are not interested in getting media stop event now */
483 uninstall_media_player_observer( p_mlp );
484 libvlc_media_player_stop( p_mlp->p_mi, p_e );
485 install_media_player_observer( p_mlp );
488 vlc_mutex_lock( &p_mlp->object_lock );
489 free( p_mlp->current_playing_item_path );
490 p_mlp->current_playing_item_path = NULL;
491 vlc_mutex_unlock( &p_mlp->object_lock );
494 /**************************************************************************
496 **************************************************************************/
497 void libvlc_media_list_player_next( libvlc_media_list_player_t * p_mlp,
498 libvlc_exception_t * p_e )
500 libvlc_media_list_path_t path;
502 if (! p_mlp->p_mlist )
504 libvlc_exception_raise( p_e, "No more element to play" );
508 libvlc_media_list_lock( p_mlp->p_mlist );
510 path = get_next_path( p_mlp );
514 libvlc_media_list_unlock( p_mlp->p_mlist );
515 libvlc_exception_raise( p_e, "No more element to play" );
516 libvlc_media_list_player_stop( p_mlp, p_e );
520 set_current_playing_item( p_mlp, path, p_e );
522 libvlc_media_player_play( p_mlp->p_mi, p_e );
524 libvlc_media_list_unlock( p_mlp->p_mlist );
526 /* Send the next item event */
527 libvlc_event_t event;
528 event.type = libvlc_MediaListPlayerNextItemSet;
529 libvlc_event_send( p_mlp->p_event_manager, &event);