Skip to content

Commit

Permalink
ALSA: usb-audio: support delay calculation on capture streams
Browse files Browse the repository at this point in the history
Enable delay report on capture path. The delay is reset when an
URB is retired and increment at each call to .pointer based
on frame counter changes. The precision of the delay
information is limited to 1ms as in the playback case.

This reverts commit 3f94fad.

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Pierre-Louis Bossart authored and Takashi Iwai committed Dec 24, 2012
1 parent a49f0d1 commit e4cc615
Showing 1 changed file with 20 additions and 3 deletions.
23 changes: 20 additions & 3 deletions sound/usb/pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,12 @@ snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs,

/* 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);
est_delay = frame_diff * rate / 1000;
if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK)
est_delay = subs->last_delay - est_delay;
else
est_delay = subs->last_delay + est_delay;

if (est_delay < 0)
est_delay = 0;
return est_delay;
Expand All @@ -78,8 +83,7 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream
return SNDRV_PCM_POS_XRUN;
spin_lock(&subs->lock);
hwptr_done = subs->hwptr_done;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
substream->runtime->delay = snd_usb_pcm_delay(subs,
substream->runtime->delay = snd_usb_pcm_delay(subs,
substream->runtime->rate);
spin_unlock(&subs->lock);
return hwptr_done / (substream->runtime->frame_bits >> 3);
Expand Down Expand Up @@ -1147,6 +1151,10 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
int i, period_elapsed = 0;
unsigned long flags;
unsigned char *cp;
int current_frame_number;

/* read frame number here, update pointer in critical section */
current_frame_number = usb_get_current_frame_number(subs->dev);

stride = runtime->frame_bits >> 3;

Expand Down Expand Up @@ -1180,6 +1188,15 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
subs->transfer_done -= runtime->period_size;
period_elapsed = 1;
}
/* capture delay is by construction limited to one URB,
* reset delays here
*/
runtime->delay = subs->last_delay = 0;

/* realign last_frame_number */
subs->last_frame_number = current_frame_number;
subs->last_frame_number &= 0xFF; /* keep 8 LSBs */

spin_unlock_irqrestore(&subs->lock, flags);
/* copy a data chunk */
if (oldptr + bytes > runtime->buffer_size * stride) {
Expand Down

0 comments on commit e4cc615

Please sign in to comment.