]> code.delx.au - pulseaudio/blob - src/modules/module-oss.c
change order of munmap and freeing of memblocks
[pulseaudio] / src / modules / module-oss.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
8
9 PulseAudio is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published
11 by the Free Software Foundation; either version 2 of the License,
12 or (at your option) any later version.
13
14 PulseAudio is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 along with PulseAudio; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 USA.
23 ***/
24
25 /* General power management rules:
26 *
27 * When SUSPENDED we close the audio device.
28 *
29 * We make no difference between IDLE and RUNNING in our handling.
30 *
31 * As long as we are in RUNNING/IDLE state we will *always* write data to
32 * the device. If none is avilable from the inputs, we write silence
33 * instead.
34 *
35 * If power should be saved on IDLE this should be implemented in a
36 * special suspend-on-idle module that will put us into SUSPEND mode
37 * as soon and we're idle for too long.
38 *
39 */
40
41 /* TODO: handle restoring of volume after suspend */
42
43 #ifdef HAVE_CONFIG_H
44 #include <config.h>
45 #endif
46
47 #ifdef HAVE_SYS_MMAN_H
48 #include <sys/mman.h>
49 #endif
50
51 #include <sys/soundcard.h>
52 #include <sys/ioctl.h>
53 #include <sys/poll.h>
54 #include <stdlib.h>
55 #include <sys/stat.h>
56 #include <stdio.h>
57 #include <errno.h>
58 #include <string.h>
59 #include <fcntl.h>
60 #include <unistd.h>
61 #include <limits.h>
62 #include <signal.h>
63
64 #include <pulse/xmalloc.h>
65 #include <pulse/util.h>
66
67 #include <pulsecore/core-error.h>
68 #include <pulsecore/thread.h>
69 #include <pulsecore/sink.h>
70 #include <pulsecore/source.h>
71 #include <pulsecore/module.h>
72 #include <pulsecore/sample-util.h>
73 #include <pulsecore/core-util.h>
74 #include <pulsecore/modargs.h>
75 #include <pulsecore/log.h>
76
77 #include "oss-util.h"
78 #include "module-oss-symdef.h"
79
80 PA_MODULE_AUTHOR("Lennart Poettering")
81 PA_MODULE_DESCRIPTION("OSS Sink/Source")
82 PA_MODULE_VERSION(PACKAGE_VERSION)
83 PA_MODULE_USAGE(
84 "sink_name=<name for the sink> "
85 "source_name=<name for the source> "
86 "device=<OSS device> "
87 "record=<enable source?> "
88 "playback=<enable sink?> "
89 "format=<sample format> "
90 "channels=<number of channels> "
91 "rate=<sample rate> "
92 "fragments=<number of fragments> "
93 "fragment_size=<fragment size> "
94 "channel_map=<channel map> "
95 "mmap=<enable memory mapping?>")
96
97 #define DEFAULT_DEVICE "/dev/dsp"
98
99 #define DEFAULT_NFRAGS 4
100 #define DEFAULT_FRAGSIZE_MSEC 25
101
102 struct userdata {
103 pa_core *core;
104 pa_module *module;
105 pa_sink *sink;
106 pa_source *source;
107 pa_thread *thread;
108 pa_asyncmsgq *asyncmsgq;
109
110 char *device_name;
111
112 pa_memchunk memchunk;
113
114 uint32_t in_fragment_size, out_fragment_size, in_nfrags, out_nfrags, in_hwbuf_size, out_hwbuf_size;
115 int use_getospace, use_getispace;
116 int use_getodelay;
117
118 int use_pcm_volume;
119 int use_input_volume;
120
121 int sink_suspended, source_suspended;
122
123 int fd;
124 int mode;
125
126 int nfrags, frag_size;
127
128 int use_mmap;
129 unsigned out_mmap_current, in_mmap_current;
130 void *in_mmap, *out_mmap;
131 pa_memblock **in_mmap_memblocks, **out_mmap_memblocks;
132
133 int in_mmap_saved_nfrags, out_mmap_saved_nfrags;
134 };
135
136 static const char* const valid_modargs[] = {
137 "sink_name",
138 "source_name",
139 "device",
140 "record",
141 "playback",
142 "fragments",
143 "fragment_size",
144 "format",
145 "rate",
146 "channels",
147 "channel_map",
148 "mmap",
149 NULL
150 };
151
152 static void trigger(struct userdata *u, int quick) {
153 int enable_bits = 0, zero = 0;
154
155 /* pa_log_debug("trigger"); */
156
157 if (u->source && u->source->thread_info.state != PA_SOURCE_SUSPENDED)
158 enable_bits |= PCM_ENABLE_INPUT;
159
160 if (u->sink && u->sink->thread_info.state != PA_SINK_SUSPENDED)
161 enable_bits |= PCM_ENABLE_OUTPUT;
162
163 if (u->use_mmap) {
164
165 if (!quick)
166 /* First, let's stop all playback, capturing */
167 ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero);
168
169 #ifdef SNDCTL_DSP_HALT
170 if (enable_bits == 0)
171 if (ioctl(u->fd, SNDCTL_DSP_HALT, NULL) < 0)
172 pa_log_warn("SNDCTL_DSP_HALT: %s", pa_cstrerror(errno));
173 #endif
174
175 if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0)
176 pa_log_warn("SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno));
177
178 if (u->sink && !(enable_bits & PCM_ENABLE_OUTPUT)) {
179 pa_log_debug("clearing playback buffer");
180 pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &u->sink->sample_spec);
181 }
182
183 } else {
184
185 if (enable_bits)
186 if (ioctl(u->fd, SNDCTL_DSP_POST, NULL) < 0)
187 pa_log_warn("SNDCTL_DSP_POST: %s", pa_cstrerror(errno));
188
189 if (!quick) {
190 /*
191 * Some crappy drivers do not start the recording until we
192 * read something. Without this snippet, poll will never
193 * register the fd as ready.
194 */
195
196 if (u->source && u->source->thread_info.state != PA_SOURCE_SUSPENDED) {
197 uint8_t *buf = pa_xnew(uint8_t, u->in_fragment_size);
198 pa_read(u->fd, buf, u->in_fragment_size, NULL);
199 pa_xfree(buf);
200 }
201 }
202 }
203 }
204
205 static void mmap_fill_memblocks(struct userdata *u, unsigned n) {
206 pa_assert(u);
207 pa_assert(u->out_mmap_memblocks);
208
209 while (n > 0) {
210 pa_memchunk chunk;
211
212 if (u->out_mmap_memblocks[u->out_mmap_current])
213 pa_memblock_unref_fixed(u->out_mmap_memblocks[u->out_mmap_current]);
214
215 chunk.memblock = u->out_mmap_memblocks[u->out_mmap_current] =
216 pa_memblock_new_fixed(
217 u->core->mempool,
218 (uint8_t*) u->out_mmap + u->out_fragment_size * u->out_mmap_current,
219 u->out_fragment_size,
220 1);
221
222 chunk.length = pa_memblock_get_length(chunk.memblock);
223 chunk.index = 0;
224
225 pa_sink_render_into_full(u->sink, &chunk);
226
227 u->out_mmap_current++;
228 while (u->out_mmap_current >= u->out_nfrags)
229 u->out_mmap_current -= u->out_nfrags;
230
231 n--;
232 }
233 }
234
235 static int mmap_write(struct userdata *u) {
236 struct count_info info;
237
238
239 pa_assert(u);
240 pa_assert(u->sink);
241
242 if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
243 pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno));
244 return -1;
245 }
246
247 info.blocks += u->out_mmap_saved_nfrags;
248 u->out_mmap_saved_nfrags = 0;
249
250 if (info.blocks > 0)
251 mmap_fill_memblocks(u, info.blocks);
252
253 return info.blocks;
254 }
255
256 static void mmap_post_memblocks(struct userdata *u, unsigned n) {
257 pa_assert(u);
258 pa_assert(u->in_mmap_memblocks);
259
260 while (n > 0) {
261 pa_memchunk chunk;
262
263 if (!u->in_mmap_memblocks[u->in_mmap_current]) {
264
265 chunk.memblock = u->in_mmap_memblocks[u->in_mmap_current] =
266 pa_memblock_new_fixed(
267 u->core->mempool,
268 (uint8_t*) u->in_mmap + u->in_fragment_size*u->in_mmap_current,
269 u->in_fragment_size,
270 1);
271
272 chunk.length = pa_memblock_get_length(chunk.memblock);
273 chunk.index = 0;
274
275 pa_source_post(u->source, &chunk);
276 }
277
278 u->in_mmap_current++;
279 while (u->in_mmap_current >= u->in_nfrags)
280 u->in_mmap_current -= u->in_nfrags;
281
282 n--;
283 }
284 }
285
286 static void mmap_clear_memblocks(struct userdata*u, unsigned n) {
287 unsigned i = u->in_mmap_current;
288
289 pa_assert(u);
290 pa_assert(u->in_mmap_memblocks);
291
292 if (n > u->in_nfrags)
293 n = u->in_nfrags;
294
295 while (n > 0) {
296 if (u->in_mmap_memblocks[i]) {
297 pa_memblock_unref_fixed(u->in_mmap_memblocks[i]);
298 u->in_mmap_memblocks[i] = NULL;
299 }
300
301 i++;
302 while (i >= u->in_nfrags)
303 i -= u->in_nfrags;
304
305 n--;
306 }
307 }
308
309 static int mmap_read(struct userdata *u) {
310 struct count_info info;
311 pa_assert(u);
312 pa_assert(u->source);
313
314 if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
315 pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno));
316 return -1;
317 }
318
319 info.blocks += u->in_mmap_saved_nfrags;
320 u->in_mmap_saved_nfrags = 0;
321
322 if (info.blocks > 0) {
323 mmap_post_memblocks(u, info.blocks);
324 mmap_clear_memblocks(u, u->in_nfrags/2);
325 }
326
327 return info.blocks;
328 }
329
330 static pa_usec_t mmap_sink_get_latency(struct userdata *u) {
331 struct count_info info;
332 size_t bpos, n;
333
334 pa_assert(u);
335
336 if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
337 pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno));
338 return 0;
339 }
340
341 u->out_mmap_saved_nfrags += info.blocks;
342
343 bpos = ((u->out_mmap_current + u->out_mmap_saved_nfrags) * u->out_fragment_size) % u->out_hwbuf_size;
344
345 if (bpos <= (size_t) info.ptr)
346 n = u->out_hwbuf_size - (info.ptr - bpos);
347 else
348 n = bpos - info.ptr;
349
350 /* 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); */
351
352 return pa_bytes_to_usec(n, &u->sink->sample_spec);
353 }
354
355 static pa_usec_t mmap_source_get_latency(struct userdata *u) {
356 struct count_info info;
357 size_t bpos, n;
358
359 pa_assert(u);
360
361 if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
362 pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno));
363 return 0;
364 }
365
366 u->in_mmap_saved_nfrags += info.blocks;
367 bpos = ((u->in_mmap_current + u->in_mmap_saved_nfrags) * u->in_fragment_size) % u->in_hwbuf_size;
368
369 if (bpos <= (size_t) info.ptr)
370 n = info.ptr - bpos;
371 else
372 n = u->in_hwbuf_size - bpos + 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->in_fragment_size, u->in_fragments); */
375
376 return pa_bytes_to_usec(n, &u->source->sample_spec);
377 }
378
379 static pa_usec_t io_sink_get_latency(struct userdata *u) {
380 pa_usec_t r = 0;
381
382 pa_assert(u);
383
384 if (u->use_getodelay) {
385 int arg;
386
387 if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) {
388 pa_log_info("Device doesn't support SNDCTL_DSP_GETODELAY: %s", pa_cstrerror(errno));
389 u->use_getodelay = 0;
390 } else
391 r = pa_bytes_to_usec(arg, &u->sink->sample_spec);
392
393 }
394
395 if (!u->use_getodelay && u->use_getospace) {
396 struct audio_buf_info info;
397
398 if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
399 pa_log_info("Device doesn't support SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno));
400 u->use_getospace = 0;
401 } else
402 r = pa_bytes_to_usec(info.bytes, &u->sink->sample_spec);
403 }
404
405 if (u->memchunk.memblock)
406 r += pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec);
407
408 return r;
409 }
410
411
412 static pa_usec_t io_source_get_latency(struct userdata *u) {
413 pa_usec_t r = 0;
414
415 pa_assert(u);
416
417 if (u->use_getispace) {
418 struct audio_buf_info info;
419
420 if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
421 pa_log_info("Device doesn't support SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno));
422 u->use_getispace = 0;
423 } else
424 r = pa_bytes_to_usec(info.bytes, &u->source->sample_spec);
425 }
426
427 return r;
428 }
429
430 static int suspend(struct userdata *u) {
431 pa_assert(u);
432 pa_assert(u->fd >= 0);
433
434 if (u->out_mmap_memblocks) {
435 unsigned i;
436 for (i = 0; i < u->out_nfrags; i++)
437 if (u->out_mmap_memblocks[i]) {
438 pa_memblock_unref_fixed(u->out_mmap_memblocks[i]);
439 u->out_mmap_memblocks[i] = NULL;
440 }
441 }
442
443 if (u->in_mmap_memblocks) {
444 unsigned i;
445 for (i = 0; i < u->in_nfrags; i++)
446 if (u->in_mmap_memblocks[i]) {
447 pa_memblock_unref_fixed(u->in_mmap_memblocks[i]);
448 u->in_mmap_memblocks[i] = NULL;
449 }
450 }
451
452 if (u->in_mmap && u->in_mmap != MAP_FAILED) {
453 munmap(u->in_mmap, u->in_hwbuf_size);
454 u->in_mmap = NULL;
455 }
456
457 if (u->out_mmap && u->out_mmap != MAP_FAILED) {
458 munmap(u->out_mmap, u->out_hwbuf_size);
459 u->out_mmap = NULL;
460 }
461
462 /* Let's suspend */
463 ioctl(u->fd, SNDCTL_DSP_SYNC, NULL);
464 close(u->fd);
465 u->fd = -1;
466
467 pa_log_debug("Device suspended...");
468
469 return 0;
470 }
471
472 static int unsuspend(struct userdata *u) {
473 int m;
474 pa_sample_spec ss, *ss_original;
475 int frag_size, in_frag_size, out_frag_size;
476 int in_nfrags, out_nfrags;
477 struct audio_buf_info info;
478
479 pa_assert(u);
480 pa_assert(u->fd < 0);
481
482 m = u->mode;
483
484 pa_log_debug("Trying resume...");
485
486 if ((u->fd = pa_oss_open(u->device_name, &m, NULL)) < 0) {
487 pa_log_warn("Resume failed, device busy (%s)", pa_cstrerror(errno));
488 return -1;
489
490 if (m != u->mode)
491 pa_log_warn("Resume failed, couldn't open device with original access mode.");
492 goto fail;
493 }
494
495 if (u->nfrags >= 2 && u->frag_size >= 1)
496 if (pa_oss_set_fragments(u->fd, u->nfrags, u->frag_size) < 0) {
497 pa_log_warn("Resume failed, couldn't set original fragment settings.");
498 goto fail;
499 }
500
501 ss = *(ss_original = u->sink ? &u->sink->sample_spec : &u->source->sample_spec);
502 if (pa_oss_auto_format(u->fd, &ss) < 0 || !pa_sample_spec_equal(&ss, ss_original)) {
503 pa_log_warn("Resume failed, couldn't set original sample format settings.");
504 goto fail;
505 }
506
507 if (ioctl(u->fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) {
508 pa_log_warn("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno));
509 goto fail;
510 }
511
512 in_frag_size = out_frag_size = frag_size;
513 in_nfrags = out_nfrags = u->nfrags;
514
515 if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) >= 0) {
516 in_frag_size = info.fragsize;
517 in_nfrags = info.fragstotal;
518 }
519
520 if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) {
521 out_frag_size = info.fragsize;
522 out_nfrags = info.fragstotal;
523 }
524
525 if ((u->source && (in_frag_size != (int) u->in_fragment_size || in_nfrags != (int) u->in_nfrags)) ||
526 (u->sink && (out_frag_size != (int) u->out_fragment_size || out_nfrags != (int) u->out_nfrags))) {
527 pa_log_warn("Resume failed, input fragment settings don't match.");
528 goto fail;
529 }
530
531 if (u->use_mmap) {
532 if (u->source) {
533 if ((u->in_mmap = mmap(NULL, u->in_hwbuf_size, PROT_READ, MAP_SHARED, u->fd, 0)) == MAP_FAILED) {
534 pa_log("Resume failed, mmap(): %s", pa_cstrerror(errno));
535 goto fail;
536 }
537 }
538
539 if (u->sink) {
540 if ((u->out_mmap = mmap(NULL, u->out_hwbuf_size, PROT_WRITE, MAP_SHARED, u->fd, 0)) == MAP_FAILED) {
541 pa_log("Resume failed, mmap(): %s", pa_cstrerror(errno));
542 if (u->in_mmap && u->in_mmap != MAP_FAILED) {
543 munmap(u->in_mmap, u->in_hwbuf_size);
544 u->in_mmap = NULL;
545 }
546
547 goto fail;
548 }
549
550 pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &ss);
551 }
552 }
553
554 u->out_mmap_current = u->in_mmap_current = 0;
555 u->out_mmap_saved_nfrags = u->in_mmap_saved_nfrags = 0;
556
557 /* Now, start only what we need */
558 trigger(u, 0);
559
560 pa_log_debug("Resumed successfully...");
561
562 return 0;
563
564 fail:
565 close(u->fd);
566 u->fd = -1;
567 return -1;
568 }
569
570 static int sink_process_msg(pa_msgobject *o, int code, void *data, pa_memchunk *chunk) {
571 struct userdata *u = PA_SINK(o)->userdata;
572 int do_trigger = 0, ret;
573
574 switch (code) {
575
576 case PA_SINK_MESSAGE_GET_LATENCY: {
577 pa_usec_t r = 0;
578
579 if (u->fd >= 0) {
580 if (u->use_mmap)
581 r = mmap_sink_get_latency(u);
582 else
583 r = io_sink_get_latency(u);
584 }
585
586 *((pa_usec_t*) data) = r;
587
588 break;
589 }
590
591 case PA_SINK_MESSAGE_SET_STATE:
592
593 if (PA_PTR_TO_UINT(data) == PA_SINK_SUSPENDED) {
594 pa_assert(u->sink->thread_info.state != PA_SINK_SUSPENDED);
595
596 if (u->source_suspended) {
597 if (suspend(u) < 0)
598 return -1;
599 } else
600 do_trigger = 1;
601
602 u->sink_suspended = 1;
603
604 } else if (u->sink->thread_info.state == PA_SINK_SUSPENDED) {
605 pa_assert(PA_PTR_TO_UINT(data) != PA_SINK_SUSPENDED);
606
607 if (u->source_suspended) {
608 if (unsuspend(u) < 0)
609 return -1;
610 } else
611 do_trigger = 1;
612
613 u->out_mmap_current = 0;
614 u->out_mmap_saved_nfrags = 0;
615
616 u->sink_suspended = 0;
617 }
618
619 break;
620
621 case PA_SINK_MESSAGE_SET_VOLUME:
622
623 if (u->use_pcm_volume && u->fd >= 0) {
624
625 if (pa_oss_set_pcm_volume(u->fd, &u->sink->sample_spec, ((pa_cvolume*) data)) < 0) {
626 pa_log_info("Device doesn't support setting mixer settings: %s", pa_cstrerror(errno));
627 u->use_pcm_volume = 0;
628 } else
629 return 0;
630 }
631
632 break;
633
634 case PA_SINK_MESSAGE_GET_VOLUME:
635
636 if (u->use_pcm_volume && u->fd >= 0) {
637
638 if (pa_oss_get_pcm_volume(u->fd, &u->sink->sample_spec, ((pa_cvolume*) data)) < 0) {
639 pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
640 u->use_pcm_volume = 0;
641 } else
642 return 0;
643 }
644
645 break;
646 }
647
648 ret = pa_sink_process_msg(o, code, data, chunk);
649
650 if (do_trigger)
651 trigger(u, 1);
652
653 return ret;
654 }
655
656 static int source_process_msg(pa_msgobject *o, int code, void *data, pa_memchunk *chunk) {
657 struct userdata *u = PA_SOURCE(o)->userdata;
658 int do_trigger = 0, ret;
659
660 switch (code) {
661
662 case PA_SOURCE_MESSAGE_GET_LATENCY: {
663 pa_usec_t r = 0;
664
665 if (u->fd >= 0) {
666 if (u->use_mmap)
667 r = mmap_source_get_latency(u);
668 else
669 r = io_source_get_latency(u);
670 }
671
672 *((pa_usec_t*) data) = r;
673 break;
674 }
675
676 case PA_SOURCE_MESSAGE_SET_STATE:
677
678 if (PA_PTR_TO_UINT(data) == PA_SOURCE_SUSPENDED) {
679 pa_assert(u->source->thread_info.state != PA_SOURCE_SUSPENDED);
680
681 if (u->sink_suspended) {
682 if (suspend(u) < 0)
683 return -1;
684 } else
685 do_trigger = 1;
686
687 u->source_suspended = 1;
688
689 } else if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) {
690 pa_assert(PA_PTR_TO_UINT(data) != PA_SOURCE_SUSPENDED);
691
692 if (u->sink_suspended) {
693 if (unsuspend(u) < 0)
694 return -1;
695 } else
696 do_trigger = 1;
697
698 u->in_mmap_current = 0;
699 u->in_mmap_saved_nfrags = 0;
700
701 u->source_suspended = 0;
702 }
703
704 break;
705
706 case PA_SOURCE_MESSAGE_SET_VOLUME:
707
708 if (u->use_input_volume && u->fd >= 0) {
709
710 if (pa_oss_set_input_volume(u->fd, &u->source->sample_spec, ((pa_cvolume*) data)) < 0) {
711 pa_log_info("Device doesn't support setting mixer settings: %s", pa_cstrerror(errno));
712 u->use_input_volume = 0;
713 } else
714 return 0;
715 }
716
717 break;
718
719 case PA_SOURCE_MESSAGE_GET_VOLUME:
720
721 if (u->use_input_volume && u->fd >= 0) {
722
723 if (pa_oss_get_input_volume(u->fd, &u->source->sample_spec, ((pa_cvolume*) data)) < 0) {
724 pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
725 u->use_input_volume = 0;
726 } else
727 return 0;
728 }
729
730 break;
731 }
732
733 ret = pa_source_process_msg(o, code, data, chunk);
734
735 if (do_trigger)
736 trigger(u, 1);
737
738 return ret;
739 }
740
741 static void thread_func(void *userdata) {
742 enum {
743 POLLFD_ASYNCQ,
744 POLLFD_DSP,
745 POLLFD_MAX,
746 };
747
748 struct userdata *u = userdata;
749 struct pollfd pollfd[POLLFD_MAX];
750 int write_type = 0, read_type = 0;
751
752 pa_assert(u);
753
754 pa_log_debug("Thread starting up");
755
756 trigger(u, 0);
757
758 memset(&pollfd, 0, sizeof(pollfd));
759
760 pollfd[POLLFD_ASYNCQ].fd = pa_asyncmsgq_get_fd(u->asyncmsgq);
761 pollfd[POLLFD_ASYNCQ].events = POLLIN;
762 pollfd[POLLFD_DSP].fd = u->fd;
763
764 for (;;) {
765 pa_msgobject *object;
766 int code;
767 void *data;
768 pa_memchunk chunk;
769 int r;
770
771 /* pa_log("loop"); */
772
773 /* Check whether there is a message for us to process */
774 if (pa_asyncmsgq_get(u->asyncmsgq, &object, &code, &data, &chunk, 0) == 0) {
775 int ret;
776
777 /* pa_log("processing msg"); */
778
779 if (!object && code == PA_MESSAGE_SHUTDOWN) {
780 pa_asyncmsgq_done(u->asyncmsgq, 0);
781 goto finish;
782 }
783
784 ret = pa_asyncmsgq_dispatch(object, code, data, &chunk);
785 pa_asyncmsgq_done(u->asyncmsgq, ret);
786 continue;
787 }
788
789 /* pa_log("loop2"); */
790
791 /* Render some data and write it to the dsp */
792
793 if (u->sink && u->sink->thread_info.state != PA_SINK_SUSPENDED && (pollfd[POLLFD_DSP].revents & POLLOUT)) {
794
795 if (u->use_mmap) {
796 int ret;
797
798 if ((ret = mmap_write(u)) < 0)
799 goto fail;
800
801 pollfd[POLLFD_DSP].revents &= ~POLLOUT;
802
803 if (ret > 0)
804 continue;
805
806 } else {
807 ssize_t l;
808 void *p;
809 int loop = 0;
810
811 l = u->out_fragment_size;
812
813 if (u->use_getospace) {
814 audio_buf_info info;
815
816 if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
817 pa_log_info("Device doesn't support SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno));
818 u->use_getospace = 0;
819 } else {
820 if (info.bytes >= l) {
821 l = (info.bytes/l)*l;
822 loop = 1;
823 }
824 }
825 }
826
827 do {
828 ssize_t t;
829
830 pa_assert(l > 0);
831
832 if (u->memchunk.length <= 0)
833 pa_sink_render(u->sink, l, &u->memchunk);
834
835 pa_assert(u->memchunk.length > 0);
836
837 p = pa_memblock_acquire(u->memchunk.memblock);
838 t = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, &write_type);
839 pa_memblock_release(u->memchunk.memblock);
840
841 /* pa_log("wrote %i bytes of %u", t, l); */
842
843 pa_assert(t != 0);
844
845 if (t < 0) {
846
847 if (errno == EINTR)
848 continue;
849
850 else if (errno == EAGAIN) {
851 pa_log_debug("EAGAIN");
852
853 pollfd[POLLFD_DSP].revents &= ~POLLOUT;
854 break;
855
856 } else {
857 pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno));
858 goto fail;
859 }
860
861 } else {
862
863 u->memchunk.index += t;
864 u->memchunk.length -= t;
865
866 if (u->memchunk.length <= 0) {
867 pa_memblock_unref(u->memchunk.memblock);
868 pa_memchunk_reset(&u->memchunk);
869 }
870
871 l -= t;
872
873 pollfd[POLLFD_DSP].revents &= ~POLLOUT;
874 }
875
876 } while (loop && l > 0);
877
878 continue;
879 }
880 }
881
882 /* Try to read some data and pass it on to the source driver */
883
884 if (u->source && u->source->thread_info.state != PA_SOURCE_SUSPENDED && ((pollfd[POLLFD_DSP].revents & POLLIN))) {
885
886 if (u->use_mmap) {
887 int ret;
888
889 if ((ret = mmap_read(u)) < 0)
890 goto fail;
891
892 pollfd[POLLFD_DSP].revents &= ~POLLIN;
893
894 if (ret > 0)
895 continue;
896
897 } else {
898
899 void *p;
900 ssize_t l;
901 pa_memchunk memchunk;
902 int loop = 0;
903
904 l = u->in_fragment_size;
905
906 if (u->use_getispace) {
907 audio_buf_info info;
908
909 if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
910 pa_log_info("Device doesn't support SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno));
911 u->use_getispace = 0;
912 } else {
913 if (info.bytes >= l) {
914 l = (info.bytes/l)*l;
915 loop = 1;
916 }
917 }
918 }
919
920 do {
921 ssize_t t;
922
923 pa_assert(l > 0);
924
925 memchunk.memblock = pa_memblock_new(u->core->mempool, l);
926
927 p = pa_memblock_acquire(memchunk.memblock);
928 t = pa_read(u->fd, p, l, &read_type);
929 pa_memblock_release(memchunk.memblock);
930
931 pa_assert(t != 0); /* EOF cannot happen */
932
933 /* pa_log("read %i bytes of %u", t, l); */
934
935 if (t < 0) {
936 pa_memblock_unref(memchunk.memblock);
937
938 if (errno == EINTR)
939 continue;
940
941 else if (errno == EAGAIN) {
942 pa_log_debug("EAGAIN");
943
944 pollfd[POLLFD_DSP].revents &= ~POLLIN;
945 break;
946
947 } else {
948 pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno));
949 goto fail;
950 }
951
952 } else {
953 memchunk.index = 0;
954 memchunk.length = t;
955
956 pa_source_post(u->source, &memchunk);
957 pa_memblock_unref(memchunk.memblock);
958
959 l -= t;
960
961 pollfd[POLLFD_DSP].revents &= ~POLLIN;
962 }
963 } while (loop && l > 0);
964
965 continue;
966 }
967 }
968
969 if (u->fd >= 0) {
970 pollfd[POLLFD_DSP].fd = u->fd;
971 pollfd[POLLFD_DSP].events =
972 ((u->source && u->source->thread_info.state != PA_SOURCE_SUSPENDED) ? POLLIN : 0) |
973 ((u->sink && u->sink->thread_info.state != PA_SINK_SUSPENDED) ? POLLOUT : 0);
974 }
975
976 /* Hmm, nothing to do. Let's sleep */
977
978 if (pa_asyncmsgq_before_poll(u->asyncmsgq) < 0)
979 continue;
980
981 /* pa_log("polling for %i (legend: %i=POLLIN, %i=POLLOUT)", u->fd >= 0 ? pollfd[POLLFD_DSP].events : -1, POLLIN, POLLOUT); */
982 r = poll(pollfd, u->fd >= 0 ? POLLFD_MAX : POLLFD_DSP, -1);
983 /* pa_log("polling got dsp=%i amq=%i (%i)", r > 0 ? pollfd[POLLFD_DSP].revents : 0, r > 0 ? pollfd[POLLFD_ASYNCQ].revents : 0, r); */
984
985 pa_asyncmsgq_after_poll(u->asyncmsgq);
986
987 if (u->fd < 0)
988 pollfd[POLLFD_DSP].revents = 0;
989
990 if (r < 0) {
991 if (errno == EINTR) {
992 pollfd[POLLFD_ASYNCQ].revents = 0;
993 pollfd[POLLFD_DSP].revents = 0;
994 continue;
995 }
996
997 pa_log("poll() failed: %s", pa_cstrerror(errno));
998 goto fail;
999 }
1000
1001 pa_assert(r > 0);
1002
1003 if (pollfd[POLLFD_DSP].revents & ~(POLLOUT|POLLIN)) {
1004 pa_log("DSP shutdown.");
1005 goto fail;
1006 }
1007
1008 pa_assert((pollfd[POLLFD_ASYNCQ].revents & ~POLLIN) == 0);
1009 }
1010
1011 fail:
1012 /* We have to continue processing messages until we receive the
1013 * SHUTDOWN message */
1014 pa_asyncmsgq_post(u->core->asyncmsgq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, NULL, NULL);
1015 pa_asyncmsgq_wait_for(u->asyncmsgq, PA_MESSAGE_SHUTDOWN);
1016
1017 finish:
1018 pa_log_debug("Thread shutting down");
1019 }
1020
1021 int pa__init(pa_core *c, pa_module*m) {
1022 struct audio_buf_info info;
1023 struct userdata *u = NULL;
1024 const char *p;
1025 int fd = -1;
1026 int nfrags, frag_size;
1027 int mode, caps;
1028 int record = 1, playback = 1, use_mmap = 1;
1029 pa_sample_spec ss;
1030 pa_channel_map map;
1031 pa_modargs *ma = NULL;
1032 char hwdesc[64], *t;
1033 const char *name;
1034 int namereg_fail;
1035
1036 pa_assert(c);
1037 pa_assert(m);
1038
1039 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1040 pa_log("Failed to parse module arguments.");
1041 goto fail;
1042 }
1043
1044 if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
1045 pa_log("record= and playback= expect numeric argument.");
1046 goto fail;
1047 }
1048
1049 if (!playback && !record) {
1050 pa_log("Neither playback nor record enabled for device.");
1051 goto fail;
1052 }
1053
1054 mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
1055
1056 ss = c->default_sample_spec;
1057 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_OSS) < 0) {
1058 pa_log("Failed to parse sample specification or channel map");
1059 goto fail;
1060 }
1061
1062 nfrags = DEFAULT_NFRAGS;
1063 frag_size = pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*1000, &ss);
1064 if (frag_size <= 0)
1065 frag_size = pa_frame_size(&ss);
1066
1067 if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) {
1068 pa_log("Failed to parse fragments arguments");
1069 goto fail;
1070 }
1071
1072 if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) {
1073 pa_log("Failed to parse mmap argument.");
1074 goto fail;
1075 }
1076
1077 if ((fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0)
1078 goto fail;
1079
1080 if (use_mmap && (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_TRIGGER))) {
1081 pa_log("OSS device not mmap capable, falling back to UNIX read/write mode");
1082 use_mmap = 0;
1083 }
1084
1085 if (pa_oss_get_hw_description(p, hwdesc, sizeof(hwdesc)) >= 0)
1086 pa_log_info("Hardware name is '%s'.", hwdesc);
1087 else
1088 hwdesc[0] = 0;
1089
1090 pa_log_info("Device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));
1091
1092 if (nfrags >= 2 && frag_size >= 1)
1093 if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0)
1094 goto fail;
1095
1096 if (pa_oss_auto_format(fd, &ss) < 0)
1097 goto fail;
1098
1099 if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) {
1100 pa_log("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno));
1101 goto fail;
1102 }
1103 pa_assert(frag_size > 0);
1104
1105 u = pa_xnew0(struct userdata, 1);
1106 u->core = c;
1107 u->module = m;
1108 m->userdata = u;
1109 u->use_getospace = u->use_getispace = 1;
1110 u->use_getodelay = 1;
1111 u->use_input_volume = u->use_pcm_volume = 1;
1112 u->mode = mode;
1113 u->device_name = pa_xstrdup(p);
1114 u->in_nfrags = u->out_nfrags = u->nfrags = nfrags;
1115 u->out_fragment_size = u->in_fragment_size = u->frag_size = frag_size;
1116 u->use_mmap = use_mmap;
1117 pa_assert_se(u->asyncmsgq = pa_asyncmsgq_new(0));
1118
1119 if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) {
1120 pa_log_info("Input -- %u fragments of size %u.", info.fragstotal, info.fragsize);
1121 u->in_fragment_size = info.fragsize;
1122 u->in_nfrags = info.fragstotal;
1123 u->use_getispace = 1;
1124 }
1125
1126 if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) {
1127 pa_log_info("Output -- %u fragments of size %u.", info.fragstotal, info.fragsize);
1128 u->out_fragment_size = info.fragsize;
1129 u->out_nfrags = info.fragstotal;
1130 u->use_getospace = 1;
1131 }
1132
1133 u->in_hwbuf_size = u->in_nfrags * u->in_fragment_size;
1134 u->out_hwbuf_size = u->out_nfrags * u->out_fragment_size;
1135
1136 if (mode != O_WRONLY) {
1137 char *name_buf = NULL;
1138
1139 if (use_mmap) {
1140 if ((u->in_mmap = mmap(NULL, u->in_hwbuf_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
1141 if (mode == O_RDWR) {
1142 pa_log_debug("mmap() failed for input. Changing to O_WRONLY mode.");
1143 mode = O_WRONLY;
1144 goto try_write;
1145 } else {
1146 pa_log("mmap(): %s", pa_cstrerror(errno));
1147 goto fail;
1148 }
1149 }
1150
1151 pa_log_debug("Successfully mmap()ed input buffer.");
1152 }
1153
1154 if ((name = pa_modargs_get_value(ma, "source_name", NULL)))
1155 namereg_fail = 1;
1156 else {
1157 name = name_buf = pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(p));
1158 namereg_fail = 0;
1159 }
1160
1161 u->source = pa_source_new(c, __FILE__, name, namereg_fail, &ss, &map);
1162 pa_xfree(name_buf);
1163 if (!u->source)
1164 goto fail;
1165
1166 u->source->parent.process_msg = source_process_msg;
1167 u->source->userdata = u;
1168
1169 pa_source_set_module(u->source, m);
1170 pa_source_set_asyncmsgq(u->source, u->asyncmsgq);
1171 pa_source_set_description(u->source, t = pa_sprintf_malloc("OSS PCM on %s%s%s%s",
1172 p,
1173 hwdesc[0] ? " (" : "",
1174 hwdesc[0] ? hwdesc : "",
1175 hwdesc[0] ? ")" : ""));
1176 pa_xfree(t);
1177 u->source->is_hardware = 1;
1178 u->source->refresh_volume = 1;
1179
1180 if (use_mmap)
1181 u->in_mmap_memblocks = pa_xnew0(pa_memblock*, u->in_nfrags);
1182 }
1183
1184 try_write:
1185
1186 if (mode != O_RDONLY) {
1187 char *name_buf = NULL;
1188
1189 if (use_mmap) {
1190 if ((u->out_mmap = mmap(NULL, u->out_hwbuf_size, PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
1191 if (mode == O_RDWR) {
1192 pa_log_debug("mmap() failed for input. Changing to O_WRONLY mode.");
1193 mode = O_WRONLY;
1194 goto go_on;
1195 } else {
1196 pa_log("mmap(): %s", pa_cstrerror(errno));
1197 goto fail;
1198 }
1199 }
1200
1201 pa_log_debug("Successfully mmap()ed output buffer.");
1202 pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &ss);
1203 }
1204
1205 if ((name = pa_modargs_get_value(ma, "sink_name", NULL)))
1206 namereg_fail = 1;
1207 else {
1208 name = name_buf = pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(p));
1209 namereg_fail = 0;
1210 }
1211
1212 u->sink = pa_sink_new(c, __FILE__, name, namereg_fail, &ss, &map);
1213 pa_xfree(name_buf);
1214 if (!u->sink)
1215 goto fail;
1216
1217 u->sink->parent.process_msg = sink_process_msg;
1218 u->sink->userdata = u;
1219
1220 pa_sink_set_module(u->sink, m);
1221 pa_sink_set_asyncmsgq(u->sink, u->asyncmsgq);
1222 pa_sink_set_description(u->sink, t = pa_sprintf_malloc("OSS PCM on %s%s%s%s",
1223 p,
1224 hwdesc[0] ? " (" : "",
1225 hwdesc[0] ? hwdesc : "",
1226 hwdesc[0] ? ")" : ""));
1227 pa_xfree(t);
1228 u->sink->is_hardware = 1;
1229 u->sink->refresh_volume = 1;
1230
1231 if (use_mmap)
1232 u->out_mmap_memblocks = pa_xnew0(pa_memblock*, u->out_nfrags);
1233 }
1234
1235 go_on:
1236
1237 pa_assert(u->source || u->sink);
1238
1239 u->fd = fd;
1240
1241 pa_memchunk_reset(&u->memchunk);
1242
1243 if (!(u->thread = pa_thread_new(thread_func, u))) {
1244 pa_log("Failed to create thread.");
1245 goto fail;
1246 }
1247
1248 pa_modargs_free(ma);
1249
1250 /* Read mixer settings */
1251 if (u->source)
1252 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->source), PA_SOURCE_MESSAGE_GET_VOLUME, &u->source->volume, NULL, NULL);
1253 if (u->sink)
1254 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->sink), PA_SINK_MESSAGE_GET_VOLUME, &u->sink->volume, NULL, NULL);
1255
1256 return 0;
1257
1258 fail:
1259 if (fd >= 0)
1260 close(fd);
1261
1262 if (ma)
1263 pa_modargs_free(ma);
1264
1265 return -1;
1266 }
1267
1268 void pa__done(pa_core *c, pa_module*m) {
1269 struct userdata *u;
1270
1271 pa_assert(c);
1272 pa_assert(m);
1273
1274 if (!(u = m->userdata))
1275 return;
1276
1277 if (u->sink)
1278 pa_sink_disconnect(u->sink);
1279
1280 if (u->source)
1281 pa_source_disconnect(u->source);
1282
1283 if (u->thread) {
1284 pa_asyncmsgq_send(u->asyncmsgq, NULL, PA_MESSAGE_SHUTDOWN, NULL, NULL);
1285 pa_thread_free(u->thread);
1286 }
1287
1288 if (u->asyncmsgq)
1289 pa_asyncmsgq_free(u->asyncmsgq);
1290
1291 if (u->sink)
1292 pa_sink_unref(u->sink);
1293
1294 if (u->source)
1295 pa_source_unref(u->source);
1296
1297 if (u->memchunk.memblock)
1298 pa_memblock_unref(u->memchunk.memblock);
1299
1300 if (u->out_mmap_memblocks) {
1301 unsigned i;
1302 for (i = 0; i < u->out_nfrags; i++)
1303 if (u->out_mmap_memblocks[i])
1304 pa_memblock_unref_fixed(u->out_mmap_memblocks[i]);
1305 pa_xfree(u->out_mmap_memblocks);
1306 }
1307
1308 if (u->in_mmap_memblocks) {
1309 unsigned i;
1310 for (i = 0; i < u->in_nfrags; i++)
1311 if (u->in_mmap_memblocks[i])
1312 pa_memblock_unref_fixed(u->in_mmap_memblocks[i]);
1313 pa_xfree(u->in_mmap_memblocks);
1314 }
1315
1316 if (u->in_mmap && u->in_mmap != MAP_FAILED)
1317 munmap(u->in_mmap, u->in_hwbuf_size);
1318
1319 if (u->out_mmap && u->out_mmap != MAP_FAILED)
1320 munmap(u->out_mmap, u->out_hwbuf_size);
1321
1322 if (u->fd >= 0)
1323 close(u->fd);
1324
1325 pa_xfree(u->device_name);
1326
1327 pa_xfree(u);
1328 }