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
75PA_MODULE_AUTHOR("Lennart Poettering");
76PA_MODULE_DESCRIPTION("OSS Sink/Source");
77PA_MODULE_VERSION(PACKAGE_VERSION);
78PA_MODULE_LOAD_ONCE(false);
79PA_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__
95PA_MODULE_DEPRECATED("Please use module-alsa-card instead of module-oss!");
96#endif
97
98#define DEFAULT_DEVICE "/dev/dsp"
99
100struct 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
141static 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. */
162static 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
228static 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
260static 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
282static 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
314static 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
337static 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
362static 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
387static 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
411static 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
457static 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
475static 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 */
492static 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 */
540static 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
639fail:
640    pa_close(u->fd);
641    u->fd = -1;
642    return -1;
643}
644
645/* Called from IO context */
646static 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. */
671static 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
735static 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. */
759static 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
822static 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
840static 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
854static 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
876static 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
893static 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
1173fail:
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
1180int 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
1482go_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
1523fail:
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
1536void 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