94b4b0aef6787fbf4526b6f113e16421a55bf991
[vlc.git] / src / control / media_discoverer.c
1 /*****************************************************************************
2  * media_discoverer.c: libvlc new API media discoverer 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 <assert.h>
25
26 #include <vlc/libvlc.h>
27 #include <vlc/libvlc_media.h>
28 #include <vlc/libvlc_media_list.h>
29 #include <vlc/libvlc_media_discoverer.h>
30 #include <vlc/libvlc_events.h>
31
32 #include <vlc_services_discovery.h>
33
34 #include "libvlc_internal.h"
35 #include "media_internal.h" // libvlc_media_new_from_input_item()
36 #include "media_list_internal.h" // _libvlc_media_list_add_media()
37
38 struct libvlc_media_discoverer_t
39 {
40     libvlc_event_manager_t * p_event_manager;
41     libvlc_instance_t *      p_libvlc_instance;
42     services_discovery_t *   p_sd;
43     libvlc_media_list_t *    p_mlist;
44     bool                     running;
45     vlc_dictionary_t         catname_to_submedialist;
46 };
47
48 /*
49  * Private functions
50  */
51
52 /**************************************************************************
53  *       services_discovery_item_added (Private) (VLC event callback)
54  **************************************************************************/
55
56 static void services_discovery_item_added( const vlc_event_t * p_event,
57                                            void * user_data )
58 {
59     input_item_t * p_item = p_event->u.services_discovery_item_added.p_new_item;
60     const char * psz_cat = p_event->u.services_discovery_item_added.psz_category;
61     libvlc_media_t * p_md;
62     libvlc_media_discoverer_t * p_mdis = user_data;
63     libvlc_media_list_t * p_mlist = p_mdis->p_mlist;
64
65     p_md = libvlc_media_new_from_input_item(
66             p_mdis->p_libvlc_instance,
67             p_item, NULL );
68
69     /* If we have a category, that mean we have to group the items having
70      * that category in a media_list. */
71     if( psz_cat )
72     {
73         p_mlist = vlc_dictionary_value_for_key( &p_mdis->catname_to_submedialist, psz_cat );
74
75         if( p_mlist == kVLCDictionaryNotFound )
76         {
77             libvlc_media_t * p_catmd;
78             p_catmd = libvlc_media_new_as_node( p_mdis->p_libvlc_instance, psz_cat, NULL );
79             p_mlist = libvlc_media_subitems( p_catmd, NULL );
80             p_mlist->b_read_only = true;
81
82             /* Insert the newly created mlist in our dictionary */
83             vlc_dictionary_insert( &p_mdis->catname_to_submedialist, psz_cat, p_mlist );
84
85             /* Insert the md into the root list */
86             libvlc_media_list_lock( p_mdis->p_mlist );
87             _libvlc_media_list_add_media( p_mdis->p_mlist, p_catmd, NULL );
88             libvlc_media_list_unlock( p_mdis->p_mlist );
89
90             /* We don't release the mlist cause the dictionary
91              * doesn't retain the object. But we release the md. */
92             libvlc_media_release( p_catmd );
93         }
94     }
95     else
96     {
97         libvlc_media_list_lock( p_mlist );
98         _libvlc_media_list_add_media( p_mlist, p_md, NULL );
99         libvlc_media_list_unlock( p_mlist );
100     }
101 }
102
103 /**************************************************************************
104  *       services_discovery_item_removed (Private) (VLC event callback)
105  **************************************************************************/
106
107 static void services_discovery_item_removed( const vlc_event_t * p_event,
108                                              void * user_data )
109 {
110     input_item_t * p_item = p_event->u.services_discovery_item_added.p_new_item;
111     libvlc_media_t * p_md;
112     libvlc_media_discoverer_t * p_mdis = user_data;
113
114     int i, count = libvlc_media_list_count( p_mdis->p_mlist, NULL );
115     libvlc_media_list_lock( p_mdis->p_mlist );
116     for( i = 0; i < count; i++ )
117     {
118         p_md = libvlc_media_list_item_at_index( p_mdis->p_mlist, i, NULL );
119         if( p_md->p_input_item == p_item )
120         {
121             _libvlc_media_list_remove_index( p_mdis->p_mlist, i, NULL );
122             break;
123         }
124     }
125     libvlc_media_list_unlock( p_mdis->p_mlist );
126 }
127
128 /**************************************************************************
129  *       services_discovery_started (Private) (VLC event callback)
130  **************************************************************************/
131
132 static void services_discovery_started( const vlc_event_t * p_event,
133                                         void * user_data )
134 {
135     VLC_UNUSED(p_event);
136     libvlc_media_discoverer_t * p_mdis = user_data;
137     libvlc_event_t event;
138     p_mdis->running = true;
139     event.type = libvlc_MediaDiscovererStarted;
140     libvlc_event_send( p_mdis->p_event_manager, &event );
141 }
142
143 /**************************************************************************
144  *       services_discovery_ended (Private) (VLC event callback)
145  **************************************************************************/
146
147 static void services_discovery_ended( const vlc_event_t * p_event,
148                                       void * user_data )
149 {
150     VLC_UNUSED(p_event);
151     libvlc_media_discoverer_t * p_mdis = user_data;
152     libvlc_event_t event;
153     p_mdis->running = false;
154     event.type = libvlc_MediaDiscovererEnded;
155     libvlc_event_send( p_mdis->p_event_manager, &event );
156 }
157
158 /*
159  * Public libvlc functions
160  */
161
162 /**************************************************************************
163  *       new (Public)
164  *
165  * Init an object.
166  **************************************************************************/
167 libvlc_media_discoverer_t *
168 libvlc_media_discoverer_new_from_name( libvlc_instance_t * p_inst,
169                                        const char * psz_name,
170                                        libvlc_exception_t * p_e )
171 {
172     libvlc_media_discoverer_t * p_mdis;
173
174     p_mdis = malloc(sizeof(libvlc_media_discoverer_t));
175     if( !p_mdis )
176     {
177         libvlc_exception_raise( p_e, "Not enough memory" );
178         return NULL;
179     }
180
181     p_mdis->p_libvlc_instance = p_inst;
182     p_mdis->p_mlist = libvlc_media_list_new( p_inst, NULL );
183     p_mdis->p_mlist->b_read_only = true;
184     p_mdis->running = false;
185
186     vlc_dictionary_init( &p_mdis->catname_to_submedialist, 0 );
187
188     p_mdis->p_event_manager = libvlc_event_manager_new( p_mdis,
189             p_inst, NULL );
190
191     libvlc_event_manager_register_event_type( p_mdis->p_event_manager,
192             libvlc_MediaDiscovererStarted, NULL );
193     libvlc_event_manager_register_event_type( p_mdis->p_event_manager,
194             libvlc_MediaDiscovererEnded, NULL );
195
196     p_mdis->p_sd = vlc_sd_Create( (vlc_object_t*)p_inst->p_libvlc_int );
197
198     if( !p_mdis->p_sd )
199     {
200         libvlc_media_list_release( p_mdis->p_mlist );
201         libvlc_exception_raise( p_e, "Can't find the services_discovery module named '%s'", psz_name );
202         free( p_mdis );
203         return NULL;
204     }
205
206     vlc_event_attach( services_discovery_EventManager( p_mdis->p_sd ),
207                       vlc_ServicesDiscoveryItemAdded,
208                       services_discovery_item_added,
209                       p_mdis );
210     vlc_event_attach( services_discovery_EventManager( p_mdis->p_sd ),
211                       vlc_ServicesDiscoveryItemRemoved,
212                       services_discovery_item_removed,
213                       p_mdis );
214     vlc_event_attach( services_discovery_EventManager( p_mdis->p_sd ),
215                       vlc_ServicesDiscoveryStarted,
216                       services_discovery_started,
217                       p_mdis );
218     vlc_event_attach( services_discovery_EventManager( p_mdis->p_sd ),
219                       vlc_ServicesDiscoveryEnded,
220                       services_discovery_ended,
221                       p_mdis );
222
223     /* Here we go */
224     if( !vlc_sd_Start( p_mdis->p_sd, psz_name ) )
225     {
226         libvlc_media_list_release( p_mdis->p_mlist );
227         libvlc_exception_raise( p_e, "Can't start the services_discovery module named '%s'", psz_name );
228         free( p_mdis );
229         return NULL;
230     }
231
232     return p_mdis;
233 }
234
235 /**************************************************************************
236  * release (Public)
237  **************************************************************************/
238 void
239 libvlc_media_discoverer_release( libvlc_media_discoverer_t * p_mdis )
240 {
241     int i;
242
243     libvlc_media_list_release( p_mdis->p_mlist );
244     vlc_sd_StopAndDestroy( p_mdis->p_sd );
245
246     /* Free catname_to_submedialist and all the mlist */
247     char ** all_keys = vlc_dictionary_all_keys( &p_mdis->catname_to_submedialist );
248     for( i = 0; all_keys[i]; i++ )
249     {
250         libvlc_media_list_t * p_catmlist = vlc_dictionary_value_for_key( &p_mdis->catname_to_submedialist, all_keys[i] );
251         libvlc_media_list_release( p_catmlist );
252         free( all_keys[i] );
253     }
254     free( all_keys );
255
256     vlc_dictionary_clear( &p_mdis->catname_to_submedialist, NULL, NULL );
257     libvlc_event_manager_release( p_mdis->p_event_manager );
258
259     free( p_mdis );
260 }
261
262 /**************************************************************************
263  * localized_name (Public)
264  **************************************************************************/
265 char *
266 libvlc_media_discoverer_localized_name( libvlc_media_discoverer_t * p_mdis )
267 {
268     return services_discovery_GetLocalizedName( p_mdis->p_sd );
269 }
270
271 /**************************************************************************
272  * media_list (Public)
273  **************************************************************************/
274 libvlc_media_list_t *
275 libvlc_media_discoverer_media_list( libvlc_media_discoverer_t * p_mdis )
276 {
277     libvlc_media_list_retain( p_mdis->p_mlist );
278     return p_mdis->p_mlist;
279 }
280
281 /**************************************************************************
282  * event_manager (Public)
283  **************************************************************************/
284 libvlc_event_manager_t *
285 libvlc_media_discoverer_event_manager( libvlc_media_discoverer_t * p_mdis )
286 {
287     return p_mdis->p_event_manager;
288 }
289
290
291 /**************************************************************************
292  * running (Public)
293  **************************************************************************/
294 int
295 libvlc_media_discoverer_is_running( libvlc_media_discoverer_t * p_mdis )
296 {
297     return p_mdis->running;
298 }