mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-04 13:29:59 -05:00
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:
parent
ada92732f0
commit
e87eb85474
6 changed files with 139 additions and 33 deletions
|
|
@ -231,6 +231,7 @@ enum {
|
|||
CONNECTION_MESSAGE_REVOKE
|
||||
};
|
||||
|
||||
static bool sink_input_process_underrun_cb(pa_sink_input *i);
|
||||
static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk);
|
||||
static void sink_input_kill_cb(pa_sink_input *i);
|
||||
static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend);
|
||||
|
|
@ -1171,6 +1172,7 @@ static playback_stream* playback_stream_new(
|
|||
|
||||
s->sink_input->parent.process_msg = sink_input_process_msg;
|
||||
s->sink_input->pop = sink_input_pop_cb;
|
||||
s->sink_input->process_underrun = sink_input_process_underrun_cb;
|
||||
s->sink_input->process_rewind = sink_input_process_rewind_cb;
|
||||
s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
|
||||
s->sink_input->update_max_request = sink_input_update_max_request_cb;
|
||||
|
|
@ -1573,6 +1575,44 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int
|
|||
return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
|
||||
}
|
||||
|
||||
|
||||
static bool handle_input_underrun(playback_stream *s, bool force)
|
||||
{
|
||||
bool send_drain;
|
||||
|
||||
if (pa_memblockq_is_readable(s->memblockq))
|
||||
return false;
|
||||
|
||||
if (!s->is_underrun)
|
||||
pa_log_debug("%s %s of '%s'", force ? "Actual" : "Implicit",
|
||||
s->drain_request ? "drain" : "underrun", pa_strnull(pa_proplist_gets(s->sink_input->proplist, PA_PROP_MEDIA_NAME)));
|
||||
|
||||
send_drain = s->drain_request && (force || pa_sink_input_safe_to_remove(s->sink_input));
|
||||
|
||||
if (send_drain) {
|
||||
s->drain_request = false;
|
||||
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, PA_UINT_TO_PTR(s->drain_tag), 0, NULL, NULL);
|
||||
pa_log_debug("Drain acknowledged of '%s'", pa_strnull(pa_proplist_gets(s->sink_input->proplist, PA_PROP_MEDIA_NAME)));
|
||||
} else if (!s->is_underrun) {
|
||||
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, pa_memblockq_get_read_index(s->memblockq), NULL, NULL);
|
||||
}
|
||||
s->is_underrun = true;
|
||||
playback_stream_request_bytes(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Called from thread context */
|
||||
static bool sink_input_process_underrun_cb(pa_sink_input *i) {
|
||||
playback_stream *s;
|
||||
|
||||
pa_sink_input_assert_ref(i);
|
||||
s = PLAYBACK_STREAM(i->userdata);
|
||||
playback_stream_assert_ref(s);
|
||||
|
||||
return handle_input_underrun(s, true);
|
||||
}
|
||||
|
||||
|
||||
/* Called from thread context */
|
||||
static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
|
||||
playback_stream *s;
|
||||
|
|
@ -1586,25 +1626,11 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
|
|||
pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq));
|
||||
#endif
|
||||
|
||||
if (pa_memblockq_is_readable(s->memblockq))
|
||||
s->is_underrun = FALSE;
|
||||
else {
|
||||
if (!s->is_underrun)
|
||||
pa_log_debug("Underrun on '%s', %lu bytes in queue.", pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME)), (unsigned long) pa_memblockq_get_length(s->memblockq));
|
||||
|
||||
if (s->drain_request && pa_sink_input_safe_to_remove(i)) {
|
||||
s->drain_request = FALSE;
|
||||
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, PA_UINT_TO_PTR(s->drain_tag), 0, NULL, NULL);
|
||||
} else if (!s->is_underrun)
|
||||
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, pa_memblockq_get_read_index(s->memblockq), NULL, NULL);
|
||||
|
||||
s->is_underrun = TRUE;
|
||||
|
||||
playback_stream_request_bytes(s);
|
||||
}
|
||||
if (!handle_input_underrun(s, false))
|
||||
s->is_underrun = false;
|
||||
|
||||
/* This call will not fail with prebuf=0, hence we check for
|
||||
underrun explicitly above */
|
||||
underrun explicitly in handle_input_underrun */
|
||||
if (pa_memblockq_peek(s->memblockq, chunk) < 0)
|
||||
return -1;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue