[pulseaudio-discuss] [PATCH] echo-cancel: Limit the maximum sink/source latency
Georg Chini
georg at chini.tk
Thu Mar 9 10:31:26 UTC 2017
On 09.03.2017 06:53, Arun Raghavan wrote:
> On systems with constrained CPUs, we might run into a situation where
> the master source/sink is configured to have too high a latency.
>
> On the source side, this would cause us to wake up with a large chunk of
> data to process, which might cause us to exhust our RT limit and thus be
> killed.
>
> So it makes sense to limit the overall latency that we request from the
> source (and correspondingly, the sink, so we don't starve for playback
> data on the source side).
>
> The 10 blocks maximum is somewhat arbitrary (I'm assuming the system has
> enough headroom to process 10 chunks through the canceller without
> getting close to the RT limit). This might make sense to make tunable in
> the future.
> ---
> src/modules/echo-cancel/module-echo-cancel.c | 32 +++++++++++++++++++++-------
> 1 file changed, 24 insertions(+), 8 deletions(-)
>
> diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c
> index ed75e0c..0a9f290 100644
> --- a/src/modules/echo-cancel/module-echo-cancel.c
> +++ b/src/modules/echo-cancel/module-echo-cancel.c
> @@ -145,6 +145,8 @@ static const pa_echo_canceller ec_table[] = {
>
> #define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
>
> +#define MAX_LATENCY_BLOCKS 10
> +
> /* Can only be used in main context */
> #define IS_ACTIVE(u) ((pa_source_get_state((u)->source) == PA_SOURCE_RUNNING) && \
> (pa_sink_get_state((u)->sink) == PA_SINK_RUNNING))
> @@ -515,6 +517,7 @@ static int sink_set_state_cb(pa_sink *s, pa_sink_state_t state) {
> /* Called from source I/O thread context */
> static void source_update_requested_latency_cb(pa_source *s) {
> struct userdata *u;
> + pa_usec_t latency;
>
> pa_source_assert_ref(s);
> pa_assert_se(u = s->userdata);
> @@ -525,15 +528,17 @@ static void source_update_requested_latency_cb(pa_source *s) {
>
> pa_log_debug("Source update requested latency");
>
> - /* Just hand this one over to the master source */
> - pa_source_output_set_requested_latency_within_thread(
> - u->source_output,
> - pa_source_get_requested_latency_within_thread(s));
> + /* Cap the maximum latency so we don't have to process too large chunks */
> + latency = PA_MIN(pa_source_get_requested_latency_within_thread(s),
> + pa_bytes_to_usec(u->source_blocksize, &s->sample_spec) * MAX_LATENCY_BLOCKS);
> +
> + pa_source_output_set_requested_latency_within_thread(u->source_output, latency);
> }
>
> /* Called from sink I/O thread context */
> static void sink_update_requested_latency_cb(pa_sink *s) {
> struct userdata *u;
> + pa_usec_t latency;
>
> pa_sink_assert_ref(s);
> pa_assert_se(u = s->userdata);
> @@ -544,10 +549,11 @@ static void sink_update_requested_latency_cb(pa_sink *s) {
>
> pa_log_debug("Sink update requested latency");
>
> - /* Just hand this one over to the master sink */
> - pa_sink_input_set_requested_latency_within_thread(
> - u->sink_input,
> - pa_sink_get_requested_latency_within_thread(s));
> + /* Cap the maximum latency so we don't have to process too large chunks */
> + latency = PA_MIN(pa_sink_get_requested_latency_within_thread(s),
> + pa_bytes_to_usec(u->sink_blocksize, &s->sample_spec) * MAX_LATENCY_BLOCKS);
> +
> + pa_sink_input_set_requested_latency_within_thread(u->sink_input, latency);
> }
>
> /* Called from sink I/O thread context */
> @@ -1658,6 +1664,7 @@ int pa__init(pa_module*m) {
> uint32_t temp;
> uint32_t nframes = 0;
> bool use_master_format;
> + pa_usec_t blocksize_usec;
>
> pa_assert(m);
>
> @@ -2020,6 +2027,15 @@ int pa__init(pa_module*m) {
>
> u->thread_info.current_volume = u->source->reference_volume;
>
> + /* We don't want to deal with too many chunks at a time */
> + blocksize_usec = pa_bytes_to_usec(u->source_blocksize, &u->source->sample_spec);
> + pa_source_set_latency_range(u->source, blocksize_usec, blocksize_usec * MAX_LATENCY_BLOCKS);
> + pa_source_output_set_requested_latency(u->source_output, blocksize_usec * MAX_LATENCY_BLOCKS);
> +
> + blocksize_usec = pa_bytes_to_usec(u->sink_blocksize, &u->sink->sample_spec);
> + pa_sink_set_latency_range(u->sink, blocksize_usec, blocksize_usec * MAX_LATENCY_BLOCKS);
> + pa_sink_input_set_requested_latency(u->sink_input, blocksize_usec * MAX_LATENCY_BLOCKS);
> +
> pa_sink_put(u->sink);
> pa_source_put(u->source);
>
You should save the initial latency ranges and restore them when the
module is unloaded.
More information about the pulseaudio-discuss
mailing list