engine.c 24.7 KB
Newer Older
1
2
3
/*****************************************************************************
 * engine.c : Run the playlist and handle its control
 *****************************************************************************
4
 * Copyright (C) 1999-2007 the VideoLAN team
dionoea's avatar
2nd try    
dionoea 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
#include <vlc/vlc.h>
zorglub's avatar
zorglub committed
26
27
28
29
#include <vlc_vout.h>
#include <vlc_sout.h>
#include <vlc_playlist.h>
#include <vlc_interface.h>
30
#include "playlist_internal.h"
zorglub's avatar
zorglub committed
31
#include "stream_output/stream_output.h" /* sout_DeleteInstance */
32
33
34
35
36
37

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

zorglub's avatar
zorglub committed
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 )
{
41
42
    (void)psz_cmd; (void)oldval; (void)newval; (void)a;

zorglub's avatar
zorglub committed
43
    ((playlist_t*)p_this)->b_reset_currently_playing = VLC_TRUE;
44
    playlist_Signal( ((playlist_t*)p_this) );
zorglub's avatar
zorglub committed
45
46
47
    return VLC_SUCCESS;
}

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

    /* Allocate structure */
    p_playlist = vlc_object_create( p_parent, VLC_OBJECT_PLAYLIST );
    if( !p_playlist )
    {
        msg_Err( p_parent, "out of memory" );
        return NULL;
    }
68

69
    TAB_INIT( p_playlist->i_sd, p_playlist->pp_sd );
70

71
    p_parent->p_libvlc->p_playlist = p_playlist;
72
73
74
75
76
77
78
79
80

    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;

81
82
    p_playlist->gc_date = 0;
    p_playlist->b_cant_sleep = VLC_FALSE;
83

zorglub's avatar
zorglub committed
84
85
86
87
    ARRAY_INIT( p_playlist->items );
    ARRAY_INIT( p_playlist->all_items );
    ARRAY_INIT( p_playlist->input_items );
    ARRAY_INIT( p_playlist->current );
88

zorglub's avatar
zorglub committed
89
90
    p_playlist->i_current_index = 0;
    p_playlist->b_reset_currently_playing = VLC_TRUE;
91
    p_playlist->last_rebuild_date = 0;
zorglub's avatar
zorglub committed
92

93
94
95
96
    i_tree = var_CreateGetBool( p_playlist, "playlist-tree" );
    p_playlist->b_always_tree = (i_tree == 1);
    p_playlist->b_never_tree = (i_tree == 2);

97
98
    p_playlist->b_doing_ml = VLC_FALSE;

99
100
101
    p_playlist->b_auto_preparse =
                        var_CreateGetBool( p_playlist, "auto-preparse") ;

102
103
104
105
    p_playlist->p_root_category = playlist_NodeCreate( p_playlist, NULL, NULL,
                                                       0 );
    p_playlist->p_root_onelevel = playlist_NodeCreate( p_playlist, NULL, NULL,
                                                       0 );
106

107
108
109
    if( !p_playlist->p_root_category || !p_playlist->p_root_onelevel )
        return NULL;

110
111
    /* Create playlist and media library */
    p_playlist->p_local_category = playlist_NodeCreate( p_playlist,
112
                              _( "Playlist" ),p_playlist->p_root_category, 0 );
113
    p_playlist->p_local_onelevel =  playlist_NodeCreate( p_playlist,
114
                              _( "Playlist" ), p_playlist->p_root_onelevel, 0 );
115
116
117
    p_playlist->p_local_category->i_flags |= PLAYLIST_RO_FLAG;
    p_playlist->p_local_onelevel->i_flags |= PLAYLIST_RO_FLAG;

118
119
120
121
122
    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;

123
    /* Link the nodes together. Todo: actually create them from the same input*/
124
125
    p_playlist->p_local_onelevel->p_input->i_id =
        p_playlist->p_local_category->p_input->i_id;
126
127
128
129

    if( config_GetInt( p_playlist, "media-library") )
    {
        p_playlist->p_ml_category =   playlist_NodeCreate( p_playlist,
130
                         _( "Media Library" ), p_playlist->p_root_category, 0 );
131
        p_playlist->p_ml_onelevel =  playlist_NodeCreate( p_playlist,
132
                         _( "Media Library" ), p_playlist->p_root_onelevel, 0 );
133
134
135
136

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

137
138
139
140
        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;
141

142
143
144
145
146
    }
    else
    {
        p_playlist->p_ml_category = p_playlist->p_ml_onelevel = NULL;
    }
147
148
149

    /* Initial status */
    p_playlist->status.p_item = NULL;
150
    p_playlist->status.p_node = p_playlist->p_local_onelevel;
151
152
153
154
155
156
    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;

157
158
    b_save = p_playlist->b_auto_preparse;
    p_playlist->b_auto_preparse = VLC_FALSE;
159
    playlist_MLLoad( p_playlist );
160
    p_playlist->b_auto_preparse = VLC_TRUE;
161
162
163
164
165
166
167
168
169
170
171
    return p_playlist;
}

void playlist_Destroy( playlist_t *p_playlist )
{
    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" );
172
    var_Destroy( p_playlist, "play-and-exit" );
173
174
175
176
177
178
    var_Destroy( p_playlist, "random" );
    var_Destroy( p_playlist, "repeat" );
    var_Destroy( p_playlist, "loop" );
    var_Destroy( p_playlist, "activity" );

    vlc_mutex_destroy( &p_playlist->gc_lock );
179
    vlc_object_detach( p_playlist );
180
181
    vlc_object_destroy( p_playlist );
}
182

183
/* Destroy remaining objects */
184
static void ObjectGarbageCollector( playlist_t *p_playlist, vlc_bool_t b_force )
185
186
187
{
    vlc_object_t *p_obj;

188
    if( !b_force )
189
    {
190
191
192
193
194
195
196
        if( mdate() - p_playlist->gc_date < 1000000 )
        {
            p_playlist->b_cant_sleep = VLC_TRUE;
            return;
        }
        else if( p_playlist->gc_date == 0 )
            return;
197
    }
198

199
200
201
    vlc_mutex_lock( &p_playlist->gc_lock );
    while( ( p_obj = vlc_object_find( p_playlist, VLC_OBJECT_VOUT,
                                                  FIND_CHILD ) ) )
202
    {
203
        if( p_obj->p_parent != VLC_OBJECT(p_playlist) )
204
205
206
207
208
209
210
211
        {
            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 );
212
    }
213
214
    while( ( p_obj = vlc_object_find( p_playlist, VLC_OBJECT_SOUT,
                                                  FIND_CHILD ) ) )
215
    {
216
        if( p_obj->p_parent != VLC_OBJECT(p_playlist) )
217
        {
218
219
            vlc_object_release( p_obj );
            break;
220
        }
221
222
        msg_Dbg( p_playlist, "garbage collector destroying 1 sout" );
        vlc_object_detach( p_obj );
223
224
        vlc_object_release( p_obj );
        sout_DeleteInstance( (sout_instance_t*)p_obj );
225
    }
226
227
    p_playlist->b_cant_sleep = VLC_FALSE;
    vlc_mutex_unlock( &p_playlist->gc_lock );
228
229
230
231
232
233
}

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

237
238
    if( p_playlist->b_reset_currently_playing &&
        mdate() - p_playlist->last_rebuild_date > 30000 ) // 30 ms
239
    {
240
241
242
        ResetCurrentlyPlaying( p_playlist, var_GetBool( p_playlist, "random"),
                             p_playlist->status.p_item );
        p_playlist->last_rebuild_date = mdate();
243
    }
244

245
check_input:
246
247
248
    /* If there is an input, check that it doesn't need to die. */
    if( p_playlist->p_input )
    {
249
250
251
252
253
254
        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 );
        }

255
256
257
258
259
        /* This input is dead. Remove it ! */
        if( p_playlist->p_input->b_dead )
        {
            int i_activity;
            input_thread_t *p_input;
zorglub's avatar
zorglub committed
260
            PL_DEBUG( "dead input" );
261
262
263
264
265
266
267
268
269
270
271

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

272
273
274
275
            PL_LOCK;

            p_playlist->gc_date = mdate();
            p_playlist->b_cant_sleep = VLC_TRUE;
276
277
278
279

            if( p_playlist->status.p_item->i_flags
                & PLAYLIST_REMOVE_FLAG )
            {
zorglub's avatar
zorglub committed
280
281
                 PL_DEBUG( "%s was marked for deletion, deleting",
                                 PLI_NAME( p_playlist->status.p_item  ) );
282
                 playlist_ItemDelete( p_playlist->status.p_item );
283
284
                 if( p_playlist->request.p_item == p_playlist->status.p_item )
                     p_playlist->request.p_item = NULL;
285
286
287
288
289
290
                 p_playlist->status.p_item = NULL;
            }

            i_activity= var_GetInteger( p_playlist, "activity") ;
            var_SetInteger( p_playlist, "activity", i_activity -
                            DEFAULT_INPUT_ACTIVITY );
291
            goto check_input;
292
293
294
295
        }
        /* This input is dying, let it do */
        else if( p_playlist->p_input->b_die )
        {
zorglub's avatar
zorglub committed
296
            PL_DEBUG( "dying input" );
297
            PL_UNLOCK;
298
            msleep( 25000 ); // 25 ms
299
            PL_LOCK;
300
            goto check_input;
301
302
303
304
305
        }
        /* This input has finished, ask it to die ! */
        else if( p_playlist->p_input->b_error
                  || p_playlist->p_input->b_eof )
        {
zorglub's avatar
zorglub committed
306
            PL_DEBUG( "finished input" );
307
            input_StopThread( p_playlist->p_input );
308
309
            /* No need to wait here, we'll wait in the p_input->b_die case */
            goto check_input;
310
311
312
        }
        else if( p_playlist->p_input->i_state != INIT_S )
        {
zorglub's avatar
zorglub committed
313
            PL_UNLOCK;
314
            ObjectGarbageCollector( p_playlist, VLC_FALSE );
315
            PL_LOCK;
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
        }
    }
    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 ) )
         {
zorglub's avatar
zorglub committed
331
             msg_Dbg( p_playlist, "starting new item" );
332
333
334
335
336
             p_item = playlist_NextItem( p_playlist );

             if( p_item == NULL )
             {
                msg_Dbg( p_playlist, "nothing to play" );
337
338
339
                if( b_playexit == VLC_TRUE )
                {
                    msg_Info( p_playlist, "end of playlist, exiting" );
340
                    vlc_object_kill( p_playlist->p_libvlc );
341
                }
342
343
                p_playlist->status.i_status = PLAYLIST_STOPPED;
                PL_UNLOCK
344
345

                ObjectGarbageCollector( p_playlist, VLC_TRUE );
346
347
348
349
350
351
                return;
             }
             playlist_PlayItem( p_playlist, p_item );
         }
         else
         {
352
353
            const vlc_bool_t b_gc_forced = p_playlist->status.i_status != PLAYLIST_STOPPED;

354
355
356
357
358
359
360
361
            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;
            }
362

363
364
            /* Collect garbage */
            PL_UNLOCK;
365
            ObjectGarbageCollector( p_playlist, b_gc_forced );
366
367
            PL_LOCK;
        }
368
369
370
371
372
373
374
375
376
377
378
379
380
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
    }
    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 );
            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 ) ) )
    {
426
        vlc_object_detach( p_obj );
427
428
429
430
431
432
433
434
435
436
437
438
        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 );
    }
439

440
    while( p_playlist->i_sd )
441
442
    {
        playlist_ServicesDiscoveryRemove( p_playlist,
443
                                          p_playlist->pp_sd[0]->psz_module );
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
    }

    playlist_MLDump( p_playlist );

    PL_LOCK;
    /* 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;
468
469
470
471
472
473
}

/** Main loop for preparser queue */
void playlist_PreparseLoop( playlist_preparse_t *p_obj )
{
    playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
474
    input_item_t *p_current;
475
    int i_activity;
zorglub's avatar
zorglub committed
476
    uint32_t i_m, i_o;
477

478
    while( !p_playlist->b_die )
479
    {
480
481
482
483
484
485
486
487
488
489
        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;
            }
        }
490

491
        p_current = p_obj->pp_waiting[0];
492
493
        REMOVE_ELEM( p_obj->pp_waiting, p_obj->i_waiting, 0 );
        vlc_mutex_unlock( &p_obj->object_lock );
494

zorglub's avatar
zorglub committed
495
        PL_LOCK;
496
497
        if( p_current )
        {
498
            if( !strncmp( p_current->psz_uri, "file:", 5 ) )
499
500
501
            {
                stats_TimerStart( p_playlist, "Preparse run",
                                  STATS_TIMER_PREPARSE );
502
                /* Do not preparse if it is already done (like by playing it) */
503
                if( !input_item_IsPreparsed( p_current ) )
504
505
506
507
508
                {
                    PL_UNLOCK;
                    input_Preparse( p_playlist, p_current );
                    PL_LOCK;
                }
509
                stats_TimerStop( p_playlist, STATS_TIMER_PREPARSE );
510
                PL_UNLOCK;
511
                input_item_SetPreparsed( p_current, VLC_TRUE );
zorglub's avatar
zorglub committed
512
                var_SetInteger( p_playlist, "item-change", p_current->i_id );
513
                PL_LOCK;
514
            }
zorglub's avatar
zorglub committed
515
            /* If we haven't retrieved enough meta, add to secondary queue
516
517
518
             * 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
519
             */
Rafaël Carré's avatar
Rafaël Carré committed
520
521
            char *psz_arturl = input_item_GetArtURL( p_current );
            char *psz_name = input_item_GetName( p_current );
522
            if( !input_MetaSatisfied( p_playlist, p_current, &i_m, &i_o ) )
zorglub's avatar
zorglub committed
523
524
            {
                preparse_item_t p;
525
                PL_DEBUG("need to fetch meta for %s", p_current->psz_name );
dionoea's avatar
dionoea committed
526
527
                p.p_item = p_current;
                p.b_fetch_art = VLC_FALSE;
528
529
530
                vlc_mutex_lock( &p_playlist->p_fetcher->object_lock );
                INSERT_ELEM( p_playlist->p_fetcher->p_waiting,
                             p_playlist->p_fetcher->i_waiting,
531
                             p_playlist->p_fetcher->i_waiting, p);
532
                vlc_cond_signal( &p_playlist->p_fetcher->object_wait );
533
                vlc_mutex_unlock( &p_playlist->p_fetcher->object_lock );
534
535
            }
            /* We already have all needed meta, but we need art right now */
536
            else if( p_playlist->p_fetcher->i_art_policy == ALBUM_ART_ALL &&
Rafaël Carré's avatar
Rafaël Carré committed
537
                     EMPTY_STR( psz_arturl ) )
538
539
            {
                preparse_item_t p;
Rafaël Carré's avatar
Rafaël Carré committed
540
                PL_DEBUG("meta ok for %s, need to fetch art", psz_name );
541
542
543
                p.p_item = p_current;
                p.b_fetch_art = VLC_TRUE;
                vlc_mutex_lock( &p_playlist->p_fetcher->object_lock );
544
545
546
                INSERT_ELEM( p_playlist->p_fetcher->p_waiting,
                             p_playlist->p_fetcher->i_waiting,
                             p_playlist->p_fetcher->i_waiting, p);
547
                vlc_cond_signal( &p_playlist->p_fetcher->object_wait );
548
                vlc_mutex_unlock( &p_playlist->p_fetcher->object_lock );
zorglub's avatar
zorglub committed
549
            }
550
            else
551
552
            {
                PL_DEBUG( "no fetch required for %s (art currently %s)",
Rafaël Carré's avatar
Rafaël Carré committed
553
                          psz_name, psz_arturl );
zorglub's avatar
zorglub committed
554
                vlc_gc_decref( p_current );
555
            }
Rafaël Carré's avatar
Rafaël Carré committed
556
557
            free( psz_name );
            free( psz_arturl );
558
            PL_UNLOCK;
559
560
        }
        else
561
562
            PL_UNLOCK;

563
        vlc_mutex_lock( &p_obj->object_lock );
564
        i_activity = var_GetInteger( p_playlist, "activity" );
565
        if( i_activity < 0 ) i_activity = 0;
zorglub's avatar
zorglub committed
566
        vlc_mutex_unlock( &p_obj->object_lock );
567
        /* Sleep at least 1ms */
568
569
570
571
        msleep( (i_activity+1) * 1000 );
    }
}

572
/** Main loop for secondary preparser queue */
573
void playlist_FetcherLoop( playlist_fetcher_t *p_obj )
574
575
{
    playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
576
577
578
    vlc_bool_t b_fetch_art;
    input_item_t *p_item;
    int i_activity;
579

580
    while( !p_playlist->b_die )
581
    {
582
583
584
585
586
587
588
589
590
591
592
593
594
        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;
dionoea's avatar
dionoea committed
595
        REMOVE_ELEM( p_obj->p_waiting, p_obj->i_waiting, 0 );
596
        vlc_mutex_unlock( &p_obj->object_lock );
dionoea's avatar
dionoea committed
597
        if( p_item )
598
        {
zorglub's avatar
zorglub committed
599
600
601
            if( !b_fetch_art )
            {
                input_MetaFetch( p_playlist, p_item );
602
603
                var_SetInteger( p_playlist, "item-change", p_item->i_id );
                /*  Fetch right now */
604
                if( p_playlist->p_fetcher->i_art_policy == ALBUM_ART_ALL )
605
606
607
608
609
                {
                    vlc_mutex_lock( &p_obj->object_lock );
                    preparse_item_t p;
                    p.p_item = p_item;
                    p.b_fetch_art = VLC_TRUE;
610
611
                    INSERT_ELEM( p_playlist->p_fetcher->p_waiting,
                                 p_playlist->p_fetcher->i_waiting,
612
                                 0, p );
613
                    PL_DEBUG("meta fetched for %s, get art", p_item->psz_name);
614
                    vlc_mutex_unlock( &p_obj->object_lock );
615
                    continue;
616
617
618
                }
                else
                    vlc_gc_decref( p_item );
zorglub's avatar
zorglub committed
619
620
            }
            else
dionoea's avatar
dionoea committed
621
            {
622
623
624
625
626
                int i_ret;

                /* Check if it is not yet preparsed and if so wait for it (at most 0.5s)
                 * (This can happen if we fetch art on play)
                 * FIXME this doesn't work if we need to fetch meta before art ... */
627
                for( i_ret = 0; i_ret < 10 && !input_item_IsPreparsed( p_item ); i_ret++ )
628
629
630
631
632
633
634
635
636
637
                {
                    vlc_bool_t b_break;
                    PL_LOCK;
                    b_break = ( !p_playlist->p_input || input_GetItem(p_playlist->p_input) != p_item  ||
                                p_playlist->p_input->b_die || p_playlist->p_input->b_eof || p_playlist->p_input->b_error );
                    PL_UNLOCK;
                    if( b_break )
                        break;
                    msleep( 50000 );
                }
638

639
                i_ret = input_ArtFind( p_playlist, p_item );
640
641
642
                if( i_ret == 1 )
                {
                    PL_DEBUG("downloading art for %s", p_item->psz_name );
643
                    if( input_DownloadAndCacheArt( p_playlist, p_item ) )
644
                        input_item_SetArtNotFound( p_item, VLC_TRUE );
645
                    else {
646
                        input_item_SetArtFetched( p_item, VLC_TRUE );
647
648
649
                        var_SetInteger( p_playlist, "item-change",
                                        p_item->i_id );
                    }
650
651
652
653
                }
                else if( i_ret == 0 ) /* Was in cache */
                {
                    PL_DEBUG("found art for %s in cache", p_item->psz_name );
654
                    input_item_SetArtFetched( p_item, VLC_TRUE );
655
                    var_SetInteger( p_playlist, "item-change", p_item->i_id );
656
657
658
659
                }
                else
                {
                    PL_DEBUG("art not found for %s", p_item->psz_name );
660
                    input_item_SetArtNotFound( p_item, VLC_TRUE );
661
                }
662
663
                vlc_gc_decref( p_item );
           }
664
        }
665
666
667
668
669
670
        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 );
671
672
673
    }
}

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
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" );
707
    var_CreateGetBool( p_playlist, "play-and-exit" );
708
709
710
    var_CreateGetBool( p_playlist, "random" );
    var_CreateGetBool( p_playlist, "repeat" );
    var_CreateGetBool( p_playlist, "loop" );
zorglub's avatar
zorglub committed
711
712

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