From ab69a4904b5dd4d7cd6996587ba066bca8d13838 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 15 Nov 2010 10:46:23 +0100 Subject: ALSA: pcm: support for period wakeup disabling This patch allows to disable period interrupts which are not needed when the application relies on a system timer to wake-up and refill the ring buffer. The behavior of the driver is left unchanged, and interrupts are only disabled if the application requests this configuration. The behavior in case of underruns is slightly different, instead of being detected during the period interrupts the underruns are detected when the application calls snd_pcm_update_avail, which in turns forces a refresh of the hw pointer and shows the buffer is empty. More specifically this patch makes a lot of sense when PulseAudio relies on timer-based scheduling to access audio devices such as HDAudio or Intel SST. Disabling interrupts removes two unwanted wake-ups due to period elapsed events in low-power playback modes. It also simplifies PulseAudio voice modules used for speech calls. To quote Lennart "This patch looks very interesting and desirable. This is something have long been waiting for." Support for this in hardware drivers is optional. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound/core/pcm_lib.c') diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index b75db8e..bc57501 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -373,6 +373,11 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, (unsigned long)new_hw_ptr, (unsigned long)runtime->hw_ptr_base); } + + /* without period interrupts, there are no regular pointer updates */ + if (runtime->no_period_wakeup) + goto no_delta_check; + /* something must be really wrong */ if (delta >= runtime->buffer_size + runtime->period_size) { hw_ptr_error(substream, @@ -442,6 +447,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, (long)old_hw_ptr); } + no_delta_check: if (runtime->status->hw_ptr == new_hw_ptr) return 0; -- cgit v1.1 From 59ff878ffb26bc0be812ca8295799164f413ae88 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 18 Nov 2010 09:43:52 +0100 Subject: ALSA: pcm: detect xruns in no-period-wakeup mode When period wakeups are disabled, successive calls to the pointer update function do not have a maximum allowed distance, so xruns cannot be detected with the pointer value only. To detect xruns, compare the actually elapsed time with the time that should have theoretically elapsed since the last update. When the hardware pointer has wrapped around due to an xrun, the actually elapsed time will be too big by about hw_ptr_buffer_jiffies. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'sound/core/pcm_lib.c') diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index bc57501..e9debaa 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -374,9 +374,23 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, (unsigned long)runtime->hw_ptr_base); } - /* without period interrupts, there are no regular pointer updates */ - if (runtime->no_period_wakeup) + if (runtime->no_period_wakeup) { + /* + * Without regular period interrupts, we have to check + * the elapsed time to detect xruns. + */ + jdelta = jiffies - runtime->hw_ptr_jiffies; + hdelta = jdelta - delta * HZ / runtime->rate; + while (hdelta > runtime->hw_ptr_buffer_jiffies / 2 + 1) { + delta += runtime->buffer_size; + hw_base += runtime->buffer_size; + if (hw_base >= runtime->boundary) + hw_base = 0; + new_hw_ptr = hw_base + pos; + hdelta -= runtime->hw_ptr_buffer_jiffies; + } goto no_delta_check; + } /* something must be really wrong */ if (delta >= runtime->buffer_size + runtime->period_size) { -- cgit v1.1 From 47228e48aecdbec423a1275a5e27697d47f1f912 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 18 Nov 2010 09:53:07 +0100 Subject: ALSA: pcm: optimize xrun detection in no-period-wakeup mode Add a lightweight condition on top of the xrun checking so that we can avoid the division when the application is calling the update function often enough. Suggested-by: Jaroslav Kysela Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/core/pcm_lib.c') diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index e9debaa..fd18c3c 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -380,6 +380,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, * the elapsed time to detect xruns. */ jdelta = jiffies - runtime->hw_ptr_jiffies; + if (jdelta < runtime->hw_ptr_buffer_jiffies / 2) + goto no_delta_check; hdelta = jdelta - delta * HZ / runtime->rate; while (hdelta > runtime->hw_ptr_buffer_jiffies / 2 + 1) { delta += runtime->buffer_size; -- cgit v1.1