From f44ba092651aa75055e109e04b4164ea92ae7fdc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 21:53:48 +0000 Subject: big s/polyp/pulse/g git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1033 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/memblockq.c | 636 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 636 insertions(+) create mode 100644 src/pulsecore/memblockq.c (limited to 'src/pulsecore/memblockq.c') diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c new file mode 100644 index 00000000..ff199f1b --- /dev/null +++ b/src/pulsecore/memblockq.c @@ -0,0 +1,636 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "memblockq.h" + +struct memblock_list { + struct memblock_list *next, *prev; + int64_t index; + pa_memchunk chunk; +}; + +struct pa_memblockq { + struct memblock_list *blocks, *blocks_tail; + unsigned n_blocks; + size_t maxlength, tlength, base, prebuf, minreq; + int64_t read_index, write_index; + enum { PREBUF, RUNNING } state; + pa_memblock_stat *memblock_stat; + pa_memblock *silence; + pa_mcalign *mcalign; +}; + +pa_memblockq* pa_memblockq_new( + int64_t idx, + size_t maxlength, + size_t tlength, + size_t base, + size_t prebuf, + size_t minreq, + pa_memblock *silence, + pa_memblock_stat *s) { + + pa_memblockq* bq; + + assert(base > 0); + assert(maxlength >= base); + + bq = pa_xnew(pa_memblockq, 1); + bq->blocks = bq->blocks_tail = NULL; + bq->n_blocks = 0; + + bq->base = base; + bq->read_index = bq->write_index = idx; + bq->memblock_stat = s; + + pa_log_debug(__FILE__": memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", + (unsigned long)maxlength, (unsigned long)tlength, (unsigned long)base, (unsigned long)prebuf, (unsigned long)minreq); + + bq->maxlength = ((maxlength+base-1)/base)*base; + assert(bq->maxlength >= base); + + bq->tlength = ((tlength+base-1)/base)*base; + if (!bq->tlength || bq->tlength >= bq->maxlength) + bq->tlength = bq->maxlength; + + bq->prebuf = (prebuf == (size_t) -1) ? bq->tlength/2 : prebuf; + bq->prebuf = ((bq->prebuf+base-1)/base)*base; + if (bq->prebuf > bq->maxlength) + bq->prebuf = bq->maxlength; + + bq->minreq = (minreq/base)*base; + + if (bq->minreq > bq->tlength - bq->prebuf) + bq->minreq = bq->tlength - bq->prebuf; + + if (!bq->minreq) + bq->minreq = 1; + + pa_log_debug(__FILE__": memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", + (unsigned long)bq->maxlength, (unsigned long)bq->tlength, (unsigned long)bq->base, (unsigned long)bq->prebuf, (unsigned long)bq->minreq); + + bq->state = bq->prebuf ? PREBUF : RUNNING; + bq->silence = silence ? pa_memblock_ref(silence) : NULL; + bq->mcalign = NULL; + + return bq; +} + +void pa_memblockq_free(pa_memblockq* bq) { + assert(bq); + + pa_memblockq_flush(bq); + + if (bq->silence) + pa_memblock_unref(bq->silence); + + if (bq->mcalign) + pa_mcalign_free(bq->mcalign); + + pa_xfree(bq); +} + +static void drop_block(pa_memblockq *bq, struct memblock_list *q) { + assert(bq); + assert(q); + + assert(bq->n_blocks >= 1); + + if (q->prev) + q->prev->next = q->next; + else + bq->blocks = q->next; + + if (q->next) + q->next->prev = q->prev; + else + bq->blocks_tail = q->prev; + + pa_memblock_unref(q->chunk.memblock); + pa_xfree(q); + + bq->n_blocks--; +} + +static int can_push(pa_memblockq *bq, size_t l) { + int64_t end; + + assert(bq); + + if (bq->read_index > bq->write_index) { + size_t d = bq->read_index - bq->write_index; + + if (l > d) + l -= d; + else + return 1; + } + + end = bq->blocks_tail ? bq->blocks_tail->index + bq->blocks_tail->chunk.length : 0; + + /* Make sure that the list doesn't get too long */ + if (bq->write_index + (int64_t)l > end) + if (bq->write_index + l - bq->read_index > bq->maxlength) + return 0; + + return 1; +} + +int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { + + struct memblock_list *q, *n; + pa_memchunk chunk; + + assert(bq); + assert(uchunk); + assert(uchunk->memblock); + assert(uchunk->length > 0); + assert(uchunk->index + uchunk->length <= uchunk->memblock->length); + + if (uchunk->length % bq->base) + return -1; + + if (!can_push(bq, uchunk->length)) + return -1; + + chunk = *uchunk; + + if (bq->read_index > bq->write_index) { + + /* We currently have a buffer underflow, we need to drop some + * incoming data */ + + size_t d = bq->read_index - bq->write_index; + + if (chunk.length > d) { + chunk.index += d; + chunk.length -= d; + bq->write_index = bq->read_index; + } else { + /* We drop the incoming data completely */ + bq->write_index += chunk.length; + return 0; + } + } + + /* We go from back to front to look for the right place to add + * this new entry. Drop data we will overwrite on the way */ + + q = bq->blocks_tail; + while (q) { + + if (bq->write_index >= q->index + (int64_t)q->chunk.length) + /* We found the entry where we need to place the new entry immediately after */ + break; + else if (bq->write_index + (int64_t)chunk.length <= q->index) { + /* This entry isn't touched at all, let's skip it */ + q = q->prev; + } else if (bq->write_index <= q->index && + bq->write_index + chunk.length >= q->index + q->chunk.length) { + + /* This entry is fully replaced by the new entry, so let's drop it */ + + struct memblock_list *p; + p = q; + q = q->prev; + drop_block(bq, p); + } else if (bq->write_index >= q->index) { + /* The write index points into this memblock, so let's + * truncate or split it */ + + if (bq->write_index + chunk.length < q->index + q->chunk.length) { + + /* We need to save the end of this memchunk */ + struct memblock_list *p; + size_t d; + + /* Create a new list entry for the end of thie memchunk */ + p = pa_xnew(struct memblock_list, 1); + p->chunk = q->chunk; + pa_memblock_ref(p->chunk.memblock); + + /* Calculate offset */ + d = bq->write_index + chunk.length - q->index; + assert(d > 0); + + /* Drop it from the new entry */ + p->index = q->index + d; + p->chunk.length -= d; + + /* Add it to the list */ + p->prev = q; + if ((p->next = q->next)) + q->next->prev = p; + else + bq->blocks_tail = p; + q->next = p; + + bq->n_blocks++; + } + + /* Truncate the chunk */ + if (!(q->chunk.length = bq->write_index - q->index)) { + struct memblock_list *p; + p = q; + q = q->prev; + drop_block(bq, p); + } + + /* We had to truncate this block, hence we're now at the right position */ + break; + } else { + size_t d; + + assert(bq->write_index + (int64_t)chunk.length > q->index && + bq->write_index + (int64_t)chunk.length < q->index + (int64_t)q->chunk.length && + bq->write_index < q->index); + + /* The job overwrites the current entry at the end, so let's drop the beginning of this entry */ + + d = bq->write_index + chunk.length - q->index; + q->index += d; + q->chunk.index += d; + q->chunk.length -= d; + + q = q->prev; + } + + } + + if (q) { + assert(bq->write_index >= q->index + (int64_t)q->chunk.length); + assert(!q->next || (bq->write_index + (int64_t)chunk.length <= q->next->index)); + + /* Try to merge memory blocks */ + + if (q->chunk.memblock == chunk.memblock && + q->chunk.index + (int64_t)q->chunk.length == chunk.index && + bq->write_index == q->index + (int64_t)q->chunk.length) { + + q->chunk.length += chunk.length; + bq->write_index += chunk.length; + return 0; + } + } else + assert(!bq->blocks || (bq->write_index + (int64_t)chunk.length <= bq->blocks->index)); + + + n = pa_xnew(struct memblock_list, 1); + n->chunk = chunk; + pa_memblock_ref(n->chunk.memblock); + n->index = bq->write_index; + bq->write_index += n->chunk.length; + + n->next = q ? q->next : bq->blocks; + n->prev = q; + + if (n->next) + n->next->prev = n; + else + bq->blocks_tail = n; + + if (n->prev) + n->prev->next = n; + else + bq->blocks = n; + + bq->n_blocks++; + return 0; +} + +int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { + assert(bq); + assert(chunk); + + if (bq->state == PREBUF) { + + /* We need to pre-buffer */ + if (pa_memblockq_get_length(bq) < bq->prebuf) + return -1; + + bq->state = RUNNING; + + } else if (bq->prebuf > 0 && bq->read_index >= bq->write_index) { + + /* Buffer underflow protection */ + bq->state = PREBUF; + return -1; + } + + /* Do we need to spit out silence? */ + if (!bq->blocks || bq->blocks->index > bq->read_index) { + + size_t length; + + /* How much silence shall we return? */ + length = bq->blocks ? bq->blocks->index - bq->read_index : 0; + + /* We need to return silence, since no data is yet available */ + if (bq->silence) { + chunk->memblock = pa_memblock_ref(bq->silence); + + if (!length || length > chunk->memblock->length) + length = chunk->memblock->length; + + chunk->length = length; + } else { + chunk->memblock = NULL; + chunk->length = length; + } + + chunk->index = 0; + return 0; + } + + /* Ok, let's pass real data to the caller */ + assert(bq->blocks->index == bq->read_index); + + *chunk = bq->blocks->chunk; + pa_memblock_ref(chunk->memblock); + + return 0; +} + +void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length) { + assert(bq); + assert(length % bq->base == 0); + + assert(!chunk || length <= chunk->length); + + if (chunk) { + + if (bq->blocks && bq->blocks->index == bq->read_index) { + /* The first item in queue is valid */ + + /* Does the chunk match with what the user supplied us? */ + if (memcmp(chunk, &bq->blocks->chunk, sizeof(pa_memchunk)) != 0) + return; + + } else { + size_t l; + + /* The first item in the queue is not yet relevant */ + + assert(!bq->blocks || bq->blocks->index > bq->read_index); + l = bq->blocks ? bq->blocks->index - bq->read_index : 0; + + if (bq->silence) { + + if (!l || l > bq->silence->length) + l = bq->silence->length; + + } + + /* Do the entries still match? */ + if (chunk->index != 0 || chunk->length != l || chunk->memblock != bq->silence) + return; + } + } + + while (length > 0) { + + if (bq->blocks) { + size_t d; + + assert(bq->blocks->index >= bq->read_index); + + d = (size_t) (bq->blocks->index - bq->read_index); + + if (d >= length) { + /* The first block is too far in the future */ + + bq->read_index += length; + break; + } else { + + length -= d; + bq->read_index += d; + } + + assert(bq->blocks->index == bq->read_index); + + if (bq->blocks->chunk.length <= length) { + /* We need to drop the full block */ + + length -= bq->blocks->chunk.length; + bq->read_index += bq->blocks->chunk.length; + + drop_block(bq, bq->blocks); + } else { + /* Only the start of this block needs to be dropped */ + + bq->blocks->chunk.index += length; + bq->blocks->chunk.length -= length; + bq->blocks->index += length; + bq->read_index += length; + break; + } + + } else { + + /* The list is empty, there's nothing we could drop */ + bq->read_index += length; + break; + } + } +} + +int pa_memblockq_is_readable(pa_memblockq *bq) { + assert(bq); + + if (bq->prebuf > 0) { + size_t l = pa_memblockq_get_length(bq); + + if (bq->state == PREBUF && l < bq->prebuf) + return 0; + + if (l <= 0) + return 0; + } + + return 1; +} + +int pa_memblockq_is_writable(pa_memblockq *bq, size_t length) { + assert(bq); + + if (length % bq->base) + return 0; + + return pa_memblockq_get_length(bq) + length <= bq->tlength; +} + +size_t pa_memblockq_get_length(pa_memblockq *bq) { + assert(bq); + + if (bq->write_index <= bq->read_index) + return 0; + + return (size_t) (bq->write_index - bq->read_index); +} + +size_t pa_memblockq_missing(pa_memblockq *bq) { + size_t l; + assert(bq); + + if ((l = pa_memblockq_get_length(bq)) >= bq->tlength) + return 0; + + l = bq->tlength - l; + return (l >= bq->minreq) ? l : 0; +} + +size_t pa_memblockq_get_minreq(pa_memblockq *bq) { + assert(bq); + + return bq->minreq; +} + +void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek) { + assert(bq); + + switch (seek) { + case PA_SEEK_RELATIVE: + bq->write_index += offset; + return; + case PA_SEEK_ABSOLUTE: + bq->write_index = offset; + return; + case PA_SEEK_RELATIVE_ON_READ: + bq->write_index = bq->read_index + offset; + return; + case PA_SEEK_RELATIVE_END: + bq->write_index = (bq->blocks_tail ? bq->blocks_tail->index + (int64_t)bq->blocks_tail->chunk.length : bq->read_index) + offset; + return; + } + + assert(0); +} + +void pa_memblockq_flush(pa_memblockq *bq) { + assert(bq); + + while (bq->blocks) + drop_block(bq, bq->blocks); + + assert(bq->n_blocks == 0); + + bq->write_index = bq->read_index; + + pa_memblockq_prebuf_force(bq); +} + +size_t pa_memblockq_get_tlength(pa_memblockq *bq) { + assert(bq); + + return bq->tlength; +} + +int64_t pa_memblockq_get_read_index(pa_memblockq *bq) { + assert(bq); + return bq->read_index; +} + +int64_t pa_memblockq_get_write_index(pa_memblockq *bq) { + assert(bq); + return bq->write_index; +} + +int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk) { + pa_memchunk rchunk; + + assert(bq); + assert(chunk && bq->base); + + if (bq->base == 1) + return pa_memblockq_push(bq, chunk); + + if (!bq->mcalign) + bq->mcalign = pa_mcalign_new(bq->base, bq->memblock_stat); + + if (!can_push(bq, pa_mcalign_csize(bq->mcalign, chunk->length))) + return -1; + + pa_mcalign_push(bq->mcalign, chunk); + + while (pa_mcalign_pop(bq->mcalign, &rchunk) >= 0) { + int r; + r = pa_memblockq_push(bq, &rchunk); + pa_memblock_unref(rchunk.memblock); + + if (r < 0) + return -1; + } + + return 0; +} + +void pa_memblockq_shorten(pa_memblockq *bq, size_t length) { + size_t l; + assert(bq); + + l = pa_memblockq_get_length(bq); + + if (l > length) + pa_memblockq_drop(bq, NULL, l - length); +} + +void pa_memblockq_prebuf_disable(pa_memblockq *bq) { + assert(bq); + + if (bq->state == PREBUF) + bq->state = RUNNING; +} + +void pa_memblockq_prebuf_force(pa_memblockq *bq) { + assert(bq); + + if (bq->state == RUNNING && bq->prebuf > 0) + bq->state = PREBUF; +} + +size_t pa_memblockq_get_maxlength(pa_memblockq *bq) { + assert(bq); + + return bq->maxlength; +} + +size_t pa_memblockq_get_prebuf(pa_memblockq *bq) { + assert(bq); + + return bq->prebuf; +} -- cgit From f15b4c7c704292ee88ae05919adc88a2765684cf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 29 Jul 2006 15:03:26 +0000 Subject: if the memblockq is empty, return -1 in all cases git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1166 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/memblockq.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/pulsecore/memblockq.c') diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index ff199f1b..822bd66c 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -368,6 +368,12 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { chunk->length = length; } else { + + /* If the memblockq is empty, return -1, otherwise return + * the time to sleep */ + if (!bq->blocks) + return -1; + chunk->memblock = NULL; chunk->length = length; } -- cgit From 0e436a6926af56f37a74a03bb5e143e078ca0d55 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 19:55:18 +0000 Subject: Rework memory management to allow shared memory data transfer. The central idea is to allocate all audio memory blocks from a per-process memory pool which is available as read-only SHM segment to other local processes. Then, instead of writing the actual audio data to the socket just write references to this shared memory pool. To work optimally all memory blocks should now be of type PA_MEMBLOCK_POOL or PA_MEMBLOCK_POOL_EXTERNAL. The function pa_memblock_new() now generates memory blocks of this type by default. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1266 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/memblockq.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src/pulsecore/memblockq.c') diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index 822bd66c..2fd38850 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -49,7 +49,6 @@ struct pa_memblockq { size_t maxlength, tlength, base, prebuf, minreq; int64_t read_index, write_index; enum { PREBUF, RUNNING } state; - pa_memblock_stat *memblock_stat; pa_memblock *silence; pa_mcalign *mcalign; }; @@ -61,8 +60,7 @@ pa_memblockq* pa_memblockq_new( size_t base, size_t prebuf, size_t minreq, - pa_memblock *silence, - pa_memblock_stat *s) { + pa_memblock *silence) { pa_memblockq* bq; @@ -75,7 +73,6 @@ pa_memblockq* pa_memblockq_new( bq->base = base; bq->read_index = bq->write_index = idx; - bq->memblock_stat = s; pa_log_debug(__FILE__": memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", (unsigned long)maxlength, (unsigned long)tlength, (unsigned long)base, (unsigned long)prebuf, (unsigned long)minreq); @@ -586,7 +583,7 @@ int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk) { return pa_memblockq_push(bq, chunk); if (!bq->mcalign) - bq->mcalign = pa_mcalign_new(bq->base, bq->memblock_stat); + bq->mcalign = pa_mcalign_new(bq->base); if (!can_push(bq, pa_mcalign_csize(bq->mcalign, chunk->length))) return -1; -- cgit From e385d93e5aad6a6fce754c00c804ff1d6a6746d4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 21:38:40 +0000 Subject: remove all occurences of pa_logXXX(__FILE__": and replace them by pa_logXXX(" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1272 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/memblockq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/pulsecore/memblockq.c') diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index 2fd38850..e6b73fc5 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -74,7 +74,7 @@ pa_memblockq* pa_memblockq_new( bq->base = base; bq->read_index = bq->write_index = idx; - pa_log_debug(__FILE__": memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", + pa_log_debug("memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", (unsigned long)maxlength, (unsigned long)tlength, (unsigned long)base, (unsigned long)prebuf, (unsigned long)minreq); bq->maxlength = ((maxlength+base-1)/base)*base; @@ -97,7 +97,7 @@ pa_memblockq* pa_memblockq_new( if (!bq->minreq) bq->minreq = 1; - pa_log_debug(__FILE__": memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", + pa_log_debug("memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", (unsigned long)bq->maxlength, (unsigned long)bq->tlength, (unsigned long)bq->base, (unsigned long)bq->prebuf, (unsigned long)bq->minreq); bq->state = bq->prebuf ? PREBUF : RUNNING; -- cgit From d210ebbb09daddb2c8c8e8e77243e088b0b19c4d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Sep 2006 23:50:56 +0000 Subject: rework memory block management to be thread-safe and mostly lock-free. pa_memblock is now an opaque structure. Access to its fields is now done through various accessor functions in a thread-safe manner. pa_memblock_acquire() and pa_memblock_release() are now used to access the attached audio data. Why? To allow safe manipulation of the memory pointer maintained by the memory block. Internally _acquire() and _release() maintain a reference counter. Please do not confuse this reference counter whith the one maintained by pa_memblock_ref()/_unref()! As a side effect this patch removes all direct usages of AO_t and replaces it with pa_atomic_xxx based code. This stuff needs some serious testing love. Especially if threads are actively used. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1404 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/memblockq.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/pulsecore/memblockq.c') diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index e6b73fc5..dab44dc3 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -176,7 +176,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { assert(uchunk); assert(uchunk->memblock); assert(uchunk->length > 0); - assert(uchunk->index + uchunk->length <= uchunk->memblock->length); + assert(uchunk->index + uchunk->length <= pa_memblock_get_length(uchunk->memblock)); if (uchunk->length % bq->base) return -1; @@ -360,8 +360,8 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { if (bq->silence) { chunk->memblock = pa_memblock_ref(bq->silence); - if (!length || length > chunk->memblock->length) - length = chunk->memblock->length; + if (!length || length > pa_memblock_get_length(chunk->memblock)) + length = pa_memblock_get_length(chunk->memblock); chunk->length = length; } else { @@ -413,8 +413,8 @@ void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length if (bq->silence) { - if (!l || l > bq->silence->length) - l = bq->silence->length; + if (!l || l > pa_memblock_get_length(bq->silence)) + l = pa_memblock_get_length(bq->silence); } -- cgit From 8dc62142765249addf131b058c27f931ede1776b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 6 Nov 2006 13:06:01 +0000 Subject: Revert r1404 and keep it on a development branch until it is fully tested. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1409 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/memblockq.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/pulsecore/memblockq.c') diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index dab44dc3..e6b73fc5 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -176,7 +176,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { assert(uchunk); assert(uchunk->memblock); assert(uchunk->length > 0); - assert(uchunk->index + uchunk->length <= pa_memblock_get_length(uchunk->memblock)); + assert(uchunk->index + uchunk->length <= uchunk->memblock->length); if (uchunk->length % bq->base) return -1; @@ -360,8 +360,8 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { if (bq->silence) { chunk->memblock = pa_memblock_ref(bq->silence); - if (!length || length > pa_memblock_get_length(chunk->memblock)) - length = pa_memblock_get_length(chunk->memblock); + if (!length || length > chunk->memblock->length) + length = chunk->memblock->length; chunk->length = length; } else { @@ -413,8 +413,8 @@ void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length if (bq->silence) { - if (!l || l > pa_memblock_get_length(bq->silence)) - l = pa_memblock_get_length(bq->silence); + if (!l || l > bq->silence->length) + l = bq->silence->length; } -- cgit From 521daf6f0ac4fa6a2fbfb5d523c0c743342dca2b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 4 Jan 2007 13:43:45 +0000 Subject: Huge trailing whitespace cleanup. Let's keep the tree pure from here on, mmmkay? git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1418 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/memblockq.c | 80 +++++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 40 deletions(-) (limited to 'src/pulsecore/memblockq.c') diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index e6b73fc5..4a845a53 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -61,12 +61,12 @@ pa_memblockq* pa_memblockq_new( size_t prebuf, size_t minreq, pa_memblock *silence) { - + pa_memblockq* bq; - + assert(base > 0); assert(maxlength >= base); - + bq = pa_xnew(pa_memblockq, 1); bq->blocks = bq->blocks_tail = NULL; bq->n_blocks = 0; @@ -90,20 +90,20 @@ pa_memblockq* pa_memblockq_new( bq->prebuf = bq->maxlength; bq->minreq = (minreq/base)*base; - + if (bq->minreq > bq->tlength - bq->prebuf) bq->minreq = bq->tlength - bq->prebuf; if (!bq->minreq) bq->minreq = 1; - + pa_log_debug("memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", (unsigned long)bq->maxlength, (unsigned long)bq->tlength, (unsigned long)bq->base, (unsigned long)bq->prebuf, (unsigned long)bq->minreq); bq->state = bq->prebuf ? PREBUF : RUNNING; bq->silence = silence ? pa_memblock_ref(silence) : NULL; bq->mcalign = NULL; - + return bq; } @@ -117,7 +117,7 @@ void pa_memblockq_free(pa_memblockq* bq) { if (bq->mcalign) pa_mcalign_free(bq->mcalign); - + pa_xfree(bq); } @@ -126,12 +126,12 @@ static void drop_block(pa_memblockq *bq, struct memblock_list *q) { assert(q); assert(bq->n_blocks >= 1); - + if (q->prev) q->prev->next = q->next; else bq->blocks = q->next; - + if (q->next) q->next->prev = q->prev; else @@ -168,10 +168,10 @@ static int can_push(pa_memblockq *bq, size_t l) { } int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { - + struct memblock_list *q, *n; pa_memchunk chunk; - + assert(bq); assert(uchunk); assert(uchunk->memblock); @@ -185,7 +185,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { return -1; chunk = *uchunk; - + if (bq->read_index > bq->write_index) { /* We currently have a buffer underflow, we need to drop some @@ -203,7 +203,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { return 0; } } - + /* We go from back to front to look for the right place to add * this new entry. Drop data we will overwrite on the way */ @@ -275,29 +275,29 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { assert(bq->write_index + (int64_t)chunk.length > q->index && bq->write_index + (int64_t)chunk.length < q->index + (int64_t)q->chunk.length && bq->write_index < q->index); - + /* The job overwrites the current entry at the end, so let's drop the beginning of this entry */ d = bq->write_index + chunk.length - q->index; q->index += d; q->chunk.index += d; q->chunk.length -= d; - + q = q->prev; } - + } if (q) { assert(bq->write_index >= q->index + (int64_t)q->chunk.length); assert(!q->next || (bq->write_index + (int64_t)chunk.length <= q->next->index)); - + /* Try to merge memory blocks */ - + if (q->chunk.memblock == chunk.memblock && q->chunk.index + (int64_t)q->chunk.length == chunk.index && bq->write_index == q->index + (int64_t)q->chunk.length) { - + q->chunk.length += chunk.length; bq->write_index += chunk.length; return 0; @@ -324,7 +324,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { n->prev->next = n; else bq->blocks = n; - + bq->n_blocks++; return 0; } @@ -347,7 +347,7 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { bq->state = PREBUF; return -1; } - + /* Do we need to spit out silence? */ if (!bq->blocks || bq->blocks->index > bq->read_index) { @@ -362,7 +362,7 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { if (!length || length > chunk->memblock->length) length = chunk->memblock->length; - + chunk->length = length; } else { @@ -370,7 +370,7 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { * the time to sleep */ if (!bq->blocks) return -1; - + chunk->memblock = NULL; chunk->length = length; } @@ -381,7 +381,7 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { /* Ok, let's pass real data to the caller */ assert(bq->blocks->index == bq->read_index); - + *chunk = bq->blocks->chunk; pa_memblock_ref(chunk->memblock); @@ -432,14 +432,14 @@ void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length assert(bq->blocks->index >= bq->read_index); d = (size_t) (bq->blocks->index - bq->read_index); - + if (d >= length) { /* The first block is too far in the future */ - + bq->read_index += length; break; } else { - + length -= d; bq->read_index += d; } @@ -462,7 +462,7 @@ void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length bq->read_index += length; break; } - + } else { /* The list is empty, there's nothing we could drop */ @@ -477,7 +477,7 @@ int pa_memblockq_is_readable(pa_memblockq *bq) { if (bq->prebuf > 0) { size_t l = pa_memblockq_get_length(bq); - + if (bq->state == PREBUF && l < bq->prebuf) return 0; @@ -493,7 +493,7 @@ int pa_memblockq_is_writable(pa_memblockq *bq, size_t length) { if (length % bq->base) return 0; - + return pa_memblockq_get_length(bq) + length <= bq->tlength; } @@ -502,7 +502,7 @@ size_t pa_memblockq_get_length(pa_memblockq *bq) { if (bq->write_index <= bq->read_index) return 0; - + return (size_t) (bq->write_index - bq->read_index); } @@ -546,7 +546,7 @@ void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek) { void pa_memblockq_flush(pa_memblockq *bq) { assert(bq); - + while (bq->blocks) drop_block(bq, bq->blocks); @@ -559,7 +559,7 @@ void pa_memblockq_flush(pa_memblockq *bq) { size_t pa_memblockq_get_tlength(pa_memblockq *bq) { assert(bq); - + return bq->tlength; } @@ -578,18 +578,18 @@ int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk) { assert(bq); assert(chunk && bq->base); - + if (bq->base == 1) return pa_memblockq_push(bq, chunk); - + if (!bq->mcalign) bq->mcalign = pa_mcalign_new(bq->base); if (!can_push(bq, pa_mcalign_csize(bq->mcalign, chunk->length))) return -1; - + pa_mcalign_push(bq->mcalign, chunk); - + while (pa_mcalign_pop(bq->mcalign, &rchunk) >= 0) { int r; r = pa_memblockq_push(bq, &rchunk); -- cgit From 06211b7c8fd329137ae9003818543912a87d9898 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 13 Feb 2007 15:35:19 +0000 Subject: Add copyright notices to all relevant files. (based on svn log) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1426 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/memblockq.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/pulsecore/memblockq.c') diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index 4a845a53..e31fb6df 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -3,6 +3,8 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, -- cgit From a67c21f093202f142438689d3f7cfbdf4ea82eea Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 28 Oct 2007 19:13:50 +0000 Subject: merge 'lennart' branch back into trunk. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1971 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/memblockq.c | 331 ++++++++++++++++++++++++++-------------------- 1 file changed, 190 insertions(+), 141 deletions(-) (limited to 'src/pulsecore/memblockq.c') diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index e31fb6df..a46155a9 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -36,23 +35,29 @@ #include #include +#include +#include #include "memblockq.h" -struct memblock_list { - struct memblock_list *next, *prev; +struct list_item { + struct list_item *next, *prev; int64_t index; pa_memchunk chunk; }; +PA_STATIC_FLIST_DECLARE(list_items, 0, pa_xfree); + struct pa_memblockq { - struct memblock_list *blocks, *blocks_tail; + struct list_item *blocks, *blocks_tail; unsigned n_blocks; size_t maxlength, tlength, base, prebuf, minreq; int64_t read_index, write_index; - enum { PREBUF, RUNNING } state; + pa_bool_t in_prebuf; pa_memblock *silence; pa_mcalign *mcalign; + int64_t missing; + size_t requested; }; pa_memblockq* pa_memblockq_new( @@ -66,8 +71,8 @@ pa_memblockq* pa_memblockq_new( pa_memblockq* bq; - assert(base > 0); - assert(maxlength >= base); + pa_assert(base > 0); + pa_assert(maxlength >= base); bq = pa_xnew(pa_memblockq, 1); bq->blocks = bq->blocks_tail = NULL; @@ -77,13 +82,13 @@ pa_memblockq* pa_memblockq_new( bq->read_index = bq->write_index = idx; pa_log_debug("memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", - (unsigned long)maxlength, (unsigned long)tlength, (unsigned long)base, (unsigned long)prebuf, (unsigned long)minreq); + (unsigned long) maxlength, (unsigned long) tlength, (unsigned long) base, (unsigned long) prebuf, (unsigned long) minreq); bq->maxlength = ((maxlength+base-1)/base)*base; - assert(bq->maxlength >= base); + pa_assert(bq->maxlength >= base); bq->tlength = ((tlength+base-1)/base)*base; - if (!bq->tlength || bq->tlength >= bq->maxlength) + if (bq->tlength <= 0 || bq->tlength > bq->maxlength) bq->tlength = bq->maxlength; bq->prebuf = (prebuf == (size_t) -1) ? bq->tlength/2 : prebuf; @@ -102,15 +107,18 @@ pa_memblockq* pa_memblockq_new( pa_log_debug("memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", (unsigned long)bq->maxlength, (unsigned long)bq->tlength, (unsigned long)bq->base, (unsigned long)bq->prebuf, (unsigned long)bq->minreq); - bq->state = bq->prebuf ? PREBUF : RUNNING; + bq->in_prebuf = bq->prebuf > 0; bq->silence = silence ? pa_memblock_ref(silence) : NULL; bq->mcalign = NULL; + bq->missing = bq->tlength; + bq->requested = 0; + return bq; } void pa_memblockq_free(pa_memblockq* bq) { - assert(bq); + pa_assert(bq); pa_memblockq_flush(bq); @@ -123,11 +131,11 @@ void pa_memblockq_free(pa_memblockq* bq) { pa_xfree(bq); } -static void drop_block(pa_memblockq *bq, struct memblock_list *q) { - assert(bq); - assert(q); +static void drop_block(pa_memblockq *bq, struct list_item *q) { + pa_assert(bq); + pa_assert(q); - assert(bq->n_blocks >= 1); + pa_assert(bq->n_blocks >= 1); if (q->prev) q->prev->next = q->next; @@ -140,15 +148,17 @@ static void drop_block(pa_memblockq *bq, struct memblock_list *q) { bq->blocks_tail = q->prev; pa_memblock_unref(q->chunk.memblock); - pa_xfree(q); + + if (pa_flist_push(PA_STATIC_FLIST_GET(list_items), q) < 0) + pa_xfree(q); bq->n_blocks--; } -static int can_push(pa_memblockq *bq, size_t l) { +static pa_bool_t can_push(pa_memblockq *bq, size_t l) { int64_t end; - assert(bq); + pa_assert(bq); if (bq->read_index > bq->write_index) { size_t d = bq->read_index - bq->write_index; @@ -156,7 +166,7 @@ static int can_push(pa_memblockq *bq, size_t l) { if (l > d) l -= d; else - return 1; + return TRUE; } end = bq->blocks_tail ? bq->blocks_tail->index + bq->blocks_tail->chunk.length : 0; @@ -164,21 +174,21 @@ static int can_push(pa_memblockq *bq, size_t l) { /* Make sure that the list doesn't get too long */ if (bq->write_index + (int64_t)l > end) if (bq->write_index + l - bq->read_index > bq->maxlength) - return 0; + return FALSE; - return 1; + return TRUE; } int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { - - struct memblock_list *q, *n; + struct list_item *q, *n; pa_memchunk chunk; + int64_t old, delta; - assert(bq); - assert(uchunk); - assert(uchunk->memblock); - assert(uchunk->length > 0); - assert(uchunk->index + uchunk->length <= uchunk->memblock->length); + pa_assert(bq); + pa_assert(uchunk); + pa_assert(uchunk->memblock); + pa_assert(uchunk->length > 0); + pa_assert(uchunk->index + uchunk->length <= pa_memblock_get_length(uchunk->memblock)); if (uchunk->length % bq->base) return -1; @@ -186,6 +196,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { if (!can_push(bq, uchunk->length)) return -1; + old = bq->write_index; chunk = *uchunk; if (bq->read_index > bq->write_index) { @@ -198,11 +209,11 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { if (chunk.length > d) { chunk.index += d; chunk.length -= d; - bq->write_index = bq->read_index; + bq->write_index += d; } else { /* We drop the incoming data completely */ bq->write_index += chunk.length; - return 0; + goto finish; } } @@ -212,10 +223,10 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { q = bq->blocks_tail; while (q) { - if (bq->write_index >= q->index + (int64_t)q->chunk.length) + if (bq->write_index >= q->index + (int64_t) q->chunk.length) /* We found the entry where we need to place the new entry immediately after */ break; - else if (bq->write_index + (int64_t)chunk.length <= q->index) { + else if (bq->write_index + (int64_t) chunk.length <= q->index) { /* This entry isn't touched at all, let's skip it */ q = q->prev; } else if (bq->write_index <= q->index && @@ -223,7 +234,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { /* This entry is fully replaced by the new entry, so let's drop it */ - struct memblock_list *p; + struct list_item *p; p = q; q = q->prev; drop_block(bq, p); @@ -234,17 +245,19 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { if (bq->write_index + chunk.length < q->index + q->chunk.length) { /* We need to save the end of this memchunk */ - struct memblock_list *p; + struct list_item *p; size_t d; /* Create a new list entry for the end of thie memchunk */ - p = pa_xnew(struct memblock_list, 1); + if (!(p = pa_flist_pop(PA_STATIC_FLIST_GET(list_items)))) + p = pa_xnew(struct list_item, 1); + p->chunk = q->chunk; pa_memblock_ref(p->chunk.memblock); /* Calculate offset */ d = bq->write_index + chunk.length - q->index; - assert(d > 0); + pa_assert(d > 0); /* Drop it from the new entry */ p->index = q->index + d; @@ -263,7 +276,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { /* Truncate the chunk */ if (!(q->chunk.length = bq->write_index - q->index)) { - struct memblock_list *p; + struct list_item *p; p = q; q = q->prev; drop_block(bq, p); @@ -274,7 +287,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { } else { size_t d; - assert(bq->write_index + (int64_t)chunk.length > q->index && + pa_assert(bq->write_index + (int64_t)chunk.length > q->index && bq->write_index + (int64_t)chunk.length < q->index + (int64_t)q->chunk.length && bq->write_index < q->index); @@ -287,12 +300,11 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { q = q->prev; } - } if (q) { - assert(bq->write_index >= q->index + (int64_t)q->chunk.length); - assert(!q->next || (bq->write_index + (int64_t)chunk.length <= q->next->index)); + pa_assert(bq->write_index >= q->index + (int64_t)q->chunk.length); + pa_assert(!q->next || (bq->write_index + (int64_t)chunk.length <= q->next->index)); /* Try to merge memory blocks */ @@ -302,13 +314,14 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { q->chunk.length += chunk.length; bq->write_index += chunk.length; - return 0; + goto finish; } } else - assert(!bq->blocks || (bq->write_index + (int64_t)chunk.length <= bq->blocks->index)); + pa_assert(!bq->blocks || (bq->write_index + (int64_t)chunk.length <= bq->blocks->index)); + if (!(n = pa_flist_pop(PA_STATIC_FLIST_GET(list_items)))) + n = pa_xnew(struct list_item, 1); - n = pa_xnew(struct memblock_list, 1); n->chunk = chunk; pa_memblock_ref(n->chunk.memblock); n->index = bq->write_index; @@ -328,27 +341,52 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { bq->blocks = n; bq->n_blocks++; + +finish: + + delta = bq->write_index - old; + + if (delta >= bq->requested) { + delta -= bq->requested; + bq->requested = 0; + } else { + bq->requested -= delta; + delta = 0; + } + + bq->missing -= delta; + return 0; } -int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { - assert(bq); - assert(chunk); +static pa_bool_t memblockq_check_prebuf(pa_memblockq *bq) { + pa_assert(bq); - if (bq->state == PREBUF) { + if (bq->in_prebuf) { - /* We need to pre-buffer */ if (pa_memblockq_get_length(bq) < bq->prebuf) - return -1; + return TRUE; - bq->state = RUNNING; + bq->in_prebuf = FALSE; + return FALSE; + } else { - } else if (bq->prebuf > 0 && bq->read_index >= bq->write_index) { + if (bq->prebuf > 0 && bq->read_index >= bq->write_index) { + bq->in_prebuf = TRUE; + return TRUE; + } - /* Buffer underflow protection */ - bq->state = PREBUF; - return -1; + return FALSE; } +} + +int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { + pa_assert(bq); + pa_assert(chunk); + + /* We need to pre-buffer */ + if (memblockq_check_prebuf(bq)) + return -1; /* Do we need to spit out silence? */ if (!bq->blocks || bq->blocks->index > bq->read_index) { @@ -362,8 +400,8 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { if (bq->silence) { chunk->memblock = pa_memblock_ref(bq->silence); - if (!length || length > chunk->memblock->length) - length = chunk->memblock->length; + if (!length || length > pa_memblock_get_length(chunk->memblock)) + length = pa_memblock_get_length(chunk->memblock); chunk->length = length; } else { @@ -382,7 +420,7 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { } /* Ok, let's pass real data to the caller */ - assert(bq->blocks->index == bq->read_index); + pa_assert(bq->blocks->index == bq->read_index); *chunk = bq->blocks->chunk; pa_memblock_ref(chunk->memblock); @@ -390,48 +428,23 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { return 0; } -void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length) { - assert(bq); - assert(length % bq->base == 0); - - assert(!chunk || length <= chunk->length); +void pa_memblockq_drop(pa_memblockq *bq, size_t length) { + int64_t old, delta; + pa_assert(bq); + pa_assert(length % bq->base == 0); - if (chunk) { - - if (bq->blocks && bq->blocks->index == bq->read_index) { - /* The first item in queue is valid */ - - /* Does the chunk match with what the user supplied us? */ - if (memcmp(chunk, &bq->blocks->chunk, sizeof(pa_memchunk)) != 0) - return; - - } else { - size_t l; - - /* The first item in the queue is not yet relevant */ - - assert(!bq->blocks || bq->blocks->index > bq->read_index); - l = bq->blocks ? bq->blocks->index - bq->read_index : 0; - - if (bq->silence) { - - if (!l || l > bq->silence->length) - l = bq->silence->length; - - } - - /* Do the entries still match? */ - if (chunk->index != 0 || chunk->length != l || chunk->memblock != bq->silence) - return; - } - } + old = bq->read_index; while (length > 0) { + /* Do not drop any data when we are in prebuffering mode */ + if (memblockq_check_prebuf(bq)) + break; + if (bq->blocks) { size_t d; - assert(bq->blocks->index >= bq->read_index); + pa_assert(bq->blocks->index >= bq->read_index); d = (size_t) (bq->blocks->index - bq->read_index); @@ -446,7 +459,7 @@ void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length bq->read_index += d; } - assert(bq->blocks->index == bq->read_index); + pa_assert(bq->blocks->index == bq->read_index); if (bq->blocks->chunk.length <= length) { /* We need to drop the full block */ @@ -472,35 +485,25 @@ void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length break; } } + + delta = bq->read_index - old; + bq->missing += delta; } int pa_memblockq_is_readable(pa_memblockq *bq) { - assert(bq); - - if (bq->prebuf > 0) { - size_t l = pa_memblockq_get_length(bq); - - if (bq->state == PREBUF && l < bq->prebuf) - return 0; - - if (l <= 0) - return 0; - } - - return 1; -} + pa_assert(bq); -int pa_memblockq_is_writable(pa_memblockq *bq, size_t length) { - assert(bq); + if (memblockq_check_prebuf(bq)) + return 0; - if (length % bq->base) + if (pa_memblockq_get_length(bq) <= 0) return 0; - return pa_memblockq_get_length(bq) + length <= bq->tlength; + return 1; } size_t pa_memblockq_get_length(pa_memblockq *bq) { - assert(bq); + pa_assert(bq); if (bq->write_index <= bq->read_index) return 0; @@ -510,76 +513,106 @@ size_t pa_memblockq_get_length(pa_memblockq *bq) { size_t pa_memblockq_missing(pa_memblockq *bq) { size_t l; - assert(bq); + pa_assert(bq); if ((l = pa_memblockq_get_length(bq)) >= bq->tlength) return 0; l = bq->tlength - l; - return (l >= bq->minreq) ? l : 0; + + return l >= bq->minreq ? l : 0; } size_t pa_memblockq_get_minreq(pa_memblockq *bq) { - assert(bq); + pa_assert(bq); return bq->minreq; } void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek) { - assert(bq); + int64_t old, delta; + pa_assert(bq); + + old = bq->write_index; switch (seek) { case PA_SEEK_RELATIVE: bq->write_index += offset; - return; + break; case PA_SEEK_ABSOLUTE: bq->write_index = offset; - return; + break; case PA_SEEK_RELATIVE_ON_READ: bq->write_index = bq->read_index + offset; - return; + break; case PA_SEEK_RELATIVE_END: - bq->write_index = (bq->blocks_tail ? bq->blocks_tail->index + (int64_t)bq->blocks_tail->chunk.length : bq->read_index) + offset; - return; + bq->write_index = (bq->blocks_tail ? bq->blocks_tail->index + (int64_t) bq->blocks_tail->chunk.length : bq->read_index) + offset; + break; + default: + pa_assert_not_reached(); } - assert(0); + delta = bq->write_index - old; + + if (delta >= bq->requested) { + delta -= bq->requested; + bq->requested = 0; + } else if (delta >= 0) { + bq->requested -= delta; + delta = 0; + } + + bq->missing -= delta; } void pa_memblockq_flush(pa_memblockq *bq) { - assert(bq); + int64_t old, delta; + pa_assert(bq); while (bq->blocks) drop_block(bq, bq->blocks); - assert(bq->n_blocks == 0); + pa_assert(bq->n_blocks == 0); + old = bq->write_index; bq->write_index = bq->read_index; pa_memblockq_prebuf_force(bq); + + delta = bq->write_index - old; + + if (delta > bq->requested) { + delta -= bq->requested; + bq->requested = 0; + } else if (delta >= 0) { + bq->requested -= delta; + delta = 0; + } + + bq->missing -= delta; } size_t pa_memblockq_get_tlength(pa_memblockq *bq) { - assert(bq); + pa_assert(bq); return bq->tlength; } int64_t pa_memblockq_get_read_index(pa_memblockq *bq) { - assert(bq); + pa_assert(bq); return bq->read_index; } int64_t pa_memblockq_get_write_index(pa_memblockq *bq) { - assert(bq); + pa_assert(bq); return bq->write_index; } int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk) { pa_memchunk rchunk; - assert(bq); - assert(chunk && bq->base); + pa_assert(bq); + pa_assert(chunk); if (bq->base == 1) return pa_memblockq_push(bq, chunk); @@ -606,36 +639,52 @@ int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk) { void pa_memblockq_shorten(pa_memblockq *bq, size_t length) { size_t l; - assert(bq); + pa_assert(bq); l = pa_memblockq_get_length(bq); if (l > length) - pa_memblockq_drop(bq, NULL, l - length); + pa_memblockq_drop(bq, l - length); } void pa_memblockq_prebuf_disable(pa_memblockq *bq) { - assert(bq); + pa_assert(bq); - if (bq->state == PREBUF) - bq->state = RUNNING; + bq->in_prebuf = FALSE; } void pa_memblockq_prebuf_force(pa_memblockq *bq) { - assert(bq); + pa_assert(bq); - if (bq->state == RUNNING && bq->prebuf > 0) - bq->state = PREBUF; + if (!bq->in_prebuf && bq->prebuf > 0) + bq->in_prebuf = TRUE; } size_t pa_memblockq_get_maxlength(pa_memblockq *bq) { - assert(bq); + pa_assert(bq); return bq->maxlength; } size_t pa_memblockq_get_prebuf(pa_memblockq *bq) { - assert(bq); + pa_assert(bq); return bq->prebuf; } + +size_t pa_memblockq_pop_missing(pa_memblockq *bq) { + size_t l; + + pa_assert(bq); + +/* pa_log("pop: %lli", bq->missing); */ + + if (bq->missing <= 0) + return 0; + + l = (size_t) bq->missing; + bq->missing = 0; + bq->requested += l; + + return l; +} -- cgit From d1d07783e0943ad51371978793d91f5b9990e17d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Nov 2007 01:19:28 +0000 Subject: add API to allow runtime reconfiguration of memblockqs git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2063 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/memblockq.c | 95 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 23 deletions(-) (limited to 'src/pulsecore/memblockq.c') diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index a46155a9..8247feab 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -72,7 +72,6 @@ pa_memblockq* pa_memblockq_new( pa_memblockq* bq; pa_assert(base > 0); - pa_assert(maxlength >= base); bq = pa_xnew(pa_memblockq, 1); bq->blocks = bq->blocks_tail = NULL; @@ -84,36 +83,20 @@ pa_memblockq* pa_memblockq_new( pa_log_debug("memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", (unsigned long) maxlength, (unsigned long) tlength, (unsigned long) base, (unsigned long) prebuf, (unsigned long) minreq); - bq->maxlength = ((maxlength+base-1)/base)*base; - pa_assert(bq->maxlength >= base); + bq->missing = bq->requested = bq->maxlength = bq->tlength = bq->prebuf = bq->minreq = 0; + bq->in_prebuf = TRUE; - bq->tlength = ((tlength+base-1)/base)*base; - if (bq->tlength <= 0 || bq->tlength > bq->maxlength) - bq->tlength = bq->maxlength; - - bq->prebuf = (prebuf == (size_t) -1) ? bq->tlength/2 : prebuf; - bq->prebuf = ((bq->prebuf+base-1)/base)*base; - if (bq->prebuf > bq->maxlength) - bq->prebuf = bq->maxlength; - - bq->minreq = (minreq/base)*base; - - if (bq->minreq > bq->tlength - bq->prebuf) - bq->minreq = bq->tlength - bq->prebuf; - - if (!bq->minreq) - bq->minreq = 1; + pa_memblockq_set_maxlength(bq, maxlength); + pa_memblockq_set_tlength(bq, tlength); + pa_memblockq_set_prebuf(bq, prebuf); + pa_memblockq_set_minreq(bq, minreq); pa_log_debug("memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu", (unsigned long)bq->maxlength, (unsigned long)bq->tlength, (unsigned long)bq->base, (unsigned long)bq->prebuf, (unsigned long)bq->minreq); - bq->in_prebuf = bq->prebuf > 0; bq->silence = silence ? pa_memblock_ref(silence) : NULL; bq->mcalign = NULL; - bq->missing = bq->tlength; - bq->requested = 0; - return bq; } @@ -688,3 +671,69 @@ size_t pa_memblockq_pop_missing(pa_memblockq *bq) { return l; } + +void pa_memblockq_set_maxlength(pa_memblockq *bq, size_t maxlength) { + pa_assert(bq); + + bq->maxlength = ((maxlength+bq->base-1)/bq->base)*bq->base; + + if (bq->maxlength < bq->base) + bq->maxlength = bq->base; + + if (bq->tlength > bq->maxlength) + pa_memblockq_set_tlength(bq, bq->maxlength); + + if (bq->prebuf > bq->maxlength) + pa_memblockq_set_prebuf(bq, bq->maxlength); +} + +void pa_memblockq_set_tlength(pa_memblockq *bq, size_t tlength) { + size_t old_tlength; + pa_assert(bq); + + old_tlength = bq->tlength; + + if (tlength <= 0) + tlength = bq->maxlength; + + bq->tlength = ((tlength+bq->base-1)/bq->base)*bq->base; + + if (bq->tlength > bq->maxlength) + bq->tlength = bq->maxlength; + + if (bq->minreq > bq->tlength - bq->prebuf) + pa_memblockq_set_minreq(bq, bq->tlength - bq->prebuf); + + bq->missing += (int64_t) bq->tlength - (int64_t) old_tlength; +} + +void pa_memblockq_set_prebuf(pa_memblockq *bq, size_t prebuf) { + pa_assert(bq); + + bq->prebuf = (prebuf == (size_t) -1) ? bq->tlength/2 : prebuf; + bq->prebuf = ((bq->prebuf+bq->base-1)/bq->base)*bq->base; + + if (prebuf > 0 && bq->prebuf < bq->base) + bq->prebuf = bq->base; + + if (bq->prebuf > bq->maxlength) + bq->prebuf = bq->maxlength; + + if (bq->prebuf <= 0 || pa_memblockq_get_length(bq) >= bq->prebuf) + bq->in_prebuf = FALSE; + + if (bq->minreq > bq->tlength - bq->prebuf) + pa_memblockq_set_minreq(bq, bq->tlength - bq->prebuf); +} + +void pa_memblockq_set_minreq(pa_memblockq *bq, size_t minreq) { + pa_assert(bq); + + bq->minreq = (minreq/bq->base)*bq->base; + + if (bq->minreq > bq->tlength - bq->prebuf) + bq->minreq = bq->tlength - bq->prebuf; + + if (bq->minreq < bq->base) + bq->minreq = bq->base; +} -- cgit