From a68ee34ebfbbc6e6bc653aadc284264e10694930 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 14 May 2007 17:07:21 +0000 Subject: add bufferq structure git-svn-id: file:///home/lennart/svn/public/libsydney/trunk@17 9ba3c220-e4d3-45a2-8aa3-73fcc9aff6ce --- bufferq.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 bufferq.c (limited to 'bufferq.c') diff --git a/bufferq.c b/bufferq.c new file mode 100644 index 0000000..df22ec3 --- /dev/null +++ b/bufferq.c @@ -0,0 +1,235 @@ +#include + +#include "malloc.h" +#include "macro.h" +#include "bufferq.h" + +int bufferq_init(bufferq_t *q, unsigned nchannels, size_t sample_size) { + sa_assert(q); + sa_assert(sample_size > 0); + sa_assert(nchannels > 0); + + memset(q, 0, sizeof(*q)); + q->sample_size = sample_size; + q->nchannels = nchannels; + + if (!(q->items = sa_new0(bufferq_item_t*, nchannels))) + return SA_ERROR_OOM; + + if (!(q->last = sa_new0(bufferq_item_t*, nchannels))) { + sa_free(q->items); + q->items = NULL; + return SA_ERROR_OOM; + } + + return SA_SUCCESS; +} + +void bufferq_done(bufferq_t *q) { + unsigned u; + sa_assert(q); + + for (u = 0; u < q->nchannels; u++) { + bufferq_item_t *i; + + while ((i = q->items[u])) { + SA_LLIST_REMOVE(bufferq_item_t, bufferq, q->items[u], i); + sa_free(i); + } + } + + sa_free(q->items); + sa_free(q->last); +} + +static bufferq_item_t* bufferq_item_new(size_t size) { + bufferq_item_t *i; + sa_assert(size > 0); + + if (!(i = sa_malloc(ALIGN(sizeof(bufferq_item_t)) + size))) + return i; + + SA_LLIST_ITEM_INIT(bufferq_item_t, bufferq, i); + + return i; +} + +int bufferq_push(bufferq_t *q, unsigned channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) { + int64_t idx; + bufferq_item_t *i, *j; + + sa_assert(q); + + switch (whence) { + case SA_SEEK_RELATIVE: + idx = q->write_index + offset; + break; + case SA_SEEK_ABSOLUTE: + idx = offset; + break; + case SA_SEEK_RELATIVE_END: + idx = q->end_index + offset; + break; + case _SA_SEEK_MAX: + sa_assert_not_reached(); + } + + if (q->read_index > idx) { + int64_t l = q->read_index - idx; + + if (l > nbytes) + l = nbytes; + + idx += l; + data += l; + nbytes -= l; + + } + + i = q->items[channel]; + + while (i && nbytes > 0) { + + if (idx >= i->idx + i->size) { + /* The new data belongs behind the current node */ + + i = i->bufferq_next; + + } else if (idx < i->idx) { + size_t l; + /* The new data belongs before the current node (at least partially) */ + + l = nbytes; + + if (l > i->idx - idx) + l = i->idx - idx; + + if (!(j = bufferq_item_new(l))) + return SA_ERROR_OOM; + + memcpy(BUFFERQ_ITEM_DATA(j), data, l); + j->idx = idx; + j->size = l; + + SA_LLIST_INSERT_BEFORE(bufferq_item_t, bufferq, q->items[channel], i, j); + + idx += l; + data += l; + nbytes -= l; + + } else { + size_t l; + + /* The data belongs right in the current node somewhere */ + + l = nbytes; + + if (l > i->idx + i->size - idx) + l = i->idx + i->size - idx; + + memcpy((uint8_t*) BUFFERQ_ITEM_DATA(i) + (idx - i->idx), data, l); + + idx += l; + data += l; + nbytes -= l; + } + } + + if (nbytes > 0) { + sa_assert(!i); + + if (!(j = bufferq_item_new(nbytes))) + return SA_ERROR_OOM; + + memcpy(BUFFERQ_ITEM_DATA(j), data, nbytes); + j->idx = idx; + j->size = nbytes; + + if (q->last[channel]) + SA_LLIST_INSERT_AFTER(bufferq_item_t, bufferq, q->items[channel], q->last[channel], j); + else + SA_LLIST_PREPEND(bufferq_item_t, bufferq, q->items[channel], j); + + q->last[channel] = j; + } + + q->write_index = idx + nbytes; + + if (q->write_index > q->end_index) + q->end_index = q->write_index; + + return SA_SUCCESS; +} + +int bufferq_get(bufferq_t *q, void *i[], size_t *bytes) { + int first = 1; + unsigned u; + sa_assert(q); + + *bytes = 0; + + for (u = 0; u < q->nchannels; u++) { + + if (q->items[u]) { + + if (q->items[u]->idx > q->read_index) { + int64_t l; + i[u] = NULL; + + l = q->items[u]->idx - q->read_index; + + if (first) { + *bytes = l; + first = 0; + } else + *bytes = l < *bytes ? l : *bytes; + } else { + int64_t l; + + i[u] = (uint8_t*) BUFFERQ_ITEM_DATA(q->items[u]) + q->read_index - q->items[u]->idx; + + l = q->items[u]->size - (q->read_index - q->items[u]->idx); + + if (first) { + *bytes = l; + first = 0; + } else + *bytes = l < *bytes ? l : *bytes; + } + + } else + i[u] = NULL; + } + + return SA_SUCCESS; +} + + +int bufferq_drop(bufferq_t *q, int64_t bytes) { + unsigned u; + + sa_assert(q); + + q->read_index += bytes; + + for (u = 0; u < q->nchannels; u++) { + + bufferq_item_t *i; + + i = q->items[u]; + + while (i && q->read_index >= i->idx + i->size) { + bufferq_item_t *n = i->bufferq_next; + + SA_LLIST_REMOVE(bufferq_item_t, bufferq, q->items[u], i); + + sa_free(i); + i = n; + } + + if (!i) + q->last[u] = NULL; + } + + return SA_SUCCESS; +} -- cgit