summaryrefslogtreecommitdiffstats
path: root/sound/usb/pcm.c
diff options
context:
space:
mode:
authorDaniel Mack <zonque@gmail.com>2012-08-30 18:52:29 +0200
committerTakashi Iwai <tiwai@suse.de>2012-08-31 21:03:08 +0200
commitfbcfbf5f673847657ccd98afb4d8e13af7fdc372 (patch)
treea6fda9b6813f578f90e5a10df3a9f45f64d96ad7 /sound/usb/pcm.c
parent03d2f44e967b3c2cf79a6dfb904c8880616c7f83 (diff)
downloadlinux-fbcfbf5f673847657ccd98afb4d8e13af7fdc372.tar.bz2
ALSA: snd-usb: restore delay information
Parts of commit 294c4fb8 ("ALSA: usb: refine delay information with USB frame counter") were unfortunately lost during the refactoring of the snd-usb driver in 3.5. This patch adds them back, restoring the correct delay information behaviour. Signed-off-by: Daniel Mack <zonque@gmail.com> Cc: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Cc: stable@kernel.org [3.5+] Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/pcm.c')
-rw-r--r--sound/usb/pcm.c29
1 files changed, 26 insertions, 3 deletions
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 1546577ae458..5ceb8f1d63fb 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -1091,7 +1091,16 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
subs->hwptr_done += bytes;
if (subs->hwptr_done >= runtime->buffer_size * stride)
subs->hwptr_done -= runtime->buffer_size * stride;
+
+ /* update delay with exact number of samples queued */
+ runtime->delay = subs->last_delay;
runtime->delay += frames;
+ subs->last_delay = runtime->delay;
+
+ /* realign last_frame_number */
+ subs->last_frame_number = usb_get_current_frame_number(subs->dev);
+ subs->last_frame_number &= 0xFF; /* keep 8 LSBs */
+
spin_unlock_irqrestore(&subs->lock, flags);
urb->transfer_buffer_length = bytes;
if (period_elapsed)
@@ -1109,12 +1118,26 @@ static void retire_playback_urb(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
int stride = runtime->frame_bits >> 3;
int processed = urb->transfer_buffer_length / stride;
+ int est_delay;
spin_lock_irqsave(&subs->lock, flags);
- if (processed > runtime->delay)
- runtime->delay = 0;
+ est_delay = snd_usb_pcm_delay(subs, runtime->rate);
+ /* update delay with exact number of samples played */
+ if (processed > subs->last_delay)
+ subs->last_delay = 0;
else
- runtime->delay -= processed;
+ subs->last_delay -= processed;
+ runtime->delay = subs->last_delay;
+
+ /*
+ * Report when delay estimate is off by more than 2ms.
+ * The error should be lower than 2ms since the estimate relies
+ * on two reads of a counter updated every ms.
+ */
+ if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2)
+ snd_printk(KERN_DEBUG "delay: estimated %d, actual %d\n",
+ est_delay, subs->last_delay);
+
spin_unlock_irqrestore(&subs->lock, flags);
}