engine.c 21.6 KB
Newer Older
1
2
3
4
/*****************************************************************************
 * engine.c : Run the playlist and handle its control
 *****************************************************************************
 * Copyright (C) 1999-2004 the VideoLAN team
dionoea's avatar
2nd try    
dionoea committed
5
 * $Id$
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 *
 * 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.
 *****************************************************************************/
#include <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/sout.h>
#include <vlc/input.h>
#include "vlc_playlist.h"
#include "vlc_interaction.h"
30
#include "playlist_internal.h"
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

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

/**
 * 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;
47
    int i_tree;
48
49
50
51
52
53
54
55

    /* Allocate structure */
    p_playlist = vlc_object_create( p_parent, VLC_OBJECT_PLAYLIST );
    if( !p_playlist )
    {
        msg_Err( p_parent, "out of memory" );
        return NULL;
    }
56
    p_parent->p_libvlc->p_playlist = p_playlist;
57
58
59
60
61
62
63
64
65

    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;

66
67
68
    p_playlist->i_vout_destroyed_date = 0;
    p_playlist->i_sout_destroyed_date = 0;

69
70
71
72
73
74
75
76
    p_playlist->i_size = 0;
    p_playlist->pp_items = NULL;
    p_playlist->i_all_size = 0;
    p_playlist->pp_all_items = NULL;

    p_playlist->i_input_items = 0;
    p_playlist->pp_input_items = NULL;

zorglub's avatar
zorglub committed
77
78
79
80
81
    p_playlist->i_random = 0;
    p_playlist->pp_random = NULL;
    p_playlist->i_random_index = 0;
    p_playlist->b_reset_random = VLC_TRUE;

82
83
84
85
    i_tree = var_CreateGetBool( p_playlist, "playlist-tree" );
    p_playlist->b_always_tree = (i_tree == 1);
    p_playlist->b_never_tree = (i_tree == 2);

86
87
    p_playlist->b_doing_ml = VLC_FALSE;

88
89
90
91
92
93
94
95
    p_playlist->p_root_category = playlist_NodeCreate( p_playlist, NULL, NULL);
    p_playlist->p_root_onelevel = playlist_NodeCreate( p_playlist, NULL, NULL);

    /* Create playlist and media library */
    p_playlist->p_local_category = playlist_NodeCreate( p_playlist,
                                 _( "Playlist" ),p_playlist->p_root_category );
    p_playlist->p_local_onelevel =  playlist_NodeCreate( p_playlist,
                                _( "Playlist" ), p_playlist->p_root_onelevel );
96
97
98
    p_playlist->p_local_category->i_flags |= PLAYLIST_RO_FLAG;
    p_playlist->p_local_onelevel->i_flags |= PLAYLIST_RO_FLAG;

99
    /* Link the nodes together. Todo: actually create them from the same input*/
100
101
    p_playlist->p_local_onelevel->p_input->i_id =
        p_playlist->p_local_category->p_input->i_id;
102
103
104
105
106
107
108
109
110
111
112

    if( config_GetInt( p_playlist, "media-library") )
    {
        p_playlist->p_ml_category =   playlist_NodeCreate( p_playlist,
                           _( "Media Library" ), p_playlist->p_root_category );
        p_playlist->p_ml_onelevel =  playlist_NodeCreate( p_playlist,
                           _( "Media Library" ), p_playlist->p_root_onelevel );
        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;
113

114
115
116
117
118
    }
    else
    {
        p_playlist->p_ml_category = p_playlist->p_ml_onelevel = NULL;
    }
119
120
121

    /* Initial status */
    p_playlist->status.p_item = NULL;
122
    p_playlist->status.p_node = p_playlist->p_local_onelevel;
123
124
125
126
127
128
129
    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;

    vlc_object_attach( p_playlist, p_parent );
130
131

    playlist_MLLoad( p_playlist );
132
133
134
135
136
137
138
139
140
141
    return p_playlist;
}

void playlist_Destroy( playlist_t *p_playlist )
{
    while( p_playlist->i_sds )
    {
        playlist_ServicesDiscoveryRemove( p_playlist,
                                          p_playlist->pp_sds[0]->psz_module );
    }
142
143
144

    playlist_MLDump( p_playlist );

145
    vlc_thread_join( p_playlist->p_preparse );
146
    vlc_thread_join( p_playlist->p_secondary_preparse );
147
148
149
    vlc_thread_join( p_playlist );

    vlc_object_detach( p_playlist->p_preparse );
150
    vlc_object_detach( p_playlist->p_secondary_preparse );
151
152
153
154
155
156
157

    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" );
158
    var_Destroy( p_playlist, "play-and-exit" );
159
160
161
162
163
    var_Destroy( p_playlist, "random" );
    var_Destroy( p_playlist, "repeat" );
    var_Destroy( p_playlist, "loop" );
    var_Destroy( p_playlist, "activity" );

164
165
166
167
168
169
    PL_LOCK;
    playlist_NodeDelete( p_playlist, p_playlist->p_root_category, VLC_TRUE,
                         VLC_TRUE );
    playlist_NodeDelete( p_playlist, p_playlist->p_root_onelevel, VLC_TRUE,
                         VLC_TRUE );
    PL_UNLOCK;
170
171
172
173
174
175

    if( p_playlist->p_stats )
        free( p_playlist->p_stats );

    vlc_mutex_destroy( &p_playlist->gc_lock );
    vlc_object_destroy( p_playlist->p_preparse );
176
    vlc_object_destroy( p_playlist->p_secondary_preparse );
177
    vlc_object_detach( p_playlist );
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
    vlc_object_destroy( p_playlist );

}
/* Destroy remaining objects */
static mtime_t ObjectGarbageCollector( playlist_t *p_playlist, int i_type,
                                       mtime_t destroy_date )
{
    vlc_object_t *p_obj;

    if( destroy_date > mdate() ) return destroy_date;

    if( destroy_date == 0 )
    {
        /* give a little time */
        return mdate() + I64C(1000000);
    }
    else
    {
        vlc_mutex_lock( &p_playlist->gc_lock );
        while( ( p_obj = vlc_object_find( p_playlist, i_type, FIND_CHILD ) ) )
        {
            if( p_obj->p_parent != (vlc_object_t*)p_playlist )
            {
                /* only first child (ie unused) */
                vlc_object_release( p_obj );
                break;
            }
            if( i_type == VLC_OBJECT_VOUT )
            {
                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 );
            }
            else if( i_type == VLC_OBJECT_SOUT )
            {
                vlc_object_release( p_obj );
                sout_DeleteInstance( (sout_instance_t*)p_obj );
            }
        }
        vlc_mutex_unlock( &p_playlist->gc_lock );
        return 0;
    }
}

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

    /* First, check if we have something to do */
    /* FIXME : this can be called several times */
    if( p_playlist->request.b_request )
    {
        /* Stop the existing input */
235
        if( p_playlist->p_input && !p_playlist->p_input->b_die )
236
        {
237
            PL_DEBUG( "incoming request - stopping current input" );
238
239
240
241
242
243
244
245
246
247
248
249
            input_StopThread( p_playlist->p_input );
        }
    }

    /* If there is an input, check that it doesn't need to die. */
    if( p_playlist->p_input )
    {
        /* 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
250
            PL_DEBUG( "dead input" );
251
252
253
254
255
256
257
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 );

            /* Unlink current input
             * (_after_ input_DestroyThread for vout garbage collector) */
            vlc_object_detach( p_input );

            /* Destroy object */
            vlc_object_destroy( p_input );

269
270
            p_playlist->i_vout_destroyed_date = 0;
            p_playlist->i_sout_destroyed_date = 0;
271
272
273
274

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

            i_activity= var_GetInteger( p_playlist, "activity") ;
            var_SetInteger( p_playlist, "activity", i_activity -
                            DEFAULT_INPUT_ACTIVITY );

            return;
        }
        /* This input is dying, let it do */
        else if( p_playlist->p_input->b_die )
        {
zorglub's avatar
zorglub committed
292
            PL_DEBUG( "dying input" );
293
294
295
296
297
        }
        /* This input has finished, ask it to die ! */
        else if( p_playlist->p_input->b_error
                  || p_playlist->p_input->b_eof )
        {
zorglub's avatar
zorglub committed
298
            PL_DEBUG( "finished input" );
299
300
301
302
303
304
305
            input_StopThread( p_playlist->p_input );
            /* Select the next playlist item */
            PL_UNLOCK
            return;
        }
        else if( p_playlist->p_input->i_state != INIT_S )
        {
zorglub's avatar
zorglub committed
306
            PL_UNLOCK;
307
            p_playlist->i_vout_destroyed_date =
308
                ObjectGarbageCollector( p_playlist, VLC_OBJECT_VOUT,
309
310
                                        p_playlist->i_vout_destroyed_date );
            p_playlist->i_sout_destroyed_date =
311
                ObjectGarbageCollector( p_playlist, VLC_OBJECT_SOUT,
312
                                        p_playlist->i_sout_destroyed_date );
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
            PL_LOCK
        }
    }
    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
329
             msg_Dbg( p_playlist, "starting new item" );
330
331
332
333
334
335
336
337
             stats_TimerStart( p_playlist, "Playlist walk",
                                  STATS_TIMER_PLAYLIST_WALK );
             p_item = playlist_NextItem( p_playlist );
             stats_TimerStop( p_playlist, STATS_TIMER_PLAYLIST_WALK );

             if( p_item == NULL )
             {
                msg_Dbg( p_playlist, "nothing to play" );
338
339
340
                if( b_playexit == VLC_TRUE )
                {
                    msg_Info( p_playlist, "end of playlist, exiting" );
341
                    p_playlist->p_libvlc->b_die = VLC_TRUE;
342
                }
343
344
345
346
347
348
349
350
                p_playlist->status.i_status = PLAYLIST_STOPPED;
                PL_UNLOCK
                return;
             }
             playlist_PlayItem( p_playlist, p_item );
         }
         else
         {
351
             p_playlist->status.i_status = PLAYLIST_STOPPED;
zorglub's avatar
zorglub committed
352
             if( p_playlist->status.p_item &&
353
354
                 p_playlist->status.p_item->i_flags & PLAYLIST_REMOVE_FLAG )
             {
zorglub's avatar
zorglub committed
355
356
                 PL_DEBUG( "deleting item marked for deletion" );
                 playlist_ItemDelete( p_playlist->status.p_item );
357
358
359
360
361
                 p_playlist->status.p_item = NULL;
             }

             /* Collect garbage */
             PL_UNLOCK
362
             p_playlist->i_sout_destroyed_date =
363
             ObjectGarbageCollector( p_playlist, VLC_OBJECT_SOUT, mdate() );
364
             p_playlist->i_vout_destroyed_date =
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
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
             ObjectGarbageCollector( p_playlist, VLC_OBJECT_VOUT, mdate() );
             PL_LOCK
         }
    }
    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 );
            /* Unlink current input (_after_ input_DestroyThread for vout
             * garbage collector)*/
            vlc_object_detach( p_input );

            /* Destroy object */
            vlc_object_destroy( 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 ) ) )
    {
        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 );
    }
}

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

454
    while( !p_playlist->b_die )
455
    {
456
457
458
459
460
461
462
463
464
465
466
467
        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];
468
469
        REMOVE_ELEM( p_obj->pp_waiting, p_obj->i_waiting, 0 );
        vlc_mutex_unlock( &p_obj->object_lock );
470

zorglub's avatar
zorglub committed
471
        PL_LOCK;
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
        if( p_current )
        {
            vlc_bool_t b_preparsed = VLC_FALSE;
            if( strncmp( p_current->psz_uri, "http:", 5 ) &&
                strncmp( p_current->psz_uri, "rtsp:", 5 ) &&
                strncmp( p_current->psz_uri, "udp:", 4 ) &&
                strncmp( p_current->psz_uri, "mms:", 4 ) &&
                strncmp( p_current->psz_uri, "cdda:", 4 ) &&
                strncmp( p_current->psz_uri, "dvd:", 4 ) &&
                strncmp( p_current->psz_uri, "v4l:", 4 ) &&
                strncmp( p_current->psz_uri, "dshow:", 6 ) )
            {
                b_preparsed = VLC_TRUE;
                stats_TimerStart( p_playlist, "Preparse run",
                                  STATS_TIMER_PREPARSE );
zorglub's avatar
zorglub committed
487
                PL_UNLOCK;
488
                input_Preparse( p_playlist, p_current );
zorglub's avatar
zorglub committed
489
                PL_LOCK;
490
491
                stats_TimerStop( p_playlist, STATS_TIMER_PREPARSE );
            }
zorglub's avatar
zorglub committed
492
            PL_UNLOCK;
493
494
            if( b_preparsed )
            {
zorglub's avatar
zorglub committed
495
496
                p_current->p_meta->i_status |= ITEM_PREPARSED;
                var_SetInteger( p_playlist, "item-change", p_current->i_id );
497
            }
498
            PL_LOCK;
499

zorglub's avatar
zorglub committed
500
            /* If we haven't retrieved enough meta, add to secondary queue
501
             * which will run the "meta fetchers"
zorglub's avatar
zorglub committed
502
503
504
             * TODO:
             *  don't do this for things we won't get meta for, like
             *  videos
505
             */
zorglub's avatar
zorglub committed
506
507
508
509
            if( !input_MetaSatisfied( p_playlist, p_current, &i_m, &i_o,
                                      VLC_TRUE ) )
            {
                preparse_item_t p;
dionoea's avatar
dionoea committed
510
511
                p.p_item = p_current;
                p.b_fetch_art = VLC_FALSE;
512
                vlc_mutex_lock( &p_playlist->p_secondary_preparse->object_lock);
dionoea's avatar
dionoea committed
513
                INSERT_ELEM( p_playlist->p_secondary_preparse->p_waiting,
514
515
                             p_playlist->p_secondary_preparse->i_waiting,
                             p_playlist->p_secondary_preparse->i_waiting,
dionoea's avatar
dionoea committed
516
                             p );
517
518
                vlc_mutex_unlock(
                            &p_playlist->p_secondary_preparse->object_lock);
519
520
                vlc_cond_signal(
                            &p_playlist->p_secondary_preparse->object_wait );
zorglub's avatar
zorglub committed
521
            }
522
            else
zorglub's avatar
zorglub committed
523
                vlc_gc_decref( p_current );
524
            PL_UNLOCK;
525
526
        }
        else
527
528
            PL_UNLOCK;

529
        vlc_mutex_lock( &p_obj->object_lock );
530
        i_activity = var_GetInteger( p_playlist, "activity" );
531
        if( i_activity < 0 ) i_activity = 0;
zorglub's avatar
zorglub committed
532
        vlc_mutex_unlock( &p_obj->object_lock );
533
        /* Sleep at least 1ms */
534
535
536
537
        msleep( (i_activity+1) * 1000 );
    }
}

538
/** Main loop for secondary preparser queue */
dionoea's avatar
dionoea committed
539
void playlist_SecondaryPreparseLoop( playlist_secondary_preparse_t *p_obj )
540
541
{
    playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
542
543
544
    vlc_bool_t b_fetch_art;
    input_item_t *p_item;
    int i_activity;
545

546
    while( !p_playlist->b_die )
547
    {
548
549
550
551
552
553
554
555
556
557
558
559
560
        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
561
        REMOVE_ELEM( p_obj->p_waiting, p_obj->i_waiting, 0 );
562
        vlc_mutex_unlock( &p_obj->object_lock );
dionoea's avatar
dionoea committed
563
        if( p_item )
564
        {
zorglub's avatar
zorglub committed
565
566
567
568
            if( !b_fetch_art )
            {
                input_MetaFetch( p_playlist, p_item );
                p_item->p_meta->i_status |= ITEM_META_FETCHED;
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
                var_SetInteger( p_playlist, "item-change", p_item->i_id );
                /*  Fetch right now */
                if( var_GetInteger( p_playlist, "album-art" ) == ALBUM_ART_ALL )
                {
                    vlc_mutex_lock( &p_obj->object_lock );
                    preparse_item_t p;
                    p.p_item = p_item;
                    p.b_fetch_art = VLC_TRUE;
                    INSERT_ELEM( p_playlist->p_secondary_preparse->p_waiting,
                                 p_playlist->p_secondary_preparse->i_waiting,
                                 0, p );
                    vlc_mutex_unlock( &p_obj->object_lock );
                }
                else
                    vlc_gc_decref( p_item );
zorglub's avatar
zorglub committed
584
585
            }
            else
dionoea's avatar
dionoea committed
586
587
588
            {
                input_ArtFetch( p_playlist, p_item );
                p_item->p_meta->i_status |= ITEM_ART_FETCHED;
589
590
                vlc_gc_decref( p_item );
           }
591
        }
592
593
594
595
596
597
        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 );
598
599
600
    }
}

601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
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" );
634
    var_CreateGetBool( p_playlist, "play-and-exit" );
635
636
637
638
    var_CreateGetBool( p_playlist, "random" );
    var_CreateGetBool( p_playlist, "repeat" );
    var_CreateGetBool( p_playlist, "loop" );
}