[alsa-devel] [RFC] ALSA: Reduce delay for a blocking pcm_drain.

Takashi Iwai tiwai at suse.de
Mon Sep 30 10:26:07 CEST 2013


At Fri, 27 Sep 2013 20:59:45 -0700,
Dylan Reid wrote:
> 
> This patch addresses two issues related to calling snd_pcm_drain.
> 
> If no_period_wakeup is set, then snd_pcm_drain would wait
> MAX_SCHEDULE_TIMEOUT jiffies, without a wakeup pending this will leave
> the calling task blocked indefinitely.  Instead block for double the
> buffer size played back at a low sample rate (4k chosen arbitrarily).
> 
> Also if the stream is running with period wakeups but with a long
> period, the delay could be seconds.  If only a small part of the
> buffer is being used, this is unnecessary.  Instead wait for the
> remaining samples to play out, plus one millisecond.  This allows
> systems that fill the buffer only part way to still do a blocking
> drain before closing to avoid losing samples.
> 
> Change-Id: I84ee1a52d9bdf80ea6065fb9533e565d3e6c8021
> Signed-off-by: Dylan Reid <dgreid at chromium.org>
> ---
> 
> This can be worked around in user space as well by using a nonblocking drain and
> sleeping based on how many samples are queued.  Would that be the right thing to
> do or is this (or something similar) worth fixing here.
> 
> To test this I opened a pcm and set no period wakeups, played a few samples and
> then called drain, which hung indefinitely.  Using a USB headset with a
> max period size of 128k but only 15ms of the buffer filled, having the
> drain time shorter without losing samples makes a blocking call
> feasible.

The no_period_wakeup option is a kind of "all your PCM timing control
are belong to us" policy.  So it's better to keep the kernel behavior
as simple as possible in that case, IMO.


thanks,

Takashi

> ---
>  sound/core/pcm_native.c | 17 +++++++----------
>  1 file changed, 7 insertions(+), 10 deletions(-)
> 
> diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
> index f4aaf5a..a5f0695 100644
> --- a/sound/core/pcm_native.c
> +++ b/sound/core/pcm_native.c
> @@ -1481,7 +1481,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
>  	}
>  
>  	for (;;) {
> -		long tout;
> +		long tout, tout_ms;
>  		struct snd_pcm_runtime *to_check;
>  		if (signal_pending(current)) {
>  			result = -ERESTARTSYS;
> @@ -1505,16 +1505,13 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
>  		snd_pcm_stream_unlock_irq(substream);
>  		up_read(&snd_pcm_link_rwsem);
>  		snd_power_unlock(card);
> -		if (runtime->no_period_wakeup)
> -			tout = MAX_SCHEDULE_TIMEOUT;
> -		else {
> -			tout = 10;
> -			if (runtime->rate) {
> -				long t = runtime->period_size * 2 / runtime->rate;
> -				tout = max(t, tout);
> -			}
> -			tout = msecs_to_jiffies(tout * 1000);
> +		tout_ms = runtime->buffer_size * 2 * 1000 / 4000;
> +		if (runtime->rate) {
> +			snd_pcm_sframes_t hw_avail;
> +			hw_avail = snd_pcm_playback_hw_avail(runtime);
> +			tout_ms = 1 + hw_avail * 1000 / runtime->rate;
>  		}
> +		tout = msecs_to_jiffies(tout_ms);
>  		tout = schedule_timeout_interruptible(tout);
>  		snd_power_lock(card);
>  		down_read(&snd_pcm_link_rwsem);
> -- 
> 1.8.1.3.605.g02339dd
> 


More information about the Alsa-devel mailing list