alsa-devel.alsa-project.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] ALSA: core: add hooks for audio timestamps
@ 2012-09-28  8:15 Pierre-Louis Bossart
  2012-09-28  8:15 ` [PATCH 2/2] ALSA: hda: support for wallclock timestamps Pierre-Louis Bossart
  2012-09-28  9:33 ` [PATCH 1/2] ALSA: core: add hooks for audio timestamps Clemens Ladisch
  0 siblings, 2 replies; 18+ messages in thread
From: Pierre-Louis Bossart @ 2012-09-28  8:15 UTC (permalink / raw)
  To: alsa-devel; +Cc: Pierre-Louis Bossart

ALSA did not provide any direct means to infer the audio time for A/V
sync and system/audio time correlations (eg. PulseAudio).
Applications had to track the number of samples read/written and
add/subtract the number of samples queued in the ring buffer.  This
accounting led to small errors, typically several samples, due to the
two-step process.  Computing the audio time in the kernel is more
direct, as all the information is available in the same routines.

Also add new .audio_wallclock routine to enable fine-grain synchronization
between monotonic system time and audio hardware time.
Using the wallclock, if supported in hardware, allows for a
much better sub-microsecond precision and a common drift tracking for
all devices sharing the same wall clock (master clock).

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 include/sound/asound.h  |    7 +++++--
 include/sound/pcm.h     |    2 ++
 sound/core/pcm_compat.c |   13 +++++++++++--
 sound/core/pcm_lib.c    |   29 +++++++++++++++++++++++++++--
 sound/core/pcm_native.c |    2 ++
 5 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/include/sound/asound.h b/include/sound/asound.h
index 0876a1e..2d1ba63 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -152,7 +152,7 @@ struct snd_hwdep_dsp_image {
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 10)
+#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 11)
 
 typedef unsigned long snd_pcm_uframes_t;
 typedef signed long snd_pcm_sframes_t;
@@ -274,6 +274,7 @@ typedef int __bitwise snd_pcm_subformat_t;
 #define SNDRV_PCM_INFO_JOINT_DUPLEX	0x00200000	/* playback and capture stream are somewhat correlated */
 #define SNDRV_PCM_INFO_SYNC_START	0x00400000	/* pcm support some kind of sync go */
 #define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP	0x00800000	/* period wakeup can be disabled */
+#define SNDRV_PCM_INFO_HAS_WALL_CLOCK   0x01000000      /* has audio wall clock for audio/system time sync */
 #define SNDRV_PCM_INFO_FIFO_IN_FRAMES	0x80000000	/* internal kernel flag - FIFO size is in frames */
 
 typedef int __bitwise snd_pcm_state_t;
@@ -422,7 +423,8 @@ struct snd_pcm_status {
 	snd_pcm_uframes_t avail_max;	/* max frames available on hw since last status */
 	snd_pcm_uframes_t overrange;	/* count of ADC (capture) overrange detections from last status */
 	snd_pcm_state_t suspended_state; /* suspended stream state */
-	unsigned char reserved[60];	/* must be filled with zero */
+	struct timespec audio_tstamp;	/* from sample counter or wall clock */
+	unsigned char reserved[60-sizeof(struct timespec)]; /* must be filled with zero */
 };
 
 struct snd_pcm_mmap_status {
@@ -431,6 +433,7 @@ struct snd_pcm_mmap_status {
 	snd_pcm_uframes_t hw_ptr;	/* RO: hw ptr (0...boundary-1) */
 	struct timespec tstamp;		/* Timestamp */
 	snd_pcm_state_t suspended_state; /* RO: suspended stream state */
+	struct timespec audio_tstamp;	/* from sample counter or wall clock */
 };
 
 struct snd_pcm_mmap_control {
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index cdca2ab..35c2bbf 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -71,6 +71,8 @@ struct snd_pcm_ops {
 	int (*prepare)(struct snd_pcm_substream *substream);
 	int (*trigger)(struct snd_pcm_substream *substream, int cmd);
 	snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream);
+	int (*wall_clock)(struct snd_pcm_substream *substream,
+			  struct timespec *audio_ts);
 	int (*copy)(struct snd_pcm_substream *substream, int channel,
 		    snd_pcm_uframes_t pos,
 		    void __user *buf, snd_pcm_uframes_t count);
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
index 91cdf94..ab4c953 100644
--- a/sound/core/pcm_compat.c
+++ b/sound/core/pcm_compat.c
@@ -190,7 +190,8 @@ struct snd_pcm_status32 {
 	u32 avail_max;
 	u32 overrange;
 	s32 suspended_state;
-	unsigned char reserved[60];
+	struct timespec audio_tstamp;
+	unsigned char reserved[60-sizeof(struct timespec)];
 } __attribute__((packed));
 
 
@@ -215,7 +216,9 @@ static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream,
 	    put_user(status.avail, &src->avail) ||
 	    put_user(status.avail_max, &src->avail_max) ||
 	    put_user(status.overrange, &src->overrange) ||
-	    put_user(status.suspended_state, &src->suspended_state))
+	    put_user(status.suspended_state, &src->suspended_state) ||
+	    put_user(status.audio_tstamp.tv_sec, &src->audio_tstamp.tv_sec) ||
+	    put_user(status.audio_tstamp.tv_nsec, &src->audio_tstamp.tv_nsec))
 		return -EFAULT;
 
 	return err;
@@ -364,6 +367,7 @@ struct snd_pcm_mmap_status32 {
 	u32 hw_ptr;
 	struct compat_timespec tstamp;
 	s32 suspended_state;
+	struct compat_timespec audio_tstamp;
 } __attribute__((packed));
 
 struct snd_pcm_mmap_control32 {
@@ -426,12 +430,17 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
 	sstatus.hw_ptr = status->hw_ptr % boundary;
 	sstatus.tstamp = status->tstamp;
 	sstatus.suspended_state = status->suspended_state;
+	sstatus.audio_tstamp = status->audio_tstamp;
 	snd_pcm_stream_unlock_irq(substream);
 	if (put_user(sstatus.state, &src->s.status.state) ||
 	    put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
 	    put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp.tv_sec) ||
 	    put_user(sstatus.tstamp.tv_nsec, &src->s.status.tstamp.tv_nsec) ||
 	    put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
+	    put_user(sstatus.audio_tstamp.tv_sec,
+		    &src->s.status.audio_tstamp.tv_sec) ||
+	    put_user(sstatus.audio_tstamp.tv_nsec,
+		    &src->s.status.audio_tstamp.tv_nsec) ||
 	    put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
 	    put_user(scontrol.avail_min, &src->c.control.avail_min))
 		return -EFAULT;
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 7ae6719..ee0c931 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -315,6 +315,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
 	unsigned long jdelta;
 	unsigned long curr_jiffies;
 	struct timespec curr_tstamp;
+	struct timespec audio_tstamp;
 
 	old_hw_ptr = runtime->status->hw_ptr;
 
@@ -326,9 +327,14 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
 	 */
 	pos = substream->ops->pointer(substream);
 	curr_jiffies = jiffies;
-	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
 		snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
 
+		if ((runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK) &&
+			(substream->ops->wall_clock))
+			substream->ops->wall_clock(substream, &audio_tstamp);
+	}
+
 	if (pos == SNDRV_PCM_POS_XRUN) {
 		xrun(substream);
 		return -EPIPE;
@@ -506,8 +512,27 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
 	runtime->hw_ptr_base = hw_base;
 	runtime->status->hw_ptr = new_hw_ptr;
 	runtime->hw_ptr_jiffies = curr_jiffies;
-	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
 		runtime->status->tstamp = curr_tstamp;
+		if (!(runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK)) {
+			/*
+			 * no wall clock available, provide audio timestamp
+			 * derived from pointer position+delay
+			 */
+			u64 audio_frames, audio_nsecs;
+
+			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+				audio_frames = runtime->status->hw_ptr
+					- runtime->delay;
+			else
+				audio_frames = runtime->status->hw_ptr
+					+ runtime->delay;
+			audio_nsecs = audio_frames * 1000000000LL /
+				runtime->rate;
+			audio_tstamp = ns_to_timespec(audio_nsecs);
+		}
+		runtime->status->audio_tstamp = audio_tstamp;
+	}
 
 	return snd_pcm_update_state(substream, runtime);
 }
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 53b5ada..c5206f4 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -594,6 +594,8 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
 		snd_pcm_update_hw_ptr(substream);
 		if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
 			status->tstamp = runtime->status->tstamp;
+			status->audio_tstamp =
+				runtime->status->audio_tstamp;
 			goto _tstamp_end;
 		}
 	}
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 18+ messages in thread
* [PATCH 0/2] RFC: support for audio wall clock
@ 2012-06-28 21:12 Pierre-Louis Bossart
  2012-06-28 21:12 ` [PATCH 2/2] ALSA: hda: support for wallclock timestamps Pierre-Louis Bossart
  0 siblings, 1 reply; 18+ messages in thread
From: Pierre-Louis Bossart @ 2012-06-28 21:12 UTC (permalink / raw)
  To: alsa-devel; +Cc: Pierre-Louis Bossart

V2 of patches to show how the audio wall clock (eg. the
HDAudio one) can be used to provide precise audio timestamps and track
the drift between audio time and system time. On my laptop I am able
to track a 7ppm delta.  
I will explain in more details how this can be
used during LPC in San Diego, but with the summer coming I'd like to
get feedback as there are changes to the core/alsa-lib that haven't
been modified in years.

TODO:
- 64-bit alignment, verification of pcm_compat.c changes
- handling of digital inputs, need to disable wall-clock timestamps in that case (feedback from Clemens)
- check differences in protocol
- change timecounter to avoid accumulation of rounding errors in cycle->ns conversions
- check overflows
- rework the timecounter init on trigger

Pierre-Louis Bossart (2):
  ALSA: core: add hooks for audio timestamps read from WALLCLOCK
  ALSA: hda: support for wallclock timestamps

 include/sound/asound.h    |    7 ++++-
 include/sound/pcm.h       |    2 +
 sound/core/pcm_compat.c   |   13 +++++++++-
 sound/core/pcm_lib.c      |   15 ++++++++++-
 sound/core/pcm_native.c   |    2 +
 sound/pci/hda/hda_intel.c |   54 ++++++++++++++++++++++++++++++++++++++++++++-
 6 files changed, 86 insertions(+), 7 deletions(-)

-- 
1.7.6.5

^ permalink raw reply	[flat|nested] 18+ messages in thread
* [PATCH 0/2] RFC: support for audio wall clock
@ 2012-06-13 20:26 Pierre-Louis Bossart
  2012-06-13 20:26 ` [PATCH 2/2] ALSA: hda: support for wallclock timestamps Pierre-Louis Bossart
  0 siblings, 1 reply; 18+ messages in thread
From: Pierre-Louis Bossart @ 2012-06-13 20:26 UTC (permalink / raw)
  To: alsa-devel; +Cc: Pierre-Louis Bossart

Attached a set of patches to show how the audio wall clock (eg. the
HDAudio one) can be used to provide precise audio timestamps and track
the drift between audio time and system time. On my laptop I am able
to track a 7ppm delta.  I will explain in more details how this can be
used during LPC in San Diego, but with the summer coming I'd like to
get feedback as there are changes to the core/alsa-lib that haven't
been modified in years.

Pierre-Louis Bossart (2):
  ALSA: core: add hooks for audio timestamps read from WALLCLOCK
  ALSA: hda: support for wallclock timestamps

 include/sound/asound.h    |    7 +++-
 include/sound/pcm.h       |    2 +
 sound/core/pcm_lib.c      |   15 ++++++-
 sound/core/pcm_native.c   |    2 +
 sound/pci/hda/hda_intel.c |  106 ++++++++++++++++++++++++++++++++++++++++++++-
 5 files changed, 128 insertions(+), 4 deletions(-)

-- 
1.7.6.5

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2012-09-30 10:13 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-09-28  8:15 [PATCH 1/2] ALSA: core: add hooks for audio timestamps Pierre-Louis Bossart
2012-09-28  8:15 ` [PATCH 2/2] ALSA: hda: support for wallclock timestamps Pierre-Louis Bossart
2012-09-28  9:33   ` Clemens Ladisch
2012-09-29 20:12     ` Pierre-Louis Bossart
2012-09-30 10:12       ` Clemens Ladisch
2012-09-29  1:47   ` Raymond Yau
2012-09-28  9:33 ` [PATCH 1/2] ALSA: core: add hooks for audio timestamps Clemens Ladisch
2012-09-29 20:17   ` Pierre-Louis Bossart
2012-09-30 10:11     ` Clemens Ladisch
  -- strict thread matches above, loose matches on Subject: below --
2012-06-28 21:12 [PATCH 0/2] RFC: support for audio wall clock Pierre-Louis Bossart
2012-06-28 21:12 ` [PATCH 2/2] ALSA: hda: support for wallclock timestamps Pierre-Louis Bossart
2012-06-13 20:26 [PATCH 0/2] RFC: support for audio wall clock Pierre-Louis Bossart
2012-06-13 20:26 ` [PATCH 2/2] ALSA: hda: support for wallclock timestamps Pierre-Louis Bossart
2012-06-14  3:32   ` Wang Xingchao
2012-06-14  4:57     ` Pierre-Louis Bossart
2012-06-14  8:15       ` Clemens Ladisch
2012-06-14 17:01         ` Pierre-Louis Bossart
2012-06-14  7:38   ` Takashi Iwai
2012-06-15 10:02     ` Pierre-Louis Bossart
2012-06-15 10:34       ` Takashi Iwai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).