engine.c 21.8 KB
Newer Older
1 2 3 4
/*****************************************************************************
 * engine.c : Run the playlist and handle its control
 *****************************************************************************
 * Copyright (C) 1999-2004 the VideoLAN team
Antoine Cellerier's avatar
Antoine Cellerier committed
5
 * $Id$
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
 *
 * Authors: Samuel Hocevar <sam@zoy.org>
 *          Clément Stenac <zorglub@videolan.org>
 *
 * 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
 * (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.
 *
 * 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.
 *****************************************************************************/
#include <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/sout.h>
#include <vlc/input.h>
#include "vlc_playlist.h"
#include "vlc_interaction.h"
30
#include "playlist_internal.h"
31 32 33 34 35 36

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static void VariablesInit( playlist_t *p_playlist );

Clément Stenac's avatar
Clément Stenac committed
37 38 39 40
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;
41
    playlist_Signal( ((playlist_t*)p_this) );
Clément Stenac's avatar
Clément Stenac committed
42 43 44
    return VLC_SUCCESS;
}

45 46 47 48 49 50 51 52 53 54
/**
 * Create playlist
 *
 * Create a playlist structure.
 * \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 *p_playlist;
55
    int i_tree;
56 57 58 59 60 61 62 63

    /* Allocate structure */
    p_playlist = vlc_object_create( p_parent, VLC_OBJECT_PLAYLIST );
    if( !p_playlist )
    {
        msg_Err( p_parent, "out of memory" );
        return NULL;
    }
64
    p_parent->p_libvlc->p_playlist = p_playlist;
65 66 67 68 69 70 71 72 73

    VariablesInit( p_playlist );

    /* Initialise data structures */
    vlc_mutex_init( p_playlist, &p_playlist->gc_lock );
    p_playlist->i_last_playlist_id = 0;
    p_playlist->i_last_input_id = 0;
    p_playlist->p_input = NULL;

74 75
    p_playlist->gc_date = 0;
    p_playlist->b_cant_sleep = VLC_FALSE;
76

Clément Stenac's avatar
Clément Stenac committed
77 78 79 80
    ARRAY_INIT( p_playlist->items );
    ARRAY_INIT( p_playlist->all_items );
    ARRAY_INIT( p_playlist->input_items );
    ARRAY_INIT( p_playlist->current );
81

Clément Stenac's avatar
Clément Stenac committed
82 83
    p_playlist->i_current_index = 0;
    p_playlist->b_reset_currently_playing = VLC_TRUE;
84
    p_playlist->last_rebuild_date = 0;
Clément Stenac's avatar
Clément Stenac committed
85

86 87 88 89
    i_tree = var_CreateGetBool( p_playlist, "playlist-tree" );
    p_playlist->b_always_tree = (i_tree == 1);
    p_playlist->b_never_tree = (i_tree == 2);

90 91
    p_playlist->b_doing_ml = VLC_FALSE;

92 93 94 95 96 97 98 99
    p_playlist->p_root_category = playlist_NodeCreate( p_playlist, NULL, NULL);
    p_playlist->p_root_onelevel = playlist_NodeCreate( p_playlist, NULL, NULL);

    /* Create playlist and media library */
    p_playlist->p_local_category = playlist_NodeCreate( p_playlist,
                                 _( "Playlist" ),p_playlist->p_root_category );
    p_playlist->p_local_onelevel =  playlist_NodeCreate( p_playlist,
                                _( "Playlist" ), p_playlist->p_root_onelevel );
100 101 102
    p_playlist->p_local_category->i_flags |= PLAYLIST_RO_FLAG;
    p_playlist->p_local_onelevel->i_flags |= PLAYLIST_RO_FLAG;

103
    /* Link the nodes together. Todo: actually create them from the same input*/
104 105
    p_playlist->p_local_onelevel->p_input->i_id =
        p_playlist->p_local_category->p_input->i_id;
106 107 108 109 110 111 112 113 114 115 116

    if( config_GetInt( p_playlist, "media-library") )
    {
        p_playlist->p_ml_category =   playlist_NodeCreate( p_playlist,
                           _( "Media Library" ), p_playlist->p_root_category );
        p_playlist->p_ml_onelevel =  playlist_NodeCreate( p_playlist,
                           _( "Media Library" ), p_playlist->p_root_onelevel );
        p_playlist->p_ml_category->i_flags |= PLAYLIST_RO_FLAG;
        p_playlist->p_ml_onelevel->i_flags |= PLAYLIST_RO_FLAG;
        p_playlist->p_ml_onelevel->p_input->i_id =
             p_playlist->p_ml_category->p_input->i_id;
117

118 119 120 121 122
    }
    else
    {
        p_playlist->p_ml_category = p_playlist->p_ml_onelevel = NULL;
    }
123 124 125

    /* Initial status */
    p_playlist->status.p_item = NULL;
126
    p_playlist->status.p_node = p_playlist->p_local_onelevel;
127 128 129 130 131 132 133
    p_playlist->request.b_request = VLC_FALSE;
    p_playlist->status.i_status = PLAYLIST_STOPPED;

    p_playlist->i_sort = SORT_ID;
    p_playlist->i_order = ORDER_NORMAL;

    vlc_object_attach( p_playlist, p_parent );
134 135

    playlist_MLLoad( p_playlist );
136 137 138 139 140 141 142 143 144 145
    return p_playlist;
}

void playlist_Destroy( playlist_t *p_playlist )
{
    while( p_playlist->i_sds )
    {
        playlist_ServicesDiscoveryRemove( p_playlist,
                                          p_playlist->pp_sds[0]->psz_module );
    }
146 147 148

    playlist_MLDump( p_playlist );

149
    vlc_thread_join( p_playlist->p_preparse );
150
    vlc_thread_join( p_playlist->p_secondary_preparse );
151 152 153
    vlc_thread_join( p_playlist );

    vlc_object_detach( p_playlist->p_preparse );
154
    vlc_object_detach( p_playlist->p_secondary_preparse );
155 156 157 158 159 160 161

    var_Destroy( p_playlist, "intf-change" );
    var_Destroy( p_playlist, "item-change" );
    var_Destroy( p_playlist, "playlist-current" );
    var_Destroy( p_playlist, "intf-popmenu" );
    var_Destroy( p_playlist, "intf-show" );
    var_Destroy( p_playlist, "play-and-stop" );
162
    var_Destroy( p_playlist, "play-and-exit" );
163 164 165 166 167
    var_Destroy( p_playlist, "random" );
    var_Destroy( p_playlist, "repeat" );
    var_Destroy( p_playlist, "loop" );
    var_Destroy( p_playlist, "activity" );

168
    PL_LOCK;
Clément Stenac's avatar
Clément Stenac committed
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
    /* 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 );

187
    PL_UNLOCK;
188 189 190 191 192 193

    if( p_playlist->p_stats )
        free( p_playlist->p_stats );

    vlc_mutex_destroy( &p_playlist->gc_lock );
    vlc_object_destroy( p_playlist->p_preparse );
194
    vlc_object_destroy( p_playlist->p_secondary_preparse );
195
    vlc_object_detach( p_playlist );
196 197 198
    vlc_object_destroy( p_playlist );

}
199

200
/* Destroy remaining objects */
201
static void ObjectGarbageCollector( playlist_t *p_playlist )
202 203 204
{
    vlc_object_t *p_obj;

205 206 207 208 209 210 211
    if( mdate() - p_playlist->gc_date < 1000000 )
    {
        p_playlist->b_cant_sleep = VLC_TRUE;
        return;
    }
    else if( p_playlist->gc_date == 0 )
        return;
212

213 214 215
    vlc_mutex_lock( &p_playlist->gc_lock );
    while( ( p_obj = vlc_object_find( p_playlist, VLC_OBJECT_VOUT,
                                                  FIND_CHILD ) ) )
216
    {
217 218 219 220 221 222 223 224 225
        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 );
226
    }
227 228
    while( ( p_obj = vlc_object_find( p_playlist, VLC_OBJECT_SOUT,
                                                  FIND_CHILD ) ) )
229
    {
230
        if( p_obj->p_parent != (vlc_object_t*)p_playlist )
231
        {
232 233
            vlc_object_release( p_obj );
            break;
234
        }
235 236
        vlc_object_release( p_obj );
        sout_DeleteInstance( (sout_instance_t*)p_obj );
237
    }
238 239
    p_playlist->b_cant_sleep = VLC_FALSE;
    vlc_mutex_unlock( &p_playlist->gc_lock );
240 241 242 243 244 245
}

/** Main loop for the playlist */
void playlist_MainLoop( playlist_t *p_playlist )
{
    playlist_item_t *p_item = NULL;
246
    vlc_bool_t b_playexit = var_GetBool( p_playlist, "play-and-exit" );
247
    PL_LOCK;
248

249 250
    if( p_playlist->b_reset_currently_playing &&
        mdate() - p_playlist->last_rebuild_date > 30000 ) // 30 ms
251
    {
252 253 254
        ResetCurrentlyPlaying( p_playlist, var_GetBool( p_playlist, "random"),
                             p_playlist->status.p_item );
        p_playlist->last_rebuild_date = mdate();
255
    }
256

257
check_input:
258 259 260
    /* If there is an input, check that it doesn't need to die. */
    if( p_playlist->p_input )
    {
261 262 263 264 265 266
        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 );
        }

267 268 269 270 271
        /* This input is dead. Remove it ! */
        if( p_playlist->p_input->b_dead )
        {
            int i_activity;
            input_thread_t *p_input;
272
            PL_DEBUG( "dead input" );
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290

            p_input = p_playlist->p_input;
            p_playlist->p_input = NULL;

            /* Release the playlist lock, because we may get stuck
             * in input_DestroyThread() for some time. */
            PL_UNLOCK

            /* Destroy input */
            input_DestroyThread( p_input );

            /* Unlink current input
             * (_after_ input_DestroyThread for vout garbage collector) */
            vlc_object_detach( p_input );

            /* Destroy object */
            vlc_object_destroy( p_input );

291 292 293 294
            PL_LOCK;

            p_playlist->gc_date = mdate();
            p_playlist->b_cant_sleep = VLC_TRUE;
295 296 297 298

            if( p_playlist->status.p_item->i_flags
                & PLAYLIST_REMOVE_FLAG )
            {
299 300
                 PL_DEBUG( "%s was marked for deletion, deleting",
                                 PLI_NAME( p_playlist->status.p_item  ) );
301
                 playlist_ItemDelete( p_playlist->status.p_item );
302 303
                 if( p_playlist->request.p_item == p_playlist->status.p_item )
                     p_playlist->request.p_item = NULL;
304 305 306 307 308 309
                 p_playlist->status.p_item = NULL;
            }

            i_activity= var_GetInteger( p_playlist, "activity") ;
            var_SetInteger( p_playlist, "activity", i_activity -
                            DEFAULT_INPUT_ACTIVITY );
310
            goto check_input;
311 312 313 314
        }
        /* This input is dying, let it do */
        else if( p_playlist->p_input->b_die )
        {
315
            PL_DEBUG( "dying input" );
316 317
            msleep( 25000 ); // 25 ms
            goto check_input;
318 319 320 321 322
        }
        /* This input has finished, ask it to die ! */
        else if( p_playlist->p_input->b_error
                  || p_playlist->p_input->b_eof )
        {
323
            PL_DEBUG( "finished input" );
324
            input_StopThread( p_playlist->p_input );
325 326
            /* No need to wait here, we'll wait in the p_input->b_die case */
            goto check_input;
327 328 329
        }
        else if( p_playlist->p_input->i_state != INIT_S )
        {
330
            PL_UNLOCK;
331 332
            ObjectGarbageCollector( p_playlist );
            PL_LOCK;
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
        }
    }
    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
         */
         if( (!p_playlist->request.b_request &&
              p_playlist->status.i_status != PLAYLIST_STOPPED) ||
              ( p_playlist->request.b_request &&
                p_playlist->request.i_status != PLAYLIST_STOPPED ) )
         {
348
             msg_Dbg( p_playlist, "starting new item" );
349 350 351 352 353
             p_item = playlist_NextItem( p_playlist );

             if( p_item == NULL )
             {
                msg_Dbg( p_playlist, "nothing to play" );
354 355 356
                if( b_playexit == VLC_TRUE )
                {
                    msg_Info( p_playlist, "end of playlist, exiting" );
357
                    p_playlist->p_libvlc->b_die = VLC_TRUE;
358
                }
359 360 361 362 363 364 365 366
                p_playlist->status.i_status = PLAYLIST_STOPPED;
                PL_UNLOCK
                return;
             }
             playlist_PlayItem( p_playlist, p_item );
         }
         else
         {
367 368 369 370 371 372 373 374
            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;
            }
375

376 377 378 379 380
            /* Collect garbage */
            PL_UNLOCK;
            ObjectGarbageCollector( p_playlist );
            PL_LOCK;
        }
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
    }
    PL_UNLOCK
}

/** Playlist dying last loop */
void playlist_LastLoop( playlist_t *p_playlist )
{
    vlc_object_t *p_obj;

    /* If there is an input, kill it */
    while( 1 )
    {
        PL_LOCK

        if( p_playlist->p_input == NULL )
        {
            PL_UNLOCK
            break;
        }

        if( p_playlist->p_input->b_dead )
        {
            input_thread_t *p_input;

            /* Unlink current input */
            p_input = p_playlist->p_input;
            p_playlist->p_input = NULL;
            PL_UNLOCK

            /* Destroy input */
            input_DestroyThread( p_input );
            /* Unlink current input (_after_ input_DestroyThread for vout
             * garbage collector)*/
            vlc_object_detach( p_input );

            /* Destroy object */
            vlc_object_destroy( p_input );
            continue;
        }
        else if( p_playlist->p_input->b_die )
        {
            /* This input is dying, leave it alone */
            ;
        }
        else if( p_playlist->p_input->b_error || p_playlist->p_input->b_eof )
        {
            input_StopThread( p_playlist->p_input );
            PL_UNLOCK
            continue;
        }
        else
        {
            p_playlist->p_input->b_eof = 1;
        }

        PL_UNLOCK

        msleep( INTF_IDLE_SLEEP );
    }

    /* close all remaining sout */
    while( ( p_obj = vlc_object_find( p_playlist,
                                      VLC_OBJECT_SOUT, FIND_CHILD ) ) )
    {
        vlc_object_release( p_obj );
        sout_DeleteInstance( (sout_instance_t*)p_obj );
    }

    /* close all remaining vout */
    while( ( p_obj = vlc_object_find( p_playlist,
                                      VLC_OBJECT_VOUT, FIND_CHILD ) ) )
    {
        vlc_object_detach( p_obj );
        vlc_object_release( p_obj );
        vout_Destroy( (vout_thread_t *)p_obj );
    }
}

/** Main loop for preparser queue */
void playlist_PreparseLoop( playlist_preparse_t *p_obj )
{
    playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
463
    input_item_t *p_current;
464
    int i_activity;
Clément Stenac's avatar
Clément Stenac committed
465
    uint32_t i_m, i_o;
466

467
    while( !p_playlist->b_die )
468
    {
469 470 471 472 473 474 475 476 477 478 479 480
        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];
481 482
        REMOVE_ELEM( p_obj->pp_waiting, p_obj->i_waiting, 0 );
        vlc_mutex_unlock( &p_obj->object_lock );
483

Clément Stenac's avatar
Clément Stenac committed
484
        PL_LOCK;
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
        if( p_current )
        {
            vlc_bool_t b_preparsed = VLC_FALSE;
            if( strncmp( p_current->psz_uri, "http:", 5 ) &&
                strncmp( p_current->psz_uri, "rtsp:", 5 ) &&
                strncmp( p_current->psz_uri, "udp:", 4 ) &&
                strncmp( p_current->psz_uri, "mms:", 4 ) &&
                strncmp( p_current->psz_uri, "cdda:", 4 ) &&
                strncmp( p_current->psz_uri, "dvd:", 4 ) &&
                strncmp( p_current->psz_uri, "v4l:", 4 ) &&
                strncmp( p_current->psz_uri, "dshow:", 6 ) )
            {
                b_preparsed = VLC_TRUE;
                stats_TimerStart( p_playlist, "Preparse run",
                                  STATS_TIMER_PREPARSE );
Clément Stenac's avatar
Clément Stenac committed
500
                PL_UNLOCK;
501
                input_Preparse( p_playlist, p_current );
Clément Stenac's avatar
Clément Stenac committed
502
                PL_LOCK;
503 504
                stats_TimerStop( p_playlist, STATS_TIMER_PREPARSE );
            }
Clément Stenac's avatar
Clément Stenac committed
505
            PL_UNLOCK;
506 507
            if( b_preparsed )
            {
508 509
                p_current->p_meta->i_status |= ITEM_PREPARSED;
                var_SetInteger( p_playlist, "item-change", p_current->i_id );
510
            }
511
            PL_LOCK;
512

Clément Stenac's avatar
Clément Stenac committed
513
            /* If we haven't retrieved enough meta, add to secondary queue
514
             * which will run the "meta fetchers"
Clément Stenac's avatar
Clément Stenac committed
515 516 517
             * TODO:
             *  don't do this for things we won't get meta for, like
             *  videos
518
             */
Clément Stenac's avatar
Clément Stenac committed
519 520 521 522
            if( !input_MetaSatisfied( p_playlist, p_current, &i_m, &i_o,
                                      VLC_TRUE ) )
            {
                preparse_item_t p;
523 524
                p.p_item = p_current;
                p.b_fetch_art = VLC_FALSE;
525
                vlc_mutex_lock( &p_playlist->p_secondary_preparse->object_lock);
526
                INSERT_ELEM( p_playlist->p_secondary_preparse->p_waiting,
527 528
                             p_playlist->p_secondary_preparse->i_waiting,
                             p_playlist->p_secondary_preparse->i_waiting,
529
                             p );
530 531
                vlc_mutex_unlock(
                            &p_playlist->p_secondary_preparse->object_lock);
532 533
                vlc_cond_signal(
                            &p_playlist->p_secondary_preparse->object_wait );
Clément Stenac's avatar
Clément Stenac committed
534
            }
535
            else
Clément Stenac's avatar
Clément Stenac committed
536
                vlc_gc_decref( p_current );
537
            PL_UNLOCK;
538 539
        }
        else
540 541
            PL_UNLOCK;

542
        vlc_mutex_lock( &p_obj->object_lock );
543
        i_activity = var_GetInteger( p_playlist, "activity" );
544
        if( i_activity < 0 ) i_activity = 0;
545
        vlc_mutex_unlock( &p_obj->object_lock );
546
        /* Sleep at least 1ms */
547 548 549 550
        msleep( (i_activity+1) * 1000 );
    }
}

551
/** Main loop for secondary preparser queue */
552
void playlist_SecondaryPreparseLoop( playlist_secondary_preparse_t *p_obj )
553 554
{
    playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
555 556 557
    vlc_bool_t b_fetch_art;
    input_item_t *p_item;
    int i_activity;
558

559
    while( !p_playlist->b_die )
560
    {
561 562 563 564 565 566 567 568 569 570 571 572 573
        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;
574
        REMOVE_ELEM( p_obj->p_waiting, p_obj->i_waiting, 0 );
575
        vlc_mutex_unlock( &p_obj->object_lock );
576
        if( p_item )
577
        {
Clément Stenac's avatar
Clément Stenac committed
578 579 580 581
            if( !b_fetch_art )
            {
                input_MetaFetch( p_playlist, p_item );
                p_item->p_meta->i_status |= ITEM_META_FETCHED;
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
                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 );
Clément Stenac's avatar
Clément Stenac committed
597 598
            }
            else
599 600 601
            {
                input_ArtFetch( p_playlist, p_item );
                p_item->p_meta->i_status |= ITEM_ART_FETCHED;
602 603
                vlc_gc_decref( p_item );
           }
604
        }
605 606 607 608 609 610
        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 );
611 612 613
    }
}

614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
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 = VLC_TRUE;
    var_Set( p_playlist, "intf-change", val );

    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-deleted", VLC_VAR_INTEGER );
    val.i_int = -1;
    var_Set( p_playlist, "item-deleted", val );

    var_Create( p_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, "intf-popupmenu", VLC_VAR_BOOL );

    var_Create( p_playlist, "intf-show", VLC_VAR_BOOL );
    val.b_bool = VLC_TRUE;
    var_Set( p_playlist, "intf-show", val );

    var_Create( p_playlist, "activity", VLC_VAR_INTEGER );
    var_SetInteger( p_playlist, "activity", 0 );

    /* Variables to control playback */
    var_CreateGetBool( p_playlist, "play-and-stop" );
647
    var_CreateGetBool( p_playlist, "play-and-exit" );
648 649 650
    var_CreateGetBool( p_playlist, "random" );
    var_CreateGetBool( p_playlist, "repeat" );
    var_CreateGetBool( p_playlist, "loop" );
Clément Stenac's avatar
Clément Stenac committed
651 652

    var_AddCallback( p_playlist, "random", RandomCallback, NULL );
653
}