[alsa-devel] 2.6.30: xruns caused by "ALSA: pcm - Safer boundary checks"
Takashi Iwai
tiwai at suse.de
Fri May 22 23:52:45 CEST 2009
At Fri, 22 May 2009 16:27:09 -0400,
Chuck Ebbert wrote:
>
> Bug report: https://bugzilla.redhat.com/show_bug.cgi?id=498858
>
> To reproduce, pause a video in mplayer and then hit play:
>
> ALSA sound/core/pcm_lib.c:263: hda_codec: hw_ptr skipping! [Q] (pos=11263,
> delta=17400, period=1024, jdelta=21/362/0)
Does the patch fix the problem?
thanks,
Takashi
---
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index c172968..7366910 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -266,6 +266,7 @@ struct snd_pcm_runtime {
struct snd_pcm_substream *trigger_master;
struct timespec trigger_tstamp; /* trigger timestamp */
int overrange;
+ unsigned int jiffies_set:1; /* hw_ptr_jiffies is set */
snd_pcm_uframes_t avail_max;
snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */
snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index a2a792c..78edd6e 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -249,6 +249,8 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
new_hw_ptr = hw_base + pos;
}
}
+ if (!runtime->jiffies_set)
+ goto no_jiffies_check;
/* Skip the jiffies check for hardwares with BATCH flag.
* Such hardware usually just increases the position at each IRQ,
* thus it can't give any strange position.
@@ -296,6 +298,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
runtime->hw_ptr_base = hw_base;
runtime->status->hw_ptr = new_hw_ptr;
runtime->hw_ptr_jiffies = jiffies;
+ runtime->jiffies_set = 1;
runtime->hw_ptr_interrupt = hw_ptr_interrupt;
return snd_pcm_update_hw_ptr_post(substream, runtime);
@@ -336,7 +339,8 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
hw_base = 0;
new_hw_ptr = hw_base + pos;
}
- if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
+ if (runtime->jiffies_set &&
+ ((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
hw_ptr_error(substream,
"hw_ptr skipping! "
"(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n",
@@ -352,6 +356,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
runtime->hw_ptr_base = hw_base;
runtime->status->hw_ptr = new_hw_ptr;
runtime->hw_ptr_jiffies = jiffies;
+ runtime->jiffies_set = 1;
return snd_pcm_update_hw_ptr_post(substream, runtime);
}
@@ -1478,7 +1483,6 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
runtime->status->hw_ptr %= runtime->buffer_size;
else
runtime->status->hw_ptr = 0;
- runtime->hw_ptr_jiffies = jiffies;
snd_pcm_stream_unlock_irqrestore(substream, flags);
return 0;
}
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index fc6f98e..5cf67a5 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -978,6 +978,7 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_trigger_tstamp(substream);
+ runtime->jiffies_set = 0;
if (push) {
runtime->status->state = SNDRV_PCM_STATE_PAUSED;
if (substream->timer)
@@ -1041,6 +1042,7 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state)
&runtime->trigger_tstamp);
runtime->status->suspended_state = runtime->status->state;
runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
+ runtime->jiffies_set = 0;
wake_up(&runtime->sleep);
}
@@ -1234,6 +1236,7 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state)
runtime->status->hw_ptr % runtime->period_size;
runtime->silence_start = runtime->status->hw_ptr;
runtime->silence_filled = 0;
+ runtime->jiffies_set = 0;
return 0;
}
More information about the Alsa-devel
mailing list