control/dynamic_media_list.c: New dynamic media list object. It shouldn't have great...
[vlc.git] / 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 /*
30  * Private functions
31  */
32
33
34
35 /**************************************************************************
36  *       notify_item_addition (private)
37  *
38  * Do the appropriate action when an item is deleted.
39  **************************************************************************/
40 static void
41 notify_item_addition( libvlc_media_list_t * p_mlist,
42                       libvlc_media_descriptor_t * p_md,
43                       int index )
44 {
45     libvlc_event_t event;
46
47     /* Construct the event */
48     event.type = libvlc_MediaListItemAdded;
49     event.u.media_list_item_added.item = p_md;
50     event.u.media_list_item_added.index = index;
51
52     /* Send the event */
53     libvlc_event_send( p_mlist->p_event_manager, &event );
54 }
55
56 /**************************************************************************
57  *       notify_item_deletion (private)
58  *
59  * Do the appropriate action when an item is added.
60  **************************************************************************/
61 static void
62 notify_item_deletion( libvlc_media_list_t * p_mlist,
63                       libvlc_media_descriptor_t * p_md,
64                       int index )
65 {
66     libvlc_event_t event;
67
68     /* Construct the event */
69     event.type = libvlc_MediaListItemDeleted;
70     event.u.media_list_item_deleted.item = p_md;
71     event.u.media_list_item_deleted.index = index;
72
73     /* Send the event */
74     libvlc_event_send( p_mlist->p_event_manager, &event );
75 }
76
77 /**************************************************************************
78  *       media_descriptor_changed (private) (libvlc Event Callback )
79  *
80  * An item has changed.
81  **************************************************************************/
82 static void
83 media_descriptor_changed( const libvlc_event_t * p_event, void * user_data )
84 {
85     libvlc_media_list_t * p_mlist = user_data;
86     libvlc_media_descriptor_t * p_md = p_event->p_obj;
87     libvlc_event_t event;
88     
89     /* Construct the new media list event */
90     event.type = libvlc_MediaListItemChanged;
91     event.u.media_list_item_changed.item = p_md;
92
93     /* XXX: this is not good, but there is a solution in the pipeline */
94     event.u.media_list_item_changed.index =
95         libvlc_media_list_index_of_item( p_mlist, p_md, NULL );
96
97     /* Send the event */
98     libvlc_event_send( p_mlist->p_event_manager, &event );
99 }
100
101 /**************************************************************************
102  *       media_descriptor_subitem_added (private) (libvlc Event Callback )
103  *
104  * An item (which is a playlist) has gained sub child.
105  **************************************************************************/
106 static void
107 media_descriptor_subitem_added( const libvlc_event_t * p_event, void * user_data )
108 {
109     libvlc_media_list_t * p_mlist = user_data;
110     libvlc_media_descriptor_t * p_new_md;
111
112     p_new_md = p_event->u.media_descriptor_subitem_added.new_child;
113
114     /* For now, just add the new item to this media list */
115     libvlc_media_list_add_media_descriptor( p_mlist, p_new_md, NULL );
116 }
117
118 /**************************************************************************
119  *       install_media_descriptor_observer (private)
120  *
121  * Do the appropriate action when an item is deleted.
122  **************************************************************************/
123 static void
124 install_media_descriptor_observer( libvlc_media_list_t * p_mlist,
125                                    libvlc_media_descriptor_t * p_md )
126 {
127     libvlc_event_attach( p_md->p_event_manager,
128                          libvlc_MediaDescriptorMetaChanged,
129                          media_descriptor_changed,
130                          p_mlist, NULL );
131     libvlc_event_attach( p_md->p_event_manager,
132                          libvlc_MediaDescriptorSubItemAdded,
133                          media_descriptor_subitem_added,
134                          p_mlist, NULL );
135 }
136
137 /**************************************************************************
138  *       uninstall_media_descriptor_observer (private)
139  *
140  * Do the appropriate action when an item is deleted.
141  **************************************************************************/
142 static void
143 uninstall_media_descriptor_observer( libvlc_media_list_t * p_mlist,
144                                      libvlc_media_descriptor_t * p_md )
145 {
146     libvlc_event_detach( p_md->p_event_manager,
147                          libvlc_MediaDescriptorMetaChanged,
148                          media_descriptor_changed,
149                          p_mlist, NULL );
150     libvlc_event_detach( p_md->p_event_manager,
151                          libvlc_MediaDescriptorSubItemAdded,
152                          media_descriptor_subitem_added,
153                          p_mlist, NULL );
154 }
155
156 /*
157  * Public libvlc functions
158  */
159
160 /**************************************************************************
161  *       libvlc_media_list_new (Public)
162  *
163  * Init an object.
164  **************************************************************************/
165 libvlc_media_list_t *
166 libvlc_media_list_new( libvlc_instance_t * p_inst,
167                        libvlc_exception_t * p_e )
168 {
169     libvlc_media_list_t * p_mlist;
170
171     p_mlist = malloc(sizeof(libvlc_media_list_t));
172
173     if( !p_mlist )
174         return NULL;
175     
176     p_mlist->p_libvlc_instance = p_inst;
177     p_mlist->p_event_manager = libvlc_event_manager_new( p_mlist, p_inst, p_e );
178
179     libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
180             libvlc_MediaListItemAdded, p_e );
181     libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
182             libvlc_MediaListItemChanged, p_e );
183     libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
184             libvlc_MediaListItemDeleted, p_e );
185
186     if( libvlc_exception_raised( p_e ) )
187     {
188         libvlc_event_manager_release( p_mlist->p_event_manager );
189         free( p_mlist );
190         return NULL;
191     }
192
193     vlc_mutex_init( p_inst->p_libvlc_int, &p_mlist->object_lock );
194     
195     ARRAY_INIT(p_mlist->items);
196     p_mlist->i_refcount = 1;
197     p_mlist->psz_name = NULL;
198
199     return p_mlist;
200 }
201
202 /**************************************************************************
203  *       libvlc_media_list_release (Public)
204  *
205  * Release an object.
206  **************************************************************************/
207 void libvlc_media_list_release( libvlc_media_list_t * p_mlist )
208 {
209     libvlc_media_descriptor_t * p_md;
210
211     vlc_mutex_lock( &p_mlist->object_lock );
212     p_mlist->i_refcount--;
213     if( p_mlist->i_refcount > 0 )
214     {
215         vlc_mutex_unlock( &p_mlist->object_lock );        
216         return;
217     }
218     vlc_mutex_unlock( &p_mlist->object_lock );        
219
220     /* Refcount null, time to free */
221
222     libvlc_event_manager_release( p_mlist->p_event_manager );
223
224     FOREACH_ARRAY( p_md, p_mlist->items )
225         uninstall_media_descriptor_observer( p_mlist, p_md );
226         libvlc_media_descriptor_release( p_md );
227     FOREACH_END()
228  
229     free( p_mlist );
230 }
231
232 /**************************************************************************
233  *       libvlc_media_list_retain (Public)
234  *
235  * Increase an object refcount.
236  **************************************************************************/
237 void libvlc_media_list_retain( libvlc_media_list_t * p_mlist )
238 {
239     vlc_mutex_lock( &p_mlist->object_lock );
240     p_mlist->i_refcount++;
241     vlc_mutex_unlock( &p_mlist->object_lock );
242 }
243
244
245 /**************************************************************************
246  *       add_file_content (Public)
247  **************************************************************************/
248 void
249 libvlc_media_list_add_file_content( libvlc_media_list_t * p_mlist,
250                                     const char * psz_uri,
251                                     libvlc_exception_t * p_e )
252 {
253     input_item_t * p_input_item;
254     libvlc_media_descriptor_t * p_md;
255
256     p_input_item = input_ItemNewExt( p_mlist->p_libvlc_instance->p_libvlc_int, psz_uri,
257                                 _("Media Library"), 0, NULL, -1 );
258
259     if( !p_input_item )
260     {
261         libvlc_exception_raise( p_e, "Can't create an input item" );
262         return;
263     }
264
265     p_md = libvlc_media_descriptor_new_from_input_item(
266             p_mlist->p_libvlc_instance,
267             p_input_item, p_e );
268
269     if( !p_md )
270     {
271         vlc_gc_decref( p_input_item );
272         return;
273     }
274
275     libvlc_media_list_add_media_descriptor( p_mlist, p_md, p_e );
276     if( libvlc_exception_raised( p_e ) )
277         return;
278
279     input_Read( p_mlist->p_libvlc_instance->p_libvlc_int, p_input_item, VLC_TRUE );
280
281     return;
282 }
283
284 /**************************************************************************
285  *       set_name (Public)
286  **************************************************************************/
287 void libvlc_media_list_set_name( libvlc_media_list_t * p_mlist,
288                                  const char * psz_name,
289                                  libvlc_exception_t * p_e)
290
291 {
292     (void)p_e;
293     vlc_mutex_lock( &p_mlist->object_lock );
294     free( p_mlist->psz_name );
295     p_mlist->psz_name = psz_name ? strdup( psz_name ) : NULL;
296     vlc_mutex_unlock( &p_mlist->object_lock );
297 }
298
299 /**************************************************************************
300  *       name (Public)
301  **************************************************************************/
302 char * libvlc_media_list_name( libvlc_media_list_t * p_mlist,
303                                libvlc_exception_t * p_e)
304 {
305     char *ret;
306     (void)p_e;
307
308     vlc_mutex_lock( &p_mlist->object_lock );
309     ret = p_mlist->psz_name ? strdup( p_mlist->psz_name ) : NULL;
310     vlc_mutex_unlock( &p_mlist->object_lock );
311
312     return ret;
313 }
314
315 /**************************************************************************
316  *       libvlc_media_list_count (Public)
317  *
318  * Lock should be hold when entering.
319  **************************************************************************/
320 int libvlc_media_list_count( libvlc_media_list_t * p_mlist,
321                              libvlc_exception_t * p_e )
322 {
323     (void)p_e;
324     return p_mlist->items.i_size;
325 }
326
327 /**************************************************************************
328  *       libvlc_media_list_add_media_descriptor (Public)
329  *
330  * Lock should be hold when entering.
331  **************************************************************************/
332 void libvlc_media_list_add_media_descriptor( 
333                                    libvlc_media_list_t * p_mlist,
334                                    libvlc_media_descriptor_t * p_md,
335                                    libvlc_exception_t * p_e )
336 {
337     (void)p_e;
338     libvlc_media_descriptor_retain( p_md );
339     ARRAY_APPEND( p_mlist->items, p_md );
340     notify_item_addition( p_mlist, p_md, p_mlist->items.i_size-1 );
341     install_media_descriptor_observer( p_mlist, p_md );
342 }
343
344 /**************************************************************************
345  *       libvlc_media_list_insert_media_descriptor (Public)
346  *
347  * Lock should be hold when entering.
348  **************************************************************************/
349 void libvlc_media_list_insert_media_descriptor( 
350                                    libvlc_media_list_t * p_mlist,
351                                    libvlc_media_descriptor_t * p_md,
352                                    int index,
353                                    libvlc_exception_t * p_e )
354 {
355     (void)p_e;
356     libvlc_media_descriptor_retain( p_md );
357
358     ARRAY_INSERT( p_mlist->items, p_md, index);
359     notify_item_addition( p_mlist, p_md, index );
360     install_media_descriptor_observer( p_mlist, p_md );
361 }
362
363 /**************************************************************************
364  *       libvlc_media_list_remove_index (Public)
365  *
366  * Lock should be hold when entering.
367  **************************************************************************/
368 void libvlc_media_list_remove_index( libvlc_media_list_t * p_mlist,
369                                      int index,
370                                      libvlc_exception_t * p_e )
371 {
372     libvlc_media_descriptor_t * p_md;
373
374     p_md = ARRAY_VAL( p_mlist->items, index );
375
376     uninstall_media_descriptor_observer( p_mlist, p_md );
377
378     ARRAY_REMOVE( p_mlist->items, index )
379     notify_item_deletion( p_mlist, p_md, index );
380
381     libvlc_media_descriptor_release( p_md );
382 }
383
384 /**************************************************************************
385  *       libvlc_media_list_item_at_index (Public)
386  *
387  * Lock should be hold when entering.
388  **************************************************************************/
389 libvlc_media_descriptor_t *
390 libvlc_media_list_item_at_index( libvlc_media_list_t * p_mlist,
391                                  int index,
392                                  libvlc_exception_t * p_e )
393 {
394     libvlc_media_descriptor_t * p_md =  ARRAY_VAL( p_mlist->items, index );
395     libvlc_media_descriptor_retain( p_md );
396     return p_md;
397 }
398
399 /**************************************************************************
400  *       libvlc_media_list_index_of_item (Public)
401  *
402  * Lock should be hold when entering.
403  * Warning: this function would return the first matching item
404  **************************************************************************/
405 int libvlc_media_list_index_of_item( libvlc_media_list_t * p_mlist,
406                                      libvlc_media_descriptor_t * p_searched_md,
407                                      libvlc_exception_t * p_e )
408 {
409     libvlc_media_descriptor_t * p_md;
410     FOREACH_ARRAY( p_md, p_mlist->items )
411         if( p_searched_md == p_md )
412             return fe_idx; /* Once more, we hate macro for that */
413     FOREACH_END()
414     return -1;
415 }
416
417 /**************************************************************************
418  *       libvlc_media_list_lock (Public)
419  *
420  * The lock must be held in access operations. It is never used in the
421  * Public method.
422  **************************************************************************/
423 void libvlc_media_list_lock( libvlc_media_list_t * p_mlist )
424 {
425     vlc_mutex_lock( &p_mlist->object_lock );
426 }
427
428
429 /**************************************************************************
430  *       libvlc_media_list_unlock (Public)
431  *
432  * The lock must be held in access operations
433  **************************************************************************/
434 void libvlc_media_list_unlock( libvlc_media_list_t * p_mlist )
435 {
436     vlc_mutex_unlock( &p_mlist->object_lock );
437 }
438
439
440
441 /**************************************************************************
442  *       libvlc_media_list_p_event_manager (Public)
443  *
444  * The p_event_manager is immutable, so you don't have to hold the lock
445  **************************************************************************/
446 libvlc_event_manager_t *
447 libvlc_media_list_event_manager( libvlc_media_list_t * p_mlist,
448                                     libvlc_exception_t * p_e )
449 {
450     (void)p_e;
451     return p_mlist->p_event_manager;
452 }