*****************************************************************************/
static void VariablesInit( playlist_t *p_playlist );
+static int RandomCallback( vlc_object_t *p_this, char const *psz_cmd,
+ vlc_value_t oldval, vlc_value_t newval, void *a )
+{
+ ((playlist_t*)p_this)->b_reset_currently_playing = VLC_TRUE;
+ playlist_Signal( ((playlist_t*)p_this) );
+ return VLC_SUCCESS;
+}
+
/**
* Create playlist
*
p_playlist->i_last_input_id = 0;
p_playlist->p_input = NULL;
- p_playlist->i_vout_destroyed_date = 0;
- p_playlist->i_sout_destroyed_date = 0;
+ p_playlist->gc_date = 0;
+ p_playlist->b_cant_sleep = VLC_FALSE;
- p_playlist->i_size = 0;
- p_playlist->pp_items = NULL;
- p_playlist->i_all_size = 0;
- p_playlist->pp_all_items = NULL;
+ ARRAY_INIT( p_playlist->items );
+ ARRAY_INIT( p_playlist->all_items );
+ ARRAY_INIT( p_playlist->input_items );
+ ARRAY_INIT( p_playlist->current );
- p_playlist->i_input_items = 0;
- p_playlist->pp_input_items = NULL;
-
- p_playlist->i_random = 0;
- p_playlist->pp_random = NULL;
- p_playlist->i_random_index = 0;
- p_playlist->b_reset_random = VLC_TRUE;
+ p_playlist->i_current_index = 0;
+ p_playlist->b_reset_currently_playing = VLC_TRUE;
+ p_playlist->last_rebuild_date = 0;
i_tree = var_CreateGetBool( p_playlist, "playlist-tree" );
p_playlist->b_always_tree = (i_tree == 1);
var_Destroy( p_playlist, "activity" );
PL_LOCK;
- playlist_NodeDelete( p_playlist, p_playlist->p_root_category, VLC_TRUE,
- VLC_TRUE );
- playlist_NodeDelete( p_playlist, p_playlist->p_root_onelevel, VLC_TRUE,
- VLC_TRUE );
+ /* Go through all items, and simply free everything without caring
+ * about the tree structure. Do not decref, it will be done by doing
+ * the same thing on the input items array */
+ FOREACH_ARRAY( playlist_item_t *p_del, p_playlist->all_items )
+ free( p_del->pp_children );
+ free( p_del );
+ FOREACH_END();
+ ARRAY_RESET( p_playlist->all_items );
+
+ FOREACH_ARRAY( input_item_t *p_del, p_playlist->input_items )
+ input_ItemClean( p_del );
+ free( p_del );
+ FOREACH_END();
+ ARRAY_RESET( p_playlist->input_items );
+
+ ARRAY_RESET( p_playlist->items );
+ ARRAY_RESET( p_playlist->current );
+
PL_UNLOCK;
if( p_playlist->p_stats )
vlc_object_destroy( p_playlist );
}
+
/* Destroy remaining objects */
-static mtime_t ObjectGarbageCollector( playlist_t *p_playlist, int i_type,
- mtime_t destroy_date )
+static void ObjectGarbageCollector( playlist_t *p_playlist )
{
vlc_object_t *p_obj;
- if( destroy_date > mdate() ) return destroy_date;
+ if( mdate() - p_playlist->gc_date < 1000000 )
+ {
+ p_playlist->b_cant_sleep = VLC_TRUE;
+ return;
+ }
+ else if( p_playlist->gc_date == 0 )
+ return;
- if( destroy_date == 0 )
+ vlc_mutex_lock( &p_playlist->gc_lock );
+ while( ( p_obj = vlc_object_find( p_playlist, VLC_OBJECT_VOUT,
+ FIND_CHILD ) ) )
{
- /* give a little time */
- return mdate() + I64C(1000000);
+ if( p_obj->p_parent != (vlc_object_t*)p_playlist )
+ {
+ vlc_object_release( p_obj );
+ break;
+ }
+ msg_Dbg( p_playlist, "garbage collector destroying 1 vout" );
+ vlc_object_detach( p_obj );
+ vlc_object_release( p_obj );
+ vout_Destroy( (vout_thread_t *)p_obj );
}
- else
+ while( ( p_obj = vlc_object_find( p_playlist, VLC_OBJECT_SOUT,
+ FIND_CHILD ) ) )
{
- vlc_mutex_lock( &p_playlist->gc_lock );
- while( ( p_obj = vlc_object_find( p_playlist, i_type, FIND_CHILD ) ) )
+ if( p_obj->p_parent != (vlc_object_t*)p_playlist )
{
- if( p_obj->p_parent != (vlc_object_t*)p_playlist )
- {
- /* only first child (ie unused) */
- vlc_object_release( p_obj );
- break;
- }
- if( i_type == VLC_OBJECT_VOUT )
- {
- msg_Dbg( p_playlist, "garbage collector destroying 1 vout" );
- vlc_object_detach( p_obj );
- vlc_object_release( p_obj );
- vout_Destroy( (vout_thread_t *)p_obj );
- }
- else if( i_type == VLC_OBJECT_SOUT )
- {
- vlc_object_release( p_obj );
- sout_DeleteInstance( (sout_instance_t*)p_obj );
- }
+ vlc_object_release( p_obj );
+ break;
}
- vlc_mutex_unlock( &p_playlist->gc_lock );
- return 0;
+ vlc_object_release( p_obj );
+ sout_DeleteInstance( (sout_instance_t*)p_obj );
}
+ p_playlist->b_cant_sleep = VLC_FALSE;
+ vlc_mutex_unlock( &p_playlist->gc_lock );
}
/** Main loop for the playlist */
{
playlist_item_t *p_item = NULL;
vlc_bool_t b_playexit = var_GetBool( p_playlist, "play-and-exit" );
- PL_LOCK
+ PL_LOCK;
- /* First, check if we have something to do */
- /* FIXME : this can be called several times */
- if( p_playlist->request.b_request )
+ if( p_playlist->b_reset_currently_playing &&
+ mdate() - p_playlist->last_rebuild_date > 30000 ) // 30 ms
{
- /* Stop the existing input */
- if( p_playlist->p_input && !p_playlist->p_input->b_die )
- {
- PL_DEBUG( "incoming request - stopping current input" );
- input_StopThread( p_playlist->p_input );
- }
+ ResetCurrentlyPlaying( p_playlist, var_GetBool( p_playlist, "random"),
+ p_playlist->status.p_item );
+ p_playlist->last_rebuild_date = mdate();
}
+check_input:
/* If there is an input, check that it doesn't need to die. */
if( p_playlist->p_input )
{
+ if( p_playlist->request.b_request && !p_playlist->p_input->b_die )
+ {
+ PL_DEBUG( "incoming request - stopping current input" );
+ input_StopThread( p_playlist->p_input );
+ }
+
/* This input is dead. Remove it ! */
if( p_playlist->p_input->b_dead )
{
/* Destroy object */
vlc_object_destroy( p_input );
- p_playlist->i_vout_destroyed_date = 0;
- p_playlist->i_sout_destroyed_date = 0;
+ PL_LOCK;
+
+ p_playlist->gc_date = mdate();
+ p_playlist->b_cant_sleep = VLC_TRUE;
if( p_playlist->status.p_item->i_flags
& PLAYLIST_REMOVE_FLAG )
i_activity= var_GetInteger( p_playlist, "activity") ;
var_SetInteger( p_playlist, "activity", i_activity -
DEFAULT_INPUT_ACTIVITY );
-
- return;
+ goto check_input;
}
/* This input is dying, let it do */
else if( p_playlist->p_input->b_die )
{
PL_DEBUG( "dying input" );
+ msleep( 25000 ); // 25 ms
+ goto check_input;
}
/* This input has finished, ask it to die ! */
else if( p_playlist->p_input->b_error
{
PL_DEBUG( "finished input" );
input_StopThread( p_playlist->p_input );
- /* Select the next playlist item */
- PL_UNLOCK
- return;
+ /* No need to wait here, we'll wait in the p_input->b_die case */
+ goto check_input;
}
else if( p_playlist->p_input->i_state != INIT_S )
{
PL_UNLOCK;
- p_playlist->i_vout_destroyed_date =
- ObjectGarbageCollector( p_playlist, VLC_OBJECT_VOUT,
- p_playlist->i_vout_destroyed_date );
- p_playlist->i_sout_destroyed_date =
- ObjectGarbageCollector( p_playlist, VLC_OBJECT_SOUT,
- p_playlist->i_sout_destroyed_date );
- PL_LOCK
+ ObjectGarbageCollector( p_playlist );
+ PL_LOCK;
}
}
else
p_playlist->request.i_status != PLAYLIST_STOPPED ) )
{
msg_Dbg( p_playlist, "starting new item" );
- stats_TimerStart( p_playlist, "Playlist walk",
- STATS_TIMER_PLAYLIST_WALK );
p_item = playlist_NextItem( p_playlist );
- stats_TimerStop( p_playlist, STATS_TIMER_PLAYLIST_WALK );
if( p_item == NULL )
{
}
else
{
- if( p_playlist->status.p_item &&
- p_playlist->status.p_item->i_flags & PLAYLIST_REMOVE_FLAG )
- {
- PL_DEBUG( "deleting item marked for deletion" );
- playlist_ItemDelete( p_playlist->status.p_item );
- p_playlist->status.p_item = NULL;
- }
+ p_playlist->status.i_status = PLAYLIST_STOPPED;
+ if( p_playlist->status.p_item &&
+ p_playlist->status.p_item->i_flags & PLAYLIST_REMOVE_FLAG )
+ {
+ PL_DEBUG( "deleting item marked for deletion" );
+ playlist_ItemDelete( p_playlist->status.p_item );
+ p_playlist->status.p_item = NULL;
+ }
- /* Collect garbage */
- PL_UNLOCK
- p_playlist->i_sout_destroyed_date =
- ObjectGarbageCollector( p_playlist, VLC_OBJECT_SOUT, mdate() );
- p_playlist->i_vout_destroyed_date =
- ObjectGarbageCollector( p_playlist, VLC_OBJECT_VOUT, mdate() );
- PL_LOCK
- }
+ /* Collect garbage */
+ PL_UNLOCK;
+ ObjectGarbageCollector( p_playlist );
+ PL_LOCK;
+ }
}
PL_UNLOCK
}
void playlist_PreparseLoop( playlist_preparse_t *p_obj )
{
playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
+ input_item_t *p_current;
int i_activity;
+ uint32_t i_m, i_o;
- vlc_mutex_lock( &p_obj->object_lock );
-
- if( p_obj->i_waiting > 0 )
+ while( !p_playlist->b_die )
{
- input_item_t *p_current = p_obj->pp_waiting[0];
+ vlc_mutex_lock( &p_obj->object_lock );
+ while( p_obj->i_waiting == 0 )
+ {
+ vlc_cond_wait( &p_obj->object_wait, &p_obj->object_lock );
+ if( p_playlist->b_die )
+ {
+ vlc_mutex_unlock( &p_obj->object_lock );
+ return;
+ }
+ }
+
+ p_current = p_obj->pp_waiting[0];
REMOVE_ELEM( p_obj->pp_waiting, p_obj->i_waiting, 0 );
vlc_mutex_unlock( &p_obj->object_lock );
+
PL_LOCK;
if( p_current )
{
var_SetInteger( p_playlist, "item-change", p_current->i_id );
}
PL_LOCK;
- /* We haven't retrieved enough meta, add to secondary queue
+
+ /* If we haven't retrieved enough meta, add to secondary queue
* which will run the "meta fetchers"
- * TODO: - use i_mandatory stuff here instead of hardcoded T/A
- * - don't do this for things we won't get meta for, like
- * videos
+ * TODO:
+ * don't do this for things we won't get meta for, like
+ * videos
*/
- if( !(p_current->p_meta->psz_title && *p_current->p_meta->psz_title
- && p_current->p_meta->psz_artist &&
- *p_current->p_meta->psz_artist) )
+ if( !input_MetaSatisfied( p_playlist, p_current, &i_m, &i_o,
+ VLC_TRUE ) )
{
+ preparse_item_t p;
+ p.p_item = p_current;
+ p.b_fetch_art = VLC_FALSE;
vlc_mutex_lock( &p_playlist->p_secondary_preparse->object_lock);
- INSERT_ELEM( p_playlist->p_secondary_preparse->pp_waiting,
+ INSERT_ELEM( p_playlist->p_secondary_preparse->p_waiting,
p_playlist->p_secondary_preparse->i_waiting,
p_playlist->p_secondary_preparse->i_waiting,
- p_current );
+ p );
vlc_mutex_unlock(
&p_playlist->p_secondary_preparse->object_lock);
+ vlc_cond_signal(
+ &p_playlist->p_secondary_preparse->object_wait );
}
else
vlc_gc_decref( p_current );
i_activity = var_GetInteger( p_playlist, "activity" );
if( i_activity < 0 ) i_activity = 0;
vlc_mutex_unlock( &p_obj->object_lock );
+ /* Sleep at least 1ms */
msleep( (i_activity+1) * 1000 );
- return;
}
- vlc_mutex_unlock( &p_obj->object_lock );
}
/** Main loop for secondary preparser queue */
-void playlist_SecondaryPreparseLoop( playlist_preparse_t *p_obj )
+void playlist_SecondaryPreparseLoop( playlist_secondary_preparse_t *p_obj )
{
playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
+ vlc_bool_t b_fetch_art;
+ input_item_t *p_item;
+ int i_activity;
- vlc_mutex_lock( &p_obj->object_lock );
-
- if( p_obj->i_waiting > 0 )
+ while( !p_playlist->b_die )
{
- input_item_t *p_current = p_obj->pp_waiting[0];
- REMOVE_ELEM( p_obj->pp_waiting, p_obj->i_waiting, 0 );
+ vlc_mutex_lock( &p_obj->object_lock );
+ while( p_obj->i_waiting == 0 )
+ {
+ vlc_cond_wait( &p_obj->object_wait, &p_obj->object_lock );
+ if( p_playlist->b_die )
+ {
+ vlc_mutex_unlock( &p_obj->object_lock );
+ return;
+ }
+ }
+
+ b_fetch_art = p_obj->p_waiting->b_fetch_art;
+ p_item = p_obj->p_waiting->p_item;
+ REMOVE_ELEM( p_obj->p_waiting, p_obj->i_waiting, 0 );
vlc_mutex_unlock( &p_obj->object_lock );
- if( p_current )
+ if( p_item )
{
- input_MetaFetch( p_playlist, p_current );
- p_current->p_meta->i_status |= ITEM_META_FETCHED;
- var_SetInteger( p_playlist, "item-change", p_current->i_id );
- vlc_gc_decref( p_current );
+ if( !b_fetch_art )
+ {
+ input_MetaFetch( p_playlist, p_item );
+ p_item->p_meta->i_status |= ITEM_META_FETCHED;
+ var_SetInteger( p_playlist, "item-change", p_item->i_id );
+ /* Fetch right now */
+ if( var_GetInteger( p_playlist, "album-art" ) == ALBUM_ART_ALL )
+ {
+ vlc_mutex_lock( &p_obj->object_lock );
+ preparse_item_t p;
+ p.p_item = p_item;
+ p.b_fetch_art = VLC_TRUE;
+ INSERT_ELEM( p_playlist->p_secondary_preparse->p_waiting,
+ p_playlist->p_secondary_preparse->i_waiting,
+ 0, p );
+ vlc_mutex_unlock( &p_obj->object_lock );
+ }
+ else
+ vlc_gc_decref( p_item );
+ }
+ else
+ {
+ input_ArtFetch( p_playlist, p_item );
+ p_item->p_meta->i_status |= ITEM_ART_FETCHED;
+ vlc_gc_decref( p_item );
+ }
}
- else
- PL_UNLOCK;
- return;
+ vlc_mutex_lock( &p_obj->object_lock );
+ i_activity = var_GetInteger( p_playlist, "activity" );
+ if( i_activity < 0 ) i_activity = 0;
+ vlc_mutex_unlock( &p_obj->object_lock );
+ /* Sleep at least 1ms */
+ msleep( (i_activity+1) * 1000 );
}
- vlc_mutex_unlock( &p_obj->object_lock );
}
static void VariablesInit( playlist_t *p_playlist )
var_CreateGetBool( p_playlist, "random" );
var_CreateGetBool( p_playlist, "repeat" );
var_CreateGetBool( p_playlist, "loop" );
+
+ var_AddCallback( p_playlist, "random", RandomCallback, NULL );
}