]> git.sesse.net Git - vlc/blob - src/control/media_list.c
Merge branch 1.0-bugfix into master
[vlc] / src / control / media_list.c
1 /*****************************************************************************
2  * media_list.c: libvlc new API media list functions
3  *****************************************************************************
4  * Copyright (C) 2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #include "libvlc_internal.h"
25 #include <vlc/libvlc.h>
26 #include <assert.h>
27 #include "vlc_arrays.h"
28
29 typedef enum EventPlaceInTime {
30     EventWillHappen,
31     EventDidHappen
32 } EventPlaceInTime;
33
34 //#define DEBUG_MEDIA_LIST
35
36 #ifdef DEBUG_MEDIA_LIST
37 # define trace( fmt, ... ) printf( "%s(): " fmt, __FUNCTION__, ##__VA_ARGS__ )
38 #else
39 # define trace( ... )
40 #endif
41
42 /*
43  * Private functions
44  */
45
46
47
48 /**************************************************************************
49  *       notify_item_addition (private)
50  *
51  * Do the appropriate action when an item is deleted.
52  **************************************************************************/
53 static void
54 notify_item_addition( libvlc_media_list_t * p_mlist,
55                       libvlc_media_t * p_md,
56                       int index,
57                       EventPlaceInTime event_status )
58 {
59     libvlc_event_t event;
60
61     /* Construct the event */
62     if( event_status == EventDidHappen )
63     {
64         trace("item was added at index %d\n", index);
65         event.type = libvlc_MediaListItemAdded;
66         event.u.media_list_item_added.item = p_md;
67         event.u.media_list_item_added.index = index;
68     }
69     else /* if( event_status == EventWillHappen ) */
70     {
71         event.type = libvlc_MediaListWillAddItem;
72         event.u.media_list_will_add_item.item = p_md;
73         event.u.media_list_will_add_item.index = index;
74     }
75
76     /* Send the event */
77     libvlc_event_send( p_mlist->p_event_manager, &event );
78 }
79
80 /**************************************************************************
81  *       notify_item_deletion (private)
82  *
83  * Do the appropriate action when an item is added.
84  **************************************************************************/
85 static void
86 notify_item_deletion( libvlc_media_list_t * p_mlist,
87                       libvlc_media_t * p_md,
88                       int index,
89                       EventPlaceInTime event_status )
90 {
91     libvlc_event_t event;
92
93     /* Construct the event */
94     if( event_status == EventDidHappen )
95     {
96         trace("item at index %d was deleted\n", index);
97         event.type = libvlc_MediaListItemDeleted;
98         event.u.media_list_item_deleted.item = p_md;
99         event.u.media_list_item_deleted.index = index;
100     }
101     else /* if( event_status == EventWillHappen ) */
102     {
103         event.type = libvlc_MediaListWillDeleteItem;
104         event.u.media_list_will_delete_item.item = p_md;
105         event.u.media_list_will_delete_item.index = index;
106     }
107
108     /* Send the event */
109     libvlc_event_send( p_mlist->p_event_manager, &event );
110 }
111
112 /**************************************************************************
113  *       static mlist_is_writable (private)
114  *
115  * Raise exception and return 0 when the media_list instance is read-only,
116  * or else return 1.
117  **************************************************************************/
118 static inline
119 int mlist_is_writable( libvlc_media_list_t *p_mlist, libvlc_exception_t *p_e )
120 {
121     if( !p_mlist||p_mlist->b_read_only )
122     {
123         /* We are read-only from user side */
124         libvlc_exception_raise( p_e, "Cannot write to read-only media list." );
125         return 0;
126     }
127     return 1;
128 }
129
130 /*
131  * Public libvlc functions
132  */
133
134 /**************************************************************************
135  *       libvlc_media_list_new (Public)
136  *
137  * Init an object.
138  **************************************************************************/
139 libvlc_media_list_t *
140 libvlc_media_list_new( libvlc_instance_t * p_inst,
141                        libvlc_exception_t * p_e )
142 {
143     libvlc_media_list_t * p_mlist;
144
145     p_mlist = malloc(sizeof(libvlc_media_list_t));
146     if( !p_mlist )
147         return NULL;
148
149     p_mlist->p_libvlc_instance = p_inst;
150     p_mlist->p_event_manager = libvlc_event_manager_new( p_mlist, p_inst, p_e );
151
152     /* Code for that one should be handled in flat_media_list.c */
153     p_mlist->p_flat_mlist = NULL;
154     p_mlist->b_read_only = false;
155
156     libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
157             libvlc_MediaListItemAdded, p_e );
158     libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
159             libvlc_MediaListWillAddItem, p_e );
160     libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
161             libvlc_MediaListItemDeleted, p_e );
162     libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
163             libvlc_MediaListWillDeleteItem, p_e );
164
165     if( libvlc_exception_raised( p_e ) )
166     {
167         libvlc_event_manager_release( p_mlist->p_event_manager );
168         free( p_mlist );
169         return NULL;
170     }
171
172     vlc_mutex_init( &p_mlist->object_lock );
173     vlc_mutex_init( &p_mlist->refcount_lock ); // FIXME: spinlock?
174
175     vlc_array_init( &p_mlist->items );
176     p_mlist->i_refcount = 1;
177     p_mlist->p_md = NULL;
178
179     return p_mlist;
180 }
181
182 /**************************************************************************
183  *       libvlc_media_list_release (Public)
184  *
185  * Release an object.
186  **************************************************************************/
187 void libvlc_media_list_release( libvlc_media_list_t * p_mlist )
188 {
189     libvlc_media_t * p_md;
190     int i;
191
192     vlc_mutex_lock( &p_mlist->refcount_lock );
193     p_mlist->i_refcount--;
194     if( p_mlist->i_refcount > 0 )
195     {
196         vlc_mutex_unlock( &p_mlist->refcount_lock );
197         return;
198     }
199     vlc_mutex_unlock( &p_mlist->refcount_lock );
200
201     /* Refcount null, time to free */
202
203     libvlc_event_manager_release( p_mlist->p_event_manager );
204
205     libvlc_media_release( p_mlist->p_md );
206
207     for ( i = 0; i < vlc_array_count( &p_mlist->items ); i++ )
208     {
209         p_md = vlc_array_item_at_index( &p_mlist->items, i );
210         libvlc_media_release( p_md );
211     }
212
213     vlc_mutex_destroy( &p_mlist->object_lock );
214     vlc_array_clear( &p_mlist->items );
215
216     free( p_mlist );
217 }
218
219 /**************************************************************************
220  *       libvlc_media_list_retain (Public)
221  *
222  * Increase an object refcount.
223  **************************************************************************/
224 void libvlc_media_list_retain( libvlc_media_list_t * p_mlist )
225 {
226     vlc_mutex_lock( &p_mlist->refcount_lock );
227     p_mlist->i_refcount++;
228     vlc_mutex_unlock( &p_mlist->refcount_lock );
229 }
230
231
232 /**************************************************************************
233  *       add_file_content (Public)
234  **************************************************************************/
235 void
236 libvlc_media_list_add_file_content( libvlc_media_list_t * p_mlist,
237                                     const char * psz_uri,
238                                     libvlc_exception_t * p_e )
239 {
240     input_item_t * p_input_item;
241     libvlc_media_t * p_md;
242
243     p_input_item = input_item_NewExt(
244                            p_mlist->p_libvlc_instance->p_libvlc_int, psz_uri,
245                                          _("Media Library"), 0, NULL, 0, -1 );
246
247     if( !p_input_item )
248     {
249         libvlc_exception_raise( p_e, "Can't create an input item" );
250         return;
251     }
252
253     p_md = libvlc_media_new_from_input_item(
254             p_mlist->p_libvlc_instance,
255             p_input_item, p_e );
256
257     if( !p_md )
258     {
259         vlc_gc_decref( p_input_item );
260         return;
261     }
262
263     libvlc_media_list_add_media( p_mlist, p_md, p_e );
264     if( libvlc_exception_raised( p_e ) )
265         return;
266
267     input_Read( p_mlist->p_libvlc_instance->p_libvlc_int, p_input_item, true );
268
269     return;
270 }
271
272 /**************************************************************************
273  *       set_media (Public)
274  **************************************************************************/
275 void libvlc_media_list_set_media( libvlc_media_list_t * p_mlist,
276                                              libvlc_media_t * p_md,
277                                              libvlc_exception_t * p_e)
278
279 {
280     VLC_UNUSED(p_e);
281     vlc_mutex_lock( &p_mlist->object_lock );
282     libvlc_media_release( p_mlist->p_md );
283     libvlc_media_retain( p_md );
284     p_mlist->p_md = p_md;
285     vlc_mutex_unlock( &p_mlist->object_lock );
286 }
287
288 /**************************************************************************
289  *       media (Public)
290  *
291  * If this media_list comes is a media's subitems,
292  * This holds the corresponding media.
293  * This md is also seen as the information holder for the media_list.
294  * Indeed a media_list can have meta information through this
295  * media.
296  **************************************************************************/
297 libvlc_media_t *
298 libvlc_media_list_media( libvlc_media_list_t * p_mlist,
299                                     libvlc_exception_t * p_e)
300 {
301     libvlc_media_t *p_md;
302     VLC_UNUSED(p_e);
303
304     vlc_mutex_lock( &p_mlist->object_lock );
305     p_md = p_mlist->p_md;
306     if( p_md )
307         libvlc_media_retain( p_md );
308     vlc_mutex_unlock( &p_mlist->object_lock );
309
310     return p_md;
311 }
312
313 /**************************************************************************
314  *       libvlc_media_list_count (Public)
315  *
316  * Lock should be hold when entering.
317  **************************************************************************/
318 int libvlc_media_list_count( libvlc_media_list_t * p_mlist,
319                              libvlc_exception_t * p_e )
320 {
321     VLC_UNUSED(p_e);
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 void libvlc_media_list_add_media(
331                                    libvlc_media_list_t * p_mlist,
332                                    libvlc_media_t * p_md,
333                                    libvlc_exception_t * p_e )
334 {
335     if( mlist_is_writable(p_mlist,p_e) )
336         _libvlc_media_list_add_media( p_mlist, p_md, p_e );
337 }
338
339 /* LibVLC internal version */
340 void _libvlc_media_list_add_media(
341                                    libvlc_media_list_t * p_mlist,
342                                    libvlc_media_t * p_md,
343                                    libvlc_exception_t * p_e )
344 {
345     VLC_UNUSED(p_e);
346     libvlc_media_retain( p_md );
347
348     notify_item_addition( p_mlist, p_md, vlc_array_count( &p_mlist->items ),
349                           EventWillHappen );
350     vlc_array_append( &p_mlist->items, p_md );
351     notify_item_addition( p_mlist, p_md, vlc_array_count( &p_mlist->items )-1,
352                           EventDidHappen );
353 }
354
355 /**************************************************************************
356  *       libvlc_media_list_insert_media (Public)
357  *
358  * Lock should be hold when entering.
359  **************************************************************************/
360 void libvlc_media_list_insert_media(
361                                    libvlc_media_list_t * p_mlist,
362                                    libvlc_media_t * p_md,
363                                    int index,
364                                    libvlc_exception_t * p_e )
365 {
366     if( mlist_is_writable(p_mlist,p_e) )
367         _libvlc_media_list_insert_media( p_mlist, p_md, index, p_e );
368 }
369
370 /* LibVLC internal version */
371 void _libvlc_media_list_insert_media(
372                                    libvlc_media_list_t * p_mlist,
373                                    libvlc_media_t * p_md,
374                                    int index,
375                                    libvlc_exception_t * p_e )
376 {
377     VLC_UNUSED(p_e);
378     libvlc_media_retain( p_md );
379
380     notify_item_addition( p_mlist, p_md, index, EventWillHappen );
381     vlc_array_insert( &p_mlist->items, p_md, index );
382     notify_item_addition( p_mlist, p_md, index, EventDidHappen );
383 }
384
385 /**************************************************************************
386  *       libvlc_media_list_remove_index (Public)
387  *
388  * Lock should be held when entering.
389  **************************************************************************/
390 void libvlc_media_list_remove_index( libvlc_media_list_t * p_mlist,
391                                      int index,
392                                      libvlc_exception_t * p_e )
393 {
394     if( mlist_is_writable(p_mlist,p_e) )
395         _libvlc_media_list_remove_index( p_mlist, index, p_e );
396 }
397
398 /* LibVLC internal version */
399 void _libvlc_media_list_remove_index( libvlc_media_list_t * p_mlist,
400                                      int index,
401                                      libvlc_exception_t * p_e )
402 {
403     libvlc_media_t * p_md;
404
405     if( index < 0 || index >= vlc_array_count( &p_mlist->items ))
406     {
407         libvlc_exception_raise( p_e, "Index out of bounds");
408         return;
409     }
410
411     p_md = vlc_array_item_at_index( &p_mlist->items, index );
412
413     notify_item_deletion( p_mlist, p_md, index, EventWillHappen );
414     vlc_array_remove( &p_mlist->items, index );
415     notify_item_deletion( p_mlist, p_md, index, EventDidHappen );
416
417     libvlc_media_release( p_md );
418 }
419
420 /**************************************************************************
421  *       libvlc_media_list_item_at_index (Public)
422  *
423  * Lock should be held when entering.
424  **************************************************************************/
425 libvlc_media_t *
426 libvlc_media_list_item_at_index( libvlc_media_list_t * p_mlist,
427                                  int index,
428                                  libvlc_exception_t * p_e )
429 {
430     libvlc_media_t * p_md;
431
432     if( index < 0 || index >= vlc_array_count( &p_mlist->items ))
433     {
434         libvlc_exception_raise( p_e, "Index out of bounds");
435         return NULL;
436     }
437
438     p_md = vlc_array_item_at_index( &p_mlist->items, index );
439     libvlc_media_retain( p_md );
440     return p_md;
441 }
442
443 /**************************************************************************
444  *       libvlc_media_list_index_of_item (Public)
445  *
446  * Lock should be held when entering.
447  * Warning: this function returns the first matching item.
448  **************************************************************************/
449 int libvlc_media_list_index_of_item( libvlc_media_list_t * p_mlist,
450                                      libvlc_media_t * p_searched_md,
451                                      libvlc_exception_t * p_e )
452 {
453     VLC_UNUSED(p_e);
454
455     libvlc_media_t * p_md;
456     int i;
457     for ( i = 0; i < vlc_array_count( &p_mlist->items ); i++ )
458     {
459         p_md = vlc_array_item_at_index( &p_mlist->items, i );
460         if( p_searched_md == p_md )
461             return i;
462     }
463     return -1;
464 }
465
466 /**************************************************************************
467  *       libvlc_media_list_is_readonly (Public)
468  *
469  * This indicates if this media list is read-only from a user point of view
470  **************************************************************************/
471 int libvlc_media_list_is_readonly( libvlc_media_list_t * p_mlist )
472 {
473     return p_mlist->b_read_only;
474 }
475
476 /**************************************************************************
477  *       libvlc_media_list_lock (Public)
478  *
479  * The lock must be held in access operations. It is never used in the
480  * Public method.
481  **************************************************************************/
482 void libvlc_media_list_lock( libvlc_media_list_t * p_mlist )
483 {
484     vlc_mutex_lock( &p_mlist->object_lock );
485 }
486
487
488 /**************************************************************************
489  *       libvlc_media_list_unlock (Public)
490  *
491  * The lock must be held in access operations
492  **************************************************************************/
493 void libvlc_media_list_unlock( libvlc_media_list_t * p_mlist )
494 {
495     vlc_mutex_unlock( &p_mlist->object_lock );
496 }
497
498
499 /**************************************************************************
500  *       libvlc_media_list_p_event_manager (Public)
501  *
502  * The p_event_manager is immutable, so you don't have to hold the lock
503  **************************************************************************/
504 libvlc_event_manager_t *
505 libvlc_media_list_event_manager( libvlc_media_list_t * p_mlist,
506                                     libvlc_exception_t * p_e )
507 {
508     VLC_UNUSED(p_e);
509     return p_mlist->p_event_manager;
510 }