]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge branch 'maint'
authorAndre Noll <maan@systemlinux.org>
Wed, 12 May 2010 22:37:37 +0000 (00:37 +0200)
committerAndre Noll <maan@systemlinux.org>
Wed, 12 May 2010 22:37:37 +0000 (00:37 +0200)
1  2 
oss_write.c

diff --combined oss_write.c
index 10a64497d58b9c024aa9d1097bd7976da3b79883,48545630a5d10865c3fc174fdfc7e1bbc6b7c7a6..d0cff0150bf9c7690ffe2eb37f0a55b46d142c00
@@@ -1,17 -1,15 +1,17 @@@
  /*
 - * Copyright (C) 2009 Andre Noll <maan@systemlinux.org>
 + * Copyright (C) 2009-2010 Andre Noll <maan@systemlinux.org>
   *
   * Licensed under the GPL v2. For licencing details see COPYING.
   */
  
  /** \file oss_write.c Paraslash's oss output plugin. */
  
 +#include <regex.h>
  #include <sys/ioctl.h>
  #include <fcntl.h>
  #include <dirent.h>
  #include <sys/soundcard.h>
 +#include <stdbool.h>
  
  #include "para.h"
  #include "fd.h"
@@@ -19,9 -17,7 +19,9 @@@
  #include "list.h"
  #include "sched.h"
  #include "ggo.h"
 +#include "buffer_tree.h"
  #include "write.h"
 +#include "write_common.h"
  #include "oss_write.cmdline.h"
  #include "error.h"
  
  struct private_oss_write_data {
        /** The file handle of the device. */
        int fd;
 -      /**
 -       * The samplerate given by command line option or the decoder
 -       * of the writer node group.
 -       */
 -      int samplerate;
 -      /**
 -       * The number of channels, given by command line option or the
 -       * decoder of the writer node group.
 -       */
 -      int channels;
        /** Four bytes for stereo streams, two bytes for mono streams. */
        int bytes_per_frame;
  };
  
 -static int oss_pre_select(struct sched *s, struct writer_node *wn)
 +static void oss_pre_select(struct sched *s, struct task *t)
  {
 +      struct writer_node *wn = container_of(t, struct writer_node, task);
        struct private_oss_write_data *powd = wn->private_data;
 -      struct writer_node_group *wng = wn->wng;
 -
 -      if (*wng->loaded - wn->written < powd->bytes_per_frame)
 -              return 0;
 -      para_fd_set(powd->fd, &s->wfds, &s->max_fileno);
 -      return 1;
 -}
 +      int ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF);
  
 -static int oss_post_select(struct sched *s, struct writer_node *wn)
 -{
 -      int ret;
 -      struct private_oss_write_data *powd = wn->private_data;
 -      struct writer_node_group *wng = wn->wng;
 -      size_t frames, bytes = *wng->loaded - wn->written;
 -      char *data = *wng->bufp + wn->written;
 -
 -      if (*wng->input_error < 0 && bytes < powd->bytes_per_frame) {
 -              wn->written = *wng->loaded;
 -              return *wng->input_error;
 -      }
 -      frames = bytes / powd->bytes_per_frame;
 -      if (!frames) /* less than a single frame available */
 -              goto out;
 -      if (!FD_ISSET(powd->fd, &s->wfds))
 -              goto out;
 -      ret = write_nonblock(powd->fd, data, frames * powd->bytes_per_frame, 0);
 +      t->error = 0;
        if (ret < 0)
 -              return ret;
 -      wn->written += ret;
 -out:
 -      return 1;
 +              sched_min_delay(s);
 +      else if (ret > 0)
 +              para_fd_set(powd->fd, &s->wfds, &s->max_fileno);
  }
  
  static void oss_close(struct writer_node *wn)
  {
        struct private_oss_write_data *powd = wn->private_data;
  
-       close(powd->fd);
+       if (powd->fd >= 0)
+               close(powd->fd);
        free(powd);
  }
  
   * incorrectly believe that the device is still in 44.1 kHz mode when actually
   * the speed is decreased to 22.05 kHz.
   */
 -static int oss_open(struct writer_node *wn)
 +static int oss_init(struct writer_node *wn, unsigned samplerate, unsigned channels)
  {
 -      int ret, format = FORMAT, channels, samplerate;
 +      int ret, format = FORMAT;
 +      unsigned ch, rate;
        struct oss_write_args_info *conf = wn->conf;
 -      struct writer_node_group *wng = wn->wng;
 -      struct private_oss_write_data *powd;
 +      struct private_oss_write_data *powd = wn->private_data;
  
        PARA_INFO_LOG("opening %s\n", conf->device_arg);
        ret = para_open(conf->device_arg, O_WRONLY, 0);
        if (ret < 0)
                return ret;
 -      powd = para_calloc(sizeof(*powd));
 -      wn->private_data = powd;
        powd->fd = ret;
        ret = mark_fd_nonblocking(powd->fd);
        if (ret < 0)
        if (format != FORMAT)
                goto err;
        /* set number of channels */
 -      if (!conf->channels_given && wng->channels)
 -              channels = *wng->channels;
 -      else
 -              channels = conf->channels_arg;
        ret = -E_BAD_CHANNEL_COUNT;
        if (channels == 0)
                goto err;
 -      powd->channels = channels;
 -      ret = ioctl(powd->fd, SNDCTL_DSP_CHANNELS, &channels);
 +      ch = channels;
 +      ret = ioctl(powd->fd, SNDCTL_DSP_CHANNELS, &ch);
        if (ret < 0) {
                ret = -ERRNO_TO_PARA_ERROR(errno);
                goto err;
        }
 -      if (powd->channels != channels)
 +      ret = -E_BAD_CHANNEL_COUNT;
 +      if (ch != channels)
                goto err;
 -      powd->bytes_per_frame = channels * 2;
 +      powd->bytes_per_frame = ch * 2;
  
        /*
         * Set sampling rate
         * device, the the highest possible speed is automatically used. The
         * value actually used is returned as the new value of the argument.
         */
 -      if (!conf->samplerate_given && wng->samplerate)
 -              samplerate = *wng->samplerate;
 -      else
 -              samplerate = conf->samplerate_arg;
 -      powd->samplerate = samplerate;
 -      ret = ioctl(powd->fd, SNDCTL_DSP_SPEED, &samplerate);
 +      rate = samplerate;
 +      ret = ioctl(powd->fd, SNDCTL_DSP_SPEED, &rate);
        if (ret < 0) {
                ret = -ERRNO_TO_PARA_ERROR(errno);
                goto err;
        }
 -      if (samplerate != powd->samplerate) {
 -              int min = PARA_MIN(samplerate, powd->samplerate),
 -                      max = PARA_MAX(samplerate, powd->samplerate);
 +      if (rate != samplerate) {
 +              unsigned min = PARA_MIN(rate, samplerate),
 +                      max = PARA_MAX(rate, samplerate);
                /*
                 * Check whether the returned sample rate differs significantly
                 * from the requested one.
                ret = -E_BAD_SAMPLERATE;
                if (100 * max > 110 * min) /* more than 10% deviation */
                        goto err;
 -              PARA_NOTICE_LOG("using %dHz rather than %dHz\n", samplerate,
 -                      powd->samplerate);
 +              PARA_NOTICE_LOG("using %dHz rather than %dHz\n", rate,
 +                      samplerate);
        }
 -
 +      wn->min_iqs = powd->bytes_per_frame;
        return 1;
  err:
        close(powd->fd);
-       free(powd);
+       powd->fd = -1;
        return ret;
  }
  
 +static void oss_post_select(__a_unused struct sched *s,
 +              struct task *t)
 +{
 +      struct writer_node *wn = container_of(t, struct writer_node, task);
 +      struct oss_write_args_info *conf = wn->conf;
 +      struct private_oss_write_data *powd = wn->private_data;
 +      struct btr_node *btrn = wn->btrn;
 +      size_t frames, bytes;
 +      int ret = btr_node_status(btrn, wn->min_iqs, BTR_NT_LEAF);
 +      char *data;
 +
 +      if (ret < 0)
 +              goto out;
 +      if (ret == 0)
 +              return;
 +      if (powd->fd < 0) {
 +              int32_t rate, ch;
 +              ret = -1;
 +              if (!conf->samplerate_given) /* config option trumps btr_exec */
 +                      ret = get_btr_samplerate(wn->btrn, &rate);
 +              if (ret < 0)
 +                      rate = conf->samplerate_arg;
 +              ret = -1;
 +              if (!conf->channels_given)
 +                      ret = get_btr_channels(wn->btrn, &ch);
 +              if (ret < 0)
 +                      ch = conf->channels_arg;
 +              ret = oss_init(wn, rate, ch);
 +              if (ret < 0)
 +                      goto out;
 +              return;
 +      }
 +      bytes = btr_next_buffer(btrn, &data);
 +      frames = bytes / powd->bytes_per_frame;
 +      if (!frames) { /* eof and less than a single frame available */
 +              ret = -E_OSS_EOF;
 +              goto out;
 +      }
 +      ret = 0;
 +      if (!FD_ISSET(powd->fd, &s->wfds))
 +              goto out;
 +      ret = write_nonblock(powd->fd, data, frames * powd->bytes_per_frame, 0);
 +      if (ret < 0)
 +              goto out;
 +      btr_consume(btrn, ret);
 +      ret = 0;
 +out:
 +      t->error = ret;
 +      if (ret < 0)
 +              btr_remove_node(btrn);
 +}
 +
 +static int oss_open(struct writer_node *wn)
 +{
 +      struct private_oss_write_data *powd;
 +
 +      powd = para_calloc(sizeof(*powd));
 +      wn->private_data = powd;
 +      powd->fd = -1;
 +      return 1;
 +}
 +
  __malloc static void *oss_parse_config(const char *options)
  {
        int ret;
        struct oss_write_args_info *conf = para_calloc(sizeof(*conf));
  
 -      PARA_INFO_LOG("options: %s, %zd\n", options, strcspn(options, " \t"));
        ret = oss_cmdline_parser_string(options, conf, "oss_write");
        if (ret)
                goto err_out;
@@@ -217,11 -195,6 +218,11 @@@ err_out
        return NULL;
  }
  
 +static void oss_free_config(void *conf)
 +{
 +      oss_cmdline_parser_free(conf);
 +}
 +
  /**
   * The init function of the oss writer.
   *
@@@ -239,7 -212,6 +240,7 @@@ void oss_write_init(struct writer *w
        w->pre_select = oss_pre_select;
        w->post_select = oss_post_select;
        w->parse_config = oss_parse_config;
 +      w->free_config = oss_free_config;
        w->shutdown = NULL;
        w->help = (struct ggo_help) {
                .short_help = oss_write_args_info_help,