From c524b4c5b59a11c0a85d27d64dfb607246abc141 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 Feb 2010 02:10:45 +0100 Subject: memblockq: implement new call pa_memblockq_peek_fixed_size() --- src/pulsecore/memblockq.c | 71 +++++++++++++++++++++++++++++++++++++++++++++- src/pulsecore/memblockq.h | 5 ++++ src/tests/memblockq-test.c | 44 ++++++++++++++++++++-------- 3 files changed, 107 insertions(+), 13 deletions(-) diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index 2b063fac..c7840484 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -481,7 +481,6 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { /* Do we need to spit out silence? */ if (!bq->current_read || bq->current_read->index > bq->read_index) { - size_t length; /* How much silence shall we return? */ @@ -527,6 +526,76 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { return 0; } +int pa_memblockq_peek_fixed_size(pa_memblockq *bq, size_t block_size, pa_memchunk *chunk) { + pa_memchunk tchunk, rchunk; + int64_t ri; + struct list_item *item; + + pa_assert(bq); + pa_assert(block_size > 0); + pa_assert(chunk); + pa_assert(bq->silence.memblock); + + if (pa_memblockq_peek(bq, &tchunk) < 0) + return -1; + + if (tchunk.length >= block_size) { + *chunk = tchunk; + chunk->length = block_size; + return 0; + } + + rchunk.memblock = pa_memblock_new(pa_memblock_get_pool(tchunk.memblock), block_size); + rchunk.index = 0; + rchunk.length = tchunk.length; + + pa_memchunk_memcpy(&rchunk, &tchunk); + pa_memblock_unref(tchunk.memblock); + + rchunk.index += tchunk.length; + + /* We don't need to call fix_current_read() here, since + * pa_memblock_peek() already did that */ + item = bq->current_read; + ri = bq->read_index + tchunk.length; + + while (rchunk.index < block_size) { + + if (!item || item->index > ri) { + /* Do we need to append silence? */ + tchunk = bq->silence; + + if (item) + tchunk.length = PA_MIN(tchunk.length, (size_t) (item->index - ri)); + + } else { + int64_t d; + + /* We can append real data! */ + tchunk = item->chunk; + + d = ri - item->index; + tchunk.index += (size_t) d; + tchunk.length -= (size_t) d; + + /* Go to next item for the next iteration */ + item = item->next; + } + + rchunk.length = tchunk.length = PA_MIN(tchunk.length, block_size - rchunk.index); + pa_memchunk_memcpy(&rchunk, &tchunk); + + rchunk.index += rchunk.length; + ri += rchunk.length; + } + + rchunk.index = 0; + rchunk.length = block_size; + + *chunk = rchunk; + return 0; +} + void pa_memblockq_drop(pa_memblockq *bq, size_t length) { int64_t old; pa_assert(bq); diff --git a/src/pulsecore/memblockq.h b/src/pulsecore/memblockq.h index 6132f31b..3775c3f3 100644 --- a/src/pulsecore/memblockq.h +++ b/src/pulsecore/memblockq.h @@ -95,6 +95,11 @@ void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek, pa * was passed we return the length of the hole in chunk->length. */ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk); +/* Much like pa_memblockq_peek, but guarantees that the returned chunk + * will have a length of the block size passed. You must configure a + * silence memchunk for this memblockq if you use this call. */ +int pa_memblockq_peek_fixed_size(pa_memblockq *bq, size_t block_size, pa_memchunk *chunk); + /* Drop the specified bytes from the queue. */ void pa_memblockq_drop(pa_memblockq *bq, size_t length); diff --git a/src/tests/memblockq-test.c b/src/tests/memblockq-test.c index ec3f5426..c3afd0a6 100644 --- a/src/tests/memblockq-test.c +++ b/src/tests/memblockq-test.c @@ -29,23 +29,43 @@ #include #include +static void dump_chunk(const pa_memchunk *chunk) { + size_t n; + void *q; + char *e; + + pa_assert(chunk); + + printf("["); + + q = pa_memblock_acquire(chunk->memblock); + for (e = (char*) q + chunk->index, n = 0; n < chunk->length; n++, e++) + printf("%c", *e); + pa_memblock_release(chunk->memblock); + + printf("]"); +} + static void dump(pa_memblockq *bq) { - printf(">"); + pa_memchunk out; - for (;;) { - pa_memchunk out; - char *e; - size_t n; - void *q; + pa_assert(bq); + + /* First let's dump this as fixed block */ + printf("FIXED >"); + pa_memblockq_peek_fixed_size(bq, 64, &out); + dump_chunk(&out); + pa_memblock_unref(out.memblock); + printf("<\n"); + /* Then let's dump the queue manually */ + printf("MANUAL>"); + + for (;;) { if (pa_memblockq_peek(bq, &out) < 0) break; - q = pa_memblock_acquire(out.memblock); - for (e = (char*) q + out.index, n = 0; n < out.length; n++) - printf("%c", *e); - pa_memblock_release(out.memblock); - + dump_chunk(&out); pa_memblock_unref(out.memblock); pa_memblockq_drop(bq, out.length); } @@ -70,7 +90,7 @@ int main(int argc, char *argv[]) { silence.index = 0; silence.length = pa_memblock_get_length(silence.memblock); - bq = pa_memblockq_new(0, 40, 10, 2, 4, 4, 40, &silence); + bq = pa_memblockq_new(0, 200, 10, 2, 4, 4, 40, &silence); assert(bq); chunk1.memblock = pa_memblock_new_fixed(p, (char*) "11", 2, 1); -- cgit