Fix up according to Coding Style
[pulseaudio-mirror.git] / src / modules / oss / module-oss.c
blob84dbbdafe066ab305f9396616fec07c00437fa11
1 /***
2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
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.
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.
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 ***/
23 /* General power management rules:
25 * When SUSPENDED we close the audio device.
27 * We make no difference between IDLE and RUNNING in our handling.
29 * As long as we are in RUNNING/IDLE state we will *always* write data to
30 * the device. If none is avilable from the inputs, we write silence
31 * instead.
33 * If power should be saved on IDLE module-suspend-on-idle should be used.
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
41 #ifdef HAVE_SYS_MMAN_H
42 #include <sys/mman.h>
43 #endif
45 #include <sys/soundcard.h>
46 #include <sys/ioctl.h>
47 #include <stdlib.h>
48 #include <sys/stat.h>
49 #include <stdio.h>
50 #include <errno.h>
51 #include <string.h>
52 #include <fcntl.h>
53 #include <unistd.h>
54 #include <limits.h>
55 #include <signal.h>
57 #include <pulse/xmalloc.h>
58 #include <pulse/util.h>
60 #include <pulsecore/core-error.h>
61 #include <pulsecore/thread.h>
62 #include <pulsecore/sink.h>
63 #include <pulsecore/source.h>
64 #include <pulsecore/module.h>
65 #include <pulsecore/sample-util.h>
66 #include <pulsecore/core-util.h>
67 #include <pulsecore/modargs.h>
68 #include <pulsecore/log.h>
69 #include <pulsecore/macro.h>
70 #include <pulsecore/thread-mq.h>
71 #include <pulsecore/rtpoll.h>
72 #include <pulsecore/poll.h>
74 #if defined(__NetBSD__) && !defined(SNDCTL_DSP_GETODELAY)
75 #include <sys/audioio.h>
76 #include <sys/syscall.h>
77 #endif
79 #include "oss-util.h"
80 #include "module-oss-symdef.h"
82 PA_MODULE_AUTHOR("Lennart Poettering");
83 PA_MODULE_DESCRIPTION("OSS Sink/Source");
84 PA_MODULE_VERSION(PACKAGE_VERSION);
85 PA_MODULE_LOAD_ONCE(FALSE);
86 PA_MODULE_USAGE(
87 "sink_name=<name for the sink> "
88 "sink_properties=<properties for the sink> "
89 "source_name=<name for the source> "
90 "source_properties=<properties for the source> "
91 "device=<OSS device> "
92 "record=<enable source?> "
93 "playback=<enable sink?> "
94 "format=<sample format> "
95 "rate=<sample rate> "
96 "channels=<number of channels> "
97 "channel_map=<channel map> "
98 "fragments=<number of fragments> "
99 "fragment_size=<fragment size> "
100 "mmap=<enable memory mapping?>");
101 #ifdef __linux__
102 PA_MODULE_DEPRECATED("Please use module-alsa-card instead of module-oss!");
103 #endif
105 #define DEFAULT_DEVICE "/dev/dsp"
107 struct userdata {
108 pa_core *core;
109 pa_module *module;
110 pa_sink *sink;
111 pa_source *source;
113 pa_thread *thread;
114 pa_thread_mq thread_mq;
115 pa_rtpoll *rtpoll;
117 char *device_name;
119 pa_memchunk memchunk;
121 size_t frame_size;
122 uint32_t in_fragment_size, out_fragment_size, in_nfrags, out_nfrags, in_hwbuf_size, out_hwbuf_size;
123 pa_bool_t use_getospace, use_getispace;
124 pa_bool_t use_getodelay;
126 pa_bool_t sink_suspended, source_suspended;
128 int fd;
129 int mode;
131 int mixer_fd;
132 int mixer_devmask;
134 int nfrags, frag_size, orig_frag_size;
136 pa_bool_t use_mmap;
137 unsigned out_mmap_current, in_mmap_current;
138 void *in_mmap, *out_mmap;
139 pa_memblock **in_mmap_memblocks, **out_mmap_memblocks;
141 int in_mmap_saved_nfrags, out_mmap_saved_nfrags;
143 pa_rtpoll_item *rtpoll_item;
146 static const char* const valid_modargs[] = {
147 "sink_name",
148 "sink_properties",
149 "source_name",
150 "source_properties",
151 "device",
152 "record",
153 "playback",
154 "fragments",
155 "fragment_size",
156 "format",
157 "rate",
158 "channels",
159 "channel_map",
160 "mmap",
161 NULL
164 static void trigger(struct userdata *u, pa_bool_t quick) {
165 int enable_bits = 0, zero = 0;
167 pa_assert(u);
169 if (u->fd < 0)
170 return;
172 pa_log_debug("trigger");
174 if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state))
175 enable_bits |= PCM_ENABLE_INPUT;
177 if (u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state))
178 enable_bits |= PCM_ENABLE_OUTPUT;
180 pa_log_debug("trigger: %i", enable_bits);
183 if (u->use_mmap) {
185 if (!quick)
186 ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero);
188 #ifdef SNDCTL_DSP_HALT
189 if (enable_bits == 0)
190 if (ioctl(u->fd, SNDCTL_DSP_HALT, NULL) < 0)
191 pa_log_warn("SNDCTL_DSP_HALT: %s", pa_cstrerror(errno));
192 #endif
194 if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0)
195 pa_log_warn("SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno));
197 if (u->sink && !(enable_bits & PCM_ENABLE_OUTPUT)) {
198 pa_log_debug("clearing playback buffer");
199 pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &u->sink->sample_spec);
202 } else {
204 if (enable_bits)
205 if (ioctl(u->fd, SNDCTL_DSP_POST, NULL) < 0)
206 pa_log_warn("SNDCTL_DSP_POST: %s", pa_cstrerror(errno));
208 if (!quick) {
210 * Some crappy drivers do not start the recording until we
211 * read something. Without this snippet, poll will never
212 * register the fd as ready.
215 if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state)) {
216 uint8_t *buf = pa_xnew(uint8_t, u->in_fragment_size);
217 pa_read(u->fd, buf, u->in_fragment_size, NULL);
218 pa_xfree(buf);
224 static void mmap_fill_memblocks(struct userdata *u, unsigned n) {
225 pa_assert(u);
226 pa_assert(u->out_mmap_memblocks);
228 /* pa_log("Mmmap writing %u blocks", n); */
230 while (n > 0) {
231 pa_memchunk chunk;
233 if (u->out_mmap_memblocks[u->out_mmap_current])
234 pa_memblock_unref_fixed(u->out_mmap_memblocks[u->out_mmap_current]);
236 chunk.memblock = u->out_mmap_memblocks[u->out_mmap_current] =
237 pa_memblock_new_fixed(
238 u->core->mempool,
239 (uint8_t*) u->out_mmap + u->out_fragment_size * u->out_mmap_current,
240 u->out_fragment_size,
243 chunk.length = pa_memblock_get_length(chunk.memblock);
244 chunk.index = 0;
246 pa_sink_render_into_full(u->sink, &chunk);
248 u->out_mmap_current++;
249 while (u->out_mmap_current >= u->out_nfrags)
250 u->out_mmap_current -= u->out_nfrags;
252 n--;
256 static int mmap_write(struct userdata *u) {
257 struct count_info info;
259 pa_assert(u);
260 pa_assert(u->sink);
262 /* pa_log("Mmmap writing..."); */
264 if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
265 pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno));
266 return -1;
269 info.blocks += u->out_mmap_saved_nfrags;
270 u->out_mmap_saved_nfrags = 0;
272 if (info.blocks > 0)
273 mmap_fill_memblocks(u, (unsigned) info.blocks);
275 return info.blocks;
278 static void mmap_post_memblocks(struct userdata *u, unsigned n) {
279 pa_assert(u);
280 pa_assert(u->in_mmap_memblocks);
282 /* pa_log("Mmmap reading %u blocks", n); */
284 while (n > 0) {
285 pa_memchunk chunk;
287 if (!u->in_mmap_memblocks[u->in_mmap_current]) {
289 chunk.memblock = u->in_mmap_memblocks[u->in_mmap_current] =
290 pa_memblock_new_fixed(
291 u->core->mempool,
292 (uint8_t*) u->in_mmap + u->in_fragment_size*u->in_mmap_current,
293 u->in_fragment_size,
296 chunk.length = pa_memblock_get_length(chunk.memblock);
297 chunk.index = 0;
299 pa_source_post(u->source, &chunk);
302 u->in_mmap_current++;
303 while (u->in_mmap_current >= u->in_nfrags)
304 u->in_mmap_current -= u->in_nfrags;
306 n--;
310 static void mmap_clear_memblocks(struct userdata*u, unsigned n) {
311 unsigned i = u->in_mmap_current;
313 pa_assert(u);
314 pa_assert(u->in_mmap_memblocks);
316 if (n > u->in_nfrags)
317 n = u->in_nfrags;
319 while (n > 0) {
320 if (u->in_mmap_memblocks[i]) {
321 pa_memblock_unref_fixed(u->in_mmap_memblocks[i]);
322 u->in_mmap_memblocks[i] = NULL;
325 i++;
326 while (i >= u->in_nfrags)
327 i -= u->in_nfrags;
329 n--;
333 static int mmap_read(struct userdata *u) {
334 struct count_info info;
335 pa_assert(u);
336 pa_assert(u->source);
338 /* pa_log("Mmmap reading..."); */
340 if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
341 pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno));
342 return -1;
345 /* pa_log("... %i", info.blocks); */
347 info.blocks += u->in_mmap_saved_nfrags;
348 u->in_mmap_saved_nfrags = 0;
350 if (info.blocks > 0) {
351 mmap_post_memblocks(u, (unsigned) info.blocks);
352 mmap_clear_memblocks(u, u->in_nfrags/2);
355 return info.blocks;
358 static pa_usec_t mmap_sink_get_latency(struct userdata *u) {
359 struct count_info info;
360 size_t bpos, n;
362 pa_assert(u);
364 if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
365 pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno));
366 return 0;
369 u->out_mmap_saved_nfrags += info.blocks;
371 bpos = ((u->out_mmap_current + (unsigned) u->out_mmap_saved_nfrags) * u->out_fragment_size) % u->out_hwbuf_size;
373 if (bpos <= (size_t) info.ptr)
374 n = u->out_hwbuf_size - ((size_t) info.ptr - bpos);
375 else
376 n = bpos - (size_t) info.ptr;
378 /* 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); */
380 return pa_bytes_to_usec(n, &u->sink->sample_spec);
383 static pa_usec_t mmap_source_get_latency(struct userdata *u) {
384 struct count_info info;
385 size_t bpos, n;
387 pa_assert(u);
389 if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
390 pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno));
391 return 0;
394 u->in_mmap_saved_nfrags += info.blocks;
395 bpos = ((u->in_mmap_current + (unsigned) u->in_mmap_saved_nfrags) * u->in_fragment_size) % u->in_hwbuf_size;
397 if (bpos <= (size_t) info.ptr)
398 n = (size_t) info.ptr - bpos;
399 else
400 n = u->in_hwbuf_size - bpos + (size_t) info.ptr;
402 /* 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); */
404 return pa_bytes_to_usec(n, &u->source->sample_spec);
407 static pa_usec_t io_sink_get_latency(struct userdata *u) {
408 pa_usec_t r = 0;
410 pa_assert(u);
412 if (u->use_getodelay) {
413 int arg;
414 #if defined(__NetBSD__) && !defined(SNDCTL_DSP_GETODELAY)
415 #if defined(AUDIO_GETBUFINFO)
416 struct audio_info info;
417 if (syscall(SYS_ioctl, u->fd, AUDIO_GETBUFINFO, &info) < 0) {
418 pa_log_info("Device doesn't support AUDIO_GETBUFINFO: %s", pa_cstrerror(errno));
419 u->use_getodelay = 0;
420 } else {
421 arg = info.play.seek + info.blocksize / 2;
422 r = pa_bytes_to_usec((size_t) arg, &u->sink->sample_spec);
424 #else
425 pa_log_info("System doesn't support AUDIO_GETBUFINFO");
426 u->use_getodelay = 0;
427 #endif
428 #else
429 if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) {
430 pa_log_info("Device doesn't support SNDCTL_DSP_GETODELAY: %s", pa_cstrerror(errno));
431 u->use_getodelay = 0;
432 } else
433 r = pa_bytes_to_usec((size_t) arg, &u->sink->sample_spec);
434 #endif
437 if (!u->use_getodelay && u->use_getospace) {
438 struct audio_buf_info info;
440 if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
441 pa_log_info("Device doesn't support SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno));
442 u->use_getospace = 0;
443 } else
444 r = pa_bytes_to_usec((size_t) info.bytes, &u->sink->sample_spec);
447 if (u->memchunk.memblock)
448 r += pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec);
450 return r;
453 static pa_usec_t io_source_get_latency(struct userdata *u) {
454 pa_usec_t r = 0;
456 pa_assert(u);
458 if (u->use_getispace) {
459 struct audio_buf_info info;
461 if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
462 pa_log_info("Device doesn't support SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno));
463 u->use_getispace = 0;
464 } else
465 r = pa_bytes_to_usec((size_t) info.bytes, &u->source->sample_spec);
468 return r;
471 static void build_pollfd(struct userdata *u) {
472 struct pollfd *pollfd;
474 pa_assert(u);
475 pa_assert(u->fd >= 0);
477 if (u->rtpoll_item)
478 pa_rtpoll_item_free(u->rtpoll_item);
480 u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
481 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
482 pollfd->fd = u->fd;
483 pollfd->events = 0;
484 pollfd->revents = 0;
487 /* Called from IO context */
488 static int suspend(struct userdata *u) {
489 pa_assert(u);
490 pa_assert(u->fd >= 0);
492 pa_log_info("Suspending...");
494 if (u->out_mmap_memblocks) {
495 unsigned i;
496 for (i = 0; i < u->out_nfrags; i++)
497 if (u->out_mmap_memblocks[i]) {
498 pa_memblock_unref_fixed(u->out_mmap_memblocks[i]);
499 u->out_mmap_memblocks[i] = NULL;
503 if (u->in_mmap_memblocks) {
504 unsigned i;
505 for (i = 0; i < u->in_nfrags; i++)
506 if (u->in_mmap_memblocks[i]) {
507 pa_memblock_unref_fixed(u->in_mmap_memblocks[i]);
508 u->in_mmap_memblocks[i] = NULL;
512 if (u->in_mmap && u->in_mmap != MAP_FAILED) {
513 munmap(u->in_mmap, u->in_hwbuf_size);
514 u->in_mmap = NULL;
517 if (u->out_mmap && u->out_mmap != MAP_FAILED) {
518 munmap(u->out_mmap, u->out_hwbuf_size);
519 u->out_mmap = NULL;
522 /* Let's suspend */
523 ioctl(u->fd, SNDCTL_DSP_SYNC, NULL);
524 pa_close(u->fd);
525 u->fd = -1;
527 if (u->rtpoll_item) {
528 pa_rtpoll_item_free(u->rtpoll_item);
529 u->rtpoll_item = NULL;
532 pa_log_info("Device suspended...");
534 return 0;
537 /* Called from IO context */
538 static int unsuspend(struct userdata *u) {
539 int m;
540 pa_sample_spec ss, *ss_original;
541 int frag_size, in_frag_size, out_frag_size;
542 int in_nfrags, out_nfrags;
543 struct audio_buf_info info;
545 pa_assert(u);
546 pa_assert(u->fd < 0);
548 m = u->mode;
550 pa_log_info("Trying resume...");
552 if ((u->fd = pa_oss_open(u->device_name, &m, NULL)) < 0) {
553 pa_log_warn("Resume failed, device busy (%s)", pa_cstrerror(errno));
554 return -1;
557 if (m != u->mode) {
558 pa_log_warn("Resume failed, couldn't open device with original access mode.");
559 goto fail;
562 if (u->nfrags >= 2 && u->frag_size >= 1)
563 if (pa_oss_set_fragments(u->fd, u->nfrags, u->orig_frag_size) < 0) {
564 pa_log_warn("Resume failed, couldn't set original fragment settings.");
565 goto fail;
568 ss = *(ss_original = u->sink ? &u->sink->sample_spec : &u->source->sample_spec);
569 if (pa_oss_auto_format(u->fd, &ss) < 0 || !pa_sample_spec_equal(&ss, ss_original)) {
570 pa_log_warn("Resume failed, couldn't set original sample format settings.");
571 goto fail;
574 if (ioctl(u->fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) {
575 pa_log_warn("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno));
576 goto fail;
579 in_frag_size = out_frag_size = frag_size;
580 in_nfrags = out_nfrags = u->nfrags;
582 if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) >= 0) {
583 in_frag_size = info.fragsize;
584 in_nfrags = info.fragstotal;
587 if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) {
588 out_frag_size = info.fragsize;
589 out_nfrags = info.fragstotal;
592 if ((u->source && (in_frag_size != (int) u->in_fragment_size || in_nfrags != (int) u->in_nfrags)) ||
593 (u->sink && (out_frag_size != (int) u->out_fragment_size || out_nfrags != (int) u->out_nfrags))) {
594 pa_log_warn("Resume failed, input fragment settings don't match.");
595 goto fail;
598 if (u->use_mmap) {
599 if (u->source) {
600 if ((u->in_mmap = mmap(NULL, u->in_hwbuf_size, PROT_READ, MAP_SHARED, u->fd, 0)) == MAP_FAILED) {
601 pa_log("Resume failed, mmap(): %s", pa_cstrerror(errno));
602 goto fail;
606 if (u->sink) {
607 if ((u->out_mmap = mmap(NULL, u->out_hwbuf_size, PROT_WRITE, MAP_SHARED, u->fd, 0)) == MAP_FAILED) {
608 pa_log("Resume failed, mmap(): %s", pa_cstrerror(errno));
609 if (u->in_mmap && u->in_mmap != MAP_FAILED) {
610 munmap(u->in_mmap, u->in_hwbuf_size);
611 u->in_mmap = NULL;
614 goto fail;
617 pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &ss);
621 u->out_mmap_current = u->in_mmap_current = 0;
622 u->out_mmap_saved_nfrags = u->in_mmap_saved_nfrags = 0;
624 pa_assert(!u->rtpoll_item);
626 build_pollfd(u);
628 if (u->sink && u->sink->get_volume)
629 u->sink->get_volume(u->sink);
630 if (u->source && u->source->get_volume)
631 u->source->get_volume(u->source);
633 pa_log_info("Resumed successfully...");
635 return 0;
637 fail:
638 pa_close(u->fd);
639 u->fd = -1;
640 return -1;
643 /* Called from IO context */
644 static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
645 struct userdata *u = PA_SINK(o)->userdata;
646 int ret;
647 pa_bool_t do_trigger = FALSE, quick = TRUE;
649 switch (code) {
651 case PA_SINK_MESSAGE_GET_LATENCY: {
652 pa_usec_t r = 0;
654 if (u->fd >= 0) {
655 if (u->use_mmap)
656 r = mmap_sink_get_latency(u);
657 else
658 r = io_sink_get_latency(u);
661 *((pa_usec_t*) data) = r;
663 return 0;
666 case PA_SINK_MESSAGE_SET_STATE:
668 switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) {
670 case PA_SINK_SUSPENDED:
671 pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state));
673 if (!u->source || u->source_suspended) {
674 if (suspend(u) < 0)
675 return -1;
678 do_trigger = TRUE;
680 u->sink_suspended = TRUE;
681 break;
683 case PA_SINK_IDLE:
684 case PA_SINK_RUNNING:
686 if (u->sink->thread_info.state == PA_SINK_INIT) {
687 do_trigger = TRUE;
688 quick = u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state);
691 if (u->sink->thread_info.state == PA_SINK_SUSPENDED) {
693 if (!u->source || u->source_suspended) {
694 if (unsuspend(u) < 0)
695 return -1;
696 quick = FALSE;
699 do_trigger = TRUE;
701 u->out_mmap_current = 0;
702 u->out_mmap_saved_nfrags = 0;
704 u->sink_suspended = FALSE;
707 break;
709 case PA_SINK_INVALID_STATE:
710 case PA_SINK_UNLINKED:
711 case PA_SINK_INIT:
715 break;
719 ret = pa_sink_process_msg(o, code, data, offset, chunk);
721 if (do_trigger)
722 trigger(u, quick);
724 return ret;
727 static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
728 struct userdata *u = PA_SOURCE(o)->userdata;
729 int ret;
730 int do_trigger = FALSE, quick = TRUE;
732 switch (code) {
734 case PA_SOURCE_MESSAGE_GET_LATENCY: {
735 pa_usec_t r = 0;
737 if (u->fd >= 0) {
738 if (u->use_mmap)
739 r = mmap_source_get_latency(u);
740 else
741 r = io_source_get_latency(u);
744 *((pa_usec_t*) data) = r;
745 return 0;
748 case PA_SOURCE_MESSAGE_SET_STATE:
750 switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) {
751 case PA_SOURCE_SUSPENDED:
752 pa_assert(PA_SOURCE_IS_OPENED(u->source->thread_info.state));
754 if (!u->sink || u->sink_suspended) {
755 if (suspend(u) < 0)
756 return -1;
759 do_trigger = TRUE;
761 u->source_suspended = TRUE;
762 break;
764 case PA_SOURCE_IDLE:
765 case PA_SOURCE_RUNNING:
767 if (u->source->thread_info.state == PA_SOURCE_INIT) {
768 do_trigger = TRUE;
769 quick = u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state);
772 if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) {
774 if (!u->sink || u->sink_suspended) {
775 if (unsuspend(u) < 0)
776 return -1;
777 quick = FALSE;
780 do_trigger = TRUE;
782 u->in_mmap_current = 0;
783 u->in_mmap_saved_nfrags = 0;
785 u->source_suspended = FALSE;
787 break;
789 case PA_SOURCE_UNLINKED:
790 case PA_SOURCE_INIT:
791 case PA_SOURCE_INVALID_STATE:
795 break;
799 ret = pa_source_process_msg(o, code, data, offset, chunk);
801 if (do_trigger)
802 trigger(u, quick);
804 return ret;
807 static void sink_get_volume(pa_sink *s) {
808 struct userdata *u;
810 pa_assert_se(u = s->userdata);
812 pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
814 if (u->mixer_devmask & SOUND_MASK_VOLUME)
815 if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_VOLUME, &s->sample_spec, &s->real_volume) >= 0)
816 return;
818 if (u->mixer_devmask & SOUND_MASK_PCM)
819 if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_PCM, &s->sample_spec, &s->real_volume) >= 0)
820 return;
822 pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
825 static void sink_set_volume(pa_sink *s) {
826 struct userdata *u;
828 pa_assert_se(u = s->userdata);
830 pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
832 if (u->mixer_devmask & SOUND_MASK_VOLUME)
833 if (pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->real_volume) >= 0)
834 return;
836 if (u->mixer_devmask & SOUND_MASK_PCM)
837 if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->real_volume) >= 0)
838 return;
840 pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
843 static void source_get_volume(pa_source *s) {
844 struct userdata *u;
846 pa_assert_se(u = s->userdata);
848 pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV));
850 if (u->mixer_devmask & SOUND_MASK_IGAIN)
851 if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_IGAIN, &s->sample_spec, &s->volume) >= 0)
852 return;
854 if (u->mixer_devmask & SOUND_MASK_RECLEV)
855 if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_RECLEV, &s->sample_spec, &s->volume) >= 0)
856 return;
858 pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
861 static void source_set_volume(pa_source *s) {
862 struct userdata *u;
864 pa_assert_se(u = s->userdata);
866 pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV));
868 if (u->mixer_devmask & SOUND_MASK_IGAIN)
869 if (pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_IGAIN, &s->sample_spec, &s->volume) >= 0)
870 return;
872 if (u->mixer_devmask & SOUND_MASK_RECLEV)
873 if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_RECLEV, &s->sample_spec, &s->volume) >= 0)
874 return;
876 pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
879 static void thread_func(void *userdata) {
880 struct userdata *u = userdata;
881 int write_type = 0, read_type = 0;
882 short revents = 0;
884 pa_assert(u);
886 pa_log_debug("Thread starting up");
888 if (u->core->realtime_scheduling)
889 pa_make_realtime(u->core->realtime_priority);
891 pa_thread_mq_install(&u->thread_mq);
893 for (;;) {
894 int ret;
896 /* pa_log("loop"); */
898 if (u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state))
899 if (u->sink->thread_info.rewind_requested)
900 pa_sink_process_rewind(u->sink, 0);
902 /* Render some data and write it to the dsp */
904 if (u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state) && ((revents & POLLOUT) || u->use_mmap || u->use_getospace)) {
906 if (u->use_mmap) {
908 if ((ret = mmap_write(u)) < 0)
909 goto fail;
911 revents &= ~POLLOUT;
913 if (ret > 0)
914 continue;
916 } else {
917 ssize_t l;
918 pa_bool_t loop = FALSE, work_done = FALSE;
920 l = (ssize_t) u->out_fragment_size;
922 if (u->use_getospace) {
923 audio_buf_info info;
925 if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
926 pa_log_info("Device doesn't support SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno));
927 u->use_getospace = FALSE;
928 } else {
929 l = info.bytes;
931 /* We loop only if GETOSPACE worked and we
932 * actually *know* that we can write more than
933 * one fragment at a time */
934 loop = TRUE;
938 /* Round down to multiples of the fragment size,
939 * because OSS needs that (at least some versions
940 * do) */
941 l = (l/(ssize_t) u->out_fragment_size) * (ssize_t) u->out_fragment_size;
943 /* Hmm, so poll() signalled us that we can read
944 * something, but GETOSPACE told us there was nothing?
945 * Hmm, make the best of it, try to read some data, to
946 * avoid spinning forever. */
947 if (l <= 0 && (revents & POLLOUT)) {
948 l = (ssize_t) u->out_fragment_size;
949 loop = FALSE;
952 while (l > 0) {
953 void *p;
954 ssize_t t;
956 if (u->memchunk.length <= 0)
957 pa_sink_render(u->sink, (size_t) l, &u->memchunk);
959 pa_assert(u->memchunk.length > 0);
961 p = pa_memblock_acquire(u->memchunk.memblock);
962 t = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, &write_type);
963 pa_memblock_release(u->memchunk.memblock);
965 /* pa_log("wrote %i bytes of %u", t, l); */
967 pa_assert(t != 0);
969 if (t < 0) {
971 if (errno == EINTR)
972 continue;
974 else if (errno == EAGAIN) {
975 pa_log_debug("EAGAIN");
977 revents &= ~POLLOUT;
978 break;
980 } else {
981 pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno));
982 goto fail;
985 } else {
987 u->memchunk.index += (size_t) t;
988 u->memchunk.length -= (size_t) t;
990 if (u->memchunk.length <= 0) {
991 pa_memblock_unref(u->memchunk.memblock);
992 pa_memchunk_reset(&u->memchunk);
995 l -= t;
997 revents &= ~POLLOUT;
998 work_done = TRUE;
1001 if (!loop)
1002 break;
1005 if (work_done)
1006 continue;
1010 /* Try to read some data and pass it on to the source driver. */
1012 if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state) && ((revents & POLLIN) || u->use_mmap || u->use_getispace)) {
1014 if (u->use_mmap) {
1016 if ((ret = mmap_read(u)) < 0)
1017 goto fail;
1019 revents &= ~POLLIN;
1021 if (ret > 0)
1022 continue;
1024 } else {
1026 void *p;
1027 ssize_t l;
1028 pa_memchunk memchunk;
1029 pa_bool_t loop = FALSE, work_done = FALSE;
1031 l = (ssize_t) u->in_fragment_size;
1033 if (u->use_getispace) {
1034 audio_buf_info info;
1036 if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
1037 pa_log_info("Device doesn't support SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno));
1038 u->use_getispace = FALSE;
1039 } else {
1040 l = info.bytes;
1041 loop = TRUE;
1045 l = (l/(ssize_t) u->in_fragment_size) * (ssize_t) u->in_fragment_size;
1047 if (l <= 0 && (revents & POLLIN)) {
1048 l = (ssize_t) u->in_fragment_size;
1049 loop = FALSE;
1052 while (l > 0) {
1053 ssize_t t;
1054 size_t k;
1056 pa_assert(l > 0);
1058 memchunk.memblock = pa_memblock_new(u->core->mempool, (size_t) -1);
1060 k = pa_memblock_get_length(memchunk.memblock);
1062 if (k > (size_t) l)
1063 k = (size_t) l;
1065 k = (k/u->frame_size)*u->frame_size;
1067 p = pa_memblock_acquire(memchunk.memblock);
1068 t = pa_read(u->fd, p, k, &read_type);
1069 pa_memblock_release(memchunk.memblock);
1071 pa_assert(t != 0); /* EOF cannot happen */
1073 /* pa_log("read %i bytes of %u", t, l); */
1075 if (t < 0) {
1076 pa_memblock_unref(memchunk.memblock);
1078 if (errno == EINTR)
1079 continue;
1081 else if (errno == EAGAIN) {
1082 pa_log_debug("EAGAIN");
1084 revents &= ~POLLIN;
1085 break;
1087 } else {
1088 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno));
1089 goto fail;
1092 } else {
1093 memchunk.index = 0;
1094 memchunk.length = (size_t) t;
1096 pa_source_post(u->source, &memchunk);
1097 pa_memblock_unref(memchunk.memblock);
1099 l -= t;
1101 revents &= ~POLLIN;
1102 work_done = TRUE;
1105 if (!loop)
1106 break;
1109 if (work_done)
1110 continue;
1114 /* pa_log("loop2 revents=%i", revents); */
1116 if (u->rtpoll_item) {
1117 struct pollfd *pollfd;
1119 pa_assert(u->fd >= 0);
1121 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
1122 pollfd->events = (short)
1123 (((u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state)) ? POLLIN : 0) |
1124 ((u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state)) ? POLLOUT : 0));
1127 /* Hmm, nothing to do. Let's sleep */
1128 if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
1129 goto fail;
1131 if (ret == 0)
1132 goto finish;
1134 if (u->rtpoll_item) {
1135 struct pollfd *pollfd;
1137 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
1139 if (pollfd->revents & ~(POLLOUT|POLLIN)) {
1140 pa_log("DSP shutdown.");
1141 goto fail;
1144 revents = pollfd->revents;
1145 } else
1146 revents = 0;
1149 fail:
1150 /* If this was no regular exit from the loop we have to continue
1151 * processing messages until we received PA_MESSAGE_SHUTDOWN */
1152 pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
1153 pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
1155 finish:
1156 pa_log_debug("Thread shutting down");
1159 int pa__init(pa_module*m) {
1161 struct audio_buf_info info;
1162 struct userdata *u = NULL;
1163 const char *dev;
1164 int fd = -1;
1165 int nfrags, orig_frag_size, frag_size;
1166 int mode, caps;
1167 pa_bool_t record = TRUE, playback = TRUE, use_mmap = TRUE;
1168 pa_sample_spec ss;
1169 pa_channel_map map;
1170 pa_modargs *ma = NULL;
1171 char hwdesc[64];
1172 const char *name;
1173 pa_bool_t namereg_fail;
1174 pa_sink_new_data sink_new_data;
1175 pa_source_new_data source_new_data;
1177 pa_assert(m);
1179 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1180 pa_log("Failed to parse module arguments.");
1181 goto fail;
1184 if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
1185 pa_log("record= and playback= expect boolean argument.");
1186 goto fail;
1189 if (!playback && !record) {
1190 pa_log("Neither playback nor record enabled for device.");
1191 goto fail;
1194 mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
1196 ss = m->core->default_sample_spec;
1197 map = m->core->default_channel_map;
1198 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_OSS) < 0) {
1199 pa_log("Failed to parse sample specification or channel map");
1200 goto fail;
1203 nfrags = (int) m->core->default_n_fragments;
1204 frag_size = (int) pa_usec_to_bytes(m->core->default_fragment_size_msec*1000, &ss);
1205 if (frag_size <= 0)
1206 frag_size = (int) pa_frame_size(&ss);
1208 if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) {
1209 pa_log("Failed to parse fragments arguments");
1210 goto fail;
1213 if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) {
1214 pa_log("Failed to parse mmap argument.");
1215 goto fail;
1218 if ((fd = pa_oss_open(dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0)
1219 goto fail;
1221 if (use_mmap && (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_TRIGGER))) {
1222 pa_log_info("OSS device not mmap capable, falling back to UNIX read/write mode.");
1223 use_mmap = FALSE;
1226 if (use_mmap && mode == O_WRONLY) {
1227 pa_log_info("Device opened for playback only, cannot do memory mapping, falling back to UNIX write() mode.");
1228 use_mmap = FALSE;
1231 if (pa_oss_get_hw_description(dev, hwdesc, sizeof(hwdesc)) >= 0)
1232 pa_log_info("Hardware name is '%s'.", hwdesc);
1233 else
1234 hwdesc[0] = 0;
1236 pa_log_info("Device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));
1238 orig_frag_size = frag_size;
1239 if (nfrags >= 2 && frag_size >= 1)
1240 if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0)
1241 goto fail;
1243 if (pa_oss_auto_format(fd, &ss) < 0)
1244 goto fail;
1246 if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) {
1247 pa_log("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno));
1248 goto fail;
1250 pa_assert(frag_size > 0);
1252 u = pa_xnew0(struct userdata, 1);
1253 u->core = m->core;
1254 u->module = m;
1255 m->userdata = u;
1256 u->fd = fd;
1257 u->mixer_fd = -1;
1258 u->mixer_devmask = 0;
1259 u->use_getospace = u->use_getispace = TRUE;
1260 u->use_getodelay = TRUE;
1261 u->mode = mode;
1262 u->frame_size = pa_frame_size(&ss);
1263 u->device_name = pa_xstrdup(dev);
1264 u->in_nfrags = u->out_nfrags = (uint32_t) (u->nfrags = nfrags);
1265 u->out_fragment_size = u->in_fragment_size = (uint32_t) (u->frag_size = frag_size);
1266 u->orig_frag_size = orig_frag_size;
1267 u->use_mmap = use_mmap;
1268 u->rtpoll = pa_rtpoll_new();
1269 pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
1270 u->rtpoll_item = NULL;
1271 build_pollfd(u);
1273 if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) {
1274 pa_log_info("Input -- %u fragments of size %u.", info.fragstotal, info.fragsize);
1275 u->in_fragment_size = (uint32_t) info.fragsize;
1276 u->in_nfrags = (uint32_t) info.fragstotal;
1277 u->use_getispace = TRUE;
1280 if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) {
1281 pa_log_info("Output -- %u fragments of size %u.", info.fragstotal, info.fragsize);
1282 u->out_fragment_size = (uint32_t) info.fragsize;
1283 u->out_nfrags = (uint32_t) info.fragstotal;
1284 u->use_getospace = TRUE;
1287 u->in_hwbuf_size = u->in_nfrags * u->in_fragment_size;
1288 u->out_hwbuf_size = u->out_nfrags * u->out_fragment_size;
1290 if (mode != O_WRONLY) {
1291 char *name_buf = NULL;
1293 if (use_mmap) {
1294 if ((u->in_mmap = mmap(NULL, u->in_hwbuf_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
1295 pa_log_warn("mmap(PROT_READ) failed, reverting to non-mmap mode: %s", pa_cstrerror(errno));
1296 use_mmap = u->use_mmap = FALSE;
1297 u->in_mmap = NULL;
1298 } else
1299 pa_log_debug("Successfully mmap()ed input buffer.");
1302 if ((name = pa_modargs_get_value(ma, "source_name", NULL)))
1303 namereg_fail = TRUE;
1304 else {
1305 name = name_buf = pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(dev));
1306 namereg_fail = FALSE;
1309 pa_source_new_data_init(&source_new_data);
1310 source_new_data.driver = __FILE__;
1311 source_new_data.module = m;
1312 pa_source_new_data_set_name(&source_new_data, name);
1313 source_new_data.namereg_fail = namereg_fail;
1314 pa_source_new_data_set_sample_spec(&source_new_data, &ss);
1315 pa_source_new_data_set_channel_map(&source_new_data, &map);
1316 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_STRING, dev);
1317 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_API, "oss");
1318 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, hwdesc[0] ? hwdesc : dev);
1319 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, use_mmap ? "mmap" : "serial");
1320 pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (u->in_hwbuf_size));
1321 pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (u->in_fragment_size));
1323 if (pa_modargs_get_proplist(ma, "source_properties", source_new_data.proplist, PA_UPDATE_REPLACE) < 0) {
1324 pa_log("Invalid properties");
1325 pa_source_new_data_done(&source_new_data);
1326 goto fail;
1329 u->source = pa_source_new(m->core, &source_new_data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY);
1330 pa_source_new_data_done(&source_new_data);
1331 pa_xfree(name_buf);
1333 if (!u->source) {
1334 pa_log("Failed to create source object");
1335 goto fail;
1338 u->source->parent.process_msg = source_process_msg;
1339 u->source->userdata = u;
1341 pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
1342 pa_source_set_rtpoll(u->source, u->rtpoll);
1343 pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(u->in_hwbuf_size, &u->source->sample_spec));
1344 u->source->refresh_volume = TRUE;
1346 if (use_mmap)
1347 u->in_mmap_memblocks = pa_xnew0(pa_memblock*, u->in_nfrags);
1350 if (mode != O_RDONLY) {
1351 char *name_buf = NULL;
1353 if (use_mmap) {
1354 if ((u->out_mmap = mmap(NULL, u->out_hwbuf_size, PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
1355 if (mode == O_RDWR) {
1356 pa_log_debug("mmap() failed for input. Changing to O_WRONLY mode.");
1357 mode = O_WRONLY;
1358 goto go_on;
1359 } else {
1360 pa_log_warn("mmap(PROT_WRITE) failed, reverting to non-mmap mode: %s", pa_cstrerror(errno));
1361 u->use_mmap = use_mmap = FALSE;
1362 u->out_mmap = NULL;
1364 } else {
1365 pa_log_debug("Successfully mmap()ed output buffer.");
1366 pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &ss);
1370 if ((name = pa_modargs_get_value(ma, "sink_name", NULL)))
1371 namereg_fail = TRUE;
1372 else {
1373 name = name_buf = pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(dev));
1374 namereg_fail = FALSE;
1377 pa_sink_new_data_init(&sink_new_data);
1378 sink_new_data.driver = __FILE__;
1379 sink_new_data.module = m;
1380 pa_sink_new_data_set_name(&sink_new_data, name);
1381 sink_new_data.namereg_fail = namereg_fail;
1382 pa_sink_new_data_set_sample_spec(&sink_new_data, &ss);
1383 pa_sink_new_data_set_channel_map(&sink_new_data, &map);
1384 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_STRING, dev);
1385 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_API, "oss");
1386 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, hwdesc[0] ? hwdesc : dev);
1387 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, use_mmap ? "mmap" : "serial");
1388 pa_proplist_setf(sink_new_data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (u->out_hwbuf_size));
1389 pa_proplist_setf(sink_new_data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (u->out_fragment_size));
1391 if (pa_modargs_get_proplist(ma, "sink_properties", sink_new_data.proplist, PA_UPDATE_REPLACE) < 0) {
1392 pa_log("Invalid properties");
1393 pa_sink_new_data_done(&sink_new_data);
1394 goto fail;
1397 u->sink = pa_sink_new(m->core, &sink_new_data, PA_SINK_HARDWARE|PA_SINK_LATENCY);
1398 pa_sink_new_data_done(&sink_new_data);
1399 pa_xfree(name_buf);
1401 if (!u->sink) {
1402 pa_log("Failed to create sink object");
1403 goto fail;
1406 u->sink->parent.process_msg = sink_process_msg;
1407 u->sink->userdata = u;
1409 pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
1410 pa_sink_set_rtpoll(u->sink, u->rtpoll);
1411 pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(u->out_hwbuf_size, &u->sink->sample_spec));
1412 u->sink->refresh_volume = TRUE;
1414 pa_sink_set_max_request(u->sink, u->out_hwbuf_size);
1416 if (use_mmap)
1417 u->out_mmap_memblocks = pa_xnew0(pa_memblock*, u->out_nfrags);
1420 if ((u->mixer_fd = pa_oss_open_mixer_for_device(u->device_name)) >= 0) {
1421 pa_bool_t do_close = TRUE;
1423 if (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &u->mixer_devmask) < 0)
1424 pa_log_warn("SOUND_MIXER_READ_DEVMASK failed: %s", pa_cstrerror(errno));
1426 else {
1427 if (u->sink && (u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM))) {
1428 pa_log_debug("Found hardware mixer track for playback.");
1429 u->sink->flags |= PA_SINK_HW_VOLUME_CTRL;
1430 u->sink->get_volume = sink_get_volume;
1431 u->sink->set_volume = sink_set_volume;
1432 u->sink->n_volume_steps = 101;
1433 do_close = FALSE;
1436 if (u->source && (u->mixer_devmask & (SOUND_MASK_RECLEV|SOUND_MASK_IGAIN))) {
1437 pa_log_debug("Found hardware mixer track for recording.");
1438 u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL;
1439 u->source->get_volume = source_get_volume;
1440 u->source->set_volume = source_set_volume;
1441 u->source->n_volume_steps = 101;
1442 do_close = FALSE;
1446 if (do_close) {
1447 pa_close(u->mixer_fd);
1448 u->mixer_fd = -1;
1449 u->mixer_devmask = 0;
1453 go_on:
1455 pa_assert(u->source || u->sink);
1457 pa_memchunk_reset(&u->memchunk);
1459 if (!(u->thread = pa_thread_new("oss", thread_func, u))) {
1460 pa_log("Failed to create thread.");
1461 goto fail;
1464 /* Read mixer settings */
1465 if (u->sink) {
1466 if (sink_new_data.volume_is_set) {
1467 if (u->sink->set_volume)
1468 u->sink->set_volume(u->sink);
1469 } else {
1470 if (u->sink->get_volume)
1471 u->sink->get_volume(u->sink);
1475 if (u->source) {
1476 if (source_new_data.volume_is_set) {
1477 if (u->source->set_volume)
1478 u->source->set_volume(u->source);
1479 } else {
1480 if (u->source->get_volume)
1481 u->source->get_volume(u->source);
1485 if (u->sink)
1486 pa_sink_put(u->sink);
1487 if (u->source)
1488 pa_source_put(u->source);
1490 pa_modargs_free(ma);
1492 return 0;
1494 fail:
1496 if (u)
1497 pa__done(m);
1498 else if (fd >= 0)
1499 pa_close(fd);
1501 if (ma)
1502 pa_modargs_free(ma);
1504 return -1;
1507 void pa__done(pa_module*m) {
1508 struct userdata *u;
1510 pa_assert(m);
1512 if (!(u = m->userdata))
1513 return;
1515 if (u->sink)
1516 pa_sink_unlink(u->sink);
1518 if (u->source)
1519 pa_source_unlink(u->source);
1521 if (u->thread) {
1522 pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
1523 pa_thread_free(u->thread);
1526 pa_thread_mq_done(&u->thread_mq);
1528 if (u->sink)
1529 pa_sink_unref(u->sink);
1531 if (u->source)
1532 pa_source_unref(u->source);
1534 if (u->memchunk.memblock)
1535 pa_memblock_unref(u->memchunk.memblock);
1537 if (u->rtpoll_item)
1538 pa_rtpoll_item_free(u->rtpoll_item);
1540 if (u->rtpoll)
1541 pa_rtpoll_free(u->rtpoll);
1543 if (u->out_mmap_memblocks) {
1544 unsigned i;
1545 for (i = 0; i < u->out_nfrags; i++)
1546 if (u->out_mmap_memblocks[i])
1547 pa_memblock_unref_fixed(u->out_mmap_memblocks[i]);
1548 pa_xfree(u->out_mmap_memblocks);
1551 if (u->in_mmap_memblocks) {
1552 unsigned i;
1553 for (i = 0; i < u->in_nfrags; i++)
1554 if (u->in_mmap_memblocks[i])
1555 pa_memblock_unref_fixed(u->in_mmap_memblocks[i]);
1556 pa_xfree(u->in_mmap_memblocks);
1559 if (u->in_mmap && u->in_mmap != MAP_FAILED)
1560 munmap(u->in_mmap, u->in_hwbuf_size);
1562 if (u->out_mmap && u->out_mmap != MAP_FAILED)
1563 munmap(u->out_mmap, u->out_hwbuf_size);
1565 if (u->fd >= 0)
1566 pa_close(u->fd);
1568 if (u->mixer_fd >= 0)
1569 pa_close(u->mixer_fd);
1571 pa_xfree(u->device_name);
1573 pa_xfree(u);