From 263c9ec8129b345b3e9310f544a1e3dbcf425c6f Mon Sep 17 00:00:00 2001 From: Andre Date: Tue, 18 Apr 2006 05:28:55 +0200 Subject: [PATCH] Further para_play abstraction: struct writer_node_group This structure contains the list of writer nodes and information common to all of these nodes. The idea is that the wng group code will be shared between para_audiod and para_play. --- play.c | 189 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 124 insertions(+), 65 deletions(-) diff --git a/play.c b/play.c index d98a4baa..f312626c 100644 --- a/play.c +++ b/play.c @@ -51,10 +51,20 @@ struct writer { void (*shutdown)(struct writer_node *); }; +struct writer_node_group { + unsigned num_writers; + struct writer_node *writer_nodes; + int *written; + size_t max_chunk_bytes; + int eof; +}; + + +#define FOR_EACH_WRITER_NODE(i, wng) for (i = 0; i < (wng)->num_writers; i++) + #define NUM_WRITERS 1 static struct writer writers[NUM_WRITERS]; #define FOR_EACH_WRITER(i) for (i = 0; i < NUM_WRITERS, i++) -static struct writer_node *writer_nodes; static unsigned char *audiobuf; @@ -281,6 +291,77 @@ static int read_stdin(char *buf, size_t bytes_to_load, size_t *loaded) return 1; } +int wng_write(struct writer_node_group *g, char *buf, size_t *loaded) +{ + int ret, i, need_more_writes = 1; + size_t min_written = 0; + + while (need_more_writes) { + need_more_writes = 0; + FOR_EACH_WRITER_NODE(i, g) { + size_t w = g->written[i]; + unsigned char *p = buf + w; + int bytes_to_write; + struct writer_node *wn = &g->writer_nodes[i]; + if (!i) + min_written = w; + else + min_written = PARA_MIN(min_written, w); + if (w == *loaded) + continue; + if (!g->eof && (*loaded < wn->chunk_bytes + w)) + continue; + bytes_to_write = PARA_MIN(wn->chunk_bytes, + *loaded - w); + ret = wn->writer->write(p, bytes_to_write, wn); + if (ret < 0) + goto out; + if (ret != bytes_to_write) + PARA_WARNING_LOG("short write: %d/%d\n", ret, + bytes_to_write); + g->written[i] += ret; + need_more_writes = 1; + } + } + *loaded -= min_written; + ret = 0; + if (g->eof) + goto out; + if (*loaded) + memmove(buf, buf + min_written, *loaded); + FOR_EACH_WRITER_NODE(i, g) + g->written[i] -= min_written; + ret = 1; +out: + return ret; +} + +int wng_open(struct writer_node_group *g) +{ + int i, ret = 1; + + FOR_EACH_WRITER_NODE(i, g) { + struct writer_node *wn = &g->writer_nodes[i]; + ret = wn->writer->open(wn); + if (ret < 0) + goto out; + wn->chunk_bytes = ret; + g->max_chunk_bytes = PARA_MAX(g->max_chunk_bytes, ret); + } +out: + return ret; +} + +void wng_close(struct writer_node_group *g) +{ + int i; + + FOR_EACH_WRITER_NODE(i, g) { + struct writer_node *wn = &g->writer_nodes[i]; + wn->writer->close(wn); + } +} + /** * play raw pcm data * \param loaded number of bytes already loaded @@ -291,27 +372,21 @@ static int read_stdin(char *buf, size_t bytes_to_load, size_t *loaded) * * \return positive on success, negative on errors. */ -static int play_pcm(size_t loaded) +static int pcm_write(struct writer_node_group *wng, size_t loaded) { - size_t bufsize, min_written = 0, prebuf_size, bytes_to_load; + size_t bufsize, prebuf_size, bytes_to_load; struct timeval delay; - int eof = 0, i, max_chunk_bytes = 0, ret, not_yet_started = 1, need_more_writes; - struct writer_node *wn; - size_t *written = para_calloc(1 * sizeof(size_t)); + int ret, not_yet_started = 1; - for (i = 0; i < 1; i++) { - wn = &writer_nodes[i]; - ret = wn->writer->open(wn); - if (ret < 0) - goto out; - wn->chunk_bytes = ret; - max_chunk_bytes = PARA_MAX(max_chunk_bytes, ret); - } - PARA_INFO_LOG("max chunk_bytes: %d\n", max_chunk_bytes); - bufsize = (conf.bufsize_arg * 1024 / max_chunk_bytes) * max_chunk_bytes; + ret = wng_open(wng); + if (ret < 0) + goto out; + PARA_INFO_LOG("max chunk_bytes: %d\n", wng->max_chunk_bytes); + bufsize = (conf.bufsize_arg * 1024 / wng->max_chunk_bytes) + * wng->max_chunk_bytes; audiobuf = para_realloc(audiobuf, bufsize); prebuf_size = conf.prebuffer_arg * bufsize / 100; - bytes_to_load = PARA_MAX(prebuf_size, max_chunk_bytes); + bytes_to_load = PARA_MAX(prebuf_size, wng->max_chunk_bytes); ret = read_stdin(audiobuf, bytes_to_load, &loaded); if (ret <= 0 || loaded < bytes_to_load) { if (ret >= 0) @@ -322,60 +397,43 @@ static int play_pcm(size_t loaded) do_initial_delay(&delay); not_yet_started = 0; again: - need_more_writes = 1; - while (need_more_writes) { - need_more_writes = 0; - for (i = 0; i < 1; i++) { - unsigned char *p = audiobuf + written[i]; - int bytes_to_write; - wn = &writer_nodes[i]; - if (!i) - min_written = written[i]; - else - min_written = PARA_MIN(min_written, written[i]); - if (loaded == written[i]) - continue; - if (!eof && (loaded < wn->chunk_bytes + written[i])) - continue; - bytes_to_write = PARA_MIN(wn->chunk_bytes, - loaded - written[i]); - ret = wn->writer->write(p, bytes_to_write, wn); - if (ret < 0) - goto out; - if (ret != bytes_to_write) - PARA_WARNING_LOG("short write: %d/%d\n", ret, - bytes_to_write); - written[i] += ret; - need_more_writes = 1; - } - } - loaded -= min_written; - ret = 0; - if (eof) + ret = wng_write(wng, audiobuf, &loaded); + if (ret <= 0) goto out; - if (loaded >= bufsize) { - ret = -E_PLAY_OVERRUN; + ret = -E_PLAY_OVERRUN; + if (loaded >= bufsize) goto out; - } - memmove(audiobuf, audiobuf + min_written, loaded); - for (i = 0; i < 1; i++) - written[i] -= min_written; - bytes_to_load = PARA_MIN(max_chunk_bytes, bufsize); + bytes_to_load = PARA_MIN(wng->max_chunk_bytes, bufsize); ret = read_stdin(audiobuf, bytes_to_load, &loaded); if (ret < 0) goto out; if (!ret) - eof = 1; + wng->eof = 1; goto again; out: - free(written); - for (i = 0; i < 1; i++) { - wn = &writer_nodes[i]; - wn->writer->close(wn); - } + wng_close(wng); return ret; } +struct writer_node_group *wng_new(unsigned num_writers) +{ + struct writer_node_group *g = para_calloc(sizeof(struct writer_node_group)); + g->num_writers = num_writers; + g->writer_nodes = para_calloc(num_writers + * sizeof(struct writer_node)); + g->written = para_calloc(num_writers * sizeof(size_t)); + return g; +} + +void wng_destroy(struct writer_node_group *g) +{ + if (!g) + return; + free(g->written); + free(g->writer_nodes); + free(g); +} + /** * test if audio buffer contains a valid wave header * @@ -396,6 +454,7 @@ int main(int argc, char *argv[]) { struct timeval tv; int ret = -E_PLAY_SYNTAX; + struct writer_node_group *wng = NULL; cmdline_parser(argc, argv, &conf); if (conf.prebuffer_arg < 0 || conf.prebuffer_arg > 100) @@ -408,18 +467,18 @@ int main(int argc, char *argv[]) } /* call init for each supported writer */ alsa_writer_init(&writers[0]); - /* one for each given writer */ - writer_nodes = para_calloc(2 * sizeof(struct writer_node)); - writer_nodes[0].writer = &writers[0]; /* alsa */ + + wng = wng_new(1); + wng->writer_nodes[0].writer = &writers[0]; /* alsa */ audiobuf = para_malloc(WAV_HEADER_LEN); ret = read_wav_header(); if (ret < 0) goto out; - ret = play_pcm(check_wave()); + ret = pcm_write(wng, check_wave()); out: + wng_destroy(wng); free(audiobuf); - free(writer_nodes); if (ret < 0) PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret)); return ret; -- 2.39.2