engine.c 24.1 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
#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
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
    p_playlist->p_root_category = playlist_NodeCreate( p_playlist, NULL, NULL,
                                                       0 );
    p_playlist->p_root_onelevel = playlist_NodeCreate( p_playlist, NULL, NULL,
                                                       0 );
101

102
103
104
    if( !p_playlist->p_root_category || !p_playlist->p_root_onelevel )
        return NULL;

105
106
    /* Create playlist and media library */
    p_playlist->p_local_category = playlist_NodeCreate( p_playlist,
107
                              _( "Playlist" ),p_playlist->p_root_category, 0 );
108
    p_playlist->p_local_onelevel =  playlist_NodeCreate( p_playlist,
109
                              _( "Playlist" ), p_playlist->p_root_onelevel, 0 );
110
111
112
    p_playlist->p_local_category->i_flags |= PLAYLIST_RO_FLAG;
    p_playlist->p_local_onelevel->i_flags |= PLAYLIST_RO_FLAG;

113
114
115
116
117
    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;

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

    if( config_GetInt( p_playlist, "media-library") )
    {
        p_playlist->p_ml_category =   playlist_NodeCreate( p_playlist,
125
                         _( "Media Library" ), p_playlist->p_root_category, 0 );
126
        p_playlist->p_ml_onelevel =  playlist_NodeCreate( p_playlist,
127
                         _( "Media Library" ), p_playlist->p_root_onelevel, 0 );
128
129
130
131

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

132
133
134
135
        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;
136

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

    /* Initial status */
    p_playlist->status.p_item = NULL;
145
    p_playlist->status.p_node = p_playlist->p_local_onelevel;
146
147
148
149
150
151
    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;

152
153
    b_save = p_playlist->b_auto_preparse;
    p_playlist->b_auto_preparse = VLC_FALSE;
154
    playlist_MLLoad( p_playlist );
155
    p_playlist->b_auto_preparse = VLC_TRUE;
156
157
158
159
160
161
162
163
164
165
166
    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" );
167
    var_Destroy( p_playlist, "play-and-exit" );
168
169
170
171
172
173
    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 );
174
    vlc_object_detach( p_playlist );
175
176
    vlc_object_destroy( p_playlist );
}
177

178
/* Destroy remaining objects */
179
static void ObjectGarbageCollector( playlist_t *p_playlist )
180
181
182
{
    vlc_object_t *p_obj;

183
184
185
186
187
188
189
    if( mdate() - p_playlist->gc_date < 1000000 )
    {
        p_playlist->b_cant_sleep = VLC_TRUE;
        return;
    }
    else if( p_playlist->gc_date == 0 )
        return;
190

191
192
193
    vlc_mutex_lock( &p_playlist->gc_lock );
    while( ( p_obj = vlc_object_find( p_playlist, VLC_OBJECT_VOUT,
                                                  FIND_CHILD ) ) )
194
    {
195
196
197
198
199
200
201
202
203
        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 );
204
    }
205
206
    while( ( p_obj = vlc_object_find( p_playlist, VLC_OBJECT_SOUT,
                                                  FIND_CHILD ) ) )
207
    {
208
        if( p_obj->p_parent != (vlc_object_t*)p_playlist )
209
        {
210
211
            vlc_object_release( p_obj );
            break;
212
        }
213
214
        msg_Dbg( p_playlist, "garbage collector destroying 1 sout" );
        vlc_object_detach( p_obj );
215
216
        vlc_object_release( p_obj );
        sout_DeleteInstance( (sout_instance_t*)p_obj );
217
    }
218
219
    p_playlist->b_cant_sleep = VLC_FALSE;
    vlc_mutex_unlock( &p_playlist->gc_lock );
220
221
222
223
224
225
}

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

229
230
    if( p_playlist->b_reset_currently_playing &&
        mdate() - p_playlist->last_rebuild_date > 30000 ) // 30 ms
231
    {
232
233
234
        ResetCurrentlyPlaying( p_playlist, var_GetBool( p_playlist, "random"),
                             p_playlist->status.p_item );
        p_playlist->last_rebuild_date = mdate();
235
    }
236

237
check_input:
238
239
240
    /* If there is an input, check that it doesn't need to die. */
    if( p_playlist->p_input )
    {
241
242
243
244
245
246
        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 );
        }

247
248
249
250
251
        /* 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
252
            PL_DEBUG( "dead input" );
253
254
255
256
257
258
259
260
261
262
263

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

264
265
266
267
            PL_LOCK;

            p_playlist->gc_date = mdate();
            p_playlist->b_cant_sleep = VLC_TRUE;
268
269
270
271

            if( p_playlist->status.p_item->i_flags
                & PLAYLIST_REMOVE_FLAG )
            {
zorglub's avatar
zorglub committed
272
273
                 PL_DEBUG( "%s was marked for deletion, deleting",
                                 PLI_NAME( p_playlist->status.p_item  ) );
274
                 playlist_ItemDelete( p_playlist->status.p_item );
275
276
                 if( p_playlist->request.p_item == p_playlist->status.p_item )
                     p_playlist->request.p_item = NULL;
277
278
279
280
281
282
                 p_playlist->status.p_item = NULL;
            }

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

             if( p_item == NULL )
             {
                msg_Dbg( p_playlist, "nothing to play" );
329
330
331
                if( b_playexit == VLC_TRUE )
                {
                    msg_Info( p_playlist, "end of playlist, exiting" );
332
                    p_playlist->p_libvlc->b_die = VLC_TRUE;
333
                }
334
335
336
337
338
339
340
341
                p_playlist->status.i_status = PLAYLIST_STOPPED;
                PL_UNLOCK
                return;
             }
             playlist_PlayItem( p_playlist, p_item );
         }
         else
         {
342
343
344
345
346
347
348
349
            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;
            }
350

351
352
353
354
355
            /* Collect garbage */
            PL_UNLOCK;
            ObjectGarbageCollector( p_playlist );
            PL_LOCK;
        }
356
357
358
359
360
361
362
363
364
365
366
367
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
    }
    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 ) ) )
    {
414
        vlc_object_detach( p_obj );
415
416
417
418
419
420
421
422
423
424
425
426
        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 );
    }
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

    while( p_playlist->i_sds )
    {
        playlist_ServicesDiscoveryRemove( p_playlist,
                                          p_playlist->pp_sds[0]->psz_module );
    }

    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;
456
457
458
459
460
461
}

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

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

zorglub's avatar
zorglub committed
483
        PL_LOCK;
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
        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
499
                PL_UNLOCK;
500
                input_Preparse( p_playlist, p_current );
zorglub's avatar
zorglub committed
501
                PL_LOCK;
502
503
                stats_TimerStop( p_playlist, STATS_TIMER_PREPARSE );
            }
zorglub's avatar
zorglub committed
504
            PL_UNLOCK;
505
506
            if( b_preparsed )
            {
zorglub's avatar
zorglub committed
507
508
                p_current->p_meta->i_status |= ITEM_PREPARSED;
                var_SetInteger( p_playlist, "item-change", p_current->i_id );
509
            }
510
            PL_LOCK;
511

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

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

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

578
    while( !p_playlist->b_die )
579
    {
580
581
582
583
584
585
586
587
588
589
590
591
592
        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
593
        REMOVE_ELEM( p_obj->p_waiting, p_obj->i_waiting, 0 );
594
        vlc_mutex_unlock( &p_obj->object_lock );
dionoea's avatar
dionoea committed
595
        if( p_item )
596
        {
597
            assert( p_item->p_meta );
zorglub's avatar
zorglub committed
598
599
600
601
            if( !b_fetch_art )
            {
                input_MetaFetch( p_playlist, p_item );
                p_item->p_meta->i_status |= ITEM_META_FETCHED;
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
                int i_ret = input_ArtFind( p_playlist, p_item );
                if( i_ret == 1 )
                {
                    PL_DEBUG("downloading art for %s", p_item->psz_name );
626
                    if( input_DownloadAndCacheArt( p_playlist, p_item ) )
627
                        p_item->p_meta->i_status |= ITEM_ART_NOTFOUND;
628
                    else {
629
                        p_item->p_meta->i_status |= ITEM_ART_FETCHED;
630
631
632
                        var_SetInteger( p_playlist, "item-change",
                                        p_item->i_id );
                    }
633
634
635
636
637
                }
                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;
638
                    var_SetInteger( p_playlist, "item-change", p_item->i_id );
639
640
641
642
643
644
                }
                else
                {
                    PL_DEBUG("art not found for %s", p_item->psz_name );
                    p_item->p_meta->i_status |= ITEM_ART_NOTFOUND;
                }
645
646
                vlc_gc_decref( p_item );
           }
647
        }
648
649
650
651
652
653
        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 );
654
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
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" );
690
    var_CreateGetBool( p_playlist, "play-and-exit" );
691
692
693
    var_CreateGetBool( p_playlist, "random" );
    var_CreateGetBool( p_playlist, "repeat" );
    var_CreateGetBool( p_playlist, "loop" );
zorglub's avatar
zorglub committed
694
695

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