chiark / gitweb /
speaker protocol redesign to cope with libao re-opening
[disorder] / lib / plugin.c
CommitLineData
460b9539 1/*
2 * This file is part of DisOrder.
3 * Copyright (C) 2004, 2005, 2006 Richard Kettlewell
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18 * USA
19 */
20
21#include <config.h>
6d2d327c 22#include "types.h"
460b9539 23
24#include <dlfcn.h>
25#include <unistd.h>
26#include <string.h>
27#include <stdio.h>
28
29#include "plugin.h"
30#include "configuration.h"
31#include "log.h"
32#include "mem.h"
33#include "defs.h"
34#include "disorder.h"
35#include "printf.h"
36
37/* generic plugin support *****************************************************/
38
39#ifndef SOSUFFIX
40# define SOSUFFIX ".so"
41#endif
42
43struct plugin {
44 struct plugin *next;
45 void *dlhandle;
46 const char *name;
47};
48
49static struct plugin *plugins;
50
51const struct plugin *open_plugin(const char *name,
52 unsigned flags) {
53 void *h = 0;
54 char *p;
55 int n;
56 struct plugin *pl;
57
58 for(pl = plugins; pl && strcmp(pl->name, name); pl = pl->next)
59 ;
60 if(pl) return pl;
61 for(n = 0; n <= config->plugins.n; ++n) {
62 byte_xasprintf(&p, "%s/%s" SOSUFFIX,
63 n == config->plugins.n ? pkglibdir : config->plugins.s[n],
64 name);
65 if(access(p, R_OK) == 0) {
66 h = dlopen(p, RTLD_NOW);
67 if(!h) {
68 error(0, "error opening %s: %s", p, dlerror());
69 continue;
70 }
71 pl = xmalloc(sizeof *pl);
72 pl->dlhandle = h;
73 pl->name = xstrdup(name);
74 pl->next = plugins;
75 plugins = pl;
76 return pl;
77 }
78 }
79 (flags & PLUGIN_FATAL ? fatal : error)(0, "cannot find plugin '%s'", name);
80 return 0;
81}
82
83function_t *get_plugin_function(const struct plugin *pl,
84 const char *symbol) {
85 function_t *f;
86 const char *e;
87
88 f = (function_t *)dlsym(pl->dlhandle, symbol);
89 if((e = dlerror()))
90 fatal(0, "error looking up function '%s' in '%s': %s",symbol, pl->name, e);
91 return f;
92}
93
94const void *get_plugin_object(const struct plugin *pl,
95 const char *symbol) {
96 void *o;
97 const char *e;
98
99 o = dlsym(pl->dlhandle, symbol);
100 if((e = dlerror()))
101 fatal(0, "error looking up object '%s' in '%s': %s", symbol, pl->name, e);
102 return o;
103}
104
105/* specific plugin interfaces *************************************************/
106
107typedef long tracklength_fn(const char *track, const char *path);
108
109long tracklength(const char *track, const char *path) {
110 static tracklength_fn *f = 0;
111
112 if(!f)
113 f = (tracklength_fn *)get_plugin_function(open_plugin("tracklength",
114 PLUGIN_FATAL),
115 "disorder_tracklength");
116 return (*f)(track, path);
117}
118
119typedef void scan_fn(const char *root);
120
121void scan(const char *module, const char *root) {
122 ((scan_fn *)get_plugin_function(open_plugin(module, PLUGIN_FATAL),
123 "disorder_scan"))(root);
124}
125
126typedef int check_fn(const char *root, const char *path);
127
128
129int check(const char *module, const char *root, const char *path) {
130 return ((check_fn *)get_plugin_function(open_plugin(module, PLUGIN_FATAL),
131 "disorder_check"))(root, path);
132}
133
134typedef void notify_play_fn(const char *track, const char *submitter);
135
136void notify_play(const char *track,
137 const char *submitter) {
138 static notify_play_fn *f;
139
140 if(!f)
141 f = (notify_play_fn *)get_plugin_function(open_plugin("notify",
142 PLUGIN_FATAL),
143 "disorder_notify_play");
144 (*f)(track, submitter);
145}
146
147typedef void notify_scratch_fn(const char *track,
148 const char *submitter,
149 const char *scratcher,
150 int seconds);
151
152void notify_scratch(const char *track,
153 const char *submitter,
154 const char *scratcher,
155 int seconds) {
156 static notify_scratch_fn *f;
157
158 if(!f)
159 f = (notify_scratch_fn *)get_plugin_function(open_plugin("notify",
160 PLUGIN_FATAL),
161 "disorder_notify_scratch");
162 (*f)(track, submitter, scratcher, seconds);
163}
164
165typedef void notify_not_scratched_fn(const char *track,
166 const char *submitter);
167
168void notify_not_scratched(const char *track,
169 const char *submitter) {
170 static notify_not_scratched_fn *f;
171
172 if(!f)
173 f = (notify_not_scratched_fn *)get_plugin_function
174 (open_plugin("notify",
175 PLUGIN_FATAL),
176 "disorder_notify_not_scratched");
177 (*f)(track, submitter);
178}
179
180typedef void notify_queue_fn(const char *track,
181 const char *submitter);
182
183void notify_queue(const char *track,
184 const char *submitter) {
185 static notify_queue_fn *f;
186
187 if(!f)
188 f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
189 PLUGIN_FATAL),
190 "disorder_notify_queue");
191 (*f)(track, submitter);
192}
193
194void notify_queue_remove(const char *track,
195 const char *remover) {
196 static notify_queue_fn *f;
197
198 if(!f)
199 f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
200 PLUGIN_FATAL),
201 "disorder_notify_queue_remove");
202 (*f)(track, remover);
203}
204
205void notify_queue_move(const char *track,
206 const char *mover) {
207 static notify_queue_fn *f;
208
209 if(!f)
210 f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
211 PLUGIN_FATAL),
212 "disorder_notify_queue_move");
213 (*f)(track, mover);
214}
215
216void notify_pause(const char *track, const char *who) {
217 static notify_queue_fn *f;
218
219 if(!f)
220 f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
221 PLUGIN_FATAL),
222 "disorder_notify_pause");
223 (*f)(track, who);
224}
225
226void notify_resume(const char *track, const char *who) {
227 static notify_queue_fn *f;
228
229 if(!f)
230 f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
231 PLUGIN_FATAL),
232 "disorder_notify_resume");
233 (*f)(track, who);
234}
235
236/* player plugin interfaces ***************************************************/
237
238/* get type */
239
240unsigned long play_get_type(const struct plugin *pl) {
241 return *(const unsigned long *)get_plugin_object(pl, "disorder_player_type");
242}
243
244/* prefork */
245
246typedef void *prefork_fn(const char *track);
247
248void *play_prefork(const struct plugin *pl,
249 const char *track) {
250 return ((prefork_fn *)get_plugin_function(pl,
251 "disorder_play_prefork"))(track);
252}
253
254/* play */
255
256typedef void play_track_fn(const char *const *parameters,
257 int nparameters,
258 const char *path,
259 const char *track);
260
261void play_track(const struct plugin *pl,
262 const char *const *parameters,
263 int nparameters,
264 const char *path,
265 const char *track) {
266 ((play_track_fn *)get_plugin_function(pl,
267 "disorder_play_track"))(parameters,
268 nparameters,
269 path,
270 track);
271}
272
273/* cleanup */
274
275typedef void cleanup_fn(void *data);
276
277void play_cleanup(const struct plugin *pl, void *data) {
278 ((cleanup_fn *)get_plugin_function(pl, "disorder_play_cleanup"))(data);
279}
280
281/* pause */
282
283typedef int pause_fn(long *playedp, void *data);
284
285int play_pause(const struct plugin *pl, long *playedp, void *data) {
286 return (((pause_fn *)get_plugin_function(pl, "disorder_pause_track"))
287 (playedp, data));
288}
289
290/* resume */
291
292typedef void resume_fn(void *data);
293
294void play_resume(const struct plugin *pl, void *data) {
295 (((resume_fn *)get_plugin_function(pl, "disorder_resume_track"))
296 (data));
297}
298
299/*
300Local Variables:
301c-basic-offset:2
302comment-column:40
303End:
304*/