提交 d7d28bc2 编写于 作者: J Jaroslav Kysela

ALSA: pcm midlevel code - add time check for double interrupt acknowledge

The current code in pcm_lib.c do all checks using only the position
in the ring buffer. Unfortunately, where the interrupts gets delayed or
merged into one, we need another timing source to check when the
buffer size boundary overlaps to avoid the wrong updating of the
ring buffer pointers.

This code uses jiffies to check the right time window without any
performance impact.
Signed-off-by: NJaroslav Kysela <perex@perex.cz>
上级 597603d6
...@@ -274,6 +274,7 @@ struct snd_pcm_runtime { ...@@ -274,6 +274,7 @@ struct snd_pcm_runtime {
snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */
snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */ snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */
unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */
unsigned long hw_ptr_buffer_jiffies; /* buffer time in jiffies */
snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */ snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */
/* -- HW params -- */ /* -- HW params -- */
......
...@@ -329,6 +329,9 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, ...@@ -329,6 +329,9 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
/* delta = "expected next hw_ptr" for in_interrupt != 0 */ /* delta = "expected next hw_ptr" for in_interrupt != 0 */
delta = runtime->hw_ptr_interrupt + runtime->period_size; delta = runtime->hw_ptr_interrupt + runtime->period_size;
if (delta > new_hw_ptr) { if (delta > new_hw_ptr) {
/* check for double acknowledged interrupts */
hdelta = jiffies - runtime->hw_ptr_jiffies;
if (hdelta > runtime->hw_ptr_buffer_jiffies/2) {
hw_base += runtime->buffer_size; hw_base += runtime->buffer_size;
if (hw_base >= runtime->boundary) if (hw_base >= runtime->boundary)
hw_base = 0; hw_base = 0;
...@@ -336,6 +339,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, ...@@ -336,6 +339,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
goto __delta; goto __delta;
} }
} }
}
/* new_hw_ptr might be lower than old_hw_ptr in case when */ /* new_hw_ptr might be lower than old_hw_ptr in case when */
/* pointer crosses the end of the ring buffer */ /* pointer crosses the end of the ring buffer */
if (new_hw_ptr < old_hw_ptr) { if (new_hw_ptr < old_hw_ptr) {
......
...@@ -867,6 +867,8 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state) ...@@ -867,6 +867,8 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_trigger_tstamp(substream); snd_pcm_trigger_tstamp(substream);
runtime->hw_ptr_jiffies = jiffies; runtime->hw_ptr_jiffies = jiffies;
runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) /
runtime->rate;
runtime->status->state = state; runtime->status->state = state;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0) runtime->silence_size > 0)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册