prefetch: don't do anything when reading 0 bytes
[vlc.git] / lib / media_list_player.c
bloba2c4875c67918919379ce3cb4aa2fd699c26d38c
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_media.h>
32 #include <vlc/libvlc_media_list.h>
33 #include <vlc/libvlc_media_player.h>
34 #include <vlc/libvlc_media_list_player.h>
35 #include <vlc/libvlc_events.h>
36 #include <assert.h>
38 #include "libvlc_internal.h"
40 #include "media_internal.h" // Abuse, could and should be removed
41 #include "media_list_path.h"
43 //#define DEBUG_MEDIA_LIST_PLAYER
45 /* This is a very dummy implementation of playlist on top of
46 * media_list and media_player.
48 * All this code is doing is simply computing the next item
49 * of a tree of media_list (see get_next_index()), and play
50 * the next item when the current is over. This is happening
51 * via the event callback media_player_reached_end().
53 * This is thread safe, and we use a two keys (locks) scheme
54 * to discriminate between callbacks and regular uses.
57 struct libvlc_media_list_player_t
59 libvlc_event_manager_t * p_event_manager;
60 int i_refcount;
61 int seek_offset;
62 /* Protect access to this structure. */
63 vlc_mutex_t object_lock;
64 /* Protect access to this structure and from callback execution. */
65 vlc_mutex_t mp_callback_lock;
66 vlc_cond_t seek_pending;
67 libvlc_media_list_path_t current_playing_item_path;
68 libvlc_media_t * p_current_playing_item;
69 libvlc_media_list_t * p_mlist;
70 libvlc_media_player_t * p_mi;
71 libvlc_playback_mode_t e_playback_mode;
73 vlc_thread_t thread;
76 /* This is not yet exported by libvlccore */
77 static inline void vlc_assert_locked(vlc_mutex_t *mutex)
79 VLC_UNUSED(mutex);
83 * Forward declaration
86 static
87 int set_relative_playlist_position_and_play(libvlc_media_list_player_t *p_mlp,
88 int i_relative_position);
89 static void stop(libvlc_media_list_player_t * p_mlp);
92 * Private functions
95 /**************************************************************************
96 * Shortcuts
97 **************************************************************************/
98 static inline void lock(libvlc_media_list_player_t * p_mlp)
100 // Obtain an access to this structure
101 vlc_mutex_lock(&p_mlp->object_lock);
103 // Make sure no callback will occurs at the same time
104 vlc_mutex_lock(&p_mlp->mp_callback_lock);
107 static inline void unlock(libvlc_media_list_player_t * p_mlp)
109 vlc_mutex_unlock(&p_mlp->mp_callback_lock);
110 vlc_mutex_unlock(&p_mlp->object_lock);
113 static inline void assert_locked(libvlc_media_list_player_t * p_mlp)
115 vlc_assert_locked(&p_mlp->mp_callback_lock);
118 static inline libvlc_event_manager_t * mlist_em(libvlc_media_list_player_t * p_mlp)
120 assert_locked(p_mlp);
121 return libvlc_media_list_event_manager(p_mlp->p_mlist);
124 static inline libvlc_event_manager_t * mplayer_em(libvlc_media_list_player_t * p_mlp)
126 assert_locked(p_mlp);
127 return libvlc_media_player_event_manager(p_mlp->p_mi);
130 /**************************************************************************
131 * get_next_path (private)
133 * Returns the path to the next item in the list.
134 * If looping is specified and the current item is the last list item in
135 * the list it will return the first item in the list.
136 **************************************************************************/
137 static libvlc_media_list_path_t
138 get_next_path(libvlc_media_list_player_t * p_mlp, bool b_loop)
140 assert_locked(p_mlp);
142 /* We are entered with libvlc_media_list_lock(p_mlp->p_list) */
143 libvlc_media_list_path_t ret;
144 libvlc_media_list_t * p_parent_of_playing_item;
145 libvlc_media_list_t * p_sublist_of_playing_item;
147 if (!p_mlp->current_playing_item_path)
149 if (!libvlc_media_list_count(p_mlp->p_mlist))
150 return NULL;
151 return libvlc_media_list_path_with_root_index(0);
154 p_sublist_of_playing_item = libvlc_media_list_sublist_at_path(
155 p_mlp->p_mlist,
156 p_mlp->current_playing_item_path);
158 /* If item just gained a sublist just play it */
159 if (p_sublist_of_playing_item)
161 libvlc_media_list_release(p_sublist_of_playing_item);
162 return libvlc_media_list_path_copy_by_appending(p_mlp->current_playing_item_path, 0);
165 /* Try to catch parent element */
166 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(p_mlp->p_mlist,
167 p_mlp->current_playing_item_path);
169 int depth = libvlc_media_list_path_depth(p_mlp->current_playing_item_path);
170 if (depth < 1 || !p_parent_of_playing_item)
171 return NULL;
173 ret = libvlc_media_list_path_copy(p_mlp->current_playing_item_path);
174 ret[depth - 1]++; /* set to next element */
176 /* If this goes beyond the end of the list */
177 while(ret[depth-1] >= libvlc_media_list_count(p_parent_of_playing_item))
179 depth--;
180 if (depth <= 0)
182 if(b_loop)
184 ret[0] = 0;
185 ret[1] = -1;
186 break;
188 else
190 free(ret);
191 libvlc_media_list_release(p_parent_of_playing_item);
192 return NULL;
195 ret[depth] = -1;
196 ret[depth-1]++;
197 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(
198 p_mlp->p_mlist,
199 ret);
202 libvlc_media_list_release(p_parent_of_playing_item);
203 return ret;
206 /**************************************************************************
207 * find_last_item (private)
209 * Returns the path of the last descendant of a given item path.
210 * Note: Due to the recursive nature of the function and the need to free
211 * media list paths, paths passed in may be freed if they are replaced.
212 Recommended usage is to set return value to the same path that was
213 passed to the function (i.e. item = find_last_item(list, item); )
214 **************************************************************************/
215 static libvlc_media_list_path_t
216 find_last_item( libvlc_media_list_t * p_mlist, libvlc_media_list_path_t current_item )
218 libvlc_media_list_t * p_sublist = libvlc_media_list_sublist_at_path(p_mlist, current_item);
219 libvlc_media_list_path_t last_item_path = current_item;
221 if(p_sublist)
223 int i_count = libvlc_media_list_count(p_sublist);
224 if(i_count > 0)
226 /* Add the last sublist item to the path. */
227 last_item_path = libvlc_media_list_path_copy_by_appending(current_item, i_count - 1);
228 free(current_item);
229 /* Check that sublist item for more descendants. */
230 last_item_path = find_last_item(p_mlist, last_item_path);
233 libvlc_media_list_release(p_sublist);
236 return last_item_path;
239 /**************************************************************************
240 * get_previous_path (private)
242 * Returns the path to the preceding item in the list.
243 * If looping is specified and the current item is the first list item in
244 * the list it will return the last descendant of the last item in the list.
245 **************************************************************************/
246 static libvlc_media_list_path_t
247 get_previous_path(libvlc_media_list_player_t * p_mlp, bool b_loop)
249 assert_locked(p_mlp);
251 /* We are entered with libvlc_media_list_lock(p_mlp->p_list) */
252 libvlc_media_list_path_t ret;
253 libvlc_media_list_t * p_parent_of_playing_item;
255 if (!p_mlp->current_playing_item_path)
257 if (!libvlc_media_list_count(p_mlp->p_mlist))
258 return NULL;
259 return libvlc_media_list_path_with_root_index(0);
262 /* Try to catch parent element */
263 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(
264 p_mlp->p_mlist,
265 p_mlp->current_playing_item_path);
267 int depth = libvlc_media_list_path_depth(p_mlp->current_playing_item_path);
268 if (depth < 1 || !p_parent_of_playing_item)
269 return NULL;
271 /* Set the return path to the current path */
272 ret = libvlc_media_list_path_copy(p_mlp->current_playing_item_path);
274 /* Change the return path to the previous list entry */
275 ret[depth - 1]--; /* set to previous element */
276 ret[depth] = -1;
278 /* Is the return path is beyond the start of the current list? */
279 if(ret[depth - 1] < 0)
281 /* Move to parent of current item */
282 depth--;
284 /* Are we at the root level of the tree? */
285 if (depth <= 0)
287 // Is looping enabled?
288 if(b_loop)
290 int i_count = libvlc_media_list_count(p_parent_of_playing_item);
292 /* Set current play item to the last element in the list */
293 ret[0] = i_count - 1;
294 ret[1] = -1;
296 /* Set the return path to the last descendant item of the current item */
297 ret = find_last_item(p_mlp->p_mlist, ret);
299 else
301 /* No looping so return empty path. */
302 free(ret);
303 ret = NULL;
306 else
308 /* This is the case of moving backward from the beginning of the
309 * subitem list to its parent item.
310 * This ensures that current path is properly terminated to
311 * use that parent.
313 ret[depth] = -1;
316 else
318 ret = find_last_item(p_mlp->p_mlist, ret);
321 libvlc_media_list_release(p_parent_of_playing_item);
322 return ret;
325 static void *playlist_thread(void *data)
327 libvlc_media_list_player_t *mlp = data;
329 vlc_mutex_lock(&mlp->mp_callback_lock);
330 mutex_cleanup_push(&mlp->mp_callback_lock);
332 for (;;)
334 int canc;
336 while (mlp->seek_offset == 0)
337 vlc_cond_wait(&mlp->seek_pending, &mlp->mp_callback_lock);
339 canc = vlc_savecancel();
340 set_relative_playlist_position_and_play(mlp, mlp->seek_offset);
341 mlp->seek_offset = 0;
342 vlc_restorecancel(canc);
345 vlc_cleanup_pop();
346 vlc_assert_unreachable();
349 /**************************************************************************
350 * media_player_reached_end (private) (Event Callback)
351 **************************************************************************/
352 static void
353 media_player_reached_end(const libvlc_event_t * p_event, void * p_user_data)
355 VLC_UNUSED(p_event);
356 libvlc_media_list_player_t * p_mlp = p_user_data;
358 /* This event is triggered from the input thread, and changing item in
359 * the media player requires the input thread to terminate. So we cannot
360 * change the playlist state here (it would cause a deadlock). Instead, we
361 * defer to a separate thread. Avoiding this would be nice... */
362 vlc_mutex_lock(&p_mlp->mp_callback_lock);
363 p_mlp->seek_offset++;
364 vlc_cond_signal(&p_mlp->seek_pending);
365 vlc_mutex_unlock(&p_mlp->mp_callback_lock);
368 /**************************************************************************
369 * playlist_item_deleted (private) (Event Callback)
370 **************************************************************************/
371 static void
372 mlist_item_deleted(const libvlc_event_t * p_event, void * p_user_data)
374 // Nothing to do. For now.
375 (void)p_event; (void)p_user_data;
379 /**************************************************************************
380 * install_playlist_observer (private)
381 **************************************************************************/
382 static void
383 install_playlist_observer(libvlc_media_list_player_t * p_mlp)
385 assert_locked(p_mlp);
386 libvlc_event_attach(mlist_em(p_mlp), libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp);
389 /**************************************************************************
390 * uninstall_playlist_observer (private)
391 **************************************************************************/
392 static void
393 uninstall_playlist_observer(libvlc_media_list_player_t * p_mlp)
395 assert_locked(p_mlp);
396 if (!p_mlp->p_mlist) return;
397 libvlc_event_detach(mlist_em(p_mlp), libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp);
400 /**************************************************************************
401 * install_media_player_observer (private)
402 **************************************************************************/
403 static void
404 install_media_player_observer(libvlc_media_list_player_t * p_mlp)
406 assert_locked(p_mlp);
407 libvlc_event_attach(mplayer_em(p_mlp), libvlc_MediaPlayerEndReached, media_player_reached_end, p_mlp);
411 /**************************************************************************
412 * uninstall_media_player_observer (private)
413 **************************************************************************/
414 static void
415 uninstall_media_player_observer(libvlc_media_list_player_t * p_mlp)
417 assert_locked(p_mlp);
419 // Allow callbacks to run, because detach() will wait until all callbacks are processed.
420 // This is safe because only callbacks are allowed, and there execution will be cancelled.
421 vlc_mutex_unlock(&p_mlp->mp_callback_lock);
422 libvlc_event_detach(mplayer_em(p_mlp), libvlc_MediaPlayerEndReached, media_player_reached_end, p_mlp);
424 // Now, lock back the callback lock. No more callback will be present from this point.
425 vlc_mutex_lock(&p_mlp->mp_callback_lock);
427 // What is here is safe, because we guarantee that we won't be able to anything concurrently,
428 // - except (cancelled) callbacks - thanks to the object_lock.
431 /**************************************************************************
432 * set_current_playing_item (private)
434 * Playlist lock should be held
435 **************************************************************************/
436 static void
437 set_current_playing_item(libvlc_media_list_player_t * p_mlp, libvlc_media_list_path_t path)
439 assert_locked(p_mlp);
441 /* First, save the new path that we are going to play */
442 if (p_mlp->current_playing_item_path != path)
444 free(p_mlp->current_playing_item_path);
445 p_mlp->current_playing_item_path = path;
448 if (!path)
449 return;
451 libvlc_media_t * p_md;
452 p_md = libvlc_media_list_item_at_path(p_mlp->p_mlist, path);
453 if (!p_md)
454 return;
456 /* Make sure media_player_reached_end() won't get called */
457 uninstall_media_player_observer(p_mlp);
459 libvlc_media_player_set_media(p_mlp->p_mi, p_md);
461 install_media_player_observer(p_mlp);
462 libvlc_media_release(p_md); /* for libvlc_media_list_item_at_index */
466 * Public libvlc functions
469 /**************************************************************************
470 * new (Public)
471 **************************************************************************/
472 libvlc_media_list_player_t *
473 libvlc_media_list_player_new(libvlc_instance_t * p_instance)
475 libvlc_media_list_player_t * p_mlp;
476 p_mlp = calloc( 1, sizeof(libvlc_media_list_player_t) );
477 if (unlikely(p_mlp == NULL))
479 libvlc_printerr("Not enough memory");
480 return NULL;
483 p_mlp->i_refcount = 1;
484 p_mlp->seek_offset = 0;
485 vlc_mutex_init(&p_mlp->object_lock);
486 vlc_mutex_init(&p_mlp->mp_callback_lock);
487 vlc_cond_init(&p_mlp->seek_pending);
489 p_mlp->p_event_manager = libvlc_event_manager_new(p_mlp);
490 if (unlikely(p_mlp->p_event_manager == NULL))
491 goto error;
493 /* Create the underlying media_player */
494 p_mlp->p_mi = libvlc_media_player_new(p_instance);
495 if( p_mlp->p_mi == NULL )
497 libvlc_event_manager_release(p_mlp->p_event_manager);
498 goto error;
500 install_media_player_observer(p_mlp);
502 if (vlc_clone(&p_mlp->thread, playlist_thread, p_mlp,
503 VLC_THREAD_PRIORITY_LOW))
505 libvlc_media_player_release(p_mlp->p_mi);
506 libvlc_event_manager_release(p_mlp->p_event_manager);
507 goto error;
510 return p_mlp;
511 error:
512 vlc_cond_destroy(&p_mlp->seek_pending);
513 vlc_mutex_destroy(&p_mlp->mp_callback_lock);
514 vlc_mutex_destroy(&p_mlp->object_lock);
515 free(p_mlp);
516 return NULL;
519 /**************************************************************************
520 * release (Public)
521 **************************************************************************/
522 void libvlc_media_list_player_release(libvlc_media_list_player_t * p_mlp)
524 if (!p_mlp)
525 return;
527 lock(p_mlp);
528 p_mlp->i_refcount--;
529 if (p_mlp->i_refcount > 0)
531 unlock(p_mlp);
532 return;
534 assert(p_mlp->i_refcount == 0);
535 unlock(p_mlp);
537 vlc_cancel(p_mlp->thread);
538 vlc_join(p_mlp->thread, NULL);
540 lock(p_mlp);
541 /* Keep the lock(), because the uninstall functions
542 * check for it. That's convenient. */
543 uninstall_media_player_observer(p_mlp);
544 libvlc_media_player_release(p_mlp->p_mi);
546 if (p_mlp->p_mlist)
548 uninstall_playlist_observer(p_mlp);
549 libvlc_media_list_release(p_mlp->p_mlist);
552 unlock(p_mlp);
554 libvlc_event_manager_release(p_mlp->p_event_manager);
555 vlc_cond_destroy(&p_mlp->seek_pending);
556 vlc_mutex_destroy(&p_mlp->mp_callback_lock);
557 vlc_mutex_destroy(&p_mlp->object_lock);
559 free(p_mlp->current_playing_item_path);
560 free(p_mlp);
563 /**************************************************************************
564 * retain (Public)
565 **************************************************************************/
566 void libvlc_media_list_player_retain(libvlc_media_list_player_t * p_mlp)
568 if (!p_mlp)
569 return;
571 lock(p_mlp);
572 p_mlp->i_refcount++;
573 unlock(p_mlp);
576 /**************************************************************************
577 * event_manager (Public)
578 **************************************************************************/
579 libvlc_event_manager_t *
580 libvlc_media_list_player_event_manager(libvlc_media_list_player_t * p_mlp)
582 return p_mlp->p_event_manager;
585 /**************************************************************************
586 * set_media_player (Public)
587 **************************************************************************/
588 void libvlc_media_list_player_set_media_player(libvlc_media_list_player_t * p_mlp, libvlc_media_player_t * p_mi)
590 libvlc_media_player_t *p_oldmi;
592 assert(p_mi != NULL);
593 libvlc_media_player_retain(p_mi);
595 lock(p_mlp);
596 uninstall_media_player_observer(p_mlp);
597 p_oldmi = p_mlp->p_mi;
598 p_mlp->p_mi = p_mi;
599 install_media_player_observer(p_mlp);
600 unlock(p_mlp);
602 libvlc_media_player_release(p_oldmi);
605 /**************************************************************************
606 * get_media_player (Public)
607 **************************************************************************/
608 libvlc_media_player_t * libvlc_media_list_player_get_media_player(libvlc_media_list_player_t * p_mlp)
610 libvlc_media_player_retain(p_mlp->p_mi);
611 return p_mlp->p_mi;
614 /**************************************************************************
615 * set_media_list (Public)
616 **************************************************************************/
617 void libvlc_media_list_player_set_media_list(libvlc_media_list_player_t * p_mlp, libvlc_media_list_t * p_mlist)
619 assert (p_mlist);
621 lock(p_mlp);
622 if (p_mlp->p_mlist)
624 uninstall_playlist_observer(p_mlp);
625 libvlc_media_list_release(p_mlp->p_mlist);
627 libvlc_media_list_retain(p_mlist);
628 p_mlp->p_mlist = p_mlist;
630 install_playlist_observer(p_mlp);
632 unlock(p_mlp);
635 /**************************************************************************
636 * Play (Public)
637 **************************************************************************/
638 void libvlc_media_list_player_play(libvlc_media_list_player_t * p_mlp)
640 lock(p_mlp);
641 if (!p_mlp->current_playing_item_path)
643 set_relative_playlist_position_and_play(p_mlp, 1);
644 unlock(p_mlp);
645 return; /* Will set to play */
647 libvlc_media_player_play(p_mlp->p_mi);
648 unlock(p_mlp);
652 /**************************************************************************
653 * Pause (Public)
654 **************************************************************************/
655 void libvlc_media_list_player_pause(libvlc_media_list_player_t * p_mlp)
657 lock(p_mlp);
658 libvlc_media_player_pause(p_mlp->p_mi);
659 unlock(p_mlp);
662 /**************************************************************************
663 * is_playing (Public)
664 **************************************************************************/
666 libvlc_media_list_player_is_playing(libvlc_media_list_player_t * p_mlp)
668 libvlc_state_t state = libvlc_media_player_get_state(p_mlp->p_mi);
669 return (state == libvlc_Opening) || (state == libvlc_Buffering) ||
670 (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_player_play(p_mlp->p_mi);
691 unlock(p_mlp);
693 /* Send the next item event */
694 libvlc_event_t event;
695 event.type = libvlc_MediaListPlayerNextItemSet;
696 libvlc_media_t * p_md = libvlc_media_list_item_at_path(p_mlp->p_mlist, path);
697 event.u.media_list_player_next_item_set.item = p_md;
698 libvlc_event_send(p_mlp->p_event_manager, &event);
699 libvlc_media_release(p_md);
700 return 0;
703 /**************************************************************************
704 * Play item (Public)
705 **************************************************************************/
706 int libvlc_media_list_player_play_item(libvlc_media_list_player_t * p_mlp, libvlc_media_t * p_md)
708 lock(p_mlp);
709 libvlc_media_list_path_t path = libvlc_media_list_path_of_item(p_mlp->p_mlist, p_md);
710 if (!path)
712 libvlc_printerr("Item not found in media list");
713 unlock(p_mlp);
714 return -1;
717 set_current_playing_item(p_mlp, path);
718 libvlc_media_player_play(p_mlp->p_mi);
719 unlock(p_mlp);
720 return 0;
723 /**************************************************************************
724 * Stop (Private)
726 * Lock must be held.
727 **************************************************************************/
728 static void stop(libvlc_media_list_player_t * p_mlp)
730 assert_locked(p_mlp);
732 /* We are not interested in getting media stop event now */
733 uninstall_media_player_observer(p_mlp);
734 libvlc_media_player_stop(p_mlp->p_mi);
735 install_media_player_observer(p_mlp);
737 free(p_mlp->current_playing_item_path);
738 p_mlp->current_playing_item_path = NULL;
740 /* Send the event */
741 libvlc_event_t event;
742 event.type = libvlc_MediaListPlayerStopped;
743 libvlc_event_send(p_mlp->p_event_manager, &event);
746 /**************************************************************************
747 * Stop (Public)
748 **************************************************************************/
749 void libvlc_media_list_player_stop(libvlc_media_list_player_t * p_mlp)
751 lock(p_mlp);
752 stop(p_mlp);
753 unlock(p_mlp);
756 /**************************************************************************
757 * Set relative playlist position and play (Private)
759 * Sets the currently played item to the given relative play item position
760 * (based on the currently playing item) and then begins the new item playback.
761 * Lock must be held.
762 **************************************************************************/
763 static int set_relative_playlist_position_and_play(
764 libvlc_media_list_player_t * p_mlp,
765 int i_relative_position)
767 assert_locked(p_mlp);
769 if (!p_mlp->p_mlist)
771 libvlc_printerr("No media list");
772 return -1;
775 libvlc_media_list_lock(p_mlp->p_mlist);
777 libvlc_media_list_path_t path = p_mlp->current_playing_item_path;
779 if(p_mlp->e_playback_mode != libvlc_playback_mode_repeat)
781 bool b_loop = (p_mlp->e_playback_mode == libvlc_playback_mode_loop);
783 while (i_relative_position > 0)
785 path = get_next_path(p_mlp, b_loop);
786 set_current_playing_item(p_mlp, path);
787 --i_relative_position;
790 while (i_relative_position < 0)
792 path = get_previous_path(p_mlp, b_loop);
793 set_current_playing_item(p_mlp, path);
794 ++i_relative_position;
797 else
799 set_current_playing_item(p_mlp, path);
802 #ifdef DEBUG_MEDIA_LIST_PLAYER
803 printf("Playing:");
804 libvlc_media_list_path_dump(path);
805 #endif
807 if (!path)
809 libvlc_media_list_unlock(p_mlp->p_mlist);
810 /* Send list played event */
811 libvlc_event_t event;
812 event.type = libvlc_MediaListPlayerPlayed;
813 libvlc_event_send(p_mlp->p_event_manager, &event);
814 return -1;
817 libvlc_media_player_play(p_mlp->p_mi);
819 libvlc_media_list_unlock(p_mlp->p_mlist);
821 /* Send the next item event */
822 libvlc_event_t event;
823 event.type = libvlc_MediaListPlayerNextItemSet;
824 libvlc_media_t * p_md = libvlc_media_list_item_at_path(p_mlp->p_mlist, path);
825 event.u.media_list_player_next_item_set.item = p_md;
826 libvlc_event_send(p_mlp->p_event_manager, &event);
827 libvlc_media_release(p_md);
828 return 0;
831 /**************************************************************************
832 * Next (Public)
833 **************************************************************************/
834 int libvlc_media_list_player_next(libvlc_media_list_player_t * p_mlp)
836 lock(p_mlp);
837 int failure = set_relative_playlist_position_and_play(p_mlp, 1);
838 unlock(p_mlp);
839 return failure;
842 /**************************************************************************
843 * Previous (Public)
844 **************************************************************************/
845 int libvlc_media_list_player_previous(libvlc_media_list_player_t * p_mlp)
847 lock(p_mlp);
848 int failure = set_relative_playlist_position_and_play(p_mlp, -1);
849 unlock(p_mlp);
850 return failure;
853 /**************************************************************************
854 * Set Playback Mode (Public)
855 **************************************************************************/
856 void libvlc_media_list_player_set_playback_mode(
857 libvlc_media_list_player_t * p_mlp,
858 libvlc_playback_mode_t e_mode )
860 lock(p_mlp);
861 p_mlp->e_playback_mode = e_mode;
862 unlock(p_mlp);