]> code.delx.au - pulseaudio/blob - src/modules/gconf/module-gconf.c
add new module "module-gconf" which reads configuration information from gconf. this...
[pulseaudio] / src / modules / gconf / module-gconf.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <assert.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <signal.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34
35 #include <pulsecore/module.h>
36 #include <pulsecore/core.h>
37 #include <pulsecore/llist.h>
38 #include <pulsecore/core-util.h>
39 #include <pulsecore/log.h>
40 #include <pulse/mainloop-api.h>
41 #include <pulse/xmalloc.h>
42 #include <pulsecore/core-error.h>
43
44 #include "module-gconf-symdef.h"
45
46 PA_MODULE_AUTHOR("Lennart Poettering")
47 PA_MODULE_DESCRIPTION("GConf Adapter")
48 PA_MODULE_VERSION(PACKAGE_VERSION)
49 PA_MODULE_USAGE("")
50
51 #define MAX_MODULES 10
52 #define BUF_MAX 2048
53
54 #undef PA_GCONF_HELPER
55 #define PA_GCONF_HELPER "/home/lennart/projects/pulseaudio/src/gconf-helper"
56
57 struct module_info {
58 char *name;
59
60 unsigned n_indexes;
61 uint32_t indexes[MAX_MODULES];
62 };
63
64 struct userdata {
65 pa_core *core;
66 pa_module *module;
67
68 pa_hashmap *module_infos;
69
70 pid_t pid;
71
72 int fd;
73 int fd_type;
74 pa_io_event *io_event;
75
76 char buf[BUF_MAX];
77 size_t buf_fill;
78 };
79
80 static int fill_buf(struct userdata *u) {
81 ssize_t r;
82 assert(u);
83
84 if (u->buf_fill >= BUF_MAX) {
85 pa_log(__FILE__": read buffer overflow");
86 return -1;
87 }
88
89 if ((r = pa_read(u->fd, u->buf + u->buf_fill, BUF_MAX - u->buf_fill, &u->fd_type)) <= 0)
90 return -1;
91
92 u->buf_fill += r;
93 return 0;
94 }
95
96 static int read_byte(struct userdata *u) {
97 int ret;
98 assert(u);
99
100 if (u->buf_fill < 1)
101 if (fill_buf(u) < 0)
102 return -1;
103
104 ret = u->buf[0];
105 assert(u->buf_fill > 0);
106 u->buf_fill--;
107 memmove(u->buf, u->buf+1, u->buf_fill);
108 return ret;
109 }
110
111 static char *read_string(struct userdata *u) {
112 assert(u);
113
114 for (;;) {
115 char *e;
116
117 if ((e = memchr(u->buf, 0, u->buf_fill))) {
118 char *ret = pa_xstrdup(u->buf);
119 u->buf_fill -= e - u->buf +1;
120 memmove(u->buf, e+1, u->buf_fill);
121 return ret;
122 }
123
124 if (fill_buf(u) < 0)
125 return NULL;
126 }
127 }
128
129 static void unload_modules(struct userdata *u, struct module_info*m) {
130 unsigned i;
131
132 assert(u);
133 assert(m);
134
135 for (i = 0; i < m->n_indexes; i++) {
136 pa_log_debug(__FILE__": Unloading module #%i", m->indexes[i]);
137 pa_module_unload_by_index(u->core, m->indexes[i]);
138 }
139
140 m->n_indexes = 0;
141 }
142
143 static void load_module(
144 struct userdata *u,
145 struct module_info *m,
146 const char *module,
147 const char *args) {
148
149 pa_module *mod;
150
151 assert(u);
152 assert(m);
153 assert(module);
154
155 assert(m->n_indexes < MAX_MODULES);
156
157 pa_log_debug(__FILE__": Loading module '%s' with args '%s' due to GConf configuration.", module, args);
158
159 if (!(mod = pa_module_load(u->core, module, args))) {
160 pa_log(__FILE__": pa_module_load() failed");
161 return;
162 }
163
164 m->indexes[m->n_indexes++] = mod->index;
165 }
166
167 static void module_info_free(void *p, void *userdata) {
168 struct module_info *m = p;
169 struct userdata *u = userdata;
170
171 assert(m);
172 assert(u);
173
174 unload_modules(u, m);
175 pa_xfree(m->name);
176 pa_xfree(m);
177 }
178
179 static int handle_event(struct userdata *u) {
180 int opcode;
181 int ret = 0;
182
183 do {
184 if ((opcode = read_byte(u)) < 0)
185 goto fail;
186
187 switch (opcode) {
188 case '!':
189 /* The helper tool is now initialized */
190 ret = 1;
191 break;
192
193 case '+': {
194 char *name;
195 struct module_info *m;
196
197 if (!(name = read_string(u)))
198 goto fail;
199
200 if ((m = pa_hashmap_get(u->module_infos, name))) {
201 unload_modules(u, m);
202 } else {
203 m = pa_xnew(struct module_info, 1);
204 m->name = pa_xstrdup(name);
205 m->n_indexes = 0;
206 pa_hashmap_put(u->module_infos, m->name, m);
207 }
208
209 while (m->n_indexes < MAX_MODULES) {
210 char *module, *args;
211
212 if (!(module = read_string(u))) {
213 pa_xfree(name);
214 goto fail;
215 }
216
217 if (!*module) {
218 pa_xfree(module);
219 break;
220 }
221
222 if (!(args = read_string(u))) {
223 pa_xfree(name);
224 pa_xfree(module);
225 goto fail;
226 }
227
228 load_module(u, m, module, args);
229
230 pa_xfree(module);
231 pa_xfree(args);
232 }
233
234 pa_xfree(name);
235
236 break;
237 }
238
239 case '-': {
240 char *name;
241 struct module_info *m;
242
243 if (!(name = read_string(u)))
244 goto fail;
245
246 if ((m = pa_hashmap_get(u->module_infos, name))) {
247 pa_hashmap_remove(u->module_infos, name);
248 module_info_free(m, u);
249 }
250
251 pa_xfree(name);
252
253 break;
254 }
255 }
256 } while (u->buf_fill > 0 && ret == 0);
257
258 return ret;
259
260 fail:
261 pa_log(__FILE__": Unable to read or parse data from client.");
262 return -1;
263 }
264
265 static void io_event_cb(
266 pa_mainloop_api*a,
267 pa_io_event* e,
268 int fd,
269 pa_io_event_flags_t events,
270 void *userdata) {
271
272 struct userdata *u = userdata;
273
274 handle_event(u);
275 }
276
277 static int start_client(const char *n, pid_t *pid) {
278 pid_t child;
279 int pipe_fds[2] = { -1, -1 };
280
281 if (pipe(pipe_fds) < 0) {
282 pa_log(__FILE__": pipe() failed: %s", pa_cstrerror(errno));
283 goto fail;
284 }
285
286 if ((child = fork()) == (pid_t) -1) {
287 pa_log(__FILE__": fork() failed: %s", pa_cstrerror(errno));
288 goto fail;
289 } else if (child != 0) {
290
291 /* Parent */
292 close(pipe_fds[1]);
293
294 if (pid)
295 *pid = child;
296
297 return pipe_fds[0];
298 } else {
299
300 /* child */
301
302 close(pipe_fds[0]);
303 dup2(pipe_fds[1], 1);
304
305 if (pipe_fds[1] != 1)
306 close(pipe_fds[1]);
307
308 execl(n, n, NULL);
309 _exit(1);
310 }
311
312 fail:
313 if (pipe_fds[0] >= 0)
314 close(pipe_fds[0]);
315
316 if (pipe_fds[1] >= 0)
317 close(pipe_fds[1]);
318
319 return -1;
320 }
321
322 int pa__init(pa_core *c, pa_module*m) {
323 struct userdata *u;
324 int r;
325
326 u = pa_xnew(struct userdata, 1);
327 u->core = c;
328 u->module = m;
329 u->module_infos = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
330 u->pid = (pid_t) -1;
331 u->fd = -1;
332 u->fd_type = 0;
333 u->io_event = NULL;
334 u->buf_fill = 0;
335
336 if ((u->fd = start_client(PA_GCONF_HELPER, &u->pid)) < 0)
337 goto fail;
338
339 u->io_event = c->mainloop->io_new(
340 c->mainloop,
341 u->fd,
342 PA_IO_EVENT_INPUT,
343 io_event_cb,
344 u);
345
346 do {
347 if ((r = handle_event(u)) < 0)
348 goto fail;
349
350 /* Read until the client signalled us that it is ready with
351 * initialization */
352 } while (r != 1);
353
354 return 0;
355
356 fail:
357 pa__done(c, m);
358 return -1;
359 }
360
361 void pa__done(pa_core *c, pa_module*m) {
362 struct userdata *u;
363
364 assert(c);
365 assert(m);
366
367 if (!(u = m->userdata))
368 return;
369
370 if (u->io_event)
371 c->mainloop->io_free(u->io_event);
372
373 if (u->fd >= 0)
374 close(u->fd);
375
376 if (u->pid != (pid_t) -1) {
377 kill(u->pid, SIGTERM);
378 waitpid(u->pid, NULL, 0);
379 }
380
381 if (u->module_infos)
382 pa_hashmap_free(u->module_infos, module_info_free, u);
383
384 pa_xfree(u);
385 }
386