Qt: fix compilation on Win32
[vlc.git] / lib / media_list_player.c
blob0188863e7a0ee5b18dbf10669d515c808ab08a7b
1 /*****************************************************************************
2 * media_list_player.c: libvlc new API media_list player functions
3 *****************************************************************************
4 * Copyright (C) 2007-2015 VLC authors and VideoLAN
6 * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
7 * Niles Bindel <zaggal69 # gmail.com>
8 * RĂ©mi Denis-Courmont
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
29 #include <vlc/libvlc.h>
30 #include <vlc/libvlc_renderer_discoverer.h>
31 #include <vlc/libvlc_picture.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;
78 * Forward declaration
81 static
82 int set_relative_playlist_position_and_play(libvlc_media_list_player_t *p_mlp,
83 int i_relative_position);
84 static void stop(libvlc_media_list_player_t * p_mlp);
87 * Private functions
90 /**************************************************************************
91 * Shortcuts
92 **************************************************************************/
93 static inline void lock(libvlc_media_list_player_t * p_mlp)
95 // Obtain an access to this structure
96 vlc_mutex_lock(&p_mlp->object_lock);
98 // Make sure no callback will occurs at the same time
99 vlc_mutex_lock(&p_mlp->mp_callback_lock);
102 static inline void unlock(libvlc_media_list_player_t * p_mlp)
104 vlc_mutex_unlock(&p_mlp->mp_callback_lock);
105 vlc_mutex_unlock(&p_mlp->object_lock);
108 static inline void assert_locked(libvlc_media_list_player_t * p_mlp)
110 vlc_mutex_assert(&p_mlp->mp_callback_lock);
111 (void) p_mlp;
114 static inline libvlc_event_manager_t * mlist_em(libvlc_media_list_player_t * p_mlp)
116 assert_locked(p_mlp);
117 return libvlc_media_list_event_manager(p_mlp->p_mlist);
120 static inline libvlc_event_manager_t * mplayer_em(libvlc_media_list_player_t * p_mlp)
122 return libvlc_media_player_event_manager(p_mlp->p_mi);
125 /**************************************************************************
126 * get_next_path (private)
128 * Returns the path to the next item in the list.
129 * If looping is specified and the current item is the last list item in
130 * the list it will return the first item in the list.
131 **************************************************************************/
132 static libvlc_media_list_path_t
133 get_next_path(libvlc_media_list_player_t * p_mlp, bool b_loop)
135 assert_locked(p_mlp);
137 /* We are entered with libvlc_media_list_lock(p_mlp->p_list) */
138 libvlc_media_list_path_t ret;
139 libvlc_media_list_t * p_parent_of_playing_item;
140 libvlc_media_list_t * p_sublist_of_playing_item;
142 if (!p_mlp->current_playing_item_path)
144 if (!libvlc_media_list_count(p_mlp->p_mlist))
145 return NULL;
146 return libvlc_media_list_path_with_root_index(0);
149 p_sublist_of_playing_item = libvlc_media_list_sublist_at_path(
150 p_mlp->p_mlist,
151 p_mlp->current_playing_item_path);
153 /* If item just gained a sublist just play it */
154 if (p_sublist_of_playing_item)
156 int i_count = libvlc_media_list_count(p_sublist_of_playing_item);
157 libvlc_media_list_release(p_sublist_of_playing_item);
158 if (i_count > 0)
159 return libvlc_media_list_path_copy_by_appending(p_mlp->current_playing_item_path, 0);
162 /* Try to catch parent element */
163 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(p_mlp->p_mlist,
164 p_mlp->current_playing_item_path);
166 int depth = libvlc_media_list_path_depth(p_mlp->current_playing_item_path);
167 if (depth < 1 || !p_parent_of_playing_item)
168 return NULL;
170 ret = libvlc_media_list_path_copy(p_mlp->current_playing_item_path);
171 ret[depth - 1]++; /* set to next element */
173 /* If this goes beyond the end of the list */
174 while(ret[depth-1] >= libvlc_media_list_count(p_parent_of_playing_item))
176 depth--;
177 if (depth <= 0)
179 if(b_loop)
181 ret[0] = 0;
182 ret[1] = -1;
183 break;
185 else
187 free(ret);
188 libvlc_media_list_release(p_parent_of_playing_item);
189 return NULL;
192 ret[depth] = -1;
193 ret[depth-1]++;
194 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(
195 p_mlp->p_mlist,
196 ret);
199 libvlc_media_list_release(p_parent_of_playing_item);
200 return ret;
203 /**************************************************************************
204 * find_last_item (private)
206 * Returns the path of the last descendant of a given item path.
207 * Note: Due to the recursive nature of the function and the need to free
208 * media list paths, paths passed in may be freed if they are replaced.
209 Recommended usage is to set return value to the same path that was
210 passed to the function (i.e. item = find_last_item(list, item); )
211 **************************************************************************/
212 static libvlc_media_list_path_t
213 find_last_item( libvlc_media_list_t * p_mlist, libvlc_media_list_path_t current_item )
215 libvlc_media_list_t * p_sublist = libvlc_media_list_sublist_at_path(p_mlist, current_item);
216 libvlc_media_list_path_t last_item_path = current_item;
218 if(p_sublist)
220 int i_count = libvlc_media_list_count(p_sublist);
221 if(i_count > 0)
223 /* Add the last sublist item to the path. */
224 last_item_path = libvlc_media_list_path_copy_by_appending(current_item, i_count - 1);
225 free(current_item);
226 /* Check that sublist item for more descendants. */
227 last_item_path = find_last_item(p_mlist, last_item_path);
230 libvlc_media_list_release(p_sublist);
233 return last_item_path;
236 /**************************************************************************
237 * get_previous_path (private)
239 * Returns the path to the preceding item in the list.
240 * If looping is specified and the current item is the first list item in
241 * the list it will return the last descendant of the last item in the list.
242 **************************************************************************/
243 static libvlc_media_list_path_t
244 get_previous_path(libvlc_media_list_player_t * p_mlp, bool b_loop)
246 assert_locked(p_mlp);
248 /* We are entered with libvlc_media_list_lock(p_mlp->p_list) */
249 libvlc_media_list_path_t ret;
250 libvlc_media_list_t * p_parent_of_playing_item;
252 if (!p_mlp->current_playing_item_path)
254 if (!libvlc_media_list_count(p_mlp->p_mlist))
255 return NULL;
256 return libvlc_media_list_path_with_root_index(0);
259 /* Try to catch parent element */
260 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(
261 p_mlp->p_mlist,
262 p_mlp->current_playing_item_path);
264 int depth = libvlc_media_list_path_depth(p_mlp->current_playing_item_path);
265 if (depth < 1 || !p_parent_of_playing_item)
266 return NULL;
268 /* Set the return path to the current path */
269 ret = libvlc_media_list_path_copy(p_mlp->current_playing_item_path);
271 /* Change the return path to the previous list entry */
272 ret[depth - 1]--; /* set to previous element */
273 ret[depth] = -1;
275 /* Is the return path is beyond the start of the current list? */
276 if(ret[depth - 1] < 0)
278 /* Move to parent of current item */
279 depth--;
281 /* Are we at the root level of the tree? */
282 if (depth <= 0)
284 // Is looping enabled?
285 if(b_loop)
287 int i_count = libvlc_media_list_count(p_parent_of_playing_item);
289 /* Set current play item to the last element in the list */
290 ret[0] = i_count - 1;
291 ret[1] = -1;
293 /* Set the return path to the last descendant item of the current item */
294 ret = find_last_item(p_mlp->p_mlist, ret);
296 else
298 /* No looping so return empty path. */
299 free(ret);
300 ret = NULL;
303 else
305 /* This is the case of moving backward from the beginning of the
306 * subitem list to its parent item.
307 * This ensures that current path is properly terminated to
308 * use that parent.
310 ret[depth] = -1;
313 else
315 ret = find_last_item(p_mlp->p_mlist, ret);
318 libvlc_media_list_release(p_parent_of_playing_item);
319 return ret;
322 static void *playlist_thread(void *data)
324 libvlc_media_list_player_t *mlp = data;
326 vlc_mutex_lock(&mlp->mp_callback_lock);
327 mutex_cleanup_push(&mlp->mp_callback_lock);
329 for (;;)
331 int canc;
333 while (mlp->seek_offset == 0)
334 vlc_cond_wait(&mlp->seek_pending, &mlp->mp_callback_lock);
336 canc = vlc_savecancel();
337 set_relative_playlist_position_and_play(mlp, mlp->seek_offset);
338 mlp->seek_offset = 0;
339 vlc_restorecancel(canc);
342 vlc_cleanup_pop();
343 vlc_assert_unreachable();
346 /**************************************************************************
347 * media_player_reached_end (private) (Event Callback)
348 **************************************************************************/
349 static void
350 media_player_reached_end(const libvlc_event_t * p_event, void * p_user_data)
352 VLC_UNUSED(p_event);
353 libvlc_media_list_player_t * p_mlp = p_user_data;
355 /* This event is triggered from the input thread, and changing item in
356 * the media player requires the input thread to terminate. So we cannot
357 * change the playlist state here (it would cause a deadlock). Instead, we
358 * defer to a separate thread. Avoiding this would be nice... */
359 vlc_mutex_lock(&p_mlp->mp_callback_lock);
360 p_mlp->seek_offset++;
361 vlc_cond_signal(&p_mlp->seek_pending);
362 vlc_mutex_unlock(&p_mlp->mp_callback_lock);
365 /**************************************************************************
366 * playlist_item_deleted (private) (Event Callback)
367 **************************************************************************/
368 static void
369 mlist_item_deleted(const libvlc_event_t * p_event, void * p_user_data)
371 // Nothing to do. For now.
372 (void)p_event; (void)p_user_data;
376 /**************************************************************************
377 * install_playlist_observer (private)
378 **************************************************************************/
379 static void
380 install_playlist_observer(libvlc_media_list_player_t * p_mlp)
382 assert_locked(p_mlp);
383 libvlc_event_attach(mlist_em(p_mlp), libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp);
386 /**************************************************************************
387 * uninstall_playlist_observer (private)
388 **************************************************************************/
389 static void
390 uninstall_playlist_observer(libvlc_media_list_player_t * p_mlp)
392 assert_locked(p_mlp);
393 if (!p_mlp->p_mlist) return;
394 libvlc_event_detach(mlist_em(p_mlp), libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp);
397 /**************************************************************************
398 * install_media_player_observer (private)
399 **************************************************************************/
400 static void
401 install_media_player_observer(libvlc_media_list_player_t * p_mlp)
403 libvlc_event_attach(mplayer_em(p_mlp), libvlc_MediaPlayerEndReached, media_player_reached_end, p_mlp);
407 /**************************************************************************
408 * uninstall_media_player_observer (private)
409 **************************************************************************/
410 static void
411 uninstall_media_player_observer(libvlc_media_list_player_t * p_mlp)
413 assert_locked(p_mlp);
415 // Allow callbacks to run, because detach() will wait until all callbacks are processed.
416 // This is safe because only callbacks are allowed, and there execution will be cancelled.
417 vlc_mutex_unlock(&p_mlp->mp_callback_lock);
418 libvlc_event_detach(mplayer_em(p_mlp), libvlc_MediaPlayerEndReached, media_player_reached_end, p_mlp);
420 // Now, lock back the callback lock. No more callback will be present from this point.
421 vlc_mutex_lock(&p_mlp->mp_callback_lock);
423 // What is here is safe, because we guarantee that we won't be able to anything concurrently,
424 // - except (cancelled) callbacks - thanks to the object_lock.
427 /**************************************************************************
428 * set_current_playing_item (private)
430 * Playlist lock should be held
431 **************************************************************************/
432 static void
433 set_current_playing_item(libvlc_media_list_player_t * p_mlp, libvlc_media_list_path_t path)
435 assert_locked(p_mlp);
437 /* First, save the new path that we are going to play */
438 if (p_mlp->current_playing_item_path != path)
440 free(p_mlp->current_playing_item_path);
441 p_mlp->current_playing_item_path = path;
444 if (!path)
445 return;
447 libvlc_media_t * p_md;
448 p_md = libvlc_media_list_item_at_path(p_mlp->p_mlist, path);
449 if (!p_md)
450 return;
452 /* Make sure media_player_reached_end() won't get called */
453 uninstall_media_player_observer(p_mlp);
455 libvlc_media_player_set_media(p_mlp->p_mi, p_md);
457 install_media_player_observer(p_mlp);
458 libvlc_media_release(p_md); /* for libvlc_media_list_item_at_index */
462 * Public libvlc functions
465 /**************************************************************************
466 * new (Public)
467 **************************************************************************/
468 libvlc_media_list_player_t *
469 libvlc_media_list_player_new(libvlc_instance_t * p_instance)
471 libvlc_media_list_player_t * p_mlp;
472 p_mlp = calloc( 1, sizeof(libvlc_media_list_player_t) );
473 if (unlikely(p_mlp == NULL))
475 libvlc_printerr("Not enough memory");
476 return NULL;
479 p_mlp->i_refcount = 1;
480 p_mlp->seek_offset = 0;
481 vlc_mutex_init(&p_mlp->object_lock);
482 vlc_mutex_init(&p_mlp->mp_callback_lock);
483 vlc_cond_init(&p_mlp->seek_pending);
484 libvlc_event_manager_init(&p_mlp->event_manager, p_mlp);
486 /* Create the underlying media_player */
487 p_mlp->p_mi = libvlc_media_player_new(p_instance);
488 if( p_mlp->p_mi == NULL )
489 goto error;
490 install_media_player_observer(p_mlp);
492 if (vlc_clone(&p_mlp->thread, playlist_thread, p_mlp,
493 VLC_THREAD_PRIORITY_LOW))
495 libvlc_media_player_release(p_mlp->p_mi);
496 goto error;
499 return p_mlp;
500 error:
501 libvlc_event_manager_destroy(&p_mlp->event_manager);
502 vlc_cond_destroy(&p_mlp->seek_pending);
503 vlc_mutex_destroy(&p_mlp->mp_callback_lock);
504 vlc_mutex_destroy(&p_mlp->object_lock);
505 free(p_mlp);
506 return NULL;
509 /**************************************************************************
510 * release (Public)
511 **************************************************************************/
512 void libvlc_media_list_player_release(libvlc_media_list_player_t * p_mlp)
514 if (!p_mlp)
515 return;
517 lock(p_mlp);
518 p_mlp->i_refcount--;
519 if (p_mlp->i_refcount > 0)
521 unlock(p_mlp);
522 return;
524 assert(p_mlp->i_refcount == 0);
525 unlock(p_mlp);
527 vlc_cancel(p_mlp->thread);
528 vlc_join(p_mlp->thread, NULL);
530 lock(p_mlp);
531 /* Keep the lock(), because the uninstall functions
532 * check for it. That's convenient. */
533 uninstall_media_player_observer(p_mlp);
534 libvlc_media_player_release(p_mlp->p_mi);
536 if (p_mlp->p_mlist)
538 uninstall_playlist_observer(p_mlp);
539 libvlc_media_list_release(p_mlp->p_mlist);
542 unlock(p_mlp);
544 libvlc_event_manager_destroy(&p_mlp->event_manager);
545 vlc_cond_destroy(&p_mlp->seek_pending);
546 vlc_mutex_destroy(&p_mlp->mp_callback_lock);
547 vlc_mutex_destroy(&p_mlp->object_lock);
549 free(p_mlp->current_playing_item_path);
550 free(p_mlp);
553 /**************************************************************************
554 * retain (Public)
555 **************************************************************************/
556 void libvlc_media_list_player_retain(libvlc_media_list_player_t * p_mlp)
558 if (!p_mlp)
559 return;
561 lock(p_mlp);
562 p_mlp->i_refcount++;
563 unlock(p_mlp);
566 /**************************************************************************
567 * event_manager (Public)
568 **************************************************************************/
569 libvlc_event_manager_t *
570 libvlc_media_list_player_event_manager(libvlc_media_list_player_t * p_mlp)
572 return &p_mlp->event_manager;
575 /**************************************************************************
576 * set_media_player (Public)
577 **************************************************************************/
578 void libvlc_media_list_player_set_media_player(libvlc_media_list_player_t * p_mlp, libvlc_media_player_t * p_mi)
580 libvlc_media_player_t *p_oldmi;
582 assert(p_mi != NULL);
583 libvlc_media_player_retain(p_mi);
585 lock(p_mlp);
586 uninstall_media_player_observer(p_mlp);
587 p_oldmi = p_mlp->p_mi;
588 p_mlp->p_mi = p_mi;
589 install_media_player_observer(p_mlp);
590 unlock(p_mlp);
592 libvlc_media_player_release(p_oldmi);
595 /**************************************************************************
596 * get_media_player (Public)
597 **************************************************************************/
598 libvlc_media_player_t * libvlc_media_list_player_get_media_player(libvlc_media_list_player_t * p_mlp)
600 libvlc_media_player_retain(p_mlp->p_mi);
601 return p_mlp->p_mi;
604 /**************************************************************************
605 * set_media_list (Public)
606 **************************************************************************/
607 void libvlc_media_list_player_set_media_list(libvlc_media_list_player_t * p_mlp, libvlc_media_list_t * p_mlist)
609 assert (p_mlist);
611 lock(p_mlp);
612 if (p_mlp->p_mlist)
614 uninstall_playlist_observer(p_mlp);
615 libvlc_media_list_release(p_mlp->p_mlist);
617 libvlc_media_list_retain(p_mlist);
618 p_mlp->p_mlist = p_mlist;
620 install_playlist_observer(p_mlp);
622 unlock(p_mlp);
625 /**************************************************************************
626 * Play (Public)
627 **************************************************************************/
628 void libvlc_media_list_player_play(libvlc_media_list_player_t * p_mlp)
630 lock(p_mlp);
631 if (!p_mlp->current_playing_item_path)
633 set_relative_playlist_position_and_play(p_mlp, 1);
634 unlock(p_mlp);
635 return; /* Will set to play */
637 libvlc_media_player_play(p_mlp->p_mi);
638 unlock(p_mlp);
642 /**************************************************************************
643 * Pause (Public)
644 **************************************************************************/
645 void libvlc_media_list_player_pause(libvlc_media_list_player_t * p_mlp)
647 lock(p_mlp);
648 libvlc_media_player_pause(p_mlp->p_mi);
649 unlock(p_mlp);
652 void libvlc_media_list_player_set_pause(libvlc_media_list_player_t * p_mlp,
653 int do_pause)
655 lock(p_mlp);
656 libvlc_media_player_set_pause(p_mlp->p_mi, do_pause);
657 unlock(p_mlp);
660 /**************************************************************************
661 * is_playing (Public)
662 **************************************************************************/
663 bool libvlc_media_list_player_is_playing(libvlc_media_list_player_t * p_mlp)
665 libvlc_state_t state = libvlc_media_player_get_state(p_mlp->p_mi);
666 return (state == libvlc_Opening) || (state == libvlc_Playing);
669 /**************************************************************************
670 * State (Public)
671 **************************************************************************/
672 libvlc_state_t
673 libvlc_media_list_player_get_state(libvlc_media_list_player_t * p_mlp)
675 return libvlc_media_player_get_state(p_mlp->p_mi);
678 /**************************************************************************
679 * Play item at index (Public)
680 **************************************************************************/
681 int libvlc_media_list_player_play_item_at_index(libvlc_media_list_player_t * p_mlp, int i_index)
683 lock(p_mlp);
684 libvlc_media_list_path_t path = libvlc_media_list_path_with_root_index(i_index);
685 set_current_playing_item(p_mlp, path);
686 libvlc_media_t *p_md = libvlc_media_player_get_media(p_mlp->p_mi);
687 libvlc_media_player_play(p_mlp->p_mi);
688 unlock(p_mlp);
690 if (!p_md)
691 return -1;
693 /* Send the next item event */
694 libvlc_event_t event;
695 event.type = libvlc_MediaListPlayerNextItemSet;
696 event.u.media_list_player_next_item_set.item = p_md;
697 libvlc_event_send(&p_mlp->event_manager, &event);
698 libvlc_media_release(p_md);
699 return 0;
702 /**************************************************************************
703 * Play item (Public)
704 **************************************************************************/
705 int libvlc_media_list_player_play_item(libvlc_media_list_player_t * p_mlp, libvlc_media_t * p_md)
707 lock(p_mlp);
708 libvlc_media_list_path_t path = libvlc_media_list_path_of_item(p_mlp->p_mlist, p_md);
709 if (!path)
711 libvlc_printerr("Item not found in media list");
712 unlock(p_mlp);
713 return -1;
716 set_current_playing_item(p_mlp, path);
717 libvlc_media_player_play(p_mlp->p_mi);
718 unlock(p_mlp);
719 return 0;
722 /**************************************************************************
723 * Stop (Private)
725 * Lock must be held.
726 **************************************************************************/
727 static void stop(libvlc_media_list_player_t * p_mlp)
729 assert_locked(p_mlp);
731 /* We are not interested in getting media stop event now */
732 uninstall_media_player_observer(p_mlp);
733 libvlc_media_player_stop_async(p_mlp->p_mi);
734 install_media_player_observer(p_mlp);
736 free(p_mlp->current_playing_item_path);
737 p_mlp->current_playing_item_path = NULL;
739 /* Send the event */
740 libvlc_event_t event;
741 event.type = libvlc_MediaListPlayerStopped;
742 libvlc_event_send(&p_mlp->event_manager, &event);
745 /**************************************************************************
746 * Stop (Public)
747 **************************************************************************/
748 void libvlc_media_list_player_stop_async(libvlc_media_list_player_t * p_mlp)
750 lock(p_mlp);
751 stop(p_mlp);
752 unlock(p_mlp);
755 /**************************************************************************
756 * Set relative playlist position and play (Private)
758 * Sets the currently played item to the given relative play item position
759 * (based on the currently playing item) and then begins the new item playback.
760 * Lock must be held.
761 **************************************************************************/
762 static int set_relative_playlist_position_and_play(
763 libvlc_media_list_player_t * p_mlp,
764 int i_relative_position)
766 assert_locked(p_mlp);
768 if (!p_mlp->p_mlist)
770 libvlc_printerr("No media list");
771 return -1;
774 libvlc_media_list_lock(p_mlp->p_mlist);
776 libvlc_media_list_path_t path = p_mlp->current_playing_item_path;
778 if(p_mlp->e_playback_mode != libvlc_playback_mode_repeat)
780 bool b_loop = (p_mlp->e_playback_mode == libvlc_playback_mode_loop);
782 while (i_relative_position > 0)
784 path = get_next_path(p_mlp, b_loop);
785 set_current_playing_item(p_mlp, path);
786 --i_relative_position;
789 while (i_relative_position < 0)
791 path = get_previous_path(p_mlp, b_loop);
792 set_current_playing_item(p_mlp, path);
793 ++i_relative_position;
796 else
798 set_current_playing_item(p_mlp, path);
801 #ifdef DEBUG_MEDIA_LIST_PLAYER
802 printf("Playing:");
803 libvlc_media_list_path_dump(path);
804 #endif
806 if (!path)
808 libvlc_media_list_unlock(p_mlp->p_mlist);
809 /* Send list played event */
810 libvlc_event_t event;
811 event.type = libvlc_MediaListPlayerPlayed;
812 libvlc_event_send(&p_mlp->event_manager, &event);
813 return -1;
816 libvlc_media_player_play(p_mlp->p_mi);
818 libvlc_media_list_unlock(p_mlp->p_mlist);
820 /* Send the next item event */
821 libvlc_event_t event;
822 event.type = libvlc_MediaListPlayerNextItemSet;
823 libvlc_media_t * p_md = libvlc_media_list_item_at_path(p_mlp->p_mlist, path);
824 event.u.media_list_player_next_item_set.item = p_md;
825 libvlc_event_send(&p_mlp->event_manager, &event);
826 libvlc_media_release(p_md);
827 return 0;
830 /**************************************************************************
831 * Next (Public)
832 **************************************************************************/
833 int libvlc_media_list_player_next(libvlc_media_list_player_t * p_mlp)
835 lock(p_mlp);
836 int failure = set_relative_playlist_position_and_play(p_mlp, 1);
837 unlock(p_mlp);
838 return failure;
841 /**************************************************************************
842 * Previous (Public)
843 **************************************************************************/
844 int libvlc_media_list_player_previous(libvlc_media_list_player_t * p_mlp)
846 lock(p_mlp);
847 int failure = set_relative_playlist_position_and_play(p_mlp, -1);
848 unlock(p_mlp);
849 return failure;
852 /**************************************************************************
853 * Set Playback Mode (Public)
854 **************************************************************************/
855 void libvlc_media_list_player_set_playback_mode(
856 libvlc_media_list_player_t * p_mlp,
857 libvlc_playback_mode_t e_mode )
859 lock(p_mlp);
860 p_mlp->e_playback_mode = e_mode;
861 unlock(p_mlp);