Implement handling for PA_SINK_MESSAGE_GET_RAW_LATENCY in alsa source and sink to improve the latency reports for alsa devices. Use *_get_raw_latency_within_thread() calls in module loopback. This will remove latency discontinuities for alsa devices. --- src/modules/alsa/alsa-sink.c | 25 ++++++++++++++++++------- src/modules/alsa/alsa-source.c | 20 +++++++++++++++++--- src/modules/module-loopback.c | 8 ++++---- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 2fdebe0..ec867cb 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -892,8 +892,7 @@ static void update_smoother(struct userdata *u) { u->smoother_interval = PA_MIN (u->smoother_interval * 2, SMOOTHER_MAX_INTERVAL); } -static pa_usec_t sink_get_latency(struct userdata *u) { - pa_usec_t r; +static pa_usec_t sink_get_latency(struct userdata *u, bool raw) { int64_t delay; pa_usec_t now1, now2; @@ -904,12 +903,13 @@ static pa_usec_t sink_get_latency(struct userdata *u) { delay = (int64_t) pa_bytes_to_usec(u->write_count, &u->sink->sample_spec) - (int64_t) now2; - r = delay >= 0 ? (pa_usec_t) delay : 0; - if (u->memchunk.memblock) - r += pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec); + delay += pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec); - return r; + if (raw) + return delay; + else + return delay >= 0 ? (pa_usec_t) delay : 0; } static int build_pollfd(struct userdata *u) { @@ -1153,13 +1153,24 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse pa_usec_t r = 0; if (u->pcm_handle) - r = sink_get_latency(u); + r = sink_get_latency(u, false); *((pa_usec_t*) data) = r; return 0; } + case PA_SINK_MESSAGE_GET_RAW_LATENCY: { + int64_t r = 0; + + if (u->pcm_handle) + r = sink_get_latency(u, true); + + *((int64_t *) data) = r; + + return 0; + } + case PA_SINK_MESSAGE_SET_STATE: switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) { diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 4683dfe..8f3571c 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -809,7 +809,7 @@ static void update_smoother(struct userdata *u) { u->smoother_interval = PA_MIN (u->smoother_interval * 2, SMOOTHER_MAX_INTERVAL); } -static pa_usec_t source_get_latency(struct userdata *u) { +static pa_usec_t source_get_latency(struct userdata *u, bool raw) { int64_t delay; pa_usec_t now1, now2; @@ -820,7 +820,10 @@ static pa_usec_t source_get_latency(struct userdata *u) { delay = (int64_t) now2 - (int64_t) pa_bytes_to_usec(u->read_count, &u->source->sample_spec); - return delay >= 0 ? (pa_usec_t) delay : 0; + if (raw) + return delay; + else + return delay >= 0 ? (pa_usec_t) delay : 0; } static int build_pollfd(struct userdata *u) { @@ -1035,13 +1038,24 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off pa_usec_t r = 0; if (u->pcm_handle) - r = source_get_latency(u); + r = source_get_latency(u, false); *((pa_usec_t*) data) = r; return 0; } + case PA_SOURCE_MESSAGE_GET_RAW_LATENCY: { + int64_t r = 0; + + if (u->pcm_handle) + r = source_get_latency(u, true); + + *((int64_t *) data) = r; + + return 0; + } + case PA_SOURCE_MESSAGE_SET_STATE: switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) { diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c index f370ae2..c54b531 100644 --- a/src/modules/module-loopback.c +++ b/src/modules/module-loopback.c @@ -110,12 +110,12 @@ struct userdata { struct { int64_t send_counter; - pa_usec_t source_latency; + int64_t source_latency; pa_usec_t source_timestamp; int64_t recv_counter; size_t sink_input_buffer; - pa_usec_t sink_latency; + int64_t sink_latency; pa_usec_t sink_timestamp; } latency_snapshot; }; @@ -400,7 +400,7 @@ static int source_output_process_msg_cb(pa_msgobject *obj, int code, void *data, u->latency_snapshot.send_counter = u->send_counter; /* Add content of delay memblockq to the source latency */ - u->latency_snapshot.source_latency = pa_source_get_latency_within_thread(u->source_output->source) + + u->latency_snapshot.source_latency = pa_source_get_raw_latency_within_thread(u->source_output->source) + pa_bytes_to_usec(length, &u->source_output->source->sample_spec); u->latency_snapshot.source_timestamp = pa_rtclock_now(); @@ -748,7 +748,7 @@ static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, in u->latency_snapshot.recv_counter = u->recv_counter; u->latency_snapshot.sink_input_buffer = pa_memblockq_get_length(u->memblockq); /* Add content of render memblockq to sink latency */ - u->latency_snapshot.sink_latency = pa_sink_get_latency_within_thread(u->sink_input->sink) + + u->latency_snapshot.sink_latency = pa_sink_get_raw_latency_within_thread(u->sink_input->sink) + pa_bytes_to_usec(length, &u->sink_input->sink->sample_spec); u->latency_snapshot.sink_timestamp = pa_rtclock_now(); -- 2.8.1