From 7d83e5c7816b5e343695a75ba58b32dbe1be969a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 1 Oct 2007 20:16:28 +0000 Subject: move all sources down to a seperate src/ tree git-svn-id: file:///home/lennart/svn/public/libsydney/trunk@34 9ba3c220-e4d3-45a2-8aa3-73fcc9aff6ce --- src/bufferq.c | 270 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 src/bufferq.c (limited to 'src/bufferq.c') diff --git a/src/bufferq.c b/src/bufferq.c new file mode 100644 index 0000000..1965dda --- /dev/null +++ b/src/bufferq.c @@ -0,0 +1,270 @@ +#include + +#include "malloc.h" +#include "macro.h" +#include "bufferq.h" + +#define SA_BUFFERQ_ITEM_CONCAT_DATA(x) ((void*) (uint8_t*) (x) + SA_ALIGN(sizeof(sa_bufferq_item_t))) + +int sa_bufferq_init(sa_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(sa_bufferq_item_t*, nchannels))) + return SA_ERROR_OOM; + + if (!(q->last = sa_new0(sa_bufferq_item_t*, nchannels))) { + sa_free(q->items); + q->items = NULL; + return SA_ERROR_OOM; + } + + return SA_SUCCESS; +} + +void sa_bufferq_done(sa_bufferq_t *q) { + unsigned u; + sa_assert(q); + + for (u = 0; u < q->nchannels; u++) { + sa_bufferq_item_t *i; + + while ((i = q->items[u])) { + SA_LLIST_REMOVE(sa_bufferq_item_t, bufferq, q->items[u], i); + sa_free(i); + } + } + + sa_free(q->items); + sa_free(q->last); +} + +static sa_bufferq_item_t* bufferq_item_new(const void *d, int64_t idx, size_t size, sa_bufferq_item_type_t type) { + sa_bufferq_item_t *i; + sa_assert(size > 0); + + if (type == SA_BUFFERQ_ITEM_STATIC) { + if (!(i = sa_new(sa_bufferq_item_t, 1))) + return NULL; + i->data = (void*) d; + } else if (type == SA_BUFFERQ_ITEM_CONCATENATED) { + if (!(i = sa_malloc(SA_ALIGN(sizeof(sa_bufferq_item_t)) + size))) + return NULL; + i->data = SA_BUFFERQ_ITEM_CONCAT_DATA(i); + memcpy(i->data, d, size); + } else { + sa_assert(type == SA_BUFFERQ_ITEM_DYNAMIC); + + if (!(i = sa_new(sa_bufferq_item_t, 1))) + return NULL; + + i->data = (void*) d; + } + + i->type = type; + i->idx = idx; + i->size = size; + SA_LLIST_ITEM_INIT(sa_bufferq_item_t, bufferq, i); + + return i; +} + +static sa_bufferq_item_t* bufferq_item_make_writable(sa_bufferq_item_t *i) { + void *d; + sa_assert(i); + + if (i->type == SA_BUFFERQ_ITEM_CONCATENATED || i->type == SA_BUFFERQ_ITEM_DYNAMIC) + return i; + + if (!(d = sa_memdup(i->data, i->size))) + return NULL; + + i->data = d; + i->type = SA_BUFFERQ_ITEM_DYNAMIC; + return i; +} + +static void bufferq_item_free(sa_bufferq_item_t *i) { + sa_assert(i); + + if (i->type == SA_BUFFERQ_ITEM_DYNAMIC) + sa_free(i->data); + sa_free(i); +} + +int sa_bufferq_push(sa_bufferq_t *q, unsigned channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence, sa_bufferq_item_type_t type) { + int64_t idx; + sa_bufferq_item_t *i, *j, *n; + + 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 && type != SA_BUFFERQ_ITEM_DYNAMIC) { + int64_t l = q->read_index - idx; + + if (l > nbytes) + l = nbytes; + + idx += l; + data += l; + nbytes -= l; + + } + + /* Allocate the new entry */ + if (!(j = bufferq_item_new(data, idx, nbytes, type))) + return SA_ERROR_OOM; + + /* Find the position where we need to insert the new entry */ + for (i = q->items[channel]; i && idx >= i->idx + i->size; i = i->bufferq_next) + ; + + /* Shorten the current entry if necessary */ + if (i && idx > i->idx) { + i->size = idx - i->idx; + i = i->bufferq_next; + } + + /* Insert the entry */ + if (i) + SA_LLIST_INSERT_BEFORE(sa_bufferq_item_t, bufferq, q->items[channel], i, j); + else { + if (q->last[channel]) + SA_LLIST_INSERT_AFTER(sa_bufferq_item_t, bufferq, q->items[channel], q->last[channel], j); + else + SA_LLIST_PREPEND(sa_bufferq_item_t, bufferq, q->items[channel], j); + + q->last[channel] = j; + } + + /* Now kick all the entries that overlap entirely with our new entry */ + for (i = j->bufferq_next; i && i->idx + i->size < j->idx + j->size ; i = n) { + n = i->bufferq_next; + SA_LLIST_REMOVE(sa_bufferq_item_t, bufferq, q->items[channel], i); + bufferq_item_free(i); + } + + q->write_index = idx + nbytes; + + if (q->write_index > q->end_index) + q->end_index = q->write_index; + + return SA_SUCCESS; +} + +void sa_bufferq_get(sa_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*) q->items[u]->data + 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; + } +} + + +void sa_bufferq_drop(sa_bufferq_t *q, int64_t bytes) { + unsigned u; + + sa_assert(q); + + q->read_index += bytes; + + for (u = 0; u < q->nchannels; u++) { + sa_bufferq_item_t *i; + + i = q->items[u]; + + while (i && q->read_index >= i->idx + i->size) { + sa_bufferq_item_t *n = i->bufferq_next; + + SA_LLIST_REMOVE(sa_bufferq_item_t, bufferq, q->items[u], i); + + bufferq_item_free(i); + i = n; + } + + if (!i) + q->last[u] = NULL; + } +} + +int sa_bufferq_realloc(sa_bufferq_t *q) { + unsigned u; + int fail = 0; + sa_assert(q); + + for (u = 0; u < q->nchannels; u++) { + sa_bufferq_item_t *i; + + for (i = q->items[u]; i; i = i->bufferq_next) { + + if (i->type != SA_BUFFERQ_ITEM_STATIC) + continue; + + if (!bufferq_item_make_writable(i)) { + fail = 1; + + /* Hmm, we couldn't allocate memory, but we can't + * return without doing anything, hence let's at least + * drop the reference to the statically allocated + * data */ + + i->size = 0; + i->data = SA_BUFFERQ_ITEM_CONCAT_DATA(i); + i->type = SA_BUFFERQ_ITEM_CONCATENATED; + } + } + } + + return fail ? SA_ERROR_OOM : SA_SUCCESS; +} -- cgit