media_list_player.c 16.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*****************************************************************************
 * media_list_player.c: libvlc new API media_list player functions
 *****************************************************************************
 * Copyright (C) 2007 the VideoLAN team
 * $Id$
 *
 * Authors: Pierre d'Herbemont <pdherbemont # 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 "libvlc_internal.h"
#include <vlc/libvlc.h>
25
#include "media_list_path.h"
26
27
28
29
30
31
32
33
34
35

/*
 * Private functions
 */

/**************************************************************************
 *       get_next_index (private)
 *
 * Simple next item fetcher.
 **************************************************************************/
36
37
static libvlc_media_list_path_t
get_next_path( libvlc_media_list_player_t * p_mlp )
38
{
39
40
41
42
    /* We are entered with libvlc_media_list_lock( p_mlp->p_list ) */
    libvlc_media_list_path_t ret;
    libvlc_media_list_t * p_parent_of_playing_item;
    libvlc_media_list_t * p_sublist_of_playing_item;
43

44
45
46
47
48
    if ( !p_mlp->current_playing_item_path )
    {
        p_mlp->current_playing_item_path = libvlc_media_list_path_empty();
    }
    
49
50
51
    p_sublist_of_playing_item = libvlc_media_list_sublist_at_path(
                            p_mlp->p_mlist,
                            p_mlp->current_playing_item_path );
52
 
53
54
55
56
57
58
    /* If item just gained a sublist just play it */
    if( p_sublist_of_playing_item )
    {
        libvlc_media_list_release( p_sublist_of_playing_item );
        return libvlc_media_list_path_copy_by_appending( p_mlp->current_playing_item_path, 0 );
    }
59

60
61
62
63
    /* Try to catch next element */
    p_parent_of_playing_item = libvlc_media_list_parentlist_at_path(
                            p_mlp->p_mlist,
                            p_mlp->current_playing_item_path );
64

65
66
67
68
69
70
    int deepness = libvlc_media_list_path_deepness( p_mlp->current_playing_item_path );
    if( deepness < 1 || !p_parent_of_playing_item )
        return NULL;

    ret = libvlc_media_list_path_copy( p_mlp->current_playing_item_path );

71
72
    while( ret[deepness-1] >= libvlc_media_list_count( p_parent_of_playing_item, NULL ) )
    {
73
74
75
76
77
78
79
80
81
82
83
84
85
86
        deepness--;
        if( deepness <= 0 )
        {
            free( ret );
            libvlc_media_list_release( p_parent_of_playing_item );
            return NULL;
        }
        ret[deepness] = -1;
        ret[deepness-1]++;
        p_parent_of_playing_item  = libvlc_media_list_parentlist_at_path(
                                        p_mlp->p_mlist,
                                        ret );
    }
    libvlc_media_list_release( p_parent_of_playing_item );
87
    return ret;
88
89
90
}

/**************************************************************************
91
 *       media_player_reached_end (private) (Event Callback)
92
 **************************************************************************/
93
static void
94
media_player_reached_end( const libvlc_event_t * p_event,
95
96
                            void * p_user_data )
{
97
    libvlc_media_list_player_t * p_mlp = p_user_data;
98
99
    libvlc_media_player_t * p_mi = p_event->p_obj;
    libvlc_media_t *p_md, * p_current_md;
100

101
    p_md = libvlc_media_player_get_media( p_mi, NULL );
102
    /* XXX: need if p_mlp->p_current_playing_index is beyond */
103
    p_current_md = libvlc_media_list_item_at_path(
104
                        p_mlp->p_mlist,
105
                        p_mlp->current_playing_item_path );
106
107
108
109
    if( p_md != p_current_md )
    {
        msg_Warn( p_mlp->p_libvlc_instance->p_libvlc_int,
                  "We are not sync-ed with the media instance" );
110
111
        libvlc_media_release( p_md );
        libvlc_media_release( p_current_md );
112
113
        return;
    }
114
115
    libvlc_media_release( p_md );
    libvlc_media_release( p_current_md );
116
    libvlc_media_list_player_next( p_mlp, NULL );
117
118
119
120
121
}

/**************************************************************************
 *       playlist_item_deleted (private) (Event Callback)
 **************************************************************************/
122
static void
123
124
mlist_item_deleted( const libvlc_event_t * p_event, void * p_user_data )
{
125
    libvlc_media_t * p_current_md;
126
127
    libvlc_media_list_player_t * p_mlp = p_user_data;
    libvlc_media_list_t * p_emitting_mlist = p_event->p_obj;
128
    /* XXX: need if p_mlp->p_current_playing_index is beyond */
129
    p_current_md = libvlc_media_list_item_at_path(
130
                        p_mlp->p_mlist,
131
                        p_mlp->current_playing_item_path );
132

133
134
135
136
137
138
    if( p_event->u.media_list_item_deleted.item == p_current_md &&
        p_emitting_mlist == p_mlp->p_mlist )
    {
        /* We are playing this item, we choose to stop */
        libvlc_media_list_player_stop( p_mlp, NULL );
    }
139
140
141
142
143
144
145
146
}

/**************************************************************************
 *       install_playlist_observer (private)
 **************************************************************************/
static void
install_playlist_observer( libvlc_media_list_player_t * p_mlp )
{
147
    libvlc_event_attach( libvlc_media_list_event_manager( p_mlp->p_mlist, NULL ),
148
149
150
151
152
153
154
155
156
            libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp, NULL );
}

/**************************************************************************
 *       uninstall_playlist_observer (private)
 **************************************************************************/
static void
uninstall_playlist_observer( libvlc_media_list_player_t * p_mlp )
{
157
158
159
160
161
    if ( !p_mlp->p_mlist )
    {
        return;
    }

162
163
164
165
166
    libvlc_event_detach( libvlc_media_list_event_manager( p_mlp->p_mlist, NULL ),
            libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp, NULL );
}

/**************************************************************************
167
 *       install_media_player_observer (private)
168
169
 **************************************************************************/
static void
170
install_media_player_observer( libvlc_media_list_player_t * p_mlp )
171
{
172
    libvlc_event_attach( libvlc_media_player_event_manager( p_mlp->p_mi, NULL ),
173
                         libvlc_MediaPlayerEndReached,
174
                          media_player_reached_end, p_mlp, NULL );
175
176
177
178
}


/**************************************************************************
179
 *       uninstall_media_player_observer (private)
180
181
 **************************************************************************/
static void
182
uninstall_media_player_observer( libvlc_media_list_player_t * p_mlp )
183
{
184
185
186
187
    if ( !p_mlp->p_mi )
    {
        return;
    }
188

189
    libvlc_event_detach( libvlc_media_player_event_manager( p_mlp->p_mi, NULL ),
190
                         libvlc_MediaPlayerEndReached,
191
                         media_player_reached_end, p_mlp, NULL );
192
}
193

194
/**************************************************************************
195
 *       set_current_playing_item (private)
196
197
198
199
 *
 * Playlist lock should be held
 **************************************************************************/
static void
200
201
202
set_current_playing_item( libvlc_media_list_player_t * p_mlp,
                          libvlc_media_list_path_t path,
                          libvlc_exception_t * p_e )
203
{
204
205
    VLC_UNUSED(p_e);

206
    libvlc_media_t * p_md;
207
    
208
    p_md = libvlc_media_list_item_at_path( p_mlp->p_mlist, path ); 
209
    vlc_mutex_lock( &p_mlp->object_lock );
210
    
211
212
    free( p_mlp->current_playing_item_path );
    p_mlp->current_playing_item_path = path;
213

214
215
216
217
218
219
    if( !p_md )
    {
        vlc_mutex_unlock( &p_mlp->object_lock );
        return;
    }

220
221
    /* We are not interested in getting media stop event now */
    uninstall_media_player_observer( p_mlp );
222
223
224

    if ( !p_mlp->p_mi )
    {
225
        p_mlp->p_mi = libvlc_media_player_new_from_media(p_md, p_e);
226
227
    }
    
228
229
    if( p_md->p_subitems && libvlc_media_list_count( p_md->p_subitems, NULL ) > 0 )
    {
230
        libvlc_media_t * p_submd;
231
        p_submd = libvlc_media_list_item_at_index( p_md->p_subitems, 0, NULL );
232
233
        libvlc_media_player_set_media( p_mlp->p_mi, p_submd, NULL );
        libvlc_media_release( p_submd );
234
235
    }
    else
236
        libvlc_media_player_set_media( p_mlp->p_mi, p_md, NULL );
237
//    wait_playing_state(); /* If we want to be synchronous */
238
    install_media_player_observer( p_mlp );
239
240
241

    vlc_mutex_unlock( &p_mlp->object_lock );

242
    libvlc_media_release( p_md ); /* for libvlc_media_list_item_at_index */
243
}
244
245
246
247
248
249

/*
 * Public libvlc functions
 */

/**************************************************************************
250
 *         new (Public)
251
252
253
254
255
256
257
258
 **************************************************************************/
libvlc_media_list_player_t *
libvlc_media_list_player_new( libvlc_instance_t * p_instance,
                              libvlc_exception_t * p_e )
{
    (void)p_e;
    libvlc_media_list_player_t * p_mlp;
    p_mlp = malloc(sizeof(libvlc_media_list_player_t));
259
    p_mlp->current_playing_item_path = NULL;
260
261
    p_mlp->p_mi = NULL;
    p_mlp->p_mlist = NULL;
262
    vlc_mutex_init( p_instance->p_libvlc_int, &p_mlp->object_lock );
263
264
265
266
267
268
    p_mlp->p_event_manager = libvlc_event_manager_new( p_mlp,
                                                       p_instance,
                                                       p_e );
    libvlc_event_manager_register_event_type( p_mlp->p_event_manager,
            libvlc_MediaListPlayerNextItemSet, p_e );

269
    return p_mlp;
270
271
272
}

/**************************************************************************
273
 *         release (Public)
274
275
276
277
278
279
280
 **************************************************************************/
void libvlc_media_list_player_release( libvlc_media_list_player_t * p_mlp )
{
    free(p_mlp);
}

/**************************************************************************
281
 *        set_media_player (Public)
282
 **************************************************************************/
283
void libvlc_media_list_player_set_media_player(
284
                                     libvlc_media_list_player_t * p_mlp,
285
                                     libvlc_media_player_t * p_mi,
286
287
                                     libvlc_exception_t * p_e )
{
288
289
    VLC_UNUSED(p_e);

290
291
    vlc_mutex_lock( &p_mlp->object_lock );

292
293
    if( p_mlp->p_mi )
    {
294
295
        uninstall_media_player_observer( p_mlp );
        libvlc_media_player_release( p_mlp->p_mi );
296
    }
297
    libvlc_media_player_retain( p_mi );
298
    p_mlp->p_mi = p_mi;
299

300
    install_media_player_observer( p_mlp );
301
302
303
304
305

    vlc_mutex_unlock( &p_mlp->object_lock );
}

/**************************************************************************
306
 *       set_media_list (Public)
307
308
309
310
311
312
313
 **************************************************************************/
void libvlc_media_list_player_set_media_list(
                                     libvlc_media_list_player_t * p_mlp,
                                     libvlc_media_list_t * p_mlist,
                                     libvlc_exception_t * p_e )
{
    vlc_mutex_lock( &p_mlp->object_lock );
314
315
 
    if( libvlc_media_list_player_is_playing( p_mlp, p_e ) )
316
    {
317
        libvlc_media_player_stop( p_mlp->p_mi, p_e );
318
319
320
        /* Don't bother if there was an error. */
        libvlc_exception_clear( p_e );
    }
321

322
323
324
325
326
327
328
329
330
    if( p_mlp->p_mlist )
    {
        uninstall_playlist_observer( p_mlp );
        libvlc_media_list_release( p_mlp->p_mlist );
    }
    libvlc_media_list_retain( p_mlist );
    p_mlp->p_mlist = p_mlist;
 
    install_playlist_observer( p_mlp );
331
332
333
334
335
336
337
338
339
340

    vlc_mutex_unlock( &p_mlp->object_lock );
}

/**************************************************************************
 *        Play (Public)
 **************************************************************************/
void libvlc_media_list_player_play( libvlc_media_list_player_t * p_mlp,
                                  libvlc_exception_t * p_e )
{
341
    if( !p_mlp->current_playing_item_path )
342
343
    {
        libvlc_media_list_player_next( p_mlp, p_e );
344
        return; /* Will set to play */
345
    }
346

347
    libvlc_media_player_play( p_mlp->p_mi, p_e );
348
349
}

350
351
352
353
354
355
356
357
358

/**************************************************************************
 *        Pause (Public)
 **************************************************************************/
void libvlc_media_list_player_pause( libvlc_media_list_player_t * p_mlp,
                                     libvlc_exception_t * p_e )
{
    if( !p_mlp->p_mi )
        return;
359
    libvlc_media_player_pause( p_mlp->p_mi, p_e );
360
361
362
363
364
}

/**************************************************************************
 *        is_playing (Public)
 **************************************************************************/
365
int
366
367
libvlc_media_list_player_is_playing( libvlc_media_list_player_t * p_mlp,
                                     libvlc_exception_t * p_e )
368
{
369
    libvlc_state_t state = libvlc_media_player_get_state( p_mlp->p_mi, p_e );
370
371
372
373
374
375
376
377
378
379
380
381
382
    return (state == libvlc_Opening) || (state == libvlc_Buffering) ||
           (state == libvlc_Playing);
}

/**************************************************************************
 *        State (Public)
 **************************************************************************/
libvlc_state_t
libvlc_media_list_player_get_state( libvlc_media_list_player_t * p_mlp,
                                    libvlc_exception_t * p_e )
{
    if( !p_mlp->p_mi )
        return libvlc_Stopped;
383
    return libvlc_media_player_get_state( p_mlp->p_mi, p_e );
384
385
}

386
387
388
389
390
391
392
393
/**************************************************************************
 *        Play item at index (Public)
 **************************************************************************/
void libvlc_media_list_player_play_item_at_index(
                        libvlc_media_list_player_t * p_mlp,
                        int i_index,
                        libvlc_exception_t * p_e )
{
394
    set_current_playing_item( p_mlp, libvlc_media_list_path_with_root_index(i_index), p_e );
395

396
397
    if( libvlc_exception_raised( p_e ) )
        return;
398

399
400
401
402
403
    /* Send the next item event */
    libvlc_event_t event;
    event.type = libvlc_MediaListPlayerNextItemSet;
    libvlc_event_send( p_mlp->p_event_manager, &event );

404
    libvlc_media_player_play( p_mlp->p_mi, p_e );
405
406
}

407
408
409
410
411
/**************************************************************************
 *        Play item (Public)
 **************************************************************************/
void libvlc_media_list_player_play_item(
                        libvlc_media_list_player_t * p_mlp,
412
                        libvlc_media_t * p_md,
413
414
                        libvlc_exception_t * p_e )
{
415
    libvlc_media_list_path_t path = libvlc_media_list_path_of_item( p_mlp->p_mlist, p_md );
416
417
418
419
420
    if( !path )
    {
        libvlc_exception_raise( p_e, "No such item in media list" );
        return;
    }
421
    set_current_playing_item( p_mlp, path, p_e );
422

423
424
    if( libvlc_exception_raised( p_e ) )
        return;
425

426
    libvlc_media_player_play( p_mlp->p_mi, p_e );
427
}
428

429
430
431
432
433
434
/**************************************************************************
 *       Stop (Public)
 **************************************************************************/
void libvlc_media_list_player_stop( libvlc_media_list_player_t * p_mlp,
                                    libvlc_exception_t * p_e )
{
435
436
    if ( p_mlp->p_mi )
    {
437
        libvlc_media_player_stop( p_mlp->p_mi, p_e );        
438
    }
439
440

    vlc_mutex_lock( &p_mlp->object_lock );
441
    free( p_mlp->current_playing_item_path );
442
    p_mlp->current_playing_item_path = NULL;
443
444
445
446
447
448
449
450
    vlc_mutex_unlock( &p_mlp->object_lock );
}

/**************************************************************************
 *       Next (Public)
 **************************************************************************/
void libvlc_media_list_player_next( libvlc_media_list_player_t * p_mlp,
                                    libvlc_exception_t * p_e )
451
452
{    
    libvlc_media_list_path_t path;
453
454
455
456
457
458

    if (! p_mlp->p_mlist )
    {
        libvlc_exception_raise( p_e, "No more element to play" );
        return;
    }
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
    
    libvlc_media_list_lock( p_mlp->p_mlist );

    path = get_next_path( p_mlp );

    if( !path )
    {
        libvlc_media_list_unlock( p_mlp->p_mlist );
        libvlc_exception_raise( p_e, "No more element to play" );
        libvlc_media_list_player_stop( p_mlp, p_e );
        return;
    }

    set_current_playing_item( p_mlp, path, p_e );
    
474
    libvlc_media_player_play( p_mlp->p_mi, p_e );
475

476
    libvlc_media_list_unlock( p_mlp->p_mlist );
477
478
479
480
481

    /* Send the next item event */
    libvlc_event_t event;
    event.type = libvlc_MediaListPlayerNextItemSet;
    libvlc_event_send( p_mlp->p_event_manager, &event);
482
}