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 <pierre-louis.bossart@intel.com> Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
d2b88e4c10
commit
ab69a4904b
@ -259,6 +259,7 @@ typedef int __bitwise snd_pcm_subformat_t;
|
|||||||
#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 /* only half duplex */
|
#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 /* only half duplex */
|
||||||
#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */
|
#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */
|
||||||
#define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */
|
#define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */
|
||||||
|
#define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000 /* period wakeup can be disabled */
|
||||||
#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */
|
#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */
|
||||||
|
|
||||||
typedef int __bitwise snd_pcm_state_t;
|
typedef int __bitwise snd_pcm_state_t;
|
||||||
@ -334,6 +335,8 @@ typedef int snd_pcm_hw_param_t;
|
|||||||
#define SNDRV_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_TICK_TIME
|
#define SNDRV_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_TICK_TIME
|
||||||
|
|
||||||
#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* avoid rate resampling */
|
#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* avoid rate resampling */
|
||||||
|
#define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER (1<<1) /* export buffer */
|
||||||
|
#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) /* disable period wakeups */
|
||||||
|
|
||||||
struct snd_interval {
|
struct snd_interval {
|
||||||
unsigned int min, max;
|
unsigned int min, max;
|
||||||
|
@ -297,6 +297,7 @@ struct snd_pcm_runtime {
|
|||||||
unsigned int info;
|
unsigned int info;
|
||||||
unsigned int rate_num;
|
unsigned int rate_num;
|
||||||
unsigned int rate_den;
|
unsigned int rate_den;
|
||||||
|
unsigned int no_period_wakeup: 1;
|
||||||
|
|
||||||
/* -- SW params -- */
|
/* -- SW params -- */
|
||||||
int tstamp_mode; /* mmap timestamp is updated */
|
int tstamp_mode; /* mmap timestamp is updated */
|
||||||
|
@ -373,6 +373,11 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
|
|||||||
(unsigned long)new_hw_ptr,
|
(unsigned long)new_hw_ptr,
|
||||||
(unsigned long)runtime->hw_ptr_base);
|
(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 */
|
/* something must be really wrong */
|
||||||
if (delta >= runtime->buffer_size + runtime->period_size) {
|
if (delta >= runtime->buffer_size + runtime->period_size) {
|
||||||
hw_ptr_error(substream,
|
hw_ptr_error(substream,
|
||||||
@ -442,6 +447,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
|
|||||||
(long)old_hw_ptr);
|
(long)old_hw_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
no_delta_check:
|
||||||
if (runtime->status->hw_ptr == new_hw_ptr)
|
if (runtime->status->hw_ptr == new_hw_ptr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -423,6 +423,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||||||
runtime->info = params->info;
|
runtime->info = params->info;
|
||||||
runtime->rate_num = params->rate_num;
|
runtime->rate_num = params->rate_num;
|
||||||
runtime->rate_den = params->rate_den;
|
runtime->rate_den = params->rate_den;
|
||||||
|
runtime->no_period_wakeup =
|
||||||
|
(params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
|
||||||
|
(params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
|
||||||
|
|
||||||
bits = snd_pcm_format_physical_width(runtime->format);
|
bits = snd_pcm_format_physical_width(runtime->format);
|
||||||
runtime->sample_bits = bits;
|
runtime->sample_bits = bits;
|
||||||
|
Loading…
Reference in New Issue
Block a user