summaryrefslogtreecommitdiffstats
path: root/bufferq.c
diff options
context:
space:
mode:
Diffstat (limited to 'bufferq.c')
-rw-r--r--bufferq.c147
1 files changed, 63 insertions, 84 deletions
diff --git a/bufferq.c b/bufferq.c
index 5261f35..1965dda 100644
--- a/bufferq.c
+++ b/bufferq.c
@@ -4,7 +4,7 @@
#include "macro.h"
#include "bufferq.h"
-#define SA_BUFFERQ_CONCAT_DATA(x) ((void*) (uint8_t*) (x) + ALIGN(sizeof(sa_bufferq_item_t)))
+#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);
@@ -44,23 +44,30 @@ void sa_bufferq_done(sa_bufferq_t *q) {
sa_free(q->last);
}
-static sa_bufferq_item_t* bufferq_item_new(const void *d, size_t size, int copy) {
+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 (!copy) {
+ if (type == SA_BUFFERQ_ITEM_STATIC) {
if (!(i = sa_new(sa_bufferq_item_t, 1)))
- return i;
- i->type = SA_BUFFERQ_ITEM_STATIC;
+ return NULL;
i->data = (void*) d;
- } else {
- if (!(i = sa_malloc(ALIGN(sizeof(sa_bufferq_item_t)) + size)))
- return i;
- i->type = SA_BUFFERQ_ITEM_CONCATENATED;
- i->data = SA_BUFFERQ_CONCAT_DATA(i);
+ } 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);
@@ -90,9 +97,9 @@ static void bufferq_item_free(sa_bufferq_item_t *i) {
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, int copy) {
+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;
+ sa_bufferq_item_t *i, *j, *n;
sa_assert(q);
@@ -110,7 +117,7 @@ int sa_bufferq_push(sa_bufferq_t *q, unsigned channel, const void *data, size_t
sa_assert_not_reached();
}
- if (q->read_index > idx) {
+ if (q->read_index > idx && type != SA_BUFFERQ_ITEM_DYNAMIC) {
int64_t l = q->read_index - idx;
if (l > nbytes)
@@ -122,72 +129,39 @@ int sa_bufferq_push(sa_bufferq_t *q, unsigned channel, const void *data, size_t
}
- 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(data, l, copy)))
- return SA_ERROR_OOM;
-
- j->idx = idx;
-
- SA_LLIST_INSERT_BEFORE(sa_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;
+ /* Allocate the new entry */
+ if (!(j = bufferq_item_new(data, idx, nbytes, type)))
+ return SA_ERROR_OOM;
- if (l > i->idx + i->size - idx)
- l = i->idx + i->size - idx;
+ /* 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)
+ ;
- if (!(i = bufferq_item_make_writable(i)))
- return SA_ERROR_OOM;
-
- memcpy((uint8_t*) i->data + (idx - i->idx), data, l);
-
- idx += l;
- data += l;
- nbytes -= l;
- }
+ /* Shorten the current entry if necessary */
+ if (i && idx > i->idx) {
+ i->size = idx - i->idx;
+ i = i->bufferq_next;
}
-
- if (nbytes > 0) {
- sa_assert(!i);
-
- if (!(j = bufferq_item_new(data, nbytes, copy)))
- return SA_ERROR_OOM;
-
- j->idx = idx;
-
+
+ /* 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)
@@ -196,7 +170,7 @@ int sa_bufferq_push(sa_bufferq_t *q, unsigned channel, const void *data, size_t
return SA_SUCCESS;
}
-int sa_bufferq_get(sa_bufferq_t *q, void *i[], size_t *bytes) {
+void sa_bufferq_get(sa_bufferq_t *q, void *i[], size_t *bytes) {
int first = 1;
unsigned u;
sa_assert(q);
@@ -221,7 +195,7 @@ int sa_bufferq_get(sa_bufferq_t *q, void *i[], size_t *bytes) {
} else {
int64_t l;
- i[u] = (uint8_t*) q->items[u]->data + q->read_index - q->items[u]->idx;
+ 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);
@@ -235,12 +209,10 @@ int sa_bufferq_get(sa_bufferq_t *q, void *i[], size_t *bytes) {
} else
i[u] = NULL;
}
-
- return SA_SUCCESS;
}
-int sa_bufferq_drop(sa_bufferq_t *q, int64_t bytes) {
+void sa_bufferq_drop(sa_bufferq_t *q, int64_t bytes) {
unsigned u;
sa_assert(q);
@@ -264,28 +236,35 @@ int sa_bufferq_drop(sa_bufferq_t *q, int64_t bytes) {
if (!i)
q->last[u] = NULL;
}
-
- return SA_SUCCESS;
}
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;
- i = q->items[u];
+ for (i = q->items[u]; i; i = i->bufferq_next) {
- while (i) {
+ if (i->type != SA_BUFFERQ_ITEM_STATIC)
+ continue;
- if (!bufferq_item_make_writable(i))
- return SA_ERROR_OOM;
+ if (!bufferq_item_make_writable(i)) {
+ fail = 1;
- i = i->bufferq_next;
+ /* 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 SA_SUCCESS;
+ return fail ? SA_ERROR_OOM : SA_SUCCESS;
}