00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <errno.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025
00026 #include <glib.h>
00027
00028 #include "debug.h"
00029 #include "effect.h"
00030 #include "general.h"
00031 #include "interface.h"
00032 #include "main.h"
00033 #include "output.h"
00034 #include "plugin.h"
00035 #include "plugins.h"
00036 #include "ui_preferences.h"
00037 #include "visualization.h"
00038
00039 static bool_t dummy_plugin_start (PluginHandle * p)
00040 {
00041 return TRUE;
00042 }
00043
00044 static void dummy_plugin_stop (PluginHandle * p)
00045 {
00046 }
00047
00048 static const struct {
00049 const char * name;
00050 bool_t is_managed, is_single;
00051
00052 union {
00053 struct {
00054 bool_t (* start) (PluginHandle * plugin);
00055 void (* stop) (PluginHandle * plugin);
00056 } m;
00057
00058 struct {
00059 PluginHandle * (* probe) (void);
00060 PluginHandle * (* get_current) (void);
00061 bool_t (* set_current) (PluginHandle * plugin);
00062 } s;
00063 } u;
00064 } table[PLUGIN_TYPES] = {
00065 [PLUGIN_TYPE_TRANSPORT] = {"transport", TRUE, FALSE, .u.m =
00066 {dummy_plugin_start, dummy_plugin_stop}},
00067 [PLUGIN_TYPE_PLAYLIST] = {"playlist", TRUE, FALSE, .u.m = {dummy_plugin_start,
00068 dummy_plugin_stop}},
00069 [PLUGIN_TYPE_INPUT] = {"input", TRUE, FALSE, .u.m = {dummy_plugin_start,
00070 dummy_plugin_stop}},
00071 [PLUGIN_TYPE_EFFECT] = {"effect", TRUE, FALSE, .u.m = {effect_plugin_start,
00072 effect_plugin_stop}},
00073 [PLUGIN_TYPE_OUTPUT] = {"output", TRUE, TRUE, .u.s = {output_plugin_probe,
00074 output_plugin_get_current, output_plugin_set_current}},
00075 [PLUGIN_TYPE_VIS] = {"visualization", TRUE, FALSE, .u.m = {vis_plugin_start,
00076 vis_plugin_stop}},
00077 [PLUGIN_TYPE_GENERAL] = {"general", TRUE, FALSE, .u.m = {general_plugin_start,
00078 general_plugin_stop}},
00079 [PLUGIN_TYPE_IFACE] = {"interface", TRUE, TRUE, .u.s = {iface_plugin_probe,
00080 iface_plugin_get_current, iface_plugin_set_current}}};
00081
00082 static bool_t find_enabled_cb (PluginHandle * p, PluginHandle * * pp)
00083 {
00084 * pp = p;
00085 return FALSE;
00086 }
00087
00088 static PluginHandle * find_enabled (int type)
00089 {
00090 PluginHandle * p = NULL;
00091 plugin_for_enabled (type, (PluginForEachFunc) find_enabled_cb, & p);
00092 return p;
00093 }
00094
00095 static void start_single (int type)
00096 {
00097 PluginHandle * p;
00098
00099 if ((p = find_enabled (type)) != NULL)
00100 {
00101 AUDDBG ("Starting selected %s plugin %s.\n", table[type].name,
00102 plugin_get_name (p));
00103
00104 if (table[type].u.s.set_current (p))
00105 return;
00106
00107 AUDDBG ("%s failed to start.\n", plugin_get_name (p));
00108 plugin_set_enabled (p, FALSE);
00109 }
00110
00111 AUDDBG ("Probing for %s plugin.\n", table[type].name);
00112
00113 if ((p = table[type].u.s.probe ()) == NULL)
00114 {
00115 fprintf (stderr, "FATAL: No %s plugin found.\n", table[type].name);
00116 exit (EXIT_FAILURE);
00117 }
00118
00119 AUDDBG ("Starting %s.\n", plugin_get_name (p));
00120 plugin_set_enabled (p, TRUE);
00121
00122 if (! table[type].u.s.set_current (p))
00123 {
00124 fprintf (stderr, "FATAL: %s failed to start.\n", plugin_get_name (p));
00125 plugin_set_enabled (p, FALSE);
00126 exit (EXIT_FAILURE);
00127 }
00128 }
00129
00130 static bool_t start_multi_cb (PluginHandle * p, void * type)
00131 {
00132 AUDDBG ("Starting %s.\n", plugin_get_name (p));
00133
00134 if (! table[GPOINTER_TO_INT (type)].u.m.start (p))
00135 {
00136 AUDDBG ("%s failed to start; disabling.\n", plugin_get_name (p));
00137 plugin_set_enabled (p, FALSE);
00138 }
00139
00140 return TRUE;
00141 }
00142
00143 static void start_plugins (int type)
00144 {
00145 if (! table[type].is_managed)
00146 return;
00147 if (headless && type == PLUGIN_TYPE_IFACE)
00148 return;
00149
00150 if (table[type].is_single)
00151 start_single (type);
00152 else
00153 plugin_for_enabled (type, (PluginForEachFunc) start_multi_cb,
00154 GINT_TO_POINTER (type));
00155 }
00156
00157 static VFSConstructor * lookup_transport (const char * scheme)
00158 {
00159 PluginHandle * plugin = transport_plugin_for_scheme (scheme);
00160 if (! plugin)
00161 return NULL;
00162
00163 TransportPlugin * tp = plugin_get_header (plugin);
00164 return tp ? tp->vtable : NULL;
00165 }
00166
00167 void start_plugins_one (void)
00168 {
00169 plugin_system_init ();
00170 vfs_set_lookup_func (lookup_transport);
00171
00172 for (int i = 0; i < PLUGIN_TYPE_GENERAL; i ++)
00173 start_plugins (i);
00174 }
00175
00176 void start_plugins_two (void)
00177 {
00178 for (int i = PLUGIN_TYPE_GENERAL; i < PLUGIN_TYPES; i ++)
00179 start_plugins (i);
00180 }
00181
00182 static bool_t stop_multi_cb (PluginHandle * p, void * type)
00183 {
00184 AUDDBG ("Shutting down %s.\n", plugin_get_name (p));
00185 table[GPOINTER_TO_INT (type)].u.m.stop (p);
00186 return TRUE;
00187 }
00188
00189 static void stop_plugins (int type)
00190 {
00191 if (! table[type].is_managed)
00192 return;
00193 if (headless && type == PLUGIN_TYPE_IFACE)
00194 return;
00195
00196 if (table[type].is_single)
00197 {
00198 AUDDBG ("Shutting down %s.\n", plugin_get_name
00199 (table[type].u.s.get_current ()));
00200 table[type].u.s.set_current (NULL);
00201 }
00202 else
00203 plugin_for_enabled (type, (PluginForEachFunc) stop_multi_cb,
00204 GINT_TO_POINTER (type));
00205 }
00206
00207 void stop_plugins_two (void)
00208 {
00209 for (int i = PLUGIN_TYPES - 1; i >= PLUGIN_TYPE_GENERAL; i --)
00210 stop_plugins (i);
00211 }
00212
00213 void stop_plugins_one (void)
00214 {
00215 for (int i = PLUGIN_TYPE_GENERAL - 1; i >= 0; i --)
00216 stop_plugins (i);
00217
00218 vfs_set_lookup_func (NULL);
00219 plugin_system_cleanup ();
00220 }
00221
00222 PluginHandle * plugin_get_current (int type)
00223 {
00224 g_return_val_if_fail (table[type].is_managed && table[type].is_single, NULL);
00225 return table[type].u.s.get_current ();
00226 }
00227
00228 static bool_t enable_single (int type, PluginHandle * p)
00229 {
00230 PluginHandle * old = table[type].u.s.get_current ();
00231
00232 AUDDBG ("Switching from %s to %s.\n", plugin_get_name (old),
00233 plugin_get_name (p));
00234 plugin_set_enabled (old, FALSE);
00235 plugin_set_enabled (p, TRUE);
00236
00237 if (table[type].u.s.set_current (p))
00238 return TRUE;
00239
00240 fprintf (stderr, "%s failed to start; falling back to %s.\n",
00241 plugin_get_name (p), plugin_get_name (old));
00242 plugin_set_enabled (p, FALSE);
00243 plugin_set_enabled (old, TRUE);
00244
00245 if (table[type].u.s.set_current (old))
00246 return FALSE;
00247
00248 fprintf (stderr, "FATAL: %s failed to start.\n", plugin_get_name (old));
00249 plugin_set_enabled (old, FALSE);
00250 exit (EXIT_FAILURE);
00251 }
00252
00253 static bool_t enable_multi (int type, PluginHandle * p, bool_t enable)
00254 {
00255 AUDDBG ("%sabling %s.\n", enable ? "En" : "Dis", plugin_get_name (p));
00256 plugin_set_enabled (p, enable);
00257
00258 if (enable)
00259 {
00260 if (! table[type].u.m.start (p))
00261 {
00262 fprintf (stderr, "%s failed to start.\n", plugin_get_name (p));
00263 plugin_set_enabled (p, FALSE);
00264 return FALSE;
00265 }
00266 }
00267 else
00268 table[type].u.m.stop (p);
00269
00270 return TRUE;
00271 }
00272
00273 bool_t plugin_enable (PluginHandle * plugin, bool_t enable)
00274 {
00275 if (! enable == ! plugin_get_enabled (plugin))
00276 {
00277 AUDDBG ("%s is already %sabled.\n", plugin_get_name (plugin), enable ?
00278 "en" : "dis");
00279 return TRUE;
00280 }
00281
00282 int type = plugin_get_type (plugin);
00283 g_return_val_if_fail (table[type].is_managed, FALSE);
00284
00285 if (table[type].is_single)
00286 {
00287 g_return_val_if_fail (enable, FALSE);
00288 return enable_single (type, plugin);
00289 }
00290
00291 return enable_multi (type, plugin, enable);
00292 }
00293
00294
00295
00296 PluginHandle * plugin_by_widget ( void * widget)
00297 {
00298 PluginHandle * p;
00299 if ((p = vis_plugin_by_widget (widget)))
00300 return p;
00301 if ((p = general_plugin_by_widget (widget)))
00302 return p;
00303 return NULL;
00304 }
00305
00306 int plugin_send_message (PluginHandle * plugin, const char * code, const void * data, int size)
00307 {
00308 if (! plugin_get_enabled (plugin))
00309 return ENOSYS;
00310
00311 Plugin * header = plugin_get_header (plugin);
00312 if (! header || ! PLUGIN_HAS_FUNC (header, take_message))
00313 return ENOSYS;
00314
00315 return header->take_message (code, data, size);
00316 }