]> code.delx.au - pulseaudio/blob - src/modules/module-solaris.c
Use LGPL 2.1 on all files previously using LGPL 2
[pulseaudio] / src / modules / module-solaris.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2006 Lennart Poettering
5 Copyright 2006-2007 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 <stdlib.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <limits.h>
34 #include <sys/ioctl.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37
38 #include <signal.h>
39 #include <stropts.h>
40 #include <sys/conf.h>
41 #include <sys/audio.h>
42
43 #include <pulse/error.h>
44 #include <pulse/mainloop-signal.h>
45 #include <pulse/xmalloc.h>
46 #include <pulse/timeval.h>
47
48 #include <pulsecore/iochannel.h>
49 #include <pulsecore/sink.h>
50 #include <pulsecore/source.h>
51 #include <pulsecore/module.h>
52 #include <pulsecore/sample-util.h>
53 #include <pulsecore/core-util.h>
54 #include <pulsecore/modargs.h>
55 #include <pulsecore/log.h>
56 #include <pulsecore/core-error.h>
57 #include <pulsecore/thread-mq.h>
58 #include <pulsecore/rtpoll.h>
59 #include <pulsecore/thread.h>
60
61 #include "module-solaris-symdef.h"
62
63 PA_MODULE_AUTHOR("Pierre Ossman")
64 PA_MODULE_DESCRIPTION("Solaris Sink/Source")
65 PA_MODULE_VERSION(PACKAGE_VERSION)
66 PA_MODULE_USAGE(
67 "sink_name=<name for the sink> "
68 "source_name=<name for the source> "
69 "device=<OSS device> record=<enable source?> "
70 "playback=<enable sink?> "
71 "format=<sample format> "
72 "channels=<number of channels> "
73 "rate=<sample rate> "
74 "buffer_size=<record buffer size> "
75 "channel_map=<channel map>")
76
77 struct userdata {
78 pa_core *core;
79 pa_sink *sink;
80 pa_source *source;
81
82 pa_thread *thread;
83 pa_thread_mq thread_mq;
84 pa_rtpoll *rtpoll;
85
86 pa_signal_event *sig;
87
88 pa_memchunk memchunk;
89
90 unsigned int page_size;
91
92 uint32_t frame_size;
93 uint32_t buffer_size;
94 unsigned int written_bytes, read_bytes;
95
96 int fd;
97 pa_rtpoll_item *rtpoll_item;
98 pa_module *module;
99 };
100
101 static const char* const valid_modargs[] = {
102 "sink_name",
103 "source_name",
104 "device",
105 "record",
106 "playback",
107 "buffer_size",
108 "format",
109 "rate",
110 "channels",
111 "channel_map",
112 NULL
113 };
114
115 #define DEFAULT_SINK_NAME "solaris_output"
116 #define DEFAULT_SOURCE_NAME "solaris_input"
117 #define DEFAULT_DEVICE "/dev/audio"
118
119 static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
120 struct userdata *u = PA_SINK(o)->userdata;
121 int err;
122 audio_info_t info;
123
124 switch (code) {
125 case PA_SINK_MESSAGE_GET_LATENCY: {
126 pa_usec_t r = 0;
127
128 if (u->fd >= 0) {
129
130 err = ioctl(u->fd, AUDIO_GETINFO, &info);
131 pa_assert(err >= 0);
132
133 r += pa_bytes_to_usec(u->written_bytes, &PA_SINK(o)->sample_spec);
134 r -= pa_bytes_to_usec(info.play.samples * u->frame_size, &PA_SINK(o)->sample_spec);
135
136 if (u->memchunk.memblock)
137 r += pa_bytes_to_usec(u->memchunk.length, &PA_SINK(o)->sample_spec);
138 }
139
140 *((pa_usec_t*) data) = r;
141
142 return 0;
143 }
144
145 case PA_SINK_MESSAGE_SET_VOLUME:
146 if (u->fd >= 0) {
147 AUDIO_INITINFO(&info);
148
149 info.play.gain = pa_cvolume_avg((pa_cvolume*)data) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
150 assert(info.play.gain <= AUDIO_MAX_GAIN);
151
152 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
153 if (errno == EINVAL)
154 pa_log("AUDIO_SETINFO: Unsupported volume.");
155 else
156 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
157 } else {
158 return 0;
159 }
160 }
161 break;
162
163 case PA_SINK_MESSAGE_GET_VOLUME:
164 if (u->fd >= 0) {
165 err = ioctl(u->fd, AUDIO_GETINFO, &info);
166 assert(err >= 0);
167
168 pa_cvolume_set((pa_cvolume*) data, ((pa_cvolume*) data)->channels,
169 info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN);
170
171 return 0;
172 }
173 break;
174
175 case PA_SINK_MESSAGE_SET_MUTE:
176 if (u->fd >= 0) {
177 AUDIO_INITINFO(&info);
178
179 info.output_muted = !!PA_PTR_TO_UINT(data);
180
181 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
182 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
183 else
184 return 0;
185 }
186 break;
187
188 case PA_SINK_MESSAGE_GET_MUTE:
189 if (u->fd >= 0) {
190 err = ioctl(u->fd, AUDIO_GETINFO, &info);
191 pa_assert(err >= 0);
192
193 *(int*)data = !!info.output_muted;
194
195 return 0;
196 }
197 break;
198 }
199
200 return pa_sink_process_msg(o, code, data, offset, chunk);
201 }
202
203 static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
204 struct userdata *u = PA_SOURCE(o)->userdata;
205 int err;
206 audio_info_t info;
207
208 switch (code) {
209 case PA_SOURCE_MESSAGE_GET_LATENCY: {
210 pa_usec_t r = 0;
211
212 if (u->fd) {
213 err = ioctl(u->fd, AUDIO_GETINFO, &info);
214 pa_assert(err >= 0);
215
216 r += pa_bytes_to_usec(info.record.samples * u->frame_size, &PA_SOURCE(o)->sample_spec);
217 r -= pa_bytes_to_usec(u->read_bytes, &PA_SOURCE(o)->sample_spec);
218 }
219
220 *((pa_usec_t*) data) = r;
221
222 return 0;
223 }
224
225 case PA_SOURCE_MESSAGE_SET_VOLUME:
226 if (u->fd >= 0) {
227 AUDIO_INITINFO(&info);
228
229 info.record.gain = pa_cvolume_avg((pa_cvolume*) data) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
230 assert(info.record.gain <= AUDIO_MAX_GAIN);
231
232 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
233 if (errno == EINVAL)
234 pa_log("AUDIO_SETINFO: Unsupported volume.");
235 else
236 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
237 } else {
238 return 0;
239 }
240 }
241 break;
242
243 case PA_SOURCE_MESSAGE_GET_VOLUME:
244 if (u->fd >= 0) {
245 err = ioctl(u->fd, AUDIO_GETINFO, &info);
246 pa_assert(err >= 0);
247
248 pa_cvolume_set((pa_cvolume*) data, ((pa_cvolume*) data)->channels,
249 info.record.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN);
250
251 return 0;
252 }
253 break;
254 }
255
256 return pa_source_process_msg(o, code, data, offset, chunk);
257 }
258
259 static void clear_underflow(struct userdata *u)
260 {
261 audio_info_t info;
262
263 AUDIO_INITINFO(&info);
264
265 info.play.error = 0;
266
267 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
268 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
269 }
270
271 static void clear_overflow(struct userdata *u)
272 {
273 audio_info_t info;
274
275 AUDIO_INITINFO(&info);
276
277 info.record.error = 0;
278
279 if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
280 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
281 }
282
283 static void thread_func(void *userdata) {
284 struct userdata *u = userdata;
285 unsigned short revents = 0;
286 int ret;
287
288 pa_assert(u);
289
290 pa_log_debug("Thread starting up");
291
292 if (u->core->high_priority)
293 pa_make_realtime();
294
295 pa_thread_mq_install(&u->thread_mq);
296 pa_rtpoll_install(u->rtpoll);
297
298 for (;;) {
299 /* Render some data and write it to the dsp */
300
301 if (u->sink && PA_SINK_OPENED(u->sink->thread_info.state)) {
302 audio_info_t info;
303 int err;
304 size_t len;
305
306 err = ioctl(u->fd, AUDIO_GETINFO, &info);
307 pa_assert(err >= 0);
308
309 /*
310 * Since we cannot modify the size of the output buffer we fake it
311 * by not filling it more than u->buffer_size.
312 */
313 len = u->buffer_size;
314 len -= u->written_bytes - (info.play.samples * u->frame_size);
315
316 /* The sample counter can sometimes go backwards :( */
317 if (len > u->buffer_size)
318 len = 0;
319
320 if (info.play.error) {
321 pa_log_debug("Solaris buffer underflow!");
322 clear_underflow(u);
323 }
324
325 len -= len % u->frame_size;
326
327 while (len) {
328 void *p;
329 ssize_t r;
330
331 if (!u->memchunk.length)
332 pa_sink_render(u->sink, len, &u->memchunk);
333
334 pa_assert(u->memchunk.length);
335
336 p = pa_memblock_acquire(u->memchunk.memblock);
337 r = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, NULL);
338 pa_memblock_release(u->memchunk.memblock);
339
340 if (r < 0) {
341 if (errno == EINTR)
342 continue;
343 else if (errno != EAGAIN) {
344 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno));
345 goto fail;
346 }
347 } else {
348 pa_assert(r % u->frame_size == 0);
349
350 u->memchunk.index += r;
351 u->memchunk.length -= r;
352
353 if (u->memchunk.length <= 0) {
354 pa_memblock_unref(u->memchunk.memblock);
355 pa_memchunk_reset(&u->memchunk);
356 }
357
358 len -= r;
359 u->written_bytes += r;
360 }
361 }
362 }
363
364 /* Try to read some data and pass it on to the source driver */
365
366 if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state) && ((revents & POLLIN))) {
367 pa_memchunk memchunk;
368 int err;
369 size_t l;
370 void *p;
371 ssize_t r;
372 audio_info_t info;
373
374 err = ioctl(u->fd, AUDIO_GETINFO, &info);
375 pa_assert(err >= 0);
376
377 if (info.record.error) {
378 pa_log_debug("Solaris buffer overflow!");
379 clear_overflow(u);
380 }
381
382 err = ioctl(u->fd, I_NREAD, &l);
383 pa_assert(err >= 0);
384
385 if (l > 0) {
386 /* This is to make sure it fits in the memory pool. Also, a page
387 should be the most efficient transfer size. */
388 if (l > u->page_size)
389 l = u->page_size;
390
391 memchunk.memblock = pa_memblock_new(u->core->mempool, l);
392 pa_assert(memchunk.memblock);
393
394 p = pa_memblock_acquire(memchunk.memblock);
395 r = pa_read(u->fd, p, l, NULL);
396 pa_memblock_release(memchunk.memblock);
397
398 if (r < 0) {
399 pa_memblock_unref(memchunk.memblock);
400 if (errno != EAGAIN) {
401 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno));
402 goto fail;
403 }
404 } else {
405 memchunk.index = 0;
406 memchunk.length = r;
407
408 pa_source_post(u->source, &memchunk);
409 pa_memblock_unref(memchunk.memblock);
410
411 u->read_bytes += r;
412
413 revents &= ~POLLIN;
414 }
415 }
416 }
417
418 if (u->fd >= 0) {
419 struct pollfd *pollfd;
420
421 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
422 pollfd->events =
423 ((u->source && PA_SOURCE_OPENED(u->source->thread_info.state)) ? POLLIN : 0);
424 }
425
426 /* Hmm, nothing to do. Let's sleep */
427 if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0)
428 goto fail;
429
430 if (ret == 0)
431 goto finish;
432
433 if (u->fd >= 0) {
434 struct pollfd *pollfd;
435
436 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
437
438 if (pollfd->revents & ~(POLLOUT|POLLIN)) {
439 pa_log("DSP shutdown.");
440 goto fail;
441 }
442
443 revents = pollfd->revents;
444 } else
445 revents = 0;
446 }
447
448 fail:
449 /* We have to continue processing messages until we receive the
450 * SHUTDOWN message */
451 pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
452 pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
453
454 finish:
455 pa_log_debug("Thread shutting down");
456 }
457
458 static void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) {
459 struct userdata *u = userdata;
460
461 assert(u);
462
463 if (u->sink) {
464 pa_sink_get_volume(u->sink);
465 pa_sink_get_mute(u->sink);
466 }
467
468 if (u->source)
469 pa_source_get_volume(u->source);
470 }
471
472 static int pa_solaris_auto_format(int fd, int mode, pa_sample_spec *ss) {
473 audio_info_t info;
474
475 AUDIO_INITINFO(&info);
476
477 if (mode != O_RDONLY) {
478 info.play.sample_rate = ss->rate;
479 info.play.channels = ss->channels;
480 switch (ss->format) {
481 case PA_SAMPLE_U8:
482 info.play.precision = 8;
483 info.play.encoding = AUDIO_ENCODING_LINEAR;
484 break;
485 case PA_SAMPLE_ALAW:
486 info.play.precision = 8;
487 info.play.encoding = AUDIO_ENCODING_ALAW;
488 break;
489 case PA_SAMPLE_ULAW:
490 info.play.precision = 8;
491 info.play.encoding = AUDIO_ENCODING_ULAW;
492 break;
493 case PA_SAMPLE_S16NE:
494 info.play.precision = 16;
495 info.play.encoding = AUDIO_ENCODING_LINEAR;
496 break;
497 default:
498 return -1;
499 }
500 }
501
502 if (mode != O_WRONLY) {
503 info.record.sample_rate = ss->rate;
504 info.record.channels = ss->channels;
505 switch (ss->format) {
506 case PA_SAMPLE_U8:
507 info.record.precision = 8;
508 info.record.encoding = AUDIO_ENCODING_LINEAR;
509 break;
510 case PA_SAMPLE_ALAW:
511 info.record.precision = 8;
512 info.record.encoding = AUDIO_ENCODING_ALAW;
513 break;
514 case PA_SAMPLE_ULAW:
515 info.record.precision = 8;
516 info.record.encoding = AUDIO_ENCODING_ULAW;
517 break;
518 case PA_SAMPLE_S16NE:
519 info.record.precision = 16;
520 info.record.encoding = AUDIO_ENCODING_LINEAR;
521 break;
522 default:
523 return -1;
524 }
525 }
526
527 if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
528 if (errno == EINVAL)
529 pa_log("AUDIO_SETINFO: Unsupported sample format.");
530 else
531 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
532 return -1;
533 }
534
535 return 0;
536 }
537
538 static int pa_solaris_set_buffer(int fd, int buffer_size) {
539 audio_info_t info;
540
541 AUDIO_INITINFO(&info);
542
543 info.play.buffer_size = buffer_size;
544 info.record.buffer_size = buffer_size;
545
546 if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
547 if (errno == EINVAL)
548 pa_log("AUDIO_SETINFO: Unsupported buffer size.");
549 else
550 pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
551 return -1;
552 }
553
554 return 0;
555 }
556
557 int pa__init(pa_module *m) {
558 struct userdata *u = NULL;
559 const char *p;
560 int fd = -1;
561 int buffer_size;
562 int mode;
563 int record = 1, playback = 1;
564 pa_sample_spec ss;
565 pa_channel_map map;
566 pa_modargs *ma = NULL;
567 char *t;
568 struct pollfd *pollfd;
569
570 pa_assert(m);
571
572 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
573 pa_log("failed to parse module arguments.");
574 goto fail;
575 }
576
577 if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
578 pa_log("record= and playback= expect numeric argument.");
579 goto fail;
580 }
581
582 if (!playback && !record) {
583 pa_log("neither playback nor record enabled for device.");
584 goto fail;
585 }
586
587 mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
588
589 buffer_size = 16384;
590 if (pa_modargs_get_value_s32(ma, "buffer_size", &buffer_size) < 0) {
591 pa_log("failed to parse buffer size argument");
592 goto fail;
593 }
594
595 ss = m->core->default_sample_spec;
596 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
597 pa_log("failed to parse sample specification");
598 goto fail;
599 }
600
601 if ((fd = open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), mode | O_NONBLOCK)) < 0)
602 goto fail;
603
604 pa_log_info("device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));
605
606 if (pa_solaris_auto_format(fd, mode, &ss) < 0)
607 goto fail;
608
609 if (pa_solaris_set_buffer(fd, buffer_size) < 0)
610 goto fail;
611
612 u = pa_xmalloc(sizeof(struct userdata));
613 u->core = m->core;
614
615 u->fd = fd;
616
617 pa_memchunk_reset(&u->memchunk);
618
619 /* We use this to get a reasonable chunk size */
620 u->page_size = PA_PAGE_SIZE;
621
622 u->frame_size = pa_frame_size(&ss);
623 u->buffer_size = buffer_size;
624
625 u->written_bytes = 0;
626 u->read_bytes = 0;
627
628 u->module = m;
629 m->userdata = u;
630
631 pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
632
633 u->rtpoll = pa_rtpoll_new();
634 pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);
635
636 pa_rtpoll_set_timer_periodic(u->rtpoll, pa_bytes_to_usec(u->buffer_size / 10, &ss));
637
638 u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
639 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
640 pollfd->fd = fd;
641 pollfd->events = 0;
642 pollfd->revents = 0;
643
644 if (mode != O_WRONLY) {
645 u->source = pa_source_new(m->core, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map);
646 pa_assert(u->source);
647
648 u->source->userdata = u;
649 u->source->parent.process_msg = source_process_msg;
650
651 pa_source_set_module(u->source, m);
652 pa_source_set_description(u->source, t = pa_sprintf_malloc("Solaris PCM on '%s'", p));
653 pa_xfree(t);
654 pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
655 pa_source_set_rtpoll(u->source, u->rtpoll);
656
657 u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL;
658 u->source->refresh_volume = 1;
659 } else
660 u->source = NULL;
661
662 if (mode != O_RDONLY) {
663 u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map);
664 pa_assert(u->sink);
665
666 u->sink->userdata = u;
667 u->sink->parent.process_msg = sink_process_msg;
668
669 pa_sink_set_module(u->sink, m);
670 pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Solaris PCM on '%s'", p));
671 pa_xfree(t);
672 pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
673 pa_sink_set_rtpoll(u->sink, u->rtpoll);
674
675 u->sink->flags = PA_SINK_HARDWARE|PA_SINK_LATENCY|PA_SINK_HW_VOLUME_CTRL;
676 u->sink->refresh_volume = 1;
677 u->sink->refresh_mute = 1;
678 } else
679 u->sink = NULL;
680
681 pa_assert(u->source || u->sink);
682
683 u->sig = pa_signal_new(SIGPOLL, sig_callback, u);
684 pa_assert(u->sig);
685 ioctl(u->fd, I_SETSIG, S_MSG);
686
687 if (!(u->thread = pa_thread_new(thread_func, u))) {
688 pa_log("Failed to create thread.");
689 goto fail;
690 }
691
692 /* Read mixer settings */
693 if (u->source)
694 pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->source), PA_SOURCE_MESSAGE_GET_VOLUME, &u->source->volume, 0, NULL);
695 if (u->sink) {
696 pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->sink), PA_SINK_MESSAGE_GET_VOLUME, &u->sink->volume, 0, NULL);
697 pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->sink), PA_SINK_MESSAGE_GET_MUTE, &u->sink->muted, 0, NULL);
698 }
699
700 if (u->sink)
701 pa_sink_put(u->sink);
702 if (u->source)
703 pa_source_put(u->source);
704
705 pa_modargs_free(ma);
706
707 return 0;
708
709 fail:
710 if (u)
711 pa__done(m);
712 else if (fd >= 0)
713 close(fd);
714
715 if (ma)
716 pa_modargs_free(ma);
717
718 return -1;
719 }
720
721 void pa__done(pa_module *m) {
722 struct userdata *u;
723
724 pa_assert(m);
725
726 if (!(u = m->userdata))
727 return;
728
729 ioctl(u->fd, I_SETSIG, 0);
730 pa_signal_free(u->sig);
731
732 if (u->sink)
733 pa_sink_unlink(u->sink);
734
735 if (u->source)
736 pa_source_unlink(u->source);
737
738 if (u->thread) {
739 pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
740 pa_thread_free(u->thread);
741 }
742
743 pa_thread_mq_done(&u->thread_mq);
744
745 if (u->sink)
746 pa_sink_unref(u->sink);
747
748 if (u->source)
749 pa_source_unref(u->source);
750
751 if (u->memchunk.memblock)
752 pa_memblock_unref(u->memchunk.memblock);
753
754 if (u->rtpoll_item)
755 pa_rtpoll_item_free(u->rtpoll_item);
756
757 if (u->rtpoll)
758 pa_rtpoll_free(u->rtpoll);
759
760 if (u->fd >= 0)
761 close(u->fd);
762
763 pa_xfree(u);
764 }