engine.c 25.4 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
/**
 * 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 )
{
62
    static const char playlist_name[] = "playlist";
63
    playlist_t *p_playlist;
64
    vlc_bool_t b_save;
65
    int i_tree;
66
67

    /* Allocate structure */
68
69
    p_playlist = vlc_custom_create( p_parent, sizeof( *p_playlist ),
                                    VLC_OBJECT_PLAYLIST, playlist_name );
70
71
72
73
74
    if( !p_playlist )
    {
        msg_Err( p_parent, "out of memory" );
        return NULL;
    }
75

76
    TAB_INIT( p_playlist->i_sds, p_playlist->pp_sds );
77

78
    p_parent->p_libvlc->p_playlist = p_playlist;
79
80
81
82
83
84
85
86

    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;

87
88
    p_playlist->gc_date = 0;
    p_playlist->b_cant_sleep = VLC_FALSE;
89

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

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

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

102
103
    p_playlist->b_doing_ml = VLC_FALSE;

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

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

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

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

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

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

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

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

137
138
139
140
141
142
143
        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;
    }
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
156
    b_save = p_playlist->b_auto_preparse;
    p_playlist->b_auto_preparse = VLC_FALSE;
157
    playlist_MLLoad( p_playlist );
158
    p_playlist->b_auto_preparse = VLC_TRUE;
159
160
161

    vlc_object_set_destructor( p_playlist, playlist_Destructor );

162
163
164
    return p_playlist;
}

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

187
    vlc_object_release( p_playlist );
188
}
189

190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
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 );
    }
}

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

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

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

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

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

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

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

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

            /* Release the playlist lock, because we may get stuck
296
             * in vlc_object_release() for some time. */
297
            PL_UNLOCK;
298
299

            /* Destroy input */
300
            vlc_object_release( p_input );
301

302
303
304
305
            PL_LOCK;

            p_playlist->gc_date = mdate();
            p_playlist->b_cant_sleep = VLC_TRUE;
306
307
308
309

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

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

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

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

381
382
383
384
385
386
387
388
            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;
            }
389

390
391
            /* Collect garbage */
            PL_UNLOCK;
392
            ObjectGarbageCollector( p_playlist, b_gc_forced );
393
394
            PL_LOCK;
        }
395
    }
396
    PL_UNLOCK;
397
398
}

399
static void recursively_decref( playlist_item_t *p_node )
400
{
401
402
    vlc_gc_decref( p_node->p_input );

403
404
405
    int i;
    if( p_node->i_children > 0 )
        for( i = 0 ; i < p_node->i_children ; i++ )
406
            recursively_decref( p_node->pp_children[i] );
407
}
ivoire's avatar
ivoire committed
408
409
410
411
412
413
414
415

/**
 * Last loop
 *
 * The playlist is dying so do the last loop
 * \param p_playlist the playlist object
 * \return nothing
*/
416
417
418
419
420
421
422
void playlist_LastLoop( playlist_t *p_playlist )
{
    vlc_object_t *p_obj;

    /* If there is an input, kill it */
    while( 1 )
    {
423
        PL_LOCK;
424
425
        if( p_playlist->p_input == NULL )
        {
426
            PL_UNLOCK;
427
428
429
430
431
432
433
434
435
436
            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;
437
            PL_UNLOCK;
438
439

            /* Destroy input */
440
            vlc_object_release( p_input );
441
442
443
444
445
446
447
448
449
450
            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 );
451
            PL_UNLOCK;
452
453
454
455
456
457
            continue;
        }
        else
        {
            p_playlist->p_input->b_eof = 1;
        }
458
        PL_UNLOCK;
459
460
461
462
463
464
465
466

        msleep( INTF_IDLE_SLEEP );
    }

    /* close all remaining sout */
    while( ( p_obj = vlc_object_find( p_playlist,
                                      VLC_OBJECT_SOUT, FIND_CHILD ) ) )
    {
467
        vlc_object_detach( p_obj );
468
469
470
471
472
473
474
475
476
477
478
479
        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 );
    }
480

481
    while( p_playlist->i_sds )
482
483
    {
        playlist_ServicesDiscoveryRemove( p_playlist,
484
                                          p_playlist->pp_sds[0]->p_sd->psz_module );
485
486
487
    }

    playlist_MLDump( p_playlist );
488
    /* We don't need the media library anymore */
489
490
491
492
493
494
495
496

    /* Because this nasty recursive function decreases the
     * p_playlist->p_ml_category refcount, it may get deleted.
     * However we will delete the p_playlist->p_ml_category in the
     * following FOREACH. */
    vlc_gc_incref( p_playlist->p_ml_category );

    /* Decref all subitems, and the given items */
497
    recursively_decref( p_playlist->p_ml_category );
498
499
500
501

    PL_LOCK;
    FOREACH_ARRAY( playlist_item_t *p_del, p_playlist->all_items )
        free( p_del->pp_children );
Rafaël Carré's avatar
Rafaël Carré committed
502
        vlc_gc_decref( p_del->p_input );
503
504
505
506
507
508
509
510
        free( p_del );
    FOREACH_END();
    ARRAY_RESET( p_playlist->all_items );

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

    PL_UNLOCK;
511
512
}

ivoire's avatar
ivoire committed
513
514
515
516
517
518
519
/**
 * Preparse loop
 *
 * Main loop for preparser queue
 * \param p_obj items to preparse
 * \return nothing
 */
520
521
522
void playlist_PreparseLoop( playlist_preparse_t *p_obj )
{
    playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
523
    input_item_t *p_current;
524
    int i_activity;
zorglub's avatar
zorglub committed
525
    uint32_t i_m, i_o;
526

527
    while( !p_playlist->b_die )
528
    {
529
        vlc_object_lock( p_obj );
530
531
        while( p_obj->i_waiting == 0 )
        {
532
            if( vlc_object_wait( p_obj ) || p_playlist->b_die )
533
            {
534
                vlc_object_unlock( p_obj );
535
536
537
                return;
            }
        }
538

539
        p_current = p_obj->pp_waiting[0];
540
        REMOVE_ELEM( p_obj->pp_waiting, p_obj->i_waiting, 0 );
541
        vlc_object_unlock( p_obj );
542

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

611
        vlc_object_lock( p_obj );
612
        i_activity = var_GetInteger( p_playlist, "activity" );
613
        if( i_activity < 0 ) i_activity = 0;
614
        vlc_object_unlock( p_obj );
615
        /* Sleep at least 1ms */
616
617
618
619
        msleep( (i_activity+1) * 1000 );
    }
}

ivoire's avatar
ivoire committed
620
621
622
623
624
625
626
/**
 * Fetcher loop
 *
 * Main loop for secondary preparser queue
 * \param p_obj items to preparse
 * \return nothing
 */
627
void playlist_FetcherLoop( playlist_fetcher_t *p_obj )
628
629
{
    playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
630
631
632
    vlc_bool_t b_fetch_art;
    input_item_t *p_item;
    int i_activity;
633

634
    while( !p_playlist->b_die )
635
    {
636
637
638
639
640
641
642
643
644
645
646
647
648
        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
649
        REMOVE_ELEM( p_obj->p_waiting, p_obj->i_waiting, 0 );
650
        vlc_mutex_unlock( &p_obj->object_lock );
dionoea's avatar
dionoea committed
651
        if( p_item )
652
        {
zorglub's avatar
zorglub committed
653
654
            if( !b_fetch_art )
            {
ivoire's avatar
ivoire committed
655
                /* If the user doesn't want us to fetch meta automatically
656
657
658
659
660
661
662
                 * 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 );
                }

663
                /*  Fetch right now */
664
                if( p_playlist->p_fetcher->i_art_policy == ALBUM_ART_ALL )
665
666
667
668
669
                {
                    vlc_mutex_lock( &p_obj->object_lock );
                    preparse_item_t p;
                    p.p_item = p_item;
                    p.b_fetch_art = VLC_TRUE;
670
671
                    INSERT_ELEM( p_playlist->p_fetcher->p_waiting,
                                 p_playlist->p_fetcher->i_waiting,
672
                                 0, p );
ivoire's avatar
ivoire committed
673
                    PL_DEBUG( "meta fetched for %s, get art", p_item->psz_name );
674
                    vlc_mutex_unlock( &p_obj->object_lock );
675
                    continue;
676
677
678
                }
                else
                    vlc_gc_decref( p_item );
zorglub's avatar
zorglub committed
679
680
            }
            else
dionoea's avatar
dionoea committed
681
            {
682
683
684
685
686
                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 ... */
687
                for( i_ret = 0; i_ret < 10 && !input_item_IsPreparsed( p_item ); i_ret++ )
688
689
690
691
692
693
694
695
696
697
                {
                    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 );
                }
698

699
                i_ret = input_ArtFind( p_playlist, p_item );
700
701
                if( i_ret == 1 )
                {
ivoire's avatar
ivoire committed
702
                    PL_DEBUG( "downloading art for %s", p_item->psz_name );
703
                    if( input_DownloadAndCacheArt( p_playlist, p_item ) )
704
                        input_item_SetArtNotFound( p_item, VLC_TRUE );
705
                    else {
706
                        input_item_SetArtFetched( p_item, VLC_TRUE );
707
708
709
                        var_SetInteger( p_playlist, "item-change",
                                        p_item->i_id );
                    }
710
711
712
                }
                else if( i_ret == 0 ) /* Was in cache */
                {
ivoire's avatar
ivoire committed
713
                    PL_DEBUG( "found art for %s in cache", p_item->psz_name );
714
                    input_item_SetArtFetched( p_item, VLC_TRUE );
715
                    var_SetInteger( p_playlist, "item-change", p_item->i_id );
716
717
718
                }
                else
                {
ivoire's avatar
ivoire committed
719
                    PL_DEBUG( "art not found for %s", p_item->psz_name );
720
                    input_item_SetArtNotFound( p_item, VLC_TRUE );
721
                }
722
723
                vlc_gc_decref( p_item );
           }
724
        }
725
        vlc_object_lock( p_obj );
726
727
        i_activity = var_GetInteger( p_playlist, "activity" );
        if( i_activity < 0 ) i_activity = 0;
728
        vlc_object_unlock( p_obj );
729
730
        /* Sleep at least 1ms */
        msleep( (i_activity+1) * 1000 );
731
732
733
    }
}

734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
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" );
767
    var_CreateGetBool( p_playlist, "play-and-exit" );
768
769
770
    var_CreateGetBool( p_playlist, "random" );
    var_CreateGetBool( p_playlist, "repeat" );
    var_CreateGetBool( p_playlist, "loop" );
zorglub's avatar
zorglub committed
771
772

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