summaryrefslogtreecommitdiffstats
path: root/src/bufferq.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2007-10-01 20:16:28 +0000
committerLennart Poettering <lennart@poettering.net>2007-10-01 20:16:28 +0000
commit7d83e5c7816b5e343695a75ba58b32dbe1be969a (patch)
treebfd1dfc9b7c8f4a2aaf66c1b30e78355dee8c88a /src/bufferq.c
parent762196328ab7e60f1d2908fd5a337d2ca99726dd (diff)
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
Diffstat (limited to 'src/bufferq.c')
-rw-r--r--src/bufferq.c270
1 files changed, 270 insertions, 0 deletions
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 <string.h>
+
+#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;
+}