engine.c 24.7 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
 *
 * 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.
 *****************************************************************************/
24

25 26 27 28 29 30
#include <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/sout.h>
#include <vlc/input.h>
#include "vlc_playlist.h"
#include "vlc_interaction.h"
31
#include "playlist_internal.h"
32 33 34 35 36 37

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

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

46 47 48 49 50 51 52 53 54 55
/**
 * 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;
56
    vlc_bool_t b_save;
57
    int i_tree;
58 59 60 61 62 63 64 65

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

    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;

76 77
    p_playlist->gc_date = 0;
    p_playlist->b_cant_sleep = VLC_FALSE;
78

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

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

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

92 93
    p_playlist->b_doing_ml = VLC_FALSE;

94 95 96
    p_playlist->b_auto_preparse =
                        var_CreateGetBool( p_playlist, "auto-preparse") ;

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);

100 101 102
    if( !p_playlist->p_root_category || !p_playlist->p_root_onelevel )
        return NULL;

103 104 105 106 107
    /* 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 );
108 109 110
    p_playlist->p_local_category->i_flags |= PLAYLIST_RO_FLAG;
    p_playlist->p_local_onelevel->i_flags |= PLAYLIST_RO_FLAG;

111 112 113 114 115
    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;

116
    /* Link the nodes together. Todo: actually create them from the same input*/
117 118
    p_playlist->p_local_onelevel->p_input->i_id =
        p_playlist->p_local_category->p_input->i_id;
119 120 121 122 123 124 125

    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 );
126 127 128 129

        if(!p_playlist->p_ml_category || !p_playlist->p_ml_onelevel)
            return NULL;

130 131 132 133
        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;
134

135 136 137 138 139
    }
    else
    {
        p_playlist->p_ml_category = p_playlist->p_ml_onelevel = NULL;
    }
140 141 142

    /* Initial status */
    p_playlist->status.p_item = NULL;
143
    p_playlist->status.p_node = p_playlist->p_local_onelevel;
144 145 146 147 148 149 150
    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 );
151 152
    b_save = p_playlist->b_auto_preparse;
    p_playlist->b_auto_preparse = VLC_FALSE;
153
    playlist_MLLoad( p_playlist );
154
    p_playlist->b_auto_preparse = VLC_TRUE;
155 156 157 158 159 160 161 162 163 164
    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 );
    }
165 166 167

    playlist_MLDump( p_playlist );

168
    vlc_thread_join( p_playlist->p_preparse );
169
    vlc_thread_join( p_playlist->p_fetcher );
170 171 172
    vlc_thread_join( p_playlist );

    vlc_object_detach( p_playlist->p_preparse );
173
    vlc_object_detach( p_playlist->p_fetcher );
174 175 176 177 178 179 180

    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" );
181
    var_Destroy( p_playlist, "play-and-exit" );
182 183 184 185 186
    var_Destroy( p_playlist, "random" );
    var_Destroy( p_playlist, "repeat" );
    var_Destroy( p_playlist, "loop" );
    var_Destroy( p_playlist, "activity" );

187
    PL_LOCK;
Clément Stenac's avatar
Clément Stenac committed
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
    /* 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 );

206
    PL_UNLOCK;
207

208
    vlc_mutex_destroy( &p_playlist->p_stats->lock );
209 210 211 212 213
    if( p_playlist->p_stats )
        free( p_playlist->p_stats );

    vlc_mutex_destroy( &p_playlist->gc_lock );
    vlc_object_destroy( p_playlist->p_preparse );
214
    vlc_object_destroy( p_playlist->p_fetcher );
215
    vlc_object_detach( p_playlist );
216 217
    vlc_object_destroy( p_playlist );
}
218

219
/* Destroy remaining objects */
220
static void ObjectGarbageCollector( playlist_t *p_playlist )
221 222 223
{
    vlc_object_t *p_obj;

224 225 226 227 228 229 230
    if( mdate() - p_playlist->gc_date < 1000000 )
    {
        p_playlist->b_cant_sleep = VLC_TRUE;
        return;
    }
    else if( p_playlist->gc_date == 0 )
        return;
231

232 233 234
    vlc_mutex_lock( &p_playlist->gc_lock );
    while( ( p_obj = vlc_object_find( p_playlist, VLC_OBJECT_VOUT,
                                                  FIND_CHILD ) ) )
235
    {
236 237 238 239 240 241 242 243 244
        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 );
245
    }
246 247
    while( ( p_obj = vlc_object_find( p_playlist, VLC_OBJECT_SOUT,
                                                  FIND_CHILD ) ) )
248
    {
249
        if( p_obj->p_parent != (vlc_object_t*)p_playlist )
250
        {
251 252
            vlc_object_release( p_obj );
            break;
253
        }
254 255
        vlc_object_release( p_obj );
        sout_DeleteInstance( (sout_instance_t*)p_obj );
256
    }
257 258
    p_playlist->b_cant_sleep = VLC_FALSE;
    vlc_mutex_unlock( &p_playlist->gc_lock );
259 260 261 262 263 264
}

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

268 269
    if( p_playlist->b_reset_currently_playing &&
        mdate() - p_playlist->last_rebuild_date > 30000 ) // 30 ms
270
    {
271 272 273
        ResetCurrentlyPlaying( p_playlist, var_GetBool( p_playlist, "random"),
                             p_playlist->status.p_item );
        p_playlist->last_rebuild_date = mdate();
274
    }
275

276
check_input:
277 278 279
    /* If there is an input, check that it doesn't need to die. */
    if( p_playlist->p_input )
    {
280 281 282 283 284 285
        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 );
        }

286 287 288 289 290
        /* This input is dead. Remove it ! */
        if( p_playlist->p_input->b_dead )
        {
            int i_activity;
            input_thread_t *p_input;
291
            PL_DEBUG( "dead input" );
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309

            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 );

310 311 312 313
            PL_LOCK;

            p_playlist->gc_date = mdate();
            p_playlist->b_cant_sleep = VLC_TRUE;
314 315 316 317

            if( p_playlist->status.p_item->i_flags
                & PLAYLIST_REMOVE_FLAG )
            {
318 319
                 PL_DEBUG( "%s was marked for deletion, deleting",
                                 PLI_NAME( p_playlist->status.p_item  ) );
320
                 playlist_ItemDelete( p_playlist->status.p_item );
321 322
                 if( p_playlist->request.p_item == p_playlist->status.p_item )
                     p_playlist->request.p_item = NULL;
323 324 325 326 327 328
                 p_playlist->status.p_item = NULL;
            }

            i_activity= var_GetInteger( p_playlist, "activity") ;
            var_SetInteger( p_playlist, "activity", i_activity -
                            DEFAULT_INPUT_ACTIVITY );
329
            goto check_input;
330 331 332 333
        }
        /* This input is dying, let it do */
        else if( p_playlist->p_input->b_die )
        {
334
            PL_DEBUG( "dying input" );
335 336
            msleep( 25000 ); // 25 ms
            goto check_input;
337 338 339 340 341
        }
        /* This input has finished, ask it to die ! */
        else if( p_playlist->p_input->b_error
                  || p_playlist->p_input->b_eof )
        {
342
            PL_DEBUG( "finished input" );
343
            input_StopThread( p_playlist->p_input );
344 345
            /* No need to wait here, we'll wait in the p_input->b_die case */
            goto check_input;
346 347 348
        }
        else if( p_playlist->p_input->i_state != INIT_S )
        {
349
            PL_UNLOCK;
350 351
            ObjectGarbageCollector( p_playlist );
            PL_LOCK;
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
        }
    }
    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 ) )
         {
367
             msg_Dbg( p_playlist, "starting new item" );
368 369 370 371 372
             p_item = playlist_NextItem( p_playlist );

             if( p_item == NULL )
             {
                msg_Dbg( p_playlist, "nothing to play" );
373 374 375
                if( b_playexit == VLC_TRUE )
                {
                    msg_Info( p_playlist, "end of playlist, exiting" );
376
                    p_playlist->p_libvlc->b_die = VLC_TRUE;
377
                }
378 379 380 381 382 383 384 385
                p_playlist->status.i_status = PLAYLIST_STOPPED;
                PL_UNLOCK
                return;
             }
             playlist_PlayItem( p_playlist, p_item );
         }
         else
         {
386 387 388 389 390 391 392 393
            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;
            }
394

395 396 397 398 399
            /* Collect garbage */
            PL_UNLOCK;
            ObjectGarbageCollector( p_playlist );
            PL_LOCK;
        }
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 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
    }
    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;
482
    input_item_t *p_current;
483
    int i_activity;
Clément Stenac's avatar
Clément Stenac committed
484
    uint32_t i_m, i_o;
485

486
    while( !p_playlist->b_die )
487
    {
488 489 490 491 492 493 494 495 496 497 498 499
        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];
500 501
        REMOVE_ELEM( p_obj->pp_waiting, p_obj->i_waiting, 0 );
        vlc_mutex_unlock( &p_obj->object_lock );
502

Clément Stenac's avatar
Clément Stenac committed
503
        PL_LOCK;
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
        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
519
                PL_UNLOCK;
520
                input_Preparse( p_playlist, p_current );
Clément Stenac's avatar
Clément Stenac committed
521
                PL_LOCK;
522 523
                stats_TimerStop( p_playlist, STATS_TIMER_PREPARSE );
            }
Clément Stenac's avatar
Clément Stenac committed
524
            PL_UNLOCK;
525 526
            if( b_preparsed )
            {
527 528
                p_current->p_meta->i_status |= ITEM_PREPARSED;
                var_SetInteger( p_playlist, "item-change", p_current->i_id );
529
            }
530
            PL_LOCK;
531

Clément Stenac's avatar
Clément Stenac committed
532
            /* If we haven't retrieved enough meta, add to secondary queue
533 534 535
             * which will run the "meta fetchers".
             * This only checks for meta, not for art
             * \todo don't do this for things we won't get meta for, like vids
536
             */
537 538
            if( p_current->p_meta &&
                !input_MetaSatisfied( p_playlist, p_current, &i_m, &i_o ) )
Clément Stenac's avatar
Clément Stenac committed
539 540
            {
                preparse_item_t p;
541
                PL_DEBUG("need to fetch meta for %s", p_current->psz_name );
542 543
                p.p_item = p_current;
                p.b_fetch_art = VLC_FALSE;
544 545 546
                vlc_mutex_lock( &p_playlist->p_fetcher->object_lock );
                INSERT_ELEM( p_playlist->p_fetcher->p_waiting,
                             p_playlist->p_fetcher->i_waiting,
547
                             p_playlist->p_fetcher->i_waiting, p);
548 549 550 551
                vlc_mutex_unlock( &p_playlist->p_fetcher->object_lock );
                vlc_cond_signal( &p_playlist->p_fetcher->object_wait );
            }
            /* We already have all needed meta, but we need art right now */
552 553
            else if( p_current->p_meta &&
                     p_playlist->p_fetcher->i_art_policy == ALBUM_ART_ALL &&
554 555 556 557 558 559 560 561
                     EMPTY_STR( p_current->p_meta->psz_arturl ) )
            {
                preparse_item_t p;
                PL_DEBUG("meta ok for %s, need to fetch art",
                                                         p_current->psz_name );
                p.p_item = p_current;
                p.b_fetch_art = VLC_TRUE;
                vlc_mutex_lock( &p_playlist->p_fetcher->object_lock );
562 563 564
                INSERT_ELEM( p_playlist->p_fetcher->p_waiting,
                             p_playlist->p_fetcher->i_waiting,
                             p_playlist->p_fetcher->i_waiting, p);
565 566
                vlc_mutex_unlock( &p_playlist->p_fetcher->object_lock );
                vlc_cond_signal( &p_playlist->p_fetcher->object_wait );
Clément Stenac's avatar
Clément Stenac committed
567
            }
568
            else
569 570
            {
                PL_DEBUG( "no fetch required for %s (art currently %s)",
571 572 573
                          p_current->psz_name,
                          p_current->p_meta ? p_current->p_meta->psz_arturl:
                                              "null" );
Clément Stenac's avatar
Clément Stenac committed
574
                vlc_gc_decref( p_current );
575
            }
576
            PL_UNLOCK;
577 578
        }
        else
579 580
            PL_UNLOCK;

581
        vlc_mutex_lock( &p_obj->object_lock );
582
        i_activity = var_GetInteger( p_playlist, "activity" );
583
        if( i_activity < 0 ) i_activity = 0;
584
        vlc_mutex_unlock( &p_obj->object_lock );
585
        /* Sleep at least 1ms */
586 587 588 589
        msleep( (i_activity+1) * 1000 );
    }
}

590
/** Main loop for secondary preparser queue */
591
void playlist_FetcherLoop( playlist_fetcher_t *p_obj )
592 593
{
    playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
594 595 596
    vlc_bool_t b_fetch_art;
    input_item_t *p_item;
    int i_activity;
597

598
    while( !p_playlist->b_die )
599
    {
600 601 602 603 604 605 606 607 608 609 610 611 612
        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;
613
        REMOVE_ELEM( p_obj->p_waiting, p_obj->i_waiting, 0 );
614
        vlc_mutex_unlock( &p_obj->object_lock );
615
        if( p_item )
616
        {
617
            assert( p_item->p_meta );
Clément Stenac's avatar
Clément Stenac committed
618 619 620 621
            if( !b_fetch_art )
            {
                input_MetaFetch( p_playlist, p_item );
                p_item->p_meta->i_status |= ITEM_META_FETCHED;
622 623
                var_SetInteger( p_playlist, "item-change", p_item->i_id );
                /*  Fetch right now */
624
                if( p_playlist->p_fetcher->i_art_policy == ALBUM_ART_ALL )
625 626 627 628 629
                {
                    vlc_mutex_lock( &p_obj->object_lock );
                    preparse_item_t p;
                    p.p_item = p_item;
                    p.b_fetch_art = VLC_TRUE;
630 631
                    INSERT_ELEM( p_playlist->p_fetcher->p_waiting,
                                 p_playlist->p_fetcher->i_waiting,
632
                                 0, p );
633
                    PL_DEBUG("meta fetched for %s, get art", p_item->psz_name);
634
                    vlc_mutex_unlock( &p_obj->object_lock );
635
                    continue;
636 637 638
                }
                else
                    vlc_gc_decref( p_item );
Clément Stenac's avatar
Clément Stenac committed
639 640
            }
            else
641
            {
642 643 644 645
                int i_ret = input_ArtFind( p_playlist, p_item );
                if( i_ret == 1 )
                {
                    PL_DEBUG("downloading art for %s", p_item->psz_name );
646
                    if( input_DownloadAndCacheArt( p_playlist, p_item ) )
647
                        p_item->p_meta->i_status |= ITEM_ART_NOTFOUND;
648
                    else {
649
                        p_item->p_meta->i_status |= ITEM_ART_FETCHED;
650 651 652
                        var_SetInteger( p_playlist, "item-change",
                                        p_item->i_id );
                    }
653 654 655 656 657
                }
                else if( i_ret == 0 ) /* Was in cache */
                {
                    PL_DEBUG("found art for %s in cache", p_item->psz_name );
                    p_item->p_meta->i_status |= ITEM_ART_FETCHED;
658
                    var_SetInteger( p_playlist, "item-change", p_item->i_id );
659 660 661 662 663 664
                }
                else
                {
                    PL_DEBUG("art not found for %s", p_item->psz_name );
                    p_item->p_meta->i_status |= ITEM_ART_NOTFOUND;
                }
665 666
                vlc_gc_decref( p_item );
           }
667
        }
668 669 670 671 672 673
        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 );
674 675 676
    }
}

677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
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" );
710
    var_CreateGetBool( p_playlist, "play-and-exit" );
711 712 713
    var_CreateGetBool( p_playlist, "random" );
    var_CreateGetBool( p_playlist, "repeat" );
    var_CreateGetBool( p_playlist, "loop" );
Clément Stenac's avatar
Clément Stenac committed
714 715

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