X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fplaylist%2Fengine.c;h=05ea3b11745ae36104250c64d71b05070f237217;hb=f658f93c23312ca6585ddaf06bc09cf84771187f;hp=97356896254c42aa098d96a2344019dfd45d36aa;hpb=d2ce7fe9c993e9977d242ae2fe68a1e46975d1ea;p=vlc diff --git a/src/playlist/engine.c b/src/playlist/engine.c index 9735689625..05ea3b1174 100644 --- a/src/playlist/engine.c +++ b/src/playlist/engine.c @@ -1,24 +1,24 @@ /***************************************************************************** * engine.c : Run the playlist and handle its control ***************************************************************************** - * Copyright (C) 1999-2008 the VideoLAN team + * Copyright (C) 1999-2008 VLC authors and VideoLAN * * Authors: Samuel Hocevar * Clément Stenac * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ #ifdef HAVE_CONFIG_H @@ -27,29 +27,164 @@ #include #include + #include #include #include #include +#include #include "playlist_internal.h" -#include "stream_output/stream_output.h" /* sout_DeleteInstance */ +#include "input/resource.h" /***************************************************************************** * Local prototypes *****************************************************************************/ static void VariablesInit( playlist_t *p_playlist ); -static void playlist_Destructor( vlc_object_t * p_this ); static int RandomCallback( vlc_object_t *p_this, char const *psz_cmd, vlc_value_t oldval, vlc_value_t newval, void *a ) { (void)psz_cmd; (void)oldval; (void)newval; (void)a; playlist_t *p_playlist = (playlist_t*)p_this; + bool random = newval.b_bool; PL_LOCK; - pl_priv(p_playlist)->b_reset_currently_playing = true; - vlc_object_signal_unlocked( p_playlist ); + if( !random ) { + pl_priv(p_playlist)->b_reset_currently_playing = true; + vlc_cond_signal( &pl_priv(p_playlist)->signal ); + } else { + /* Shuffle and sync the playlist on activation of random mode. + * This preserves the current playing item, so that the user + * can return to it if needed. (See #4472) + */ + playlist_private_t *p_sys = pl_priv(p_playlist); + playlist_item_t *p_new = p_sys->status.p_item; + ResetCurrentlyPlaying( p_playlist, NULL ); + if( p_new ) + ResyncCurrentIndex( p_playlist, p_new ); + } + + PL_UNLOCK; + return VLC_SUCCESS; +} + +/** + * When there are one or more pending corks, playback should be paused. + * This is used for audio policy. + * \warning Always add and remove a cork with var_IncInteger() and var_DecInteger(). + * var_Get() and var_Set() are prone to race conditions. + */ +static int CorksCallback( vlc_object_t *obj, char const *var, + vlc_value_t old, vlc_value_t cur, void *dummy ) +{ + playlist_t *pl = (playlist_t *)obj; + + msg_Dbg( obj, "corks count: %"PRId64" -> %"PRId64, old.i_int, cur.i_int ); + if( !old.i_int == !cur.i_int ) + return VLC_SUCCESS; /* nothing to do */ + + if( !var_InheritBool( obj, "playlist-cork" ) ) + return VLC_SUCCESS; + + if( cur.i_int ) + { + msg_Dbg( obj, "corked" ); + playlist_Pause( pl ); + } + else + { + msg_Dbg( obj, "uncorked" ); + playlist_Resume( pl ); + } + + (void) var; (void) dummy; + return VLC_SUCCESS; +} + +static int RateCallback( vlc_object_t *p_this, char const *psz_cmd, + vlc_value_t oldval, vlc_value_t newval, void *p ) +{ + (void)psz_cmd; (void)oldval;(void)p; + playlist_t *p_playlist = (playlist_t*)p_this; + + PL_LOCK; + + if( pl_priv(p_playlist)->p_input == NULL ) + { + PL_UNLOCK; + return VLC_SUCCESS; + } + + var_SetFloat( pl_priv( p_playlist )->p_input, "rate", newval.f_float ); + PL_UNLOCK; + return VLC_SUCCESS; +} + +static int RateOffsetCallback( vlc_object_t *obj, char const *psz_cmd, + vlc_value_t oldval, vlc_value_t newval, void *p_data ) +{ + playlist_t *p_playlist = (playlist_t *)obj; + VLC_UNUSED(oldval); VLC_UNUSED(p_data); VLC_UNUSED(newval); + + static const float pf_rate[] = { + 1.0/64, 1.0/32, 1.0/16, 1.0/8, 1.0/4, 1.0/3, 1.0/2, 2.0/3, + 1.0/1, + 3.0/2, 2.0/1, 3.0/1, 4.0/1, 8.0/1, 16.0/1, 32.0/1, 64.0/1, + }; + const size_t i_rate_count = sizeof(pf_rate)/sizeof(*pf_rate); + + float f_rate; + struct input_thread_t *input; + + PL_LOCK; + input = pl_priv( p_playlist )->p_input; + f_rate = var_GetFloat( input ? (vlc_object_t *)input : obj, "rate" ); + PL_UNLOCK; + + if( !strcmp( psz_cmd, "rate-faster" ) ) + { + /* compensate for input rounding errors */ + float r = f_rate * 1.1f; + for( size_t i = 0; i < i_rate_count; i++ ) + if( r < pf_rate[i] ) + { + f_rate = pf_rate[i]; + break; + } + } + else + { + /* compensate for input rounding errors */ + float r = f_rate * .9f; + for( size_t i = 1; i < i_rate_count; i++ ) + if( r <= pf_rate[i] ) + { + f_rate = pf_rate[i - 1]; + break; + } + } + + var_SetFloat( p_playlist, "rate", f_rate ); + return VLC_SUCCESS; +} + +static int VideoSplitterCallback( vlc_object_t *p_this, char const *psz_cmd, + vlc_value_t oldval, vlc_value_t newval, void *p_data ) +{ + playlist_t *p_playlist = (playlist_t*)p_this; + VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data); VLC_UNUSED(newval); + + PL_LOCK; + + /* Force the input to restart the video ES to force a vout recreation */ + input_thread_t *p_input = pl_priv( p_playlist )->p_input; + if( p_input ) + { + const double f_position = var_GetFloat( p_input, "position" ); + input_Control( p_input, INPUT_RESTART_ES, -VIDEO_ES ); + var_SetFloat( p_input, "position", f_position ); + } PL_UNLOCK; return VLC_SUCCESS; @@ -62,15 +197,13 @@ static int RandomCallback( vlc_object_t *p_this, char const *psz_cmd, * \param p_parent the vlc object that is to be the parent of this playlist * \return a pointer to the created playlist, or NULL on error */ -playlist_t * playlist_Create( vlc_object_t *p_parent ) +playlist_t *playlist_Create( vlc_object_t *p_parent ) { - static const char playlist_name[] = "playlist"; playlist_t *p_playlist; playlist_private_t *p; /* Allocate structure */ - p = vlc_custom_create( p_parent, sizeof( *p ), - VLC_OBJECT_GENERIC, playlist_name ); + p = vlc_custom_create( p_parent, sizeof( *p ), "playlist" ); if( !p ) return NULL; @@ -78,9 +211,10 @@ playlist_t * playlist_Create( vlc_object_t *p_parent ) p_playlist = &p->public_data; TAB_INIT( pl_priv(p_playlist)->i_sds, pl_priv(p_playlist)->pp_sds ); - libvlc_priv(p_parent->p_libvlc)->p_playlist = p_playlist; - VariablesInit( p_playlist ); + vlc_mutex_init( &p->lock ); + vlc_cond_init( &p->signal ); + p->killed = false; /* Initialise data structures */ pl_priv(p_playlist)->i_last_playlist_id = 0; @@ -93,147 +227,150 @@ playlist_t * playlist_Create( vlc_object_t *p_parent ) p_playlist->i_current_index = 0; pl_priv(p_playlist)->b_reset_currently_playing = true; - pl_priv(p_playlist)->last_rebuild_date = 0; - - pl_priv(p_playlist)->b_tree = var_CreateGetBool( p_playlist, "playlist-tree" ); - pl_priv(p_playlist)->b_doing_ml = false; + pl_priv(p_playlist)->b_tree = var_InheritBool( p_parent, "playlist-tree" ); - pl_priv(p_playlist)->b_auto_preparse = - var_CreateGetBool( p_playlist, "auto-preparse" ) ; + /* Create the root, playing items and meida library nodes */ + playlist_item_t *root, *playing, *ml; - PL_LOCK; /* playlist_NodeCreate will check for it */ - p_playlist->p_root_category = playlist_NodeCreate( p_playlist, NULL, NULL, - 0, NULL ); - p_playlist->p_root_onelevel = playlist_NodeCreate( p_playlist, NULL, NULL, - 0, p_playlist->p_root_category->p_input ); + PL_LOCK; + root = playlist_NodeCreate( p_playlist, NULL, NULL, + PLAYLIST_END, 0, NULL ); + playing = playlist_NodeCreate( p_playlist, _( "Playlist" ), root, + PLAYLIST_END, PLAYLIST_RO_FLAG, NULL ); + if( var_InheritBool( p_parent, "media-library") ) + ml = playlist_NodeCreate( p_playlist, _( "Media Library" ), root, + PLAYLIST_END, PLAYLIST_RO_FLAG, NULL ); + else + ml = NULL; PL_UNLOCK; - if( !p_playlist->p_root_category || !p_playlist->p_root_onelevel ) - return NULL; + if( unlikely(root == NULL || playing == NULL) ) + abort(); - /* Create playlist and media library */ - PL_LOCK; /* playlist_NodesPairCreate will check for it */ - playlist_NodesPairCreate( p_playlist, _( "Playlist" ), - &p_playlist->p_local_category, - &p_playlist->p_local_onelevel, false ); - PL_UNLOCK; + p_playlist->p_root = root; + p_playlist->p_playing = playing; + p_playlist->p_media_library = ml; + p_playlist->p_root_category = p_playlist->p_root; + p_playlist->p_root_onelevel = p_playlist->p_root; + p_playlist->p_local_category = p_playlist->p_playing; + p_playlist->p_local_onelevel = p_playlist->p_playing; + p_playlist->p_ml_category = p_playlist->p_media_library; + p_playlist->p_ml_onelevel = p_playlist->p_media_library;; - p_playlist->p_local_category->i_flags |= PLAYLIST_RO_FLAG; - p_playlist->p_local_onelevel->i_flags |= PLAYLIST_RO_FLAG; + /* Initial status */ + pl_priv(p_playlist)->status.p_item = NULL; + pl_priv(p_playlist)->status.p_node = p_playlist->p_playing; + pl_priv(p_playlist)->request.b_request = false; - if( !p_playlist->p_local_category || !p_playlist->p_local_onelevel || - !p_playlist->p_local_category->p_input || - !p_playlist->p_local_onelevel->p_input ) - return NULL; + if (ml != NULL) + playlist_MLLoad( p_playlist ); - if( config_GetInt( p_playlist, "media-library") ) + /* Preparser (and meta retriever) _after_ the Media Library*/ + if( var_InheritBool( p_parent, "auto-preparse" ) ) { - PL_LOCK; /* playlist_NodesPairCreate will check for it */ - playlist_NodesPairCreate( p_playlist, _( "Media Library" ), - &p_playlist->p_ml_category, - &p_playlist->p_ml_onelevel, false ); - PL_UNLOCK; + p->p_preparser = playlist_preparser_New( VLC_OBJECT(p_playlist) ); + if( unlikely(p->p_preparser == NULL) ) + msg_Err( p_playlist, "cannot create preparser" ); + } - if(!p_playlist->p_ml_category || !p_playlist->p_ml_onelevel) - return NULL; + /* Input resources */ + p->p_input_resource = input_resource_New( VLC_OBJECT( p_playlist ) ); + if( unlikely(p->p_input_resource == NULL) ) + abort(); - p_playlist->p_ml_category->i_flags |= PLAYLIST_RO_FLAG; - p_playlist->p_ml_onelevel->i_flags |= PLAYLIST_RO_FLAG; - } - else + /* Audio output (needed for volume and device controls). */ + audio_output_t *aout = input_resource_GetAout( p->p_input_resource ); + if( aout != NULL ) + input_resource_PutAout( p->p_input_resource, aout ); + + /* Initialize the shared HTTP cookie jar */ + vlc_value_t cookies; + cookies.p_address = vlc_http_cookies_new(); + if ( likely(cookies.p_address) ) { - p_playlist->p_ml_category = p_playlist->p_ml_onelevel = NULL; + var_Create( p_playlist, "http-cookies", VLC_VAR_ADDRESS ); + var_SetChecked( p_playlist, "http-cookies", VLC_VAR_ADDRESS, cookies ); } - /* Initial status */ - pl_priv(p_playlist)->status.p_item = NULL; - pl_priv(p_playlist)->status.p_node = p_playlist->p_local_onelevel; - pl_priv(p_playlist)->request.b_request = false; - pl_priv(p_playlist)->status.i_status = PLAYLIST_STOPPED; + /* Thread */ + playlist_Activate (p_playlist); - pl_priv(p_playlist)->b_auto_preparse = false; - playlist_MLLoad( p_playlist ); - pl_priv(p_playlist)->b_auto_preparse = true; - - vlc_object_set_destructor( p_playlist, playlist_Destructor ); + /* Add service discovery modules */ + char *mods = var_InheritString( p_playlist, "services-discovery" ); + if( mods != NULL ) + { + char *s = mods, *m; + while( (m = strsep( &s, " :," )) != NULL ) + playlist_ServicesDiscoveryAdd( p_playlist, m ); + free( mods ); + } return p_playlist; } /** - * Destroy playlist + * Destroy playlist. + * This is not thread-safe. Any reference to the playlist is assumed gone. + * (In particular, all interface and services threads must have been joined). * - * Destroy a playlist structure. * \param p_playlist the playlist object - * \return nothing */ - -static void playlist_Destructor( vlc_object_t * p_this ) +void playlist_Destroy( playlist_t *p_playlist ) { - playlist_t *p_playlist = (playlist_t *)p_this; playlist_private_t *p_sys = pl_priv(p_playlist); - assert( !p_sys->p_sout ); - assert( !p_sys->p_preparser ); - assert( !p_sys->p_fetcher ); + /* Remove all services discovery */ + playlist_ServicesDiscoveryKillAll( p_playlist ); - msg_Err( p_this, "Destroyed" ); -} + msg_Dbg( p_playlist, "destroying" ); -/* Input Callback */ -static int InputEvent( vlc_object_t *p_this, char const *psz_cmd, - vlc_value_t oldval, vlc_value_t newval, void *p_data ) -{ - VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); - playlist_t *p_playlist = p_data; - - if( newval.i_int != INPUT_EVENT_STATE && - newval.i_int != INPUT_EVENT_ES ) - return VLC_SUCCESS; + playlist_Deactivate( p_playlist ); + if( p_sys->p_preparser ) + playlist_preparser_Delete( p_sys->p_preparser ); - PL_LOCK; + /* Release input resources */ + assert( p_sys->p_input == NULL ); + input_resource_Release( p_sys->p_input_resource ); - vlc_object_signal_unlocked( p_playlist ); + if( p_playlist->p_media_library != NULL ) + playlist_MLDump( p_playlist ); - PL_UNLOCK; - return VLC_SUCCESS; -} - -/* Internals */ -void playlist_release_current_input( playlist_t * p_playlist ) -{ - PL_ASSERT_LOCKED; - - if( !pl_priv(p_playlist)->p_input ) return; - - input_thread_t * p_input = pl_priv(p_playlist)->p_input; - - var_DelCallback( p_input, "intf-event", InputEvent, p_playlist ); - pl_priv(p_playlist)->p_input = NULL; - - /* Release the playlist lock, because we may get stuck - * in vlc_object_release() for some time. */ - PL_UNLOCK; - vlc_thread_join( p_input ); - vlc_object_release( p_input ); PL_LOCK; -} - -void playlist_set_current_input( - playlist_t * p_playlist, input_thread_t * p_input ) -{ - PL_ASSERT_LOCKED; - - playlist_release_current_input( p_playlist ); + /* Release the current node */ + set_current_status_node( p_playlist, NULL ); + /* Release the current item */ + set_current_status_item( p_playlist, NULL ); + PL_UNLOCK; - if( p_input ) + vlc_cond_destroy( &p_sys->signal ); + vlc_mutex_destroy( &p_sys->lock ); + + /* Remove all remaining items */ + FOREACH_ARRAY( playlist_item_t *p_del, p_playlist->all_items ) + free( p_del->pp_children ); + vlc_gc_decref( p_del->p_input ); + free( p_del ); + FOREACH_END(); + ARRAY_RESET( p_playlist->all_items ); + FOREACH_ARRAY( playlist_item_t *p_del, p_sys->items_to_delete ) + free( p_del->pp_children ); + vlc_gc_decref( p_del->p_input ); + free( p_del ); + FOREACH_END(); + ARRAY_RESET( p_sys->items_to_delete ); + + ARRAY_RESET( p_playlist->items ); + ARRAY_RESET( p_playlist->current ); + + vlc_http_cookie_jar_t *cookies = var_GetAddress( p_playlist, "http-cookies" ); + if ( cookies ) { - vlc_object_hold( p_input ); - pl_priv(p_playlist)->p_input = p_input; - - var_AddCallback( p_input, "intf-event", InputEvent, p_playlist ); + var_Destroy( p_playlist, "http-cookies" ); + vlc_http_cookies_destroy( cookies ); } + + vlc_object_release( p_playlist ); } /** Get current playing input. @@ -298,171 +435,75 @@ void set_current_status_node( playlist_t * p_playlist, pl_priv(p_playlist)->status.p_node = p_node; } -/** - * Main loop - * - * Main loop for the playlist. It should be entered with the - * playlist lock (otherwise input event may be lost) - * \param p_playlist the playlist object - * \return nothing - */ -void playlist_MainLoop( playlist_t *p_playlist ) -{ - bool b_playexit = var_GetBool( p_playlist, "play-and-exit" ); - - PL_ASSERT_LOCKED; - - if( pl_priv(p_playlist)->b_reset_currently_playing && - mdate() - pl_priv(p_playlist)->last_rebuild_date > 30000 ) // 30 ms - { - ResetCurrentlyPlaying( p_playlist, var_GetBool( p_playlist, "random" ), - get_current_status_item( p_playlist ) ); - pl_priv(p_playlist)->last_rebuild_date = mdate(); - } - -check_input: - /* If there is an input, check that it doesn't need to die. */ - if( pl_priv(p_playlist)->p_input ) - { - input_thread_t *p_input = pl_priv(p_playlist)->p_input; - - if( pl_priv(p_playlist)->request.b_request && !p_input->b_die ) - { - PL_DEBUG( "incoming request - stopping current input" ); - input_StopThread( p_input ); - } - - /* This input is dead. Remove it ! */ - if( p_input->b_dead ) - { - sout_instance_t **pp_sout = &pl_priv(p_playlist)->p_sout; - - PL_DEBUG( "dead input" ); - - assert( *pp_sout == NULL ); - if( var_CreateGetBool( p_input, "sout-keep" ) ) - *pp_sout = input_DetachSout( p_input ); - - /* Destroy input */ - playlist_release_current_input( p_playlist ); - - int i_activity= var_GetInteger( p_playlist, "activity" ); - var_SetInteger( p_playlist, "activity", - i_activity - DEFAULT_INPUT_ACTIVITY ); - goto check_input; - } - /* This input is dying, let it do */ - else if( p_input->b_die ) - { - PL_DEBUG( "dying input" ); - PL_UNLOCK; - msleep( INTF_IDLE_SLEEP ); - PL_LOCK; - goto check_input; - } - /* This input has finished, ask it to die ! */ - else if( p_input->b_error || p_input->b_eof ) - { - PL_DEBUG( "finished input" ); - input_StopThread( p_input ); - /* No need to wait here, we'll wait in the p_input->b_die case */ - goto check_input; - } - } - else - { - /* 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 - */ - int i_status = pl_priv(p_playlist)->request.b_request ? - pl_priv(p_playlist)->request.i_status : pl_priv(p_playlist)->status.i_status; - if( i_status != PLAYLIST_STOPPED ) - { - msg_Dbg( p_playlist, "starting new item" ); - playlist_item_t *p_item = playlist_NextItem( p_playlist ); - - if( p_item == NULL ) - { - msg_Dbg( p_playlist, "nothing to play" ); - pl_priv(p_playlist)->status.i_status = PLAYLIST_STOPPED; - - if( b_playexit == true ) - { - msg_Info( p_playlist, "end of playlist, exiting" ); - vlc_object_kill( p_playlist->p_libvlc ); - } - return; - } - playlist_PlayItem( p_playlist, p_item ); - /* playlist_PlayItem loose input event, we need to recheck */ - goto check_input; - } - else - { - pl_priv(p_playlist)->status.i_status = PLAYLIST_STOPPED; - } - } -} - static void VariablesInit( playlist_t *p_playlist ) { - vlc_value_t val; /* These variables control updates */ var_Create( p_playlist, "intf-change", VLC_VAR_BOOL ); - val.b_bool = true; - var_Set( p_playlist, "intf-change", val ); + var_SetBool( p_playlist, "intf-change", true ); - var_Create( p_playlist, "item-change", VLC_VAR_INTEGER ); - val.i_int = -1; - var_Set( p_playlist, "item-change", val ); + var_Create( p_playlist, "item-change", VLC_VAR_ADDRESS ); + var_Create( p_playlist, "leaf-to-parent", VLC_VAR_INTEGER ); - var_Create( p_playlist, "item-deleted", VLC_VAR_INTEGER ); - val.i_int = -1; - var_Set( p_playlist, "item-deleted", val ); + var_Create( p_playlist, "playlist-item-deleted", VLC_VAR_INTEGER ); + var_SetInteger( p_playlist, "playlist-item-deleted", -1 ); - var_Create( p_playlist, "item-append", VLC_VAR_ADDRESS ); + var_Create( p_playlist, "playlist-item-append", VLC_VAR_ADDRESS ); - var_Create( p_playlist, "playlist-current", VLC_VAR_INTEGER ); - val.i_int = -1; - var_Set( p_playlist, "playlist-current", val ); + var_Create( p_playlist, "input-current", VLC_VAR_ADDRESS ); - var_Create( p_playlist, "activity", VLC_VAR_INTEGER ); - var_SetInteger( p_playlist, "activity", 0 ); + var_Create( p_playlist, "activity", VLC_VAR_VOID ); /* Variables to control playback */ - var_Create( p_playlist, "play-and-stop", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); - var_Create( p_playlist, "play-and-exit", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); + var_Create( p_playlist, "playlist-autostart", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); var_Create( p_playlist, "random", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); + var_AddCallback( p_playlist, "random", RandomCallback, NULL ); var_Create( p_playlist, "repeat", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); var_Create( p_playlist, "loop", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); + var_Create( p_playlist, "corks", VLC_VAR_INTEGER ); + var_AddCallback( p_playlist, "corks", CorksCallback, NULL ); - var_AddCallback( p_playlist, "random", RandomCallback, NULL ); + var_Create( p_playlist, "rate", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT ); + var_AddCallback( p_playlist, "rate", RateCallback, NULL ); + var_Create( p_playlist, "rate-slower", VLC_VAR_VOID ); + var_AddCallback( p_playlist, "rate-slower", RateOffsetCallback, NULL ); + var_Create( p_playlist, "rate-faster", VLC_VAR_VOID ); + var_AddCallback( p_playlist, "rate-faster", RateOffsetCallback, NULL ); + + var_Create( p_playlist, "video-splitter", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); + var_AddCallback( p_playlist, "video-splitter", VideoSplitterCallback, NULL ); /* */ var_Create( p_playlist, "album-art", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); -} - -int playlist_CurrentId( playlist_t * p_playlist ) -{ - return pl_priv(p_playlist)->status.p_item->i_id; + var_Create( p_playlist, "metadata-network-access", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); -} + /* Variables to preserve video output parameters */ + var_Create( p_playlist, "fullscreen", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); + var_Create( p_playlist, "video-on-top", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); + var_Create( p_playlist, "video-wallpaper", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); -bool playlist_IsPlaying( playlist_t * p_playlist ) -{ - return ( pl_priv(p_playlist)->status.i_status == PLAYLIST_RUNNING && - !(pl_priv(p_playlist)->request.b_request && pl_priv(p_playlist)->request.i_status == PLAYLIST_STOPPED) ); + /* Audio output parameters */ + var_Create( p_playlist, "mute", VLC_VAR_BOOL ); + var_Create( p_playlist, "volume", VLC_VAR_FLOAT ); + var_SetFloat( p_playlist, "volume", -1.f ); } playlist_item_t * playlist_CurrentPlayingItem( playlist_t * p_playlist ) { + PL_ASSERT_LOCKED; + return pl_priv(p_playlist)->status.p_item; } int playlist_Status( playlist_t * p_playlist ) { - return pl_priv(p_playlist)->status.i_status; + input_thread_t *p_input = pl_priv(p_playlist)->p_input; + + PL_ASSERT_LOCKED; + + if( p_input == NULL ) + return PLAYLIST_STOPPED; + if( var_GetInteger( p_input, "state" ) == PAUSE_S ) + return PLAYLIST_PAUSED; + return PLAYLIST_RUNNING; } +