Big pile of dependant changes:

* Change pa_memblockq to carry silence memchunk instead of memblock and adapt all users
* Add new call pa_sink_input_get_silence() to get the suitable silence block for a sink input
* Implement monitoring sources properly by adding a delay queue to even out rewinds
* Remove pa_{sink|source}_ping() becaused unnecessary these days and not used
* Fix naming of various rewind related functions. Downstream is now _request_rewind(), upstream is _process_rewind()
* Fix volume adjustments for a single stream in pa_sink_render()
* Properly handle prebuf-style buffer underruns in pa_sink_input
* Don't allow rewinding to more than the last underrun
* Rework default buffering metrics selection for native protocol
* New functions pa_memblockq_prebuf_active(), pa_memblockq_silence()
* add option "mixer_reset=" to module-alsa-sink
* Other cleanups


git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/glitch-free@2283 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2008-04-20 20:16:55 +00:00
parent 7556ef5bfc
commit 62e7bc17c4
20 changed files with 950 additions and 531 deletions

View file

@ -55,7 +55,7 @@ struct pa_memblockq {
size_t maxlength, tlength, base, prebuf, minreq, maxrewind;
int64_t read_index, write_index;
pa_bool_t in_prebuf;
pa_memblock *silence;
pa_memchunk silence;
pa_mcalign *mcalign;
int64_t missing;
size_t requested;
@ -69,7 +69,7 @@ pa_memblockq* pa_memblockq_new(
size_t prebuf,
size_t minreq,
size_t maxrewind,
pa_memblock *silence) {
pa_memchunk *silence) {
pa_memblockq* bq;
@ -98,7 +98,12 @@ pa_memblockq* pa_memblockq_new(
pa_log_debug("memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu maxrewind=%lu",
(unsigned long) bq->maxlength, (unsigned long) bq->tlength, (unsigned long) bq->base, (unsigned long) bq->prebuf, (unsigned long) bq->minreq, (unsigned long) bq->maxrewind);
bq->silence = silence ? pa_memblock_ref(silence) : NULL;
if (silence) {
bq->silence = *silence;
pa_memblock_ref(bq->silence.memblock);
} else
pa_memchunk_reset(&bq->silence);
bq->mcalign = pa_mcalign_new(bq->base);
return bq;
@ -109,8 +114,8 @@ void pa_memblockq_free(pa_memblockq* bq) {
pa_memblockq_flush(bq);
if (bq->silence)
pa_memblock_unref(bq->silence);
if (bq->silence.memblock)
pa_memblock_unref(bq->silence.memblock);
if (bq->mcalign)
pa_mcalign_free(bq->mcalign);
@ -420,7 +425,7 @@ finish:
return 0;
}
static pa_bool_t memblockq_check_prebuf(pa_memblockq *bq) {
pa_bool_t pa_memblockq_prebuf_active(pa_memblockq *bq) {
pa_assert(bq);
if (bq->in_prebuf) {
@ -447,7 +452,7 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) {
pa_assert(chunk);
/* We need to pre-buffer */
if (memblockq_check_prebuf(bq))
if (pa_memblockq_prebuf_active(bq))
return -1;
fix_current_read(bq);
@ -466,13 +471,12 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) {
length = 0;
/* We need to return silence, since no data is yet available */
if (bq->silence) {
size_t l;
if (bq->silence.memblock) {
*chunk = bq->silence;
pa_memblock_ref(chunk->memblock);
chunk->memblock = pa_memblock_ref(bq->silence);
l = pa_memblock_get_length(chunk->memblock);
chunk->length = (length <= 0 || length > l) ? l : length;
if (length > 0 && length < chunk->length)
chunk->length = length;
} else {
@ -511,7 +515,7 @@ void pa_memblockq_drop(pa_memblockq *bq, size_t length) {
while (length > 0) {
/* Do not drop any data when we are in prebuffering mode */
if (memblockq_check_prebuf(bq))
if (pa_memblockq_prebuf_active(bq))
break;
fix_current_read(bq);
@ -546,10 +550,20 @@ void pa_memblockq_drop(pa_memblockq *bq, size_t length) {
bq->missing += delta;
}
void pa_memblockq_rewind(pa_memblockq *bq, size_t length) {
pa_assert(bq);
pa_assert(length % bq->base == 0);
/* This is kind of the inverse of pa_memblockq_drop() */
bq->read_index -= length;
bq->missing -= length;
}
pa_bool_t pa_memblockq_is_readable(pa_memblockq *bq) {
pa_assert(bq);
if (memblockq_check_prebuf(bq))
if (pa_memblockq_prebuf_active(bq))
return FALSE;
if (pa_memblockq_get_length(bq) <= 0)
@ -621,10 +635,7 @@ void pa_memblockq_flush(pa_memblockq *bq) {
int64_t old, delta;
pa_assert(bq);
while (bq->blocks)
drop_block(bq, bq->blocks);
pa_assert(bq->n_blocks == 0);
pa_memblockq_silence(bq);
old = bq->write_index;
bq->write_index = bq->read_index;
@ -757,18 +768,17 @@ 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;
old_tlength = bq->tlength;
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);
if (bq->minreq > bq->tlength)
pa_memblockq_set_minreq(bq, bq->tlength);
bq->missing += (int64_t) bq->tlength - (int64_t) old_tlength;
}
@ -776,8 +786,10 @@ void pa_memblockq_set_tlength(pa_memblockq *bq, size_t tlength) {
void pa_memblockq_set_prebuf(pa_memblockq *bq, size_t prebuf) {
pa_assert(bq);
bq->prebuf = (prebuf == (size_t) -1) ? bq->tlength : prebuf;
bq->prebuf = ((bq->prebuf+bq->base-1)/bq->base)*bq->base;
if (prebuf == (size_t) -1)
prebuf = bq->tlength;
bq->prebuf = ((prebuf+bq->base-1)/bq->base)*bq->base;
if (prebuf > 0 && bq->prebuf < bq->base)
bq->prebuf = bq->base;
@ -788,8 +800,8 @@ void pa_memblockq_set_prebuf(pa_memblockq *bq, size_t prebuf) {
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);
if (bq->minreq > bq->prebuf)
pa_memblockq_set_minreq(bq, bq->prebuf);
}
void pa_memblockq_set_minreq(pa_memblockq *bq, size_t minreq) {
@ -797,8 +809,11 @@ void pa_memblockq_set_minreq(pa_memblockq *bq, size_t minreq) {
bq->minreq = (minreq/bq->base)*bq->base;
if (bq->minreq > bq->tlength - bq->prebuf)
bq->minreq = bq->tlength - bq->prebuf;
if (bq->minreq > bq->tlength)
bq->minreq = bq->tlength;
if (bq->minreq > bq->prebuf)
bq->minreq = bq->prebuf;
if (bq->minreq < bq->base)
bq->minreq = bq->base;
@ -810,14 +825,6 @@ void pa_memblockq_set_maxrewind(pa_memblockq *bq, size_t maxrewind) {
bq->maxrewind = (maxrewind/bq->base)*bq->base;
}
void pa_memblockq_rewind(pa_memblockq *bq, size_t length) {
pa_assert(bq);
pa_assert(length % bq->base == 0);
bq->read_index -= length;
bq->missing -= length;
}
int pa_memblockq_splice(pa_memblockq *bq, pa_memblockq *source) {
pa_assert(bq);
@ -859,13 +866,17 @@ void pa_memblockq_willneed(pa_memblockq *bq) {
pa_memchunk_will_need(&q->chunk);
}
void pa_memblockq_set_silence(pa_memblockq *bq, pa_memblock *silence) {
void pa_memblockq_set_silence(pa_memblockq *bq, pa_memchunk *silence) {
pa_assert(bq);
if (bq->silence)
pa_memblock_unref(bq->silence);
if (bq->silence.memblock)
pa_memblock_unref(bq->silence.memblock);
bq->silence = silence ? pa_memblock_ref(silence) : NULL;
if (silence) {
bq->silence = *silence;
pa_memblock_ref(bq->silence.memblock);
} else
pa_memchunk_reset(&bq->silence);
}
pa_bool_t pa_memblockq_is_empty(pa_memblockq *bq) {
@ -873,3 +884,12 @@ pa_bool_t pa_memblockq_is_empty(pa_memblockq *bq) {
return !bq->blocks;
}
void pa_memblockq_silence(pa_memblockq *bq) {
pa_assert(bq);
while (bq->blocks)
drop_block(bq, bq->blocks);
pa_assert(bq->n_blocks == 0);
}