• 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 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