aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/usb/card.h2
-rw-r--r--sound/usb/pcm.c28
-rw-r--r--sound/usb/pcm.h3
-rw-r--r--sound/usb/urb.c30
4 files changed, 60 insertions, 3 deletions
diff --git a/sound/usb/card.h b/sound/usb/card.h
index ae4251d5abf7..a39edcc32a93 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -94,6 +94,8 @@ struct snd_usb_substream {
94 spinlock_t lock; 94 spinlock_t lock;
95 95
96 struct snd_urb_ops ops; /* callbacks (must be filled at init) */ 96 struct snd_urb_ops ops; /* callbacks (must be filled at init) */
97 int last_frame_number; /* stored frame number */
98 int last_delay; /* stored delay */
97}; 99};
98 100
99struct snd_usb_stream { 101struct snd_usb_stream {
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index b8dcbf407bbb..0b699ca1957e 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -34,6 +34,30 @@
34#include "clock.h" 34#include "clock.h"
35#include "power.h" 35#include "power.h"
36 36
37/* return the estimated delay based on USB frame counters */
38snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs,
39 unsigned int rate)
40{
41 int current_frame_number;
42 int frame_diff;
43 int est_delay;
44
45 current_frame_number = usb_get_current_frame_number(subs->dev);
46 /*
47 * HCD implementations use different widths, use lower 8 bits.
48 * The delay will be managed up to 256ms, which is more than
49 * enough
50 */
51 frame_diff = (current_frame_number - subs->last_frame_number) & 0xff;
52
53 /* Approximation based on number of samples per USB frame (ms),
54 some truncation for 44.1 but the estimate is good enough */
55 est_delay = subs->last_delay - (frame_diff * rate / 1000);
56 if (est_delay < 0)
57 est_delay = 0;
58 return est_delay;
59}
60
37/* 61/*
38 * return the current pcm pointer. just based on the hwptr_done value. 62 * return the current pcm pointer. just based on the hwptr_done value.
39 */ 63 */
@@ -45,6 +69,8 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream
45 subs = (struct snd_usb_substream *)substream->runtime->private_data; 69 subs = (struct snd_usb_substream *)substream->runtime->private_data;
46 spin_lock(&subs->lock); 70 spin_lock(&subs->lock);
47 hwptr_done = subs->hwptr_done; 71 hwptr_done = subs->hwptr_done;
72 substream->runtime->delay = snd_usb_pcm_delay(subs,
73 substream->runtime->rate);
48 spin_unlock(&subs->lock); 74 spin_unlock(&subs->lock);
49 return hwptr_done / (substream->runtime->frame_bits >> 3); 75 return hwptr_done / (substream->runtime->frame_bits >> 3);
50} 76}
@@ -417,6 +443,8 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
417 subs->hwptr_done = 0; 443 subs->hwptr_done = 0;
418 subs->transfer_done = 0; 444 subs->transfer_done = 0;
419 subs->phase = 0; 445 subs->phase = 0;
446 subs->last_delay = 0;
447 subs->last_frame_number = 0;
420 runtime->delay = 0; 448 runtime->delay = 0;
421 449
422 return snd_usb_substream_prepare(subs, runtime); 450 return snd_usb_substream_prepare(subs, runtime);
diff --git a/sound/usb/pcm.h b/sound/usb/pcm.h
index ed3e283f618d..df7a003682ad 100644
--- a/sound/usb/pcm.h
+++ b/sound/usb/pcm.h
@@ -1,6 +1,9 @@
1#ifndef __USBAUDIO_PCM_H 1#ifndef __USBAUDIO_PCM_H
2#define __USBAUDIO_PCM_H 2#define __USBAUDIO_PCM_H
3 3
4snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs,
5 unsigned int rate);
6
4void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream); 7void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream);
5 8
6int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, 9int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
diff --git a/sound/usb/urb.c b/sound/usb/urb.c
index e184349aee83..b4dcccc237dc 100644
--- a/sound/usb/urb.c
+++ b/sound/usb/urb.c
@@ -718,7 +718,16 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
718 subs->hwptr_done += bytes; 718 subs->hwptr_done += bytes;
719 if (subs->hwptr_done >= runtime->buffer_size * stride) 719 if (subs->hwptr_done >= runtime->buffer_size * stride)
720 subs->hwptr_done -= runtime->buffer_size * stride; 720 subs->hwptr_done -= runtime->buffer_size * stride;
721
722 /* update delay with exact number of samples queued */
723 runtime->delay = subs->last_delay;
721 runtime->delay += frames; 724 runtime->delay += frames;
725 subs->last_delay = runtime->delay;
726
727 /* realign last_frame_number */
728 subs->last_frame_number = usb_get_current_frame_number(subs->dev);
729 subs->last_frame_number &= 0xFF; /* keep 8 LSBs */
730
722 spin_unlock_irqrestore(&subs->lock, flags); 731 spin_unlock_irqrestore(&subs->lock, flags);
723 urb->transfer_buffer_length = bytes; 732 urb->transfer_buffer_length = bytes;
724 if (period_elapsed) 733 if (period_elapsed)
@@ -737,12 +746,27 @@ static int retire_playback_urb(struct snd_usb_substream *subs,
737 unsigned long flags; 746 unsigned long flags;
738 int stride = runtime->frame_bits >> 3; 747 int stride = runtime->frame_bits >> 3;
739 int processed = urb->transfer_buffer_length / stride; 748 int processed = urb->transfer_buffer_length / stride;
749 int est_delay;
740 750
741 spin_lock_irqsave(&subs->lock, flags); 751 spin_lock_irqsave(&subs->lock, flags);
742 if (processed > runtime->delay) 752
743 runtime->delay = 0; 753 est_delay = snd_usb_pcm_delay(subs, runtime->rate);
754 /* update delay with exact number of samples played */
755 if (processed > subs->last_delay)
756 subs->last_delay = 0;
744 else 757 else
745 runtime->delay -= processed; 758 subs->last_delay -= processed;
759 runtime->delay = subs->last_delay;
760
761 /*
762 * Report when delay estimate is off by more than 2ms.
763 * The error should be lower than 2ms since the estimate relies
764 * on two reads of a counter updated every ms.
765 */
766 if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2)
767 snd_printk(KERN_DEBUG "delay: estimated %d, actual %d\n",
768 est_delay, subs->last_delay);
769
746 spin_unlock_irqrestore(&subs->lock, flags); 770 spin_unlock_irqrestore(&subs->lock, flags);
747 return 0; 771 return 0;
748} 772}