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