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