media_list.c 15.3 KB
Newer Older
1 2 3
/*****************************************************************************
 * media_list.c: libvlc new API media list functions
 *****************************************************************************
Jean-Baptiste Kempf's avatar
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
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
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
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
    libvlc_event_send( &p_mlist->event_manager, &event );
82 83 84 85 86
}

/**************************************************************************
 *       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
    /* Send the event */
112
    libvlc_event_send( &p_mlist->event_manager, &event );
113 114
}

115 116 117 118 119 120 121 122
/* 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 */
123
    libvlc_event_send( &p_mlist->event_manager, &event );
124 125
}

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

162
    p_mlist->p_libvlc_instance = p_inst;
163
    libvlc_event_manager_init( &p_mlist->event_manager, p_mlist );
164
    p_mlist->b_read_only = false;
165

166
    vlc_mutex_init( &p_mlist->object_lock );
167
    vlc_mutex_init( &p_mlist->refcount_lock ); // FIXME: spinlock?
168

169
    vlc_array_init( &p_mlist->items );
170
    assert( p_mlist->items.i_count == 0 );
171
    p_mlist->i_refcount = 1;
172
    p_mlist->p_md = NULL;
173
    p_mlist->p_internal_md = NULL;
174

175
    libvlc_retain( p_inst );
176 177 178 179 180 181 182 183 184 185
    return p_mlist;
}

/**************************************************************************
 *       libvlc_media_list_release (Public)
 *
 * Release an object.
 **************************************************************************/
void libvlc_media_list_release( libvlc_media_list_t * p_mlist )
{
186
    vlc_mutex_lock( &p_mlist->refcount_lock );
187 188 189
    p_mlist->i_refcount--;
    if( p_mlist->i_refcount > 0 )
    {
190
        vlc_mutex_unlock( &p_mlist->refcount_lock );
191 192
        return;
    }
193
    vlc_mutex_unlock( &p_mlist->refcount_lock );
194 195 196

    /* Refcount null, time to free */

197
    libvlc_event_manager_destroy( &p_mlist->event_manager );
198
    libvlc_media_release( p_mlist->p_md );
199

200
    for( size_t i = 0; i < vlc_array_count( &p_mlist->items ); i++ )
201
    {
202
        libvlc_media_t* p_md = vlc_array_item_at_index( &p_mlist->items, i );
203
        libvlc_media_release( p_md );
204 205
    }

206
    vlc_mutex_destroy( &p_mlist->object_lock );
207
    vlc_mutex_destroy( &p_mlist->refcount_lock );
208 209
    vlc_array_clear( &p_mlist->items );

210
    libvlc_release( p_mlist->p_libvlc_instance );
211 212
    free( p_mlist );
}
213

214 215 216 217 218 219 220
/**************************************************************************
 *       libvlc_media_list_retain (Public)
 *
 * Increase an object refcount.
 **************************************************************************/
void libvlc_media_list_retain( libvlc_media_list_t * p_mlist )
{
221
    vlc_mutex_lock( &p_mlist->refcount_lock );
222
    p_mlist->i_refcount++;
223
    vlc_mutex_unlock( &p_mlist->refcount_lock );
224 225
}

226 227 228 229

/**************************************************************************
 *       add_file_content (Public)
 **************************************************************************/
230
int
231
libvlc_media_list_add_file_content( libvlc_media_list_t * p_mlist,
232
                                    const char * psz_uri )
233 234
{
    input_item_t * p_input_item;
235
    libvlc_media_t * p_md;
236

237
    p_input_item = input_item_New( psz_uri, _("Media Library") );
238 239 240

    if( !p_input_item )
    {
241
        libvlc_printerr( "Not enough memory" );
242
        return -1;
243 244
    }

245 246
    p_md = libvlc_media_new_from_input_item( p_mlist->p_libvlc_instance,
                                             p_input_item );
247 248
    if( !p_md )
    {
249
        input_item_Release( p_input_item );
250
        return -1;
251 252
    }

253 254
    if( libvlc_media_list_add_media( p_mlist, p_md ) )
    {
255 256 257
#warning Missing error handling!
        /* printerr and leaks */
        return -1;
258
    }
259

260
    input_Read( p_mlist->p_libvlc_instance->p_libvlc_int, p_input_item );
261
    return 0;
262 263 264
}

/**************************************************************************
265
 *       set_media (Public)
266
 **************************************************************************/
267
void libvlc_media_list_set_media( libvlc_media_list_t * p_mlist,
268
                                  libvlc_media_t * p_md )
269 270 271

{
    vlc_mutex_lock( &p_mlist->object_lock );
272
    if( p_mlist->p_internal_md || !mlist_is_writable(p_mlist) )
273 274 275 276
    {
        vlc_mutex_unlock( &p_mlist->object_lock );
        return;
    }
277
    libvlc_media_release( p_mlist->p_md );
278
    libvlc_media_retain( p_md );
279
    p_mlist->p_md = p_md;
280 281 282 283
    vlc_mutex_unlock( &p_mlist->object_lock );
}

/**************************************************************************
284
 *       media (Public)
285
 *
286 287
 * If this media_list comes is a media's subitems,
 * This holds the corresponding media.
288 289
 * This md is also seen as the information holder for the media_list.
 * Indeed a media_list can have meta information through this
290
 * media.
291
 **************************************************************************/
292
libvlc_media_t *
293
libvlc_media_list_media( libvlc_media_list_t * p_mlist )
294
{
295
    libvlc_media_t *p_md;
296 297

    vlc_mutex_lock( &p_mlist->object_lock );
298
    p_md = p_mlist->p_internal_md ? p_mlist->p_internal_md : p_mlist->p_md;
299
    if( p_md )
300
        libvlc_media_retain( p_md );
301 302
    vlc_mutex_unlock( &p_mlist->object_lock );

303
    return p_md;
304 305
}

306 307 308
/**************************************************************************
 *       libvlc_media_list_count (Public)
 *
309
 * Lock should be held when entering.
310
 **************************************************************************/
311
int libvlc_media_list_count( libvlc_media_list_t * p_mlist )
312
{
313
    return vlc_array_count( &p_mlist->items );
314 315 316
}

/**************************************************************************
317
 *       libvlc_media_list_add_media (Public)
318
 *
319
 * Lock should be held when entering.
320
 **************************************************************************/
321 322
int libvlc_media_list_add_media( libvlc_media_list_t * p_mlist,
                                 libvlc_media_t * p_md )
323
{
324 325
    if( !mlist_is_writable(p_mlist) )
        return -1;
326
    libvlc_media_list_internal_add_media( p_mlist, p_md );
327
    return 0;
328 329 330
}

/* LibVLC internal version */
331 332
void libvlc_media_list_internal_add_media( libvlc_media_list_t * p_mlist,
                                           libvlc_media_t * p_md )
333
{
334
    libvlc_media_retain( p_md );
335

336 337
    notify_item_addition( p_mlist, p_md, vlc_array_count( &p_mlist->items ),
                          EventWillHappen );
338
    vlc_array_append( &p_mlist->items, p_md );
339 340
    notify_item_addition( p_mlist, p_md, vlc_array_count( &p_mlist->items )-1,
                          EventDidHappen );
341 342 343
}

/**************************************************************************
344
 *       libvlc_media_list_insert_media (Public)
345 346 347
 *
 * Lock should be hold when entering.
 **************************************************************************/
348 349 350
int libvlc_media_list_insert_media( libvlc_media_list_t * p_mlist,
                                    libvlc_media_t * p_md,
                                    int index )
351
{
352 353
    if( !mlist_is_writable(p_mlist) )
        return -1;
354
    libvlc_media_list_internal_insert_media( p_mlist, p_md, index );
355
    return 0;
356 357 358
}

/* LibVLC internal version */
359 360 361
void libvlc_media_list_internal_insert_media( libvlc_media_list_t * p_mlist,
                                              libvlc_media_t * p_md,
                                              int index )
362
{
363
    libvlc_media_retain( p_md );
364

365
    notify_item_addition( p_mlist, p_md, index, EventWillHappen );
366
    vlc_array_insert( &p_mlist->items, p_md, index );
367
    notify_item_addition( p_mlist, p_md, index, EventDidHappen );
368 369 370 371 372
}

/**************************************************************************
 *       libvlc_media_list_remove_index (Public)
 *
373
 * Lock should be held when entering.
374
 **************************************************************************/
375 376
int libvlc_media_list_remove_index( libvlc_media_list_t * p_mlist,
                                     int index )
377
{
378 379
    if( !mlist_is_writable(p_mlist) )
        return -1;
380
    return libvlc_media_list_internal_remove_index( p_mlist, index );
381 382 383
}

/* LibVLC internal version */
384 385
int libvlc_media_list_internal_remove_index( libvlc_media_list_t * p_mlist,
                                             int index )
386
{
387
    libvlc_media_t * p_md;
388

389
    if( (size_t) index >= vlc_array_count( &p_mlist->items ))
390
    {
391
        libvlc_printerr( "Index out of bounds" );
392
        return -1;
393
    }
394

395
    p_md = vlc_array_item_at_index( &p_mlist->items, index );
396

397
    notify_item_deletion( p_mlist, p_md, index, EventWillHappen );
398
    vlc_array_remove( &p_mlist->items, index );
399
    notify_item_deletion( p_mlist, p_md, index, EventDidHappen );
400

401
    libvlc_media_release( p_md );
402
    return 0;
403 404 405 406 407
}

/**************************************************************************
 *       libvlc_media_list_item_at_index (Public)
 *
408
 * Lock should be held when entering.
409
 **************************************************************************/
410
libvlc_media_t *
411
libvlc_media_list_item_at_index( libvlc_media_list_t * p_mlist,
412
                                 int index )
413
{
414
    libvlc_media_t * p_md;
415

416
    if( (size_t) index >= vlc_array_count( &p_mlist->items ))
417
    {
418
        libvlc_printerr( "Index out of bounds" );
419 420 421
        return NULL;
    }

422
    p_md = vlc_array_item_at_index( &p_mlist->items, index );
423
    libvlc_media_retain( p_md );
424
    return p_md;
425 426 427 428 429
}

/**************************************************************************
 *       libvlc_media_list_index_of_item (Public)
 *
430 431
 * Lock should be held when entering.
 * Warning: this function returns the first matching item.
432 433
 **************************************************************************/
int libvlc_media_list_index_of_item( libvlc_media_list_t * p_mlist,
434
                                     libvlc_media_t * p_searched_md )
435
{
436 437 438 439 440
    int idx = vlc_array_index_of_item( &p_mlist->items, p_searched_md );
    if( idx == -1 )
        libvlc_printerr( "Media not found" );

    return idx;
441 442
}

443 444 445 446 447
/**************************************************************************
 *       libvlc_media_list_is_readonly (Public)
 *
 * This indicates if this media list is read-only from a user point of view
 **************************************************************************/
448
int libvlc_media_list_is_readonly( libvlc_media_list_t * p_mlist )
449 450 451 452
{
    return p_mlist->b_read_only;
}

453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
/**************************************************************************
 *       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 );
}


/**************************************************************************
477
 *       libvlc_media_list_event_manager (Public)
478 479 480 481
 *
 * The p_event_manager is immutable, so you don't have to hold the lock
 **************************************************************************/
libvlc_event_manager_t *
482
libvlc_media_list_event_manager( libvlc_media_list_t * p_mlist )
483
{
484
    return &p_mlist->event_manager;
485
}