1 /*****************************************************************************
2 * media_list.c: libvlc new API media list functions
3 *****************************************************************************
4 * Copyright (C) 2007 the VideoLAN team
7 * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
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.
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.
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 *****************************************************************************/
24 #include "libvlc_internal.h"
25 #include <vlc/libvlc.h>
27 #include "vlc_arrays.h"
33 /**************************************************************************
34 * notify_item_addition (private)
36 * Call parent playlist and send the appropriate event.
37 **************************************************************************/
39 notify_item_addition( libvlc_media_list_t * p_mlist,
40 libvlc_media_descriptor_t * p_md,
45 event.type = libvlc_MediaListItemAdded;
46 event.u.media_list_item_added.item = p_md;
47 event.u.media_list_item_added.index = index;
49 libvlc_event_send( p_mlist->p_event_manager, &event );
52 /**************************************************************************
53 * notify_item_deletion (private)
55 * Call parent playlist and send the appropriate event.
56 **************************************************************************/
58 notify_item_deletion( libvlc_media_list_t * p_mlist,
59 libvlc_media_descriptor_t * p_md,
64 event.type = libvlc_MediaListItemDeleted;
65 event.u.media_list_item_deleted.item = p_md;
66 event.u.media_list_item_deleted.index = index;
68 libvlc_event_send( p_mlist->p_event_manager, &event );
71 /**************************************************************************
72 * dynamic_list_propose_item (private) (Event Callback)
74 * This is called if the dynamic sublist's data provider adds a new item.
75 **************************************************************************/
77 dynamic_list_propose_item( const libvlc_event_t * p_event, void * p_user_data )
79 libvlc_media_list_t * p_submlist = p_user_data;
80 libvlc_media_descriptor_t * p_md = p_event->u.media_list_item_added.item;
82 //libvlc_media_descriptor_lock( p_md );
83 if( libvlc_tag_query_match( p_submlist->p_query, p_md, NULL ) )
85 libvlc_media_list_lock( p_submlist );
86 libvlc_media_list_add_media_descriptor( p_submlist, p_md, NULL );
87 libvlc_media_list_unlock( p_submlist );
89 //libvlc_media_descriptor_unlock( p_md );
92 /**************************************************************************
93 * dynamic_list_remove_item (private) (Event Callback)
95 * This is called if the dynamic sublist's data provider adds a new item.
96 **************************************************************************/
98 dynamic_list_remove_item( const libvlc_event_t * p_event, void * p_user_data )
100 libvlc_media_list_t * p_submlist = p_user_data;
101 libvlc_media_descriptor_t * p_md = p_event->u.media_list_item_deleted.item;
103 //libvlc_media_descriptor_lock( p_md );
104 if( libvlc_tag_query_match( p_submlist->p_query, p_md, NULL ) )
107 libvlc_media_list_lock( p_submlist );
108 i = libvlc_media_list_index_of_item( p_submlist, p_md, NULL );
111 /* We've missed one item addition, that could happen especially
112 * if we add item in a threaded maner, so we just ignore */
113 libvlc_media_list_unlock( p_submlist );
114 //libvlc_media_descriptor_unlock( p_md );
117 libvlc_media_list_remove_index( p_submlist, i, NULL );
118 libvlc_media_list_unlock( p_submlist );
120 //libvlc_media_descriptor_unlock( p_md );
123 /**************************************************************************
124 * dynamic_list_change_item (private) (Event Callback)
126 * This is called if the dynamic sublist's data provider adds a new item.
127 **************************************************************************/
129 dynamic_list_change_item( const libvlc_event_t * p_event , void * p_user_data)
131 libvlc_media_list_t * p_submlist = p_user_data;
132 libvlc_media_descriptor_t * p_md = p_event->u.media_list_item_changed.item;
135 libvlc_media_list_lock( p_submlist );
137 index = libvlc_media_list_index_of_item( p_submlist, p_md, NULL );
140 libvlc_media_list_unlock( p_submlist );
141 return; /* Not found, no prob, just ignore */
144 //libvlc_media_descriptor_lock( p_md );
145 if( !libvlc_tag_query_match( p_submlist->p_query, p_md, NULL ) )
146 libvlc_media_list_remove_index( p_submlist, index, NULL );
147 //libvlc_media_descriptor_unlock( p_md );
149 libvlc_media_list_unlock( p_submlist );
153 * Public libvlc functions
156 /**************************************************************************
157 * libvlc_media_list_new (Public)
160 **************************************************************************/
161 libvlc_media_list_t *
162 libvlc_media_list_new( libvlc_instance_t * p_inst,
163 libvlc_exception_t * p_e )
165 libvlc_media_list_t * p_mlist;
167 p_mlist = malloc(sizeof(libvlc_media_list_t));
172 p_mlist->p_libvlc_instance = p_inst;
173 p_mlist->p_event_manager = libvlc_event_manager_new( p_mlist, p_inst, p_e );
175 libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
176 libvlc_MediaListItemAdded, p_e );
177 libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
178 libvlc_MediaListItemChanged, p_e );
179 libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
180 libvlc_MediaListItemDeleted, p_e );
182 if( libvlc_exception_raised( p_e ) )
184 libvlc_event_manager_release( p_mlist->p_event_manager );
189 vlc_mutex_init( p_inst->p_libvlc_int, &p_mlist->object_lock );
191 ARRAY_INIT(p_mlist->items);
192 p_mlist->i_refcount = 1;
193 p_mlist->p_media_provider = NULL;
198 /**************************************************************************
199 * libvlc_media_list_release (Public)
202 **************************************************************************/
203 void libvlc_media_list_release( libvlc_media_list_t * p_mlist )
205 libvlc_media_descriptor_t * p_md;
207 vlc_mutex_lock( &p_mlist->object_lock );
208 p_mlist->i_refcount--;
209 if( p_mlist->i_refcount > 0 )
211 vlc_mutex_unlock( &p_mlist->object_lock );
214 vlc_mutex_unlock( &p_mlist->object_lock );
216 /* Refcount null, time to free */
217 if( p_mlist->p_media_provider )
218 libvlc_media_list_release( p_mlist->p_media_provider );
220 if( p_mlist->p_query )
221 libvlc_tag_query_release( p_mlist->p_query );
223 libvlc_event_manager_release( p_mlist->p_event_manager );
225 FOREACH_ARRAY( p_md, p_mlist->items )
226 libvlc_media_descriptor_release( p_md );
231 /**************************************************************************
232 * libvlc_media_list_retain (Public)
234 * Increase an object refcount.
235 **************************************************************************/
236 void libvlc_media_list_retain( libvlc_media_list_t * p_mlist )
238 vlc_mutex_lock( &p_mlist->object_lock );
239 p_mlist->i_refcount++;
240 vlc_mutex_unlock( &p_mlist->object_lock );
243 /**************************************************************************
244 * libvlc_media_list_count (Public)
246 * Lock should be hold when entering.
247 **************************************************************************/
248 int libvlc_media_list_count( libvlc_media_list_t * p_mlist,
249 libvlc_exception_t * p_e )
252 return p_mlist->items.i_size;
255 /**************************************************************************
256 * libvlc_media_list_add_media_descriptor (Public)
258 * Lock should be hold when entering.
259 **************************************************************************/
260 void libvlc_media_list_add_media_descriptor(
261 libvlc_media_list_t * p_mlist,
262 libvlc_media_descriptor_t * p_md,
263 libvlc_exception_t * p_e )
266 libvlc_media_descriptor_retain( p_md );
268 ARRAY_APPEND( p_mlist->items, p_md );
269 notify_item_addition( p_mlist, p_md, p_mlist->items.i_size-1 );
272 /**************************************************************************
273 * libvlc_media_list_insert_media_descriptor (Public)
275 * Lock should be hold when entering.
276 **************************************************************************/
277 void libvlc_media_list_insert_media_descriptor(
278 libvlc_media_list_t * p_mlist,
279 libvlc_media_descriptor_t * p_md,
281 libvlc_exception_t * p_e )
284 libvlc_media_descriptor_retain( p_md );
286 ARRAY_INSERT( p_mlist->items, p_md, index);
287 notify_item_addition( p_mlist, p_md, index );
290 /**************************************************************************
291 * libvlc_media_list_remove_index (Public)
293 * Lock should be hold when entering.
294 **************************************************************************/
295 void libvlc_media_list_remove_index( libvlc_media_list_t * p_mlist,
297 libvlc_exception_t * p_e )
299 libvlc_media_descriptor_t * p_md;
301 p_md = ARRAY_VAL( p_mlist->items, index );
303 ARRAY_REMOVE( p_mlist->items, index )
304 notify_item_deletion( p_mlist, p_md, index );
306 libvlc_media_descriptor_release( p_md );
309 /**************************************************************************
310 * libvlc_media_list_item_at_index (Public)
312 * Lock should be hold when entering.
313 **************************************************************************/
314 libvlc_media_descriptor_t *
315 libvlc_media_list_item_at_index( libvlc_media_list_t * p_mlist,
317 libvlc_exception_t * p_e )
319 return ARRAY_VAL( p_mlist->items, index );
322 /**************************************************************************
323 * libvlc_media_list_index_of_item (Public)
325 * Lock should be hold when entering.
326 * Warning: this function would return the first matching item
327 **************************************************************************/
328 int libvlc_media_list_index_of_item( libvlc_media_list_t * p_mlist,
329 libvlc_media_descriptor_t * p_searched_md,
330 libvlc_exception_t * p_e )
332 libvlc_media_descriptor_t * p_md;
333 FOREACH_ARRAY( p_md, p_mlist->items )
334 if( p_searched_md == p_md )
335 return fe_idx; /* Once more, we hate macro for that */
340 /**************************************************************************
341 * libvlc_media_list_lock (Public)
343 * The lock must be held in access operations. It is never used in the
345 **************************************************************************/
346 void libvlc_media_list_lock( libvlc_media_list_t * p_mlist )
348 vlc_mutex_lock( &p_mlist->object_lock );
352 /**************************************************************************
353 * libvlc_media_list_unlock (Public)
355 * The lock must be held in access operations
356 **************************************************************************/
357 void libvlc_media_list_unlock( libvlc_media_list_t * p_mlist )
359 vlc_mutex_unlock( &p_mlist->object_lock );
364 /**************************************************************************
365 * libvlc_media_list_p_event_manager (Public)
367 * The p_event_manager is immutable, so you don't have to hold the lock
368 **************************************************************************/
369 libvlc_event_manager_t *
370 libvlc_media_list_event_manager( libvlc_media_list_t * p_mlist,
371 libvlc_exception_t * p_e )
374 return p_mlist->p_event_manager;
377 /**************************************************************************
378 * libvlc_media_list_dynamic_sublist (Public)
380 * Lock should be hold when entering.
381 **************************************************************************/
382 libvlc_media_list_t *
383 libvlc_media_list_dynamic_sublist( libvlc_media_list_t * p_mlist,
384 libvlc_tag_query_t * p_query,
385 libvlc_exception_t * p_e )
387 libvlc_media_list_t * p_submlist;
388 libvlc_event_manager_t * p_em;
393 p_submlist = libvlc_media_list_new( p_mlist->p_libvlc_instance, p_e );
396 if( !libvlc_exception_raised( p_e ) )
397 libvlc_exception_raise( p_e, "Can't get the new media_list" );
401 /* We have a query */
402 libvlc_tag_query_retain( p_query );
403 p_submlist->p_query = p_query;
405 /* We have a media provider */
406 libvlc_media_list_retain( p_mlist );
407 p_submlist->p_media_provider = p_mlist;
410 libvlc_media_list_lock( p_submlist );
412 count = libvlc_media_list_count( p_mlist, p_e );
414 /* This should be running in a thread, a good plan to achieve that
415 * move all the dynamic code to libvlc_tag_query. */
416 for( i = 0; i < count; i++ )
418 libvlc_media_descriptor_t * p_md;
419 p_md = libvlc_media_list_item_at_index( p_mlist, i, p_e );
420 if( libvlc_tag_query_match( p_query, p_md, NULL ) )
421 libvlc_media_list_add_media_descriptor( p_submlist, p_md, p_e );
424 /* And we will listen to its event, so we can update p_submlist
426 p_em = libvlc_media_list_event_manager( p_mlist, p_e );
427 libvlc_event_attach( p_em, libvlc_MediaListItemAdded,
428 dynamic_list_propose_item, p_submlist, p_e );
429 libvlc_event_attach( p_em, libvlc_MediaListItemDeleted,
430 dynamic_list_remove_item, p_submlist, p_e );
431 libvlc_event_attach( p_em, libvlc_MediaListItemChanged,
432 dynamic_list_change_item, p_submlist, p_e );
434 libvlc_media_list_unlock( p_submlist );