mmal: Link to core, components, util explicitly
[vlc.git] / lib / media_list_player.c
blob930b69061a62634c4f2878eeba7c76556b9ec5fb
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 libvlc_media_list_release(p_sublist_of_playing_item);
163 return libvlc_media_list_path_copy_by_appending(p_mlp->current_playing_item_path, 0);
166 /* Try to catch parent element */
167 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(p_mlp->p_mlist,
168 p_mlp->current_playing_item_path);
170 int depth = libvlc_media_list_path_depth(p_mlp->current_playing_item_path);
171 if (depth < 1 || !p_parent_of_playing_item)
172 return NULL;
174 ret = libvlc_media_list_path_copy(p_mlp->current_playing_item_path);
175 ret[depth - 1]++; /* set to next element */
177 /* If this goes beyond the end of the list */
178 while(ret[depth-1] >= libvlc_media_list_count(p_parent_of_playing_item))
180 depth--;
181 if (depth <= 0)
183 if(b_loop)
185 ret[0] = 0;
186 ret[1] = -1;
187 break;
189 else
191 free(ret);
192 libvlc_media_list_release(p_parent_of_playing_item);
193 return NULL;
196 ret[depth] = -1;
197 ret[depth-1]++;
198 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(
199 p_mlp->p_mlist,
200 ret);
203 libvlc_media_list_release(p_parent_of_playing_item);
204 return ret;
207 /**************************************************************************
208 * find_last_item (private)
210 * Returns the path of the last descendant of a given item path.
211 * Note: Due to the recursive nature of the function and the need to free
212 * media list paths, paths passed in may be freed if they are replaced.
213 Recommended usage is to set return value to the same path that was
214 passed to the function (i.e. item = find_last_item(list, item); )
215 **************************************************************************/
216 static libvlc_media_list_path_t
217 find_last_item( libvlc_media_list_t * p_mlist, libvlc_media_list_path_t current_item )
219 libvlc_media_list_t * p_sublist = libvlc_media_list_sublist_at_path(p_mlist, current_item);
220 libvlc_media_list_path_t last_item_path = current_item;
222 if(p_sublist)
224 int i_count = libvlc_media_list_count(p_sublist);
225 if(i_count > 0)
227 /* Add the last sublist item to the path. */
228 last_item_path = libvlc_media_list_path_copy_by_appending(current_item, i_count - 1);
229 free(current_item);
230 /* Check that sublist item for more descendants. */
231 last_item_path = find_last_item(p_mlist, last_item_path);
234 libvlc_media_list_release(p_sublist);
237 return last_item_path;
240 /**************************************************************************
241 * get_previous_path (private)
243 * Returns the path to the preceding item in the list.
244 * If looping is specified and the current item is the first list item in
245 * the list it will return the last descendant of the last item in the list.
246 **************************************************************************/
247 static libvlc_media_list_path_t
248 get_previous_path(libvlc_media_list_player_t * p_mlp, bool b_loop)
250 assert_locked(p_mlp);
252 /* We are entered with libvlc_media_list_lock(p_mlp->p_list) */
253 libvlc_media_list_path_t ret;
254 libvlc_media_list_t * p_parent_of_playing_item;
256 if (!p_mlp->current_playing_item_path)
258 if (!libvlc_media_list_count(p_mlp->p_mlist))
259 return NULL;
260 return libvlc_media_list_path_with_root_index(0);
263 /* Try to catch parent element */
264 p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(
265 p_mlp->p_mlist,
266 p_mlp->current_playing_item_path);
268 int depth = libvlc_media_list_path_depth(p_mlp->current_playing_item_path);
269 if (depth < 1 || !p_parent_of_playing_item)
270 return NULL;
272 /* Set the return path to the current path */
273 ret = libvlc_media_list_path_copy(p_mlp->current_playing_item_path);
275 /* Change the return path to the previous list entry */
276 ret[depth - 1]--; /* set to previous element */
277 ret[depth] = -1;
279 /* Is the return path is beyond the start of the current list? */
280 if(ret[depth - 1] < 0)
282 /* Move to parent of current item */
283 depth--;
285 /* Are we at the root level of the tree? */
286 if (depth <= 0)
288 // Is looping enabled?
289 if(b_loop)
291 int i_count = libvlc_media_list_count(p_parent_of_playing_item);
293 /* Set current play item to the last element in the list */
294 ret[0] = i_count - 1;
295 ret[1] = -1;
297 /* Set the return path to the last descendant item of the current item */
298 ret = find_last_item(p_mlp->p_mlist, ret);
300 else
302 /* No looping so return empty path. */
303 free(ret);
304 ret = NULL;
307 else
309 /* This is the case of moving backward from the beginning of the
310 * subitem list to its parent item.
311 * This ensures that current path is properly terminated to
312 * use that parent.
314 ret[depth] = -1;
317 else
319 ret = find_last_item(p_mlp->p_mlist, ret);
322 libvlc_media_list_release(p_parent_of_playing_item);
323 return ret;
326 static void *playlist_thread(void *data)
328 libvlc_media_list_player_t *mlp = data;
330 vlc_mutex_lock(&mlp->mp_callback_lock);
331 mutex_cleanup_push(&mlp->mp_callback_lock);
333 for (;;)
335 int canc;
337 while (mlp->seek_offset == 0)
338 vlc_cond_wait(&mlp->seek_pending, &mlp->mp_callback_lock);
340 canc = vlc_savecancel();
341 set_relative_playlist_position_and_play(mlp, mlp->seek_offset);
342 mlp->seek_offset = 0;
343 vlc_restorecancel(canc);
346 vlc_cleanup_pop();
347 vlc_assert_unreachable();
350 /**************************************************************************
351 * media_player_reached_end (private) (Event Callback)
352 **************************************************************************/
353 static void
354 media_player_reached_end(const libvlc_event_t * p_event, void * p_user_data)
356 VLC_UNUSED(p_event);
357 libvlc_media_list_player_t * p_mlp = p_user_data;
359 /* This event is triggered from the input thread, and changing item in
360 * the media player requires the input thread to terminate. So we cannot
361 * change the playlist state here (it would cause a deadlock). Instead, we
362 * defer to a separate thread. Avoiding this would be nice... */
363 vlc_mutex_lock(&p_mlp->mp_callback_lock);
364 p_mlp->seek_offset++;
365 vlc_cond_signal(&p_mlp->seek_pending);
366 vlc_mutex_unlock(&p_mlp->mp_callback_lock);
369 /**************************************************************************
370 * playlist_item_deleted (private) (Event Callback)
371 **************************************************************************/
372 static void
373 mlist_item_deleted(const libvlc_event_t * p_event, void * p_user_data)
375 // Nothing to do. For now.
376 (void)p_event; (void)p_user_data;
380 /**************************************************************************
381 * install_playlist_observer (private)
382 **************************************************************************/
383 static void
384 install_playlist_observer(libvlc_media_list_player_t * p_mlp)
386 assert_locked(p_mlp);
387 libvlc_event_attach(mlist_em(p_mlp), libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp);
390 /**************************************************************************
391 * uninstall_playlist_observer (private)
392 **************************************************************************/
393 static void
394 uninstall_playlist_observer(libvlc_media_list_player_t * p_mlp)
396 assert_locked(p_mlp);
397 if (!p_mlp->p_mlist) return;
398 libvlc_event_detach(mlist_em(p_mlp), libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp);
401 /**************************************************************************
402 * install_media_player_observer (private)
403 **************************************************************************/
404 static void
405 install_media_player_observer(libvlc_media_list_player_t * p_mlp)
407 assert_locked(p_mlp);
408 libvlc_event_attach(mplayer_em(p_mlp), libvlc_MediaPlayerEndReached, media_player_reached_end, p_mlp);
412 /**************************************************************************
413 * uninstall_media_player_observer (private)
414 **************************************************************************/
415 static void
416 uninstall_media_player_observer(libvlc_media_list_player_t * p_mlp)
418 assert_locked(p_mlp);
420 // Allow callbacks to run, because detach() will wait until all callbacks are processed.
421 // This is safe because only callbacks are allowed, and there execution will be cancelled.
422 vlc_mutex_unlock(&p_mlp->mp_callback_lock);
423 libvlc_event_detach(mplayer_em(p_mlp), libvlc_MediaPlayerEndReached, media_player_reached_end, p_mlp);
425 // Now, lock back the callback lock. No more callback will be present from this point.
426 vlc_mutex_lock(&p_mlp->mp_callback_lock);
428 // What is here is safe, because we guarantee that we won't be able to anything concurrently,
429 // - except (cancelled) callbacks - thanks to the object_lock.
432 /**************************************************************************
433 * set_current_playing_item (private)
435 * Playlist lock should be held
436 **************************************************************************/
437 static void
438 set_current_playing_item(libvlc_media_list_player_t * p_mlp, libvlc_media_list_path_t path)
440 assert_locked(p_mlp);
442 /* First, save the new path that we are going to play */
443 if (p_mlp->current_playing_item_path != path)
445 free(p_mlp->current_playing_item_path);
446 p_mlp->current_playing_item_path = path;
449 if (!path)
450 return;
452 libvlc_media_t * p_md;
453 p_md = libvlc_media_list_item_at_path(p_mlp->p_mlist, path);
454 if (!p_md)
455 return;
457 /* Make sure media_player_reached_end() won't get called */
458 uninstall_media_player_observer(p_mlp);
460 libvlc_media_player_set_media(p_mlp->p_mi, p_md);
462 install_media_player_observer(p_mlp);
463 libvlc_media_release(p_md); /* for libvlc_media_list_item_at_index */
467 * Public libvlc functions
470 /**************************************************************************
471 * new (Public)
472 **************************************************************************/
473 libvlc_media_list_player_t *
474 libvlc_media_list_player_new(libvlc_instance_t * p_instance)
476 libvlc_media_list_player_t * p_mlp;
477 p_mlp = calloc( 1, sizeof(libvlc_media_list_player_t) );
478 if (unlikely(p_mlp == NULL))
480 libvlc_printerr("Not enough memory");
481 return NULL;
484 p_mlp->i_refcount = 1;
485 p_mlp->seek_offset = 0;
486 vlc_mutex_init(&p_mlp->object_lock);
487 vlc_mutex_init(&p_mlp->mp_callback_lock);
488 vlc_cond_init(&p_mlp->seek_pending);
489 libvlc_event_manager_init(&p_mlp->event_manager, p_mlp);
491 /* Create the underlying media_player */
492 p_mlp->p_mi = libvlc_media_player_new(p_instance);
493 if( p_mlp->p_mi == NULL )
494 goto error;
495 install_media_player_observer(p_mlp);
497 if (vlc_clone(&p_mlp->thread, playlist_thread, p_mlp,
498 VLC_THREAD_PRIORITY_LOW))
500 libvlc_media_player_release(p_mlp->p_mi);
501 goto error;
504 return p_mlp;
505 error:
506 libvlc_event_manager_destroy(&p_mlp->event_manager);
507 vlc_cond_destroy(&p_mlp->seek_pending);
508 vlc_mutex_destroy(&p_mlp->mp_callback_lock);
509 vlc_mutex_destroy(&p_mlp->object_lock);
510 free(p_mlp);
511 return NULL;
514 /**************************************************************************
515 * release (Public)
516 **************************************************************************/
517 void libvlc_media_list_player_release(libvlc_media_list_player_t * p_mlp)
519 if (!p_mlp)
520 return;
522 lock(p_mlp);
523 p_mlp->i_refcount--;
524 if (p_mlp->i_refcount > 0)
526 unlock(p_mlp);
527 return;
529 assert(p_mlp->i_refcount == 0);
530 unlock(p_mlp);
532 vlc_cancel(p_mlp->thread);
533 vlc_join(p_mlp->thread, NULL);
535 lock(p_mlp);
536 /* Keep the lock(), because the uninstall functions
537 * check for it. That's convenient. */
538 uninstall_media_player_observer(p_mlp);
539 libvlc_media_player_release(p_mlp->p_mi);
541 if (p_mlp->p_mlist)
543 uninstall_playlist_observer(p_mlp);
544 libvlc_media_list_release(p_mlp->p_mlist);
547 unlock(p_mlp);
549 libvlc_event_manager_destroy(&p_mlp->event_manager);
550 vlc_cond_destroy(&p_mlp->seek_pending);
551 vlc_mutex_destroy(&p_mlp->mp_callback_lock);
552 vlc_mutex_destroy(&p_mlp->object_lock);
554 free(p_mlp->current_playing_item_path);
555 free(p_mlp);
558 /**************************************************************************
559 * retain (Public)
560 **************************************************************************/
561 void libvlc_media_list_player_retain(libvlc_media_list_player_t * p_mlp)
563 if (!p_mlp)
564 return;
566 lock(p_mlp);
567 p_mlp->i_refcount++;
568 unlock(p_mlp);
571 /**************************************************************************
572 * event_manager (Public)
573 **************************************************************************/
574 libvlc_event_manager_t *
575 libvlc_media_list_player_event_manager(libvlc_media_list_player_t * p_mlp)
577 return &p_mlp->event_manager;
580 /**************************************************************************
581 * set_media_player (Public)
582 **************************************************************************/
583 void libvlc_media_list_player_set_media_player(libvlc_media_list_player_t * p_mlp, libvlc_media_player_t * p_mi)
585 libvlc_media_player_t *p_oldmi;
587 assert(p_mi != NULL);
588 libvlc_media_player_retain(p_mi);
590 lock(p_mlp);
591 uninstall_media_player_observer(p_mlp);
592 p_oldmi = p_mlp->p_mi;
593 p_mlp->p_mi = p_mi;
594 install_media_player_observer(p_mlp);
595 unlock(p_mlp);
597 libvlc_media_player_release(p_oldmi);
600 /**************************************************************************
601 * get_media_player (Public)
602 **************************************************************************/
603 libvlc_media_player_t * libvlc_media_list_player_get_media_player(libvlc_media_list_player_t * p_mlp)
605 libvlc_media_player_retain(p_mlp->p_mi);
606 return p_mlp->p_mi;
609 /**************************************************************************
610 * set_media_list (Public)
611 **************************************************************************/
612 void libvlc_media_list_player_set_media_list(libvlc_media_list_player_t * p_mlp, libvlc_media_list_t * p_mlist)
614 assert (p_mlist);
616 lock(p_mlp);
617 if (p_mlp->p_mlist)
619 uninstall_playlist_observer(p_mlp);
620 libvlc_media_list_release(p_mlp->p_mlist);
622 libvlc_media_list_retain(p_mlist);
623 p_mlp->p_mlist = p_mlist;
625 install_playlist_observer(p_mlp);
627 unlock(p_mlp);
630 /**************************************************************************
631 * Play (Public)
632 **************************************************************************/
633 void libvlc_media_list_player_play(libvlc_media_list_player_t * p_mlp)
635 lock(p_mlp);
636 if (!p_mlp->current_playing_item_path)
638 set_relative_playlist_position_and_play(p_mlp, 1);
639 unlock(p_mlp);
640 return; /* Will set to play */
642 libvlc_media_player_play(p_mlp->p_mi);
643 unlock(p_mlp);
647 /**************************************************************************
648 * Pause (Public)
649 **************************************************************************/
650 void libvlc_media_list_player_pause(libvlc_media_list_player_t * p_mlp)
652 lock(p_mlp);
653 libvlc_media_player_pause(p_mlp->p_mi);
654 unlock(p_mlp);
657 /**************************************************************************
658 * is_playing (Public)
659 **************************************************************************/
661 libvlc_media_list_player_is_playing(libvlc_media_list_player_t * p_mlp)
663 libvlc_state_t state = libvlc_media_player_get_state(p_mlp->p_mi);
664 return (state == libvlc_Opening) || (state == libvlc_Playing);
667 /**************************************************************************
668 * State (Public)
669 **************************************************************************/
670 libvlc_state_t
671 libvlc_media_list_player_get_state(libvlc_media_list_player_t * p_mlp)
673 return libvlc_media_player_get_state(p_mlp->p_mi);
676 /**************************************************************************
677 * Play item at index (Public)
678 **************************************************************************/
679 int libvlc_media_list_player_play_item_at_index(libvlc_media_list_player_t * p_mlp, int i_index)
681 lock(p_mlp);
682 libvlc_media_list_path_t path = libvlc_media_list_path_with_root_index(i_index);
683 set_current_playing_item(p_mlp, path);
684 libvlc_media_t *p_md = libvlc_media_player_get_media(p_mlp->p_mi);
685 libvlc_media_player_play(p_mlp->p_mi);
686 unlock(p_mlp);
688 if (!p_md)
689 return -1;
691 /* Send the next item event */
692 libvlc_event_t event;
693 event.type = libvlc_MediaListPlayerNextItemSet;
694 event.u.media_list_player_next_item_set.item = p_md;
695 libvlc_event_send(&p_mlp->event_manager, &event);
696 libvlc_media_release(p_md);
697 return 0;
700 /**************************************************************************
701 * Play item (Public)
702 **************************************************************************/
703 int libvlc_media_list_player_play_item(libvlc_media_list_player_t * p_mlp, libvlc_media_t * p_md)
705 lock(p_mlp);
706 libvlc_media_list_path_t path = libvlc_media_list_path_of_item(p_mlp->p_mlist, p_md);
707 if (!path)
709 libvlc_printerr("Item not found in media list");
710 unlock(p_mlp);
711 return -1;
714 set_current_playing_item(p_mlp, path);
715 libvlc_media_player_play(p_mlp->p_mi);
716 unlock(p_mlp);
717 return 0;
720 /**************************************************************************
721 * Stop (Private)
723 * Lock must be held.
724 **************************************************************************/
725 static void stop(libvlc_media_list_player_t * p_mlp)
727 assert_locked(p_mlp);
729 /* We are not interested in getting media stop event now */
730 uninstall_media_player_observer(p_mlp);
731 libvlc_media_player_stop(p_mlp->p_mi);
732 install_media_player_observer(p_mlp);
734 free(p_mlp->current_playing_item_path);
735 p_mlp->current_playing_item_path = NULL;
737 /* Send the event */
738 libvlc_event_t event;
739 event.type = libvlc_MediaListPlayerStopped;
740 libvlc_event_send(&p_mlp->event_manager, &event);
743 /**************************************************************************
744 * Stop (Public)
745 **************************************************************************/
746 void libvlc_media_list_player_stop(libvlc_media_list_player_t * p_mlp)
748 lock(p_mlp);
749 stop(p_mlp);
750 unlock(p_mlp);
753 /**************************************************************************
754 * Set relative playlist position and play (Private)
756 * Sets the currently played item to the given relative play item position
757 * (based on the currently playing item) and then begins the new item playback.
758 * Lock must be held.
759 **************************************************************************/
760 static int set_relative_playlist_position_and_play(
761 libvlc_media_list_player_t * p_mlp,
762 int i_relative_position)
764 assert_locked(p_mlp);
766 if (!p_mlp->p_mlist)
768 libvlc_printerr("No media list");
769 return -1;
772 libvlc_media_list_lock(p_mlp->p_mlist);
774 libvlc_media_list_path_t path = p_mlp->current_playing_item_path;
776 if(p_mlp->e_playback_mode != libvlc_playback_mode_repeat)
778 bool b_loop = (p_mlp->e_playback_mode == libvlc_playback_mode_loop);
780 while (i_relative_position > 0)
782 path = get_next_path(p_mlp, b_loop);
783 set_current_playing_item(p_mlp, path);
784 --i_relative_position;
787 while (i_relative_position < 0)
789 path = get_previous_path(p_mlp, b_loop);
790 set_current_playing_item(p_mlp, path);
791 ++i_relative_position;
794 else
796 set_current_playing_item(p_mlp, path);
799 #ifdef DEBUG_MEDIA_LIST_PLAYER
800 printf("Playing:");
801 libvlc_media_list_path_dump(path);
802 #endif
804 if (!path)
806 libvlc_media_list_unlock(p_mlp->p_mlist);
807 /* Send list played event */
808 libvlc_event_t event;
809 event.type = libvlc_MediaListPlayerPlayed;
810 libvlc_event_send(&p_mlp->event_manager, &event);
811 return -1;
814 libvlc_media_player_play(p_mlp->p_mi);
816 libvlc_media_list_unlock(p_mlp->p_mlist);
818 /* Send the next item event */
819 libvlc_event_t event;
820 event.type = libvlc_MediaListPlayerNextItemSet;
821 libvlc_media_t * p_md = libvlc_media_list_item_at_path(p_mlp->p_mlist, path);
822 event.u.media_list_player_next_item_set.item = p_md;
823 libvlc_event_send(&p_mlp->event_manager, &event);
824 libvlc_media_release(p_md);
825 return 0;
828 /**************************************************************************
829 * Next (Public)
830 **************************************************************************/
831 int libvlc_media_list_player_next(libvlc_media_list_player_t * p_mlp)
833 lock(p_mlp);
834 int failure = set_relative_playlist_position_and_play(p_mlp, 1);
835 unlock(p_mlp);
836 return failure;
839 /**************************************************************************
840 * Previous (Public)
841 **************************************************************************/
842 int libvlc_media_list_player_previous(libvlc_media_list_player_t * p_mlp)
844 lock(p_mlp);
845 int failure = set_relative_playlist_position_and_play(p_mlp, -1);
846 unlock(p_mlp);
847 return failure;
850 /**************************************************************************
851 * Set Playback Mode (Public)
852 **************************************************************************/
853 void libvlc_media_list_player_set_playback_mode(
854 libvlc_media_list_player_t * p_mlp,
855 libvlc_playback_mode_t e_mode )
857 lock(p_mlp);
858 p_mlp->e_playback_mode = e_mode;
859 unlock(p_mlp);