Fortunes about QT and "hearing" video codecs
[vlc.git] / lib / media_list_player.c
blobd4ea676172b456498f26cb47a2299e3543f75bef
1 /*****************************************************************************
2 * media_list_player.c: libvlc new API media_list player functions
3 *****************************************************************************
4 * Copyright (C) 2007-2015 VLC authors and VideoLAN
5 * $Id$
7 * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
8 * Niles Bindel <zaggal69 # gmail.com>
9 * RĂ©mi Denis-Courmont
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 2.1 of the License, or
14 * (at your option) any later version.
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 Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
30 #include <vlc/libvlc.h>
31 #include <vlc/libvlc_renderer_discoverer.h>
32 #include <vlc/libvlc_picture.h>
33 #include <vlc/libvlc_media.h>
34 #include <vlc/libvlc_media_list.h>
35 #include <vlc/libvlc_media_player.h>
36 #include <vlc/libvlc_media_list_player.h>
37 #include <vlc/libvlc_events.h>
38 #include <assert.h>
40 #include "libvlc_internal.h"
42 #include "media_internal.h" // Abuse, could and should be removed
43 #include "media_list_path.h"
45 //#define DEBUG_MEDIA_LIST_PLAYER
47 /* This is a very dummy implementation of playlist on top of
48 * media_list and media_player.
50 * All this code is doing is simply computing the next item
51 * of a tree of media_list (see get_next_index()), and play
52 * the next item when the current is over. This is happening
53 * via the event callback media_player_reached_end().
55 * This is thread safe, and we use a two keys (locks) scheme
56 * to discriminate between callbacks and regular uses.
59 struct libvlc_media_list_player_t
61 libvlc_event_manager_t event_manager;
62 int i_refcount;
63 int seek_offset;
64 /* Protect access to this structure. */
65 vlc_mutex_t object_lock;
66 /* Protect access to this structure and from callback execution. */
67 vlc_mutex_t mp_callback_lock;
68 vlc_cond_t seek_pending;
69 libvlc_media_list_path_t current_playing_item_path;
70 libvlc_media_t * p_current_playing_item;
71 libvlc_media_list_t * p_mlist;
72 libvlc_media_player_t * p_mi;
73 libvlc_playback_mode_t e_playback_mode;
75 vlc_thread_t thread;
79 * Forward declaration
82 static
83 int set_relative_playlist_position_and_play(libvlc_media_list_player_t *p_mlp,
84 int i_relative_position);
85 static void stop(libvlc_media_list_player_t * p_mlp);
88 * Private functions
91 /**************************************************************************
92 * Shortcuts
93 **************************************************************************/
94 static inline void lock(libvlc_media_list_player_t * p_mlp)
96 // Obtain an access to this structure
97 vlc_mutex_lock(&p_mlp->object_lock);
99 // Make sure no callback will occurs at the same time
100 vlc_mutex_lock(&p_mlp->mp_callback_lock);
103 static inline void unlock(libvlc_media_list_player_t * p_mlp)
105 vlc_mutex_unlock(&p_mlp->mp_callback_lock);
106 vlc_mutex_unlock(&p_mlp->object_lock);
109 static inline void assert_locked(libvlc_media_list_player_t * p_mlp)
111 vlc_mutex_assert(&p_mlp->mp_callback_lock);
112 (void) p_mlp;
115 static inline libvlc_event_manager_t * mlist_em(libvlc_media_list_player_t * p_mlp)
117 assert_locked(p_mlp);
118 return libvlc_media_list_event_manager(p_mlp->p_mlist);
121 static inline libvlc_event_manager_t * mplayer_em(libvlc_media_list_player_t * p_mlp)
123 assert_locked(p_mlp);
124 return libvlc_media_player_event_manager(p_mlp->p_mi);
127 /**************************************************************************
128 * get_next_path (private)
130 * Returns the path to the next item in the list.
131 * If looping is specified and the current item is the last list item in
132 * the list it will return the first item in the list.
133 **************************************************************************/
134 static libvlc_media_list_path_t
135 get_next_path(libvlc_media_list_player_t * p_mlp, bool b_loop)
137 assert_locked(p_mlp);
139 /* We are entered with libvlc_media_list_lock(p_mlp->p_list) */
140 libvlc_media_list_path_t ret;
141 libvlc_media_list_t * p_parent_of_playing_item;
142 libvlc_media_list_t * p_sublist_of_playing_item;
144 if (!p_mlp->current_playing_item_path)
146 if (!libvlc_media_list_count(p_mlp->p_mlist))
147 return NULL;
148 return libvlc_media_list_path_with_root_index(0);
151 p_sublist_of_playing_item = libvlc_media_list_sublist_at_path(
152 p_mlp->p_mlist,
153 p_mlp->current_playing_item_path);
155 /* If item just gained a sublist just play it */
156 if (p_sublist_of_playing_item)
158 int i_count = libvlc_media_list_count(p_sublist_of_playing_item);
159 libvlc_media_list_release(p_sublist_of_playing_item);
160 if (i_count > 0)
161 return libvlc_media_list_path_copy_by_appending(p_mlp->current_playing_item_path, 0);
164 /* Try to catch parent element */
165 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(p_mlp->p_mlist,
166 p_mlp->current_playing_item_path);
168 int depth = libvlc_media_list_path_depth(p_mlp->current_playing_item_path);
169 if (depth < 1 || !p_parent_of_playing_item)
170 return NULL;
172 ret = libvlc_media_list_path_copy(p_mlp->current_playing_item_path);
173 ret[depth - 1]++; /* set to next element */
175 /* If this goes beyond the end of the list */
176 while(ret[depth-1] >= libvlc_media_list_count(p_parent_of_playing_item))
178 depth--;
179 if (depth <= 0)
181 if(b_loop)
183 ret[0] = 0;
184 ret[1] = -1;
185 break;
187 else
189 free(ret);
190 libvlc_media_list_release(p_parent_of_playing_item);
191 return NULL;
194 ret[depth] = -1;
195 ret[depth-1]++;
196 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(
197 p_mlp->p_mlist,
198 ret);
201 libvlc_media_list_release(p_parent_of_playing_item);
202 return ret;
205 /**************************************************************************
206 * find_last_item (private)
208 * Returns the path of the last descendant of a given item path.
209 * Note: Due to the recursive nature of the function and the need to free
210 * media list paths, paths passed in may be freed if they are replaced.
211 Recommended usage is to set return value to the same path that was
212 passed to the function (i.e. item = find_last_item(list, item); )
213 **************************************************************************/
214 static libvlc_media_list_path_t
215 find_last_item( libvlc_media_list_t * p_mlist, libvlc_media_list_path_t current_item )
217 libvlc_media_list_t * p_sublist = libvlc_media_list_sublist_at_path(p_mlist, current_item);
218 libvlc_media_list_path_t last_item_path = current_item;
220 if(p_sublist)
222 int i_count = libvlc_media_list_count(p_sublist);
223 if(i_count > 0)
225 /* Add the last sublist item to the path. */
226 last_item_path = libvlc_media_list_path_copy_by_appending(current_item, i_count - 1);
227 free(current_item);
228 /* Check that sublist item for more descendants. */
229 last_item_path = find_last_item(p_mlist, last_item_path);
232 libvlc_media_list_release(p_sublist);
235 return last_item_path;
238 /**************************************************************************
239 * get_previous_path (private)
241 * Returns the path to the preceding item in the list.
242 * If looping is specified and the current item is the first list item in
243 * the list it will return the last descendant of the last item in the list.
244 **************************************************************************/
245 static libvlc_media_list_path_t
246 get_previous_path(libvlc_media_list_player_t * p_mlp, bool b_loop)
248 assert_locked(p_mlp);
250 /* We are entered with libvlc_media_list_lock(p_mlp->p_list) */
251 libvlc_media_list_path_t ret;
252 libvlc_media_list_t * p_parent_of_playing_item;
254 if (!p_mlp->current_playing_item_path)
256 if (!libvlc_media_list_count(p_mlp->p_mlist))
257 return NULL;
258 return libvlc_media_list_path_with_root_index(0);
261 /* Try to catch parent element */
262 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(
263 p_mlp->p_mlist,
264 p_mlp->current_playing_item_path);
266 int depth = libvlc_media_list_path_depth(p_mlp->current_playing_item_path);
267 if (depth < 1 || !p_parent_of_playing_item)
268 return NULL;
270 /* Set the return path to the current path */
271 ret = libvlc_media_list_path_copy(p_mlp->current_playing_item_path);
273 /* Change the return path to the previous list entry */
274 ret[depth - 1]--; /* set to previous element */
275 ret[depth] = -1;
277 /* Is the return path is beyond the start of the current list? */
278 if(ret[depth - 1] < 0)
280 /* Move to parent of current item */
281 depth--;
283 /* Are we at the root level of the tree? */
284 if (depth <= 0)
286 // Is looping enabled?
287 if(b_loop)
289 int i_count = libvlc_media_list_count(p_parent_of_playing_item);
291 /* Set current play item to the last element in the list */
292 ret[0] = i_count - 1;
293 ret[1] = -1;
295 /* Set the return path to the last descendant item of the current item */
296 ret = find_last_item(p_mlp->p_mlist, ret);
298 else
300 /* No looping so return empty path. */
301 free(ret);
302 ret = NULL;
305 else
307 /* This is the case of moving backward from the beginning of the
308 * subitem list to its parent item.
309 * This ensures that current path is properly terminated to
310 * use that parent.
312 ret[depth] = -1;
315 else
317 ret = find_last_item(p_mlp->p_mlist, ret);
320 libvlc_media_list_release(p_parent_of_playing_item);
321 return ret;
324 static void *playlist_thread(void *data)
326 libvlc_media_list_player_t *mlp = data;
328 vlc_mutex_lock(&mlp->mp_callback_lock);
329 mutex_cleanup_push(&mlp->mp_callback_lock);
331 for (;;)
333 int canc;
335 while (mlp->seek_offset == 0)
336 vlc_cond_wait(&mlp->seek_pending, &mlp->mp_callback_lock);
338 canc = vlc_savecancel();
339 set_relative_playlist_position_and_play(mlp, mlp->seek_offset);
340 mlp->seek_offset = 0;
341 vlc_restorecancel(canc);
344 vlc_cleanup_pop();
345 vlc_assert_unreachable();
348 /**************************************************************************
349 * media_player_reached_end (private) (Event Callback)
350 **************************************************************************/
351 static void
352 media_player_reached_end(const libvlc_event_t * p_event, void * p_user_data)
354 VLC_UNUSED(p_event);
355 libvlc_media_list_player_t * p_mlp = p_user_data;
357 /* This event is triggered from the input thread, and changing item in
358 * the media player requires the input thread to terminate. So we cannot
359 * change the playlist state here (it would cause a deadlock). Instead, we
360 * defer to a separate thread. Avoiding this would be nice... */
361 vlc_mutex_lock(&p_mlp->mp_callback_lock);
362 p_mlp->seek_offset++;
363 vlc_cond_signal(&p_mlp->seek_pending);
364 vlc_mutex_unlock(&p_mlp->mp_callback_lock);
367 /**************************************************************************
368 * playlist_item_deleted (private) (Event Callback)
369 **************************************************************************/
370 static void
371 mlist_item_deleted(const libvlc_event_t * p_event, void * p_user_data)
373 // Nothing to do. For now.
374 (void)p_event; (void)p_user_data;
378 /**************************************************************************
379 * install_playlist_observer (private)
380 **************************************************************************/
381 static void
382 install_playlist_observer(libvlc_media_list_player_t * p_mlp)
384 assert_locked(p_mlp);
385 libvlc_event_attach(mlist_em(p_mlp), libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp);
388 /**************************************************************************
389 * uninstall_playlist_observer (private)
390 **************************************************************************/
391 static void
392 uninstall_playlist_observer(libvlc_media_list_player_t * p_mlp)
394 assert_locked(p_mlp);
395 if (!p_mlp->p_mlist) return;
396 libvlc_event_detach(mlist_em(p_mlp), libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp);
399 /**************************************************************************
400 * install_media_player_observer (private)
401 **************************************************************************/
402 static void
403 install_media_player_observer(libvlc_media_list_player_t * p_mlp)
405 assert_locked(p_mlp);
406 libvlc_event_attach(mplayer_em(p_mlp), libvlc_MediaPlayerEndReached, media_player_reached_end, p_mlp);
410 /**************************************************************************
411 * uninstall_media_player_observer (private)
412 **************************************************************************/
413 static void
414 uninstall_media_player_observer(libvlc_media_list_player_t * p_mlp)
416 assert_locked(p_mlp);
418 // Allow callbacks to run, because detach() will wait until all callbacks are processed.
419 // This is safe because only callbacks are allowed, and there execution will be cancelled.
420 vlc_mutex_unlock(&p_mlp->mp_callback_lock);
421 libvlc_event_detach(mplayer_em(p_mlp), libvlc_MediaPlayerEndReached, media_player_reached_end, p_mlp);
423 // Now, lock back the callback lock. No more callback will be present from this point.
424 vlc_mutex_lock(&p_mlp->mp_callback_lock);
426 // What is here is safe, because we guarantee that we won't be able to anything concurrently,
427 // - except (cancelled) callbacks - thanks to the object_lock.
430 /**************************************************************************
431 * set_current_playing_item (private)
433 * Playlist lock should be held
434 **************************************************************************/
435 static void
436 set_current_playing_item(libvlc_media_list_player_t * p_mlp, libvlc_media_list_path_t path)
438 assert_locked(p_mlp);
440 /* First, save the new path that we are going to play */
441 if (p_mlp->current_playing_item_path != path)
443 free(p_mlp->current_playing_item_path);
444 p_mlp->current_playing_item_path = path;
447 if (!path)
448 return;
450 libvlc_media_t * p_md;
451 p_md = libvlc_media_list_item_at_path(p_mlp->p_mlist, path);
452 if (!p_md)
453 return;
455 /* Make sure media_player_reached_end() won't get called */
456 uninstall_media_player_observer(p_mlp);
458 libvlc_media_player_set_media(p_mlp->p_mi, p_md);
460 install_media_player_observer(p_mlp);
461 libvlc_media_release(p_md); /* for libvlc_media_list_item_at_index */
465 * Public libvlc functions
468 /**************************************************************************
469 * new (Public)
470 **************************************************************************/
471 libvlc_media_list_player_t *
472 libvlc_media_list_player_new(libvlc_instance_t * p_instance)
474 libvlc_media_list_player_t * p_mlp;
475 p_mlp = calloc( 1, sizeof(libvlc_media_list_player_t) );
476 if (unlikely(p_mlp == NULL))
478 libvlc_printerr("Not enough memory");
479 return NULL;
482 p_mlp->i_refcount = 1;
483 p_mlp->seek_offset = 0;
484 vlc_mutex_init(&p_mlp->object_lock);
485 vlc_mutex_init(&p_mlp->mp_callback_lock);
486 vlc_cond_init(&p_mlp->seek_pending);
487 libvlc_event_manager_init(&p_mlp->event_manager, p_mlp);
489 /* Create the underlying media_player */
490 p_mlp->p_mi = libvlc_media_player_new(p_instance);
491 if( p_mlp->p_mi == NULL )
492 goto error;
493 install_media_player_observer(p_mlp);
495 if (vlc_clone(&p_mlp->thread, playlist_thread, p_mlp,
496 VLC_THREAD_PRIORITY_LOW))
498 libvlc_media_player_release(p_mlp->p_mi);
499 goto error;
502 return p_mlp;
503 error:
504 libvlc_event_manager_destroy(&p_mlp->event_manager);
505 vlc_cond_destroy(&p_mlp->seek_pending);
506 vlc_mutex_destroy(&p_mlp->mp_callback_lock);
507 vlc_mutex_destroy(&p_mlp->object_lock);
508 free(p_mlp);
509 return NULL;
512 /**************************************************************************
513 * release (Public)
514 **************************************************************************/
515 void libvlc_media_list_player_release(libvlc_media_list_player_t * p_mlp)
517 if (!p_mlp)
518 return;
520 lock(p_mlp);
521 p_mlp->i_refcount--;
522 if (p_mlp->i_refcount > 0)
524 unlock(p_mlp);
525 return;
527 assert(p_mlp->i_refcount == 0);
528 unlock(p_mlp);
530 vlc_cancel(p_mlp->thread);
531 vlc_join(p_mlp->thread, NULL);
533 lock(p_mlp);
534 /* Keep the lock(), because the uninstall functions
535 * check for it. That's convenient. */
536 uninstall_media_player_observer(p_mlp);
537 libvlc_media_player_release(p_mlp->p_mi);
539 if (p_mlp->p_mlist)
541 uninstall_playlist_observer(p_mlp);
542 libvlc_media_list_release(p_mlp->p_mlist);
545 unlock(p_mlp);
547 libvlc_event_manager_destroy(&p_mlp->event_manager);
548 vlc_cond_destroy(&p_mlp->seek_pending);
549 vlc_mutex_destroy(&p_mlp->mp_callback_lock);
550 vlc_mutex_destroy(&p_mlp->object_lock);
552 free(p_mlp->current_playing_item_path);
553 free(p_mlp);
556 /**************************************************************************
557 * retain (Public)
558 **************************************************************************/
559 void libvlc_media_list_player_retain(libvlc_media_list_player_t * p_mlp)
561 if (!p_mlp)
562 return;
564 lock(p_mlp);
565 p_mlp->i_refcount++;
566 unlock(p_mlp);
569 /**************************************************************************
570 * event_manager (Public)
571 **************************************************************************/
572 libvlc_event_manager_t *
573 libvlc_media_list_player_event_manager(libvlc_media_list_player_t * p_mlp)
575 return &p_mlp->event_manager;
578 /**************************************************************************
579 * set_media_player (Public)
580 **************************************************************************/
581 void libvlc_media_list_player_set_media_player(libvlc_media_list_player_t * p_mlp, libvlc_media_player_t * p_mi)
583 libvlc_media_player_t *p_oldmi;
585 assert(p_mi != NULL);
586 libvlc_media_player_retain(p_mi);
588 lock(p_mlp);
589 uninstall_media_player_observer(p_mlp);
590 p_oldmi = p_mlp->p_mi;
591 p_mlp->p_mi = p_mi;
592 install_media_player_observer(p_mlp);
593 unlock(p_mlp);
595 libvlc_media_player_release(p_oldmi);
598 /**************************************************************************
599 * get_media_player (Public)
600 **************************************************************************/
601 libvlc_media_player_t * libvlc_media_list_player_get_media_player(libvlc_media_list_player_t * p_mlp)
603 libvlc_media_player_retain(p_mlp->p_mi);
604 return p_mlp->p_mi;
607 /**************************************************************************
608 * set_media_list (Public)
609 **************************************************************************/
610 void libvlc_media_list_player_set_media_list(libvlc_media_list_player_t * p_mlp, libvlc_media_list_t * p_mlist)
612 assert (p_mlist);
614 lock(p_mlp);
615 if (p_mlp->p_mlist)
617 uninstall_playlist_observer(p_mlp);
618 libvlc_media_list_release(p_mlp->p_mlist);
620 libvlc_media_list_retain(p_mlist);
621 p_mlp->p_mlist = p_mlist;
623 install_playlist_observer(p_mlp);
625 unlock(p_mlp);
628 /**************************************************************************
629 * Play (Public)
630 **************************************************************************/
631 void libvlc_media_list_player_play(libvlc_media_list_player_t * p_mlp)
633 lock(p_mlp);
634 if (!p_mlp->current_playing_item_path)
636 set_relative_playlist_position_and_play(p_mlp, 1);
637 unlock(p_mlp);
638 return; /* Will set to play */
640 libvlc_media_player_play(p_mlp->p_mi);
641 unlock(p_mlp);
645 /**************************************************************************
646 * Pause (Public)
647 **************************************************************************/
648 void libvlc_media_list_player_pause(libvlc_media_list_player_t * p_mlp)
650 lock(p_mlp);
651 libvlc_media_player_pause(p_mlp->p_mi);
652 unlock(p_mlp);
655 void libvlc_media_list_player_set_pause(libvlc_media_list_player_t * p_mlp,
656 int do_pause)
658 lock(p_mlp);
659 libvlc_media_player_set_pause(p_mlp->p_mi, do_pause);
660 unlock(p_mlp);
663 /**************************************************************************
664 * is_playing (Public)
665 **************************************************************************/
667 libvlc_media_list_player_is_playing(libvlc_media_list_player_t * p_mlp)
669 libvlc_state_t state = libvlc_media_player_get_state(p_mlp->p_mi);
670 return (state == libvlc_Opening) || (state == libvlc_Playing);
673 /**************************************************************************
674 * State (Public)
675 **************************************************************************/
676 libvlc_state_t
677 libvlc_media_list_player_get_state(libvlc_media_list_player_t * p_mlp)
679 return libvlc_media_player_get_state(p_mlp->p_mi);
682 /**************************************************************************
683 * Play item at index (Public)
684 **************************************************************************/
685 int libvlc_media_list_player_play_item_at_index(libvlc_media_list_player_t * p_mlp, int i_index)
687 lock(p_mlp);
688 libvlc_media_list_path_t path = libvlc_media_list_path_with_root_index(i_index);
689 set_current_playing_item(p_mlp, path);
690 libvlc_media_t *p_md = libvlc_media_player_get_media(p_mlp->p_mi);
691 libvlc_media_player_play(p_mlp->p_mi);
692 unlock(p_mlp);
694 if (!p_md)
695 return -1;
697 /* Send the next item event */
698 libvlc_event_t event;
699 event.type = libvlc_MediaListPlayerNextItemSet;
700 event.u.media_list_player_next_item_set.item = p_md;
701 libvlc_event_send(&p_mlp->event_manager, &event);
702 libvlc_media_release(p_md);
703 return 0;
706 /**************************************************************************
707 * Play item (Public)
708 **************************************************************************/
709 int libvlc_media_list_player_play_item(libvlc_media_list_player_t * p_mlp, libvlc_media_t * p_md)
711 lock(p_mlp);
712 libvlc_media_list_path_t path = libvlc_media_list_path_of_item(p_mlp->p_mlist, p_md);
713 if (!path)
715 libvlc_printerr("Item not found in media list");
716 unlock(p_mlp);
717 return -1;
720 set_current_playing_item(p_mlp, path);
721 libvlc_media_player_play(p_mlp->p_mi);
722 unlock(p_mlp);
723 return 0;
726 /**************************************************************************
727 * Stop (Private)
729 * Lock must be held.
730 **************************************************************************/
731 static void stop(libvlc_media_list_player_t * p_mlp)
733 assert_locked(p_mlp);
735 /* We are not interested in getting media stop event now */
736 uninstall_media_player_observer(p_mlp);
737 libvlc_media_player_stop(p_mlp->p_mi);
738 install_media_player_observer(p_mlp);
740 free(p_mlp->current_playing_item_path);
741 p_mlp->current_playing_item_path = NULL;
743 /* Send the event */
744 libvlc_event_t event;
745 event.type = libvlc_MediaListPlayerStopped;
746 libvlc_event_send(&p_mlp->event_manager, &event);
749 /**************************************************************************
750 * Stop (Public)
751 **************************************************************************/
752 void libvlc_media_list_player_stop(libvlc_media_list_player_t * p_mlp)
754 lock(p_mlp);
755 stop(p_mlp);
756 unlock(p_mlp);
759 /**************************************************************************
760 * Set relative playlist position and play (Private)
762 * Sets the currently played item to the given relative play item position
763 * (based on the currently playing item) and then begins the new item playback.
764 * Lock must be held.
765 **************************************************************************/
766 static int set_relative_playlist_position_and_play(
767 libvlc_media_list_player_t * p_mlp,
768 int i_relative_position)
770 assert_locked(p_mlp);
772 if (!p_mlp->p_mlist)
774 libvlc_printerr("No media list");
775 return -1;
778 libvlc_media_list_lock(p_mlp->p_mlist);
780 libvlc_media_list_path_t path = p_mlp->current_playing_item_path;
782 if(p_mlp->e_playback_mode != libvlc_playback_mode_repeat)
784 bool b_loop = (p_mlp->e_playback_mode == libvlc_playback_mode_loop);
786 while (i_relative_position > 0)
788 path = get_next_path(p_mlp, b_loop);
789 set_current_playing_item(p_mlp, path);
790 --i_relative_position;
793 while (i_relative_position < 0)
795 path = get_previous_path(p_mlp, b_loop);
796 set_current_playing_item(p_mlp, path);
797 ++i_relative_position;
800 else
802 set_current_playing_item(p_mlp, path);
805 #ifdef DEBUG_MEDIA_LIST_PLAYER
806 printf("Playing:");
807 libvlc_media_list_path_dump(path);
808 #endif
810 if (!path)
812 libvlc_media_list_unlock(p_mlp->p_mlist);
813 /* Send list played event */
814 libvlc_event_t event;
815 event.type = libvlc_MediaListPlayerPlayed;
816 libvlc_event_send(&p_mlp->event_manager, &event);
817 return -1;
820 libvlc_media_player_play(p_mlp->p_mi);
822 libvlc_media_list_unlock(p_mlp->p_mlist);
824 /* Send the next item event */
825 libvlc_event_t event;
826 event.type = libvlc_MediaListPlayerNextItemSet;
827 libvlc_media_t * p_md = libvlc_media_list_item_at_path(p_mlp->p_mlist, path);
828 event.u.media_list_player_next_item_set.item = p_md;
829 libvlc_event_send(&p_mlp->event_manager, &event);
830 libvlc_media_release(p_md);
831 return 0;
834 /**************************************************************************
835 * Next (Public)
836 **************************************************************************/
837 int libvlc_media_list_player_next(libvlc_media_list_player_t * p_mlp)
839 lock(p_mlp);
840 int failure = set_relative_playlist_position_and_play(p_mlp, 1);
841 unlock(p_mlp);
842 return failure;
845 /**************************************************************************
846 * Previous (Public)
847 **************************************************************************/
848 int libvlc_media_list_player_previous(libvlc_media_list_player_t * p_mlp)
850 lock(p_mlp);
851 int failure = set_relative_playlist_position_and_play(p_mlp, -1);
852 unlock(p_mlp);
853 return failure;
856 /**************************************************************************
857 * Set Playback Mode (Public)
858 **************************************************************************/
859 void libvlc_media_list_player_set_playback_mode(
860 libvlc_media_list_player_t * p_mlp,
861 libvlc_playback_mode_t e_mode )
863 lock(p_mlp);
864 p_mlp->e_playback_mode = e_mode;
865 unlock(p_mlp);