]> code.delx.au - pulseaudio/blob - src/modules/oss/module-oss.c
modules: introduce PA_MODULE_DEPRECATED() macro for marking modules deprecated
[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->virtual_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->virtual_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->virtual_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->virtual_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->virtual_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->virtual_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->virtual_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->virtual_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 pa_rtpoll_install(u->rtpoll);
893
894 for (;;) {
895 int ret;
896
897 /* pa_log("loop"); */
898
899 if (u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state))
900 if (u->sink->thread_info.rewind_requested)
901 pa_sink_process_rewind(u->sink, 0);
902
903 /* Render some data and write it to the dsp */
904
905 if (u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state) && ((revents & POLLOUT) || u->use_mmap || u->use_getospace)) {
906
907 if (u->use_mmap) {
908
909 if ((ret = mmap_write(u)) < 0)
910 goto fail;
911
912 revents &= ~POLLOUT;
913
914 if (ret > 0)
915 continue;
916
917 } else {
918 ssize_t l;
919 pa_bool_t loop = FALSE, work_done = FALSE;
920
921 l = (ssize_t) u->out_fragment_size;
922
923 if (u->use_getospace) {
924 audio_buf_info info;
925
926 if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
927 pa_log_info("Device doesn't support SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno));
928 u->use_getospace = FALSE;
929 } else {
930 l = info.bytes;
931
932 /* We loop only if GETOSPACE worked and we
933 * actually *know* that we can write more than
934 * one fragment at a time */
935 loop = TRUE;
936 }
937 }
938
939 /* Round down to multiples of the fragment size,
940 * because OSS needs that (at least some versions
941 * do) */
942 l = (l/(ssize_t) u->out_fragment_size) * (ssize_t) u->out_fragment_size;
943
944 /* Hmm, so poll() signalled us that we can read
945 * something, but GETOSPACE told us there was nothing?
946 * Hmm, make the best of it, try to read some data, to
947 * avoid spinning forever. */
948 if (l <= 0 && (revents & POLLOUT)) {
949 l = (ssize_t) u->out_fragment_size;
950 loop = FALSE;
951 }
952
953 while (l > 0) {
954 void *p;
955 ssize_t t;
956
957 if (u->memchunk.length <= 0)
958 pa_sink_render(u->sink, (size_t) l, &u->memchunk);
959
960 pa_assert(u->memchunk.length > 0);
961
962 p = pa_memblock_acquire(u->memchunk.memblock);
963 t = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, &write_type);
964 pa_memblock_release(u->memchunk.memblock);
965
966 /* pa_log("wrote %i bytes of %u", t, l); */
967
968 pa_assert(t != 0);
969
970 if (t < 0) {
971
972 if (errno == EINTR)
973 continue;
974
975 else if (errno == EAGAIN) {
976 pa_log_debug("EAGAIN");
977
978 revents &= ~POLLOUT;
979 break;
980
981 } else {
982 pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno));
983 goto fail;
984 }
985
986 } else {
987
988 u->memchunk.index += (size_t) t;
989 u->memchunk.length -= (size_t) t;
990
991 if (u->memchunk.length <= 0) {
992 pa_memblock_unref(u->memchunk.memblock);
993 pa_memchunk_reset(&u->memchunk);
994 }
995
996 l -= t;
997
998 revents &= ~POLLOUT;
999 work_done = TRUE;
1000 }
1001
1002 if (!loop)
1003 break;
1004 }
1005
1006 if (work_done)
1007 continue;
1008 }
1009 }
1010
1011 /* Try to read some data and pass it on to the source driver. */
1012
1013 if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state) && ((revents & POLLIN) || u->use_mmap || u->use_getispace)) {
1014
1015 if (u->use_mmap) {
1016
1017 if ((ret = mmap_read(u)) < 0)
1018 goto fail;
1019
1020 revents &= ~POLLIN;
1021
1022 if (ret > 0)
1023 continue;
1024
1025 } else {
1026
1027 void *p;
1028 ssize_t l;
1029 pa_memchunk memchunk;
1030 pa_bool_t loop = FALSE, work_done = FALSE;
1031
1032 l = (ssize_t) u->in_fragment_size;
1033
1034 if (u->use_getispace) {
1035 audio_buf_info info;
1036
1037 if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
1038 pa_log_info("Device doesn't support SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno));
1039 u->use_getispace = FALSE;
1040 } else {
1041 l = info.bytes;
1042 loop = TRUE;
1043 }
1044 }
1045
1046 l = (l/(ssize_t) u->in_fragment_size) * (ssize_t) u->in_fragment_size;
1047
1048 if (l <= 0 && (revents & POLLIN)) {
1049 l = (ssize_t) u->in_fragment_size;
1050 loop = FALSE;
1051 }
1052
1053 while (l > 0) {
1054 ssize_t t;
1055 size_t k;
1056
1057 pa_assert(l > 0);
1058
1059 memchunk.memblock = pa_memblock_new(u->core->mempool, (size_t) -1);
1060
1061 k = pa_memblock_get_length(memchunk.memblock);
1062
1063 if (k > (size_t) l)
1064 k = (size_t) l;
1065
1066 k = (k/u->frame_size)*u->frame_size;
1067
1068 p = pa_memblock_acquire(memchunk.memblock);
1069 t = pa_read(u->fd, p, k, &read_type);
1070 pa_memblock_release(memchunk.memblock);
1071
1072 pa_assert(t != 0); /* EOF cannot happen */
1073
1074 /* pa_log("read %i bytes of %u", t, l); */
1075
1076 if (t < 0) {
1077 pa_memblock_unref(memchunk.memblock);
1078
1079 if (errno == EINTR)
1080 continue;
1081
1082 else if (errno == EAGAIN) {
1083 pa_log_debug("EAGAIN");
1084
1085 revents &= ~POLLIN;
1086 break;
1087
1088 } else {
1089 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno));
1090 goto fail;
1091 }
1092
1093 } else {
1094 memchunk.index = 0;
1095 memchunk.length = (size_t) t;
1096
1097 pa_source_post(u->source, &memchunk);
1098 pa_memblock_unref(memchunk.memblock);
1099
1100 l -= t;
1101
1102 revents &= ~POLLIN;
1103 work_done = TRUE;
1104 }
1105
1106 if (!loop)
1107 break;
1108 }
1109
1110 if (work_done)
1111 continue;
1112 }
1113 }
1114
1115 /* pa_log("loop2 revents=%i", revents); */
1116
1117 if (u->rtpoll_item) {
1118 struct pollfd *pollfd;
1119
1120 pa_assert(u->fd >= 0);
1121
1122 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
1123 pollfd->events = (short)
1124 (((u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state)) ? POLLIN : 0) |
1125 ((u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state)) ? POLLOUT : 0));
1126 }
1127
1128 /* Hmm, nothing to do. Let's sleep */
1129 if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
1130 goto fail;
1131
1132 if (ret == 0)
1133 goto finish;
1134
1135 if (u->rtpoll_item) {
1136 struct pollfd *pollfd;
1137
1138 pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
1139
1140 if (pollfd->revents & ~(POLLOUT|POLLIN)) {
1141 pa_log("DSP shutdown.");
1142 goto fail;
1143 }
1144
1145 revents = pollfd->revents;
1146 } else
1147 revents = 0;
1148 }
1149
1150 fail:
1151 /* If this was no regular exit from the loop we have to continue
1152 * processing messages until we received PA_MESSAGE_SHUTDOWN */
1153 pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
1154 pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
1155
1156 finish:
1157 pa_log_debug("Thread shutting down");
1158 }
1159
1160 int pa__init(pa_module*m) {
1161
1162 struct audio_buf_info info;
1163 struct userdata *u = NULL;
1164 const char *dev;
1165 int fd = -1;
1166 int nfrags, orig_frag_size, frag_size;
1167 int mode, caps;
1168 pa_bool_t record = TRUE, playback = TRUE, use_mmap = TRUE;
1169 pa_sample_spec ss;
1170 pa_channel_map map;
1171 pa_modargs *ma = NULL;
1172 char hwdesc[64];
1173 const char *name;
1174 pa_bool_t namereg_fail;
1175 pa_sink_new_data sink_new_data;
1176 pa_source_new_data source_new_data;
1177
1178 pa_assert(m);
1179
1180 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1181 pa_log("Failed to parse module arguments.");
1182 goto fail;
1183 }
1184
1185 if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
1186 pa_log("record= and playback= expect boolean argument.");
1187 goto fail;
1188 }
1189
1190 if (!playback && !record) {
1191 pa_log("Neither playback nor record enabled for device.");
1192 goto fail;
1193 }
1194
1195 mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
1196
1197 ss = m->core->default_sample_spec;
1198 map = m->core->default_channel_map;
1199 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_OSS) < 0) {
1200 pa_log("Failed to parse sample specification or channel map");
1201 goto fail;
1202 }
1203
1204 nfrags = (int) m->core->default_n_fragments;
1205 frag_size = (int) pa_usec_to_bytes(m->core->default_fragment_size_msec*1000, &ss);
1206 if (frag_size <= 0)
1207 frag_size = (int) pa_frame_size(&ss);
1208
1209 if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) {
1210 pa_log("Failed to parse fragments arguments");
1211 goto fail;
1212 }
1213
1214 if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) {
1215 pa_log("Failed to parse mmap argument.");
1216 goto fail;
1217 }
1218
1219 if ((fd = pa_oss_open(dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0)
1220 goto fail;
1221
1222 if (use_mmap && (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_TRIGGER))) {
1223 pa_log_info("OSS device not mmap capable, falling back to UNIX read/write mode.");
1224 use_mmap = FALSE;
1225 }
1226
1227 if (use_mmap && mode == O_WRONLY) {
1228 pa_log_info("Device opened for playback only, cannot do memory mapping, falling back to UNIX write() mode.");
1229 use_mmap = FALSE;
1230 }
1231
1232 if (pa_oss_get_hw_description(dev, hwdesc, sizeof(hwdesc)) >= 0)
1233 pa_log_info("Hardware name is '%s'.", hwdesc);
1234 else
1235 hwdesc[0] = 0;
1236
1237 pa_log_info("Device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));
1238
1239 orig_frag_size = frag_size;
1240 if (nfrags >= 2 && frag_size >= 1)
1241 if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0)
1242 goto fail;
1243
1244 if (pa_oss_auto_format(fd, &ss) < 0)
1245 goto fail;
1246
1247 if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) {
1248 pa_log("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno));
1249 goto fail;
1250 }
1251 pa_assert(frag_size > 0);
1252
1253 u = pa_xnew0(struct userdata, 1);
1254 u->core = m->core;
1255 u->module = m;
1256 m->userdata = u;
1257 u->fd = fd;
1258 u->mixer_fd = -1;
1259 u->mixer_devmask = 0;
1260 u->use_getospace = u->use_getispace = TRUE;
1261 u->use_getodelay = TRUE;
1262 u->mode = mode;
1263 u->frame_size = pa_frame_size(&ss);
1264 u->device_name = pa_xstrdup(dev);
1265 u->in_nfrags = u->out_nfrags = (uint32_t) (u->nfrags = nfrags);
1266 u->out_fragment_size = u->in_fragment_size = (uint32_t) (u->frag_size = frag_size);
1267 u->orig_frag_size = orig_frag_size;
1268 u->use_mmap = use_mmap;
1269 u->rtpoll = pa_rtpoll_new();
1270 pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
1271 u->rtpoll_item = NULL;
1272 build_pollfd(u);
1273
1274 if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) {
1275 pa_log_info("Input -- %u fragments of size %u.", info.fragstotal, info.fragsize);
1276 u->in_fragment_size = (uint32_t) info.fragsize;
1277 u->in_nfrags = (uint32_t) info.fragstotal;
1278 u->use_getispace = TRUE;
1279 }
1280
1281 if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) {
1282 pa_log_info("Output -- %u fragments of size %u.", info.fragstotal, info.fragsize);
1283 u->out_fragment_size = (uint32_t) info.fragsize;
1284 u->out_nfrags = (uint32_t) info.fragstotal;
1285 u->use_getospace = TRUE;
1286 }
1287
1288 u->in_hwbuf_size = u->in_nfrags * u->in_fragment_size;
1289 u->out_hwbuf_size = u->out_nfrags * u->out_fragment_size;
1290
1291 if (mode != O_WRONLY) {
1292 char *name_buf = NULL;
1293
1294 if (use_mmap) {
1295 if ((u->in_mmap = mmap(NULL, u->in_hwbuf_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
1296 pa_log_warn("mmap(PROT_READ) failed, reverting to non-mmap mode: %s", pa_cstrerror(errno));
1297 use_mmap = u->use_mmap = FALSE;
1298 u->in_mmap = NULL;
1299 } else
1300 pa_log_debug("Successfully mmap()ed input buffer.");
1301 }
1302
1303 if ((name = pa_modargs_get_value(ma, "source_name", NULL)))
1304 namereg_fail = TRUE;
1305 else {
1306 name = name_buf = pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(dev));
1307 namereg_fail = FALSE;
1308 }
1309
1310 pa_source_new_data_init(&source_new_data);
1311 source_new_data.driver = __FILE__;
1312 source_new_data.module = m;
1313 pa_source_new_data_set_name(&source_new_data, name);
1314 source_new_data.namereg_fail = namereg_fail;
1315 pa_source_new_data_set_sample_spec(&source_new_data, &ss);
1316 pa_source_new_data_set_channel_map(&source_new_data, &map);
1317 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_STRING, dev);
1318 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_API, "oss");
1319 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, hwdesc[0] ? hwdesc : dev);
1320 pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, use_mmap ? "mmap" : "serial");
1321 pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (u->in_hwbuf_size));
1322 pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (u->in_fragment_size));
1323
1324 if (pa_modargs_get_proplist(ma, "source_properties", source_new_data.proplist, PA_UPDATE_REPLACE) < 0) {
1325 pa_log("Invalid properties");
1326 pa_source_new_data_done(&source_new_data);
1327 goto fail;
1328 }
1329
1330 u->source = pa_source_new(m->core, &source_new_data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY);
1331 pa_source_new_data_done(&source_new_data);
1332 pa_xfree(name_buf);
1333
1334 if (!u->source) {
1335 pa_log("Failed to create source object");
1336 goto fail;
1337 }
1338
1339 u->source->parent.process_msg = source_process_msg;
1340 u->source->userdata = u;
1341
1342 pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
1343 pa_source_set_rtpoll(u->source, u->rtpoll);
1344 pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(u->in_hwbuf_size, &u->source->sample_spec));
1345 u->source->refresh_volume = TRUE;
1346
1347 if (use_mmap)
1348 u->in_mmap_memblocks = pa_xnew0(pa_memblock*, u->in_nfrags);
1349 }
1350
1351 if (mode != O_RDONLY) {
1352 char *name_buf = NULL;
1353
1354 if (use_mmap) {
1355 if ((u->out_mmap = mmap(NULL, u->out_hwbuf_size, PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
1356 if (mode == O_RDWR) {
1357 pa_log_debug("mmap() failed for input. Changing to O_WRONLY mode.");
1358 mode = O_WRONLY;
1359 goto go_on;
1360 } else {
1361 pa_log_warn("mmap(PROT_WRITE) failed, reverting to non-mmap mode: %s", pa_cstrerror(errno));
1362 u->use_mmap = use_mmap = FALSE;
1363 u->out_mmap = NULL;
1364 }
1365 } else {
1366 pa_log_debug("Successfully mmap()ed output buffer.");
1367 pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &ss);
1368 }
1369 }
1370
1371 if ((name = pa_modargs_get_value(ma, "sink_name", NULL)))
1372 namereg_fail = TRUE;
1373 else {
1374 name = name_buf = pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(dev));
1375 namereg_fail = FALSE;
1376 }
1377
1378 pa_sink_new_data_init(&sink_new_data);
1379 sink_new_data.driver = __FILE__;
1380 sink_new_data.module = m;
1381 pa_sink_new_data_set_name(&sink_new_data, name);
1382 sink_new_data.namereg_fail = namereg_fail;
1383 pa_sink_new_data_set_sample_spec(&sink_new_data, &ss);
1384 pa_sink_new_data_set_channel_map(&sink_new_data, &map);
1385 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_STRING, dev);
1386 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_API, "oss");
1387 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, hwdesc[0] ? hwdesc : dev);
1388 pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, use_mmap ? "mmap" : "serial");
1389 pa_proplist_setf(sink_new_data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (u->out_hwbuf_size));
1390 pa_proplist_setf(sink_new_data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (u->out_fragment_size));
1391
1392 if (pa_modargs_get_proplist(ma, "sink_properties", sink_new_data.proplist, PA_UPDATE_REPLACE) < 0) {
1393 pa_log("Invalid properties");
1394 pa_sink_new_data_done(&sink_new_data);
1395 goto fail;
1396 }
1397
1398 u->sink = pa_sink_new(m->core, &sink_new_data, PA_SINK_HARDWARE|PA_SINK_LATENCY);
1399 pa_sink_new_data_done(&sink_new_data);
1400 pa_xfree(name_buf);
1401
1402 if (!u->sink) {
1403 pa_log("Failed to create sink object");
1404 goto fail;
1405 }
1406
1407 u->sink->parent.process_msg = sink_process_msg;
1408 u->sink->userdata = u;
1409
1410 pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
1411 pa_sink_set_rtpoll(u->sink, u->rtpoll);
1412 pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(u->out_hwbuf_size, &u->sink->sample_spec));
1413 u->sink->refresh_volume = TRUE;
1414
1415 pa_sink_set_max_request(u->sink, u->out_hwbuf_size);
1416
1417 if (use_mmap)
1418 u->out_mmap_memblocks = pa_xnew0(pa_memblock*, u->out_nfrags);
1419 }
1420
1421 if ((u->mixer_fd = pa_oss_open_mixer_for_device(u->device_name)) >= 0) {
1422 pa_bool_t do_close = TRUE;
1423
1424 if (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &u->mixer_devmask) < 0)
1425 pa_log_warn("SOUND_MIXER_READ_DEVMASK failed: %s", pa_cstrerror(errno));
1426
1427 else {
1428 if (u->sink && (u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM))) {
1429 pa_log_debug("Found hardware mixer track for playback.");
1430 u->sink->flags |= PA_SINK_HW_VOLUME_CTRL;
1431 u->sink->get_volume = sink_get_volume;
1432 u->sink->set_volume = sink_set_volume;
1433 u->sink->n_volume_steps = 101;
1434 do_close = FALSE;
1435 }
1436
1437 if (u->source && (u->mixer_devmask & (SOUND_MASK_RECLEV|SOUND_MASK_IGAIN))) {
1438 pa_log_debug("Found hardware mixer track for recording.");
1439 u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL;
1440 u->source->get_volume = source_get_volume;
1441 u->source->set_volume = source_set_volume;
1442 u->source->n_volume_steps = 101;
1443 do_close = FALSE;
1444 }
1445 }
1446
1447 if (do_close) {
1448 pa_close(u->mixer_fd);
1449 u->mixer_fd = -1;
1450 u->mixer_devmask = 0;
1451 }
1452 }
1453
1454 go_on:
1455
1456 pa_assert(u->source || u->sink);
1457
1458 pa_memchunk_reset(&u->memchunk);
1459
1460 if (!(u->thread = pa_thread_new(thread_func, u))) {
1461 pa_log("Failed to create thread.");
1462 goto fail;
1463 }
1464
1465 /* Read mixer settings */
1466 if (u->sink) {
1467 if (sink_new_data.volume_is_set) {
1468 if (u->sink->set_volume)
1469 u->sink->set_volume(u->sink);
1470 } else {
1471 if (u->sink->get_volume)
1472 u->sink->get_volume(u->sink);
1473 }
1474 }
1475
1476 if (u->source) {
1477 if (source_new_data.volume_is_set) {
1478 if (u->source->set_volume)
1479 u->source->set_volume(u->source);
1480 } else {
1481 if (u->source->get_volume)
1482 u->source->get_volume(u->source);
1483 }
1484 }
1485
1486 if (u->sink)
1487 pa_sink_put(u->sink);
1488 if (u->source)
1489 pa_source_put(u->source);
1490
1491 pa_modargs_free(ma);
1492
1493 return 0;
1494
1495 fail:
1496
1497 if (u)
1498 pa__done(m);
1499 else if (fd >= 0)
1500 pa_close(fd);
1501
1502 if (ma)
1503 pa_modargs_free(ma);
1504
1505 return -1;
1506 }
1507
1508 void pa__done(pa_module*m) {
1509 struct userdata *u;
1510
1511 pa_assert(m);
1512
1513 if (!(u = m->userdata))
1514 return;
1515
1516 if (u->sink)
1517 pa_sink_unlink(u->sink);
1518
1519 if (u->source)
1520 pa_source_unlink(u->source);
1521
1522 if (u->thread) {
1523 pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
1524 pa_thread_free(u->thread);
1525 }
1526
1527 pa_thread_mq_done(&u->thread_mq);
1528
1529 if (u->sink)
1530 pa_sink_unref(u->sink);
1531
1532 if (u->source)
1533 pa_source_unref(u->source);
1534
1535 if (u->memchunk.memblock)
1536 pa_memblock_unref(u->memchunk.memblock);
1537
1538 if (u->rtpoll_item)
1539 pa_rtpoll_item_free(u->rtpoll_item);
1540
1541 if (u->rtpoll)
1542 pa_rtpoll_free(u->rtpoll);
1543
1544 if (u->out_mmap_memblocks) {
1545 unsigned i;
1546 for (i = 0; i < u->out_nfrags; i++)
1547 if (u->out_mmap_memblocks[i])
1548 pa_memblock_unref_fixed(u->out_mmap_memblocks[i]);
1549 pa_xfree(u->out_mmap_memblocks);
1550 }
1551
1552 if (u->in_mmap_memblocks) {
1553 unsigned i;
1554 for (i = 0; i < u->in_nfrags; i++)
1555 if (u->in_mmap_memblocks[i])
1556 pa_memblock_unref_fixed(u->in_mmap_memblocks[i]);
1557 pa_xfree(u->in_mmap_memblocks);
1558 }
1559
1560 if (u->in_mmap && u->in_mmap != MAP_FAILED)
1561 munmap(u->in_mmap, u->in_hwbuf_size);
1562
1563 if (u->out_mmap && u->out_mmap != MAP_FAILED)
1564 munmap(u->out_mmap, u->out_hwbuf_size);
1565
1566 if (u->fd >= 0)
1567 pa_close(u->fd);
1568
1569 if (u->mixer_fd >= 0)
1570 pa_close(u->mixer_fd);
1571
1572 pa_xfree(u->device_name);
1573
1574 pa_xfree(u);
1575 }