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