|
@@ -212,7 +212,7 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static int start_endpoints(struct snd_usb_substream *subs)
|
|
|
+static int start_endpoints(struct snd_usb_substream *subs, int can_sleep)
|
|
|
{
|
|
|
int err;
|
|
|
|
|
@@ -225,7 +225,7 @@ static int start_endpoints(struct snd_usb_substream *subs)
|
|
|
snd_printdd(KERN_DEBUG "Starting data EP @%p\n", ep);
|
|
|
|
|
|
ep->data_subs = subs;
|
|
|
- err = snd_usb_endpoint_start(ep);
|
|
|
+ err = snd_usb_endpoint_start(ep, can_sleep);
|
|
|
if (err < 0) {
|
|
|
clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags);
|
|
|
return err;
|
|
@@ -236,10 +236,25 @@ static int start_endpoints(struct snd_usb_substream *subs)
|
|
|
!test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) {
|
|
|
struct snd_usb_endpoint *ep = subs->sync_endpoint;
|
|
|
|
|
|
+ if (subs->data_endpoint->iface != subs->sync_endpoint->iface ||
|
|
|
+ subs->data_endpoint->alt_idx != subs->sync_endpoint->alt_idx) {
|
|
|
+ err = usb_set_interface(subs->dev,
|
|
|
+ subs->sync_endpoint->iface,
|
|
|
+ subs->sync_endpoint->alt_idx);
|
|
|
+ if (err < 0) {
|
|
|
+ snd_printk(KERN_ERR
|
|
|
+ "%d:%d:%d: cannot set interface (%d)\n",
|
|
|
+ subs->dev->devnum,
|
|
|
+ subs->sync_endpoint->iface,
|
|
|
+ subs->sync_endpoint->alt_idx, err);
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
snd_printdd(KERN_DEBUG "Starting sync EP @%p\n", ep);
|
|
|
|
|
|
ep->sync_slave = subs->data_endpoint;
|
|
|
- err = snd_usb_endpoint_start(ep);
|
|
|
+ err = snd_usb_endpoint_start(ep, can_sleep);
|
|
|
if (err < 0) {
|
|
|
clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags);
|
|
|
return err;
|
|
@@ -544,13 +559,10 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
|
|
|
subs->last_frame_number = 0;
|
|
|
runtime->delay = 0;
|
|
|
|
|
|
- /* clear the pending deactivation on the target EPs */
|
|
|
- deactivate_endpoints(subs);
|
|
|
-
|
|
|
/* for playback, submit the URBs now; otherwise, the first hwptr_done
|
|
|
* updates for all URBs would happen at the same time when starting */
|
|
|
if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK)
|
|
|
- return start_endpoints(subs);
|
|
|
+ return start_endpoints(subs, 1);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -1032,6 +1044,7 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
|
|
|
struct urb *urb)
|
|
|
{
|
|
|
struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
|
|
|
+ struct snd_usb_endpoint *ep = subs->data_endpoint;
|
|
|
struct snd_urb_ctx *ctx = urb->context;
|
|
|
unsigned int counts, frames, bytes;
|
|
|
int i, stride, period_elapsed = 0;
|
|
@@ -1043,7 +1056,11 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
|
|
|
urb->number_of_packets = 0;
|
|
|
spin_lock_irqsave(&subs->lock, flags);
|
|
|
for (i = 0; i < ctx->packets; i++) {
|
|
|
- counts = ctx->packet_size[i];
|
|
|
+ if (ctx->packet_size[i])
|
|
|
+ counts = ctx->packet_size[i];
|
|
|
+ else
|
|
|
+ counts = snd_usb_endpoint_next_packet_size(ep);
|
|
|
+
|
|
|
/* set up descriptor */
|
|
|
urb->iso_frame_desc[i].offset = frames * stride;
|
|
|
urb->iso_frame_desc[i].length = counts * stride;
|
|
@@ -1094,7 +1111,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)
|
|
@@ -1112,12 +1138,32 @@ 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;
|
|
|
+
|
|
|
+ /* ignore the delay accounting when procssed=0 is given, i.e.
|
|
|
+ * silent payloads are procssed before handling the actual data
|
|
|
+ */
|
|
|
+ if (!processed)
|
|
|
+ return;
|
|
|
|
|
|
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);
|
|
|
}
|
|
|
|
|
@@ -1175,7 +1221,7 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream
|
|
|
|
|
|
switch (cmd) {
|
|
|
case SNDRV_PCM_TRIGGER_START:
|
|
|
- err = start_endpoints(subs);
|
|
|
+ err = start_endpoints(subs, 0);
|
|
|
if (err < 0)
|
|
|
return err;
|
|
|
|