summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-11-23 16:00:37 +0100
committerTakashi Iwai <tiwai@suse.de>2012-11-23 16:07:11 +0100
commit48779a0b8ffc45f7f2b519ef462a72b1c5208d09 (patch)
tree4ba2b63bfe9d922a6fd6d5c6d9558f4fd2f28981
parent3f94fad09538ec988919ec3f371841182df71d04 (diff)
ALSA: usb-audio: fix delay account during pause
When a playback stream is paused, the stream isn't actually stopped, thus we still need to take care of the in-flight data amount for the delay calculation. Otherwise the value of subs->last_delay is no longer reliable and can give a bogus value after resuming from pause. This will result in "delay: estimated XX, actual YY" error messages. Also, during pause after all in flight data are processed (i.e. last_delay = 0), we don't have to calculate the actual delay from the current frame. Give a short path in such a case. Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/usb/pcm.c18
1 files changed, 17 insertions, 1 deletions
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 8e1d5e00c18..7c64b9560b1 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -46,6 +46,9 @@ snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs,
int frame_diff;
int est_delay;
+ if (!subs->last_delay)
+ return 0; /* short path */
+
current_frame_number = usb_get_current_frame_number(subs->dev);
/*
* HCD implementations use different widths, use lower 8 bits.
@@ -1195,6 +1198,9 @@ static void retire_playback_urb(struct snd_usb_substream *subs,
return;
spin_lock_irqsave(&subs->lock, flags);
+ if (!subs->last_delay)
+ goto out; /* short path */
+
est_delay = snd_usb_pcm_delay(subs, runtime->rate);
/* update delay with exact number of samples played */
if (processed > subs->last_delay)
@@ -1212,6 +1218,15 @@ static void retire_playback_urb(struct snd_usb_substream *subs,
snd_printk(KERN_DEBUG "delay: estimated %d, actual %d\n",
est_delay, subs->last_delay);
+ if (!subs->running) {
+ /* update last_frame_number for delay counting here since
+ * prepare_playback_urb won't be called during pause
+ */
+ subs->last_frame_number =
+ usb_get_current_frame_number(subs->dev) & 0xff;
+ }
+
+ out:
spin_unlock_irqrestore(&subs->lock, flags);
}
@@ -1253,7 +1268,8 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea
return 0;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
subs->data_endpoint->prepare_data_urb = NULL;
- subs->data_endpoint->retire_data_urb = NULL;
+ /* keep retire_data_urb for delay calculation */
+ subs->data_endpoint->retire_data_urb = retire_playback_urb;
subs->running = 0;
return 0;
}