diff options
Diffstat (limited to 'sound/usb/pcm.c')
-rw-r--r-- | sound/usb/pcm.c | 34 |
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 */ | ||
38 | snd_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); |