]> git.tuebingen.mpg.de Git - paraslash.git/blobdiff - ao_write.c
ao_write: Enforce a 20ms timeout.
[paraslash.git] / ao_write.c
index a45d4fb946eea25087746fc786712229dae0dacc..fc65af60b3ca06735474e95c89de25387c1c9702 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2012 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 2011-2014 Andre Noll <maan@systemlinux.org>
  *
  * Licensed under the GPL v2. For licencing details see COPYING.
  */
@@ -48,10 +48,26 @@ static void aow_close(struct writer_node *wn)
 static void aow_pre_select(struct sched *s, struct task *t)
 {
        struct writer_node *wn = container_of(t, struct writer_node, task);
-       int ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF);
+       struct private_aow_data *pawd = wn->private_data;
+       int ret;
 
-       if (ret == 0)
-               return;
+       if (pawd)
+               pthread_mutex_lock(&pawd->mutex);
+       ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF);
+       if (pawd)
+               pthread_mutex_unlock(&pawd->mutex);
+
+       if (ret == 0) {
+               /*
+                * Even though the node status is zero, we might have data
+                * available, but the output buffer is full. If we don't set a
+                * timeout here, we are woken up only if new data arrives,
+                * which might be too late and result in a buffer underrun in
+                * the playing thread. To avoid this we never sleep longer than
+                * the (default) buffer time.
+                */
+               return sched_request_timeout_ms(20, s);
+       }
        sched_min_delay(s);
 }
 
@@ -223,7 +239,9 @@ __noreturn static void *aow_play(void *priv)
                ret = -E_AO_PLAY;
                if (ao_play(pawd->dev, data, bytes) == 0) /* failure */
                        goto out;
+               pthread_mutex_lock(&pawd->mutex);
                btr_consume(btrn, bytes);
+               pthread_mutex_unlock(&pawd->mutex);
        }
 unlock:
        pthread_mutex_unlock(&pawd->mutex);
@@ -276,7 +294,7 @@ fail:
        return -E_AO_PTHREAD;
 }
 
-static void aow_post_select(__a_unused struct sched *s,
+static int aow_post_select(__a_unused struct sched *s,
                struct task *t)
 {
        struct writer_node *wn = container_of(t, struct writer_node, task);
@@ -291,7 +309,7 @@ static void aow_post_select(__a_unused struct sched *s,
                if (ret < 0)
                        goto remove_btrn;
                if (ret == 0)
-                       return;
+                       return 0;
                get_btr_sample_rate(wn->btrn, &rate);
                get_btr_channels(wn->btrn, &ch);
                get_btr_sample_format(wn->btrn, &format);
@@ -312,7 +330,7 @@ static void aow_post_select(__a_unused struct sched *s,
                ret = aow_create_thread(wn);
                if (ret < 0)
                        goto remove_thread_btrn;
-               return;
+               return 0;
        }
        pthread_mutex_lock(&pawd->mutex);
        ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF);
@@ -334,21 +352,21 @@ remove_thread_btrn:
 remove_btrn:
        btr_remove_node(&wn->btrn);
 out:
-       t->error = ret;
+       return ret;
 }
 
-__malloc static void *aow_parse_config_or_die(const char *options)
+__malloc static void *aow_parse_config_or_die(int argc, char **argv)
 {
        struct ao_write_args_info *conf = para_calloc(sizeof(*conf));
 
        /* exits on errors */
-       ao_cmdline_parser_string(options, conf, "ao_write");
+       ao_write_cmdline_parser(argc, argv, conf);
        return conf;
 }
 
 static void aow_free_config(void *conf)
 {
-       ao_cmdline_parser_free(conf);
+       ao_write_cmdline_parser_free(conf);
 }
 
 /**
@@ -365,15 +383,13 @@ void ao_write_init(struct writer *w)
        ao_info **driver_list;
        char **dh; /* detailed help */
 
-       ao_cmdline_parser_init(&dummy);
+       ao_write_cmdline_parser_init(&dummy);
        w->close = aow_close;
        w->pre_select = aow_pre_select;
        w->post_select = aow_post_select;
        w->parse_config_or_die = aow_parse_config_or_die;
        w->free_config = aow_free_config;
-       w->help = (struct ggo_help) {
-               .short_help = ao_write_args_info_help,
-       };
+       w->help = (struct ggo_help)DEFINE_GGO_HELP(ao_write);
        /* create detailed help containing all supported drivers/options */
        for (i = 0; ao_write_args_info_detailed_help[i]; i++)
                ; /* nothing */
@@ -411,7 +427,7 @@ void ao_write_init(struct writer *w)
        }
        dh[num_lines] = NULL;
        w->help.detailed_help = (const char **)dh;
-       ao_cmdline_parser_free(&dummy);
+       ao_write_cmdline_parser_free(&dummy);
        ao_shutdown();
 }