Update Changelogs
[vlc.git] / lib / media_list_player.c
blobb20d58d33ee85480df28b10a267260a942cae266
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 <vlc_common.h>
40 #include <vlc_atomic.h>
42 #include "libvlc_internal.h"
44 #include "media_internal.h" // Abuse, could and should be removed
45 #include "media_list_path.h"
47 //#define DEBUG_MEDIA_LIST_PLAYER
49 /* This is a very dummy implementation of playlist on top of
50 * media_list and media_player.
52 * All this code is doing is simply computing the next item
53 * of a tree of media_list (see get_next_index()), and play
54 * the next item when the current is over. This is happening
55 * via the event callback media_player_reached_end().
57 * This is thread safe, and we use a two keys (locks) scheme
58 * to discriminate between callbacks and regular uses.
61 struct libvlc_media_list_player_t
63 libvlc_event_manager_t event_manager;
64 int seek_offset;
65 bool dead;
66 /* Protect access to this structure. */
67 vlc_mutex_t object_lock;
68 /* Protect access to this structure and from callback execution. */
69 vlc_mutex_t mp_callback_lock;
70 vlc_cond_t seek_pending;
71 libvlc_media_list_path_t current_playing_item_path;
72 libvlc_media_t * p_current_playing_item;
73 libvlc_media_list_t * p_mlist;
74 libvlc_media_player_t * p_mi;
75 libvlc_playback_mode_t e_playback_mode;
77 vlc_thread_t thread;
78 vlc_atomic_rc_t rc;
82 * Forward declaration
85 static
86 int set_relative_playlist_position_and_play(libvlc_media_list_player_t *p_mlp,
87 int i_relative_position);
88 static void stop(libvlc_media_list_player_t * p_mlp);
91 * Private functions
94 /**************************************************************************
95 * Shortcuts
96 **************************************************************************/
97 static inline void lock(libvlc_media_list_player_t * p_mlp)
99 // Obtain an access to this structure
100 vlc_mutex_lock(&p_mlp->object_lock);
102 // Make sure no callback will occurs at the same time
103 vlc_mutex_lock(&p_mlp->mp_callback_lock);
106 static inline void unlock(libvlc_media_list_player_t * p_mlp)
108 vlc_mutex_unlock(&p_mlp->mp_callback_lock);
109 vlc_mutex_unlock(&p_mlp->object_lock);
112 static inline void assert_locked(libvlc_media_list_player_t * p_mlp)
114 vlc_mutex_assert(&p_mlp->mp_callback_lock);
115 (void) p_mlp;
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 return libvlc_media_player_event_manager(p_mlp->p_mi);
129 /**************************************************************************
130 * get_next_path (private)
132 * Returns the path to the next item in the list.
133 * If looping is specified and the current item is the last list item in
134 * the list it will return the first item in the list.
135 **************************************************************************/
136 static libvlc_media_list_path_t
137 get_next_path(libvlc_media_list_player_t * p_mlp, bool b_loop)
139 assert_locked(p_mlp);
141 /* We are entered with libvlc_media_list_lock(p_mlp->p_list) */
142 libvlc_media_list_path_t ret;
143 libvlc_media_list_t * p_parent_of_playing_item;
144 libvlc_media_list_t * p_sublist_of_playing_item;
146 if (!p_mlp->current_playing_item_path)
148 if (!libvlc_media_list_count(p_mlp->p_mlist))
149 return NULL;
150 return libvlc_media_list_path_with_root_index(0);
153 p_sublist_of_playing_item = libvlc_media_list_sublist_at_path(
154 p_mlp->p_mlist,
155 p_mlp->current_playing_item_path);
157 /* If item just gained a sublist just play it */
158 if (p_sublist_of_playing_item)
160 int i_count = libvlc_media_list_count(p_sublist_of_playing_item);
161 libvlc_media_list_release(p_sublist_of_playing_item);
162 if (i_count > 0)
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);
332 while (!mlp->dead)
334 if (mlp->seek_offset != 0)
336 set_relative_playlist_position_and_play(mlp, mlp->seek_offset);
337 mlp->seek_offset = 0;
339 vlc_cond_wait(&mlp->seek_pending, &mlp->mp_callback_lock);
342 vlc_mutex_unlock(&mlp->mp_callback_lock);
343 return NULL;
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 vlc_atomic_rc_init(&p_mlp->rc);
480 p_mlp->seek_offset = 0;
481 p_mlp->dead = false;
482 vlc_mutex_init(&p_mlp->object_lock);
483 vlc_mutex_init(&p_mlp->mp_callback_lock);
484 vlc_cond_init(&p_mlp->seek_pending);
485 libvlc_event_manager_init(&p_mlp->event_manager, p_mlp);
487 /* Create the underlying media_player */
488 p_mlp->p_mi = libvlc_media_player_new(p_instance);
489 if( p_mlp->p_mi == NULL )
490 goto error;
491 install_media_player_observer(p_mlp);
493 if (vlc_clone(&p_mlp->thread, playlist_thread, p_mlp,
494 VLC_THREAD_PRIORITY_LOW))
496 libvlc_media_player_release(p_mlp->p_mi);
497 goto error;
500 return p_mlp;
501 error:
502 libvlc_event_manager_destroy(&p_mlp->event_manager);
503 free(p_mlp);
504 return NULL;
507 /**************************************************************************
508 * release (Public)
509 **************************************************************************/
510 void libvlc_media_list_player_release(libvlc_media_list_player_t * p_mlp)
512 if (!p_mlp)
513 return;
515 if (!vlc_atomic_rc_dec(&p_mlp->rc))
516 return;
518 vlc_mutex_lock(&p_mlp->mp_callback_lock);
519 p_mlp->dead = true;
520 vlc_cond_signal(&p_mlp->seek_pending);
521 vlc_mutex_unlock(&p_mlp->mp_callback_lock);
522 vlc_join(p_mlp->thread, NULL);
524 lock(p_mlp);
525 /* Keep the lock(), because the uninstall functions
526 * check for it. That's convenient. */
527 uninstall_media_player_observer(p_mlp);
528 libvlc_media_player_release(p_mlp->p_mi);
530 if (p_mlp->p_mlist)
532 uninstall_playlist_observer(p_mlp);
533 libvlc_media_list_release(p_mlp->p_mlist);
536 unlock(p_mlp);
538 libvlc_event_manager_destroy(&p_mlp->event_manager);
539 free(p_mlp->current_playing_item_path);
540 free(p_mlp);
543 /**************************************************************************
544 * retain (Public)
545 **************************************************************************/
546 void libvlc_media_list_player_retain(libvlc_media_list_player_t * p_mlp)
548 if (!p_mlp)
549 return;
551 vlc_atomic_rc_inc(&p_mlp->rc);
554 /**************************************************************************
555 * event_manager (Public)
556 **************************************************************************/
557 libvlc_event_manager_t *
558 libvlc_media_list_player_event_manager(libvlc_media_list_player_t * p_mlp)
560 return &p_mlp->event_manager;
563 /**************************************************************************
564 * set_media_player (Public)
565 **************************************************************************/
566 void libvlc_media_list_player_set_media_player(libvlc_media_list_player_t * p_mlp, libvlc_media_player_t * p_mi)
568 libvlc_media_player_t *p_oldmi;
570 assert(p_mi != NULL);
571 libvlc_media_player_retain(p_mi);
573 lock(p_mlp);
574 uninstall_media_player_observer(p_mlp);
575 p_oldmi = p_mlp->p_mi;
576 p_mlp->p_mi = p_mi;
577 install_media_player_observer(p_mlp);
578 unlock(p_mlp);
580 libvlc_media_player_release(p_oldmi);
583 /**************************************************************************
584 * get_media_player (Public)
585 **************************************************************************/
586 libvlc_media_player_t * libvlc_media_list_player_get_media_player(libvlc_media_list_player_t * p_mlp)
588 libvlc_media_player_retain(p_mlp->p_mi);
589 return p_mlp->p_mi;
592 /**************************************************************************
593 * set_media_list (Public)
594 **************************************************************************/
595 void libvlc_media_list_player_set_media_list(libvlc_media_list_player_t * p_mlp, libvlc_media_list_t * p_mlist)
597 assert (p_mlist);
599 lock(p_mlp);
600 if (p_mlp->p_mlist)
602 uninstall_playlist_observer(p_mlp);
603 libvlc_media_list_release(p_mlp->p_mlist);
605 libvlc_media_list_retain(p_mlist);
606 p_mlp->p_mlist = p_mlist;
608 install_playlist_observer(p_mlp);
610 unlock(p_mlp);
613 /**************************************************************************
614 * Play (Public)
615 **************************************************************************/
616 void libvlc_media_list_player_play(libvlc_media_list_player_t * p_mlp)
618 lock(p_mlp);
619 if (!p_mlp->current_playing_item_path)
621 set_relative_playlist_position_and_play(p_mlp, 1);
622 unlock(p_mlp);
623 return; /* Will set to play */
625 libvlc_media_player_play(p_mlp->p_mi);
626 unlock(p_mlp);
630 /**************************************************************************
631 * Pause (Public)
632 **************************************************************************/
633 void libvlc_media_list_player_pause(libvlc_media_list_player_t * p_mlp)
635 lock(p_mlp);
636 libvlc_media_player_pause(p_mlp->p_mi);
637 unlock(p_mlp);
640 void libvlc_media_list_player_set_pause(libvlc_media_list_player_t * p_mlp,
641 int do_pause)
643 lock(p_mlp);
644 libvlc_media_player_set_pause(p_mlp->p_mi, do_pause);
645 unlock(p_mlp);
648 /**************************************************************************
649 * is_playing (Public)
650 **************************************************************************/
651 bool libvlc_media_list_player_is_playing(libvlc_media_list_player_t * p_mlp)
653 libvlc_state_t state = libvlc_media_player_get_state(p_mlp->p_mi);
654 return (state == libvlc_Opening) || (state == libvlc_Playing);
657 /**************************************************************************
658 * State (Public)
659 **************************************************************************/
660 libvlc_state_t
661 libvlc_media_list_player_get_state(libvlc_media_list_player_t * p_mlp)
663 return libvlc_media_player_get_state(p_mlp->p_mi);
666 /**************************************************************************
667 * Play item at index (Public)
668 **************************************************************************/
669 int libvlc_media_list_player_play_item_at_index(libvlc_media_list_player_t * p_mlp, int i_index)
671 lock(p_mlp);
672 libvlc_media_list_path_t path = libvlc_media_list_path_with_root_index(i_index);
673 set_current_playing_item(p_mlp, path);
674 libvlc_media_t *p_md = libvlc_media_player_get_media(p_mlp->p_mi);
675 libvlc_media_player_play(p_mlp->p_mi);
676 unlock(p_mlp);
678 if (!p_md)
679 return -1;
681 /* Send the next item event */
682 libvlc_event_t event;
683 event.type = libvlc_MediaListPlayerNextItemSet;
684 event.u.media_list_player_next_item_set.item = p_md;
685 libvlc_event_send(&p_mlp->event_manager, &event);
686 libvlc_media_release(p_md);
687 return 0;
690 /**************************************************************************
691 * Play item (Public)
692 **************************************************************************/
693 int libvlc_media_list_player_play_item(libvlc_media_list_player_t * p_mlp, libvlc_media_t * p_md)
695 lock(p_mlp);
696 libvlc_media_list_path_t path = libvlc_media_list_path_of_item(p_mlp->p_mlist, p_md);
697 if (!path)
699 libvlc_printerr("Item not found in media list");
700 unlock(p_mlp);
701 return -1;
704 set_current_playing_item(p_mlp, path);
705 libvlc_media_player_play(p_mlp->p_mi);
706 unlock(p_mlp);
707 return 0;
710 /**************************************************************************
711 * Stop (Private)
713 * Lock must be held.
714 **************************************************************************/
715 static void stop(libvlc_media_list_player_t * p_mlp)
717 assert_locked(p_mlp);
719 /* We are not interested in getting media stop event now */
720 uninstall_media_player_observer(p_mlp);
721 libvlc_media_player_stop_async(p_mlp->p_mi);
722 install_media_player_observer(p_mlp);
724 free(p_mlp->current_playing_item_path);
725 p_mlp->current_playing_item_path = NULL;
727 /* Send the event */
728 libvlc_event_t event;
729 event.type = libvlc_MediaListPlayerStopped;
730 libvlc_event_send(&p_mlp->event_manager, &event);
733 /**************************************************************************
734 * Stop (Public)
735 **************************************************************************/
736 void libvlc_media_list_player_stop_async(libvlc_media_list_player_t * p_mlp)
738 lock(p_mlp);
739 stop(p_mlp);
740 unlock(p_mlp);
743 /**************************************************************************
744 * Set relative playlist position and play (Private)
746 * Sets the currently played item to the given relative play item position
747 * (based on the currently playing item) and then begins the new item playback.
748 * Lock must be held.
749 **************************************************************************/
750 static int set_relative_playlist_position_and_play(
751 libvlc_media_list_player_t * p_mlp,
752 int i_relative_position)
754 assert_locked(p_mlp);
756 if (!p_mlp->p_mlist)
758 libvlc_printerr("No media list");
759 return -1;
762 libvlc_media_list_lock(p_mlp->p_mlist);
764 libvlc_media_list_path_t path = p_mlp->current_playing_item_path;
766 if(p_mlp->e_playback_mode != libvlc_playback_mode_repeat)
768 bool b_loop = (p_mlp->e_playback_mode == libvlc_playback_mode_loop);
770 while (i_relative_position > 0)
772 path = get_next_path(p_mlp, b_loop);
773 set_current_playing_item(p_mlp, path);
774 --i_relative_position;
777 while (i_relative_position < 0)
779 path = get_previous_path(p_mlp, b_loop);
780 set_current_playing_item(p_mlp, path);
781 ++i_relative_position;
784 else
786 set_current_playing_item(p_mlp, path);
789 #ifdef DEBUG_MEDIA_LIST_PLAYER
790 printf("Playing:");
791 libvlc_media_list_path_dump(path);
792 #endif
794 if (!path)
796 libvlc_media_list_unlock(p_mlp->p_mlist);
797 /* Send list played event */
798 libvlc_event_t event;
799 event.type = libvlc_MediaListPlayerPlayed;
800 libvlc_event_send(&p_mlp->event_manager, &event);
801 return -1;
804 libvlc_media_player_play(p_mlp->p_mi);
806 libvlc_media_list_unlock(p_mlp->p_mlist);
808 /* Send the next item event */
809 libvlc_event_t event;
810 event.type = libvlc_MediaListPlayerNextItemSet;
811 libvlc_media_t * p_md = libvlc_media_list_item_at_path(p_mlp->p_mlist, path);
812 event.u.media_list_player_next_item_set.item = p_md;
813 libvlc_event_send(&p_mlp->event_manager, &event);
814 libvlc_media_release(p_md);
815 return 0;
818 /**************************************************************************
819 * Next (Public)
820 **************************************************************************/
821 int libvlc_media_list_player_next(libvlc_media_list_player_t * p_mlp)
823 lock(p_mlp);
824 int failure = set_relative_playlist_position_and_play(p_mlp, 1);
825 unlock(p_mlp);
826 return failure;
829 /**************************************************************************
830 * Previous (Public)
831 **************************************************************************/
832 int libvlc_media_list_player_previous(libvlc_media_list_player_t * p_mlp)
834 lock(p_mlp);
835 int failure = set_relative_playlist_position_and_play(p_mlp, -1);
836 unlock(p_mlp);
837 return failure;
840 /**************************************************************************
841 * Set Playback Mode (Public)
842 **************************************************************************/
843 void libvlc_media_list_player_set_playback_mode(
844 libvlc_media_list_player_t * p_mlp,
845 libvlc_playback_mode_t e_mode )
847 lock(p_mlp);
848 p_mlp->e_playback_mode = e_mode;
849 unlock(p_mlp);