mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-08 13:29:59 -05:00
remove underrun condition in pa_sinks. Instead return silence in pa_sink_render() when necessary. This is required to guarantee that the time functions in connected sink inputs stays linear
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1490 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
780f736547
commit
013a55a692
2 changed files with 81 additions and 55 deletions
|
|
@ -116,6 +116,7 @@ pa_sink* pa_sink_new(
|
||||||
s->userdata = NULL;
|
s->userdata = NULL;
|
||||||
|
|
||||||
s->asyncmsgq = NULL;
|
s->asyncmsgq = NULL;
|
||||||
|
s->silence = NULL;
|
||||||
|
|
||||||
r = pa_idxset_put(core->sinks, s, &s->index);
|
r = pa_idxset_put(core->sinks, s, &s->index);
|
||||||
pa_assert(s->index != PA_IDXSET_INVALID && r >= 0);
|
pa_assert(s->index != PA_IDXSET_INVALID && r >= 0);
|
||||||
|
|
@ -222,6 +223,9 @@ static void sink_free(pa_object *o) {
|
||||||
|
|
||||||
pa_hashmap_free(s->thread_info.inputs, NULL, NULL);
|
pa_hashmap_free(s->thread_info.inputs, NULL, NULL);
|
||||||
|
|
||||||
|
if (s->silence)
|
||||||
|
pa_memblock_unref(s->silence);
|
||||||
|
|
||||||
pa_xfree(s->name);
|
pa_xfree(s->name);
|
||||||
pa_xfree(s->description);
|
pa_xfree(s->description);
|
||||||
pa_xfree(s->driver);
|
pa_xfree(s->driver);
|
||||||
|
|
@ -270,53 +274,85 @@ static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) {
|
||||||
pa_sink_assert_ref(s);
|
pa_sink_assert_ref(s);
|
||||||
pa_assert(info);
|
pa_assert(info);
|
||||||
|
|
||||||
while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
|
while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxinfo > 0) {
|
||||||
/* Increase ref counter, to make sure that this input doesn't
|
pa_sink_input_assert_ref(i);
|
||||||
* vanish while we still need it */
|
|
||||||
pa_sink_input_ref(i);
|
|
||||||
|
|
||||||
if (pa_sink_input_peek(i, &info->chunk, &info->volume) < 0) {
|
if (pa_sink_input_peek(i, &info->chunk, &info->volume) < 0)
|
||||||
pa_sink_input_unref(i);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
info->userdata = i;
|
info->userdata = pa_sink_input_ref(i);
|
||||||
|
|
||||||
pa_assert(info->chunk.memblock);
|
pa_assert(info->chunk.memblock);
|
||||||
pa_assert(info->chunk.length);
|
pa_assert(info->chunk.length > 0);
|
||||||
|
|
||||||
info++;
|
info++;
|
||||||
maxinfo--;
|
|
||||||
n++;
|
n++;
|
||||||
|
maxinfo--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, size_t length) {
|
static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, size_t length) {
|
||||||
|
pa_sink_input *i;
|
||||||
|
void *state = NULL;
|
||||||
|
unsigned p = 0;
|
||||||
|
unsigned n_unreffed = 0;
|
||||||
|
|
||||||
pa_sink_assert_ref(s);
|
pa_sink_assert_ref(s);
|
||||||
pa_assert(info);
|
|
||||||
|
|
||||||
for (; maxinfo > 0; maxinfo--, info++) {
|
/* We optimize for the case where the order of the inputs has not changed */
|
||||||
pa_sink_input *i = info->userdata;
|
|
||||||
|
|
||||||
pa_assert(i);
|
while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
|
||||||
pa_assert(info->chunk.memblock);
|
unsigned j;
|
||||||
|
pa_mix_info* m;
|
||||||
|
|
||||||
|
pa_sink_input_assert_ref(i);
|
||||||
|
|
||||||
|
m = NULL;
|
||||||
|
|
||||||
|
/* Let's try to find the matching entry info the pa_mix_info array */
|
||||||
|
for (j = 0; j < n; j ++) {
|
||||||
|
|
||||||
|
if (info[p].userdata == i) {
|
||||||
|
m = info + p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++p > n)
|
||||||
|
p = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Drop read data */
|
/* Drop read data */
|
||||||
pa_sink_input_drop(i, &info->chunk, length);
|
pa_sink_input_drop(i, m ? &m->chunk : NULL, length);
|
||||||
pa_memblock_unref(info->chunk.memblock);
|
|
||||||
|
|
||||||
/* Decrease ref counter */
|
if (m) {
|
||||||
pa_sink_input_unref(i);
|
pa_sink_input_unref(m->userdata);
|
||||||
info->userdata = NULL;
|
m->userdata = NULL;
|
||||||
|
if (m->chunk.memblock)
|
||||||
|
pa_memblock_unref(m->chunk.memblock);
|
||||||
|
pa_memchunk_reset(&m->chunk);
|
||||||
|
|
||||||
|
n_unreffed += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now drop references to entries that are included in the
|
||||||
|
* pa_mix_info array but don't exist anymore */
|
||||||
|
|
||||||
|
if (n_unreffed < n) {
|
||||||
|
for (; n > 0; info++, n--) {
|
||||||
|
if (info->userdata)
|
||||||
|
pa_sink_input_unref(info->userdata);
|
||||||
|
if (info->chunk.memblock)
|
||||||
|
pa_memblock_unref(info->chunk.memblock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
|
void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
|
||||||
pa_mix_info info[MAX_MIX_CHANNELS];
|
pa_mix_info info[MAX_MIX_CHANNELS];
|
||||||
unsigned n;
|
unsigned n;
|
||||||
int r = -1;
|
|
||||||
|
|
||||||
pa_sink_assert_ref(s);
|
pa_sink_assert_ref(s);
|
||||||
pa_assert(length);
|
pa_assert(length);
|
||||||
|
|
@ -326,10 +362,19 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
|
||||||
|
|
||||||
n = fill_mix_info(s, info, MAX_MIX_CHANNELS);
|
n = fill_mix_info(s, info, MAX_MIX_CHANNELS);
|
||||||
|
|
||||||
if (n <= 0)
|
if (n == 0) {
|
||||||
goto finish;
|
|
||||||
|
|
||||||
if (n == 1) {
|
if (!s->silence || pa_memblock_get_length(s->silence) < length) {
|
||||||
|
if (s->silence)
|
||||||
|
pa_memblock_unref(s->silence);
|
||||||
|
s->silence = pa_silence_memblock_new(s->core->mempool, &s->sample_spec, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
result->memblock = pa_memblock_ref(s->silence);
|
||||||
|
result->length = length;
|
||||||
|
result->index = 0;
|
||||||
|
|
||||||
|
} else if (n == 1) {
|
||||||
pa_cvolume volume;
|
pa_cvolume volume;
|
||||||
|
|
||||||
*result = info[0].chunk;
|
*result = info[0].chunk;
|
||||||
|
|
@ -363,18 +408,12 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
|
||||||
if (s->monitor_source)
|
if (s->monitor_source)
|
||||||
pa_source_post(s->monitor_source, result);
|
pa_source_post(s->monitor_source, result);
|
||||||
|
|
||||||
r = 0;
|
|
||||||
|
|
||||||
finish:
|
|
||||||
pa_sink_unref(s);
|
pa_sink_unref(s);
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
|
void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
|
||||||
pa_mix_info info[MAX_MIX_CHANNELS];
|
pa_mix_info info[MAX_MIX_CHANNELS];
|
||||||
unsigned n;
|
unsigned n;
|
||||||
int r = -1;
|
|
||||||
|
|
||||||
pa_sink_assert_ref(s);
|
pa_sink_assert_ref(s);
|
||||||
pa_assert(target);
|
pa_assert(target);
|
||||||
|
|
@ -385,11 +424,9 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
|
||||||
|
|
||||||
n = fill_mix_info(s, info, MAX_MIX_CHANNELS);
|
n = fill_mix_info(s, info, MAX_MIX_CHANNELS);
|
||||||
|
|
||||||
if (n <= 0)
|
if (n == 0) {
|
||||||
goto finish;
|
pa_silence_memchunk(target, &s->sample_spec);
|
||||||
|
} else if (n == 1) {
|
||||||
|
|
||||||
if (n == 1) {
|
|
||||||
if (target->length > info[0].chunk.length)
|
if (target->length > info[0].chunk.length)
|
||||||
target->length = info[0].chunk.length;
|
target->length = info[0].chunk.length;
|
||||||
|
|
||||||
|
|
@ -435,12 +472,7 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
|
||||||
if (s->monitor_source)
|
if (s->monitor_source)
|
||||||
pa_source_post(s->monitor_source, target);
|
pa_source_post(s->monitor_source, target);
|
||||||
|
|
||||||
r = 0;
|
|
||||||
|
|
||||||
finish:
|
|
||||||
pa_sink_unref(s);
|
pa_sink_unref(s);
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
|
void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
|
||||||
|
|
@ -461,20 +493,12 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
|
||||||
chunk.index += d;
|
chunk.index += d;
|
||||||
chunk.length -= d;
|
chunk.length -= d;
|
||||||
|
|
||||||
if (pa_sink_render_into(s, &chunk) < 0)
|
pa_sink_render_into(s, &chunk);
|
||||||
break;
|
|
||||||
|
|
||||||
d += chunk.length;
|
d += chunk.length;
|
||||||
l -= chunk.length;
|
l -= chunk.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l > 0) {
|
|
||||||
chunk = *target;
|
|
||||||
chunk.index += d;
|
|
||||||
chunk.length -= d;
|
|
||||||
pa_silence_memchunk(&chunk, &s->sample_spec);
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_sink_unref(s);
|
pa_sink_unref(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,8 @@ struct pa_sink {
|
||||||
int soft_muted;
|
int soft_muted;
|
||||||
} thread_info;
|
} thread_info;
|
||||||
|
|
||||||
|
pa_memblock *silence;
|
||||||
|
|
||||||
void *userdata;
|
void *userdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -149,9 +151,9 @@ unsigned pa_sink_used_by(pa_sink *s);
|
||||||
|
|
||||||
/* To be used exclusively by the sink driver thread */
|
/* To be used exclusively by the sink driver thread */
|
||||||
|
|
||||||
int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result);
|
void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result);
|
||||||
void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result);
|
void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result);
|
||||||
int pa_sink_render_into(pa_sink*s, pa_memchunk *target);
|
void pa_sink_render_into(pa_sink*s, pa_memchunk *target);
|
||||||
void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target);
|
void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target);
|
||||||
|
|
||||||
int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk);
|
int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue