engine.c 24.6 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
26
27
28
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

29
#include <vlc/vlc.h>
zorglub's avatar
zorglub committed
30
31
32
33
#include <vlc_vout.h>
#include <vlc_sout.h>
#include <vlc_playlist.h>
#include <vlc_interface.h>
34
#include "playlist_internal.h"
zorglub's avatar
zorglub committed
35
#include "stream_output/stream_output.h" /* sout_DeleteInstance */
36
37
38
39
40
41

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

zorglub's avatar
zorglub committed
42
43
44
static int RandomCallback( vlc_object_t *p_this, char const *psz_cmd,
                           vlc_value_t oldval, vlc_value_t newval, void *a )
{
45
46
    (void)psz_cmd; (void)oldval; (void)newval; (void)a;

zorglub's avatar
zorglub committed
47
    ((playlist_t*)p_this)->b_reset_currently_playing = VLC_TRUE;
48
    playlist_Signal( ((playlist_t*)p_this) );
zorglub's avatar
zorglub committed
49
50
51
    return VLC_SUCCESS;
}

52
53
54
55
56
57
58
59
60
61
/**
 * 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;
62
    vlc_bool_t b_save;
63
    int i_tree;
64
65
66
67
68
69
70
71

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

73
    TAB_INIT( p_playlist->i_sds, p_playlist->pp_sds );
74

75
    p_parent->p_libvlc->p_playlist = p_playlist;
76
77
78
79
80
81
82
83
84

    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;

85
86
    p_playlist->gc_date = 0;
    p_playlist->b_cant_sleep = VLC_FALSE;
87

zorglub's avatar
zorglub committed
88
89
90
91
    ARRAY_INIT( p_playlist->items );
    ARRAY_INIT( p_playlist->all_items );
    ARRAY_INIT( p_playlist->input_items );
    ARRAY_INIT( p_playlist->current );
92

zorglub's avatar
zorglub committed
93
94
    p_playlist->i_current_index = 0;
    p_playlist->b_reset_currently_playing = VLC_TRUE;
95
    p_playlist->last_rebuild_date = 0;
zorglub's avatar
zorglub committed
96

97
98
99
100
    i_tree = var_CreateGetBool( p_playlist, "playlist-tree" );
    p_playlist->b_always_tree = (i_tree == 1);
    p_playlist->b_never_tree = (i_tree == 2);

101
102
    p_playlist->b_doing_ml = VLC_FALSE;

103
    p_playlist->b_auto_preparse =
ivoire's avatar
ivoire committed
104
                        var_CreateGetBool( p_playlist, "auto-preparse" ) ;
105

106
    p_playlist->p_root_category = playlist_NodeCreate( p_playlist, NULL, NULL,
107
                                    0, NULL );
108
    p_playlist->p_root_onelevel = playlist_NodeCreate( p_playlist, NULL, NULL,
109
                                    0, p_playlist->p_root_category->p_input );
110

111
112
113
    if( !p_playlist->p_root_category || !p_playlist->p_root_onelevel )
        return NULL;

114
    /* Create playlist and media library */
115
116
117
118
    playlist_NodesPairCreate( p_playlist, _( "Playlist" ),
                            &p_playlist->p_local_category,
                            &p_playlist->p_local_onelevel, VLC_FALSE );

119
120
121
    p_playlist->p_local_category->i_flags |= PLAYLIST_RO_FLAG;
    p_playlist->p_local_onelevel->i_flags |= PLAYLIST_RO_FLAG;

122
123
124
125
126
    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;

127
128
    if( config_GetInt( p_playlist, "media-library") )
    {
129
130
131
        playlist_NodesPairCreate( p_playlist, _( "Media Library" ),
                            &p_playlist->p_ml_category,
                            &p_playlist->p_ml_onelevel, VLC_FALSE );
132
133
134
135

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

136
137
138
139
140
141
142
        p_playlist->p_ml_category->i_flags |= PLAYLIST_RO_FLAG;
        p_playlist->p_ml_onelevel->i_flags |= PLAYLIST_RO_FLAG;
    }
    else
    {
        p_playlist->p_ml_category = p_playlist->p_ml_onelevel = NULL;
    }
143
144
145

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

153

154
155
    b_save = p_playlist->b_auto_preparse;
    p_playlist->b_auto_preparse = VLC_FALSE;
156
    playlist_MLLoad( p_playlist );
157
    p_playlist->b_auto_preparse = VLC_TRUE;
158
159
160
    return p_playlist;
}

ivoire's avatar
ivoire committed
161
162
163
164
165
166
167
/**
 * Destroy playlist
 *
 * Destroy a playlist structure.
 * \param p_playlist the playlist object
 * \return nothing
 */
168
169
170
171
172
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" );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
173
    var_Destroy( p_playlist, "intf-popupmenu" );
174
175
    var_Destroy( p_playlist, "intf-show" );
    var_Destroy( p_playlist, "play-and-stop" );
176
    var_Destroy( p_playlist, "play-and-exit" );
177
178
179
180
181
182
    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 );
183
    vlc_object_detach( p_playlist );
184
    vlc_object_release( p_playlist );
185
}
186

187
/* Destroy remaining objects */
188
static void ObjectGarbageCollector( playlist_t *p_playlist, vlc_bool_t b_force )
189
190
191
{
    vlc_object_t *p_obj;

192
    if( !b_force )
193
    {
194
195
196
197
198
199
200
        if( mdate() - p_playlist->gc_date < 1000000 )
        {
            p_playlist->b_cant_sleep = VLC_TRUE;
            return;
        }
        else if( p_playlist->gc_date == 0 )
            return;
201
    }
202

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

ivoire's avatar
ivoire committed
234
235
236
237
238
239
240
/**
 * Main loop
 *
 * Main loop for the playlist
 * \param p_playlist the playlist object
 * \return nothing
 */
241
242
243
void playlist_MainLoop( playlist_t *p_playlist )
{
    playlist_item_t *p_item = NULL;
244
    vlc_bool_t b_playexit = var_GetBool( p_playlist, "play-and-exit" );
245
    PL_LOCK;
246

247
248
    if( p_playlist->b_reset_currently_playing &&
        mdate() - p_playlist->last_rebuild_date > 30000 ) // 30 ms
249
    {
ivoire's avatar
ivoire committed
250
        ResetCurrentlyPlaying( p_playlist, var_GetBool( p_playlist, "random" ),
251
252
                             p_playlist->status.p_item );
        p_playlist->last_rebuild_date = mdate();
253
    }
254

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

265
266
267
268
269
        /* 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
270
            PL_DEBUG( "dead input" );
271
272
273
274
275

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

            /* Release the playlist lock, because we may get stuck
276
             * in vlc_object_release() for some time. */
277
            PL_UNLOCK;
278
279

            /* Destroy input */
280
            vlc_object_release( p_input );
281

282
283
284
285
            PL_LOCK;

            p_playlist->gc_date = mdate();
            p_playlist->b_cant_sleep = VLC_TRUE;
286
287
288
289

            if( p_playlist->status.p_item->i_flags
                & PLAYLIST_REMOVE_FLAG )
            {
zorglub's avatar
zorglub committed
290
291
                 PL_DEBUG( "%s was marked for deletion, deleting",
                                 PLI_NAME( p_playlist->status.p_item  ) );
292
                 playlist_ItemDelete( p_playlist->status.p_item );
293
294
                 if( p_playlist->request.p_item == p_playlist->status.p_item )
                     p_playlist->request.p_item = NULL;
295
296
297
                 p_playlist->status.p_item = NULL;
            }

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

ivoire's avatar
ivoire committed
341
342
            if( p_item == NULL )
            {
343
                msg_Dbg( p_playlist, "nothing to play" );
344
                p_playlist->status.i_status = PLAYLIST_STOPPED;
345
                PL_UNLOCK;
346

347
348
349
                if( b_playexit == VLC_TRUE )
                {
                    msg_Info( p_playlist, "end of playlist, exiting" );
350
                    vlc_object_kill( p_playlist->p_libvlc );
351
                }
352
                ObjectGarbageCollector( p_playlist, VLC_TRUE );
353
354
355
356
357
358
                return;
             }
             playlist_PlayItem( p_playlist, p_item );
         }
         else
         {
359
360
            const vlc_bool_t b_gc_forced = p_playlist->status.i_status != PLAYLIST_STOPPED;

361
362
363
364
365
366
367
368
            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;
            }
369

370
371
            /* Collect garbage */
            PL_UNLOCK;
372
            ObjectGarbageCollector( p_playlist, b_gc_forced );
373
374
            PL_LOCK;
        }
375
    }
376
    PL_UNLOCK;
377
378
}

ivoire's avatar
ivoire committed
379
380
381
382
383
384
385
386

/**
 * Last loop
 *
 * The playlist is dying so do the last loop
 * \param p_playlist the playlist object
 * \return nothing
*/
387
388
389
390
391
392
393
void playlist_LastLoop( playlist_t *p_playlist )
{
    vlc_object_t *p_obj;

    /* If there is an input, kill it */
    while( 1 )
    {
394
        PL_LOCK;
395
396
        if( p_playlist->p_input == NULL )
        {
397
            PL_UNLOCK;
398
399
400
401
402
403
404
405
406
407
            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;
408
            PL_UNLOCK;
409
410

            /* Destroy input */
411
            vlc_object_release( p_input );
412
413
414
415
416
417
418
419
420
421
            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 );
422
            PL_UNLOCK;
423
424
425
426
427
428
            continue;
        }
        else
        {
            p_playlist->p_input->b_eof = 1;
        }
429
        PL_UNLOCK;
430
431
432
433
434
435
436
437

        msleep( INTF_IDLE_SLEEP );
    }

    /* close all remaining sout */
    while( ( p_obj = vlc_object_find( p_playlist,
                                      VLC_OBJECT_SOUT, FIND_CHILD ) ) )
    {
438
        vlc_object_detach( p_obj );
439
440
441
442
443
444
445
446
447
448
449
450
        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 );
    }
451

452
    while( p_playlist->i_sds )
453
454
    {
        playlist_ServicesDiscoveryRemove( p_playlist,
455
                                          p_playlist->pp_sds[0]->p_sd->psz_module );
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
    }

    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;
480
481
}

ivoire's avatar
ivoire committed
482
483
484
485
486
487
488
/**
 * Preparse loop
 *
 * Main loop for preparser queue
 * \param p_obj items to preparse
 * \return nothing
 */
489
490
491
void playlist_PreparseLoop( playlist_preparse_t *p_obj )
{
    playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
492
    input_item_t *p_current;
493
    int i_activity;
zorglub's avatar
zorglub committed
494
    uint32_t i_m, i_o;
495

496
    while( !p_playlist->b_die )
497
    {
498
        vlc_object_lock( p_obj );
499
500
        while( p_obj->i_waiting == 0 )
        {
501
            if( vlc_object_wait( p_obj ) || p_playlist->b_die )
502
            {
503
                vlc_object_unlock( p_obj );
504
505
506
                return;
            }
        }
507

508
        p_current = p_obj->pp_waiting[0];
509
        REMOVE_ELEM( p_obj->pp_waiting, p_obj->i_waiting, 0 );
510
        vlc_object_unlock( p_obj );
511

zorglub's avatar
zorglub committed
512
        PL_LOCK;
513
514
        if( p_current )
        {
515
            if( p_current->i_type == ITEM_TYPE_FILE )
516
517
518
            {
                stats_TimerStart( p_playlist, "Preparse run",
                                  STATS_TIMER_PREPARSE );
519
                /* Do not preparse if it is already done (like by playing it) */
520
                if( !input_item_IsPreparsed( p_current ) )
521
522
523
524
525
                {
                    PL_UNLOCK;
                    input_Preparse( p_playlist, p_current );
                    PL_LOCK;
                }
526
                stats_TimerStop( p_playlist, STATS_TIMER_PREPARSE );
527
                PL_UNLOCK;
528
                input_item_SetPreparsed( p_current, VLC_TRUE );
zorglub's avatar
zorglub committed
529
                var_SetInteger( p_playlist, "item-change", p_current->i_id );
530
                PL_LOCK;
531
            }
zorglub's avatar
zorglub 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
             */
Rafaël Carré's avatar
Rafaël Carré committed
537
538
            char *psz_arturl = input_item_GetArtURL( p_current );
            char *psz_name = input_item_GetName( p_current );
539
            if( !input_MetaSatisfied( p_playlist, p_current, &i_m, &i_o ) )
zorglub's avatar
zorglub committed
540
541
            {
                preparse_item_t p;
ivoire's avatar
ivoire committed
542
                PL_DEBUG( "need to fetch meta for %s", p_current->psz_name );
dionoea's avatar
dionoea committed
543
544
                p.p_item = p_current;
                p.b_fetch_art = VLC_FALSE;
545
                vlc_object_lock( p_playlist->p_fetcher );
546
547
                INSERT_ELEM( p_playlist->p_fetcher->p_waiting,
                             p_playlist->p_fetcher->i_waiting,
548
                             p_playlist->p_fetcher->i_waiting, p);
549
550
                vlc_object_signal_unlocked( p_playlist->p_fetcher );
                vlc_object_unlock( p_playlist->p_fetcher );
551
552
            }
            /* We already have all needed meta, but we need art right now */
553
            else if( p_playlist->p_fetcher->i_art_policy == ALBUM_ART_ALL &&
554
                        ( !psz_arturl || strncmp( psz_arturl, "file://", 7 ) ) )
555
556
            {
                preparse_item_t p;
Rafaël Carré's avatar
Rafaël Carré committed
557
                PL_DEBUG("meta ok for %s, need to fetch art", psz_name );
558
559
                p.p_item = p_current;
                p.b_fetch_art = VLC_TRUE;
560
                vlc_object_lock( p_playlist->p_fetcher );
561
562
563
                INSERT_ELEM( p_playlist->p_fetcher->p_waiting,
                             p_playlist->p_fetcher->i_waiting,
                             p_playlist->p_fetcher->i_waiting, p);
564
565
                vlc_object_signal_unlocked( p_playlist->p_fetcher );
                vlc_object_unlock( p_playlist->p_fetcher );
zorglub's avatar
zorglub committed
566
            }
567
            else
568
569
            {
                PL_DEBUG( "no fetch required for %s (art currently %s)",
Rafaël Carré's avatar
Rafaël Carré committed
570
                          psz_name, psz_arturl );
zorglub's avatar
zorglub committed
571
                vlc_gc_decref( p_current );
572
            }
Rafaël Carré's avatar
Rafaël Carré committed
573
574
            free( psz_name );
            free( psz_arturl );
575
            PL_UNLOCK;
576
577
        }
        else
578
579
            PL_UNLOCK;

580
        vlc_object_lock( p_obj );
581
        i_activity = var_GetInteger( p_playlist, "activity" );
582
        if( i_activity < 0 ) i_activity = 0;
583
        vlc_object_unlock( p_obj );
584
        /* Sleep at least 1ms */
585
586
587
588
        msleep( (i_activity+1) * 1000 );
    }
}

ivoire's avatar
ivoire committed
589
590
591
592
593
594
595
/**
 * Fetcher loop
 *
 * Main loop for secondary preparser queue
 * \param p_obj items to preparse
 * \return nothing
 */
596
void playlist_FetcherLoop( playlist_fetcher_t *p_obj )
597
598
{
    playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
599
600
601
    vlc_bool_t b_fetch_art;
    input_item_t *p_item;
    int i_activity;
602

603
    while( !p_playlist->b_die )
604
    {
605
606
607
608
609
610
611
612
613
614
615
616
617
        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
618
        REMOVE_ELEM( p_obj->p_waiting, p_obj->i_waiting, 0 );
619
        vlc_mutex_unlock( &p_obj->object_lock );
dionoea's avatar
dionoea committed
620
        if( p_item )
621
        {
zorglub's avatar
zorglub committed
622
623
            if( !b_fetch_art )
            {
ivoire's avatar
ivoire committed
624
                /* If the user doesn't want us to fetch meta automatically
625
626
627
628
629
630
631
                 * abort here. */
                if( p_playlist->p_fetcher->b_fetch_meta )
                {
                    input_MetaFetch( p_playlist, p_item );
                    var_SetInteger( p_playlist, "item-change", p_item->i_id );
                }

632
                /*  Fetch right now */
633
                if( p_playlist->p_fetcher->i_art_policy == ALBUM_ART_ALL )
634
635
636
637
638
                {
                    vlc_mutex_lock( &p_obj->object_lock );
                    preparse_item_t p;
                    p.p_item = p_item;
                    p.b_fetch_art = VLC_TRUE;
639
640
                    INSERT_ELEM( p_playlist->p_fetcher->p_waiting,
                                 p_playlist->p_fetcher->i_waiting,
641
                                 0, p );
ivoire's avatar
ivoire committed
642
                    PL_DEBUG( "meta fetched for %s, get art", p_item->psz_name );
643
                    vlc_mutex_unlock( &p_obj->object_lock );
644
                    continue;
645
646
647
                }
                else
                    vlc_gc_decref( p_item );
zorglub's avatar
zorglub committed
648
649
            }
            else
dionoea's avatar
dionoea committed
650
            {
651
652
653
654
655
                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 ... */
656
                for( i_ret = 0; i_ret < 10 && !input_item_IsPreparsed( p_item ); i_ret++ )
657
658
659
660
661
662
663
664
665
666
                {
                    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 );
                }
667

668
                i_ret = input_ArtFind( p_playlist, p_item );
669
670
                if( i_ret == 1 )
                {
ivoire's avatar
ivoire committed
671
                    PL_DEBUG( "downloading art for %s", p_item->psz_name );
672
                    if( input_DownloadAndCacheArt( p_playlist, p_item ) )
673
                        input_item_SetArtNotFound( p_item, VLC_TRUE );
674
                    else {
675
                        input_item_SetArtFetched( p_item, VLC_TRUE );
676
677
678
                        var_SetInteger( p_playlist, "item-change",
                                        p_item->i_id );
                    }
679
680
681
                }
                else if( i_ret == 0 ) /* Was in cache */
                {
ivoire's avatar
ivoire committed
682
                    PL_DEBUG( "found art for %s in cache", p_item->psz_name );
683
                    input_item_SetArtFetched( p_item, VLC_TRUE );
684
                    var_SetInteger( p_playlist, "item-change", p_item->i_id );
685
686
687
                }
                else
                {
ivoire's avatar
ivoire committed
688
                    PL_DEBUG( "art not found for %s", p_item->psz_name );
689
                    input_item_SetArtNotFound( p_item, VLC_TRUE );
690
                }
691
692
                vlc_gc_decref( p_item );
           }
693
        }
694
        vlc_object_lock( p_obj );
695
696
        i_activity = var_GetInteger( p_playlist, "activity" );
        if( i_activity < 0 ) i_activity = 0;
697
        vlc_object_unlock( p_obj );
698
699
        /* Sleep at least 1ms */
        msleep( (i_activity+1) * 1000 );
700
701
702
    }
}

703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
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" );
736
    var_CreateGetBool( p_playlist, "play-and-exit" );
737
738
739
    var_CreateGetBool( p_playlist, "random" );
    var_CreateGetBool( p_playlist, "repeat" );
    var_CreateGetBool( p_playlist, "loop" );
zorglub's avatar
zorglub committed
740
741

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