media_list.c 15.6 KB
Newer Older
1 2 3
/*****************************************************************************
 * media_list.c: libvlc new API media list functions
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2007 VLC authors and VideoLAN
5 6 7 8
 * $Id$
 *
 * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
9 10 11
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
12 13 14 15
 * (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
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
16 17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
18
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
19 20 21
 * You should have received a copy of the GNU Lesser 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.
22 23
 *****************************************************************************/

24 25 26 27
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

28
#include <assert.h>
29 30 31 32 33 34 35 36 37 38 39 40

#include <vlc/libvlc.h>
#include <vlc/libvlc_media.h>
#include <vlc/libvlc_media_list.h>
#include <vlc/libvlc_events.h>

#include <vlc_common.h>
#include <vlc_input.h>

#include "libvlc_internal.h"
#include "media_internal.h" // libvlc_media_new_from_input_item()
#include "media_list_internal.h"
41

42 43 44 45 46
typedef enum EventPlaceInTime {
    EventWillHappen,
    EventDidHappen
} EventPlaceInTime;

47 48 49 50
/*
 * Private functions
 */

51 52


53 54 55
/**************************************************************************
 *       notify_item_addition (private)
 *
56
 * Do the appropriate action when an item is deleted.
57 58 59
 **************************************************************************/
static void
notify_item_addition( libvlc_media_list_t * p_mlist,
60
                      libvlc_media_t * p_md,
61 62
                      int index,
                      EventPlaceInTime event_status )
63 64 65
{
    libvlc_event_t event;

66
    /* Construct the event */
67 68 69 70 71 72 73 74 75 76 77 78
    if( event_status == EventDidHappen )
    {
        event.type = libvlc_MediaListItemAdded;
        event.u.media_list_item_added.item = p_md;
        event.u.media_list_item_added.index = index;
    }
    else /* if( event_status == EventWillHappen ) */
    {
        event.type = libvlc_MediaListWillAddItem;
        event.u.media_list_will_add_item.item = p_md;
        event.u.media_list_will_add_item.index = index;
    }
79 80

    /* Send the event */
81 82 83 84 85 86
    libvlc_event_send( p_mlist->p_event_manager, &event );
}

/**************************************************************************
 *       notify_item_deletion (private)
 *
87
 * Do the appropriate action when an item is added.
88 89 90
 **************************************************************************/
static void
notify_item_deletion( libvlc_media_list_t * p_mlist,
91
                      libvlc_media_t * p_md,
92 93
                      int index,
                      EventPlaceInTime event_status )
94 95
{
    libvlc_event_t event;
96 97

    /* Construct the event */
98 99 100 101 102 103 104 105 106 107 108 109
    if( event_status == EventDidHappen )
    {
        event.type = libvlc_MediaListItemDeleted;
        event.u.media_list_item_deleted.item = p_md;
        event.u.media_list_item_deleted.index = index;
    }
    else /* if( event_status == EventWillHappen ) */
    {
        event.type = libvlc_MediaListWillDeleteItem;
        event.u.media_list_will_delete_item.item = p_md;
        event.u.media_list_will_delete_item.index = index;
    }
110

111 112 113 114
    /* Send the event */
    libvlc_event_send( p_mlist->p_event_manager, &event );
}

115 116 117 118 119 120 121 122 123 124 125
/* LibVLC internal */
void libvlc_media_list_internal_end_reached( libvlc_media_list_t * p_mlist )
{
    libvlc_event_t event;

    event.type = libvlc_MediaListEndReached;

    /* Send the event */
    libvlc_event_send( p_mlist->p_event_manager, &event );
}

126 127 128 129
/**************************************************************************
 *       static mlist_is_writable (private)
 **************************************************************************/
static inline
130
bool mlist_is_writable( libvlc_media_list_t *p_mlist )
131 132 133 134
{
    if( !p_mlist||p_mlist->b_read_only )
    {
        /* We are read-only from user side */
135
        libvlc_printerr( "Attempt to write a read-only media list" );
136
        return false;
137
    }
138
    return true;
139 140
}

141 142 143 144 145 146 147 148 149 150
/*
 * Public libvlc functions
 */

/**************************************************************************
 *       libvlc_media_list_new (Public)
 *
 * Init an object.
 **************************************************************************/
libvlc_media_list_t *
151
libvlc_media_list_new( libvlc_instance_t * p_inst )
152 153 154 155
{
    libvlc_media_list_t * p_mlist;

    p_mlist = malloc(sizeof(libvlc_media_list_t));
156 157 158
    if( unlikely(p_mlist == NULL) )
    {
        libvlc_printerr( "Not enough memory" );
159
        return NULL;
160
    }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
161

162
    p_mlist->p_libvlc_instance = p_inst;
163
    p_mlist->p_event_manager = libvlc_event_manager_new( p_mlist );
164 165 166 167 168
    if( unlikely(p_mlist->p_event_manager == NULL) )
    {
        free(p_mlist);
        return NULL;
    }
169

170
    p_mlist->b_read_only = false;
171

172
    vlc_mutex_init( &p_mlist->object_lock );
173
    vlc_mutex_init( &p_mlist->refcount_lock ); // FIXME: spinlock?
Jean-Paul Saman's avatar
Jean-Paul Saman committed
174

175
    vlc_array_init( &p_mlist->items );
176
    assert( p_mlist->items.i_count == 0 );
177
    p_mlist->i_refcount = 1;
178
    p_mlist->p_md = NULL;
179
    p_mlist->p_internal_md = NULL;
180

181
    libvlc_retain( p_inst );
182 183 184 185 186 187 188 189 190 191
    return p_mlist;
}

/**************************************************************************
 *       libvlc_media_list_release (Public)
 *
 * Release an object.
 **************************************************************************/
void libvlc_media_list_release( libvlc_media_list_t * p_mlist )
{
192
    libvlc_media_t * p_md;
193

194
    vlc_mutex_lock( &p_mlist->refcount_lock );
195 196 197
    p_mlist->i_refcount--;
    if( p_mlist->i_refcount > 0 )
    {
198
        vlc_mutex_unlock( &p_mlist->refcount_lock );
199 200
        return;
    }
201
    vlc_mutex_unlock( &p_mlist->refcount_lock );
202 203 204 205 206

    /* Refcount null, time to free */

    libvlc_event_manager_release( p_mlist->p_event_manager );

207
    libvlc_media_release( p_mlist->p_md );
208

209
    for ( int i = 0; i < vlc_array_count( &p_mlist->items ); i++ )
210
    {
211
        p_md = vlc_array_item_at_index( &p_mlist->items, i );
212
        libvlc_media_release( p_md );
213 214
    }

215
    vlc_mutex_destroy( &p_mlist->object_lock );
216
    vlc_mutex_destroy( &p_mlist->refcount_lock );
217 218
    vlc_array_clear( &p_mlist->items );

219
    libvlc_release( p_mlist->p_libvlc_instance );
220 221
    free( p_mlist );
}
222

223 224 225 226 227 228 229
/**************************************************************************
 *       libvlc_media_list_retain (Public)
 *
 * Increase an object refcount.
 **************************************************************************/
void libvlc_media_list_retain( libvlc_media_list_t * p_mlist )
{
230
    vlc_mutex_lock( &p_mlist->refcount_lock );
231
    p_mlist->i_refcount++;
232
    vlc_mutex_unlock( &p_mlist->refcount_lock );
233 234
}

235 236 237 238

/**************************************************************************
 *       add_file_content (Public)
 **************************************************************************/
239
int
240
libvlc_media_list_add_file_content( libvlc_media_list_t * p_mlist,
241
                                    const char * psz_uri )
242 243
{
    input_item_t * p_input_item;
244
    libvlc_media_t * p_md;
245

246
    p_input_item = input_item_New( psz_uri, _("Media Library") );
247 248 249

    if( !p_input_item )
    {
250
        libvlc_printerr( "Not enough memory" );
251
        return -1;
252 253
    }

254 255
    p_md = libvlc_media_new_from_input_item( p_mlist->p_libvlc_instance,
                                             p_input_item );
256 257 258
    if( !p_md )
    {
        vlc_gc_decref( p_input_item );
259
        return -1;
260 261
    }

262 263
    if( libvlc_media_list_add_media( p_mlist, p_md ) )
    {
264 265 266
#warning Missing error handling!
        /* printerr and leaks */
        return -1;
267
    }
268

269
    input_Read( p_mlist->p_libvlc_instance->p_libvlc_int, p_input_item );
270
    return 0;
271 272 273
}

/**************************************************************************
274
 *       set_media (Public)
275
 **************************************************************************/
276
void libvlc_media_list_set_media( libvlc_media_list_t * p_mlist,
277
                                  libvlc_media_t * p_md )
278 279 280

{
    vlc_mutex_lock( &p_mlist->object_lock );
281
    if( p_mlist->p_internal_md || !mlist_is_writable(p_mlist) )
282 283 284 285
    {
        vlc_mutex_unlock( &p_mlist->object_lock );
        return;
    }
286
    libvlc_media_release( p_mlist->p_md );
287
    libvlc_media_retain( p_md );
288
    p_mlist->p_md = p_md;
289 290 291 292
    vlc_mutex_unlock( &p_mlist->object_lock );
}

/**************************************************************************
293
 *       media (Public)
294
 *
295 296
 * If this media_list comes is a media's subitems,
 * This holds the corresponding media.
297 298
 * This md is also seen as the information holder for the media_list.
 * Indeed a media_list can have meta information through this
299
 * media.
300
 **************************************************************************/
301
libvlc_media_t *
302
libvlc_media_list_media( libvlc_media_list_t * p_mlist )
303
{
304
    libvlc_media_t *p_md;
305 306

    vlc_mutex_lock( &p_mlist->object_lock );
307
    p_md = p_mlist->p_internal_md ? p_mlist->p_internal_md : p_mlist->p_md;
308
    if( p_md )
309
        libvlc_media_retain( p_md );
310 311
    vlc_mutex_unlock( &p_mlist->object_lock );

312
    return p_md;
313 314
}

315 316 317
/**************************************************************************
 *       libvlc_media_list_count (Public)
 *
318
 * Lock should be held when entering.
319
 **************************************************************************/
320
int libvlc_media_list_count( libvlc_media_list_t * p_mlist )
321
{
322
    return vlc_array_count( &p_mlist->items );
323 324 325
}

/**************************************************************************
326
 *       libvlc_media_list_add_media (Public)
327
 *
328
 * Lock should be held when entering.
329
 **************************************************************************/
330 331
int libvlc_media_list_add_media( libvlc_media_list_t * p_mlist,
                                 libvlc_media_t * p_md )
332
{
333 334
    if( !mlist_is_writable(p_mlist) )
        return -1;
335
    libvlc_media_list_internal_add_media( p_mlist, p_md );
336
    return 0;
337 338 339
}

/* LibVLC internal version */
340 341
void libvlc_media_list_internal_add_media( libvlc_media_list_t * p_mlist,
                                           libvlc_media_t * p_md )
342
{
343
    libvlc_media_retain( p_md );
344

345 346
    notify_item_addition( p_mlist, p_md, vlc_array_count( &p_mlist->items ),
                          EventWillHappen );
347
    vlc_array_append( &p_mlist->items, p_md );
348 349
    notify_item_addition( p_mlist, p_md, vlc_array_count( &p_mlist->items )-1,
                          EventDidHappen );
350 351 352
}

/**************************************************************************
353
 *       libvlc_media_list_insert_media (Public)
354 355 356
 *
 * Lock should be hold when entering.
 **************************************************************************/
357 358 359
int libvlc_media_list_insert_media( libvlc_media_list_t * p_mlist,
                                    libvlc_media_t * p_md,
                                    int index )
360
{
361 362
    if( !mlist_is_writable(p_mlist) )
        return -1;
363
    libvlc_media_list_internal_insert_media( p_mlist, p_md, index );
364
    return 0;
365 366 367
}

/* LibVLC internal version */
368 369 370
void libvlc_media_list_internal_insert_media( libvlc_media_list_t * p_mlist,
                                              libvlc_media_t * p_md,
                                              int index )
371
{
372
    libvlc_media_retain( p_md );
373

374
    notify_item_addition( p_mlist, p_md, index, EventWillHappen );
375
    vlc_array_insert( &p_mlist->items, p_md, index );
376
    notify_item_addition( p_mlist, p_md, index, EventDidHappen );
377 378 379 380 381
}

/**************************************************************************
 *       libvlc_media_list_remove_index (Public)
 *
382
 * Lock should be held when entering.
383
 **************************************************************************/
384 385
int libvlc_media_list_remove_index( libvlc_media_list_t * p_mlist,
                                     int index )
386
{
387 388
    if( !mlist_is_writable(p_mlist) )
        return -1;
389
    return libvlc_media_list_internal_remove_index( p_mlist, index );
390 391 392
}

/* LibVLC internal version */
393 394
int libvlc_media_list_internal_remove_index( libvlc_media_list_t * p_mlist,
                                             int index )
395
{
396
    libvlc_media_t * p_md;
397

398
    if( index < 0 || index >= vlc_array_count( &p_mlist->items ))
399
    {
400
        libvlc_printerr( "Index out of bounds" );
401
        return -1;
402
    }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
403

404
    p_md = vlc_array_item_at_index( &p_mlist->items, index );
405

406
    notify_item_deletion( p_mlist, p_md, index, EventWillHappen );
407
    vlc_array_remove( &p_mlist->items, index );
408
    notify_item_deletion( p_mlist, p_md, index, EventDidHappen );
409

410
    libvlc_media_release( p_md );
411
    return 0;
412 413 414 415 416
}

/**************************************************************************
 *       libvlc_media_list_item_at_index (Public)
 *
417
 * Lock should be held when entering.
418
 **************************************************************************/
419
libvlc_media_t *
420
libvlc_media_list_item_at_index( libvlc_media_list_t * p_mlist,
421
                                 int index )
422
{
423
    libvlc_media_t * p_md;
424

425 426
    if( index < 0 || index >= vlc_array_count( &p_mlist->items ))
    {
427
        libvlc_printerr( "Index out of bounds" );
428 429 430
        return NULL;
    }

431
    p_md = vlc_array_item_at_index( &p_mlist->items, index );
432
    libvlc_media_retain( p_md );
433
    return p_md;
434 435 436 437 438
}

/**************************************************************************
 *       libvlc_media_list_index_of_item (Public)
 *
439 440
 * Lock should be held when entering.
 * Warning: this function returns the first matching item.
441 442
 **************************************************************************/
int libvlc_media_list_index_of_item( libvlc_media_list_t * p_mlist,
443
                                     libvlc_media_t * p_searched_md )
444
{
445
    libvlc_media_t * p_md;
446
    for ( int i = 0; i < vlc_array_count( &p_mlist->items ); i++ )
447
    {
448
        p_md = vlc_array_item_at_index( &p_mlist->items, i );
449
        if( p_searched_md == p_md )
450 451
            return i;
    }
452
    libvlc_printerr( "Media not found" );
453 454 455
    return -1;
}

456 457 458 459 460
/**************************************************************************
 *       libvlc_media_list_is_readonly (Public)
 *
 * This indicates if this media list is read-only from a user point of view
 **************************************************************************/
461
int libvlc_media_list_is_readonly( libvlc_media_list_t * p_mlist )
462 463 464 465
{
    return p_mlist->b_read_only;
}

466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
/**************************************************************************
 *       libvlc_media_list_lock (Public)
 *
 * The lock must be held in access operations. It is never used in the
 * Public method.
 **************************************************************************/
void libvlc_media_list_lock( libvlc_media_list_t * p_mlist )
{
    vlc_mutex_lock( &p_mlist->object_lock );
}


/**************************************************************************
 *       libvlc_media_list_unlock (Public)
 *
 * The lock must be held in access operations
 **************************************************************************/
void libvlc_media_list_unlock( libvlc_media_list_t * p_mlist )
{
    vlc_mutex_unlock( &p_mlist->object_lock );
}


/**************************************************************************
 *       libvlc_media_list_p_event_manager (Public)
 *
 * The p_event_manager is immutable, so you don't have to hold the lock
 **************************************************************************/
libvlc_event_manager_t *
495
libvlc_media_list_event_manager( libvlc_media_list_t * p_mlist )
496 497 498
{
    return p_mlist->p_event_manager;
}