engine.c 24.9 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

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static void VariablesInit( playlist_t *p_playlist );
41
static void playlist_Destructor( vlc_object_t * p_this );
42

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

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

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

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

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

76
    p_parent->p_libvlc->p_playlist = p_playlist;
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->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
    ARRAY_INIT( p_playlist->items );
    ARRAY_INIT( p_playlist->all_items );
    ARRAY_INIT( p_playlist->current );
91

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

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

100
101
    p_playlist->b_doing_ml = VLC_FALSE;

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

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

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

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

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

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

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

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

135
136
137
138
139
140
141
        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;
    }
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
154
    b_save = p_playlist->b_auto_preparse;
    p_playlist->b_auto_preparse = VLC_FALSE;
155
    playlist_MLLoad( p_playlist );
156
    p_playlist->b_auto_preparse = VLC_TRUE;
157
158
159

    vlc_object_set_destructor( p_playlist, playlist_Destructor );

160
161
162
    return p_playlist;
}

ivoire's avatar
ivoire committed
163
164
165
166
167
168
169
/**
 * Destroy playlist
 *
 * Destroy a playlist structure.
 * \param p_playlist the playlist object
 * \return nothing
 */
170
171
void playlist_Destroy( playlist_t *p_playlist )
{
172
    /* XXX: should go in the playlist destructor */
173
174
175
    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
176
    var_Destroy( p_playlist, "intf-popupmenu" );
177
178
    var_Destroy( p_playlist, "intf-show" );
    var_Destroy( p_playlist, "play-and-stop" );
179
    var_Destroy( p_playlist, "play-and-exit" );
180
181
182
183
184
    var_Destroy( p_playlist, "random" );
    var_Destroy( p_playlist, "repeat" );
    var_Destroy( p_playlist, "loop" );
    var_Destroy( p_playlist, "activity" );

185
    vlc_object_release( p_playlist );
186
}
187

188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
static void playlist_Destructor( vlc_object_t * p_this )
{
    playlist_t * p_playlist = (playlist_t *)p_this;

    // Kill preparser
    if( p_playlist->p_preparse )
    {
        vlc_object_release( p_playlist->p_preparse );
    }

    // Kill meta fetcher
    if( p_playlist->p_fetcher )
    {
        vlc_object_release( p_playlist->p_fetcher );
    }

    // Stats
    vlc_mutex_destroy( &p_playlist->p_stats->lock );
    if( p_playlist->p_stats )
        free( p_playlist->p_stats );
}

210
/* Destroy remaining objects */
211
static void ObjectGarbageCollector( playlist_t *p_playlist, vlc_bool_t b_force )
212
213
214
{
    vlc_object_t *p_obj;

215
    if( !b_force )
216
    {
217
218
219
220
221
222
223
        if( mdate() - p_playlist->gc_date < 1000000 )
        {
            p_playlist->b_cant_sleep = VLC_TRUE;
            return;
        }
        else if( p_playlist->gc_date == 0 )
            return;
224
    }
225

226
227
228
    vlc_mutex_lock( &p_playlist->gc_lock );
    while( ( p_obj = vlc_object_find( p_playlist, VLC_OBJECT_VOUT,
                                                  FIND_CHILD ) ) )
229
    {
230
        if( p_obj->p_parent != VLC_OBJECT(p_playlist) )
231
232
233
234
235
236
237
238
        {
            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 );
239
    }
240
241
    while( ( p_obj = vlc_object_find( p_playlist, VLC_OBJECT_SOUT,
                                                  FIND_CHILD ) ) )
242
    {
243
        if( p_obj->p_parent != VLC_OBJECT(p_playlist) )
244
        {
245
246
            vlc_object_release( p_obj );
            break;
247
        }
248
249
        msg_Dbg( p_playlist, "garbage collector destroying 1 sout" );
        vlc_object_detach( p_obj );
250
251
        vlc_object_release( p_obj );
        sout_DeleteInstance( (sout_instance_t*)p_obj );
252
    }
253
254
    p_playlist->b_cant_sleep = VLC_FALSE;
    vlc_mutex_unlock( &p_playlist->gc_lock );
255
256
}

ivoire's avatar
ivoire committed
257
258
259
260
261
262
263
/**
 * Main loop
 *
 * Main loop for the playlist
 * \param p_playlist the playlist object
 * \return nothing
 */
264
265
266
void playlist_MainLoop( playlist_t *p_playlist )
{
    playlist_item_t *p_item = NULL;
267
    vlc_bool_t b_playexit = var_GetBool( p_playlist, "play-and-exit" );
268
    PL_LOCK;
269

270
271
    if( p_playlist->b_reset_currently_playing &&
        mdate() - p_playlist->last_rebuild_date > 30000 ) // 30 ms
272
    {
ivoire's avatar
ivoire committed
273
        ResetCurrentlyPlaying( p_playlist, var_GetBool( p_playlist, "random" ),
274
275
                             p_playlist->status.p_item );
        p_playlist->last_rebuild_date = mdate();
276
    }
277

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

288
289
290
291
292
        /* 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
293
            PL_DEBUG( "dead input" );
294
295
296
297
298

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

            /* Release the playlist lock, because we may get stuck
299
             * in vlc_object_release() for some time. */
300
            PL_UNLOCK;
301
302

            /* Destroy input */
303
            vlc_object_release( p_input );
304

305
306
307
308
            PL_LOCK;

            p_playlist->gc_date = mdate();
            p_playlist->b_cant_sleep = VLC_TRUE;
309
310
311
312

            if( p_playlist->status.p_item->i_flags
                & PLAYLIST_REMOVE_FLAG )
            {
zorglub's avatar
zorglub committed
313
314
                 PL_DEBUG( "%s was marked for deletion, deleting",
                                 PLI_NAME( p_playlist->status.p_item  ) );
315
                 playlist_ItemDelete( p_playlist->status.p_item );
316
317
                 if( p_playlist->request.p_item == p_playlist->status.p_item )
                     p_playlist->request.p_item = NULL;
318
319
320
                 p_playlist->status.p_item = NULL;
            }

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

ivoire's avatar
ivoire committed
364
365
            if( p_item == NULL )
            {
366
                msg_Dbg( p_playlist, "nothing to play" );
367
                p_playlist->status.i_status = PLAYLIST_STOPPED;
368
                PL_UNLOCK;
369

370
371
372
                if( b_playexit == VLC_TRUE )
                {
                    msg_Info( p_playlist, "end of playlist, exiting" );
373
                    vlc_object_kill( p_playlist->p_libvlc );
374
                }
375
                ObjectGarbageCollector( p_playlist, VLC_TRUE );
376
377
378
379
380
381
                return;
             }
             playlist_PlayItem( p_playlist, p_item );
         }
         else
         {
382
383
            const vlc_bool_t b_gc_forced = p_playlist->status.i_status != PLAYLIST_STOPPED;

384
385
386
387
388
389
390
391
            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;
            }
392

393
394
            /* Collect garbage */
            PL_UNLOCK;
395
            ObjectGarbageCollector( p_playlist, b_gc_forced );
396
397
            PL_LOCK;
        }
398
    }
399
    PL_UNLOCK;
400
401
}

ivoire's avatar
ivoire committed
402
403
404
405
406
407
408
409

/**
 * Last loop
 *
 * The playlist is dying so do the last loop
 * \param p_playlist the playlist object
 * \return nothing
*/
410
411
412
413
414
415
416
void playlist_LastLoop( playlist_t *p_playlist )
{
    vlc_object_t *p_obj;

    /* If there is an input, kill it */
    while( 1 )
    {
417
        PL_LOCK;
418
419
        if( p_playlist->p_input == NULL )
        {
420
            PL_UNLOCK;
421
422
423
424
425
426
427
428
429
430
            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;
431
            PL_UNLOCK;
432
433

            /* Destroy input */
434
            vlc_object_release( p_input );
435
436
437
438
439
440
441
442
443
444
            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 );
445
            PL_UNLOCK;
446
447
448
449
450
451
            continue;
        }
        else
        {
            p_playlist->p_input->b_eof = 1;
        }
452
        PL_UNLOCK;
453
454
455
456
457
458
459
460

        msleep( INTF_IDLE_SLEEP );
    }

    /* close all remaining sout */
    while( ( p_obj = vlc_object_find( p_playlist,
                                      VLC_OBJECT_SOUT, FIND_CHILD ) ) )
    {
461
        vlc_object_detach( p_obj );
462
463
464
465
466
467
468
469
470
471
472
473
        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 );
    }
474

475
    while( p_playlist->i_sds )
476
477
    {
        playlist_ServicesDiscoveryRemove( p_playlist,
478
                                          p_playlist->pp_sds[0]->p_sd->psz_module );
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
    }

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

    ARRAY_RESET( p_playlist->items );
    ARRAY_RESET( p_playlist->current );

    PL_UNLOCK;
497
498
}

ivoire's avatar
ivoire committed
499
500
501
502
503
504
505
/**
 * Preparse loop
 *
 * Main loop for preparser queue
 * \param p_obj items to preparse
 * \return nothing
 */
506
507
508
void playlist_PreparseLoop( playlist_preparse_t *p_obj )
{
    playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
509
    input_item_t *p_current;
510
    int i_activity;
zorglub's avatar
zorglub committed
511
    uint32_t i_m, i_o;
512

513
    while( !p_playlist->b_die )
514
    {
515
        vlc_object_lock( p_obj );
516
517
        while( p_obj->i_waiting == 0 )
        {
518
            if( vlc_object_wait( p_obj ) || p_playlist->b_die )
519
            {
520
                vlc_object_unlock( p_obj );
521
522
523
                return;
            }
        }
524

525
        p_current = p_obj->pp_waiting[0];
526
        REMOVE_ELEM( p_obj->pp_waiting, p_obj->i_waiting, 0 );
527
        vlc_object_unlock( p_obj );
528

zorglub's avatar
zorglub committed
529
        PL_LOCK;
530
531
        if( p_current )
        {
532
            if( p_current->i_type == ITEM_TYPE_FILE )
533
534
535
            {
                stats_TimerStart( p_playlist, "Preparse run",
                                  STATS_TIMER_PREPARSE );
536
                /* Do not preparse if it is already done (like by playing it) */
537
                if( !input_item_IsPreparsed( p_current ) )
538
539
540
541
542
                {
                    PL_UNLOCK;
                    input_Preparse( p_playlist, p_current );
                    PL_LOCK;
                }
543
                stats_TimerStop( p_playlist, STATS_TIMER_PREPARSE );
544
                PL_UNLOCK;
545
                input_item_SetPreparsed( p_current, VLC_TRUE );
zorglub's avatar
zorglub committed
546
                var_SetInteger( p_playlist, "item-change", p_current->i_id );
547
                PL_LOCK;
548
            }
zorglub's avatar
zorglub committed
549
            /* If we haven't retrieved enough meta, add to secondary queue
550
551
552
             * 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
553
             */
Rafaël Carré's avatar
Rafaël Carré committed
554
555
            char *psz_arturl = input_item_GetArtURL( p_current );
            char *psz_name = input_item_GetName( p_current );
556
            if( !input_MetaSatisfied( p_playlist, p_current, &i_m, &i_o ) )
zorglub's avatar
zorglub committed
557
558
            {
                preparse_item_t p;
ivoire's avatar
ivoire committed
559
                PL_DEBUG( "need to fetch meta for %s", p_current->psz_name );
dionoea's avatar
dionoea committed
560
561
                p.p_item = p_current;
                p.b_fetch_art = VLC_FALSE;
562
                vlc_object_lock( p_playlist->p_fetcher );
563
564
                INSERT_ELEM( p_playlist->p_fetcher->p_waiting,
                             p_playlist->p_fetcher->i_waiting,
565
                             p_playlist->p_fetcher->i_waiting, p);
566
567
                vlc_object_signal_unlocked( p_playlist->p_fetcher );
                vlc_object_unlock( p_playlist->p_fetcher );
568
569
            }
            /* We already have all needed meta, but we need art right now */
570
            else if( p_playlist->p_fetcher->i_art_policy == ALBUM_ART_ALL &&
571
                        ( !psz_arturl || strncmp( psz_arturl, "file://", 7 ) ) )
572
573
            {
                preparse_item_t p;
Rafaël Carré's avatar
Rafaël Carré committed
574
                PL_DEBUG("meta ok for %s, need to fetch art", psz_name );
575
576
                p.p_item = p_current;
                p.b_fetch_art = VLC_TRUE;
577
                vlc_object_lock( p_playlist->p_fetcher );
578
579
580
                INSERT_ELEM( p_playlist->p_fetcher->p_waiting,
                             p_playlist->p_fetcher->i_waiting,
                             p_playlist->p_fetcher->i_waiting, p);
581
582
                vlc_object_signal_unlocked( p_playlist->p_fetcher );
                vlc_object_unlock( p_playlist->p_fetcher );
zorglub's avatar
zorglub committed
583
            }
584
            else
585
586
            {
                PL_DEBUG( "no fetch required for %s (art currently %s)",
Rafaël Carré's avatar
Rafaël Carré committed
587
                          psz_name, psz_arturl );
zorglub's avatar
zorglub committed
588
                vlc_gc_decref( p_current );
589
            }
Rafaël Carré's avatar
Rafaël Carré committed
590
591
            free( psz_name );
            free( psz_arturl );
592
            PL_UNLOCK;
593
594
        }
        else
595
596
            PL_UNLOCK;

597
        vlc_object_lock( p_obj );
598
        i_activity = var_GetInteger( p_playlist, "activity" );
599
        if( i_activity < 0 ) i_activity = 0;
600
        vlc_object_unlock( p_obj );
601
        /* Sleep at least 1ms */
602
603
604
605
        msleep( (i_activity+1) * 1000 );
    }
}

ivoire's avatar
ivoire committed
606
607
608
609
610
611
612
/**
 * Fetcher loop
 *
 * Main loop for secondary preparser queue
 * \param p_obj items to preparse
 * \return nothing
 */
613
void playlist_FetcherLoop( playlist_fetcher_t *p_obj )
614
615
{
    playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
616
617
618
    vlc_bool_t b_fetch_art;
    input_item_t *p_item;
    int i_activity;
619

620
    while( !p_playlist->b_die )
621
    {
622
623
624
625
626
627
628
629
630
631
632
633
634
        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
635
        REMOVE_ELEM( p_obj->p_waiting, p_obj->i_waiting, 0 );
636
        vlc_mutex_unlock( &p_obj->object_lock );
dionoea's avatar
dionoea committed
637
        if( p_item )
638
        {
zorglub's avatar
zorglub committed
639
640
            if( !b_fetch_art )
            {
ivoire's avatar
ivoire committed
641
                /* If the user doesn't want us to fetch meta automatically
642
643
644
645
646
647
648
                 * 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 );
                }

649
                /*  Fetch right now */
650
                if( p_playlist->p_fetcher->i_art_policy == ALBUM_ART_ALL )
651
652
653
654
655
                {
                    vlc_mutex_lock( &p_obj->object_lock );
                    preparse_item_t p;
                    p.p_item = p_item;
                    p.b_fetch_art = VLC_TRUE;
656
657
                    INSERT_ELEM( p_playlist->p_fetcher->p_waiting,
                                 p_playlist->p_fetcher->i_waiting,
658
                                 0, p );
ivoire's avatar
ivoire committed
659
                    PL_DEBUG( "meta fetched for %s, get art", p_item->psz_name );
660
                    vlc_mutex_unlock( &p_obj->object_lock );
661
                    continue;
662
663
664
                }
                else
                    vlc_gc_decref( p_item );
zorglub's avatar
zorglub committed
665
666
            }
            else
dionoea's avatar
dionoea committed
667
            {
668
669
670
671
672
                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 ... */
673
                for( i_ret = 0; i_ret < 10 && !input_item_IsPreparsed( p_item ); i_ret++ )
674
675
676
677
678
679
680
681
682
683
                {
                    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 );
                }
684

685
                i_ret = input_ArtFind( p_playlist, p_item );
686
687
                if( i_ret == 1 )
                {
ivoire's avatar
ivoire committed
688
                    PL_DEBUG( "downloading art for %s", p_item->psz_name );
689
                    if( input_DownloadAndCacheArt( p_playlist, p_item ) )
690
                        input_item_SetArtNotFound( p_item, VLC_TRUE );
691
                    else {
692
                        input_item_SetArtFetched( p_item, VLC_TRUE );
693
694
695
                        var_SetInteger( p_playlist, "item-change",
                                        p_item->i_id );
                    }
696
697
698
                }
                else if( i_ret == 0 ) /* Was in cache */
                {
ivoire's avatar
ivoire committed
699
                    PL_DEBUG( "found art for %s in cache", p_item->psz_name );
700
                    input_item_SetArtFetched( p_item, VLC_TRUE );
701
                    var_SetInteger( p_playlist, "item-change", p_item->i_id );
702
703
704
                }
                else
                {
ivoire's avatar
ivoire committed
705
                    PL_DEBUG( "art not found for %s", p_item->psz_name );
706
                    input_item_SetArtNotFound( p_item, VLC_TRUE );
707
                }
708
709
                vlc_gc_decref( p_item );
           }
710
        }
711
        vlc_object_lock( p_obj );
712
713
        i_activity = var_GetInteger( p_playlist, "activity" );
        if( i_activity < 0 ) i_activity = 0;
714
        vlc_object_unlock( p_obj );
715
716
        /* Sleep at least 1ms */
        msleep( (i_activity+1) * 1000 );
717
718
719
    }
}

720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
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" );
753
    var_CreateGetBool( p_playlist, "play-and-exit" );
754
755
756
    var_CreateGetBool( p_playlist, "random" );
    var_CreateGetBool( p_playlist, "repeat" );
    var_CreateGetBool( p_playlist, "loop" );
zorglub's avatar
zorglub committed
757
758

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