qt: "short-jump-size" is in seconds, not an mtime_t
[vlc.git] / lib / media_list_player.c
blob7f4d427f632098b26be956ec4289d15967ab4f7d
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_media.h>
33 #include <vlc/libvlc_media_list.h>
34 #include <vlc/libvlc_media_player.h>
35 #include <vlc/libvlc_media_list_player.h>
36 #include <vlc/libvlc_events.h>
37 #include <assert.h>
39 #include "libvlc_internal.h"
41 #include "media_internal.h" // Abuse, could and should be removed
42 #include "media_list_path.h"
44 //#define DEBUG_MEDIA_LIST_PLAYER
46 /* This is a very dummy implementation of playlist on top of
47 * media_list and media_player.
49 * All this code is doing is simply computing the next item
50 * of a tree of media_list (see get_next_index()), and play
51 * the next item when the current is over. This is happening
52 * via the event callback media_player_reached_end().
54 * This is thread safe, and we use a two keys (locks) scheme
55 * to discriminate between callbacks and regular uses.
58 struct libvlc_media_list_player_t
60 libvlc_event_manager_t event_manager;
61 int i_refcount;
62 int seek_offset;
63 /* Protect access to this structure. */
64 vlc_mutex_t object_lock;
65 /* Protect access to this structure and from callback execution. */
66 vlc_mutex_t mp_callback_lock;
67 vlc_cond_t seek_pending;
68 libvlc_media_list_path_t current_playing_item_path;
69 libvlc_media_t * p_current_playing_item;
70 libvlc_media_list_t * p_mlist;
71 libvlc_media_player_t * p_mi;
72 libvlc_playback_mode_t e_playback_mode;
74 vlc_thread_t thread;
77 /* This is not yet exported by libvlccore */
78 static inline void vlc_assert_locked(vlc_mutex_t *mutex)
80 VLC_UNUSED(mutex);
84 * Forward declaration
87 static
88 int set_relative_playlist_position_and_play(libvlc_media_list_player_t *p_mlp,
89 int i_relative_position);
90 static void stop(libvlc_media_list_player_t * p_mlp);
93 * Private functions
96 /**************************************************************************
97 * Shortcuts
98 **************************************************************************/
99 static inline void lock(libvlc_media_list_player_t * p_mlp)
101 // Obtain an access to this structure
102 vlc_mutex_lock(&p_mlp->object_lock);
104 // Make sure no callback will occurs at the same time
105 vlc_mutex_lock(&p_mlp->mp_callback_lock);
108 static inline void unlock(libvlc_media_list_player_t * p_mlp)
110 vlc_mutex_unlock(&p_mlp->mp_callback_lock);
111 vlc_mutex_unlock(&p_mlp->object_lock);
114 static inline void assert_locked(libvlc_media_list_player_t * p_mlp)
116 vlc_assert_locked(&p_mlp->mp_callback_lock);
119 static inline libvlc_event_manager_t * mlist_em(libvlc_media_list_player_t * p_mlp)
121 assert_locked(p_mlp);
122 return libvlc_media_list_event_manager(p_mlp->p_mlist);
125 static inline libvlc_event_manager_t * mplayer_em(libvlc_media_list_player_t * p_mlp)
127 assert_locked(p_mlp);
128 return libvlc_media_player_event_manager(p_mlp->p_mi);
131 /**************************************************************************
132 * get_next_path (private)
134 * Returns the path to the next item in the list.
135 * If looping is specified and the current item is the last list item in
136 * the list it will return the first item in the list.
137 **************************************************************************/
138 static libvlc_media_list_path_t
139 get_next_path(libvlc_media_list_player_t * p_mlp, bool b_loop)
141 assert_locked(p_mlp);
143 /* We are entered with libvlc_media_list_lock(p_mlp->p_list) */
144 libvlc_media_list_path_t ret;
145 libvlc_media_list_t * p_parent_of_playing_item;
146 libvlc_media_list_t * p_sublist_of_playing_item;
148 if (!p_mlp->current_playing_item_path)
150 if (!libvlc_media_list_count(p_mlp->p_mlist))
151 return NULL;
152 return libvlc_media_list_path_with_root_index(0);
155 p_sublist_of_playing_item = libvlc_media_list_sublist_at_path(
156 p_mlp->p_mlist,
157 p_mlp->current_playing_item_path);
159 /* If item just gained a sublist just play it */
160 if (p_sublist_of_playing_item)
162 int i_count = libvlc_media_list_count(p_sublist_of_playing_item);
163 libvlc_media_list_release(p_sublist_of_playing_item);
164 if (i_count > 0)
165 return libvlc_media_list_path_copy_by_appending(p_mlp->current_playing_item_path, 0);
168 /* Try to catch parent element */
169 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(p_mlp->p_mlist,
170 p_mlp->current_playing_item_path);
172 int depth = libvlc_media_list_path_depth(p_mlp->current_playing_item_path);
173 if (depth < 1 || !p_parent_of_playing_item)
174 return NULL;
176 ret = libvlc_media_list_path_copy(p_mlp->current_playing_item_path);
177 ret[depth - 1]++; /* set to next element */
179 /* If this goes beyond the end of the list */
180 while(ret[depth-1] >= libvlc_media_list_count(p_parent_of_playing_item))
182 depth--;
183 if (depth <= 0)
185 if(b_loop)
187 ret[0] = 0;
188 ret[1] = -1;
189 break;
191 else
193 free(ret);
194 libvlc_media_list_release(p_parent_of_playing_item);
195 return NULL;
198 ret[depth] = -1;
199 ret[depth-1]++;
200 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(
201 p_mlp->p_mlist,
202 ret);
205 libvlc_media_list_release(p_parent_of_playing_item);
206 return ret;
209 /**************************************************************************
210 * find_last_item (private)
212 * Returns the path of the last descendant of a given item path.
213 * Note: Due to the recursive nature of the function and the need to free
214 * media list paths, paths passed in may be freed if they are replaced.
215 Recommended usage is to set return value to the same path that was
216 passed to the function (i.e. item = find_last_item(list, item); )
217 **************************************************************************/
218 static libvlc_media_list_path_t
219 find_last_item( libvlc_media_list_t * p_mlist, libvlc_media_list_path_t current_item )
221 libvlc_media_list_t * p_sublist = libvlc_media_list_sublist_at_path(p_mlist, current_item);
222 libvlc_media_list_path_t last_item_path = current_item;
224 if(p_sublist)
226 int i_count = libvlc_media_list_count(p_sublist);
227 if(i_count > 0)
229 /* Add the last sublist item to the path. */
230 last_item_path = libvlc_media_list_path_copy_by_appending(current_item, i_count - 1);
231 free(current_item);
232 /* Check that sublist item for more descendants. */
233 last_item_path = find_last_item(p_mlist, last_item_path);
236 libvlc_media_list_release(p_sublist);
239 return last_item_path;
242 /**************************************************************************
243 * get_previous_path (private)
245 * Returns the path to the preceding item in the list.
246 * If looping is specified and the current item is the first list item in
247 * the list it will return the last descendant of the last item in the list.
248 **************************************************************************/
249 static libvlc_media_list_path_t
250 get_previous_path(libvlc_media_list_player_t * p_mlp, bool b_loop)
252 assert_locked(p_mlp);
254 /* We are entered with libvlc_media_list_lock(p_mlp->p_list) */
255 libvlc_media_list_path_t ret;
256 libvlc_media_list_t * p_parent_of_playing_item;
258 if (!p_mlp->current_playing_item_path)
260 if (!libvlc_media_list_count(p_mlp->p_mlist))
261 return NULL;
262 return libvlc_media_list_path_with_root_index(0);
265 /* Try to catch parent element */
266 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(
267 p_mlp->p_mlist,
268 p_mlp->current_playing_item_path);
270 int depth = libvlc_media_list_path_depth(p_mlp->current_playing_item_path);
271 if (depth < 1 || !p_parent_of_playing_item)
272 return NULL;
274 /* Set the return path to the current path */
275 ret = libvlc_media_list_path_copy(p_mlp->current_playing_item_path);
277 /* Change the return path to the previous list entry */
278 ret[depth - 1]--; /* set to previous element */
279 ret[depth] = -1;
281 /* Is the return path is beyond the start of the current list? */
282 if(ret[depth - 1] < 0)
284 /* Move to parent of current item */
285 depth--;
287 /* Are we at the root level of the tree? */
288 if (depth <= 0)
290 // Is looping enabled?
291 if(b_loop)
293 int i_count = libvlc_media_list_count(p_parent_of_playing_item);
295 /* Set current play item to the last element in the list */
296 ret[0] = i_count - 1;
297 ret[1] = -1;
299 /* Set the return path to the last descendant item of the current item */
300 ret = find_last_item(p_mlp->p_mlist, ret);
302 else
304 /* No looping so return empty path. */
305 free(ret);
306 ret = NULL;
309 else
311 /* This is the case of moving backward from the beginning of the
312 * subitem list to its parent item.
313 * This ensures that current path is properly terminated to
314 * use that parent.
316 ret[depth] = -1;
319 else
321 ret = find_last_item(p_mlp->p_mlist, ret);
324 libvlc_media_list_release(p_parent_of_playing_item);
325 return ret;
328 static void *playlist_thread(void *data)
330 libvlc_media_list_player_t *mlp = data;
332 vlc_mutex_lock(&mlp->mp_callback_lock);
333 mutex_cleanup_push(&mlp->mp_callback_lock);
335 for (;;)
337 int canc;
339 while (mlp->seek_offset == 0)
340 vlc_cond_wait(&mlp->seek_pending, &mlp->mp_callback_lock);
342 canc = vlc_savecancel();
343 set_relative_playlist_position_and_play(mlp, mlp->seek_offset);
344 mlp->seek_offset = 0;
345 vlc_restorecancel(canc);
348 vlc_cleanup_pop();
349 vlc_assert_unreachable();
352 /**************************************************************************
353 * media_player_reached_end (private) (Event Callback)
354 **************************************************************************/
355 static void
356 media_player_reached_end(const libvlc_event_t * p_event, void * p_user_data)
358 VLC_UNUSED(p_event);
359 libvlc_media_list_player_t * p_mlp = p_user_data;
361 /* This event is triggered from the input thread, and changing item in
362 * the media player requires the input thread to terminate. So we cannot
363 * change the playlist state here (it would cause a deadlock). Instead, we
364 * defer to a separate thread. Avoiding this would be nice... */
365 vlc_mutex_lock(&p_mlp->mp_callback_lock);
366 p_mlp->seek_offset++;
367 vlc_cond_signal(&p_mlp->seek_pending);
368 vlc_mutex_unlock(&p_mlp->mp_callback_lock);
371 /**************************************************************************
372 * playlist_item_deleted (private) (Event Callback)
373 **************************************************************************/
374 static void
375 mlist_item_deleted(const libvlc_event_t * p_event, void * p_user_data)
377 // Nothing to do. For now.
378 (void)p_event; (void)p_user_data;
382 /**************************************************************************
383 * install_playlist_observer (private)
384 **************************************************************************/
385 static void
386 install_playlist_observer(libvlc_media_list_player_t * p_mlp)
388 assert_locked(p_mlp);
389 libvlc_event_attach(mlist_em(p_mlp), libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp);
392 /**************************************************************************
393 * uninstall_playlist_observer (private)
394 **************************************************************************/
395 static void
396 uninstall_playlist_observer(libvlc_media_list_player_t * p_mlp)
398 assert_locked(p_mlp);
399 if (!p_mlp->p_mlist) return;
400 libvlc_event_detach(mlist_em(p_mlp), libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp);
403 /**************************************************************************
404 * install_media_player_observer (private)
405 **************************************************************************/
406 static void
407 install_media_player_observer(libvlc_media_list_player_t * p_mlp)
409 assert_locked(p_mlp);
410 libvlc_event_attach(mplayer_em(p_mlp), libvlc_MediaPlayerEndReached, media_player_reached_end, p_mlp);
414 /**************************************************************************
415 * uninstall_media_player_observer (private)
416 **************************************************************************/
417 static void
418 uninstall_media_player_observer(libvlc_media_list_player_t * p_mlp)
420 assert_locked(p_mlp);
422 // Allow callbacks to run, because detach() will wait until all callbacks are processed.
423 // This is safe because only callbacks are allowed, and there execution will be cancelled.
424 vlc_mutex_unlock(&p_mlp->mp_callback_lock);
425 libvlc_event_detach(mplayer_em(p_mlp), libvlc_MediaPlayerEndReached, media_player_reached_end, p_mlp);
427 // Now, lock back the callback lock. No more callback will be present from this point.
428 vlc_mutex_lock(&p_mlp->mp_callback_lock);
430 // What is here is safe, because we guarantee that we won't be able to anything concurrently,
431 // - except (cancelled) callbacks - thanks to the object_lock.
434 /**************************************************************************
435 * set_current_playing_item (private)
437 * Playlist lock should be held
438 **************************************************************************/
439 static void
440 set_current_playing_item(libvlc_media_list_player_t * p_mlp, libvlc_media_list_path_t path)
442 assert_locked(p_mlp);
444 /* First, save the new path that we are going to play */
445 if (p_mlp->current_playing_item_path != path)
447 free(p_mlp->current_playing_item_path);
448 p_mlp->current_playing_item_path = path;
451 if (!path)
452 return;
454 libvlc_media_t * p_md;
455 p_md = libvlc_media_list_item_at_path(p_mlp->p_mlist, path);
456 if (!p_md)
457 return;
459 /* Make sure media_player_reached_end() won't get called */
460 uninstall_media_player_observer(p_mlp);
462 libvlc_media_player_set_media(p_mlp->p_mi, p_md);
464 install_media_player_observer(p_mlp);
465 libvlc_media_release(p_md); /* for libvlc_media_list_item_at_index */
469 * Public libvlc functions
472 /**************************************************************************
473 * new (Public)
474 **************************************************************************/
475 libvlc_media_list_player_t *
476 libvlc_media_list_player_new(libvlc_instance_t * p_instance)
478 libvlc_media_list_player_t * p_mlp;
479 p_mlp = calloc( 1, sizeof(libvlc_media_list_player_t) );
480 if (unlikely(p_mlp == NULL))
482 libvlc_printerr("Not enough memory");
483 return NULL;
486 p_mlp->i_refcount = 1;
487 p_mlp->seek_offset = 0;
488 vlc_mutex_init(&p_mlp->object_lock);
489 vlc_mutex_init(&p_mlp->mp_callback_lock);
490 vlc_cond_init(&p_mlp->seek_pending);
491 libvlc_event_manager_init(&p_mlp->event_manager, p_mlp);
493 /* Create the underlying media_player */
494 p_mlp->p_mi = libvlc_media_player_new(p_instance);
495 if( p_mlp->p_mi == NULL )
496 goto error;
497 install_media_player_observer(p_mlp);
499 if (vlc_clone(&p_mlp->thread, playlist_thread, p_mlp,
500 VLC_THREAD_PRIORITY_LOW))
502 libvlc_media_player_release(p_mlp->p_mi);
503 goto error;
506 return p_mlp;
507 error:
508 libvlc_event_manager_destroy(&p_mlp->event_manager);
509 vlc_cond_destroy(&p_mlp->seek_pending);
510 vlc_mutex_destroy(&p_mlp->mp_callback_lock);
511 vlc_mutex_destroy(&p_mlp->object_lock);
512 free(p_mlp);
513 return NULL;
516 /**************************************************************************
517 * release (Public)
518 **************************************************************************/
519 void libvlc_media_list_player_release(libvlc_media_list_player_t * p_mlp)
521 if (!p_mlp)
522 return;
524 lock(p_mlp);
525 p_mlp->i_refcount--;
526 if (p_mlp->i_refcount > 0)
528 unlock(p_mlp);
529 return;
531 assert(p_mlp->i_refcount == 0);
532 unlock(p_mlp);
534 vlc_cancel(p_mlp->thread);
535 vlc_join(p_mlp->thread, NULL);
537 lock(p_mlp);
538 /* Keep the lock(), because the uninstall functions
539 * check for it. That's convenient. */
540 uninstall_media_player_observer(p_mlp);
541 libvlc_media_player_release(p_mlp->p_mi);
543 if (p_mlp->p_mlist)
545 uninstall_playlist_observer(p_mlp);
546 libvlc_media_list_release(p_mlp->p_mlist);
549 unlock(p_mlp);
551 libvlc_event_manager_destroy(&p_mlp->event_manager);
552 vlc_cond_destroy(&p_mlp->seek_pending);
553 vlc_mutex_destroy(&p_mlp->mp_callback_lock);
554 vlc_mutex_destroy(&p_mlp->object_lock);
556 free(p_mlp->current_playing_item_path);
557 free(p_mlp);
560 /**************************************************************************
561 * retain (Public)
562 **************************************************************************/
563 void libvlc_media_list_player_retain(libvlc_media_list_player_t * p_mlp)
565 if (!p_mlp)
566 return;
568 lock(p_mlp);
569 p_mlp->i_refcount++;
570 unlock(p_mlp);
573 /**************************************************************************
574 * event_manager (Public)
575 **************************************************************************/
576 libvlc_event_manager_t *
577 libvlc_media_list_player_event_manager(libvlc_media_list_player_t * p_mlp)
579 return &p_mlp->event_manager;
582 /**************************************************************************
583 * set_media_player (Public)
584 **************************************************************************/
585 void libvlc_media_list_player_set_media_player(libvlc_media_list_player_t * p_mlp, libvlc_media_player_t * p_mi)
587 libvlc_media_player_t *p_oldmi;
589 assert(p_mi != NULL);
590 libvlc_media_player_retain(p_mi);
592 lock(p_mlp);
593 uninstall_media_player_observer(p_mlp);
594 p_oldmi = p_mlp->p_mi;
595 p_mlp->p_mi = p_mi;
596 install_media_player_observer(p_mlp);
597 unlock(p_mlp);
599 libvlc_media_player_release(p_oldmi);
602 /**************************************************************************
603 * get_media_player (Public)
604 **************************************************************************/
605 libvlc_media_player_t * libvlc_media_list_player_get_media_player(libvlc_media_list_player_t * p_mlp)
607 libvlc_media_player_retain(p_mlp->p_mi);
608 return p_mlp->p_mi;
611 /**************************************************************************
612 * set_media_list (Public)
613 **************************************************************************/
614 void libvlc_media_list_player_set_media_list(libvlc_media_list_player_t * p_mlp, libvlc_media_list_t * p_mlist)
616 assert (p_mlist);
618 lock(p_mlp);
619 if (p_mlp->p_mlist)
621 uninstall_playlist_observer(p_mlp);
622 libvlc_media_list_release(p_mlp->p_mlist);
624 libvlc_media_list_retain(p_mlist);
625 p_mlp->p_mlist = p_mlist;
627 install_playlist_observer(p_mlp);
629 unlock(p_mlp);
632 /**************************************************************************
633 * Play (Public)
634 **************************************************************************/
635 void libvlc_media_list_player_play(libvlc_media_list_player_t * p_mlp)
637 lock(p_mlp);
638 if (!p_mlp->current_playing_item_path)
640 set_relative_playlist_position_and_play(p_mlp, 1);
641 unlock(p_mlp);
642 return; /* Will set to play */
644 libvlc_media_player_play(p_mlp->p_mi);
645 unlock(p_mlp);
649 /**************************************************************************
650 * Pause (Public)
651 **************************************************************************/
652 void libvlc_media_list_player_pause(libvlc_media_list_player_t * p_mlp)
654 lock(p_mlp);
655 libvlc_media_player_pause(p_mlp->p_mi);
656 unlock(p_mlp);
659 void libvlc_media_list_player_set_pause(libvlc_media_list_player_t * p_mlp,
660 int do_pause)
662 lock(p_mlp);
663 libvlc_media_player_set_pause(p_mlp->p_mi, do_pause);
664 unlock(p_mlp);
667 /**************************************************************************
668 * is_playing (Public)
669 **************************************************************************/
671 libvlc_media_list_player_is_playing(libvlc_media_list_player_t * p_mlp)
673 libvlc_state_t state = libvlc_media_player_get_state(p_mlp->p_mi);
674 return (state == libvlc_Opening) || (state == libvlc_Playing);
677 /**************************************************************************
678 * State (Public)
679 **************************************************************************/
680 libvlc_state_t
681 libvlc_media_list_player_get_state(libvlc_media_list_player_t * p_mlp)
683 return libvlc_media_player_get_state(p_mlp->p_mi);
686 /**************************************************************************
687 * Play item at index (Public)
688 **************************************************************************/
689 int libvlc_media_list_player_play_item_at_index(libvlc_media_list_player_t * p_mlp, int i_index)
691 lock(p_mlp);
692 libvlc_media_list_path_t path = libvlc_media_list_path_with_root_index(i_index);
693 set_current_playing_item(p_mlp, path);
694 libvlc_media_t *p_md = libvlc_media_player_get_media(p_mlp->p_mi);
695 libvlc_media_player_play(p_mlp->p_mi);
696 unlock(p_mlp);
698 if (!p_md)
699 return -1;
701 /* Send the next item event */
702 libvlc_event_t event;
703 event.type = libvlc_MediaListPlayerNextItemSet;
704 event.u.media_list_player_next_item_set.item = p_md;
705 libvlc_event_send(&p_mlp->event_manager, &event);
706 libvlc_media_release(p_md);
707 return 0;
710 /**************************************************************************
711 * Play item (Public)
712 **************************************************************************/
713 int libvlc_media_list_player_play_item(libvlc_media_list_player_t * p_mlp, libvlc_media_t * p_md)
715 lock(p_mlp);
716 libvlc_media_list_path_t path = libvlc_media_list_path_of_item(p_mlp->p_mlist, p_md);
717 if (!path)
719 libvlc_printerr("Item not found in media list");
720 unlock(p_mlp);
721 return -1;
724 set_current_playing_item(p_mlp, path);
725 libvlc_media_player_play(p_mlp->p_mi);
726 unlock(p_mlp);
727 return 0;
730 /**************************************************************************
731 * Stop (Private)
733 * Lock must be held.
734 **************************************************************************/
735 static void stop(libvlc_media_list_player_t * p_mlp)
737 assert_locked(p_mlp);
739 /* We are not interested in getting media stop event now */
740 uninstall_media_player_observer(p_mlp);
741 libvlc_media_player_stop(p_mlp->p_mi);
742 install_media_player_observer(p_mlp);
744 free(p_mlp->current_playing_item_path);
745 p_mlp->current_playing_item_path = NULL;
747 /* Send the event */
748 libvlc_event_t event;
749 event.type = libvlc_MediaListPlayerStopped;
750 libvlc_event_send(&p_mlp->event_manager, &event);
753 /**************************************************************************
754 * Stop (Public)
755 **************************************************************************/
756 void libvlc_media_list_player_stop(libvlc_media_list_player_t * p_mlp)
758 lock(p_mlp);
759 stop(p_mlp);
760 unlock(p_mlp);
763 /**************************************************************************
764 * Set relative playlist position and play (Private)
766 * Sets the currently played item to the given relative play item position
767 * (based on the currently playing item) and then begins the new item playback.
768 * Lock must be held.
769 **************************************************************************/
770 static int set_relative_playlist_position_and_play(
771 libvlc_media_list_player_t * p_mlp,
772 int i_relative_position)
774 assert_locked(p_mlp);
776 if (!p_mlp->p_mlist)
778 libvlc_printerr("No media list");
779 return -1;
782 libvlc_media_list_lock(p_mlp->p_mlist);
784 libvlc_media_list_path_t path = p_mlp->current_playing_item_path;
786 if(p_mlp->e_playback_mode != libvlc_playback_mode_repeat)
788 bool b_loop = (p_mlp->e_playback_mode == libvlc_playback_mode_loop);
790 while (i_relative_position > 0)
792 path = get_next_path(p_mlp, b_loop);
793 set_current_playing_item(p_mlp, path);
794 --i_relative_position;
797 while (i_relative_position < 0)
799 path = get_previous_path(p_mlp, b_loop);
800 set_current_playing_item(p_mlp, path);
801 ++i_relative_position;
804 else
806 set_current_playing_item(p_mlp, path);
809 #ifdef DEBUG_MEDIA_LIST_PLAYER
810 printf("Playing:");
811 libvlc_media_list_path_dump(path);
812 #endif
814 if (!path)
816 libvlc_media_list_unlock(p_mlp->p_mlist);
817 /* Send list played event */
818 libvlc_event_t event;
819 event.type = libvlc_MediaListPlayerPlayed;
820 libvlc_event_send(&p_mlp->event_manager, &event);
821 return -1;
824 libvlc_media_player_play(p_mlp->p_mi);
826 libvlc_media_list_unlock(p_mlp->p_mlist);
828 /* Send the next item event */
829 libvlc_event_t event;
830 event.type = libvlc_MediaListPlayerNextItemSet;
831 libvlc_media_t * p_md = libvlc_media_list_item_at_path(p_mlp->p_mlist, path);
832 event.u.media_list_player_next_item_set.item = p_md;
833 libvlc_event_send(&p_mlp->event_manager, &event);
834 libvlc_media_release(p_md);
835 return 0;
838 /**************************************************************************
839 * Next (Public)
840 **************************************************************************/
841 int libvlc_media_list_player_next(libvlc_media_list_player_t * p_mlp)
843 lock(p_mlp);
844 int failure = set_relative_playlist_position_and_play(p_mlp, 1);
845 unlock(p_mlp);
846 return failure;
849 /**************************************************************************
850 * Previous (Public)
851 **************************************************************************/
852 int libvlc_media_list_player_previous(libvlc_media_list_player_t * p_mlp)
854 lock(p_mlp);
855 int failure = set_relative_playlist_position_and_play(p_mlp, -1);
856 unlock(p_mlp);
857 return failure;
860 /**************************************************************************
861 * Set Playback Mode (Public)
862 **************************************************************************/
863 void libvlc_media_list_player_set_playback_mode(
864 libvlc_media_list_player_t * p_mlp,
865 libvlc_playback_mode_t e_mode )
867 lock(p_mlp);
868 p_mlp->e_playback_mode = e_mode;
869 unlock(p_mlp);