mux: mp4: add esds comments
[vlc.git] / lib / media_list_player.c
blobc7086cf4b83659813dd0ef0aa0df154d0ecf688a
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 assert_locked(p_mlp);
123 return libvlc_media_player_event_manager(p_mlp->p_mi);
126 /**************************************************************************
127 * get_next_path (private)
129 * Returns the path to the next item in the list.
130 * If looping is specified and the current item is the last list item in
131 * the list it will return the first item in the list.
132 **************************************************************************/
133 static libvlc_media_list_path_t
134 get_next_path(libvlc_media_list_player_t * p_mlp, bool b_loop)
136 assert_locked(p_mlp);
138 /* We are entered with libvlc_media_list_lock(p_mlp->p_list) */
139 libvlc_media_list_path_t ret;
140 libvlc_media_list_t * p_parent_of_playing_item;
141 libvlc_media_list_t * p_sublist_of_playing_item;
143 if (!p_mlp->current_playing_item_path)
145 if (!libvlc_media_list_count(p_mlp->p_mlist))
146 return NULL;
147 return libvlc_media_list_path_with_root_index(0);
150 p_sublist_of_playing_item = libvlc_media_list_sublist_at_path(
151 p_mlp->p_mlist,
152 p_mlp->current_playing_item_path);
154 /* If item just gained a sublist just play it */
155 if (p_sublist_of_playing_item)
157 int i_count = libvlc_media_list_count(p_sublist_of_playing_item);
158 libvlc_media_list_release(p_sublist_of_playing_item);
159 if (i_count > 0)
160 return libvlc_media_list_path_copy_by_appending(p_mlp->current_playing_item_path, 0);
163 /* Try to catch parent element */
164 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(p_mlp->p_mlist,
165 p_mlp->current_playing_item_path);
167 int depth = libvlc_media_list_path_depth(p_mlp->current_playing_item_path);
168 if (depth < 1 || !p_parent_of_playing_item)
169 return NULL;
171 ret = libvlc_media_list_path_copy(p_mlp->current_playing_item_path);
172 ret[depth - 1]++; /* set to next element */
174 /* If this goes beyond the end of the list */
175 while(ret[depth-1] >= libvlc_media_list_count(p_parent_of_playing_item))
177 depth--;
178 if (depth <= 0)
180 if(b_loop)
182 ret[0] = 0;
183 ret[1] = -1;
184 break;
186 else
188 free(ret);
189 libvlc_media_list_release(p_parent_of_playing_item);
190 return NULL;
193 ret[depth] = -1;
194 ret[depth-1]++;
195 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(
196 p_mlp->p_mlist,
197 ret);
200 libvlc_media_list_release(p_parent_of_playing_item);
201 return ret;
204 /**************************************************************************
205 * find_last_item (private)
207 * Returns the path of the last descendant of a given item path.
208 * Note: Due to the recursive nature of the function and the need to free
209 * media list paths, paths passed in may be freed if they are replaced.
210 Recommended usage is to set return value to the same path that was
211 passed to the function (i.e. item = find_last_item(list, item); )
212 **************************************************************************/
213 static libvlc_media_list_path_t
214 find_last_item( libvlc_media_list_t * p_mlist, libvlc_media_list_path_t current_item )
216 libvlc_media_list_t * p_sublist = libvlc_media_list_sublist_at_path(p_mlist, current_item);
217 libvlc_media_list_path_t last_item_path = current_item;
219 if(p_sublist)
221 int i_count = libvlc_media_list_count(p_sublist);
222 if(i_count > 0)
224 /* Add the last sublist item to the path. */
225 last_item_path = libvlc_media_list_path_copy_by_appending(current_item, i_count - 1);
226 free(current_item);
227 /* Check that sublist item for more descendants. */
228 last_item_path = find_last_item(p_mlist, last_item_path);
231 libvlc_media_list_release(p_sublist);
234 return last_item_path;
237 /**************************************************************************
238 * get_previous_path (private)
240 * Returns the path to the preceding item in the list.
241 * If looping is specified and the current item is the first list item in
242 * the list it will return the last descendant of the last item in the list.
243 **************************************************************************/
244 static libvlc_media_list_path_t
245 get_previous_path(libvlc_media_list_player_t * p_mlp, bool b_loop)
247 assert_locked(p_mlp);
249 /* We are entered with libvlc_media_list_lock(p_mlp->p_list) */
250 libvlc_media_list_path_t ret;
251 libvlc_media_list_t * p_parent_of_playing_item;
253 if (!p_mlp->current_playing_item_path)
255 if (!libvlc_media_list_count(p_mlp->p_mlist))
256 return NULL;
257 return libvlc_media_list_path_with_root_index(0);
260 /* Try to catch parent element */
261 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(
262 p_mlp->p_mlist,
263 p_mlp->current_playing_item_path);
265 int depth = libvlc_media_list_path_depth(p_mlp->current_playing_item_path);
266 if (depth < 1 || !p_parent_of_playing_item)
267 return NULL;
269 /* Set the return path to the current path */
270 ret = libvlc_media_list_path_copy(p_mlp->current_playing_item_path);
272 /* Change the return path to the previous list entry */
273 ret[depth - 1]--; /* set to previous element */
274 ret[depth] = -1;
276 /* Is the return path is beyond the start of the current list? */
277 if(ret[depth - 1] < 0)
279 /* Move to parent of current item */
280 depth--;
282 /* Are we at the root level of the tree? */
283 if (depth <= 0)
285 // Is looping enabled?
286 if(b_loop)
288 int i_count = libvlc_media_list_count(p_parent_of_playing_item);
290 /* Set current play item to the last element in the list */
291 ret[0] = i_count - 1;
292 ret[1] = -1;
294 /* Set the return path to the last descendant item of the current item */
295 ret = find_last_item(p_mlp->p_mlist, ret);
297 else
299 /* No looping so return empty path. */
300 free(ret);
301 ret = NULL;
304 else
306 /* This is the case of moving backward from the beginning of the
307 * subitem list to its parent item.
308 * This ensures that current path is properly terminated to
309 * use that parent.
311 ret[depth] = -1;
314 else
316 ret = find_last_item(p_mlp->p_mlist, ret);
319 libvlc_media_list_release(p_parent_of_playing_item);
320 return ret;
323 static void *playlist_thread(void *data)
325 libvlc_media_list_player_t *mlp = data;
327 vlc_mutex_lock(&mlp->mp_callback_lock);
328 mutex_cleanup_push(&mlp->mp_callback_lock);
330 for (;;)
332 int canc;
334 while (mlp->seek_offset == 0)
335 vlc_cond_wait(&mlp->seek_pending, &mlp->mp_callback_lock);
337 canc = vlc_savecancel();
338 set_relative_playlist_position_and_play(mlp, mlp->seek_offset);
339 mlp->seek_offset = 0;
340 vlc_restorecancel(canc);
343 vlc_cleanup_pop();
344 vlc_assert_unreachable();
347 /**************************************************************************
348 * media_player_reached_end (private) (Event Callback)
349 **************************************************************************/
350 static void
351 media_player_reached_end(const libvlc_event_t * p_event, void * p_user_data)
353 VLC_UNUSED(p_event);
354 libvlc_media_list_player_t * p_mlp = p_user_data;
356 /* This event is triggered from the input thread, and changing item in
357 * the media player requires the input thread to terminate. So we cannot
358 * change the playlist state here (it would cause a deadlock). Instead, we
359 * defer to a separate thread. Avoiding this would be nice... */
360 vlc_mutex_lock(&p_mlp->mp_callback_lock);
361 p_mlp->seek_offset++;
362 vlc_cond_signal(&p_mlp->seek_pending);
363 vlc_mutex_unlock(&p_mlp->mp_callback_lock);
366 /**************************************************************************
367 * playlist_item_deleted (private) (Event Callback)
368 **************************************************************************/
369 static void
370 mlist_item_deleted(const libvlc_event_t * p_event, void * p_user_data)
372 // Nothing to do. For now.
373 (void)p_event; (void)p_user_data;
377 /**************************************************************************
378 * install_playlist_observer (private)
379 **************************************************************************/
380 static void
381 install_playlist_observer(libvlc_media_list_player_t * p_mlp)
383 assert_locked(p_mlp);
384 libvlc_event_attach(mlist_em(p_mlp), libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp);
387 /**************************************************************************
388 * uninstall_playlist_observer (private)
389 **************************************************************************/
390 static void
391 uninstall_playlist_observer(libvlc_media_list_player_t * p_mlp)
393 assert_locked(p_mlp);
394 if (!p_mlp->p_mlist) return;
395 libvlc_event_detach(mlist_em(p_mlp), libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp);
398 /**************************************************************************
399 * install_media_player_observer (private)
400 **************************************************************************/
401 static void
402 install_media_player_observer(libvlc_media_list_player_t * p_mlp)
404 assert_locked(p_mlp);
405 libvlc_event_attach(mplayer_em(p_mlp), libvlc_MediaPlayerEndReached, media_player_reached_end, p_mlp);
409 /**************************************************************************
410 * uninstall_media_player_observer (private)
411 **************************************************************************/
412 static void
413 uninstall_media_player_observer(libvlc_media_list_player_t * p_mlp)
415 assert_locked(p_mlp);
417 // Allow callbacks to run, because detach() will wait until all callbacks are processed.
418 // This is safe because only callbacks are allowed, and there execution will be cancelled.
419 vlc_mutex_unlock(&p_mlp->mp_callback_lock);
420 libvlc_event_detach(mplayer_em(p_mlp), libvlc_MediaPlayerEndReached, media_player_reached_end, p_mlp);
422 // Now, lock back the callback lock. No more callback will be present from this point.
423 vlc_mutex_lock(&p_mlp->mp_callback_lock);
425 // What is here is safe, because we guarantee that we won't be able to anything concurrently,
426 // - except (cancelled) callbacks - thanks to the object_lock.
429 /**************************************************************************
430 * set_current_playing_item (private)
432 * Playlist lock should be held
433 **************************************************************************/
434 static void
435 set_current_playing_item(libvlc_media_list_player_t * p_mlp, libvlc_media_list_path_t path)
437 assert_locked(p_mlp);
439 /* First, save the new path that we are going to play */
440 if (p_mlp->current_playing_item_path != path)
442 free(p_mlp->current_playing_item_path);
443 p_mlp->current_playing_item_path = path;
446 if (!path)
447 return;
449 libvlc_media_t * p_md;
450 p_md = libvlc_media_list_item_at_path(p_mlp->p_mlist, path);
451 if (!p_md)
452 return;
454 /* Make sure media_player_reached_end() won't get called */
455 uninstall_media_player_observer(p_mlp);
457 libvlc_media_player_set_media(p_mlp->p_mi, p_md);
459 install_media_player_observer(p_mlp);
460 libvlc_media_release(p_md); /* for libvlc_media_list_item_at_index */
464 * Public libvlc functions
467 /**************************************************************************
468 * new (Public)
469 **************************************************************************/
470 libvlc_media_list_player_t *
471 libvlc_media_list_player_new(libvlc_instance_t * p_instance)
473 libvlc_media_list_player_t * p_mlp;
474 p_mlp = calloc( 1, sizeof(libvlc_media_list_player_t) );
475 if (unlikely(p_mlp == NULL))
477 libvlc_printerr("Not enough memory");
478 return NULL;
481 p_mlp->i_refcount = 1;
482 p_mlp->seek_offset = 0;
483 vlc_mutex_init(&p_mlp->object_lock);
484 vlc_mutex_init(&p_mlp->mp_callback_lock);
485 vlc_cond_init(&p_mlp->seek_pending);
486 libvlc_event_manager_init(&p_mlp->event_manager, p_mlp);
488 /* Create the underlying media_player */
489 p_mlp->p_mi = libvlc_media_player_new(p_instance);
490 if( p_mlp->p_mi == NULL )
491 goto error;
492 install_media_player_observer(p_mlp);
494 if (vlc_clone(&p_mlp->thread, playlist_thread, p_mlp,
495 VLC_THREAD_PRIORITY_LOW))
497 libvlc_media_player_release(p_mlp->p_mi);
498 goto error;
501 return p_mlp;
502 error:
503 libvlc_event_manager_destroy(&p_mlp->event_manager);
504 vlc_cond_destroy(&p_mlp->seek_pending);
505 vlc_mutex_destroy(&p_mlp->mp_callback_lock);
506 vlc_mutex_destroy(&p_mlp->object_lock);
507 free(p_mlp);
508 return NULL;
511 /**************************************************************************
512 * release (Public)
513 **************************************************************************/
514 void libvlc_media_list_player_release(libvlc_media_list_player_t * p_mlp)
516 if (!p_mlp)
517 return;
519 lock(p_mlp);
520 p_mlp->i_refcount--;
521 if (p_mlp->i_refcount > 0)
523 unlock(p_mlp);
524 return;
526 assert(p_mlp->i_refcount == 0);
527 unlock(p_mlp);
529 vlc_cancel(p_mlp->thread);
530 vlc_join(p_mlp->thread, NULL);
532 lock(p_mlp);
533 /* Keep the lock(), because the uninstall functions
534 * check for it. That's convenient. */
535 uninstall_media_player_observer(p_mlp);
536 libvlc_media_player_release(p_mlp->p_mi);
538 if (p_mlp->p_mlist)
540 uninstall_playlist_observer(p_mlp);
541 libvlc_media_list_release(p_mlp->p_mlist);
544 unlock(p_mlp);
546 libvlc_event_manager_destroy(&p_mlp->event_manager);
547 vlc_cond_destroy(&p_mlp->seek_pending);
548 vlc_mutex_destroy(&p_mlp->mp_callback_lock);
549 vlc_mutex_destroy(&p_mlp->object_lock);
551 free(p_mlp->current_playing_item_path);
552 free(p_mlp);
555 /**************************************************************************
556 * retain (Public)
557 **************************************************************************/
558 void libvlc_media_list_player_retain(libvlc_media_list_player_t * p_mlp)
560 if (!p_mlp)
561 return;
563 lock(p_mlp);
564 p_mlp->i_refcount++;
565 unlock(p_mlp);
568 /**************************************************************************
569 * event_manager (Public)
570 **************************************************************************/
571 libvlc_event_manager_t *
572 libvlc_media_list_player_event_manager(libvlc_media_list_player_t * p_mlp)
574 return &p_mlp->event_manager;
577 /**************************************************************************
578 * set_media_player (Public)
579 **************************************************************************/
580 void libvlc_media_list_player_set_media_player(libvlc_media_list_player_t * p_mlp, libvlc_media_player_t * p_mi)
582 libvlc_media_player_t *p_oldmi;
584 assert(p_mi != NULL);
585 libvlc_media_player_retain(p_mi);
587 lock(p_mlp);
588 uninstall_media_player_observer(p_mlp);
589 p_oldmi = p_mlp->p_mi;
590 p_mlp->p_mi = p_mi;
591 install_media_player_observer(p_mlp);
592 unlock(p_mlp);
594 libvlc_media_player_release(p_oldmi);
597 /**************************************************************************
598 * get_media_player (Public)
599 **************************************************************************/
600 libvlc_media_player_t * libvlc_media_list_player_get_media_player(libvlc_media_list_player_t * p_mlp)
602 libvlc_media_player_retain(p_mlp->p_mi);
603 return p_mlp->p_mi;
606 /**************************************************************************
607 * set_media_list (Public)
608 **************************************************************************/
609 void libvlc_media_list_player_set_media_list(libvlc_media_list_player_t * p_mlp, libvlc_media_list_t * p_mlist)
611 assert (p_mlist);
613 lock(p_mlp);
614 if (p_mlp->p_mlist)
616 uninstall_playlist_observer(p_mlp);
617 libvlc_media_list_release(p_mlp->p_mlist);
619 libvlc_media_list_retain(p_mlist);
620 p_mlp->p_mlist = p_mlist;
622 install_playlist_observer(p_mlp);
624 unlock(p_mlp);
627 /**************************************************************************
628 * Play (Public)
629 **************************************************************************/
630 void libvlc_media_list_player_play(libvlc_media_list_player_t * p_mlp)
632 lock(p_mlp);
633 if (!p_mlp->current_playing_item_path)
635 set_relative_playlist_position_and_play(p_mlp, 1);
636 unlock(p_mlp);
637 return; /* Will set to play */
639 libvlc_media_player_play(p_mlp->p_mi);
640 unlock(p_mlp);
644 /**************************************************************************
645 * Pause (Public)
646 **************************************************************************/
647 void libvlc_media_list_player_pause(libvlc_media_list_player_t * p_mlp)
649 lock(p_mlp);
650 libvlc_media_player_pause(p_mlp->p_mi);
651 unlock(p_mlp);
654 void libvlc_media_list_player_set_pause(libvlc_media_list_player_t * p_mlp,
655 int do_pause)
657 lock(p_mlp);
658 libvlc_media_player_set_pause(p_mlp->p_mi, do_pause);
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_Playing);
672 /**************************************************************************
673 * State (Public)
674 **************************************************************************/
675 libvlc_state_t
676 libvlc_media_list_player_get_state(libvlc_media_list_player_t * p_mlp)
678 return libvlc_media_player_get_state(p_mlp->p_mi);
681 /**************************************************************************
682 * Play item at index (Public)
683 **************************************************************************/
684 int libvlc_media_list_player_play_item_at_index(libvlc_media_list_player_t * p_mlp, int i_index)
686 lock(p_mlp);
687 libvlc_media_list_path_t path = libvlc_media_list_path_with_root_index(i_index);
688 set_current_playing_item(p_mlp, path);
689 libvlc_media_t *p_md = libvlc_media_player_get_media(p_mlp->p_mi);
690 libvlc_media_player_play(p_mlp->p_mi);
691 unlock(p_mlp);
693 if (!p_md)
694 return -1;
696 /* Send the next item event */
697 libvlc_event_t event;
698 event.type = libvlc_MediaListPlayerNextItemSet;
699 event.u.media_list_player_next_item_set.item = p_md;
700 libvlc_event_send(&p_mlp->event_manager, &event);
701 libvlc_media_release(p_md);
702 return 0;
705 /**************************************************************************
706 * Play item (Public)
707 **************************************************************************/
708 int libvlc_media_list_player_play_item(libvlc_media_list_player_t * p_mlp, libvlc_media_t * p_md)
710 lock(p_mlp);
711 libvlc_media_list_path_t path = libvlc_media_list_path_of_item(p_mlp->p_mlist, p_md);
712 if (!path)
714 libvlc_printerr("Item not found in media list");
715 unlock(p_mlp);
716 return -1;
719 set_current_playing_item(p_mlp, path);
720 libvlc_media_player_play(p_mlp->p_mi);
721 unlock(p_mlp);
722 return 0;
725 /**************************************************************************
726 * Stop (Private)
728 * Lock must be held.
729 **************************************************************************/
730 static void stop(libvlc_media_list_player_t * p_mlp)
732 assert_locked(p_mlp);
734 /* We are not interested in getting media stop event now */
735 uninstall_media_player_observer(p_mlp);
736 libvlc_media_player_stop(p_mlp->p_mi);
737 install_media_player_observer(p_mlp);
739 free(p_mlp->current_playing_item_path);
740 p_mlp->current_playing_item_path = NULL;
742 /* Send the event */
743 libvlc_event_t event;
744 event.type = libvlc_MediaListPlayerStopped;
745 libvlc_event_send(&p_mlp->event_manager, &event);
748 /**************************************************************************
749 * Stop (Public)
750 **************************************************************************/
751 void libvlc_media_list_player_stop(libvlc_media_list_player_t * p_mlp)
753 lock(p_mlp);
754 stop(p_mlp);
755 unlock(p_mlp);
758 /**************************************************************************
759 * Set relative playlist position and play (Private)
761 * Sets the currently played item to the given relative play item position
762 * (based on the currently playing item) and then begins the new item playback.
763 * Lock must be held.
764 **************************************************************************/
765 static int set_relative_playlist_position_and_play(
766 libvlc_media_list_player_t * p_mlp,
767 int i_relative_position)
769 assert_locked(p_mlp);
771 if (!p_mlp->p_mlist)
773 libvlc_printerr("No media list");
774 return -1;
777 libvlc_media_list_lock(p_mlp->p_mlist);
779 libvlc_media_list_path_t path = p_mlp->current_playing_item_path;
781 if(p_mlp->e_playback_mode != libvlc_playback_mode_repeat)
783 bool b_loop = (p_mlp->e_playback_mode == libvlc_playback_mode_loop);
785 while (i_relative_position > 0)
787 path = get_next_path(p_mlp, b_loop);
788 set_current_playing_item(p_mlp, path);
789 --i_relative_position;
792 while (i_relative_position < 0)
794 path = get_previous_path(p_mlp, b_loop);
795 set_current_playing_item(p_mlp, path);
796 ++i_relative_position;
799 else
801 set_current_playing_item(p_mlp, path);
804 #ifdef DEBUG_MEDIA_LIST_PLAYER
805 printf("Playing:");
806 libvlc_media_list_path_dump(path);
807 #endif
809 if (!path)
811 libvlc_media_list_unlock(p_mlp->p_mlist);
812 /* Send list played event */
813 libvlc_event_t event;
814 event.type = libvlc_MediaListPlayerPlayed;
815 libvlc_event_send(&p_mlp->event_manager, &event);
816 return -1;
819 libvlc_media_player_play(p_mlp->p_mi);
821 libvlc_media_list_unlock(p_mlp->p_mlist);
823 /* Send the next item event */
824 libvlc_event_t event;
825 event.type = libvlc_MediaListPlayerNextItemSet;
826 libvlc_media_t * p_md = libvlc_media_list_item_at_path(p_mlp->p_mlist, path);
827 event.u.media_list_player_next_item_set.item = p_md;
828 libvlc_event_send(&p_mlp->event_manager, &event);
829 libvlc_media_release(p_md);
830 return 0;
833 /**************************************************************************
834 * Next (Public)
835 **************************************************************************/
836 int libvlc_media_list_player_next(libvlc_media_list_player_t * p_mlp)
838 lock(p_mlp);
839 int failure = set_relative_playlist_position_and_play(p_mlp, 1);
840 unlock(p_mlp);
841 return failure;
844 /**************************************************************************
845 * Previous (Public)
846 **************************************************************************/
847 int libvlc_media_list_player_previous(libvlc_media_list_player_t * p_mlp)
849 lock(p_mlp);
850 int failure = set_relative_playlist_position_and_play(p_mlp, -1);
851 unlock(p_mlp);
852 return failure;
855 /**************************************************************************
856 * Set Playback Mode (Public)
857 **************************************************************************/
858 void libvlc_media_list_player_set_playback_mode(
859 libvlc_media_list_player_t * p_mlp,
860 libvlc_playback_mode_t e_mode )
862 lock(p_mlp);
863 p_mlp->e_playback_mode = e_mode;
864 unlock(p_mlp);