]> code.delx.au - pulseaudio/blob - src/modules/module-oss.c
tag modules that may only be loaded once at most especially, and enforce that in...
[pulseaudio] / src / modules / module-oss.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006 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 /* General power management rules:
26 *
27 * When SUSPENDED we close the audio device.
28 *
29 * We make no difference between IDLE and RUNNING in our handling.
30 *
31 * As long as we are in RUNNING/IDLE state we will *always* write data to
32 * the device. If none is avilable from the inputs, we write silence
33 * instead.
34 *
35 * If power should be saved on IDLE module-suspend-on-idle should be used.
36 *
37 */
38
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42
43 #ifdef HAVE_SYS_MMAN_H
44 #include <sys/mman.h>
45 #endif
46
47 #include <sys/soundcard.h>
48 #include <sys/ioctl.h>
49 #include <stdlib.h>
50 #include <sys/stat.h>
51 #include <stdio.h>
52 #include <errno.h>
53 #include <string.h>
54 #include <fcntl.h>
55 #include <unistd.h>
56 #include <limits.h>
57 #include <signal.h>
58 #include <poll.h>
59
60 #include <pulse/xmalloc.h>
61 #include <pulse/util.h>
62
63 #include <pulsecore/core-error.h>
64 #include <pulsecore/thread.h>
65 #include <pulsecore/sink.h>
66 #include <pulsecore/source.h>
67 #include <pulsecore/module.h>
68 #include <pulsecore/sample-util.h>
69 #include <pulsecore/core-util.h>
70 #include <pulsecore/modargs.h>
71 #include <pulsecore/log.h>
72 #include <pulsecore/macro.h>
73 #include <pulsecore/thread-mq.h>
74 #include <pulsecore/rtpoll.h>
75
76 #include "oss-util.h"
77 #include "module-oss-symdef.h"
78
79 PA_MODULE_AUTHOR("Lennart Poettering");
80 PA_MODULE_DESCRIPTION("OSS Sink/Source");
81 PA_MODULE_VERSION(PACKAGE_VERSION);
82 PA_MODULE_LOAD_ONCE(FALSE);
83 PA_MODULE_USAGE(
84 "sink_name=<name for the sink> "
85 "source_name=<name for the source> "
86 "device=<OSS device> "
87 "record=<enable source?> "
88 "playback=<enable sink?> "
89 "format=<sample format> "
90 "channels=<number of channels> "
91 "rate=<sample rate> "
92 "fragments=<number of fragments> "
93 "fragment_size=<fragment size> "
94 "channel_map=<channel map> "
95 "mmap=<enable memory mapping?>");
96
97 #define DEFAULT_DEVICE "/dev/dsp"
98
99 struct userdata {
100 pa_core *core;
101 pa_module *module;
102 pa_sink *sink;
103 pa_source *source;
104
105 pa_thread *thread;
106 pa_thread_mq thread_mq;
107 pa_rtpoll *rtpoll;
108
109 char *device_name;
110
111 pa_memchunk memchunk;
112
113 size_t frame_size;
114 uint32_t in_fragment_size, out_fragment_size, in_nfrags, out_nfrags, in_hwbuf_size, out_hwbuf_size;
115 pa_bool_t use_getospace, use_getispace;
116 pa_bool_t use_getodelay;
117
118 pa_bool_t sink_suspended, source_suspended;
119
120 int fd;
121 int mode;
122
123 int mixer_fd;
124 int mixer_devmask;
125
126 int nfrags, frag_size;
127
128 pa_bool_t use_mmap;
129 unsigned out_mmap_current, in_mmap_current;
130 void *in_mmap, *out_mmap;
131 pa_memblock **in_mmap_memblocks, **out_mmap_memblocks;
132
133 int in_mmap_saved_nfrags, out_mmap_saved_nfrags;
134
135 pa_rtpoll_item *rtpoll_item;
136 };
137
138 static const char* const valid_modargs[] = {
139 "sink_name",
140 "source_name",
141 "device",
142 "record",
143 "playback",
144 "fragments",
145 "fragment_size",
146 "format",
147 "rate",
148 "channels",
149 "channel_map",
150 "mmap",
151 NULL
152 };
153
154 static void trigger(struct userdata *u, pa_bool_t quick) {
155 int enable_bits = 0, zero = 0;
156
157 pa_assert(u);
158
159 if (u->fd < 0)
160 return;
161
162 pa_log_debug("trigger");
163
164 if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state))
165 enable_bits |= PCM_ENABLE_INPUT;
166
167 if (u->sink && PA_SINK_OPENED(u->sink->thread_info.state))
168 enable_bits |= PCM_ENABLE_OUTPUT;
169
170 pa_log_debug("trigger: %i", enable_bits);
171
172
173 if (u->use_mmap) {
174
175 if (!quick)
176 ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero);
177
178 #ifdef SNDCTL_DSP_HALT
179 if (enable_bits == 0)
180 if (ioctl(u->fd, SNDCTL_DSP_HALT, NULL) < 0)
181 pa_log_warn("SNDCTL_DSP_HALT: %s", pa_cstrerror(errno));
182 #endif
183
184 if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0)
185 pa_log_warn("SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno));
186
187 if (u->sink && !(enable_bits & PCM_ENABLE_OUTPUT)) {
188 pa_log_debug("clearing playback buffer");
189 pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &u->sink->sample_spec);
190 }
191
192 } else {
193
194 if (enable_bits)
195 if (ioctl(u->fd, SNDCTL_DSP_POST, NULL) < 0)
196 pa_log_warn("SNDCTL_DSP_POST: %s", pa_cstrerror(errno));
197
198 if (!quick) {
199 /*
200 * Some crappy drivers do not start the recording until we
201 * read something. Without this snippet, poll will never
202 * register the fd as ready.
203 */
204
205 if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state)) {
206 uint8_t *buf = pa_xnew(uint8_t, u->in_fragment_size);
207 pa_read(u->fd, buf, u->in_fragment_size, NULL);
208 pa_xfree(buf);
209 }
210 }
211 }
212 }
213
214 static void mmap_fill_memblocks(struct userdata *u, unsigned n) {
215 pa_assert(u);
216 pa_assert(u->out_mmap_memblocks);
217
218 /* pa_log("Mmmap writing %u blocks", n); */
219
220 while (n > 0) {
221 pa_memchunk chunk;
222
223 if (u->out_mmap_memblocks[u->out_mmap_current])
224 pa_memblock_unref_fixed(u->out_mmap_memblocks[u->out_mmap_current]);
225
226 chunk.memblock = u->out_mmap_memblocks[u->out_mmap_current] =
227 pa_memblock_new_fixed(
228 u->core->mempool,
229 (uint8_t*) u->out_mmap + u->out_fragment_size * u->out_mmap_current,
230 u->out_fragment_size,
231 1);
232
233 chunk.length = pa_memblock_get_length(chunk.memblock);
234 chunk.index = 0;
235
236 pa_sink_render_into_full(u->sink, &chunk);
237
238 u->out_mmap_current++;
239 while (u->out_mmap_current >= u->out_nfrags)
240 u->out_mmap_current -= u->out_nfrags;
241
242 n--;
243 }
244 }
245
246 static int mmap_write(struct userdata *u) {
247 struct count_info info;
248
249 pa_assert(u);
250 pa_assert(u->sink);
251
252 /* pa_log("Mmmap writing..."); */
253
254 if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
255 pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno));
256 return -1;
257 }
258
259 info.blocks += u->out_mmap_saved_nfrags;
260 u->out_mmap_saved_nfrags = 0;
261
262 if (info.blocks > 0)
263 mmap_fill_memblocks(u, info.blocks);
264
265 return info.blocks;
266 }
267
268 static void mmap_post_memblocks(struct userdata *u, unsigned n) {
269 pa_assert(u);
270 pa_assert(u->in_mmap_memblocks);
271
272 /* pa_log("Mmmap reading %u blocks", n); */
273
274 while (n > 0) {
275 pa_memchunk chunk;
276
277 if (!u->in_mmap_memblocks[u->in_mmap_current]) {
278
279 chunk.memblock = u->in_mmap_memblocks[u->in_mmap_current] =
280 pa_memblock_new_fixed(
281 u->core->mempool,
282 (uint8_t*) u->in_mmap + u->in_fragment_size*u->in_mmap_current,
283 u->in_fragment_size,
284 1);
285
286 chunk.length = pa_memblock_get_length(chunk.memblock);
287 chunk.index = 0;
288
289 pa_source_post(u->source, &chunk);
290 }
291
292 u->in_mmap_current++;
293 while (u->in_mmap_current >= u->in_nfrags)
294 u->in_mmap_current -= u->in_nfrags;
295
296 n--;
297 }
298 }
299
300 static void mmap_clear_memblocks(struct userdata*u, unsigned n) {
301 unsigned i = u->in_mmap_current;
302
303 pa_assert(u);
304 pa_assert(u->in_mmap_memblocks);
305
306 if (n > u->in_nfrags)
307 n = u->in_nfrags;
308
309 while (n > 0) {
310 if (u->in_mmap_memblocks[i]) {
311 pa_memblock_unref_fixed(u->in_mmap_memblocks[i]);
312 u->in_mmap_memblocks[i] = NULL;
313 }
314
315 i++;
316 while (i >= u->in_nfrags)
317 i -= u->in_nfrags;
318
319 n--;
320 }
321 }
322
323 static int mmap_read(struct userdata *u) {
324 struct count_info info;
325 pa_assert(u);
326 pa_assert(u->source);
327
328 /* pa_log("Mmmap reading..."); */
329
330 if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
331 pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno));
332 return -1;
333 }
334
335 /* pa_log("... %i", info.blocks); */
336
337 info.blocks += u->in_mmap_saved_nfrags;
338 u->in_mmap_saved_nfrags = 0;
339
340 if (info.blocks > 0) {
341 mmap_post_memblocks(u, info.blocks);
342 mmap_clear_memblocks(u, u->in_nfrags/2);
343 }
344
345 return info.blocks;
346 }
347
348 static pa_usec_t mmap_sink_get_latency(struct userdata *u) {
349 struct count_info info;
350 size_t bpos, n;
351
352 pa_assert(u);
353
354 if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
355 pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno));
356 return 0;
357 }
358
359 u->out_mmap_saved_nfrags += info.blocks;
360
361 bpos = ((u->out_mmap_current + u->out_mmap_saved_nfrags) * u->out_fragment_size) % u->out_hwbuf_size;
362
363 if (bpos <= (size_t) info.ptr)
364 n = u->out_hwbuf_size - (info.ptr - bpos);
365 else
366 n = bpos - info.ptr;
367
368 /* pa_log("n = %u, bpos = %u, ptr = %u, total=%u, fragsize = %u, n_frags = %u\n", n, bpos, (unsigned) info.ptr, total, u->out_fragment_size, u->out_fragments); */
369
370 return pa_bytes_to_usec(n, &u->sink->sample_spec);
371 }
372
373 static pa_usec_t mmap_source_get_latency(struct userdata *u) {
374 struct count_info info;
375 size_t bpos, n;
376
377 pa_assert(u);
378
379 if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
380 pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno));
381 return 0;
382 }
383
384 u->in_mmap_saved_nfrags += info.blocks;
385 bpos = ((u->in_mmap_current + u->in_mmap_saved_nfrags) * u->in_fragment_size) % u->in_hwbuf_size;
386
387 if (bpos <= (size_t) info.ptr)
388 n = info.ptr - bpos;
389 else
390 n = u->in_hwbuf_size - bpos + info.ptr;
391
392 /* pa_log("n = %u, bpos = %u, ptr = %u, total=%u, fragsize = %u, n_frags = %u\n", n, bpos, (unsigned) info.ptr, total, u->in_fragment_size, u->in_fragments); */
393
394 return pa_bytes_to_usec(n, &u->source->sample_spec);
395 }
396
397 static pa_usec_t io_sink_get_latency(struct userdata *u) {
398 pa_usec_t r = 0;
399
400 pa_assert(u);
401
402 if (u->use_getodelay) {
403 int arg;
404
405 if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) {
406 pa_log_info("Device doesn't support SNDCTL_DSP_GETODELAY: %s", pa_cstrerror(errno));
407 u->use_getodelay = 0;
408 } else
409 r = pa_bytes_to_usec(arg, &u->sink->sample_spec);
410
411 }
412
413 if (!u->use_getodelay && u->use_getospace) {
414 struct audio_buf_info info;
415
416 if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
417 pa_log_info("Device doesn't support SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno));
418 u->use_getospace = 0;
419 } else
420 r = pa_bytes_to_usec(info.bytes, &u->sink->sample_spec);
421 }
422
423 if (u->memchunk.memblock)
424 r += pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec);
425
426 return r;
427 }
428
429
430 static pa_usec_t io_source_get_latency(struct userdata *u) {
431 pa_usec_t r = 0;
432
433 pa_assert(u);
434
435 if (u->use_getispace) {
436 struct audio_buf_info info;
437
438 if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
439 pa_log_info("Device doesn't support SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno));
440 u->use_getispace = 0;
441 } else
442 r = pa_bytes_to_usec(info.bytes, &u->source->sample_spec);
443 }
444
445 return r;
446 }
447
448 static void build_pollfd(struct userdata *u) {
449 struct pollfd *pollfd;
450
451 pa_assert(u);
452 pa_assert(u->fd >= 0);
453
454 if (u->rtpoll_item)
455 pa_rtpoll_item_free(u->rtpoll_item);
456
457 u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
458 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
459 pollfd->fd = u->fd;
460 pollfd->events = 0;
461 pollfd->revents = 0;
462 }
463
464 static int suspend(struct userdata *u) {
465 pa_assert(u);
466 pa_assert(u->fd >= 0);
467
468 pa_log_info("Suspending...");
469
470 if (u->out_mmap_memblocks) {
471 unsigned i;
472 for (i = 0; i < u->out_nfrags; i++)
473 if (u->out_mmap_memblocks[i]) {
474 pa_memblock_unref_fixed(u->out_mmap_memblocks[i]);
475 u->out_mmap_memblocks[i] = NULL;
476 }
477 }
478
479 if (u->in_mmap_memblocks) {
480 unsigned i;
481 for (i = 0; i < u->in_nfrags; i++)
482 if (u->in_mmap_memblocks[i]) {
483 pa_memblock_unref_fixed(u->in_mmap_memblocks[i]);
484 u->in_mmap_memblocks[i] = NULL;
485 }
486 }
487
488 if (u->in_mmap && u->in_mmap != MAP_FAILED) {
489 munmap(u->in_mmap, u->in_hwbuf_size);
490 u->in_mmap = NULL;
491 }
492
493 if (u->out_mmap && u->out_mmap != MAP_FAILED) {
494 munmap(u->out_mmap, u->out_hwbuf_size);
495 u->out_mmap = NULL;
496 }
497
498 /* Let's suspend */
499 ioctl(u->fd, SNDCTL_DSP_SYNC, NULL);
500 pa_close(u->fd);
501 u->fd = -1;
502
503 if (u->rtpoll_item) {
504 pa_rtpoll_item_free(u->rtpoll_item);
505 u->rtpoll_item = NULL;
506 }
507
508 pa_log_info("Device suspended...");
509
510 return 0;
511 }
512
513 static int unsuspend(struct userdata *u) {
514 int m;
515 pa_sample_spec ss, *ss_original;
516 int frag_size, in_frag_size, out_frag_size;
517 int in_nfrags, out_nfrags;
518 struct audio_buf_info info;
519
520 pa_assert(u);
521 pa_assert(u->fd < 0);
522
523 m = u->mode;
524
525 pa_log_info("Trying resume...");
526
527 if ((u->fd = pa_oss_open(u->device_name, &m, NULL)) < 0) {
528 pa_log_warn("Resume failed, device busy (%s)", pa_cstrerror(errno));
529 return -1;
530
531 if (m != u->mode)
532 pa_log_warn("Resume failed, couldn't open device with original access mode.");
533 goto fail;
534 }
535
536 if (u->nfrags >= 2 && u->frag_size >= 1)
537 if (pa_oss_set_fragments(u->fd, u->nfrags, u->frag_size) < 0) {
538 pa_log_warn("Resume failed, couldn't set original fragment settings.");
539 goto fail;
540 }
541
542 ss = *(ss_original = u->sink ? &u->sink->sample_spec : &u->source->sample_spec);
543 if (pa_oss_auto_format(u->fd, &ss) < 0 || !pa_sample_spec_equal(&ss, ss_original)) {
544 pa_log_warn("Resume failed, couldn't set original sample format settings.");
545 goto fail;
546 }
547
548 if (ioctl(u->fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) {
549 pa_log_warn("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno));
550 goto fail;
551 }
552
553 in_frag_size = out_frag_size = frag_size;
554 in_nfrags = out_nfrags = u->nfrags;
555
556 if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) >= 0) {
557 in_frag_size = info.fragsize;
558 in_nfrags = info.fragstotal;
559 }
560
561 if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) {
562 out_frag_size = info.fragsize;
563 out_nfrags = info.fragstotal;
564 }
565
566 if ((u->source && (in_frag_size != (int) u->in_fragment_size || in_nfrags != (int) u->in_nfrags)) ||
567 (u->sink && (out_frag_size != (int) u->out_fragment_size || out_nfrags != (int) u->out_nfrags))) {
568 pa_log_warn("Resume failed, input fragment settings don't match.");
569 goto fail;
570 }
571
572 if (u->use_mmap) {
573 if (u->source) {
574 if ((u->in_mmap = mmap(NULL, u->in_hwbuf_size, PROT_READ, MAP_SHARED, u->fd, 0)) == MAP_FAILED) {
575 pa_log("Resume failed, mmap(): %s", pa_cstrerror(errno));
576 goto fail;
577 }
578 }
579
580 if (u->sink) {
581 if ((u->out_mmap = mmap(NULL, u->out_hwbuf_size, PROT_WRITE, MAP_SHARED, u->fd, 0)) == MAP_FAILED) {
582 pa_log("Resume failed, mmap(): %s", pa_cstrerror(errno));
583 if (u->in_mmap && u->in_mmap != MAP_FAILED) {
584 munmap(u->in_mmap, u->in_hwbuf_size);
585 u->in_mmap = NULL;
586 }
587
588 goto fail;
589 }
590
591 pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &ss);
592 }
593 }
594
595 u->out_mmap_current = u->in_mmap_current = 0;
596 u->out_mmap_saved_nfrags = u->in_mmap_saved_nfrags = 0;
597
598 pa_assert(!u->rtpoll_item);
599
600 build_pollfd(u);
601
602 if (u->sink)
603 pa_sink_get_volume(u->sink);
604 if (u->source)
605 pa_source_get_volume(u->source);
606
607 pa_log_info("Resumed successfully...");
608
609 return 0;
610
611 fail:
612 pa_close(u->fd);
613 u->fd = -1;
614 return -1;
615 }
616
617 static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
618 struct userdata *u = PA_SINK(o)->userdata;
619 int ret;
620 pa_bool_t do_trigger = FALSE, quick = TRUE;
621
622 switch (code) {
623
624 case PA_SINK_MESSAGE_GET_LATENCY: {
625 pa_usec_t r = 0;
626
627 if (u->fd >= 0) {
628 if (u->use_mmap)
629 r = mmap_sink_get_latency(u);
630 else
631 r = io_sink_get_latency(u);
632 }
633
634 *((pa_usec_t*) data) = r;
635
636 return 0;
637 }
638
639 case PA_SINK_MESSAGE_SET_STATE:
640
641 switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) {
642
643 case PA_SINK_SUSPENDED:
644 pa_assert(PA_SINK_OPENED(u->sink->thread_info.state));
645
646 if (!u->source || u->source_suspended) {
647 if (suspend(u) < 0)
648 return -1;
649 }
650
651 do_trigger = TRUE;
652
653 u->sink_suspended = TRUE;
654 break;
655
656 case PA_SINK_IDLE:
657 case PA_SINK_RUNNING:
658
659 if (u->sink->thread_info.state == PA_SINK_INIT) {
660 do_trigger = TRUE;
661 quick = u->source && PA_SOURCE_OPENED(u->source->thread_info.state);
662 }
663
664 if (u->sink->thread_info.state == PA_SINK_SUSPENDED) {
665
666 if (!u->source || u->source_suspended) {
667 if (unsuspend(u) < 0)
668 return -1;
669 quick = FALSE;
670 }
671
672 do_trigger = TRUE;
673
674 u->out_mmap_current = 0;
675 u->out_mmap_saved_nfrags = 0;
676
677 u->sink_suspended = FALSE;
678 }
679
680 break;
681
682 case PA_SINK_UNLINKED:
683 case PA_SINK_INIT:
684 ;
685 }
686
687 break;
688
689 }
690
691 ret = pa_sink_process_msg(o, code, data, offset, chunk);
692
693 if (do_trigger)
694 trigger(u, quick);
695
696 return ret;
697 }
698
699 static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
700 struct userdata *u = PA_SOURCE(o)->userdata;
701 int ret;
702 int do_trigger = FALSE, quick = TRUE;
703
704 switch (code) {
705
706 case PA_SOURCE_MESSAGE_GET_LATENCY: {
707 pa_usec_t r = 0;
708
709 if (u->fd >= 0) {
710 if (u->use_mmap)
711 r = mmap_source_get_latency(u);
712 else
713 r = io_source_get_latency(u);
714 }
715
716 *((pa_usec_t*) data) = r;
717 return 0;
718 }
719
720 case PA_SOURCE_MESSAGE_SET_STATE:
721
722 switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) {
723 case PA_SOURCE_SUSPENDED:
724 pa_assert(PA_SOURCE_OPENED(u->source->thread_info.state));
725
726 if (!u->sink || u->sink_suspended) {
727 if (suspend(u) < 0)
728 return -1;
729 }
730
731 do_trigger = TRUE;
732
733 u->source_suspended = TRUE;
734 break;
735
736 case PA_SOURCE_IDLE:
737 case PA_SOURCE_RUNNING:
738
739 if (u->source->thread_info.state == PA_SOURCE_INIT) {
740 do_trigger = TRUE;
741 quick = u->sink && PA_SINK_OPENED(u->sink->thread_info.state);
742 }
743
744 if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) {
745
746 if (!u->sink || u->sink_suspended) {
747 if (unsuspend(u) < 0)
748 return -1;
749 quick = FALSE;
750 }
751
752 do_trigger = TRUE;
753
754 u->in_mmap_current = 0;
755 u->in_mmap_saved_nfrags = 0;
756
757 u->source_suspended = FALSE;
758 }
759 break;
760
761 case PA_SOURCE_UNLINKED:
762 case PA_SOURCE_INIT:
763 ;
764
765 }
766 break;
767
768 }
769
770 ret = pa_source_process_msg(o, code, data, offset, chunk);
771
772 if (do_trigger)
773 trigger(u, quick);
774
775 return ret;
776 }
777
778 static int sink_get_volume(pa_sink *s) {
779 struct userdata *u;
780 int r;
781
782 pa_assert_se(u = s->userdata);
783
784 pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
785
786 if (u->mixer_devmask & SOUND_MASK_VOLUME)
787 if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_VOLUME, &s->sample_spec, &s->volume)) >= 0)
788 return r;
789
790 if (u->mixer_devmask & SOUND_MASK_PCM)
791 if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_PCM, &s->sample_spec, &s->volume)) >= 0)
792 return r;
793
794 pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
795 return -1;
796 }
797
798 static int sink_set_volume(pa_sink *s) {
799 struct userdata *u;
800 int r;
801
802 pa_assert_se(u = s->userdata);
803
804 pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
805
806 if (u->mixer_devmask & SOUND_MASK_VOLUME)
807 if ((r = pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->volume)) >= 0)
808 return r;
809
810 if (u->mixer_devmask & SOUND_MASK_PCM)
811 if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->volume)) >= 0)
812 return r;
813
814 pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
815 return -1;
816 }
817
818 static int source_get_volume(pa_source *s) {
819 struct userdata *u;
820 int r;
821
822 pa_assert_se(u = s->userdata);
823
824 pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV));
825
826 if (u->mixer_devmask & SOUND_MASK_IGAIN)
827 if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_IGAIN, &s->sample_spec, &s->volume)) >= 0)
828 return r;
829
830 if (u->mixer_devmask & SOUND_MASK_RECLEV)
831 if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_RECLEV, &s->sample_spec, &s->volume)) >= 0)
832 return r;
833
834 pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
835 return -1;
836 }
837
838 static int source_set_volume(pa_source *s) {
839 struct userdata *u;
840 int r;
841
842 pa_assert_se(u = s->userdata);
843
844 pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV));
845
846 if (u->mixer_devmask & SOUND_MASK_IGAIN)
847 if ((r = pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_IGAIN, &s->sample_spec, &s->volume)) >= 0)
848 return r;
849
850 if (u->mixer_devmask & SOUND_MASK_RECLEV)
851 if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_RECLEV, &s->sample_spec, &s->volume)) >= 0)
852 return r;
853
854 pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
855 return -1;
856 }
857
858 static void thread_func(void *userdata) {
859 struct userdata *u = userdata;
860 int write_type = 0, read_type = 0;
861 unsigned short revents = 0;
862
863 pa_assert(u);
864
865 pa_log_debug("Thread starting up");
866
867 if (u->core->realtime_scheduling)
868 pa_make_realtime(u->core->realtime_priority);
869
870 pa_thread_mq_install(&u->thread_mq);
871 pa_rtpoll_install(u->rtpoll);
872
873 for (;;) {
874 int ret;
875
876 /* pa_log("loop"); */
877
878 /* Render some data and write it to the dsp */
879
880 if (u->sink && PA_SINK_OPENED(u->sink->thread_info.state) && ((revents & POLLOUT) || u->use_mmap || u->use_getospace)) {
881
882 if (u->use_mmap) {
883
884 if ((ret = mmap_write(u)) < 0)
885 goto fail;
886
887 revents &= ~POLLOUT;
888
889 if (ret > 0)
890 continue;
891
892 } else {
893 ssize_t l;
894 pa_bool_t loop = FALSE, work_done = FALSE;
895
896 l = u->out_fragment_size;
897
898 if (u->use_getospace) {
899 audio_buf_info info;
900
901 if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
902 pa_log_info("Device doesn't support SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno));
903 u->use_getospace = FALSE;
904 } else {
905 l = info.bytes;
906
907 /* We loop only if GETOSPACE worked and we
908 * actually *know* that we can write more than
909 * one fragment at a time */
910 loop = TRUE;
911 }
912 }
913
914 /* Round down to multiples of the fragment size,
915 * because OSS needs that (at least some versions
916 * do) */
917 l = (l/u->out_fragment_size) * u->out_fragment_size;
918
919 /* Hmm, so poll() signalled us that we can read
920 * something, but GETOSPACE told us there was nothing?
921 * Hmm, make the best of it, try to read some data, to
922 * avoid spinning forever. */
923 if (l <= 0 && (revents & POLLOUT)) {
924 l = u->out_fragment_size;
925 loop = FALSE;
926 }
927
928 while (l > 0) {
929 void *p;
930 ssize_t t;
931
932 if (u->memchunk.length <= 0)
933 pa_sink_render(u->sink, l, &u->memchunk);
934
935 pa_assert(u->memchunk.length > 0);
936
937 p = pa_memblock_acquire(u->memchunk.memblock);
938 t = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, &write_type);
939 pa_memblock_release(u->memchunk.memblock);
940
941 /* pa_log("wrote %i bytes of %u", t, l); */
942
943 pa_assert(t != 0);
944
945 if (t < 0) {
946
947 if (errno == EINTR)
948 continue;
949
950 else if (errno == EAGAIN) {
951 pa_log_debug("EAGAIN");
952
953 revents &= ~POLLOUT;
954 break;
955
956 } else {
957 pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno));
958 goto fail;
959 }
960
961 } else {
962
963 u->memchunk.index += t;
964 u->memchunk.length -= t;
965
966 if (u->memchunk.length <= 0) {
967 pa_memblock_unref(u->memchunk.memblock);
968 pa_memchunk_reset(&u->memchunk);
969 }
970
971 l -= t;
972
973 revents &= ~POLLOUT;
974 work_done = TRUE;
975 }
976
977 if (!loop)
978 break;
979 }
980
981 if (work_done)
982 continue;
983 }
984 }
985
986 /* Try to read some data and pass it on to the source driver. */
987
988 if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state) && ((revents & POLLIN) || u->use_mmap || u->use_getispace)) {
989
990 if (u->use_mmap) {
991
992 if ((ret = mmap_read(u)) < 0)
993 goto fail;
994
995 revents &= ~POLLIN;
996
997 if (ret > 0)
998 continue;
999
1000 } else {
1001
1002 void *p;
1003 ssize_t l;
1004 pa_memchunk memchunk;
1005 pa_bool_t loop = FALSE, work_done = FALSE;
1006
1007 l = u->in_fragment_size;
1008
1009 if (u->use_getispace) {
1010 audio_buf_info info;
1011
1012 if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
1013 pa_log_info("Device doesn't support SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno));
1014 u->use_getispace = FALSE;
1015 } else {
1016 l = info.bytes;
1017 loop = TRUE;
1018 }
1019 }
1020
1021 l = (l/u->in_fragment_size) * u->in_fragment_size;
1022
1023 if (l <= 0 && (revents & POLLIN)) {
1024 l = u->in_fragment_size;
1025 loop = FALSE;
1026 }
1027
1028 while (l > 0) {
1029 ssize_t t, k;
1030
1031 pa_assert(l > 0);
1032
1033 memchunk.memblock = pa_memblock_new(u->core->mempool, (size_t) -1);
1034
1035 k = pa_memblock_get_length(memchunk.memblock);
1036
1037 if (k > l)
1038 k = l;
1039
1040 k = (k/u->frame_size)*u->frame_size;
1041
1042 p = pa_memblock_acquire(memchunk.memblock);
1043 t = pa_read(u->fd, p, k, &read_type);
1044 pa_memblock_release(memchunk.memblock);
1045
1046 pa_assert(t != 0); /* EOF cannot happen */
1047
1048 /* pa_log("read %i bytes of %u", t, l); */
1049
1050 if (t < 0) {
1051 pa_memblock_unref(memchunk.memblock);
1052
1053 if (errno == EINTR)
1054 continue;
1055
1056 else if (errno == EAGAIN) {
1057 pa_log_debug("EAGAIN");
1058
1059 revents &= ~POLLIN;
1060 break;
1061
1062 } else {
1063 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno));
1064 goto fail;
1065 }
1066
1067 } else {
1068 memchunk.index = 0;
1069 memchunk.length = t;
1070
1071 pa_source_post(u->source, &memchunk);
1072 pa_memblock_unref(memchunk.memblock);
1073
1074 l -= t;
1075
1076 revents &= ~POLLIN;
1077 work_done = TRUE;
1078 }
1079
1080 if (!loop)
1081 break;
1082 }
1083
1084 if (work_done)
1085 continue;
1086 }
1087 }
1088
1089 /* pa_log("loop2 revents=%i", revents); */
1090
1091 if (u->rtpoll_item) {
1092 struct pollfd *pollfd;
1093
1094 pa_assert(u->fd >= 0);
1095
1096 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
1097 pollfd->events =
1098 ((u->source && PA_SOURCE_OPENED(u->source->thread_info.state)) ? POLLIN : 0) |
1099 ((u->sink && PA_SINK_OPENED(u->sink->thread_info.state)) ? POLLOUT : 0);
1100 }
1101
1102 /* Hmm, nothing to do. Let's sleep */
1103 if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
1104 goto fail;
1105
1106 if (ret == 0)
1107 goto finish;
1108
1109 if (u->rtpoll_item) {
1110 struct pollfd *pollfd;
1111
1112 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
1113
1114 if (pollfd->revents & ~(POLLOUT|POLLIN)) {
1115 pa_log("DSP shutdown.");
1116 goto fail;
1117 }
1118
1119 revents = pollfd->revents;
1120 } else
1121 revents = 0;
1122 }
1123
1124 fail:
1125 /* If this was no regular exit from the loop we have to continue
1126 * processing messages until we received PA_MESSAGE_SHUTDOWN */
1127 pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
1128 pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
1129
1130 finish:
1131 pa_log_debug("Thread shutting down");
1132 }
1133
1134 int pa__init(pa_module*m) {
1135
1136 struct audio_buf_info info;
1137 struct userdata *u = NULL;
1138 const char *dev;
1139 int fd = -1;
1140 int nfrags, frag_size;
1141 int mode, caps;
1142 int record = 1, playback = 1, use_mmap = 1;
1143 pa_sample_spec ss;
1144 pa_channel_map map;
1145 pa_modargs *ma = NULL;
1146 char hwdesc[64], *t;
1147 const char *name;
1148 int namereg_fail;
1149
1150 pa_assert(m);
1151
1152 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1153 pa_log("Failed to parse module arguments.");
1154 goto fail;
1155 }
1156
1157 if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
1158 pa_log("record= and playback= expect numeric argument.");
1159 goto fail;
1160 }
1161
1162 if (!playback && !record) {
1163 pa_log("Neither playback nor record enabled for device.");
1164 goto fail;
1165 }
1166
1167 mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
1168
1169 ss = m->core->default_sample_spec;
1170 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_OSS) < 0) {
1171 pa_log("Failed to parse sample specification or channel map");
1172 goto fail;
1173 }
1174
1175 nfrags = m->core->default_n_fragments;
1176 frag_size = pa_usec_to_bytes(m->core->default_fragment_size_msec*1000, &ss);
1177 if (frag_size <= 0)
1178 frag_size = pa_frame_size(&ss);
1179
1180 if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) {
1181 pa_log("Failed to parse fragments arguments");
1182 goto fail;
1183 }
1184
1185 if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) {
1186 pa_log("Failed to parse mmap argument.");
1187 goto fail;
1188 }
1189
1190 if ((fd = pa_oss_open(dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0)
1191 goto fail;
1192
1193 if (use_mmap && (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_TRIGGER))) {
1194 pa_log_info("OSS device not mmap capable, falling back to UNIX read/write mode.");
1195 use_mmap = 0;
1196 }
1197
1198 if (use_mmap && mode == O_WRONLY) {
1199 pa_log_info("Device opened for playback only, cannot do memory mapping, falling back to UNIX write() mode.");
1200 use_mmap = 0;
1201 }
1202
1203 if (pa_oss_get_hw_description(dev, hwdesc, sizeof(hwdesc)) >= 0)
1204 pa_log_info("Hardware name is '%s'.", hwdesc);
1205 else
1206 hwdesc[0] = 0;
1207
1208 pa_log_info("Device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));
1209
1210 if (nfrags >= 2 && frag_size >= 1)
1211 if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0)
1212 goto fail;
1213
1214 if (pa_oss_auto_format(fd, &ss) < 0)
1215 goto fail;
1216
1217 if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) {
1218 pa_log("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno));
1219 goto fail;
1220 }
1221 pa_assert(frag_size > 0);
1222
1223 u = pa_xnew0(struct userdata, 1);
1224 u->core = m->core;
1225 u->module = m;
1226 m->userdata = u;
1227 u->fd = fd;
1228 u->mixer_fd = -1;
1229 u->use_getospace = u->use_getispace = 1;
1230 u->use_getodelay = 1;
1231 u->mode = mode;
1232 u->frame_size = pa_frame_size(&ss);
1233 u->device_name = pa_xstrdup(dev);
1234 u->in_nfrags = u->out_nfrags = u->nfrags = nfrags;
1235 u->out_fragment_size = u->in_fragment_size = u->frag_size = frag_size;
1236 u->use_mmap = use_mmap;
1237 pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
1238 u->rtpoll = pa_rtpoll_new();
1239 pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);
1240 u->rtpoll_item = NULL;
1241 build_pollfd(u);
1242
1243 if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) {
1244 pa_log_info("Input -- %u fragments of size %u.", info.fragstotal, info.fragsize);
1245 u->in_fragment_size = info.fragsize;
1246 u->in_nfrags = info.fragstotal;
1247 u->use_getispace = 1;
1248 }
1249
1250 if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) {
1251 pa_log_info("Output -- %u fragments of size %u.", info.fragstotal, info.fragsize);
1252 u->out_fragment_size = info.fragsize;
1253 u->out_nfrags = info.fragstotal;
1254 u->use_getospace = 1;
1255 }
1256
1257 u->in_hwbuf_size = u->in_nfrags * u->in_fragment_size;
1258 u->out_hwbuf_size = u->out_nfrags * u->out_fragment_size;
1259
1260 if (mode != O_WRONLY) {
1261 char *name_buf = NULL;
1262
1263 if (use_mmap) {
1264 if ((u->in_mmap = mmap(NULL, u->in_hwbuf_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
1265 pa_log_warn("mmap(PROT_READ) failed, reverting to non-mmap mode: %s", pa_cstrerror(errno));
1266 use_mmap = u->use_mmap = 0;
1267 u->in_mmap = NULL;
1268 } else
1269 pa_log_debug("Successfully mmap()ed input buffer.");
1270 }
1271
1272 if ((name = pa_modargs_get_value(ma, "source_name", NULL)))
1273 namereg_fail = 1;
1274 else {
1275 name = name_buf = pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(dev));
1276 namereg_fail = 0;
1277 }
1278
1279 u->source = pa_source_new(m->core, __FILE__, name, namereg_fail, &ss, &map);
1280 pa_xfree(name_buf);
1281 if (!u->source) {
1282 pa_log("Failed to create source object");
1283 goto fail;
1284 }
1285
1286 u->source->parent.process_msg = source_process_msg;
1287 u->source->userdata = u;
1288
1289 pa_source_set_module(u->source, m);
1290 pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
1291 pa_source_set_rtpoll(u->source, u->rtpoll);
1292 pa_source_set_description(u->source, t = pa_sprintf_malloc(
1293 "OSS PCM on %s%s%s%s%s",
1294 dev,
1295 hwdesc[0] ? " (" : "",
1296 hwdesc[0] ? hwdesc : "",
1297 hwdesc[0] ? ")" : "",
1298 use_mmap ? " via DMA" : ""));
1299 pa_xfree(t);
1300 u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY;
1301 u->source->refresh_volume = TRUE;
1302
1303 if (use_mmap)
1304 u->in_mmap_memblocks = pa_xnew0(pa_memblock*, u->in_nfrags);
1305 }
1306
1307 if (mode != O_RDONLY) {
1308 char *name_buf = NULL;
1309
1310 if (use_mmap) {
1311 if ((u->out_mmap = mmap(NULL, u->out_hwbuf_size, PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
1312 if (mode == O_RDWR) {
1313 pa_log_debug("mmap() failed for input. Changing to O_WRONLY mode.");
1314 mode = O_WRONLY;
1315 goto go_on;
1316 } else {
1317 pa_log_warn("mmap(PROT_WRITE) failed, reverting to non-mmap mode: %s", pa_cstrerror(errno));
1318 u->use_mmap = (use_mmap = FALSE);
1319 u->out_mmap = NULL;
1320 }
1321 } else {
1322 pa_log_debug("Successfully mmap()ed output buffer.");
1323 pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &ss);
1324 }
1325 }
1326
1327 if ((name = pa_modargs_get_value(ma, "sink_name", NULL)))
1328 namereg_fail = 1;
1329 else {
1330 name = name_buf = pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(dev));
1331 namereg_fail = 0;
1332 }
1333
1334 u->sink = pa_sink_new(m->core, __FILE__, name, namereg_fail, &ss, &map);
1335 pa_xfree(name_buf);
1336 if (!u->sink) {
1337 pa_log("Failed to create sink object");
1338 goto fail;
1339 }
1340
1341 u->sink->parent.process_msg = sink_process_msg;
1342 u->sink->userdata = u;
1343
1344 pa_sink_set_module(u->sink, m);
1345 pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
1346 pa_sink_set_rtpoll(u->sink, u->rtpoll);
1347 pa_sink_set_description(u->sink, t = pa_sprintf_malloc(
1348 "OSS PCM on %s%s%s%s%s",
1349 dev,
1350 hwdesc[0] ? " (" : "",
1351 hwdesc[0] ? hwdesc : "",
1352 hwdesc[0] ? ")" : "",
1353 use_mmap ? " via DMA" : ""));
1354 pa_xfree(t);
1355 u->sink->flags = PA_SINK_HARDWARE|PA_SINK_LATENCY;
1356 u->sink->refresh_volume = TRUE;
1357
1358 if (use_mmap)
1359 u->out_mmap_memblocks = pa_xnew0(pa_memblock*, u->out_nfrags);
1360 }
1361
1362 if ((u->mixer_fd = pa_oss_open_mixer_for_device(u->device_name)) >= 0) {
1363 int do_close = 1;
1364 u->mixer_devmask = 0;
1365
1366 if (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &u->mixer_devmask) < 0)
1367 pa_log_warn("SOUND_MIXER_READ_DEVMASK failed: %s", pa_cstrerror(errno));
1368
1369 else {
1370 if (u->sink && (u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM))) {
1371 pa_log_debug("Found hardware mixer track for playback.");
1372 u->sink->flags |= PA_SINK_HW_VOLUME_CTRL;
1373 u->sink->get_volume = sink_get_volume;
1374 u->sink->set_volume = sink_set_volume;
1375 do_close = 0;
1376 }
1377
1378 if (u->source && (u->mixer_devmask & (SOUND_MASK_RECLEV|SOUND_MASK_IGAIN))) {
1379 pa_log_debug("Found hardware mixer track for recording.");
1380 u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL;
1381 u->source->get_volume = source_get_volume;
1382 u->source->set_volume = source_set_volume;
1383 do_close = 0;
1384 }
1385 }
1386
1387 if (do_close) {
1388 pa_close(u->mixer_fd);
1389 u->mixer_fd = -1;
1390 }
1391 }
1392
1393 go_on:
1394
1395 pa_assert(u->source || u->sink);
1396
1397 pa_memchunk_reset(&u->memchunk);
1398
1399 if (!(u->thread = pa_thread_new(thread_func, u))) {
1400 pa_log("Failed to create thread.");
1401 goto fail;
1402 }
1403
1404 /* Read mixer settings */
1405 if (u->sink && u->sink->get_volume)
1406 sink_get_volume(u->sink);
1407 if (u->source && u->source->get_volume)
1408 source_get_volume(u->source);
1409
1410 if (u->sink)
1411 pa_sink_put(u->sink);
1412 if (u->source)
1413 pa_source_put(u->source);
1414
1415 pa_modargs_free(ma);
1416
1417 return 0;
1418
1419 fail:
1420
1421 if (u)
1422 pa__done(m);
1423 else if (fd >= 0)
1424 pa_close(fd);
1425
1426 if (ma)
1427 pa_modargs_free(ma);
1428
1429 return -1;
1430 }
1431
1432 void pa__done(pa_module*m) {
1433 struct userdata *u;
1434
1435 pa_assert(m);
1436
1437 if (!(u = m->userdata))
1438 return;
1439
1440 if (u->sink)
1441 pa_sink_unlink(u->sink);
1442
1443 if (u->source)
1444 pa_source_unlink(u->source);
1445
1446 if (u->thread) {
1447 pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
1448 pa_thread_free(u->thread);
1449 }
1450
1451 pa_thread_mq_done(&u->thread_mq);
1452
1453 if (u->sink)
1454 pa_sink_unref(u->sink);
1455
1456 if (u->source)
1457 pa_source_unref(u->source);
1458
1459 if (u->memchunk.memblock)
1460 pa_memblock_unref(u->memchunk.memblock);
1461
1462 if (u->rtpoll_item)
1463 pa_rtpoll_item_free(u->rtpoll_item);
1464
1465 if (u->rtpoll)
1466 pa_rtpoll_free(u->rtpoll);
1467
1468 if (u->out_mmap_memblocks) {
1469 unsigned i;
1470 for (i = 0; i < u->out_nfrags; i++)
1471 if (u->out_mmap_memblocks[i])
1472 pa_memblock_unref_fixed(u->out_mmap_memblocks[i]);
1473 pa_xfree(u->out_mmap_memblocks);
1474 }
1475
1476 if (u->in_mmap_memblocks) {
1477 unsigned i;
1478 for (i = 0; i < u->in_nfrags; i++)
1479 if (u->in_mmap_memblocks[i])
1480 pa_memblock_unref_fixed(u->in_mmap_memblocks[i]);
1481 pa_xfree(u->in_mmap_memblocks);
1482 }
1483
1484 if (u->in_mmap && u->in_mmap != MAP_FAILED)
1485 munmap(u->in_mmap, u->in_hwbuf_size);
1486
1487 if (u->out_mmap && u->out_mmap != MAP_FAILED)
1488 munmap(u->out_mmap, u->out_hwbuf_size);
1489
1490 if (u->fd >= 0)
1491 pa_close(u->fd);
1492
1493 if (u->mixer_fd >= 0)
1494 pa_close(u->mixer_fd);
1495
1496 pa_xfree(u->device_name);
1497
1498 pa_xfree(u);
1499 }