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_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
}