All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/5] sync asound.h with kernel version
@ 2015-01-30 23:57 Pierre-Louis Bossart
  2015-01-30 23:57 ` [PATCH 2/5] add support for get/set_audio_htstamp_config Pierre-Louis Bossart
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Pierre-Louis Bossart @ 2015-01-30 23:57 UTC (permalink / raw)
  To: alsa-devel; +Cc: Pierre-Louis Bossart

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 include/sound/asound.h | 37 ++++++++++++++++++++++++++++++++-----
 1 file changed, 32 insertions(+), 5 deletions(-)

diff --git a/include/sound/asound.h b/include/sound/asound.h
index 1f23cd6..3d46e9a 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -140,7 +140,7 @@ struct snd_hwdep_dsp_image {
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 12)
+#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 13)
 
 typedef unsigned long snd_pcm_uframes_t;
 typedef signed long snd_pcm_sframes_t;
@@ -267,9 +267,17 @@ 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_HAS_WALL_CLOCK   0x01000000      /* (Deprecated)has audio wall clock for audio/system time sync */
+#define SNDRV_PCM_INFO_HAS_LINK_ATIME              0x01000000  /* report hardware link audio time, reset on startup */
+#define SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME     0x02000000  /* report absolute hardware link audio time, not reset on startup */
+#define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME    0x04000000  /* report estimated link audio time */
+#define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000  /* report synchronized audio/system time */
+
+#define SNDRV_PCM_INFO_DRAIN_TRIGGER	0x40000000		/* internal kernel flag - trigger in drain */
 #define SNDRV_PCM_INFO_FIFO_IN_FRAMES	0x80000000	/* internal kernel flag - FIFO size is in frames */
 
+
+
 typedef int __bitwise snd_pcm_state_t;
 #define	SNDRV_PCM_STATE_OPEN		((__force snd_pcm_state_t) 0) /* stream is open */
 #define	SNDRV_PCM_STATE_SETUP		((__force snd_pcm_state_t) 1) /* stream has a setup */
@@ -407,6 +415,22 @@ struct snd_pcm_channel_info {
 	unsigned int step;		/* samples distance in bits */
 };
 
+enum {
+	/*
+	 *  first definition for backwards compatibility only,
+	 *  maps to wallclock/link time for HDAudio playback and DEFAULT/DMA time for everything else
+	 */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT = 0,
+
+	/* timestamp definitions */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT = 1,           /* DMA time, reported as per hw_ptr */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK = 2,	           /* link time reported by sample or wallclock counter, reset on startup */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE = 3,	   /* link time reported by sample or wallclock counter, not reset on startup */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED = 4,    /* link time estimated indirectly */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED = 5, /* link time synchronized with system time */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_LAST = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED
+};
+
 struct snd_pcm_status {
 	snd_pcm_state_t state;		/* stream state */
 	struct timespec trigger_tstamp;	/* time when stream was started/stopped/paused */
@@ -418,9 +442,11 @@ 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 */
-	__u32 reserved_alignment;	/* must be filled with zero */
-	struct timespec audio_tstamp;	/* from sample counter or wall clock */
-	unsigned char reserved[56-sizeof(struct timespec)]; /* must be filled with zero */
+	__u32 audio_tstamp_data;	 /* needed for 64-bit alignment, used for configs/report to/from userspace */
+	struct timespec audio_tstamp;	/* sample counter, wall clock, PHC or on-demand sync'ed */
+	struct timespec driver_tstamp;	/* useful in case reference system tstamp is reported with delay */
+	__u32 audio_tstamp_accuracy;	/* in ns units, only valid if indicated in audio_tstamp_data */
+	unsigned char reserved[52-2*sizeof(struct timespec)]; /* must be filled with zero */
 };
 
 struct snd_pcm_mmap_status {
@@ -533,6 +559,7 @@ enum {
 #define SNDRV_PCM_IOCTL_DELAY		_IOR('A', 0x21, snd_pcm_sframes_t)
 #define SNDRV_PCM_IOCTL_HWSYNC		_IO('A', 0x22)
 #define SNDRV_PCM_IOCTL_SYNC_PTR	_IOWR('A', 0x23, struct snd_pcm_sync_ptr)
+#define SNDRV_PCM_IOCTL_STATUS_EXT	_IOWR('A', 0x24, struct snd_pcm_status)
 #define SNDRV_PCM_IOCTL_CHANNEL_INFO	_IOR('A', 0x32, struct snd_pcm_channel_info)
 #define SNDRV_PCM_IOCTL_PREPARE		_IO('A', 0x40)
 #define SNDRV_PCM_IOCTL_RESET		_IO('A', 0x41)
-- 
1.9.1

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

* [PATCH 2/5] add support for get/set_audio_htstamp_config
  2015-01-30 23:57 [PATCH 1/5] sync asound.h with kernel version Pierre-Louis Bossart
@ 2015-01-30 23:57 ` Pierre-Louis Bossart
  2015-01-30 23:57 ` [PATCH 3/5] pcm: add helper functions to query timestamping capabilities Pierre-Louis Bossart
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Pierre-Louis Bossart @ 2015-01-30 23:57 UTC (permalink / raw)
  To: alsa-devel; +Cc: Pierre-Louis Bossart

Enable kernel-side functionality by letting user select what sort of
timestamp it desires

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 include/pcm.h | 44 ++++++++++++++++++++++++++++++++++++++++++++
 src/pcm/pcm.c | 38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 82 insertions(+)

diff --git a/include/pcm.h b/include/pcm.h
index 0655e7f..b5bbd2d 100644
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -330,6 +330,26 @@ typedef enum _snd_pcm_tstamp_type {
 	SND_PCM_TSTAMP_TYPE_LAST = SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW,
 } snd_pcm_tstamp_type_t;
 
+typedef struct _snd_pcm_audio_tstamp_config {
+	/* 5 of max 16 bits used */
+	unsigned int type_requested:4;
+	unsigned int report_delay:1; /* add total delay to A/D or D/A */
+} snd_pcm_audio_tstamp_config_t;
+
+typedef struct _snd_pcm_audio_tstamp_report {
+	/* 6 of max 16 bits used for bit-fields */
+
+	/* for backwards compatibility */
+	unsigned int valid:1;
+
+	/* actual type if hardware could not support requested timestamp */
+	unsigned int actual_type:4;
+
+	/* accuracy represented in ns units */
+	unsigned int accuracy_report:1; /* 0 if accuracy unknown, 1 if accuracy field is valid */
+	unsigned int accuracy; /* up to 4.29s, will be packed in separate field  */
+} snd_pcm_audio_tstamp_report_t;
+
 /** Unsigned frames quantity */
 typedef unsigned long snd_pcm_uframes_t;
 /** Signed frames quantity */
@@ -980,6 +1000,30 @@ void snd_pcm_status_get_trigger_htstamp(const snd_pcm_status_t *obj, snd_htimest
 void snd_pcm_status_get_tstamp(const snd_pcm_status_t *obj, snd_timestamp_t *ptr);
 void snd_pcm_status_get_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr);
 void snd_pcm_status_get_audio_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr);
+void snd_pcm_status_get_driver_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr);
+void snd_pcm_status_get_audio_htstamp_report(const snd_pcm_status_t *obj,
+					     snd_pcm_audio_tstamp_report_t *audio_tstamp_report);
+void snd_pcm_status_set_audio_htstamp_config(snd_pcm_status_t *obj,
+					     snd_pcm_audio_tstamp_config_t *audio_tstamp_config);
+
+static inline void snd_pcm_pack_audio_tstamp_config(unsigned int *data,
+						snd_pcm_audio_tstamp_config_t *config)
+{
+	*data = config->report_delay;
+	*data <<= 4;
+	*data |= config->type_requested;
+}
+
+static inline void snd_pcm_unpack_audio_tstamp_report(unsigned int data, unsigned int accuracy,
+						snd_pcm_audio_tstamp_report_t *report)
+{
+	data >>= 16;
+	report->valid = data & 1;
+	report->actual_type = (data >> 1) & 0xF;
+	report->accuracy_report = (data >> 5) & 1;
+	report->accuracy = accuracy;
+}
+
 snd_pcm_sframes_t snd_pcm_status_get_delay(const snd_pcm_status_t *obj);
 snd_pcm_uframes_t snd_pcm_status_get_avail(const snd_pcm_status_t *obj);
 snd_pcm_uframes_t snd_pcm_status_get_avail_max(const snd_pcm_status_t *obj);
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index e74e02f..441b3db 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -6334,6 +6334,44 @@ void snd_pcm_status_get_audio_htstamp(const snd_pcm_status_t *obj, snd_htimestam
 }
 
 /**
+ * \brief Get "now" hi-res driver timestamp from a PCM status container. Defines when the status
+ * was generated by driver, may differ from normal timestamp.
+ * \param obj pointer to #snd_pcm_status_t
+ * \param ptr Pointer to returned timestamp
+ */
+void snd_pcm_status_get_driver_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr)
+{
+	assert(obj && ptr);
+	*ptr = obj->driver_tstamp;
+}
+
+/**
+ * \brief Get audio_tstamp_report from a PCM status container
+ * \param obj pointer to #snd_pcm_status_t
+ * \param ptr Pointer to returned report (valid fields are accuracy and type)
+ */
+void snd_pcm_status_get_audio_htstamp_report(const snd_pcm_status_t *obj,
+					     snd_pcm_audio_tstamp_report_t *audio_tstamp_report)
+{
+	assert(obj && audio_tstamp_report);
+	snd_pcm_unpack_audio_tstamp_report(obj->audio_tstamp_data,
+					obj->audio_tstamp_accuracy,
+					audio_tstamp_report);
+}
+
+/**
+ * \brief set audio_tstamp_config from a PCM status container
+ * \param obj pointer to #snd_pcm_status_t
+ * \param ptr Pointer to config (valid fields are type and report_analog_delay)
+ */
+void snd_pcm_status_set_audio_htstamp_config(snd_pcm_status_t *obj,
+					     snd_pcm_audio_tstamp_config_t *audio_tstamp_config)
+{
+	assert(obj && audio_tstamp_config);
+	snd_pcm_pack_audio_tstamp_config(&obj->audio_tstamp_data, audio_tstamp_config);
+}
+
+/**
  * \brief Get delay from a PCM status container (see #snd_pcm_delay)
  * \return Delay in frames
  *
-- 
1.9.1

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

* [PATCH 3/5] pcm: add helper functions to query timestamping capabilities
  2015-01-30 23:57 [PATCH 1/5] sync asound.h with kernel version Pierre-Louis Bossart
  2015-01-30 23:57 ` [PATCH 2/5] add support for get/set_audio_htstamp_config Pierre-Louis Bossart
@ 2015-01-30 23:57 ` Pierre-Louis Bossart
  2015-01-30 23:57 ` [PATCH 4/5] pcm: add support for new STATUS_EXT ioctl Pierre-Louis Bossart
  2015-01-30 23:57 ` [PATCH 5/5] test: fix audio_time with new get/set audio_tstamp_config Pierre-Louis Bossart
  3 siblings, 0 replies; 5+ messages in thread
From: Pierre-Louis Bossart @ 2015-01-30 23:57 UTC (permalink / raw)
  To: alsa-devel; +Cc: Pierre-Louis Bossart

extend support to link, link_estimated and link_synchronized
timestamp. wall-clock is deprecated

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 include/pcm.h |  3 ++-
 src/pcm/pcm.c | 35 ++++++++++++++++++++++++++++++++++-
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/include/pcm.h b/include/pcm.h
index b5bbd2d..a1d14a9 100644
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -688,7 +688,8 @@ int snd_pcm_hw_params_is_half_duplex(const snd_pcm_hw_params_t *params);
 int snd_pcm_hw_params_is_joint_duplex(const snd_pcm_hw_params_t *params);
 int snd_pcm_hw_params_can_sync_start(const snd_pcm_hw_params_t *params);
 int snd_pcm_hw_params_can_disable_period_wakeup(const snd_pcm_hw_params_t *params);
-int snd_pcm_hw_params_supports_audio_wallclock_ts(const snd_pcm_hw_params_t *params);
+int snd_pcm_hw_params_supports_audio_wallclock_ts(const snd_pcm_hw_params_t *params); /* deprecated, use audio_ts_type */
+int snd_pcm_hw_params_supports_audio_ts_type(const snd_pcm_hw_params_t *params, int type);
 int snd_pcm_hw_params_get_rate_numden(const snd_pcm_hw_params_t *params,
 				      unsigned int *rate_num,
 				      unsigned int *rate_den);
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index 441b3db..294da52 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -3190,12 +3190,45 @@ int snd_pcm_hw_params_can_disable_period_wakeup(const snd_pcm_hw_params_t *param
  */
 int snd_pcm_hw_params_supports_audio_wallclock_ts(const snd_pcm_hw_params_t *params)
 {
+	/* deprecated */
+	return snd_pcm_hw_params_supports_audio_ts_type(params,
+							SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT);
+}
+
+/**
+ * \brief Check if hardware supports type of audio timestamps
+ * \param params Configuration space
+ * \param type   Audio timestamp type
+ * \retval 0 Hardware doesn't support type of audio timestamps
+ * \retval 1 Hardware supports type of audio timestamps
+ *
+ * This function should only be called when the configuration space
+ * contains a single configuration. Call #snd_pcm_hw_params to choose
+ * a single configuration from the configuration space.
+ */
+int snd_pcm_hw_params_supports_audio_ts_type(const snd_pcm_hw_params_t *params, int type)
+{
 	assert(params);
 	if (CHECK_SANITY(params->info == ~0U)) {
 		SNDMSG("invalid PCM info field");
 		return 0; /* FIXME: should be a negative error? */
 	}
-	return !!(params->info & SNDRV_PCM_INFO_HAS_WALL_CLOCK);
+	switch (type) {
+	case SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT:
+		return !!(params->info & SNDRV_PCM_INFO_HAS_WALL_CLOCK); /* deprecated */
+	case SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT:
+		return 1; /* always supported, based on hw_ptr */
+	case SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK:
+		return !!(params->info & SNDRV_PCM_INFO_HAS_LINK_ATIME);
+	case SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE:
+		return !!(params->info & SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME);
+	case SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED:
+		return !!(params->info & SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME);
+	case SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED:
+		return !!(params->info & SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME);
+	default:
+		return 0;
+	}
 }
 
 /**
-- 
1.9.1

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

* [PATCH 4/5] pcm: add support for new STATUS_EXT ioctl
  2015-01-30 23:57 [PATCH 1/5] sync asound.h with kernel version Pierre-Louis Bossart
  2015-01-30 23:57 ` [PATCH 2/5] add support for get/set_audio_htstamp_config Pierre-Louis Bossart
  2015-01-30 23:57 ` [PATCH 3/5] pcm: add helper functions to query timestamping capabilities Pierre-Louis Bossart
@ 2015-01-30 23:57 ` Pierre-Louis Bossart
  2015-01-30 23:57 ` [PATCH 5/5] test: fix audio_time with new get/set audio_tstamp_config Pierre-Louis Bossart
  3 siblings, 0 replies; 5+ messages in thread
From: Pierre-Louis Bossart @ 2015-01-30 23:57 UTC (permalink / raw)
  To: alsa-devel; +Cc: Pierre-Louis Bossart

use STATUS_EXT ioctl if PCM protocol is > 2.0.12
All audio timestamp configuration will be ignored with an
older protocol.

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 src/pcm/pcm_hw.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c
index c34b766..232b197 100644
--- a/src/pcm/pcm_hw.c
+++ b/src/pcm/pcm_hw.c
@@ -510,10 +510,18 @@ static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
 {
 	snd_pcm_hw_t *hw = pcm->private_data;
 	int fd = hw->fd, err;
-	if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS, status) < 0) {
-		err = -errno;
-		SYSMSG("SNDRV_PCM_IOCTL_STATUS failed (%i)", err);
-		return err;
+	if (SNDRV_PROTOCOL_VERSION(2, 0, 13) > hw->version) {
+		if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS, status) < 0) {
+			err = -errno;
+			SYSMSG("SNDRV_PCM_IOCTL_STATUS failed (%i)", err);
+			return err;
+		}
+	} else {
+		if (ioctl(fd, SNDRV_PCM_IOCTL_STATUS_EXT, status) < 0) {
+			err = -errno;
+			SYSMSG("SNDRV_PCM_IOCTL_STATUS_EXT failed (%i)", err);
+			return err;
+		}
 	}
 	if (SNDRV_PROTOCOL_VERSION(2, 0, 5) > hw->version) {
 		status->tstamp.tv_nsec *= 1000L;
-- 
1.9.1

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

* [PATCH 5/5] test: fix audio_time with new get/set audio_tstamp_config
  2015-01-30 23:57 [PATCH 1/5] sync asound.h with kernel version Pierre-Louis Bossart
                   ` (2 preceding siblings ...)
  2015-01-30 23:57 ` [PATCH 4/5] pcm: add support for new STATUS_EXT ioctl Pierre-Louis Bossart
@ 2015-01-30 23:57 ` Pierre-Louis Bossart
  3 siblings, 0 replies; 5+ messages in thread
From: Pierre-Louis Bossart @ 2015-01-30 23:57 UTC (permalink / raw)
  To: alsa-devel; +Cc: Pierre-Louis Bossart

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 test/audio_time.c | 491 ++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 313 insertions(+), 178 deletions(-)

diff --git a/test/audio_time.c b/test/audio_time.c
index 7435db6..e369e59 100644
--- a/test/audio_time.c
+++ b/test/audio_time.c
@@ -4,13 +4,39 @@
  * helpful to verify the information reported by drivers.
  */
 
-#include "../include/asoundlib.h"
+#include <stdio.h>
+#include <malloc.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <time.h>
+#include <locale.h>
 #include <math.h>
+#include "../include/asoundlib.h"
 
-static char *device = "hw:0,0";
-
+static char *command;
+static char *pcm_name = "hw:0";
 snd_output_t *output = NULL;
 
+static void usage(char *command)
+{
+	printf("Usage: %s [OPTION]... \n"
+		"\n"
+		"-h, --help              help\n"
+		"-c, --capture           capture tstamps \n"
+		"-d, --delay             add delay \n"
+		"-D, --device=NAME       select PCM by name \n"
+		"-p, --playback          playback tstamps \n"
+		"-t, --ts_type=TYPE      Default(0),link(1),link_estimated(2),synchronized(3) \n"
+		, command);
+}
+
+
 long long timestamp2ns(snd_htimestamp_t t)
 {
 	long long nsec;
@@ -31,15 +57,20 @@ long long timediff(snd_htimestamp_t t1, snd_htimestamp_t t2)
 	return nsec1 - nsec2;
 }
 
-void gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp,
-		  snd_htimestamp_t *trigger_timestamp,
-		  snd_htimestamp_t *audio_timestamp,
-		  snd_pcm_uframes_t *avail, snd_pcm_sframes_t *delay)
+void _gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp,
+		   snd_htimestamp_t *trigger_timestamp,
+		   snd_htimestamp_t *audio_timestamp,
+		   snd_pcm_audio_tstamp_config_t  *audio_tstamp_config,
+		   snd_pcm_audio_tstamp_report_t  *audio_tstamp_report,
+		   snd_pcm_uframes_t *avail, snd_pcm_sframes_t *delay)
 {
 	int err;
 	snd_pcm_status_t *status;
 
 	snd_pcm_status_alloca(&status);
+
+	snd_pcm_status_set_audio_htstamp_config(status, audio_tstamp_config);
+
 	if ((err = snd_pcm_status(handle, status)) < 0) {
 		printf("Stream status error: %s\n", snd_strerror(err));
 		exit(0);
@@ -47,26 +78,30 @@ void gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp,
 	snd_pcm_status_get_trigger_htstamp(status, trigger_timestamp);
 	snd_pcm_status_get_htstamp(status, timestamp);
 	snd_pcm_status_get_audio_htstamp(status, audio_timestamp);
+	snd_pcm_status_get_audio_htstamp_report(status, audio_tstamp_report);
 	*avail = snd_pcm_status_get_avail(status);
 	*delay = snd_pcm_status_get_delay(status);
 }
 
-#define PERIOD 6000
+#define TIMESTAMP_FREQ 8 /* Hz */
+#define SAMPLE_FREQ 48000
+#define PERIOD (SAMPLE_FREQ/TIMESTAMP_FREQ)
 #define PCM_LINK        /* sync start for playback and capture */
 #define TRACK_CAPTURE   /* dump capture timing info  */
 #define TRACK_PLAYBACK  /* dump playback timing info */
-#define TRACK_SAMPLE_COUNTS /* show difference between sample counters and audiotimestamps returned by driver */
+/*#define TRACK_SAMPLE_COUNTS */ /* show difference between sample counters and audiotimestamps returned by driver */
 #define PLAYBACK_BUFFERS 4
-#define TSTAMP_TYPE	SND_PCM_TSTAMP_TYPE_MONOTONIC
+#define TSTAMP_TYPE	SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW
 
 
-int main(void)
+int main(int argc, char *argv[])
 {
-        int err;
-        unsigned int i;
-        snd_pcm_t *handle_p = NULL;
-        snd_pcm_t *handle_c = NULL;
-        snd_pcm_sframes_t frames;
+	int c;
+	int err;
+	unsigned int i;
+	snd_pcm_t *handle_p = NULL;
+	snd_pcm_t *handle_c = NULL;
+	snd_pcm_sframes_t frames;
 	snd_htimestamp_t tstamp_c, tstamp_p;
 	snd_htimestamp_t trigger_tstamp_c, trigger_tstamp_p;
 	snd_htimestamp_t audio_tstamp_c, audio_tstamp_p;
@@ -87,206 +122,306 @@ int main(void)
 	snd_pcm_sframes_t delay_p, delay_c;
 	snd_pcm_uframes_t avail_p, avail_c;
 
-	if ((err = snd_pcm_open(&handle_p, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
-		printf("Playback open error: %s\n", snd_strerror(err));
-		goto _exit;
-	}
-	if ((err = snd_pcm_set_params(handle_p,
-	                              SND_PCM_FORMAT_S16,
-	                              SND_PCM_ACCESS_RW_INTERLEAVED,
-	                              2,
-	                              48000,
-	                              0,
-	                              500000)) < 0) {	/* 0.5sec */
-		printf("Playback open error: %s\n", snd_strerror(err));
-		goto _exit;
+	snd_pcm_audio_tstamp_config_t audio_tstamp_config_p;
+	snd_pcm_audio_tstamp_config_t audio_tstamp_config_c;
+	snd_pcm_audio_tstamp_report_t audio_tstamp_report_p;
+	snd_pcm_audio_tstamp_report_t audio_tstamp_report_c;
+
+	int option_index;
+	static const char short_options[] = "hcpdD:t:";
+
+	static const struct option long_options[] = {
+		{"capture", 0, 0, 'c'},
+		{"delay", 0, 0, 'd'},
+		{"device", required_argument, 0, 'D'},
+		{"help", no_argument, 0, 'h'},
+		{"playback", 0, 0, 'p'},
+		{"ts_type", required_argument, 0, 't'},
+		{0, 0, 0, 0}
+	};
+
+	int do_delay = 0;
+	int do_playback = 0;
+	int do_capture = 0;
+	int type = 0;
+
+	while ((c = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1) {
+		switch (c) {
+		case 'h':
+			usage(command);
+			return 0;
+		case 'p':
+			do_playback = 1;
+			break;
+		case 'c':
+			do_capture = 1;
+			break;
+		case 'd':
+			do_delay = 1;
+			break;
+		case 'D':
+			pcm_name = optarg;
+			break;
+		case 't':
+			type = atoi(optarg);
+			break;
+		}
 	}
 
-	snd_pcm_hw_params_alloca(&hwparams_p);
-	/* get the current hwparams */
-	err = snd_pcm_hw_params_current(handle_p, hwparams_p);
-	if (err < 0) {
-		printf("Unable to determine current hwparams_p: %s\n", snd_strerror(err));
-		goto _exit;
-	}
-	if (snd_pcm_hw_params_supports_audio_wallclock_ts(hwparams_p))
-		printf("Playback relies on audio wallclock timestamps\n");
-	else
-		printf("Playback relies on audio sample counter timestamps\n");
-
-	snd_pcm_sw_params_alloca(&swparams_p);
-	/* get the current swparams */
-	err = snd_pcm_sw_params_current(handle_p, swparams_p);
-	if (err < 0) {
-		printf("Unable to determine current swparams_p: %s\n", snd_strerror(err));
-		goto _exit;
-	}
+	memset(&audio_tstamp_config_p, 0, sizeof(snd_pcm_audio_tstamp_config_t));
+	memset(&audio_tstamp_config_c, 0, sizeof(snd_pcm_audio_tstamp_config_t));
+	memset(&audio_tstamp_report_p, 0, sizeof(snd_pcm_audio_tstamp_report_t));
+	memset(&audio_tstamp_report_c, 0, sizeof(snd_pcm_audio_tstamp_report_t));
 
-	/* enable tstamp */
-	err = snd_pcm_sw_params_set_tstamp_mode(handle_p, swparams_p, SND_PCM_TSTAMP_ENABLE);
-	if (err < 0) {
-		printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
-		goto _exit;
-	}
+	if (do_playback) {
+		if ((err = snd_pcm_open(&handle_p, pcm_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
+			printf("Playback open error: %s\n", snd_strerror(err));
+			goto _exit;
+		}
 
-	err = snd_pcm_sw_params_set_tstamp_type(handle_p, swparams_p, TSTAMP_TYPE);
-	if (err < 0) {
-		printf("Unable to set tstamp type : %s\n", snd_strerror(err));
-		goto _exit;
-	}
+		if ((err = snd_pcm_set_params(handle_p,
+							SND_PCM_FORMAT_S16,
+							SND_PCM_ACCESS_RW_INTERLEAVED,
+							2,
+							SAMPLE_FREQ,
+							0,
+							4*1000000/TIMESTAMP_FREQ)) < 0) {
+			printf("Playback open error: %s\n", snd_strerror(err));
+			goto _exit;
+		}
 
-	/* write the sw parameters */
-	err = snd_pcm_sw_params(handle_p, swparams_p);
-	if (err < 0) {
-		printf("Unable to set swparams_p : %s\n", snd_strerror(err));
-		goto _exit;
-	}
+		snd_pcm_hw_params_alloca(&hwparams_p);
+/* get the current hwparams */
+		err = snd_pcm_hw_params_current(handle_p, hwparams_p);
+		if (err < 0) {
+			printf("Unable to determine current hwparams_p: %s\n", snd_strerror(err));
+			goto _exit;
+		}
 
-	if ((err = snd_pcm_open(&handle_c, device, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) {
-		printf("Capture open error: %s\n", snd_strerror(err));
-		goto _exit;
-	}
-	if ((err = snd_pcm_set_params(handle_c,
-	                              SND_PCM_FORMAT_S16,
-	                              SND_PCM_ACCESS_RW_INTERLEAVED,
-	                              2,
-	                              48000,
-	                              0,
-	                              500000)) < 0) {	/* 0.5sec */
-		printf("Capture open error: %s\n", snd_strerror(err));
-		goto _exit;
-	}
+		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 0))
+			printf("Playback supports audio compat timestamps\n");
+		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 1))
+			printf("Playback supports audio default timestamps\n");
+		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 2))
+			printf("Playback supports audio link timestamps\n");
+		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 3))
+			printf("Playback supports audio link absolute timestamps\n");
+		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 4))
+			printf("Playback supports audio link estimated timestamps\n");
+		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 5))
+			printf("Playback supports audio link synchronized timestamps\n");
+
+		snd_pcm_sw_params_alloca(&swparams_p);
+		/* get the current swparams */
+		err = snd_pcm_sw_params_current(handle_p, swparams_p);
+		if (err < 0) {
+			printf("Unable to determine current swparams_p: %s\n", snd_strerror(err));
+			goto _exit;
+		}
 
-	snd_pcm_hw_params_alloca(&hwparams_c);
-	/* get the current hwparams */
-	err = snd_pcm_hw_params_current(handle_c, hwparams_c);
-	if (err < 0) {
-		printf("Unable to determine current hwparams_c: %s\n", snd_strerror(err));
-		goto _exit;
-	}
-	if (snd_pcm_hw_params_supports_audio_wallclock_ts(hwparams_c))
-		printf("Capture relies on audio wallclock timestamps\n");
-	else
-		printf("Capture relies on audio sample counter timestamps\n");
-
-	snd_pcm_sw_params_alloca(&swparams_c);
-	/* get the current swparams */
-	err = snd_pcm_sw_params_current(handle_c, swparams_c);
-	if (err < 0) {
-		printf("Unable to determine current swparams_c: %s\n", snd_strerror(err));
-		goto _exit;
-	}
+		/* enable tstamp */
+		err = snd_pcm_sw_params_set_tstamp_mode(handle_p, swparams_p, SND_PCM_TSTAMP_ENABLE);
+		if (err < 0) {
+			printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
+			goto _exit;
+		}
 
-	/* enable tstamp */
-	err = snd_pcm_sw_params_set_tstamp_mode(handle_c, swparams_c, SND_PCM_TSTAMP_ENABLE);
-	if (err < 0) {
-		printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
-		goto _exit;
-	}
+		err = snd_pcm_sw_params_set_tstamp_type(handle_p, swparams_p, TSTAMP_TYPE);
+		if (err < 0) {
+			printf("Unable to set tstamp type : %s\n", snd_strerror(err));
+			goto _exit;
+		}
+
+		/* write the sw parameters */
+		err = snd_pcm_sw_params(handle_p, swparams_p);
+		if (err < 0) {
+			printf("Unable to set swparams_p : %s\n", snd_strerror(err));
+			goto _exit;
+		}
 
-	err = snd_pcm_sw_params_set_tstamp_type(handle_c, swparams_c, TSTAMP_TYPE);
-	if (err < 0) {
-		printf("Unable to set tstamp type : %s\n", snd_strerror(err));
-		goto _exit;
 	}
 
-	/* write the sw parameters */
-	err = snd_pcm_sw_params(handle_c, swparams_c);
-	if (err < 0) {
-		printf("Unable to set swparams_c : %s\n", snd_strerror(err));
-		goto _exit;
+	if (do_capture) {
+
+		if ((err = snd_pcm_open(&handle_c, pcm_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) {
+			printf("Capture open error: %s\n", snd_strerror(err));
+			goto _exit;
+		}
+		if ((err = snd_pcm_set_params(handle_c,
+							SND_PCM_FORMAT_S16,
+							SND_PCM_ACCESS_RW_INTERLEAVED,
+							2,
+							SAMPLE_FREQ,
+							0,
+							4*1000000/TIMESTAMP_FREQ)) < 0) {
+			printf("Capture open error: %s\n", snd_strerror(err));
+			goto _exit;
+		}
+
+		snd_pcm_hw_params_alloca(&hwparams_c);
+		/* get the current hwparams */
+		err = snd_pcm_hw_params_current(handle_c, hwparams_c);
+		if (err < 0) {
+			printf("Unable to determine current hwparams_c: %s\n", snd_strerror(err));
+			goto _exit;
+		}
+
+		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 0))
+			printf("Capture supports audio compat timestamps\n");
+		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 1))
+			printf("Capture supports audio default timestamps\n");
+		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 2))
+			printf("Capture supports audio link timestamps\n");
+		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 3))
+			printf("Capture supports audio link absolute timestamps\n");
+		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 4))
+			printf("Capture supports audio link estimated timestamps\n");
+		if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 5))
+			printf("Capture supports audio link synchronized timestamps\n");
+
+		snd_pcm_sw_params_alloca(&swparams_c);
+		/* get the current swparams */
+		err = snd_pcm_sw_params_current(handle_c, swparams_c);
+		if (err < 0) {
+			printf("Unable to determine current swparams_c: %s\n", snd_strerror(err));
+			goto _exit;
+		}
+
+		/* enable tstamp */
+		err = snd_pcm_sw_params_set_tstamp_mode(handle_c, swparams_c, SND_PCM_TSTAMP_ENABLE);
+		if (err < 0) {
+			printf("Unable to set tstamp mode : %s\n", snd_strerror(err));
+			goto _exit;
+		}
+
+		err = snd_pcm_sw_params_set_tstamp_type(handle_c, swparams_c, TSTAMP_TYPE);
+		if (err < 0) {
+			printf("Unable to set tstamp type : %s\n", snd_strerror(err));
+			goto _exit;
+		}
+
+		/* write the sw parameters */
+		err = snd_pcm_sw_params(handle_c, swparams_c);
+		if (err < 0) {
+			printf("Unable to set swparams_c : %s\n", snd_strerror(err));
+			goto _exit;
+		}
 	}
 
+	if (do_playback && do_capture) {
 #ifdef PCM_LINK
-	if ((err = snd_pcm_link(handle_c, handle_p)) < 0) {
-		printf("Streams link error: %s\n", snd_strerror(err));
-		exit(0);
-	}
+		if ((err = snd_pcm_link(handle_c, handle_p)) < 0) {
+			printf("Streams link error: %s\n", snd_strerror(err));
+			exit(0);
+		}
 #endif
-
-	i = PLAYBACK_BUFFERS;
-	while (i--) {
-                frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
-                if (frames < 0) {
-                        printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
-                        goto _exit;
-                }
-		frame_count_p += frames;
 	}
 
-	if (PLAYBACK_BUFFERS != 4)
-		snd_pcm_start(handle_p);
+	if (do_playback) {
+		i = PLAYBACK_BUFFERS;
+		while (i--) {
+			frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
+			if (frames < 0) {
+				printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
+				goto _exit;
+			}
+			frame_count_p += frames;
+		}
+
+		if (PLAYBACK_BUFFERS != 4)
+			snd_pcm_start(handle_p);
+	}
 
+	if (do_capture) {
 #ifndef PCM_LINK
-	/* need to start capture explicitly */
-	snd_pcm_start(handle_c);
+		/* need to start capture explicitly */
+		snd_pcm_start(handle_c);
+#else
+		if (!do_playback)
+			/* need to start capture explicitly */
+			snd_pcm_start(handle_c);
 #endif
+	}
 
-        while (1) {
-
-		frames = snd_pcm_wait(handle_c, -1);
-		if (frames < 0) {
-			printf("snd_pcm_wait failed: %s\n", snd_strerror(frames));
-                        goto _exit;
-		}
-
-		frames = snd_pcm_readi(handle_c, buffer_c, PERIOD);
-                if (frames < 0) {
-                        printf("snd_pcm_readi failed: %s\n", snd_strerror(frames));
-                        goto _exit;
-                }
-		frame_count_c += frames;
+	while (1) {
 
-                frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
-                if (frames < 0) {
-                        printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
-                        goto _exit;
-                }
+		if (do_capture) {
 
-		frame_count_p += frames;
+			frames = snd_pcm_wait(handle_c, -1);
+			if (frames < 0) {
+				printf("snd_pcm_wait failed: %s\n", snd_strerror(frames));
+				goto _exit;
+			}
 
-#if defined(TRACK_PLAYBACK)
-		gettimestamp(handle_p, &tstamp_p, &trigger_tstamp_p, &audio_tstamp_p, &avail_p, &delay_p);
+			frames = snd_pcm_readi(handle_c, buffer_c, PERIOD);
+			if (frames < 0) {
+				printf("snd_pcm_readi failed: %s\n", snd_strerror(frames));
+				goto _exit;
+			}
+			frame_count_c += frames;
 
+#if defined(TRACK_CAPTURE)
+			audio_tstamp_config_c.type_requested = type;
+			audio_tstamp_config_c.report_delay = do_delay;
+			_gettimestamp(handle_c, &tstamp_c, &trigger_tstamp_c,
+				&audio_tstamp_c, &audio_tstamp_config_c, &audio_tstamp_report_c,
+				&avail_c, &delay_c);
 #if defined(TRACK_SAMPLE_COUNTS)
-		curr_count_p = frame_count_p - delay_p; /* written minus queued */
+			curr_count_c = frame_count_c + delay_c; /* read plus queued */
 
-		printf("playback: curr_count %lli driver count %lli, delta %lli\n",
-		       (long long)curr_count_p * 1000000000LL / 48000 ,
-		       timestamp2ns(audio_tstamp_p),
-		       (long long)curr_count_p * 1000000000LL / 48000 - timestamp2ns(audio_tstamp_p)
-		       );
+
+			printf("capture: curr_count %lli driver count %lli, delta %lli\n",
+				(long long)curr_count_c * 1000000000LL / SAMPLE_FREQ ,
+				timestamp2ns(audio_tstamp_c),
+				(long long)curr_count_c * 1000000000LL / SAMPLE_FREQ - timestamp2ns(audio_tstamp_c)
+				);
 #endif
 
-		printf("playback: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli\n",
-		       timediff(tstamp_p, trigger_tstamp_p),
-		       timestamp2ns(audio_tstamp_p),
-		       timediff(tstamp_p, trigger_tstamp_p) - timestamp2ns(audio_tstamp_p)
-		       );
+			printf("\t capture: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli\n",
+				timediff(tstamp_c, trigger_tstamp_c),
+				timestamp2ns(audio_tstamp_c),
+				timediff(tstamp_c, trigger_tstamp_c) - timestamp2ns(audio_tstamp_c)
+				);
 #endif
+		}
 
-#if defined(TRACK_CAPTURE)
-		gettimestamp(handle_c, &tstamp_c, &trigger_tstamp_c, &audio_tstamp_c, &avail_c, &delay_c);
+		if (do_playback) {
+			frames = snd_pcm_writei(handle_p, buffer_p, PERIOD);
+			if (frames < 0) {
+				printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
+				goto _exit;
+			}
 
-#if defined(TRACK_SAMPLE_COUNTS)
-		curr_count_c = frame_count_c + delay_c; /* read plus queued */
+			frame_count_p += frames;
+
+#if defined(TRACK_PLAYBACK)
 
+			audio_tstamp_config_p.type_requested = type;
+			audio_tstamp_config_p.report_delay = do_delay;
+			_gettimestamp(handle_p, &tstamp_p, &trigger_tstamp_p,
+				&audio_tstamp_p, &audio_tstamp_config_p, &audio_tstamp_report_p,
+				&avail_p, &delay_p);
 
-		printf("capture: curr_count %lli driver count %lli, delta %lli\n",
-		       (long long)curr_count_c * 1000000000LL / 48000 ,
-		       timestamp2ns(audio_tstamp_c),
-		       (long long)curr_count_c * 1000000000LL / 48000 - timestamp2ns(audio_tstamp_c)
-		       );
+#if defined(TRACK_SAMPLE_COUNTS)
+			curr_count_p = frame_count_p - delay_p; /* written minus queued */
+
+			printf("playback: curr_count %lli driver count %lli, delta %lli\n",
+				(long long)curr_count_p * 1000000000LL / SAMPLE_FREQ ,
+				timestamp2ns(audio_tstamp_p),
+				(long long)curr_count_p * 1000000000LL / SAMPLE_FREQ - timestamp2ns(audio_tstamp_p)
+				);
 #endif
 
-		printf("\t capture: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli\n",
-		       timediff(tstamp_c, trigger_tstamp_c),
-		       timestamp2ns(audio_tstamp_c),
-		       timediff(tstamp_c, trigger_tstamp_c) - timestamp2ns(audio_tstamp_c)
-		       );
+			printf("playback: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli\n",
+				timediff(tstamp_p, trigger_tstamp_p),
+				timestamp2ns(audio_tstamp_p),
+				timediff(tstamp_p, trigger_tstamp_p) - timestamp2ns(audio_tstamp_p)
+				);
 #endif
+		}
+
 
-        }
+	} /* while(1) */
 
 _exit:
 	if (handle_p)
-- 
1.9.1

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

end of thread, other threads:[~2015-01-30 23:57 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-30 23:57 [PATCH 1/5] sync asound.h with kernel version Pierre-Louis Bossart
2015-01-30 23:57 ` [PATCH 2/5] add support for get/set_audio_htstamp_config Pierre-Louis Bossart
2015-01-30 23:57 ` [PATCH 3/5] pcm: add helper functions to query timestamping capabilities Pierre-Louis Bossart
2015-01-30 23:57 ` [PATCH 4/5] pcm: add support for new STATUS_EXT ioctl Pierre-Louis Bossart
2015-01-30 23:57 ` [PATCH 5/5] test: fix audio_time with new get/set audio_tstamp_config Pierre-Louis Bossart

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.