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 b8dcbf407bb..0220b0f335b 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -28,12 +28,36 @@ #include "card.h" #include "quirks.h" #include "debug.h" -#include "urb.h" +#include "endpoint.h" #include "helper.h" #include "pcm.h" #include "clock.h" #include "power.h" +/* return the estimated delay based on USB frame counters */ +snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, + unsigned int rate) +{ + int current_frame_number; + int frame_diff; + int est_delay; + + current_frame_number = usb_get_current_frame_number(subs->dev); + /* + * HCD implementations use different widths, use lower 8 bits. + * The delay will be managed up to 256ms, which is more than + * enough + */ + frame_diff = (current_frame_number - subs->last_frame_number) & 0xff; + + /* Approximation based on number of samples per USB frame (ms), + some truncation for 44.1 but the estimate is good enough */ + est_delay = subs->last_delay - (frame_diff * rate / 1000); + if (est_delay < 0) + est_delay = 0; + return est_delay; +} + /* * return the current pcm pointer. just based on the hwptr_done value. */ @@ -45,6 +69,8 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream subs = (struct snd_usb_substream *)substream->runtime->private_data; spin_lock(&subs->lock); hwptr_done = subs->hwptr_done; + substream->runtime->delay = snd_usb_pcm_delay(subs, + substream->runtime->rate); spin_unlock(&subs->lock); return hwptr_done / (substream->runtime->frame_bits >> 3); } @@ -126,7 +152,7 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface, if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep, - data, sizeof(data), 1000)) < 0) { + data, sizeof(data))) < 0) { snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n", dev->devnum, iface, ep); return err; @@ -150,7 +176,7 @@ static int init_pitch_v2(struct snd_usb_audio *chip, int iface, if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, UAC2_EP_CS_PITCH << 8, 0, - data, sizeof(data), 1000)) < 0) { + data, sizeof(data))) < 0) { snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH (v2)\n", dev->devnum, iface, fmt->altsetting); return err; @@ -417,6 +443,8 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) subs->hwptr_done = 0; subs->transfer_done = 0; subs->phase = 0; + subs->last_delay = 0; + subs->last_frame_number = 0; runtime->delay = 0; return snd_usb_substream_prepare(subs, runtime); |