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