VT: only use hw decoding unless explicitely requested
[vlc.git] / src / misc / addons.c
blob662b6bcc79ff0cfec9de2443ac238b492bbbca67
1 /*****************************************************************************
2 * addons.c: VLC addons manager
3 *****************************************************************************
4 * Copyright (C) 2014 VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
25 #include <vlc_common.h>
26 #include <vlc_atomic.h>
27 #include <vlc_modules.h>
28 #include <vlc_arrays.h>
29 #include "libvlc.h"
31 #include <vlc_addons.h>
33 /*****************************************************************************
34 * Structures/definitions
35 *****************************************************************************/
37 typedef struct addon_entry_owner
39 addon_entry_t entry;
40 atomic_uint refs;
41 } addon_entry_owner_t;
43 struct addons_manager_private_t
45 vlc_object_t *p_parent;
47 struct
49 vlc_thread_t thread;
50 vlc_cond_t waitcond;
51 bool b_live;
52 vlc_mutex_t lock;
53 DECL_ARRAY(char*) uris;
54 DECL_ARRAY(addon_entry_t*) entries;
55 } finder;
57 struct
59 vlc_thread_t thread;
60 vlc_cond_t waitcond;
61 bool b_live;
62 vlc_mutex_t lock;
63 DECL_ARRAY(addon_entry_t*) entries;
64 } installer;
67 static void *FinderThread( void * );
68 static void LoadLocalStorage( addons_manager_t *p_manager );
70 /*****************************************************************************
71 * Public functions
72 *****************************************************************************/
74 addon_entry_t * addon_entry_New(void)
76 addon_entry_owner_t *owner = calloc( 1, sizeof(addon_entry_owner_t) );
77 if( unlikely(owner == NULL) )
78 return NULL;
80 atomic_init( &owner->refs, 1 );
82 addon_entry_t *p_entry = &owner->entry;
83 vlc_mutex_init( &p_entry->lock );
84 ARRAY_INIT( p_entry->files );
85 return p_entry;
88 addon_entry_t * addon_entry_Hold( addon_entry_t * p_entry )
90 addon_entry_owner_t *owner = (addon_entry_owner_t *) p_entry;
92 atomic_fetch_add( &owner->refs, 1 );
93 return p_entry;
96 void addon_entry_Release( addon_entry_t * p_entry )
98 addon_entry_owner_t *owner = (addon_entry_owner_t *) p_entry;
100 if( atomic_fetch_sub(&owner->refs, 1) != 1 )
101 return;
103 free( p_entry->psz_name );
104 free( p_entry->psz_summary );
105 free( p_entry->psz_description );
106 free( p_entry->psz_archive_uri );
107 free( p_entry->psz_author );
108 free( p_entry->psz_source_uri );
109 free( p_entry->psz_image_uri );
110 free( p_entry->psz_image_data );
111 free( p_entry->psz_source_module );
112 free( p_entry->psz_version );
113 free( p_entry->p_custom );
115 addon_file_t *p_file;
116 FOREACH_ARRAY( p_file, p_entry->files )
117 free( p_file->psz_filename );
118 free( p_file->psz_download_uri );
119 free( p_file );
120 FOREACH_END()
121 ARRAY_RESET( p_entry->files );
123 vlc_mutex_destroy( &p_entry->lock );
124 free( owner );
127 addons_manager_t *addons_manager_New( vlc_object_t *p_this,
128 const struct addons_manager_owner *restrict owner )
130 addons_manager_t *p_manager = malloc( sizeof(addons_manager_t) );
131 if ( !p_manager ) return NULL;
133 p_manager->p_priv = malloc( sizeof(addons_manager_private_t) );
134 if ( !p_manager->p_priv )
136 free( p_manager );
137 return NULL;
140 p_manager->owner = *owner;
141 p_manager->p_priv->p_parent = p_this;
143 #define INIT_QUEUE( name ) \
144 p_manager->p_priv->name.b_live = false;\
145 vlc_mutex_init( &p_manager->p_priv->name.lock );\
146 vlc_cond_init( &p_manager->p_priv->name.waitcond );\
147 ARRAY_INIT( p_manager->p_priv->name.entries );
149 INIT_QUEUE( finder )
150 INIT_QUEUE( installer )
151 ARRAY_INIT( p_manager->p_priv->finder.uris );
153 return p_manager;
156 void addons_manager_Delete( addons_manager_t *p_manager )
158 bool b_live;
160 vlc_mutex_lock( &p_manager->p_priv->finder.lock );
161 b_live = p_manager->p_priv->finder.b_live;
162 vlc_mutex_unlock( &p_manager->p_priv->finder.lock );
163 if ( b_live )
165 vlc_cancel( p_manager->p_priv->finder.thread );
166 vlc_join( p_manager->p_priv->finder.thread, NULL );
169 vlc_mutex_lock( &p_manager->p_priv->installer.lock );
170 b_live = p_manager->p_priv->installer.b_live;
171 vlc_mutex_unlock( &p_manager->p_priv->installer.lock );
172 if ( b_live )
174 vlc_cancel( p_manager->p_priv->installer.thread );
175 vlc_join( p_manager->p_priv->installer.thread, NULL );
178 #define FREE_QUEUE( name ) \
179 FOREACH_ARRAY( addon_entry_t *p_entry, p_manager->p_priv->name.entries )\
180 addon_entry_Release( p_entry );\
181 FOREACH_END();\
182 ARRAY_RESET( p_manager->p_priv->name.entries );\
183 vlc_mutex_destroy( &p_manager->p_priv->name.lock );\
184 vlc_cond_destroy( &p_manager->p_priv->name.waitcond );
186 FREE_QUEUE( finder )
187 FREE_QUEUE( installer )
188 FOREACH_ARRAY( char *psz_uri, p_manager->p_priv->finder.uris )
189 free( psz_uri );
190 FOREACH_END();
191 ARRAY_RESET( p_manager->p_priv->finder.uris );
193 free( p_manager->p_priv );
194 free( p_manager );
197 void addons_manager_Gather( addons_manager_t *p_manager, const char *psz_uri )
199 if ( !psz_uri )
200 return;
202 vlc_mutex_lock( &p_manager->p_priv->finder.lock );
204 ARRAY_APPEND( p_manager->p_priv->finder.uris, strdup( psz_uri ) );
206 if( !p_manager->p_priv->finder.b_live )
208 if( vlc_clone( &p_manager->p_priv->finder.thread, FinderThread, p_manager,
209 VLC_THREAD_PRIORITY_LOW ) )
211 msg_Err( p_manager->p_priv->p_parent,
212 "cannot spawn entries provider thread" );
213 vlc_mutex_unlock( &p_manager->p_priv->finder.lock );
214 return;
216 p_manager->p_priv->finder.b_live = true;
219 vlc_mutex_unlock( &p_manager->p_priv->finder.lock );
220 vlc_cond_signal( &p_manager->p_priv->finder.waitcond );
223 /*****************************************************************************
224 * Private functions
225 *****************************************************************************/
227 static addon_entry_t * getHeldEntryByUUID( addons_manager_t *p_manager,
228 const addon_uuid_t uuid )
230 addon_entry_t *p_return = NULL;
231 vlc_mutex_lock( &p_manager->p_priv->finder.lock );
232 FOREACH_ARRAY( addon_entry_t *p_entry, p_manager->p_priv->finder.entries )
233 if ( !memcmp( p_entry->uuid, uuid, sizeof( addon_uuid_t ) ) )
235 p_return = p_entry;
236 addon_entry_Hold( p_return );
237 break;
239 FOREACH_END()
240 vlc_mutex_unlock( &p_manager->p_priv->finder.lock );
241 return p_return;
244 static void MergeSources( addons_manager_t *p_manager,
245 addon_entry_t **pp_addons, int i_count )
247 addon_entry_t *p_entry, *p_manager_entry;
248 addon_uuid_t zerouuid;
249 memset( zerouuid, 0, sizeof( addon_uuid_t ) );
250 for ( int i=0; i < i_count; i++ )
252 p_entry = pp_addons[i];
253 vlc_mutex_lock( &p_entry->lock );
254 if ( memcmp( p_entry->uuid, zerouuid, sizeof( addon_uuid_t ) ) )
255 p_manager_entry = getHeldEntryByUUID( p_manager, p_entry->uuid );
256 else
257 p_manager_entry = NULL;
258 if ( !p_manager_entry )
260 ARRAY_APPEND( p_manager->p_priv->finder.entries, p_entry );
261 p_manager->owner.addon_found( p_manager, p_entry );
263 else
265 vlc_mutex_lock( &p_manager_entry->lock );
266 if ( ( p_manager_entry->psz_version && p_entry->psz_version )
267 && /* FIXME: better version comparison */
268 strcmp( p_manager_entry->psz_version, p_entry->psz_version )
271 p_manager_entry->e_flags |= ADDON_UPDATABLE;
273 vlc_mutex_unlock( &p_manager_entry->lock );
274 addon_entry_Release( p_manager_entry );
276 vlc_mutex_unlock( &p_entry->lock );
280 static void LoadLocalStorage( addons_manager_t *p_manager )
282 addons_finder_t *p_finder =
283 vlc_custom_create( p_manager->p_priv->p_parent, sizeof( *p_finder ), "entries finder" );
284 p_finder->obj.flags |= OBJECT_FLAGS_NOINTERACT;
286 module_t *p_module = module_need( p_finder, "addons finder",
287 "addons.store.list", true );
288 if( p_module )
290 ARRAY_INIT( p_finder->entries );
291 p_finder->psz_uri = NULL;
292 p_finder->pf_find( p_finder );
293 module_unneed( p_finder, p_module );
295 MergeSources( p_manager, p_finder->entries.p_elems, p_finder->entries.i_size );
297 ARRAY_RESET( p_finder->entries );
299 vlc_object_release( p_finder );
302 static void *FinderThread( void *p_data )
304 addons_manager_t *p_manager = p_data;
306 for( ;; )
308 char *psz_uri;
310 vlc_mutex_lock( &p_manager->p_priv->finder.lock );
311 mutex_cleanup_push( &p_manager->p_priv->finder.lock );
312 while( p_manager->p_priv->finder.uris.i_size == 0 )
314 vlc_cond_wait( &p_manager->p_priv->finder.waitcond,
315 &p_manager->p_priv->finder.lock );
317 psz_uri = p_manager->p_priv->finder.uris.p_elems[0];
318 ARRAY_REMOVE( p_manager->p_priv->finder.uris, 0 );
319 vlc_cleanup_pop();
320 vlc_mutex_unlock( &p_manager->p_priv->finder.lock );
322 int i_cancel = vlc_savecancel();
324 addons_finder_t *p_finder =
325 vlc_custom_create( p_manager->p_priv->p_parent, sizeof( *p_finder ), "entries finder" );
327 if( p_finder != NULL )
329 p_finder->obj.flags |= OBJECT_FLAGS_NOINTERACT;
330 module_t *p_module;
331 ARRAY_INIT( p_finder->entries );
332 p_finder->psz_uri = psz_uri;
334 p_module = module_need( p_finder, "addons finder", NULL, false );
335 if( p_module )
337 p_finder->pf_find( p_finder );
338 module_unneed( p_finder, p_module );
339 MergeSources( p_manager, p_finder->entries.p_elems, p_finder->entries.i_size );
341 ARRAY_RESET( p_finder->entries );
342 free( psz_uri );
343 vlc_object_release( p_finder );
346 p_manager->owner.discovery_ended( p_manager );
347 vlc_restorecancel( i_cancel );
348 vlc_testcancel();
351 return NULL;
354 static int addons_manager_WriteCatalog( addons_manager_t *p_manager )
356 int i_return = VLC_EGENERIC;
358 addons_storage_t *p_storage =
359 vlc_custom_create( p_manager->p_priv->p_parent, sizeof( *p_storage ), "entries storage" );
360 p_storage->obj.flags |= OBJECT_FLAGS_NOINTERACT;
362 module_t *p_module = module_need( p_storage, "addons storage",
363 "addons.store.install", true );
364 if( p_module )
366 vlc_mutex_lock( &p_manager->p_priv->finder.lock );
367 i_return = p_storage->pf_catalog( p_storage, p_manager->p_priv->finder.entries.p_elems,
368 p_manager->p_priv->finder.entries.i_size );
369 vlc_mutex_unlock( &p_manager->p_priv->finder.lock );
370 module_unneed( p_storage, p_module );
372 vlc_object_release( p_storage );
374 return i_return;
377 int addons_manager_LoadCatalog( addons_manager_t *p_manager )
379 LoadLocalStorage( p_manager );
380 return VLC_SUCCESS;
383 static int installOrRemoveAddon( addons_manager_t *p_manager, addon_entry_t *p_entry, bool b_install )
385 int i_return = VLC_EGENERIC;
387 addons_storage_t *p_storage =
388 vlc_custom_create( p_manager->p_priv->p_parent, sizeof( *p_storage ), "entries storage" );
389 p_storage->obj.flags |= OBJECT_FLAGS_NOINTERACT;
391 module_t *p_module = module_need( p_storage, "addons storage",
392 "addons.store.install", true );
393 if( p_module )
395 if ( b_install )
396 i_return = p_storage->pf_install( p_storage, p_entry );
397 else
398 i_return = p_storage->pf_remove( p_storage, p_entry );
399 module_unneed( p_storage, p_module );
400 msg_Dbg( p_manager->p_priv->p_parent, "InstallAddon returns %d", i_return );
401 if ( i_return == VLC_SUCCESS )
403 /* Reset flags */
404 vlc_mutex_lock( &p_entry->lock );
405 p_entry->e_flags = ADDON_MANAGEABLE;
406 vlc_mutex_unlock( &p_entry->lock );
409 vlc_object_release( p_storage );
411 return i_return;
414 static void *InstallerThread( void *p_data )
416 addons_manager_t *p_manager = p_data;
417 int i_ret;
419 for( ;; )
421 vlc_mutex_lock( &p_manager->p_priv->installer.lock );
422 mutex_cleanup_push( &p_manager->p_priv->installer.lock );
423 while ( !p_manager->p_priv->installer.entries.i_size )
425 /* No queued addons */
426 vlc_cond_wait( &p_manager->p_priv->installer.waitcond,
427 &p_manager->p_priv->installer.lock );
429 vlc_cleanup_pop();
431 addon_entry_t *p_entry = p_manager->p_priv->installer.entries.p_elems[0];
432 ARRAY_REMOVE( p_manager->p_priv->installer.entries, 0 );
433 addon_entry_Hold( p_entry );
434 vlc_mutex_unlock( &p_manager->p_priv->installer.lock );
436 int i_cancel = vlc_savecancel();
437 vlc_mutex_lock( &p_entry->lock );
438 /* DO WORK */
439 if ( p_entry->e_state == ADDON_INSTALLED )
441 p_entry->e_state = ADDON_UNINSTALLING;
442 vlc_mutex_unlock( &p_entry->lock );
444 /* notify */
445 p_manager->owner.addon_changed( p_manager, p_entry );
447 i_ret = installOrRemoveAddon( p_manager, p_entry, false );
449 vlc_mutex_lock( &p_entry->lock );
450 p_entry->e_state = ( i_ret == VLC_SUCCESS ) ? ADDON_NOTINSTALLED
451 : ADDON_INSTALLED;
453 else if ( p_entry->e_state == ADDON_NOTINSTALLED )
455 p_entry->e_state = ADDON_INSTALLING;
456 vlc_mutex_unlock( &p_entry->lock );
458 /* notify */
459 p_manager->owner.addon_changed( p_manager, p_entry );
461 i_ret = installOrRemoveAddon( p_manager, p_entry, true );
463 vlc_mutex_lock( &p_entry->lock );
464 p_entry->e_state = ( i_ret == VLC_SUCCESS ) ? ADDON_INSTALLED
465 : ADDON_NOTINSTALLED;
467 vlc_mutex_unlock( &p_entry->lock );
468 /* !DO WORK */
470 p_manager->owner.addon_changed( p_manager, p_entry );
472 addon_entry_Release( p_entry );
474 addons_manager_WriteCatalog( p_manager );
475 vlc_restorecancel( i_cancel );
478 return NULL;
481 static int InstallEntry( addons_manager_t *p_manager, addon_entry_t *p_entry )
483 if ( p_entry->e_type == ADDON_UNKNOWN ||
484 p_entry->e_type == ADDON_PLUGIN ||
485 p_entry->e_type == ADDON_OTHER )
486 return VLC_EBADVAR;
488 vlc_mutex_lock( &p_manager->p_priv->installer.lock );
489 ARRAY_APPEND( p_manager->p_priv->installer.entries, p_entry );
490 if( !p_manager->p_priv->installer.b_live )
492 if( vlc_clone( &p_manager->p_priv->installer.thread, InstallerThread, p_manager,
493 VLC_THREAD_PRIORITY_LOW ) )
495 msg_Err( p_manager->p_priv->p_parent,
496 "cannot spawn addons installer thread" );
497 vlc_mutex_unlock( &p_manager->p_priv->installer.lock );
498 return VLC_EGENERIC;
500 else
501 p_manager->p_priv->installer.b_live = true;
503 vlc_mutex_unlock( &p_manager->p_priv->installer.lock );
504 vlc_cond_signal( &p_manager->p_priv->installer.waitcond );
505 return VLC_SUCCESS;
508 int addons_manager_Install( addons_manager_t *p_manager, const addon_uuid_t uuid )
510 addon_entry_t *p_install_entry = getHeldEntryByUUID( p_manager, uuid );
511 if ( ! p_install_entry ) return VLC_EGENERIC;
512 int i_ret = InstallEntry( p_manager, p_install_entry );
513 addon_entry_Release( p_install_entry );
514 return i_ret;
517 int addons_manager_Remove( addons_manager_t *p_manager, const addon_uuid_t uuid )
519 return addons_manager_Install( p_manager, uuid );