]> code.delx.au - pulseaudio/blob - src/pulsecore/module.c
Merge branch 'master' of ssh://rootserver/home/lennart/git/public/pulseaudio
[pulseaudio] / src / pulsecore / module.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <limits.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <ctype.h>
33
34 #include <pulse/timeval.h>
35 #include <pulse/xmalloc.h>
36 #include <pulse/proplist.h>
37
38 #include <pulsecore/core-subscribe.h>
39 #include <pulsecore/log.h>
40 #include <pulsecore/core-util.h>
41 #include <pulsecore/macro.h>
42 #include <pulsecore/ltdl-helper.h>
43 #include <pulsecore/modinfo.h>
44
45 #include "module.h"
46
47 #define PA_SYMBOL_INIT "pa__init"
48 #define PA_SYMBOL_DONE "pa__done"
49 #define PA_SYMBOL_LOAD_ONCE "pa__load_once"
50 #define PA_SYMBOL_GET_N_USED "pa__get_n_used"
51
52 pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) {
53 pa_module *m = NULL;
54 pa_bool_t (*load_once)(void);
55 pa_modinfo *mi;
56
57 pa_assert(c);
58 pa_assert(name);
59
60 if (c->disallow_module_loading)
61 goto fail;
62
63 m = pa_xnew(pa_module, 1);
64 m->name = pa_xstrdup(name);
65 m->argument = pa_xstrdup(argument);
66 m->load_once = FALSE;
67 m->proplist = pa_proplist_new();
68
69 if (!(m->dl = lt_dlopenext(name))) {
70 pa_log("Failed to open module \"%s\": %s", name, lt_dlerror());
71 goto fail;
72 }
73
74 if ((load_once = (pa_bool_t (*)(void)) pa_load_sym(m->dl, name, PA_SYMBOL_LOAD_ONCE))) {
75
76 m->load_once = load_once();
77
78 if (m->load_once) {
79 pa_module *i;
80 uint32_t idx;
81 /* OK, the module only wants to be loaded once, let's make sure it is */
82
83 for (i = pa_idxset_first(c->modules, &idx); i; i = pa_idxset_next(c->modules, &idx)) {
84 if (strcmp(name, i->name) == 0) {
85 pa_log("Module \"%s\" should be loaded once at most. Refusing to load.", name);
86 goto fail;
87 }
88 }
89 }
90 }
91
92 if (!(m->init = (int (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_INIT))) {
93 pa_log("Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.", name);
94 goto fail;
95 }
96
97 m->done = (void (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_DONE);
98 m->get_n_used = (int (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_GET_N_USED);
99 m->userdata = NULL;
100 m->core = c;
101 m->unload_requested = FALSE;
102
103 if (m->init(m) < 0) {
104 pa_log_error("Failed to load module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : "");
105 goto fail;
106 }
107
108 pa_assert_se(pa_idxset_put(c->modules, m, &m->index) >= 0);
109 pa_assert(m->index != PA_IDXSET_INVALID);
110
111 pa_log_info("Loaded \"%s\" (index: #%u; argument: \"%s\").", m->name, m->index, m->argument ? m->argument : "");
112
113 pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_NEW, m->index);
114
115 if ((mi = pa_modinfo_get_by_handle(m->dl, name))) {
116
117 if (mi->author && !pa_proplist_contains(m->proplist, PA_PROP_MODULE_AUTHOR))
118 pa_proplist_sets(m->proplist, PA_PROP_MODULE_AUTHOR, mi->author);
119
120 if (mi->description && !pa_proplist_contains(m->proplist, PA_PROP_MODULE_DESCRIPTION))
121 pa_proplist_sets(m->proplist, PA_PROP_MODULE_DESCRIPTION, mi->description);
122
123 if (mi->version && !pa_proplist_contains(m->proplist, PA_PROP_MODULE_VERSION))
124 pa_proplist_sets(m->proplist, PA_PROP_MODULE_VERSION, mi->version);
125
126 pa_modinfo_free(mi);
127 }
128
129 return m;
130
131 fail:
132
133 if (m) {
134 if (m->proplist)
135 pa_proplist_free(m->proplist);
136
137 pa_xfree(m->argument);
138 pa_xfree(m->name);
139
140 if (m->dl)
141 lt_dlclose(m->dl);
142
143 pa_xfree(m);
144 }
145
146 return NULL;
147 }
148
149 static void pa_module_free(pa_module *m) {
150 pa_assert(m);
151 pa_assert(m->core);
152
153 pa_log_info("Unloading \"%s\" (index: #%u).", m->name, m->index);
154
155 if (m->done)
156 m->done(m);
157
158 if (m->proplist)
159 pa_proplist_free(m->proplist);
160
161 lt_dlclose(m->dl);
162
163 pa_log_info("Unloaded \"%s\" (index: #%u).", m->name, m->index);
164
165 pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_REMOVE, m->index);
166
167 pa_xfree(m->name);
168 pa_xfree(m->argument);
169 pa_xfree(m);
170 }
171
172 void pa_module_unload(pa_core *c, pa_module *m, pa_bool_t force) {
173 pa_assert(c);
174 pa_assert(m);
175
176 if (m->core->disallow_module_loading && !force)
177 return;
178
179 if (!(m = pa_idxset_remove_by_data(c->modules, m, NULL)))
180 return;
181
182 pa_module_free(m);
183 }
184
185 void pa_module_unload_by_index(pa_core *c, uint32_t idx, pa_bool_t force) {
186 pa_module *m;
187 pa_assert(c);
188 pa_assert(idx != PA_IDXSET_INVALID);
189
190 if (c->disallow_module_loading && !force)
191 return;
192
193 if (!(m = pa_idxset_remove_by_index(c->modules, idx)))
194 return;
195
196 pa_module_free(m);
197 }
198
199 void pa_module_unload_all(pa_core *c) {
200 pa_module *m;
201 pa_assert(c);
202
203 while ((m = pa_idxset_steal_first(c->modules, NULL)))
204 pa_module_free(m);
205
206 if (c->module_defer_unload_event) {
207 c->mainloop->defer_free(c->module_defer_unload_event);
208 c->module_defer_unload_event = NULL;
209 }
210 }
211
212 static void defer_cb(pa_mainloop_api*api, pa_defer_event *e, void *userdata) {
213 void *state = NULL;
214 pa_core *c = PA_CORE(userdata);
215 pa_module *m;
216
217 pa_core_assert_ref(c);
218 api->defer_enable(e, 0);
219
220 while ((m = pa_idxset_iterate(c->modules, &state, NULL)))
221 if (m->unload_requested)
222 pa_module_unload(c, m, TRUE);
223 }
224
225 void pa_module_unload_request(pa_module *m, pa_bool_t force) {
226 pa_assert(m);
227
228 if (m->core->disallow_module_loading && !force)
229 return;
230
231 m->unload_requested = TRUE;
232
233 if (!m->core->module_defer_unload_event)
234 m->core->module_defer_unload_event = m->core->mainloop->defer_new(m->core->mainloop, defer_cb, m->core);
235
236 m->core->mainloop->defer_enable(m->core->module_defer_unload_event, 1);
237 }
238
239 void pa_module_unload_request_by_index(pa_core *c, uint32_t idx, pa_bool_t force) {
240 pa_module *m;
241 pa_assert(c);
242
243 if (!(m = pa_idxset_get_by_index(c->modules, idx)))
244 return;
245
246 pa_module_unload_request(m, force);
247 }
248
249 int pa_module_get_n_used(pa_module*m) {
250 pa_assert(m);
251
252 if (!m->get_n_used)
253 return -1;
254
255 return m->get_n_used(m);
256 }