aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-11-23 10:00:37 -0500
committerTakashi Iwai <tiwai@suse.de>2012-11-23 10:07:11 -0500
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 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 }