From 382e7aefd471a4600010a04e6497d4bfd2fd8663 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Jun 2004 17:12:50 +0000 Subject: some more work git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@23 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/cli.c | 28 +++++++++++++++++++++++++--- src/memblock.c | 16 +++++++++++----- src/memblock.h | 2 +- src/memblockq.c | 24 +++++++++++++++--------- src/memblockq.h | 3 ++- src/module-oss.c | 7 +++---- src/protocol-simple.c | 21 ++++++++++----------- src/sample.c | 6 ++++++ src/sample.h | 1 + src/sink.c | 4 +++- src/sinkinput.c | 39 +++++++++++++++++++++++++++++++++++++++ src/sinkinput.h | 7 ++++++- src/sourceoutput.c | 23 +++++++++++++++++++++++ src/sourceoutput.h | 2 ++ 14 files changed, 147 insertions(+), 36 deletions(-) diff --git a/src/cli.c b/src/cli.c index 9aad7f56..4a198141 100644 --- a/src/cli.c +++ b/src/cli.c @@ -9,6 +9,8 @@ #include "sink.h" #include "source.h" #include "client.h" +#include "sinkinput.h" +#include "sourceoutput.h" struct cli { struct core *core; @@ -34,7 +36,7 @@ struct cli* cli_new(struct core *core, struct iochannel *io) { c->eof_callback = NULL; ioline_set_callback(c->line, line_callback, c); - ioline_puts(c->line, "Welcome to polypaudio!\n> "); + ioline_puts(c->line, "Welcome to polypaudio! Use \"help\" for usage information.\n> "); return c; } @@ -66,10 +68,30 @@ static void line_callback(struct ioline *line, const char *s, void *userdata) { ioline_puts(line, (t = sink_list_to_string(c->core))); else if (!strcmp(s, "clients")) ioline_puts(line, (t = client_list_to_string(c->core))); - else if (!strcmp(s, "exit")) { + else if (!strcmp(s, "source_outputs")) + ioline_puts(line, (t = source_output_list_to_string(c->core))); + else if (!strcmp(s, "sink_inputs")) + ioline_puts(line, (t = sink_input_list_to_string(c->core))); + else if (!strcmp(s, "stat")) { + char txt[256]; + snprintf(txt, sizeof(txt), "Memory blocks allocated: %u, total size: %u bytes.\n", memblock_count, memblock_total); + ioline_puts(line, txt); + } else if (!strcmp(s, "exit")) { assert(c->core && c->core->mainloop); mainloop_quit(c->core->mainloop, -1); - } else if (*s) + } else if (!strcmp(s, "help")) + ioline_puts(line, + "Available commands:\n" + " modules\t\tlist modules\n" + " sinks\t\tlist sinks\n" + " sources\t\tlist sources\n" + " clients\t\tlist clients\n" + " source_outputs\tlist source outputs\n" + " sink_inputs\t\tlist sink inputs\n" + " stat\t\tshow memblock statistics\n" + " exit\t\tterminate the daemon\n" + " help\t\tshow this help\n"); + else if (*s) ioline_puts(line, "Unknown command\n"); free(t); diff --git a/src/memblock.c b/src/memblock.c index 6f05918a..067243c5 100644 --- a/src/memblock.c +++ b/src/memblock.c @@ -5,7 +5,7 @@ #include "memblock.h" -unsigned n_blocks = 0; +unsigned memblock_count = 0, memblock_total = 0; struct memblock *memblock_new(size_t length) { struct memblock *b = malloc(sizeof(struct memblock)+length); @@ -13,7 +13,8 @@ struct memblock *memblock_new(size_t length) { b->ref = 1; b->length = length; b->data = b+1; - n_blocks++; + memblock_count++; + memblock_total += length; return b; } @@ -23,7 +24,8 @@ struct memblock *memblock_new_fixed(void *d, size_t length) { b->ref = 1; b->length = length; b->data = d; - n_blocks++; + memblock_count++; + memblock_total += length; return b; } @@ -33,7 +35,8 @@ struct memblock *memblock_new_dynamic(void *d, size_t length) { b->ref = 1; b->length = length; b->data = d; - n_blocks++; + memblock_count++; + memblock_total += length; return b; } @@ -50,8 +53,11 @@ void memblock_unref(struct memblock*b) { if (b->ref == 0) { if (b->type == MEMBLOCK_DYNAMIC) free(b->data); + + memblock_count--; + memblock_total -= b->length; + free(b); - n_blocks--; } } diff --git a/src/memblock.h b/src/memblock.h index 52f1fe50..cba11101 100644 --- a/src/memblock.h +++ b/src/memblock.h @@ -29,6 +29,6 @@ void memblock_unref_fixed(struct memblock*b); #define memblock_assert_exclusive(b) assert((b)->ref == 1) -extern unsigned n_blocks; +extern unsigned memblock_count, memblock_total; #endif diff --git a/src/memblockq.c b/src/memblockq.c index 9e9c109f..10c59e50 100644 --- a/src/memblockq.c +++ b/src/memblockq.c @@ -16,8 +16,8 @@ struct memblockq { struct memblock_list *blocks, *blocks_tail; unsigned n_blocks; size_t total_length, maxlength, base, prebuf; - int measure_latency; - uint32_t latency; + int measure_delay; + uint32_t delay; }; struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf) { @@ -38,8 +38,8 @@ struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf) { assert(bq->maxlength >= base); - bq->measure_latency = 1; - bq->latency = 0; + bq->measure_delay = 0; + bq->delay = 0; return bq; } @@ -64,7 +64,7 @@ void memblockq_push(struct memblockq* bq, struct memchunk *chunk, size_t delta) q = malloc(sizeof(struct memblock_list)); assert(q); - if (bq->measure_latency) + if (bq->measure_delay) gettimeofday(&q->stamp, NULL); else timerclear(&q->stamp); @@ -152,8 +152,8 @@ void memblockq_drop(struct memblockq *bq, size_t length) { if (l > bq->blocks->chunk.length) l = bq->blocks->chunk.length; - if (bq->measure_latency) - bq->latency = age(&bq->blocks->stamp); + if (bq->measure_delay) + bq->delay = age(&bq->blocks->stamp); bq->blocks->chunk.index += l; bq->blocks->chunk.length -= l; @@ -211,6 +211,12 @@ int memblockq_is_writable(struct memblockq *bq, size_t length) { return bq->total_length + length <= bq->maxlength; } -uint32_t memblockq_get_latency(struct memblockq *bq) { - return bq->latency; +uint32_t memblockq_get_delay(struct memblockq *bq) { + assert(bq); + return bq->delay; +} + +uint32_t memblockq_get_length(struct memblockq *bq) { + assert(bq); + return bq->total_length; } diff --git a/src/memblockq.h b/src/memblockq.h index 9543b40a..0a68ddaf 100644 --- a/src/memblockq.h +++ b/src/memblockq.h @@ -22,6 +22,7 @@ void memblockq_empty(struct memblockq *bq); int memblockq_is_readable(struct memblockq *bq); int memblockq_is_writable(struct memblockq *bq, size_t length); -uint32_t memblockq_get_latency(struct memblockq *bq); +uint32_t memblockq_get_delay(struct memblockq *bq); +uint32_t memblockq_get_length(struct memblockq *bq); #endif diff --git a/src/module-oss.c b/src/module-oss.c index 170d864d..fab5c8c5 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -25,7 +25,7 @@ struct userdata { struct memchunk memchunk, silence; - uint32_t in_fragment_size, out_fragment_size, sample_size, sample_usec; + uint32_t in_fragment_size, out_fragment_size, sample_size; int fd; }; @@ -99,7 +99,7 @@ static void io_callback(struct iochannel *io, void*userdata) { static uint32_t sink_get_latency_cb(struct sink *s) { int arg; struct userdata *u = s->userdata; - assert(s && u); + assert(s && u && u->sink); if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { fprintf(stderr, "module-oss: device doesn't support SNDCTL_DSP_GETODELAY.\n"); @@ -107,7 +107,7 @@ static uint32_t sink_get_latency_cb(struct sink *s) { return 0; } - return arg/u->sample_size*u->sample_usec; + return samples_usec(arg, &s->sample_spec); } int module_init(struct core *c, struct module*m) { @@ -204,7 +204,6 @@ int module_init(struct core *c, struct module*m) { u->memchunk.memblock = NULL; u->memchunk.length = 0; u->sample_size = sample_size(&ss); - u->sample_usec = 1000000/ss.rate; u->out_fragment_size = out_frag_size; u->in_fragment_size = in_frag_size; diff --git a/src/protocol-simple.c b/src/protocol-simple.c index 3563419e..a0a996cb 100644 --- a/src/protocol-simple.c +++ b/src/protocol-simple.c @@ -56,7 +56,6 @@ static void destroy_connection(struct connection *c) { static int do_read(struct connection *c) { struct memchunk chunk; ssize_t r; - uint32_t u1, u2; if (!iochannel_is_readable(c->io)) return 0; @@ -81,12 +80,6 @@ static int do_read(struct connection *c) { memblockq_push(c->input_memblockq, &chunk, 0); memblock_unref(chunk.memblock); sink_notify(c->sink_input->sink); - - - u1 = memblockq_get_latency(c->input_memblockq); - u2 = sink_get_latency(c->sink_input->sink); - - fprintf(stderr, "latency: %u+%u=%u\r", u1, u2, u1+u2); return 0; } @@ -120,14 +113,13 @@ static int do_write(struct connection *c) { /*** sink_input callbacks ***/ -static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk, uint8_t *volume) { +static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk) { struct connection*c = i->userdata; - assert(i && c && chunk && volume); + assert(i && c && chunk); if (memblockq_peek(c->input_memblockq, chunk) < 0) return -1; - *volume = 0xFF; return 0; } @@ -146,6 +138,13 @@ static void sink_input_kill_cb(struct sink_input *i) { destroy_connection((struct connection *) i->userdata); } + +static uint32_t sink_input_get_latency_cb(struct sink_input *i) { + struct connection*c = i->userdata; + assert(i && c); + return samples_usec(memblockq_get_length(c->input_memblockq), &DEFAULT_SAMPLE_SPEC); +} + /*** source_output callbacks ***/ static void source_output_push_cb(struct source_output *o, struct memchunk *chunk) { @@ -163,7 +162,6 @@ static void source_output_kill_cb(struct source_output *o) { destroy_connection((struct connection *) o->userdata); } - /*** client callbacks ***/ static void client_kill_cb(struct client *c) { @@ -234,6 +232,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us c->sink_input->peek = sink_input_peek_cb; c->sink_input->drop = sink_input_drop_cb; c->sink_input->kill = sink_input_kill_cb; + c->sink_input->get_latency = sink_input_get_latency_cb; c->sink_input->userdata = c; l = bytes_per_second(&DEFAULT_SAMPLE_SPEC)/2; /* half a second */ diff --git a/src/sample.c b/src/sample.c index 81fe6991..c270f255 100644 --- a/src/sample.c +++ b/src/sample.c @@ -113,3 +113,9 @@ size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, si data += sizeof(int16_t); } } + +uint32_t samples_usec(size_t length, struct sample_spec *spec) { + assert(spec); + + return (uint32_t) (((double) length /sample_size(spec))/spec->rate*1000000); +} diff --git a/src/sample.h b/src/sample.h index 23fc0883..5ed740e4 100644 --- a/src/sample.h +++ b/src/sample.h @@ -40,5 +40,6 @@ size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, si size_t bytes_per_second(struct sample_spec *spec); size_t sample_size(struct sample_spec *spec); +uint32_t samples_usec(size_t length, struct sample_spec *spec); #endif diff --git a/src/sink.c b/src/sink.c index 89f5e088..cd12b463 100644 --- a/src/sink.c +++ b/src/sink.c @@ -81,9 +81,11 @@ static unsigned fill_mix_info(struct sink *s, struct mix_info *info, unsigned ma for (i = idxset_first(s->inputs, &index); maxinfo > 0 && i; i = idxset_next(s->inputs, &index)) { assert(i->peek); - if (i->peek(i, &info->chunk, &info->volume) < 0) + if (i->peek(i, &info->chunk) < 0) continue; + info->volume = i->volume; + assert(info->chunk.memblock && info->chunk.memblock->data && info->chunk.length); info->userdata = i; diff --git a/src/sinkinput.c b/src/sinkinput.c index ae7b27ff..f589b4d9 100644 --- a/src/sinkinput.c +++ b/src/sinkinput.c @@ -3,6 +3,7 @@ #include #include "sinkinput.h" +#include "strbuf.h" struct sink_input* sink_input_new(struct sink *s, struct sample_spec *spec, const char *name) { struct sink_input *i; @@ -18,6 +19,7 @@ struct sink_input* sink_input_new(struct sink *s, struct sample_spec *spec, cons i->peek = NULL; i->drop = NULL; i->kill = NULL; + i->get_latency = NULL; i->userdata = NULL; assert(s->core); @@ -46,3 +48,40 @@ void sink_input_kill(struct sink_input*i) { if (i->kill) i->kill(i); } + +char *sink_input_list_to_string(struct core *c) { + struct strbuf *s; + struct sink_input *i; + uint32_t index = IDXSET_INVALID; + assert(c); + + s = strbuf_new(); + assert(s); + + strbuf_printf(s, "%u sink input(s) available.\n", idxset_ncontents(c->sink_inputs)); + + for (i = idxset_first(c->sink_inputs, &index); i; i = idxset_next(c->sink_inputs, &index)) { + assert(i->sink); + strbuf_printf(s, " index: %u, name: <%s>, sink: <%u>; volume: <0x%02x>, latency: <%u usec>\n", + i->index, + i->name, + i->sink->index, + (unsigned) i->volume, + sink_input_get_latency(i)); + } + + return strbuf_tostring_free(s); +} + +uint32_t sink_input_get_latency(struct sink_input *i) { + uint32_t l = 0; + + assert(i); + if (i->get_latency) + l += i->get_latency(i); + + assert(i->sink); + l += sink_get_latency(i->sink); + + return l; +} diff --git a/src/sinkinput.h b/src/sinkinput.h index 5e71d210..f62070c4 100644 --- a/src/sinkinput.h +++ b/src/sinkinput.h @@ -13,10 +13,13 @@ struct sink_input { char *name; struct sink *sink; struct sample_spec spec; + uint8_t volume; - int (*peek) (struct sink_input *i, struct memchunk *chunk, uint8_t *volume); + int (*peek) (struct sink_input *i, struct memchunk *chunk); void (*drop) (struct sink_input *i, size_t length); void (*kill) (struct sink_input *i); + uint32_t (*get_latency) (struct sink_input *i); + void *userdata; }; @@ -28,5 +31,7 @@ void sink_input_free(struct sink_input* i); * request destruction of it */ void sink_input_kill(struct sink_input *i); +uint32_t sink_input_get_latency(struct sink_input *i); +char *sink_input_list_to_string(struct core *c); #endif diff --git a/src/sourceoutput.c b/src/sourceoutput.c index d4e7a50f..8021b522 100644 --- a/src/sourceoutput.c +++ b/src/sourceoutput.c @@ -3,6 +3,7 @@ #include #include "sourceoutput.h" +#include "strbuf.h" struct source_output* source_output_new(struct source *s, struct sample_spec *spec, const char *name) { struct source_output *o; @@ -45,3 +46,25 @@ void source_output_kill(struct source_output*i) { if (i->kill) i->kill(i); } + +char *source_output_list_to_string(struct core *c) { + struct strbuf *s; + struct source_output *o; + uint32_t index = IDXSET_INVALID; + assert(c); + + s = strbuf_new(); + assert(s); + + strbuf_printf(s, "%u source outputs(s) available.\n", idxset_ncontents(c->source_outputs)); + + for (o = idxset_first(c->source_outputs, &index); o; o = idxset_next(c->source_outputs, &index)) { + assert(o->source); + strbuf_printf(s, " %c index: %u, name: <%s>, source: <%u>\n", + o->index, + o->name, + o->source->index); + } + + return strbuf_tostring_free(s); +} diff --git a/src/sourceoutput.h b/src/sourceoutput.h index fecfea34..359ff151 100644 --- a/src/sourceoutput.h +++ b/src/sourceoutput.h @@ -25,4 +25,6 @@ void source_output_free(struct source_output* o); void source_output_kill(struct source_output*o); +char *source_output_list_to_string(struct core *c); + #endif -- cgit