engine.c 23.9 KB
Newer Older
1
2
3
4
/*****************************************************************************
 * engine.c : Run the playlist and handle its control
 *****************************************************************************
 * Copyright (C) 1999-2004 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
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 );

zorglub's avatar
zorglub 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) );
zorglub's avatar
zorglub 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

zorglub's avatar
zorglub 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

zorglub's avatar
zorglub committed
84
85
    p_playlist->i_current_index = 0;
    p_playlist->b_reset_currently_playing = VLC_TRUE;
86
    p_playlist->last_rebuild_date = 0;
zorglub's avatar
zorglub 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
100
101
102
103
104
    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 );
105
106
107
    p_playlist->p_local_category->i_flags |= PLAYLIST_RO_FLAG;
    p_playlist->p_local_onelevel->i_flags |= PLAYLIST_RO_FLAG;

108
    /* Link the nodes together. Todo: actually create them from the same input*/
109
110
    p_playlist->p_local_onelevel->p_input->i_id =
        p_playlist->p_local_category->p_input->i_id;
111
112
113
114
115
116
117
118
119
120
121

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

123
124
125
126
127
    }
    else
    {
        p_playlist->p_ml_category = p_playlist->p_ml_onelevel = NULL;
    }
128
129
130

    /* Initial status */
    p_playlist->status.p_item = NULL;
131
    p_playlist->status.p_node = p_playlist->p_local_onelevel;
132
133
134
135
136
137
138
    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 );
139
140
    b_save = p_playlist->b_auto_preparse;
    p_playlist->b_auto_preparse = VLC_FALSE;
141
    playlist_MLLoad( p_playlist );
142
    p_playlist->b_auto_preparse = VLC_TRUE;
143
144
145
146
147
148
149
150
151
152
    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 );
    }
153
154
155

    playlist_MLDump( p_playlist );

156
    vlc_thread_join( p_playlist->p_preparse );
157
    vlc_thread_join( p_playlist->p_fetcher );
158
159
160
    vlc_thread_join( p_playlist );

    vlc_object_detach( p_playlist->p_preparse );
161
    vlc_object_detach( p_playlist->p_fetcher );
162
163
164
165
166
167
168

    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" );
169
    var_Destroy( p_playlist, "play-and-exit" );
170
171
172
173
174
    var_Destroy( p_playlist, "random" );
    var_Destroy( p_playlist, "repeat" );
    var_Destroy( p_playlist, "loop" );
    var_Destroy( p_playlist, "activity" );

175
    PL_LOCK;
zorglub's avatar
zorglub committed
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    /* 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 );

194
    PL_UNLOCK;
195
196
197
198
199
200

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

    vlc_mutex_destroy( &p_playlist->gc_lock );
    vlc_object_destroy( p_playlist->p_preparse );
201
    vlc_object_destroy( p_playlist->p_fetcher );
202
    vlc_object_detach( p_playlist );
203
204
205
    vlc_object_destroy( p_playlist );

}
206

207
/* Destroy remaining objects */
208
static void ObjectGarbageCollector( playlist_t *p_playlist )
209
210
211
{
    vlc_object_t *p_obj;

212
213
214
215
216
217
218
    if( mdate() - p_playlist->gc_date < 1000000 )
    {
        p_playlist->b_cant_sleep = VLC_TRUE;
        return;
    }
    else if( p_playlist->gc_date == 0 )
        return;
219

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

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

256
257
    if( p_playlist->b_reset_currently_playing &&
        mdate() - p_playlist->last_rebuild_date > 30000 ) // 30 ms
258
    {
259
260
261
        ResetCurrentlyPlaying( p_playlist, var_GetBool( p_playlist, "random"),
                             p_playlist->status.p_item );
        p_playlist->last_rebuild_date = mdate();
262
    }
263

264
check_input:
265
266
267
    /* If there is an input, check that it doesn't need to die. */
    if( p_playlist->p_input )
    {
268
269
270
271
272
273
        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 );
        }

274
275
276
277
278
        /* 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
279
            PL_DEBUG( "dead input" );
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297

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

298
299
300
301
            PL_LOCK;

            p_playlist->gc_date = mdate();
            p_playlist->b_cant_sleep = VLC_TRUE;
302
303
304
305

            if( p_playlist->status.p_item->i_flags
                & PLAYLIST_REMOVE_FLAG )
            {
zorglub's avatar
zorglub committed
306
307
                 PL_DEBUG( "%s was marked for deletion, deleting",
                                 PLI_NAME( p_playlist->status.p_item  ) );
308
                 playlist_ItemDelete( p_playlist->status.p_item );
309
310
                 if( p_playlist->request.p_item == p_playlist->status.p_item )
                     p_playlist->request.p_item = NULL;
311
312
313
314
315
316
                 p_playlist->status.p_item = NULL;
            }

            i_activity= var_GetInteger( p_playlist, "activity") ;
            var_SetInteger( p_playlist, "activity", i_activity -
                            DEFAULT_INPUT_ACTIVITY );
317
            goto check_input;
318
319
320
321
        }
        /* This input is dying, let it do */
        else if( p_playlist->p_input->b_die )
        {
zorglub's avatar
zorglub committed
322
            PL_DEBUG( "dying input" );
323
324
            msleep( 25000 ); // 25 ms
            goto check_input;
325
326
327
328
329
        }
        /* 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
330
            PL_DEBUG( "finished input" );
331
            input_StopThread( p_playlist->p_input );
332
333
            /* No need to wait here, we'll wait in the p_input->b_die case */
            goto check_input;
334
335
336
        }
        else if( p_playlist->p_input->i_state != INIT_S )
        {
zorglub's avatar
zorglub committed
337
            PL_UNLOCK;
338
339
            ObjectGarbageCollector( p_playlist );
            PL_LOCK;
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
        }
    }
    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
355
             msg_Dbg( p_playlist, "starting new item" );
356
357
358
359
360
             p_item = playlist_NextItem( p_playlist );

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

383
384
385
386
387
            /* Collect garbage */
            PL_UNLOCK;
            ObjectGarbageCollector( p_playlist );
            PL_LOCK;
        }
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
463
464
465
466
467
468
469
    }
    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;
470
    input_item_t *p_current;
471
    int i_activity;
zorglub's avatar
zorglub committed
472
    uint32_t i_m, i_o;
473

474
    while( !p_playlist->b_die )
475
    {
476
477
478
479
480
481
482
483
484
485
486
487
        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];
488
489
        REMOVE_ELEM( p_obj->pp_waiting, p_obj->i_waiting, 0 );
        vlc_mutex_unlock( &p_obj->object_lock );
490

zorglub's avatar
zorglub committed
491
        PL_LOCK;
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
        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 );
zorglub's avatar
zorglub committed
507
                PL_UNLOCK;
508
                input_Preparse( p_playlist, p_current );
zorglub's avatar
zorglub committed
509
                PL_LOCK;
510
511
                stats_TimerStop( p_playlist, STATS_TIMER_PREPARSE );
            }
zorglub's avatar
zorglub committed
512
            PL_UNLOCK;
513
514
            if( b_preparsed )
            {
zorglub's avatar
zorglub committed
515
516
                p_current->p_meta->i_status |= ITEM_PREPARSED;
                var_SetInteger( p_playlist, "item-change", p_current->i_id );
517
            }
518
            PL_LOCK;
519

zorglub's avatar
zorglub committed
520
            /* If we haven't retrieved enough meta, add to secondary queue
521
522
523
             * 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
524
             */
525
            if( !input_MetaSatisfied( p_playlist, p_current, &i_m, &i_o ) )
zorglub's avatar
zorglub committed
526
527
            {
                preparse_item_t p;
528
                PL_DEBUG("need to fetch meta for %s", p_current->psz_name );
dionoea's avatar
dionoea committed
529
530
                p.p_item = p_current;
                p.b_fetch_art = VLC_FALSE;
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
                vlc_mutex_lock( &p_playlist->p_fetcher->object_lock );
                INSERT_ELEM( p_playlist->p_fetcher->p_waiting,
                             p_playlist->p_fetcher->i_waiting,
                             p_playlist->p_fetcher->i_waiting,
                             p );
                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 */
            else if( p_playlist->p_fetcher->i_art_policy == ALBUM_ART_ALL &&
                     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 );
                INSERT_ELEM( p_playlist->p_fetcher->p_waiting,
                             p_playlist->p_fetcher->i_waiting,
                             p_playlist->p_fetcher->i_waiting,
dionoea's avatar
dionoea committed
552
                             p );
553
554
                vlc_mutex_unlock( &p_playlist->p_fetcher->object_lock );
                vlc_cond_signal( &p_playlist->p_fetcher->object_wait );
zorglub's avatar
zorglub committed
555
            }
556
            else
557
558
559
            {
                PL_DEBUG( "no fetch required for %s (art currently %s)",
                          p_current->psz_name, p_current->p_meta->psz_arturl );
zorglub's avatar
zorglub committed
560
                vlc_gc_decref( p_current );
561
            }
562
            PL_UNLOCK;
563
564
        }
        else
565
566
            PL_UNLOCK;

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

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

584
    while( !p_playlist->b_die )
585
    {
586
587
588
589
590
591
592
593
594
595
596
597
598
        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
599
        REMOVE_ELEM( p_obj->p_waiting, p_obj->i_waiting, 0 );
600
        vlc_mutex_unlock( &p_obj->object_lock );
dionoea's avatar
dionoea committed
601
        if( p_item )
602
        {
zorglub's avatar
zorglub committed
603
604
605
606
            if( !b_fetch_art )
            {
                input_MetaFetch( p_playlist, p_item );
                p_item->p_meta->i_status |= ITEM_META_FETCHED;
607
608
                var_SetInteger( p_playlist, "item-change", p_item->i_id );
                /*  Fetch right now */
609
                if( p_playlist->p_fetcher->i_art_policy == ALBUM_ART_ALL )
610
611
612
613
614
                {
                    vlc_mutex_lock( &p_obj->object_lock );
                    preparse_item_t p;
                    p.p_item = p_item;
                    p.b_fetch_art = VLC_TRUE;
615
616
                    INSERT_ELEM( p_playlist->p_fetcher->p_waiting,
                                 p_playlist->p_fetcher->i_waiting,
617
                                 0, p );
618
                    PL_DEBUG("meta fetched for %s, get art", p_item->psz_name);
619
                    vlc_mutex_unlock( &p_obj->object_lock );
620
                    continue;
621
622
623
                }
                else
                    vlc_gc_decref( p_item );
zorglub's avatar
zorglub committed
624
625
            }
            else
dionoea's avatar
dionoea committed
626
            {
627
628
629
630
631
632
633
634
635
636
637
638
639
640
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 );
                    if( !input_DownloadAndCacheArt( p_playlist, p_item ) )
                        p_item->p_meta->i_status |= ITEM_ART_NOTFOUND;
                    else
                        p_item->p_meta->i_status |= ITEM_ART_FETCHED;
                }
                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;
                }
                else
                {
                    PL_DEBUG("art not found for %s", p_item->psz_name );
                    p_item->p_meta->i_status |= ITEM_ART_NOTFOUND;
                }
646
647
                vlc_gc_decref( p_item );
           }
648
        }
649
650
651
652
653
654
        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 );
655
656
657
    }
}

658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
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" );
691
    var_CreateGetBool( p_playlist, "play-and-exit" );
692
693
694
    var_CreateGetBool( p_playlist, "random" );
    var_CreateGetBool( p_playlist, "repeat" );
    var_CreateGetBool( p_playlist, "loop" );
zorglub's avatar
zorglub committed
695
696

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