engine.c 25.2 KB
Newer Older
1
2
3
/*****************************************************************************
 * engine.c : Run the playlist and handle its control
 *****************************************************************************
4
 * Copyright (C) 1999-2007 the VideoLAN team
dionoea's avatar
2nd try    
dionoea committed
5
 * $Id$
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 *
 * Authors: Samuel Hocevar <sam@zoy.org>
 *          Clément Stenac <zorglub@videolan.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/
24

25
#include <vlc/vlc.h>
zorglub's avatar
zorglub committed
26
27
28
29
#include <vlc_vout.h>
#include <vlc_sout.h>
#include <vlc_playlist.h>
#include <vlc_interface.h>
30
#include "playlist_internal.h"
zorglub's avatar
zorglub committed
31
#include "stream_output/stream_output.h" /* sout_DeleteInstance */
32
33
34
35
36
37

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

zorglub's avatar
zorglub committed
38
39
40
static int RandomCallback( vlc_object_t *p_this, char const *psz_cmd,
                           vlc_value_t oldval, vlc_value_t newval, void *a )
{
41
42
    (void)psz_cmd; (void)oldval; (void)newval; (void)a;

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

48
49
50
51
52
53
54
55
56
57
/**
 * Create playlist
 *
 * Create a playlist structure.
 * \param p_parent the vlc object that is to be the parent of this playlist
 * \return a pointer to the created playlist, or NULL on error
 */
playlist_t * playlist_Create( vlc_object_t *p_parent )
{
    playlist_t *p_playlist;
58
    vlc_bool_t b_save;
59
    int i_tree;
60
61
62
63
64
65
66
67

    /* Allocate structure */
    p_playlist = vlc_object_create( p_parent, VLC_OBJECT_PLAYLIST );
    if( !p_playlist )
    {
        msg_Err( p_parent, "out of memory" );
        return NULL;
    }
68
    p_parent->p_libvlc->p_playlist = p_playlist;
69
70
71
72
73
74
75
76
77

    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;

78
79
    p_playlist->gc_date = 0;
    p_playlist->b_cant_sleep = VLC_FALSE;
80

zorglub's avatar
zorglub committed
81
82
83
84
    ARRAY_INIT( p_playlist->items );
    ARRAY_INIT( p_playlist->all_items );
    ARRAY_INIT( p_playlist->input_items );
    ARRAY_INIT( p_playlist->current );
85

zorglub's avatar
zorglub committed
86
87
    p_playlist->i_current_index = 0;
    p_playlist->b_reset_currently_playing = VLC_TRUE;
88
    p_playlist->last_rebuild_date = 0;
zorglub's avatar
zorglub committed
89

90
91
92
93
    i_tree = var_CreateGetBool( p_playlist, "playlist-tree" );
    p_playlist->b_always_tree = (i_tree == 1);
    p_playlist->b_never_tree = (i_tree == 2);

94
95
    p_playlist->b_doing_ml = VLC_FALSE;

96
97
98
    p_playlist->b_auto_preparse =
                        var_CreateGetBool( p_playlist, "auto-preparse") ;

99
100
101
102
    p_playlist->p_root_category = playlist_NodeCreate( p_playlist, NULL, NULL,
                                                       0 );
    p_playlist->p_root_onelevel = playlist_NodeCreate( p_playlist, NULL, NULL,
                                                       0 );
103

104
105
106
    if( !p_playlist->p_root_category || !p_playlist->p_root_onelevel )
        return NULL;

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

115
116
117
118
119
    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;

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

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

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

134
135
136
137
        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;
138

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

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

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
161
162
163
164
165
166
167
168
    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" );
169
    var_Destroy( p_playlist, "play-and-exit" );
170
171
172
173
174
175
    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 );
176
    vlc_object_detach( p_playlist );
177
178
    vlc_object_destroy( p_playlist );
}
179

180
/* Destroy remaining objects */
181
static void ObjectGarbageCollector( playlist_t *p_playlist, vlc_bool_t b_force )
182
183
184
{
    vlc_object_t *p_obj;

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

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

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

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

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

252
253
254
255
256
        /* 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
257
            PL_DEBUG( "dead input" );
258
259
260
261
262
263
264
265
266
267
268

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

269
270
271
272
            PL_LOCK;

            p_playlist->gc_date = mdate();
            p_playlist->b_cant_sleep = VLC_TRUE;
273
274
275
276

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

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

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

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

351
352
353
354
355
356
357
358
            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;
            }
359

360
361
            /* Collect garbage */
            PL_UNLOCK;
362
            ObjectGarbageCollector( p_playlist, b_gc_forced );
363
364
            PL_LOCK;
        }
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
414
415
416
417
418
419
420
421
422
    }
    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 ) ) )
    {
423
        vlc_object_detach( p_obj );
424
425
426
427
428
429
430
431
432
433
434
435
        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 );
    }
436

437
    while( p_playlist->i_asds )
438
439
    {
        playlist_ServicesDiscoveryRemove( p_playlist,
440
                                          p_playlist->pp_asds[0]->p_sd->psz_module );
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
    }

    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;
465
466
467
468
469
470
}

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

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

zorglub's avatar
zorglub committed
492
        PL_LOCK;
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
        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 );
508
                /* Do not preparse if it is already done (like by playing it) */
509
                if( !input_item_IsPreparsed( p_current ) )
510
511
512
513
514
                {
                    PL_UNLOCK;
                    input_Preparse( p_playlist, p_current );
                    PL_LOCK;
                }
515
516
                stats_TimerStop( p_playlist, STATS_TIMER_PREPARSE );
            }
zorglub's avatar
zorglub committed
517
            PL_UNLOCK;
518
519
            if( b_preparsed )
            {
520
                input_item_SetPreparsed( p_current, VLC_TRUE );
zorglub's avatar
zorglub committed
521
                var_SetInteger( p_playlist, "item-change", p_current->i_id );
522
            }
523
            PL_LOCK;
524

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

573
        vlc_mutex_lock( &p_obj->object_lock );
574
        i_activity = var_GetInteger( p_playlist, "activity" );
575
        if( i_activity < 0 ) i_activity = 0;
zorglub's avatar
zorglub committed
576
        vlc_mutex_unlock( &p_obj->object_lock );
577
        /* Sleep at least 1ms */
578
579
580
581
        msleep( (i_activity+1) * 1000 );
    }
}

582
/** Main loop for secondary preparser queue */
583
void playlist_FetcherLoop( playlist_fetcher_t *p_obj )
584
585
{
    playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
586
587
588
    vlc_bool_t b_fetch_art;
    input_item_t *p_item;
    int i_activity;
589

590
    while( !p_playlist->b_die )
591
    {
592
593
594
595
596
597
598
599
600
601
602
603
604
        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
605
        REMOVE_ELEM( p_obj->p_waiting, p_obj->i_waiting, 0 );
606
        vlc_mutex_unlock( &p_obj->object_lock );
dionoea's avatar
dionoea committed
607
        if( p_item )
608
        {
zorglub's avatar
zorglub committed
609
610
611
            if( !b_fetch_art )
            {
                input_MetaFetch( p_playlist, p_item );
612
613
                var_SetInteger( p_playlist, "item-change", p_item->i_id );
                /*  Fetch right now */
614
                if( p_playlist->p_fetcher->i_art_policy == ALBUM_ART_ALL )
615
616
617
618
619
                {
                    vlc_mutex_lock( &p_obj->object_lock );
                    preparse_item_t p;
                    p.p_item = p_item;
                    p.b_fetch_art = VLC_TRUE;
620
621
                    INSERT_ELEM( p_playlist->p_fetcher->p_waiting,
                                 p_playlist->p_fetcher->i_waiting,
622
                                 0, p );
623
                    PL_DEBUG("meta fetched for %s, get art", p_item->psz_name);
624
                    vlc_mutex_unlock( &p_obj->object_lock );
625
                    continue;
626
627
628
                }
                else
                    vlc_gc_decref( p_item );
zorglub's avatar
zorglub committed
629
630
            }
            else
dionoea's avatar
dionoea committed
631
            {
632
633
634
635
636
                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 ... */
637
                for( i_ret = 0; i_ret < 10 && !input_item_IsPreparsed( p_item ); i_ret++ )
638
639
640
641
642
643
644
645
646
647
648
649
                {
                    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 );
                }
                
                i_ret = input_ArtFind( p_playlist, p_item );
650
651
652
                if( i_ret == 1 )
                {
                    PL_DEBUG("downloading art for %s", p_item->psz_name );
653
                    if( input_DownloadAndCacheArt( p_playlist, p_item ) )
654
                        input_item_SetArtNotFound( p_item, VLC_TRUE );
655
                    else {
656
                        input_item_SetArtFetched( p_item, VLC_TRUE );
657
658
659
                        var_SetInteger( p_playlist, "item-change",
                                        p_item->i_id );
                    }
660
661
662
663
                }
                else if( i_ret == 0 ) /* Was in cache */
                {
                    PL_DEBUG("found art for %s in cache", p_item->psz_name );
664
                    input_item_SetArtFetched( p_item, VLC_TRUE );
665
                    var_SetInteger( p_playlist, "item-change", p_item->i_id );
666
667
668
669
                }
                else
                {
                    PL_DEBUG("art not found for %s", p_item->psz_name );
670
                    input_item_SetArtNotFound( p_item, VLC_TRUE );
671
                }
672
673
                vlc_gc_decref( p_item );
           }
674
        }
675
676
677
678
679
680
        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 );
681
682
683
    }
}

684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
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" );
717
    var_CreateGetBool( p_playlist, "play-and-exit" );
718
719
720
    var_CreateGetBool( p_playlist, "random" );
    var_CreateGetBool( p_playlist, "repeat" );
    var_CreateGetBool( p_playlist, "loop" );
zorglub's avatar
zorglub committed
721
722

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