X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fplaylist%2Fthread.c;h=12a452d67cf247e243b78baeadc0a488efe40687;hb=f658f93c23312ca6585ddaf06bc09cf84771187f;hp=5f22924ed4a1d4f7058f1a0eca6fe4eb4c922597;hpb=d32dc564a1639b2750100020421f9cb38032978b;p=vlc diff --git a/src/playlist/thread.c b/src/playlist/thread.c index 5f22924ed4..12a452d67c 100644 --- a/src/playlist/thread.c +++ b/src/playlist/thread.c @@ -33,7 +33,6 @@ #include #include #include -#include "stream_output/stream_output.h" #include "playlist_internal.h" /***************************************************************************** @@ -46,29 +45,18 @@ static void *Thread ( void * ); *****************************************************************************/ /** - * 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" ); } /** @@ -80,9 +68,6 @@ void playlist_Deactivate( playlist_t *p_playlist ) { 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 @@ -205,9 +190,8 @@ void ResetCurrentlyPlaying( playlist_t *p_playlist, * * \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; @@ -216,60 +200,49 @@ static int PlayItem( playlist_t *p_playlist, playlist_item_t *p_item ) 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; } /** @@ -283,6 +256,10 @@ static playlist_item_t *NextItem( playlist_t *p_playlist ) { 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 */ @@ -293,9 +270,13 @@ static playlist_item_t *NextItem( playlist_t *p_playlist ) } /* 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 ), @@ -346,6 +327,12 @@ static playlist_item_t *NextItem( playlist_t *p_playlist ) 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; } } @@ -360,21 +347,25 @@ static playlist_item_t *NextItem( playlist_t *p_playlist ) 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 ) ) @@ -420,6 +411,12 @@ static playlist_item_t *NextItem( playlist_t *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 ); @@ -444,7 +441,7 @@ static void LoopInput( playlist_t *p_playlist ) 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... @@ -455,6 +452,8 @@ static void LoopInput( playlist_t *p_playlist ) 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" ) ) @@ -470,47 +469,21 @@ static void LoopInput( playlist_t *p_playlist ) 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 ); } /** @@ -521,32 +494,43 @@ static void *Thread ( void *data ) 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;