]> code.delx.au - pulseaudio/blob - src/modules/oss/module-oss.c
sink: volume handling rework, new flat volume logic
[pulseaudio] / src / modules / oss / module-oss.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 /* General power management rules:
24 *
25 * When SUSPENDED we close the audio device.
26 *
27 * We make no difference between IDLE and RUNNING in our handling.
28 *
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.
32 *
33 * If power should be saved on IDLE module-suspend-on-idle should be used.
34 *
35 */
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #ifdef HAVE_SYS_MMAN_H
42 #include <sys/mman.h>
43 #endif
44
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>
56 #include <poll.h>
57
58 #include <pulse/xmalloc.h>
59 #include <pulse/util.h>
60
61 #include <pulsecore/core-error.h>
62 #include <pulsecore/thread.h>
63 #include <pulsecore/sink.h>
64 #include <pulsecore/source.h>
65 #include <pulsecore/module.h>
66 #include <pulsecore/sample-util.h>
67 #include <pulsecore/core-util.h>
68 #include <pulsecore/modargs.h>
69 #include <pulsecore/log.h>
70 #include <pulsecore/macro.h>
71 #include <pulsecore/thread-mq.h>
72 #include <pulsecore/rtpoll.h>
73
74 #if defined(__NetBSD__) && !defined(SNDCTL_DSP_GETODELAY)
75 #include <sys/audioio.h>
76 #include <sys/syscall.h>
77 #endif
78
79 #include "oss-util.h"
80 #include "module-oss-symdef.h"
81
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
104
105 #define DEFAULT_DEVICE "/dev/dsp"
106
107 struct userdata {
108 pa_core *core;
109 pa_module *module;
110 pa_sink *sink;
111 pa_source *source;
112
113 pa_thread *thread;
114 pa_thread_mq thread_mq;
115 pa_rtpoll *rtpoll;
116
117 char *device_name;
118
119 pa_memchunk memchunk;
120
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;
125
126 pa_bool_t sink_suspended, source_suspended;
127
128 int fd;
129 int mode;
130
131 int mixer_fd;
132 int mixer_devmask;
133
134 int nfrags, frag_size, orig_frag_size;
135
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;
140
141 int in_mmap_saved_nfrags, out_mmap_saved_nfrags;
142
143 pa_rtpoll_item *rtpoll_item;
144 };
145
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
162 };
163
164 static void trigger(struct userdata *u, pa_bool_t quick) {
165 int enable_bits = 0, zero = 0;
166
167 pa_assert(u);
168
169 if (u->fd < 0)
170 return;
171
172 pa_log_debug("trigger");
173
174 if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state))
175 enable_bits |= PCM_ENABLE_INPUT;
176
177 if (u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state))
178 enable_bits |= PCM_ENABLE_OUTPUT;
179
180 pa_log_debug("trigger: %i", enable_bits);
181
182
183 if (u->use_mmap) {
184
185 if (!quick)
186 ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero);
187
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
193
194 if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0)
195 pa_log_warn("SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno));
196
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);
200 }
201
202 } else {
203
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));
207
208 if (!quick) {
209 /*
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.
213 */
214
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);
219 }
220 }
221 }
222 }
223
224 static void mmap_fill_memblocks(struct userdata *u, unsigned n) {
225 pa_assert(u);
226 pa_assert(u->out_mmap_memblocks);
227
228 /* pa_log("Mmmap writing %u blocks", n); */
229
230 while (n > 0) {
231 pa_memchunk chunk;
232
233 if (u->out_mmap_memblocks[u->out_mmap_current])
234 pa_memblock_unref_fixed(u->out_mmap_memblocks[u->out_mmap_current]);
235
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,
241 1);
242
243 chunk.length = pa_memblock_get_length(chunk.memblock);
244 chunk.index = 0;
245
246 pa_sink_render_into_full(u->sink, &chunk);
247
248 u->out_mmap_current++;
249 while (u->out_mmap_current >= u->out_nfrags)
250 u->out_mmap_current -= u->out_nfrags;
251
252 n--;
253 }
254 }
255
256 static int mmap_write(struct userdata *u) {
257 struct count_info info;
258
259 pa_assert(u);
260 pa_assert(u->sink);
261
262 /* pa_log("Mmmap writing..."); */
263
264 if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
265 pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno));
266 return -1;
267 }
268
269 info.blocks += u->out_mmap_saved_nfrags;
270 u->out_mmap_saved_nfrags = 0;
271
272 if (info.blocks > 0)
273 mmap_fill_memblocks(u, (unsigned) info.blocks);
274
275 return info.blocks;
276 }
277
278 static void mmap_post_memblocks(struct userdata *u, unsigned n) {
279 pa_assert(u);
280 pa_assert(u->in_mmap_memblocks);
281
282 /* pa_log("Mmmap reading %u blocks", n); */
283
284 while (n > 0) {
285 pa_memchunk chunk;
286
287 if (!u->in_mmap_memblocks[u->in_mmap_current]) {
288
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,
294 1);
295
296 chunk.length = pa_memblock_get_length(chunk.memblock);
297 chunk.index = 0;
298
299 pa_source_post(u->source, &chunk);
300 }
301
302 u->in_mmap_current++;
303 while (u->in_mmap_current >= u->in_nfrags)
304 u->in_mmap_current -= u->in_nfrags;
305
306 n--;
307 }
308 }
309
310 static void mmap_clear_memblocks(struct userdata*u, unsigned n) {
311 unsigned i = u->in_mmap_current;
312
313 pa_assert(u);
314 pa_assert(u->in_mmap_memblocks);
315
316 if (n > u->in_nfrags)
317 n = u->in_nfrags;
318
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;
323 }
324
325 i++;
326 while (i >= u->in_nfrags)
327 i -= u->in_nfrags;
328
329 n--;
330 }
331 }
332
333 static int mmap_read(struct userdata *u) {
334 struct count_info info;
335 pa_assert(u);
336 pa_assert(u->source);
337
338 /* pa_log("Mmmap reading..."); */
339
340 if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
341 pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno));
342 return -1;
343 }
344
345 /* pa_log("... %i", info.blocks); */
346
347 info.blocks += u->in_mmap_saved_nfrags;
348 u->in_mmap_saved_nfrags = 0;
349
350 if (info.blocks > 0) {
351 mmap_post_memblocks(u, (unsigned) info.blocks);
352 mmap_clear_memblocks(u, u->in_nfrags/2);
353 }
354
355 return info.blocks;
356 }
357
358 static pa_usec_t mmap_sink_get_latency(struct userdata *u) {
359 struct count_info info;
360 size_t bpos, n;
361
362 pa_assert(u);
363
364 if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
365 pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno));
366 return 0;
367 }
368
369 u->out_mmap_saved_nfrags += info.blocks;
370
371 bpos = ((u->out_mmap_current + (unsigned) u->out_mmap_saved_nfrags) * u->out_fragment_size) % u->out_hwbuf_size;
372
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;
377
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); */
379
380 return pa_bytes_to_usec(n, &u->sink->sample_spec);
381 }
382
383 static pa_usec_t mmap_source_get_latency(struct userdata *u) {
384 struct count_info info;
385 size_t bpos, n;
386
387 pa_assert(u);
388
389 if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
390 pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno));
391 return 0;
392 }
393
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;
396
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;
401
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); */
403
404 return pa_bytes_to_usec(n, &u->source->sample_spec);
405 }
406
407 static pa_usec_t io_sink_get_latency(struct userdata *u) {
408 pa_usec_t r = 0;
409
410 pa_assert(u);
411
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);
423 }
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
435 }
436
437 if (!u->use_getodelay && u->use_getospace) {
438 struct audio_buf_info info;
439
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);
445 }
446
447 if (u->memchunk.memblock)
448 r += pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec);
449
450 return r;
451 }
452
453 static pa_usec_t io_source_get_latency(struct userdata *u) {
454 pa_usec_t r = 0;
455
456 pa_assert(u);
457
458 if (u->use_getispace) {
459 struct audio_buf_info info;
460
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);
466 }
467
468 return r;
469 }
470
471 static void build_pollfd(struct userdata *u) {
472 struct pollfd *pollfd;
473
474 pa_assert(u);
475 pa_assert(u->fd >= 0);
476
477 if (u->rtpoll_item)
478 pa_rtpoll_item_free(u->rtpoll_item);
479
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;
485 }
486
487 /* Called from IO context */
488 static int suspend(struct userdata *u) {
489 pa_assert(u);
490 pa_assert(u->fd >= 0);
491
492 pa_log_info("Suspending...");
493
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;
500 }
501 }
502
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;
509 }
510 }
511
512 if (u->in_mmap && u->in_mmap != MAP_FAILED) {
513 munmap(u->in_mmap, u->in_hwbuf_size);
514 u->in_mmap = NULL;
515 }
516
517 if (u->out_mmap && u->out_mmap != MAP_FAILED) {
518 munmap(u->out_mmap, u->out_hwbuf_size);
519 u->out_mmap = NULL;
520 }
521
522 /* Let's suspend */
523 ioctl(u->fd, SNDCTL_DSP_SYNC, NULL);
524 pa_close(u->fd);
525 u->fd = -1;
526
527 if (u->rtpoll_item) {
528 pa_rtpoll_item_free(u->rtpoll_item);
529 u->rtpoll_item = NULL;
530 }
531
532 pa_log_info("Device suspended...");
533
534 return 0;
535 }
536
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;
544
545 pa_assert(u);
546 pa_assert(u->fd < 0);
547
548 m = u->mode;
549
550 pa_log_info("Trying resume...");
551
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;
555 }
556
557 if (m != u->mode) {
558 pa_log_warn("Resume failed, couldn't open device with original access mode.");
559 goto fail;
560 }
561
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;
566 }
567
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;
572 }
573
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;
577 }
578
579 in_frag_size = out_frag_size = frag_size;
580 in_nfrags = out_nfrags = u->nfrags;
581
582 if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) >= 0) {
583 in_frag_size = info.fragsize;
584 in_nfrags = info.fragstotal;
585 }
586
587 if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) {
588 out_frag_size = info.fragsize;
589 out_nfrags = info.fragstotal;
590 }
591
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;
596 }
597
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;
603 }
604 }
605
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;
612 }
613
614 goto fail;
615 }
616
617 pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &ss);
618 }
619 }
620
621 u->out_mmap_current = u->in_mmap_current = 0;
622 u->out_mmap_saved_nfrags = u->in_mmap_saved_nfrags = 0;
623
624 pa_assert(!u->rtpoll_item);
625
626 build_pollfd(u);
627
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);
632
633 pa_log_info("Resumed successfully...");
634
635 return 0;
636
637 fail:
638 pa_close(u->fd);
639 u->fd = -1;
640 return -1;
641 }
642
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;
648
649 switch (code) {
650
651 case PA_SINK_MESSAGE_GET_LATENCY: {
652 pa_usec_t r = 0;
653
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);
659 }
660
661 *((pa_usec_t*) data) = r;
662
663 return 0;
664 }
665
666 case PA_SINK_MESSAGE_SET_STATE:
667
668 switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) {
669
670 case PA_SINK_SUSPENDED:
671 pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state));
672
673 if (!u->source || u->source_suspended) {
674 if (suspend(u) < 0)
675 return -1;
676 }
677
678 do_trigger = TRUE;
679
680 u->sink_suspended = TRUE;
681 break;
682
683 case PA_SINK_IDLE:
684 case PA_SINK_RUNNING:
685
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);
689 }
690
691 if (u->sink->thread_info.state == PA_SINK_SUSPENDED) {
692
693 if (!u->source || u->source_suspended) {
694 if (unsuspend(u) < 0)
695 return -1;
696 quick = FALSE;
697 }
698
699 do_trigger = TRUE;
700
701 u->out_mmap_current = 0;
702 u->out_mmap_saved_nfrags = 0;
703
704 u->sink_suspended = FALSE;
705 }
706
707 break;
708
709 case PA_SINK_INVALID_STATE:
710 case PA_SINK_UNLINKED:
711 case PA_SINK_INIT:
712 ;
713 }
714
715 break;
716
717 }
718
719 ret = pa_sink_process_msg(o, code, data, offset, chunk);
720
721 if (do_trigger)
722 trigger(u, quick);
723
724 return ret;
725 }
726
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;
731
732 switch (code) {
733
734 case PA_SOURCE_MESSAGE_GET_LATENCY: {
735 pa_usec_t r = 0;
736
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);
742 }
743
744 *((pa_usec_t*) data) = r;
745 return 0;
746 }
747
748 case PA_SOURCE_MESSAGE_SET_STATE:
749
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));
753
754 if (!u->sink || u->sink_suspended) {
755 if (suspend(u) < 0)
756 return -1;
757 }
758
759 do_trigger = TRUE;
760
761 u->source_suspended = TRUE;
762 break;
763
764 case PA_SOURCE_IDLE:
765 case PA_SOURCE_RUNNING:
766
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);
770 }
771
772 if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) {
773
774 if (!u->sink || u->sink_suspended) {
775 if (unsuspend(u) < 0)
776 return -1;
777 quick = FALSE;
778 }
779
780 do_trigger = TRUE;
781
782 u->in_mmap_current = 0;
783 u->in_mmap_saved_nfrags = 0;
784
785 u->source_suspended = FALSE;
786 }
787 break;
788
789 case PA_SOURCE_UNLINKED:
790 case PA_SOURCE_INIT:
791 case PA_SOURCE_INVALID_STATE:
792 ;
793
794 }
795 break;
796
797 }
798
799 ret = pa_source_process_msg(o, code, data, offset, chunk);
800
801 if (do_trigger)
802 trigger(u, quick);
803
804 return ret;
805 }
806
807 static void sink_get_volume(pa_sink *s) {
808 struct userdata *u;
809
810 pa_assert_se(u = s->userdata);
811
812 pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
813
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;
817
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;
821
822 pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
823 }
824
825 static void sink_set_volume(pa_sink *s) {
826 struct userdata *u;
827
828 pa_assert_se(u = s->userdata);
829
830 pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
831
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;
835
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;
839
840 pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
841 }
842
843 static void source_get_volume(pa_source *s) {
844 struct userdata *u;
845
846 pa_assert_se(u = s->userdata);
847
848 pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV));
849
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;
853
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;
857
858 pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
859 }
860
861 static void source_set_volume(pa_source *s) {
862 struct userdata *u;
863
864 pa_assert_se(u = s->userdata);
865
866 pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV));
867
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;
871
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;
875
876 pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
877 }
878
879 static void thread_func(void *userdata) {
880 struct userdata *u = userdata;
881 int write_type = 0, read_type = 0;
882 short revents = 0;
883
884 pa_assert(u);
885
886 pa_log_debug("Thread starting up");
887
888 if (u->core->realtime_scheduling)
889 pa_make_realtime(u->core->realtime_priority);
890
891 pa_thread_mq_install(&u->thread_mq);
892
893 for (;;) {
894 int ret;
895
896 /* pa_log("loop"); */
897
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);
901
902 /* Render some data and write it to the dsp */
903
904 if (u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state) && ((revents & POLLOUT) || u->use_mmap || u->use_getospace)) {
905
906 if (u->use_mmap) {
907
908 if ((ret = mmap_write(u)) < 0)
909 goto fail;
910
911 revents &= ~POLLOUT;
912
913 if (ret > 0)
914 continue;
915
916 } else {
917 ssize_t l;
918 pa_bool_t loop = FALSE, work_done = FALSE;
919
920 l = (ssize_t) u->out_fragment_size;
921
922 if (u->use_getospace) {
923 audio_buf_info info;
924
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;
930
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;
935 }
936 }
937
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;
942
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;
950 }
951
952 while (l > 0) {
953 void *p;
954 ssize_t t;
955
956 if (u->memchunk.length <= 0)
957 pa_sink_render(u->sink, (size_t) l, &u->memchunk);
958
959 pa_assert(u->memchunk.length > 0);
960
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);
964
965 /* pa_log("wrote %i bytes of %u", t, l); */
966
967 pa_assert(t != 0);
968
969 if (t < 0) {
970
971 if (errno == EINTR)
972 continue;
973
974 else if (errno == EAGAIN) {
975 pa_log_debug("EAGAIN");
976
977 revents &= ~POLLOUT;
978 break;
979
980 } else {
981 pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno));
982 goto fail;
983 }
984
985 } else {
986
987 u->memchunk.index += (size_t) t;
988 u->memchunk.length -= (size_t) t;
989
990 if (u->memchunk.length <= 0) {
991 pa_memblock_unref(u->memchunk.memblock);
992 pa_memchunk_reset(&u->memchunk);
993 }
994
995 l -= t;
996
997 revents &= ~POLLOUT;
998 work_done = TRUE;
999 }
1000
1001 if (!loop)
1002 break;
1003 }
1004
1005 if (work_done)
1006 continue;
1007 }
1008 }
1009
1010 /* Try to read some data and pass it on to the source driver. */
1011
1012 if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state) && ((revents & POLLIN) || u->use_mmap || u->use_getispace)) {
1013
1014 if (u->use_mmap) {
1015
1016 if ((ret = mmap_read(u)) < 0)
1017 goto fail;
1018
1019 revents &= ~POLLIN;
1020
1021 if (ret > 0)
1022 continue;
1023
1024 } else {
1025
1026 void *p;
1027 ssize_t l;
1028 pa_memchunk memchunk;
1029 pa_bool_t loop = FALSE, work_done = FALSE;
1030
1031 l = (ssize_t) u->in_fragment_size;
1032
1033 if (u->use_getispace) {
1034 audio_buf_info info;
1035
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;
1042 }
1043 }
1044
1045 l = (l/(ssize_t) u->in_fragment_size) * (ssize_t) u->in_fragment_size;
1046
1047 if (l <= 0 && (revents & POLLIN)) {
1048 l = (ssize_t) u->in_fragment_size;
1049 loop = FALSE;
1050 }
1051
1052 while (l > 0) {
1053 ssize_t t;
1054 size_t k;
1055
1056 pa_assert(l > 0);
1057
1058 memchunk.memblock = pa_memblock_new(u->core->mempool, (size_t) -1);
1059
1060 k = pa_memblock_get_length(memchunk.memblock);
1061
1062 if (k > (size_t) l)
1063 k = (size_t) l;
1064
1065 k = (k/u->frame_size)*u->frame_size;
1066
1067 p = pa_memblock_acquire(memchunk.memblock);
1068 t = pa_read(u->fd, p, k, &read_type);
1069 pa_memblock_release(memchunk.memblock);
1070
1071 pa_assert(t != 0); /* EOF cannot happen */
1072
1073 /* pa_log("read %i bytes of %u", t, l); */
1074
1075 if (t < 0) {
1076 pa_memblock_unref(memchunk.memblock);
1077
1078 if (errno == EINTR)
1079 continue;
1080
1081 else if (errno == EAGAIN) {
1082 pa_log_debug("EAGAIN");
1083
1084 revents &= ~POLLIN;
1085 break;
1086
1087 } else {
1088 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno));
1089 goto fail;
1090 }
1091
1092 } else {
1093 memchunk.index = 0;
1094 memchunk.length = (size_t) t;
1095
1096 pa_source_post(u->source, &memchunk);
1097 pa_memblock_unref(memchunk.memblock);
1098
1099 l -= t;
1100
1101 revents &= ~POLLIN;
1102 work_done = TRUE;
1103 }
1104
1105 if (!loop)
1106 break;
1107 }
1108
1109 if (work_done)
1110 continue;
1111 }
1112 }
1113
1114 /* pa_log("loop2 revents=%i", revents); */
1115
1116 if (u->rtpoll_item) {
1117 struct pollfd *pollfd;
1118
1119 pa_assert(u->fd >= 0);
1120
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));
1125 }
1126
1127 /* Hmm, nothing to do. Let's sleep */
1128 if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
1129 goto fail;
1130
1131 if (ret == 0)
1132 goto finish;
1133
1134 if (u->rtpoll_item) {
1135 struct pollfd *pollfd;
1136
1137 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
1138
1139 if (pollfd->revents & ~(POLLOUT|POLLIN)) {
1140 pa_log("DSP shutdown.");
1141 goto fail;
1142 }
1143
1144 revents = pollfd->revents;
1145 } else
1146 revents = 0;
1147 }
1148
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);
1154
1155 finish:
1156 pa_log_debug("Thread shutting down");
1157 }
1158
1159 int pa__init(pa_module*m) {
1160
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;
1176
1177 pa_assert(m);
1178
1179 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1180 pa_log("Failed to parse module arguments.");
1181 goto fail;
1182 }
1183
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;
1187 }
1188
1189 if (!playback && !record) {
1190 pa_log("Neither playback nor record enabled for device.");
1191 goto fail;
1192 }
1193
1194 mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
1195
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;
1201 }
1202
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);
1207
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;
1211 }
1212
1213 if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) {
1214 pa_log("Failed to parse mmap argument.");
1215 goto fail;
1216 }
1217
1218 if ((fd = pa_oss_open(dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0)
1219 goto fail;
1220
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;
1224 }
1225
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;
1229 }
1230
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;
1235
1236 pa_log_info("Device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));
1237
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;
1242
1243 if (pa_oss_auto_format(fd, &ss) < 0)
1244 goto fail;
1245
1246 if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) {
1247 pa_log("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno));
1248 goto fail;
1249 }
1250 pa_assert(frag_size > 0);
1251
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);
1272
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;
1278 }
1279
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;
1285 }
1286
1287 u->in_hwbuf_size = u->in_nfrags * u->in_fragment_size;
1288 u->out_hwbuf_size = u->out_nfrags * u->out_fragment_size;
1289
1290 if (mode != O_WRONLY) {
1291 char *name_buf = NULL;
1292
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.");
1300 }
1301
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;
1307 }
1308
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));
1322
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;
1327 }
1328
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);
1332
1333 if (!u->source) {
1334 pa_log("Failed to create source object");
1335 goto fail;
1336 }
1337
1338 u->source->parent.process_msg = source_process_msg;
1339 u->source->userdata = u;
1340
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;
1345
1346 if (use_mmap)
1347 u->in_mmap_memblocks = pa_xnew0(pa_memblock*, u->in_nfrags);
1348 }
1349
1350 if (mode != O_RDONLY) {
1351 char *name_buf = NULL;
1352
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;
1363 }
1364 } else {
1365 pa_log_debug("Successfully mmap()ed output buffer.");
1366 pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &ss);
1367 }
1368 }
1369
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;
1375 }
1376
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));
1390
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;
1395 }
1396
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);
1400
1401 if (!u->sink) {
1402 pa_log("Failed to create sink object");
1403 goto fail;
1404 }
1405
1406 u->sink->parent.process_msg = sink_process_msg;
1407 u->sink->userdata = u;
1408
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;
1413
1414 pa_sink_set_max_request(u->sink, u->out_hwbuf_size);
1415
1416 if (use_mmap)
1417 u->out_mmap_memblocks = pa_xnew0(pa_memblock*, u->out_nfrags);
1418 }
1419
1420 if ((u->mixer_fd = pa_oss_open_mixer_for_device(u->device_name)) >= 0) {
1421 pa_bool_t do_close = TRUE;
1422
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));
1425
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;
1434 }
1435
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;
1443 }
1444 }
1445
1446 if (do_close) {
1447 pa_close(u->mixer_fd);
1448 u->mixer_fd = -1;
1449 u->mixer_devmask = 0;
1450 }
1451 }
1452
1453 go_on:
1454
1455 pa_assert(u->source || u->sink);
1456
1457 pa_memchunk_reset(&u->memchunk);
1458
1459 if (!(u->thread = pa_thread_new(thread_func, u))) {
1460 pa_log("Failed to create thread.");
1461 goto fail;
1462 }
1463
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);
1472 }
1473 }
1474
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);
1482 }
1483 }
1484
1485 if (u->sink)
1486 pa_sink_put(u->sink);
1487 if (u->source)
1488 pa_source_put(u->source);
1489
1490 pa_modargs_free(ma);
1491
1492 return 0;
1493
1494 fail:
1495
1496 if (u)
1497 pa__done(m);
1498 else if (fd >= 0)
1499 pa_close(fd);
1500
1501 if (ma)
1502 pa_modargs_free(ma);
1503
1504 return -1;
1505 }
1506
1507 void pa__done(pa_module*m) {
1508 struct userdata *u;
1509
1510 pa_assert(m);
1511
1512 if (!(u = m->userdata))
1513 return;
1514
1515 if (u->sink)
1516 pa_sink_unlink(u->sink);
1517
1518 if (u->source)
1519 pa_source_unlink(u->source);
1520
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);
1524 }
1525
1526 pa_thread_mq_done(&u->thread_mq);
1527
1528 if (u->sink)
1529 pa_sink_unref(u->sink);
1530
1531 if (u->source)
1532 pa_source_unref(u->source);
1533
1534 if (u->memchunk.memblock)
1535 pa_memblock_unref(u->memchunk.memblock);
1536
1537 if (u->rtpoll_item)
1538 pa_rtpoll_item_free(u->rtpoll_item);
1539
1540 if (u->rtpoll)
1541 pa_rtpoll_free(u->rtpoll);
1542
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);
1549 }
1550
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);
1557 }
1558
1559 if (u->in_mmap && u->in_mmap != MAP_FAILED)
1560 munmap(u->in_mmap, u->in_hwbuf_size);
1561
1562 if (u->out_mmap && u->out_mmap != MAP_FAILED)
1563 munmap(u->out_mmap, u->out_hwbuf_size);
1564
1565 if (u->fd >= 0)
1566 pa_close(u->fd);
1567
1568 if (u->mixer_fd >= 0)
1569 pa_close(u->mixer_fd);
1570
1571 pa_xfree(u->device_name);
1572
1573 pa_xfree(u);
1574 }