2 * This file is part of DisOrder.
3 * Copyright (C) 2004-2009, 2011 Richard Kettlewell
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 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 /** @file server/plugin.c
19 * @brief Server plugin interface
21 #include "disorder-server.h"
25 /* generic plugin support *****************************************************/
28 # define SOSUFFIX ".so"
31 /** @brief A loaded plugin */
33 /** @brief Next plugin */
36 /** @brief Handle returned from dlopen() */
39 /** @brief Plugin name */
43 static struct plugin
*plugins
;
45 const struct plugin
*open_plugin(const char *name
,
52 for(pl
= plugins
; pl
&& strcmp(pl
->name
, name
); pl
= pl
->next
)
55 /* Search the plugin path */
56 for(n
= 0; n
<= config
->plugins
.n
; ++n
) {
57 byte_xasprintf(&p
, "%s/%s" SOSUFFIX
,
58 n
== config
->plugins
.n ? pkglibdir
: config
->plugins
.s
[n
],
60 if(access(p
, R_OK
) == 0) {
61 h
= dlopen(p
, RTLD_NOW
);
63 disorder_error(0, "error opening %s: %s", p
, dlerror());
66 pl
= xmalloc(sizeof *pl
);
68 pl
->name
= xstrdup(name
);
74 (flags
& PLUGIN_FATAL ? disorder_fatal
: disorder_error
)
75 (0, "cannot find plugin '%s'", name
);
79 function_t
*get_plugin_function(const struct plugin
*pl
,
83 f
= (function_t
*)dlsym(pl
->dlhandle
, symbol
);
85 disorder_fatal(0, "error looking up function '%s' in '%s': %s",
86 symbol
, pl
->name
, dlerror());
90 const void *get_plugin_object(const struct plugin
*pl
,
94 o
= dlsym(pl
->dlhandle
, symbol
);
96 disorder_fatal(0, "error looking up object '%s' in '%s': %s",
97 symbol
, pl
->name
, dlerror());
101 /* specific plugin interfaces *************************************************/
103 typedef long tracklength_fn(const char *track
, const char *path
);
105 /** Compute the length of a track
106 * @param plugin plugin to use, as configured
107 * @param track UTF-8 name of track
108 * @param path file system path or 0
109 * @return length of track in seconds, 0 for unknown, -1 for error
111 long tracklength(const char *plugin
, const char *track
, const char *path
) {
112 tracklength_fn
*f
= 0;
114 f
= (tracklength_fn
*)get_plugin_function(open_plugin(plugin
,
116 "disorder_tracklength");
117 return (*f
)(track
, path
);
120 typedef void scan_fn(const char *root
);
122 void scan(const char *module
, const char *root
) {
123 ((scan_fn
*)get_plugin_function(open_plugin(module
, PLUGIN_FATAL
),
124 "disorder_scan"))(root
);
127 typedef int check_fn(const char *root
, const char *path
);
130 int check(const char *module
, const char *root
, const char *path
) {
131 return ((check_fn
*)get_plugin_function(open_plugin(module
, PLUGIN_FATAL
),
132 "disorder_check"))(root
, path
);
135 typedef void notify_play_fn(const char *track
, const char *submitter
);
137 void notify_play(const char *track
,
138 const char *submitter
) {
139 static notify_play_fn
*f
;
142 f
= (notify_play_fn
*)get_plugin_function(open_plugin("notify",
144 "disorder_notify_play");
145 (*f
)(track
, submitter
);
148 typedef void notify_scratch_fn(const char *track
,
149 const char *submitter
,
150 const char *scratcher
,
153 void notify_scratch(const char *track
,
154 const char *submitter
,
155 const char *scratcher
,
157 static notify_scratch_fn
*f
;
160 f
= (notify_scratch_fn
*)get_plugin_function(open_plugin("notify",
162 "disorder_notify_scratch");
163 (*f
)(track
, submitter
, scratcher
, seconds
);
166 typedef void notify_not_scratched_fn(const char *track
,
167 const char *submitter
);
169 void notify_not_scratched(const char *track
,
170 const char *submitter
) {
171 static notify_not_scratched_fn
*f
;
174 f
= (notify_not_scratched_fn
*)get_plugin_function
175 (open_plugin("notify",
177 "disorder_notify_not_scratched");
178 (*f
)(track
, submitter
);
181 typedef void notify_queue_fn(const char *track
,
182 const char *submitter
);
184 void notify_queue(const char *track
,
185 const char *submitter
) {
186 static notify_queue_fn
*f
;
189 f
= (notify_queue_fn
*)get_plugin_function(open_plugin("notify",
191 "disorder_notify_queue");
192 (*f
)(track
, submitter
);
195 void notify_queue_remove(const char *track
,
196 const char *remover
) {
197 static notify_queue_fn
*f
;
200 f
= (notify_queue_fn
*)get_plugin_function(open_plugin("notify",
202 "disorder_notify_queue_remove");
203 (*f
)(track
, remover
);
206 void notify_queue_move(const char *track
,
208 static notify_queue_fn
*f
;
211 f
= (notify_queue_fn
*)get_plugin_function(open_plugin("notify",
213 "disorder_notify_queue_move");
217 void notify_pause(const char *track
, const char *who
) {
218 static notify_queue_fn
*f
;
221 f
= (notify_queue_fn
*)get_plugin_function(open_plugin("notify",
223 "disorder_notify_pause");
227 void notify_resume(const char *track
, const char *who
) {
228 static notify_queue_fn
*f
;
231 f
= (notify_queue_fn
*)get_plugin_function(open_plugin("notify",
233 "disorder_notify_resume");
237 /* player plugin interfaces ***************************************************/
241 unsigned long play_get_type(const struct plugin
*pl
) {
242 return *(const unsigned long *)get_plugin_object(pl
, "disorder_player_type");
247 typedef void *prefork_fn(const char *track
);
249 void *play_prefork(const struct plugin
*pl
,
251 return ((prefork_fn
*)get_plugin_function(pl
,
252 "disorder_play_prefork"))(track
);
257 typedef void play_track_fn(const char *const *parameters
,
262 void play_track(const struct plugin
*pl
,
263 const char *const *parameters
,
267 ((play_track_fn
*)get_plugin_function(pl
,
268 "disorder_play_track"))(parameters
,
276 typedef void cleanup_fn(void *data
);
278 void play_cleanup(const struct plugin
*pl
, void *data
) {
279 ((cleanup_fn
*)get_plugin_function(pl
, "disorder_play_cleanup"))(data
);
284 typedef int pause_fn(long *playedp
, void *data
);
286 int play_pause(const struct plugin
*pl
, long *playedp
, void *data
) {
287 return (((pause_fn
*)get_plugin_function(pl
, "disorder_pause_track"))
293 typedef void resume_fn(void *data
);
295 void play_resume(const struct plugin
*pl
, void *data
) {
296 (((resume_fn
*)get_plugin_function(pl
, "disorder_resume_track"))