aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/pcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb/pcm.c')
-rw-r--r--sound/usb/pcm.c34
1 files changed, 31 insertions, 3 deletions
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index b8dcbf407bbb..0220b0f335b9 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -28,12 +28,36 @@
28#include "card.h" 28#include "card.h"
29#include "quirks.h" 29#include "quirks.h"
30#include "debug.h" 30#include "debug.h"
31#include "urb.h" 31#include "endpoint.h"
32#include "helper.h" 32#include "helper.h"
33#include "pcm.h" 33#include "pcm.h"
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}
@@ -126,7 +152,7 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface,
126 if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, 152 if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
127 USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 153 USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
128 UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep, 154 UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep,
129 data, sizeof(data), 1000)) < 0) { 155 data, sizeof(data))) < 0) {
130 snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n", 156 snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n",
131 dev->devnum, iface, ep); 157 dev->devnum, iface, ep);
132 return err; 158 return err;
@@ -150,7 +176,7 @@ static int init_pitch_v2(struct snd_usb_audio *chip, int iface,
150 if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, 176 if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
151 USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, 177 USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
152 UAC2_EP_CS_PITCH << 8, 0, 178 UAC2_EP_CS_PITCH << 8, 0,
153 data, sizeof(data), 1000)) < 0) { 179 data, sizeof(data))) < 0) {
154 snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH (v2)\n", 180 snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH (v2)\n",
155 dev->devnum, iface, fmt->altsetting); 181 dev->devnum, iface, fmt->altsetting);
156 return err; 182 return err;
@@ -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);