00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifdef HAVE_CONFIG_H
00027 # include "config.h"
00028 #endif
00029
00030 #ifndef SHARED_SUFFIX
00031 # define SHARED_SUFFIX G_MODULE_SUFFIX
00032 #endif
00033
00034 #include <glib.h>
00035 #include <gmodule.h>
00036 #include <gtk/gtk.h>
00037 #include <string.h>
00038
00039 #include <libaudcore/audstrings.h>
00040 #include <libaudgui/init.h>
00041
00042 #include "pluginenum.h"
00043 #include "plugins.h"
00044
00045 #include "audconfig.h"
00046 #include "debug.h"
00047 #include "effect.h"
00048 #include "general.h"
00049 #include "i18n.h"
00050 #include "interface.h"
00051 #include "main.h"
00052 #include "output.h"
00053 #include "playback.h"
00054 #include "util.h"
00055 #include "visualization.h"
00056
00057 #define AUD_API_DECLARE
00058 #include "configdb.h"
00059 #include "drct.h"
00060 #include "misc.h"
00061 #include "playlist.h"
00062 #include "plugins.h"
00063 #undef AUD_API_DECLARE
00064
00065 const gchar *plugin_dir_list[] = {
00066 PLUGINSUBS,
00067 NULL
00068 };
00069
00070 static AudAPITable api_table = {
00071 .configdb_api = & configdb_api,
00072 .drct_api = & drct_api,
00073 .misc_api = & misc_api,
00074 .playlist_api = & playlist_api,
00075 .plugins_api = & plugins_api,
00076 .cfg = & cfg};
00077
00078 extern GList *vfs_transports;
00079 static mowgli_list_t *headers_list = NULL;
00080
00081 static void input_plugin_init(Plugin * plugin)
00082 {
00083 InputPlugin *p = INPUT_PLUGIN(plugin);
00084
00085 if (p->init != NULL)
00086 p->init ();
00087 }
00088
00089 static void effect_plugin_init(Plugin * plugin)
00090 {
00091 EffectPlugin *p = EFFECT_PLUGIN(plugin);
00092
00093 if (p->init != NULL)
00094 p->init ();
00095 }
00096
00097 static void vis_plugin_disable_by_header (VisPlugin * header)
00098 {
00099 vis_plugin_enable (plugin_by_header (header), FALSE);
00100 }
00101
00102 static void vis_plugin_init(Plugin * plugin)
00103 {
00104 ((VisPlugin *) plugin)->disable_plugin = vis_plugin_disable_by_header;
00105 }
00106
00107
00108
00109 static void plugin2_dispose(GModule * module, const gchar * str, ...)
00110 {
00111 gchar *buf;
00112 va_list va;
00113
00114 va_start(va, str);
00115 buf = g_strdup_vprintf(str, va);
00116 va_end(va);
00117
00118 AUDDBG ("*** %s\n", buf);
00119 g_free(buf);
00120
00121 g_module_close(module);
00122 }
00123
00124 void plugin2_process(PluginHeader * header, GModule * module, const gchar * filename)
00125 {
00126 gint i, n;
00127 mowgli_node_t *hlist_node;
00128
00129 if (header->magic != PLUGIN_MAGIC)
00130 {
00131 plugin2_dispose (module, "plugin <%s> discarded, invalid module magic",
00132 filename);
00133 return;
00134 }
00135
00136 if (header->api_version != __AUDACIOUS_PLUGIN_API__)
00137 {
00138 plugin2_dispose (module, "plugin <%s> discarded, wanting API version "
00139 "%d, we implement API version %d", filename, header->api_version,
00140 __AUDACIOUS_PLUGIN_API__);
00141 return;
00142 }
00143
00144 hlist_node = mowgli_node_create();
00145 mowgli_node_add(header, hlist_node, headers_list);
00146
00147 if (header->init)
00148 {
00149 plugin_register (filename, PLUGIN_TYPE_BASIC, 0, NULL);
00150 header->init();
00151 }
00152
00153 header->priv_assoc = g_new0(Plugin, 1);
00154 header->priv_assoc->handle = module;
00155 header->priv_assoc->filename = g_strdup(filename);
00156
00157 n = 0;
00158
00159 if (header->ip_list)
00160 {
00161 for (i = 0; (header->ip_list)[i] != NULL; i++, n++)
00162 {
00163 plugin_register (filename, PLUGIN_TYPE_INPUT, i, header->ip_list[i]);
00164 PLUGIN((header->ip_list)[i])->filename = g_strdup_printf("%s (#%d)", filename, n);
00165 input_plugin_init(PLUGIN((header->ip_list)[i]));
00166 }
00167 }
00168
00169 if (header->op_list)
00170 {
00171 for (i = 0; (header->op_list)[i] != NULL; i++, n++)
00172 {
00173 OutputPlugin * plugin = header->op_list[i];
00174
00175 plugin->filename = g_strdup_printf ("%s (#%d)", filename, n);
00176 plugin_register (filename, PLUGIN_TYPE_OUTPUT, i, plugin);
00177 }
00178 }
00179
00180 if (header->ep_list)
00181 {
00182 for (i = 0; (header->ep_list)[i] != NULL; i++, n++)
00183 {
00184 plugin_register (filename, PLUGIN_TYPE_EFFECT, i, header->ep_list[i]);
00185 PLUGIN((header->ep_list)[i])->filename = g_strdup_printf("%s (#%d)", filename, n);
00186 effect_plugin_init(PLUGIN((header->ep_list)[i]));
00187 }
00188 }
00189
00190
00191 if (header->gp_list)
00192 {
00193 for (i = 0; (header->gp_list)[i] != NULL; i++, n++)
00194 {
00195 plugin_register (filename, PLUGIN_TYPE_GENERAL, i, header->gp_list[i]);
00196 PLUGIN((header->gp_list)[i])->filename = g_strdup_printf("%s (#%d)", filename, n);
00197 }
00198 }
00199
00200 if (header->vp_list)
00201 {
00202 for (i = 0; (header->vp_list)[i] != NULL; i++, n++)
00203 {
00204 plugin_register (filename, PLUGIN_TYPE_VIS, i, header->vp_list[i]);
00205 PLUGIN((header->vp_list)[i])->filename = g_strdup_printf("%s (#%d)", filename, n);
00206 vis_plugin_init(PLUGIN((header->vp_list)[i]));
00207 }
00208 }
00209
00210 if (header->interface)
00211 plugin_register (filename, PLUGIN_TYPE_IFACE, 0, header->interface);
00212 }
00213
00214 void plugin2_unload(PluginHeader * header, mowgli_node_t * hlist_node)
00215 {
00216 GModule *module;
00217
00218 g_return_if_fail(header->priv_assoc != NULL);
00219
00220 if (header->ip_list != NULL)
00221 {
00222 for (gint i = 0; header->ip_list[i] != NULL; i ++)
00223 {
00224 if (header->ip_list[i]->cleanup != NULL)
00225 header->ip_list[i]->cleanup ();
00226
00227 g_free (header->ip_list[i]->filename);
00228 }
00229 }
00230
00231 if (header->op_list != NULL)
00232 {
00233 for (gint i = 0; header->op_list[i] != NULL; i ++)
00234 g_free (header->op_list[i]->filename);
00235 }
00236
00237 if (header->ep_list != NULL)
00238 {
00239 for (gint i = 0; header->ep_list[i] != NULL; i ++)
00240 {
00241 if (header->ep_list[i]->cleanup != NULL)
00242 header->ep_list[i]->cleanup ();
00243
00244 g_free (header->ep_list[i]->filename);
00245 }
00246 }
00247
00248 if (header->vp_list != NULL)
00249 {
00250 for (gint i = 0; header->vp_list[i] != NULL; i ++)
00251 g_free (header->vp_list[i]->filename);
00252 }
00253
00254 if (header->gp_list != NULL)
00255 {
00256 for (gint i = 0; header->gp_list[i] != NULL; i ++)
00257 g_free (header->gp_list[i]->filename);
00258 }
00259
00260 module = header->priv_assoc->handle;
00261
00262 g_free(header->priv_assoc->filename);
00263 g_free(header->priv_assoc);
00264
00265 if (header->fini)
00266 header->fini();
00267
00268 mowgli_node_delete(hlist_node, headers_list);
00269 mowgli_node_free(hlist_node);
00270
00271 g_module_close(module);
00272 }
00273
00274
00275
00276 void module_load (const gchar * filename)
00277 {
00278 GModule *module;
00279 PluginHeader * (* func) (AudAPITable * table);
00280
00281 AUDDBG ("Loading plugin: %s.\n", filename);
00282
00283 if (!(module = g_module_open(filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL)))
00284 {
00285 printf("Failed to load plugin (%s): %s\n", filename, g_module_error());
00286 return;
00287 }
00288
00289
00290 if (g_module_symbol (module, "get_plugin_info", (void *) & func))
00291 {
00292 PluginHeader * header = func (& api_table);
00293 g_return_if_fail (header != NULL);
00294 plugin2_process(header, module, filename);
00295 return;
00296 }
00297
00298 printf("Invalid plugin (%s)\n", filename);
00299 g_module_close(module);
00300 }
00301
00302 static gboolean scan_plugin_func(const gchar * path, const gchar * basename, gpointer data)
00303 {
00304 if (!str_has_suffix_nocase(basename, SHARED_SUFFIX))
00305 return FALSE;
00306
00307 if (!g_file_test(path, G_FILE_TEST_IS_REGULAR))
00308 return FALSE;
00309
00310 module_register (path);
00311
00312 return FALSE;
00313 }
00314
00315 static void scan_plugins(const gchar * path)
00316 {
00317 dir_foreach(path, scan_plugin_func, NULL, NULL);
00318 }
00319
00320 static OutputPlugin * output_load_selected (void)
00321 {
00322 if (cfg.output_path == NULL)
00323 return NULL;
00324
00325 PluginHandle * handle = plugin_by_path (cfg.output_path, PLUGIN_TYPE_OUTPUT,
00326 cfg.output_number);
00327 if (handle == NULL)
00328 return NULL;
00329
00330 OutputPlugin * plugin = plugin_get_header (handle);
00331 if (plugin == NULL || plugin->init () != OUTPUT_PLUGIN_INIT_FOUND_DEVICES)
00332 return NULL;
00333
00334 return plugin;
00335 }
00336
00337 static gboolean output_probe_func (PluginHandle * handle, OutputPlugin * * result)
00338 {
00339 AUDDBG ("Probing output plugin %s.\n", plugin_get_name (handle));
00340 OutputPlugin * plugin = plugin_get_header (handle);
00341
00342 if (plugin == NULL || plugin->init == NULL || plugin->init () !=
00343 OUTPUT_PLUGIN_INIT_FOUND_DEVICES)
00344 return TRUE;
00345
00346 * result = plugin;
00347 return FALSE;
00348 }
00349
00350 static OutputPlugin * output_probe (void)
00351 {
00352 OutputPlugin * plugin = NULL;
00353 plugin_for_each (PLUGIN_TYPE_OUTPUT, (PluginForEachFunc) output_probe_func,
00354 & plugin);
00355
00356 if (plugin == NULL)
00357 fprintf (stderr, "ALL OUTPUT PLUGINS FAILED TO INITIALIZE.\n");
00358
00359 return plugin;
00360 }
00361
00362 void plugin_system_init(void)
00363 {
00364 gchar *dir;
00365 GtkWidget *dialog;
00366 gint dirsel = 0;
00367
00368 audgui_init (& api_table);
00369
00370 if (!g_module_supported())
00371 {
00372 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Module loading not supported! Plugins will not be loaded.\n"));
00373 gtk_dialog_run(GTK_DIALOG(dialog));
00374 gtk_widget_destroy(dialog);
00375 return;
00376 }
00377
00378 plugin_registry_load ();
00379
00380 headers_list = mowgli_list_create();
00381
00382 #ifndef DISABLE_USER_PLUGIN_DIR
00383 scan_plugins(aud_paths[BMP_PATH_USER_PLUGIN_DIR]);
00384
00385
00386
00387
00388
00389 while (plugin_dir_list[dirsel])
00390 {
00391 dir = g_build_filename(aud_paths[BMP_PATH_USER_PLUGIN_DIR], plugin_dir_list[dirsel++], NULL);
00392 scan_plugins(dir);
00393 g_free(dir);
00394 }
00395 dirsel = 0;
00396 #endif
00397
00398 while (plugin_dir_list[dirsel])
00399 {
00400 dir = g_build_filename(PLUGIN_DIR, plugin_dir_list[dirsel++], NULL);
00401 scan_plugins(dir);
00402 g_free(dir);
00403 }
00404
00405 plugin_registry_prune ();
00406
00407 current_output_plugin = output_load_selected ();
00408
00409 if (current_output_plugin == NULL)
00410 current_output_plugin = output_probe ();
00411
00412 general_init ();
00413 }
00414
00415 void plugin_system_cleanup(void)
00416 {
00417 mowgli_node_t *hlist_node;
00418
00419 AUDDBG ("Shutting down plugin system.\n");
00420
00421 if (current_output_plugin != NULL)
00422 {
00423 if (current_output_plugin->cleanup != NULL)
00424 current_output_plugin->cleanup ();
00425
00426 current_output_plugin = NULL;
00427 }
00428
00429 general_cleanup ();
00430
00431 plugin_registry_save ();
00432
00433
00434 if (vfs_transports != NULL)
00435 {
00436 g_list_free(vfs_transports);
00437 vfs_transports = NULL;
00438 }
00439
00440 MOWGLI_LIST_FOREACH(hlist_node, headers_list->head) plugin2_unload(hlist_node->data, hlist_node);
00441
00442 mowgli_list_free(headers_list);
00443 }