Re: Timer instability

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



At Wed, 25 Feb 2009 18:34:31 +0000,
Clive Messer wrote:
> 
> On Wednesday 25 Feb 2009 18:13:47 Takashi Iwai wrote:
> 
> > > > diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c
> > > > index e9ce092..5211d1c 100644
> > > > --- a/src/pcm/pcm_hw.c
> > > > +++ b/src/pcm/pcm_hw.c
> > > > @@ -131,6 +131,10 @@ struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t
> > > > *pcm) static int sync_ptr1(snd_pcm_hw_t *hw, unsigned int flags)
> > > >  {
> > > >         int err;
> > > > +       long old_hwptr, new_hwptr;
> > > > +       long old_applptr, new_applptr;
> > > > +       old_hwptr = hw->sync_ptr->s.status.hw_ptr;
> > > > +       old_applptr = hw->sync_ptr->c.control.appl_ptr;
> > > >         hw->sync_ptr->flags = flags;
> > > >         err = ioctl((hw)->fd, SNDRV_PCM_IOCTL_SYNC_PTR,
> > > > (hw)->sync_ptr); if (err < 0) {
> > > > @@ -138,6 +142,11 @@ static int sync_ptr1(snd_pcm_hw_t *hw, unsigned
> > > > int flags) SYSMSG("SNDRV_PCM_IOCTL_SYNC_PTR failed");
> > > >                 return err;
> > > >         }
> > > > +       new_hwptr = hw->sync_ptr->s.status.hw_ptr;
> > > > +       new_applptr = hw->sync_ptr->c.control.appl_ptr;
> > > > +       printf("sync_ptr1: %ld(%ld), %ld(%ld)\n",
> > > > +              new_hwptr, new_hwptr - old_hwptr,
> > > > +              new_applptr, new_applptr - old_applptr);
> > > >         return 0;
> > > >  }
> > > >  
> 
> With sync_ptr I cannot reproduce the very large numbers. Here's a typical log. 
> (Attached).

Hrm, but still an unexpected jump is found.

If you build the driver with CONFIG_SND_PCM_XRUN_DEBUG=y, you must
have /proc/asound/card0/pcm0p/xrun_debug.  Echo 1 to this (as root)
	echo 1 > /proc/asound/card0/pcm0p/xrun_debug
and try the program, see whether any debug message appears.
If any message appears, it means basically an unstable hardware.

Also, the below is a patch I tried to clean up and improve the
handling.  Give it a try (and do echo 1 above for testing).


thanks,

Takashi
---
>From 6568cc56af28ff0371509e5354dcce43ecd9b4fd Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@xxxxxxx>
Date: Tue, 3 Mar 2009 17:00:15 +0100
Subject: [PATCH] ALSA: Rewrite hw_ptr updaters

Clean up and improve snd_pcm_update_hw_ptr*() functions.

Signed-off-by: Takashi Iwai <tiwai@xxxxxxx>
---
 sound/core/pcm_lib.c |  125 +++++++++++++++++++++++++++++++++-----------------
 1 files changed, 82 insertions(+), 43 deletions(-)

diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 9216910..7d13eee 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -125,19 +125,23 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
 	}
 }
 
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+#define xrun_debug(substream)	((substream)->pstr->xrun_debug)
+#else
+#define xrun_debug(substream)	0
+#endif
+
 static void xrun(struct snd_pcm_substream *substream)
 {
 	snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-#ifdef CONFIG_SND_PCM_XRUN_DEBUG
-	if (substream->pstr->xrun_debug) {
+	if (xrun_debug(substream)) {
 		snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n",
 			   substream->pcm->card->number,
 			   substream->pcm->device,
 			   substream->stream ? 'c' : 'p');
-		if (substream->pstr->xrun_debug > 1)
+		if (xrun_debug(substream) > 1)
 			dump_stack();
 	}
-#endif
 }
 
 static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream,
@@ -182,11 +186,26 @@ static inline int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream
 	return 0;
 }
 
+static void hw_ptr_error(struct snd_pcm_substream *substream,
+			 const char *fmt, ...)
+{
+	if (xrun_debug(substream)) {
+		if (printk_ratelimit()) {
+			va_list args;
+			va_start(args, fmt);
+			vprintk(fmt, args);
+			va_end(args);
+			if (xrun_debug(substream) > 1)
+				dump_stack();
+		}
+	}
+}
+
 static inline int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_pcm_uframes_t pos;
-	snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt;
+	snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt, hw_base;
 	snd_pcm_sframes_t delta;
 
 	pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
@@ -194,36 +213,47 @@ static inline int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *subs
 		xrun(substream);
 		return -EPIPE;
 	}
-	if (runtime->period_size == runtime->buffer_size)
-		goto __next_buf;
-	new_hw_ptr = runtime->hw_ptr_base + pos;
+	hw_base = runtime->hw_ptr_base;
+	new_hw_ptr = hw_base + pos;
 	hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size;
-
-	delta = hw_ptr_interrupt - new_hw_ptr;
-	if (delta > 0) {
-		if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
-#ifdef CONFIG_SND_PCM_XRUN_DEBUG
-			if (runtime->periods > 1 && substream->pstr->xrun_debug) {
-				snd_printd(KERN_ERR "Unexpected hw_pointer value [1] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
-				if (substream->pstr->xrun_debug > 1)
-					dump_stack();
-			}
-#endif
-			return 0;
+	delta = new_hw_ptr - hw_ptr_interrupt;
+	if (hw_ptr_interrupt == runtime->boundary)
+		hw_ptr_interrupt = 0;
+	if (delta < 0) {
+		delta += runtime->buffer_size;
+		if (delta < 0) {
+			hw_ptr_error(substream, 
+				     "Unexpected hw_pointer value "
+				     "(stream=%i, pos=%ld, intr_ptr=%ld)\n",
+				     substream->stream, (long)pos,
+				     (long)hw_ptr_interrupt);
+			/* rebase to interrupt position */
+			hw_base = new_hw_ptr = hw_ptr_interrupt;
+			delta = 0;
+		} else {
+			hw_base += runtime->buffer_size;
+			if (hw_base == runtime->boundary)
+				hw_base = 0;
+			new_hw_ptr = hw_base + pos;
 		}
-	      __next_buf:
-		runtime->hw_ptr_base += runtime->buffer_size;
-		if (runtime->hw_ptr_base == runtime->boundary)
-			runtime->hw_ptr_base = 0;
-		new_hw_ptr = runtime->hw_ptr_base + pos;
 	}
-
+	if (delta > runtime->period_size) {
+		hw_ptr_error(substream,
+			     "Lost interrupts? "
+			     "(stream=%i, delta=%ld, intr_ptr=%ld)\n",
+			     substream->stream, (long)delta,
+			     (long)hw_ptr_interrupt);
+		/* rebase hw_ptr_interrupt */
+		hw_ptr_interrupt =
+			new_hw_ptr - new_hw_ptr % runtime->period_size;
+	}
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
 	    runtime->silence_size > 0)
 		snd_pcm_playback_silence(substream, new_hw_ptr);
 
+	runtime->hw_ptr_base = hw_base;
 	runtime->status->hw_ptr = new_hw_ptr;
-	runtime->hw_ptr_interrupt = new_hw_ptr - new_hw_ptr % runtime->period_size;
+	runtime->hw_ptr_interrupt = hw_ptr_interrupt;
 
 	return snd_pcm_update_hw_ptr_post(substream, runtime);
 }
@@ -233,7 +263,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_pcm_uframes_t pos;
-	snd_pcm_uframes_t old_hw_ptr, new_hw_ptr;
+	snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
 	snd_pcm_sframes_t delta;
 
 	old_hw_ptr = runtime->status->hw_ptr;
@@ -242,29 +272,38 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
 		xrun(substream);
 		return -EPIPE;
 	}
-	new_hw_ptr = runtime->hw_ptr_base + pos;
-
-	delta = old_hw_ptr - new_hw_ptr;
-	if (delta > 0) {
-		if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
-#ifdef CONFIG_SND_PCM_XRUN_DEBUG
-			if (runtime->periods > 2 && substream->pstr->xrun_debug) {
-				snd_printd(KERN_ERR "Unexpected hw_pointer value [2] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
-				if (substream->pstr->xrun_debug > 1)
-					dump_stack();
-			}
-#endif
+	hw_base = runtime->hw_ptr_base;
+	new_hw_ptr = hw_base + pos;
+
+	delta = new_hw_ptr - old_hw_ptr;
+	if (delta < 0) {
+		delta += runtime->buffer_size;
+		if (delta < 0) {
+			hw_ptr_error(substream, 
+				     "Unexpected hw_pointer value [2] "
+				     "(stream=%i, pos=%ld, old_ptr=%ld)\n",
+				     substream->stream, (long)pos,
+				     (long)old_hw_ptr);
 			return 0;
 		}
-		runtime->hw_ptr_base += runtime->buffer_size;
-		if (runtime->hw_ptr_base == runtime->boundary)
-			runtime->hw_ptr_base = 0;
-		new_hw_ptr = runtime->hw_ptr_base + pos;
+		hw_base += runtime->buffer_size;
+		if (hw_base == runtime->boundary)
+			hw_base = 0;
+		new_hw_ptr = hw_base + pos;
+	}
+	if (delta > runtime->period_size && runtime->periods > 1) {
+		hw_ptr_error(substream,
+			     "hw_ptr skipping! "
+			     "(pos=%ld, delta=%ld, period=%ld)\n",
+			     (long)pos, (long)delta,
+			     (long)runtime->period_size);
+		return 0;
 	}
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
 	    runtime->silence_size > 0)
 		snd_pcm_playback_silence(substream, new_hw_ptr);
 
+	runtime->hw_ptr_base = hw_base;
 	runtime->status->hw_ptr = new_hw_ptr;
 
 	return snd_pcm_update_hw_ptr_post(substream, runtime);
-- 
1.6.1.3

_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxx
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel


[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux