X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=alsa_write.c;h=53854e08c012dd7952df4d94ce50dae987dc004a;hp=a4863a59a5bc3a426a08e6a69d333bded736d780;hb=dc26e5bc49d839fd966b7ad6f596e444ac8908d3;hpb=1cefe6a503c74d609db4e99e689d46575a5e40fd diff --git a/alsa_write.c b/alsa_write.c index a4863a59..53854e08 100644 --- a/alsa_write.c +++ b/alsa_write.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2012 Andre Noll + * Copyright (C) 2005-2013 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -15,7 +15,6 @@ #include #include #include -#include #include "para.h" #include "fd.h" @@ -35,16 +34,21 @@ struct private_alsa_write_data { snd_pcm_t *handle; /** Determined and set by alsa_init(). */ int bytes_per_frame; - /** - * The sample rate given by command line option or the decoder - * of the writer node group. + /* + * If the sample rate is not given at the command line and no wav + * header was detected, the btr exec mechanism is employed to query the + * ancestor buffer tree nodes for this information. In a typical setup + * the decoder passes the sample rate back to the alsa writer. + * + * \sa \ref btr_exec_up(). */ unsigned sample_rate; - snd_pcm_format_t sample_format; - /** - * The number of channels, given by command line option or the - * decoder of the writer node group. + /* + * The sample format (8/16 bit, signed/unsigned, little/big endian) is + * determined in the same way as the \a sample_rate. */ + snd_pcm_format_t sample_format; + /* The number of channels, again determined like \a sample_rate. */ unsigned channels; struct timeval drain_barrier; /* File descriptor for select(). */ @@ -72,7 +76,7 @@ static int alsa_init(struct private_alsa_write_data *pad, snd_pcm_sw_params_t *swparams; snd_pcm_uframes_t start_threshold, stop_threshold; snd_pcm_uframes_t buffer_size, period_size; - snd_output_t *log; + snd_output_t *output_log; unsigned buffer_time; int ret; const char *msg; @@ -113,6 +117,8 @@ static int alsa_init(struct private_alsa_write_data *pad, NULL); if (ret < 0 || buffer_time == 0) goto fail; + /* buffer at most 500 milliseconds */ + buffer_time = PARA_MIN(buffer_time, 500U * 1000U); msg = "could not set buffer time"; ret = snd_pcm_hw_params_set_buffer_time_near(pad->handle, hwparams, &buffer_time, NULL); @@ -161,21 +167,22 @@ static int alsa_init(struct private_alsa_write_data *pad, ret = snd_pcm_nonblock(pad->handle, 1); if (ret < 0) goto fail; - ret = snd_output_buffer_open(&log); + ret = snd_output_buffer_open(&output_log); if (ret == 0) { - char *buf; + char *buf, *p; + size_t sz; PARA_INFO_LOG("dumping alsa configuration\n"); - snd_pcm_dump(pad->handle, log); - snd_output_buffer_string(log, &buf); - for (;;) { - char *p = strchr(buf, '\n'); - if (!p) /* omit last output line, it's empty */ + snd_pcm_dump(pad->handle, output_log); + sz = snd_output_buffer_string(output_log, &buf); + for (p = buf; p < buf + sz;) { + char *q = memchr(p, '\n', buf + sz - p); + if (!q) break; - *p = '\0'; - PARA_INFO_LOG("%s\n", buf); - buf = p + 1; + *q = '\0'; + PARA_INFO_LOG("%s\n", p); + p = q + 1; } - snd_output_close(log); + snd_output_close(output_log); } return 1; fail: @@ -209,7 +216,6 @@ static void alsa_write_pre_select(struct sched *s, struct task *t) if (ret < 0) { PARA_ERROR_LOG("could not get alsa poll fd: %s\n", snd_strerror(-ret)); - t->error = -E_ALSA; return; } pad->poll_fd = pfd.fd; @@ -234,7 +240,7 @@ static void alsa_close(struct writer_node *wn) free(pad); } -static void alsa_write_post_select(__a_unused struct sched *s, +static int alsa_write_post_select(__a_unused struct sched *s, struct task *t) { struct writer_node *wn = container_of(t, struct writer_node, task); @@ -245,11 +251,13 @@ static void alsa_write_post_select(__a_unused struct sched *s, snd_pcm_sframes_t frames; int ret; + ret = task_get_notification(t); + if (ret < 0) + goto err; again: - t->error = 0; ret = btr_node_status(btrn, wn->min_iqs, BTR_NT_LEAF); if (ret == 0) - return; + return 0; btr_merge(btrn, wn->min_iqs); bytes = btr_next_buffer(btrn, &data); if (ret < 0 || bytes < wn->min_iqs) { /* eof */ @@ -262,17 +270,17 @@ again: PARA_DEBUG_LOG("waiting for device to drain\n"); tv_add(now, &(struct timeval)EMBRACE(0, 200 * 1000), &pad->drain_barrier); - return; + return 0; } if (tv_diff(now, &pad->drain_barrier, NULL) > 0) goto err; - return; + return 0; } if (!pad) { int32_t val; if (bytes == 0) /* no data available */ - return; + return 0; pad = para_calloc(sizeof(*pad)); get_btr_sample_rate(btrn, &val); pad->sample_rate = val; @@ -293,7 +301,7 @@ again: goto again; } if (pad->poll_fd < 0 || !FD_ISSET(pad->poll_fd, &s->rfds)) - return; + return 0; frames = bytes / pad->bytes_per_frame; frames = snd_pcm_writei(pad->handle, data, frames); if (frames == 0 || frames == -EAGAIN) { @@ -307,7 +315,7 @@ again: char buf[100]; if (read(pad->poll_fd, buf, 100)) do_nothing; - return; + return 0; } if (frames > 0) { btr_consume(btrn, frames * pad->bytes_per_frame); @@ -316,28 +324,28 @@ again: if (frames == -EPIPE) { PARA_WARNING_LOG("underrun (tried to write %zu bytes)\n", bytes); snd_pcm_prepare(pad->handle); - return; + return 0; } PARA_ERROR_LOG("alsa write error: %s\n", snd_strerror(-frames)); ret = -E_ALSA; err: assert(ret < 0); - btr_remove_node(btrn); - t->error = ret; + btr_remove_node(&wn->btrn); + return ret; } -__malloc static void *alsa_parse_config_or_die(const char *options) +__malloc static void *alsa_parse_config_or_die(int argc, char **argv) { struct alsa_write_args_info *conf = para_calloc(sizeof(*conf)); /* exits on errors */ - alsa_cmdline_parser_string(options, conf, "alsa_write"); + alsa_write_cmdline_parser(argc, argv, conf); return conf; } static void alsa_free_config(void *conf) { - alsa_cmdline_parser_free(conf); + alsa_write_cmdline_parser_free(conf); } /** @@ -351,16 +359,12 @@ void alsa_write_init(struct writer *w) { struct alsa_write_args_info dummy; - alsa_cmdline_parser_init(&dummy); + alsa_write_cmdline_parser_init(&dummy); w->close = alsa_close; w->pre_select = alsa_write_pre_select; w->post_select = alsa_write_post_select; w->parse_config_or_die = alsa_parse_config_or_die; - w->shutdown = NULL; /* nothing to do */ w->free_config = alsa_free_config; - w->help = (struct ggo_help) { - .short_help = alsa_write_args_info_help, - .detailed_help = alsa_write_args_info_detailed_help - }; - alsa_cmdline_parser_free(&dummy); + w->help = (struct ggo_help)DEFINE_GGO_HELP(alsa_write); + alsa_write_cmdline_parser_free(&dummy); }