"Fossies" - the Fresh Open Source Software Archive

Member "pulseaudio-13.0/src/modules/oss/module-oss.c" (13 Sep 2019, 48667 Bytes) of package /linux/misc/pulseaudio-13.0.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "module-oss.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 12.2_vs_13.0.

    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. */
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 
  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 */
  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 */
  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 */
  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. */
  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 
  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. */
  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 
  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 
  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 
  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 
  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 
  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 
 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 
 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 }