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