core, alsa: Better drain reporting

Previously, a drain request was acknowledged up to two hw buffers
too late, causing unnecessary delays.

This implements a new chain of events called process_underrun
which triggers exactly when the sink input has finished playing,
so the drain can be acknowledged quicker.

It could later be improved to give better underrun reporting to
clients too.

Tested-by: Dmitri Paduchikh <dpaduchikh@gmail.com>
Signed-off-by: David Henningsson <david.henningsson@canonical.com>
This commit is contained in:
David Henningsson 2013-03-01 11:51:54 +01:00
parent ada92732f0
commit e87eb85474
6 changed files with 139 additions and 33 deletions

View file

@ -532,6 +532,7 @@ int pa_sink_input_new(
i->thread_info.rewrite_flush = FALSE;
i->thread_info.dont_rewind_render = FALSE;
i->thread_info.underrun_for = (uint64_t) -1;
i->thread_info.underrun_for_sink = 0;
i->thread_info.playing_for = 0;
i->thread_info.direct_outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
@ -827,7 +828,7 @@ pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency) {
}
/* Called from thread context */
void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, pa_memchunk *chunk, pa_cvolume *volume) {
void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink bytes */, pa_memchunk *chunk, pa_cvolume *volume) {
pa_bool_t do_volume_adj_here, need_volume_factor_sink;
pa_bool_t volume_is_norm;
size_t block_size_max_sink, block_size_max_sink_input;
@ -896,8 +897,10 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p
pa_memblockq_seek(i->thread_info.render_memblockq, (int64_t) slength, PA_SEEK_RELATIVE, TRUE);
i->thread_info.playing_for = 0;
if (i->thread_info.underrun_for != (uint64_t) -1)
if (i->thread_info.underrun_for != (uint64_t) -1) {
i->thread_info.underrun_for += ilength_full;
i->thread_info.underrun_for_sink += slength;
}
break;
}
@ -907,6 +910,7 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p
pa_assert(tchunk.memblock);
i->thread_info.underrun_for = 0;
i->thread_info.underrun_for_sink = 0;
i->thread_info.playing_for += tchunk.length;
while (tchunk.length > 0) {
@ -1019,6 +1023,23 @@ void pa_sink_input_drop(pa_sink_input *i, size_t nbytes /* in sink sample spec *
pa_memblockq_drop(i->thread_info.render_memblockq, nbytes);
}
/* Called from thread context */
bool pa_sink_input_process_underrun(pa_sink_input *i) {
pa_sink_input_assert_ref(i);
pa_sink_input_assert_io_context(i);
if (pa_memblockq_is_readable(i->thread_info.render_memblockq))
return false;
if (i->process_underrun && i->process_underrun(i)) {
/* All valid data has been played back, so we can empty this queue. */
pa_memblockq_silence(i->thread_info.render_memblockq);
return true;
}
return false;
}
/* Called from thread context */
void pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in sink sample spec */) {
size_t lbq;
@ -1903,6 +1924,7 @@ void pa_sink_input_set_state_within_thread(pa_sink_input *i, pa_sink_input_state
pa_log_debug("Requesting rewind due to uncorking");
i->thread_info.underrun_for = (uint64_t) -1;
i->thread_info.underrun_for_sink = 0;
i->thread_info.playing_for = 0;
/* Set the uncorked state *before* requesting rewind */