diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-11-23 10:00:37 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-11-23 10:07:11 -0500 |
commit | 48779a0b8ffc45f7f2b519ef462a72b1c5208d09 (patch) | |
tree | 4ba2b63bfe9d922a6fd6d5c6d9558f4fd2f28981 | |
parent | 3f94fad09538ec988919ec3f371841182df71d04 (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.c | 18 |
1 files changed, 17 insertions, 1 deletions
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 8e1d5e00c182..7c64b9560b18 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, | |||
46 | int frame_diff; | 46 | int frame_diff; |
47 | int est_delay; | 47 | int est_delay; |
48 | 48 | ||
49 | if (!subs->last_delay) | ||
50 | return 0; /* short path */ | ||
51 | |||
49 | current_frame_number = usb_get_current_frame_number(subs->dev); | 52 | current_frame_number = usb_get_current_frame_number(subs->dev); |
50 | /* | 53 | /* |
51 | * HCD implementations use different widths, use lower 8 bits. | 54 | * HCD implementations use different widths, use lower 8 bits. |
@@ -1195,6 +1198,9 @@ static void retire_playback_urb(struct snd_usb_substream *subs, | |||
1195 | return; | 1198 | return; |
1196 | 1199 | ||
1197 | spin_lock_irqsave(&subs->lock, flags); | 1200 | spin_lock_irqsave(&subs->lock, flags); |
1201 | if (!subs->last_delay) | ||
1202 | goto out; /* short path */ | ||
1203 | |||
1198 | est_delay = snd_usb_pcm_delay(subs, runtime->rate); | 1204 | est_delay = snd_usb_pcm_delay(subs, runtime->rate); |
1199 | /* update delay with exact number of samples played */ | 1205 | /* update delay with exact number of samples played */ |
1200 | if (processed > subs->last_delay) | 1206 | if (processed > subs->last_delay) |
@@ -1212,6 +1218,15 @@ static void retire_playback_urb(struct snd_usb_substream *subs, | |||
1212 | snd_printk(KERN_DEBUG "delay: estimated %d, actual %d\n", | 1218 | snd_printk(KERN_DEBUG "delay: estimated %d, actual %d\n", |
1213 | est_delay, subs->last_delay); | 1219 | est_delay, subs->last_delay); |
1214 | 1220 | ||
1221 | if (!subs->running) { | ||
1222 | /* update last_frame_number for delay counting here since | ||
1223 | * prepare_playback_urb won't be called during pause | ||
1224 | */ | ||
1225 | subs->last_frame_number = | ||
1226 | usb_get_current_frame_number(subs->dev) & 0xff; | ||
1227 | } | ||
1228 | |||
1229 | out: | ||
1215 | spin_unlock_irqrestore(&subs->lock, flags); | 1230 | spin_unlock_irqrestore(&subs->lock, flags); |
1216 | } | 1231 | } |
1217 | 1232 | ||
@@ -1253,7 +1268,8 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea | |||
1253 | return 0; | 1268 | return 0; |
1254 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 1269 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
1255 | subs->data_endpoint->prepare_data_urb = NULL; | 1270 | subs->data_endpoint->prepare_data_urb = NULL; |
1256 | subs->data_endpoint->retire_data_urb = NULL; | 1271 | /* keep retire_data_urb for delay calculation */ |
1272 | subs->data_endpoint->retire_data_urb = retire_playback_urb; | ||
1257 | subs->running = 0; | 1273 | subs->running = 0; |
1258 | return 0; | 1274 | return 0; |
1259 | } | 1275 | } |