Browse Source

ALSA: usb: update trigger timestamp on first non-zero URB submitted

The first URBs are submitted during the prepare stage. When .trigger is
called, the ALSA core saves a trigger tstamp that doesn't correspond to
the actual time when the samples are submitted. The trigger_tstamp is
now updated when the first data are submitted to avoid any time offsets.

A usb-specific trigger_tstamp_pending_update flag is used for now,
at some point the flag would need to move to the ALSA core, USB
is not the only interface where silent block transfers are programmed
as part of the prepare stage, with actual data enabled when .trigger
is called.

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Pierre-Louis Bossart 10 years ago
parent
commit
ea33d359c4
2 changed files with 11 additions and 0 deletions
  1. 2 0
      sound/usb/card.h
  2. 9 0
      sound/usb/pcm.c

+ 2 - 0
sound/usb/card.h

@@ -153,6 +153,8 @@ struct snd_usb_substream {
 		int channel;
 		int channel;
 		int byte_idx;
 		int byte_idx;
 	} dsd_dop;
 	} dsd_dop;
+
+	bool trigger_tstamp_pending_update; /* trigger timestamp being updated from initial estimate */
 };
 };
 
 
 struct snd_usb_stream {
 struct snd_usb_stream {

+ 9 - 0
sound/usb/pcm.c

@@ -1464,6 +1464,14 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
 	subs->last_frame_number = usb_get_current_frame_number(subs->dev);
 	subs->last_frame_number = usb_get_current_frame_number(subs->dev);
 	subs->last_frame_number &= 0xFF; /* keep 8 LSBs */
 	subs->last_frame_number &= 0xFF; /* keep 8 LSBs */
 
 
+	if (subs->trigger_tstamp_pending_update) {
+		/* this is the first actual URB submitted,
+		 * update trigger timestamp to reflect actual start time
+		 */
+		snd_pcm_gettime(runtime, &runtime->trigger_tstamp);
+		subs->trigger_tstamp_pending_update = false;
+	}
+
 	spin_unlock_irqrestore(&subs->lock, flags);
 	spin_unlock_irqrestore(&subs->lock, flags);
 	urb->transfer_buffer_length = bytes;
 	urb->transfer_buffer_length = bytes;
 	if (period_elapsed)
 	if (period_elapsed)
@@ -1550,6 +1558,7 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea
 
 
 	switch (cmd) {
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_START:
+		subs->trigger_tstamp_pending_update = true;
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		subs->data_endpoint->prepare_data_urb = prepare_playback_urb;
 		subs->data_endpoint->prepare_data_urb = prepare_playback_urb;
 		subs->data_endpoint->retire_data_urb = retire_playback_urb;
 		subs->data_endpoint->retire_data_urb = retire_playback_urb;