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