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