#include <vlc_interface.h>
#include <vlc_playlist.h>
#include <vlc_rand.h>
-#include "stream_output/stream_output.h"
#include "playlist_internal.h"
/*****************************************************************************
*****************************************************************************/
/**
- * Create the main playlist threads.
- * Additionally to the playlist, this thread controls :
- * - Statistics
- * - VLM
- * \param p_parent
- * \return an object with a started thread
+ * Creates the main playlist thread.
*/
void playlist_Activate( playlist_t *p_playlist )
{
- /* */
playlist_private_t *p_sys = pl_priv(p_playlist);
- p_sys->p_input_resource = input_resource_New( VLC_OBJECT( p_playlist ) );
- if( unlikely(p_sys->p_input_resource == NULL) )
- abort();
-
- /* Start the playlist thread */
if( vlc_clone( &p_sys->thread, Thread, p_playlist,
VLC_THREAD_PRIORITY_LOW ) )
{
msg_Err( p_playlist, "cannot spawn playlist thread" );
+ abort();
}
- msg_Dbg( p_playlist, "playlist threads correctly activated" );
}
/**
{
playlist_private_t *p_sys = pl_priv(p_playlist);
- if( p_sys->p_input_resource == NULL )
- return; /* playlist was never activated... */
-
PL_LOCK;
/* WARNING: There is a latent bug. It is assumed that only one thread will
* be waiting for playlist deactivation at a time. So far, that works
*
* \param p_playlist the playlist object
* \param p_item the item to play
- * \return nothing
*/
-static int PlayItem( playlist_t *p_playlist, playlist_item_t *p_item )
+static bool PlayItem( playlist_t *p_playlist, playlist_item_t *p_item )
{
playlist_private_t *p_sys = pl_priv(p_playlist);
input_item_t *p_input = p_item->p_input;
msg_Dbg( p_playlist, "creating new input thread" );
- p_input->i_nb_played++;
+ p_item->i_nb_played++;
set_current_status_item( p_playlist, p_item );
-
- p_sys->status.i_status = PLAYLIST_RUNNING;
-
assert( p_sys->p_input == NULL );
+ PL_UNLOCK;
- input_thread_t *p_input_thread = input_Create( p_playlist, p_input, NULL, p_sys->p_input_resource );
- if( p_input_thread )
+ input_thread_t *p_input_thread = input_Create( p_playlist, p_input, NULL,
+ p_sys->p_input_resource );
+ if( likely(p_input_thread != NULL) )
{
- p_sys->p_input = p_input_thread;
- var_AddCallback( p_input_thread, "intf-event", InputEvent, p_playlist );
-
- var_SetAddress( p_playlist, "input-current", p_input_thread );
+ var_AddCallback( p_input_thread, "intf-event",
+ InputEvent, p_playlist );
- if( input_Start( p_sys->p_input ) )
+ if( input_Start( p_input_thread ) )
{
+ var_DelCallback( p_input_thread, "intf-event",
+ InputEvent, p_playlist );
vlc_object_release( p_input_thread );
- p_sys->p_input = p_input_thread = NULL;
+ p_input_thread = NULL;
}
}
- bool b_find_art = var_GetInteger( p_playlist, "album-art" )
- == ALBUM_ART_WHEN_PLAYED;
- if( b_find_art )
- {
- char *psz_uri = input_item_GetURI( p_item->p_input );
- if( psz_uri != NULL && (!strncmp( psz_uri, "directory:", 10 ) ||
- !strncmp( psz_uri, "vlc:", 4 )) )
- b_find_art = false;
- free( psz_uri );
- }
+ var_SetAddress( p_playlist, "input-current", p_input_thread );
/* TODO store art policy in playlist private data */
- if( b_find_art )
- {
- char *psz_arturl = input_item_GetArtURL( p_input );
- char *psz_name = input_item_GetName( p_input );
- /* p_input->p_meta should not be null after a successful CreateThread */
- bool b_has_art = !EMPTY_STR( psz_arturl );
+ char *psz_arturl = input_item_GetArtURL( p_input );
+ /* p_input->p_meta should not be null after a successful CreateThread */
+ bool b_has_art = !EMPTY_STR( psz_arturl );
- if( !b_has_art || strncmp( psz_arturl, "attachment://", 13 ) )
- {
- PL_DEBUG( "requesting art for %s", psz_name );
- playlist_AskForArtEnqueue( p_playlist, p_input );
- }
- free( psz_arturl );
- free( psz_name );
+ if( !b_has_art || strncmp( psz_arturl, "attachment://", 13 ) )
+ {
+ PL_DEBUG( "requesting art for new input thread" );
+ libvlc_ArtRequest( p_playlist->p_libvlc, p_input, META_REQUEST_OPTION_NONE );
}
+ free( psz_arturl );
+
+ PL_LOCK;
+ p_sys->p_input = p_input_thread;
PL_UNLOCK;
+
var_TriggerCallback( p_playlist, "activity" );
- PL_LOCK;
- return VLC_SUCCESS;
+ PL_LOCK;
+ return p_input_thread != NULL;
}
/**
{
playlist_private_t *p_sys = pl_priv(p_playlist);
playlist_item_t *p_new = NULL;
+ bool requested = p_sys->request.b_request;
+
+ /* Clear the request */
+ p_sys->request.b_request = false;
/* Handle quickly a few special cases */
/* No items to play */
}
/* Start the real work */
- if( p_sys->request.b_request )
+ if( requested )
{
p_new = p_sys->request.p_item;
+
+ if( p_new == NULL && p_sys->request.p_node == NULL )
+ return NULL; /* Stop request! */
+
int i_skip = p_sys->request.i_skip;
PL_DEBUG( "processing request item: %s, node: %s, skip: %i",
PLI_NAME( p_sys->request.p_item ),
if( p_playlist->i_current_index >= p_playlist->current.i_size )
{
PL_DEBUG( "looping - restarting at beginning of node" );
+ /* reshuffle playlist when end is reached */
+ if( var_GetBool( p_playlist, "random" ) ) {
+ PL_DEBUG( "reshuffle playlist" );
+ ResetCurrentlyPlaying( p_playlist,
+ get_current_status_item( p_playlist ) );
+ }
p_playlist->i_current_index = 0;
}
}
if( p_playlist->i_current_index <= -1 )
{
PL_DEBUG( "looping - restarting at end of node" );
+ /* reshuffle playlist when beginning is reached */
+ if( var_GetBool( p_playlist, "random" ) ) {
+ PL_DEBUG( "reshuffle playlist" );
+ ResetCurrentlyPlaying( p_playlist,
+ get_current_status_item( p_playlist ) );
+ }
p_playlist->i_current_index = p_playlist->current.i_size-1;
}
}
p_new = ARRAY_VAL( p_playlist->current,
p_playlist->i_current_index );
}
- /* Clear the request */
- p_sys->request.b_request = false;
}
/* "Automatic" item change ( next ) */
else
{
bool b_loop = var_GetBool( p_playlist, "loop" );
bool b_repeat = var_GetBool( p_playlist, "repeat" );
- bool b_playstop = var_GetBool( p_playlist, "play-and-stop" );
+ bool b_playstop = var_InheritBool( p_playlist, "play-and-stop" );
/* Repeat and play/stop */
if( b_repeat && get_current_status_item( p_playlist ) )
{
if( !b_loop || p_playlist->current.i_size == 0 )
return NULL;
+ /* reshuffle after last item has been played */
+ if( var_GetBool( p_playlist, "random" ) ) {
+ PL_DEBUG( "reshuffle playlist" );
+ ResetCurrentlyPlaying( p_playlist,
+ get_current_status_item( p_playlist ) );
+ }
p_playlist->i_current_index = 0;
}
PL_DEBUG( "using item %i", p_playlist->i_current_index );
if( p_sys->request.b_request || p_sys->killed )
{
PL_DEBUG( "incoming request - stopping current input" );
- input_Stop( p_input, true );
+ input_Stop( p_input );
}
#warning Unsynchronized access to *p_input flags...
PL_DEBUG( "dead input" );
PL_UNLOCK;
+ var_SetAddress( p_playlist, "input-current", NULL );
+
/* WARNING: Input resource manipulation and callback deletion are
* incompatible with the playlist lock. */
if( !var_InheritBool( p_input, "sout-keep" ) )
else if( p_input->b_error || p_input->b_eof )
{
PL_DEBUG( "finished input" );
- input_Stop( p_input, false );
+ input_Stop( p_input );
}
vlc_cond_wait( &p_sys->signal, &p_sys->lock );
}
-static void LoopRequest( playlist_t *p_playlist, int i_status )
+static bool Next( playlist_t *p_playlist )
{
- playlist_private_t *p_sys = pl_priv(p_playlist);
- assert( !p_sys->p_input );
-
- /* No input. Several cases
- * - No request, running status -> start new item
- * - No request, stopped status -> collect garbage
- * - Request, running requested -> start new item
- * - Request, stopped requested -> collect garbage
- */
- if( i_status == PLAYLIST_STOPPED )
- {
- p_sys->status.i_status = PLAYLIST_STOPPED;
- vlc_cond_wait( &p_sys->signal, &p_sys->lock );
- return;
- }
-
playlist_item_t *p_item = NextItem( p_playlist );
- if( p_item )
- {
- msg_Dbg( p_playlist, "starting playback of the new playlist item" );
- ResyncCurrentIndex( p_playlist, p_item );
- PlayItem( p_playlist, p_item );
- return;
- }
-
- msg_Dbg( p_playlist, "nothing to play" );
- p_sys->status.i_status = PLAYLIST_STOPPED;
+ if( p_item == NULL )
+ return false;
- if( var_GetBool( p_playlist, "play-and-exit" ) )
- {
- msg_Info( p_playlist, "end of playlist, exiting" );
- libvlc_Quit( p_playlist->p_libvlc );
- }
+ msg_Dbg( p_playlist, "starting playback of new item" );
+ ResyncCurrentIndex( p_playlist, p_item );
+ return PlayItem( p_playlist, p_item );
}
/**
playlist_t *p_playlist = data;
playlist_private_t *p_sys = pl_priv(p_playlist);
- playlist_Lock( p_playlist );
- for( ;; )
+ PL_LOCK;
+ while( !p_sys->killed )
{
- while( p_sys->p_input != NULL )
- LoopInput( p_playlist );
+ /* Playlist in stopped state */
+ assert(p_sys->p_input == NULL);
+
+ if( !p_sys->request.b_request )
+ {
+ vlc_cond_wait( &p_sys->signal, &p_sys->lock );
+ continue;
+ }
- if( p_sys->killed )
- break; /* THE END */
+ while( !p_sys->killed && Next( p_playlist ) )
+ { /* Playlist in running state */
+ assert(p_sys->p_input != NULL);
- const int status = p_sys->request.b_request ?
- p_sys->request.i_status : p_sys->status.i_status;
+ do
+ LoopInput( p_playlist );
+ while( p_sys->p_input != NULL );
+ }
+
+ msg_Dbg( p_playlist, "nothing to play" );
+ if( var_InheritBool( p_playlist, "play-and-exit" ) )
+ {
+ msg_Info( p_playlist, "end of playlist, exiting" );
+ libvlc_Quit( p_playlist->p_libvlc );
+ }
- /* Destroy any video display if the playlist is supposed to stop */
- if( status == PLAYLIST_STOPPED
- && input_resource_HasVout( p_sys->p_input_resource ) )
+ /* Destroy any video display now (XXX: ugly hack) */
+ if( input_resource_HasVout( p_sys->p_input_resource ) )
{
PL_UNLOCK; /* Mind: NO LOCKS while manipulating input resources! */
input_resource_TerminateVout( p_sys->p_input_resource );
PL_LOCK;
- continue; /* lost lock = lost state */
}
-
- LoopRequest( p_playlist, status );
}
- p_sys->status.i_status = PLAYLIST_STOPPED;
- playlist_Unlock( p_playlist );
+ PL_UNLOCK;
input_resource_Terminate( p_sys->p_input_resource );
return NULL;