Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 270417
b: refs/heads/master
c: 294c4fb
h: refs/heads/master
i:
  270415: 02240de
v: v3
  • Loading branch information
Pierre-Louis Bossart authored and Takashi Iwai committed Sep 12, 2011
1 parent 8a04243 commit 53e521d
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 4 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 1ef0e0a05345b7411bdabbfca27f58bd33dcc7c8
refs/heads/master: 294c4fb8ab01728358836f478bcc1174ba7fb9d8
2 changes: 2 additions & 0 deletions trunk/sound/usb/card.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ struct snd_usb_substream {
spinlock_t lock;

struct snd_urb_ops ops; /* callbacks (must be filled at init) */
int last_frame_number; /* stored frame number */
int last_delay; /* stored delay */
};

struct snd_usb_stream {
Expand Down
28 changes: 28 additions & 0 deletions trunk/sound/usb/pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,30 @@
#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.
*/
Expand All @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions trunk/sound/usb/pcm.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#ifndef __USBAUDIO_PCM_H
#define __USBAUDIO_PCM_H

snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs,
unsigned int rate);

void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream);

int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
Expand Down
30 changes: 27 additions & 3 deletions trunk/sound/usb/urb.c
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,16 @@ static int 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)
Expand All @@ -737,12 +746,27 @@ static int retire_playback_urb(struct snd_usb_substream *subs,
unsigned long flags;
int stride = runtime->frame_bits >> 3;
int processed = urb->transfer_buffer_length / stride;
int est_delay;

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);
return 0;
}
Expand Down

0 comments on commit 53e521d

Please sign in to comment.