[alsa-devel] POSIX clocks and ALSA

Jaroslav Kysela perex at perex.cz
Mon Nov 26 15:51:02 CET 2007


On Mon, 26 Nov 2007, Heikki Lindholm wrote:

> I had a look at the proposal and the thread at
> http://thread.gmane.org/gmane.linux.alsa.devel/45237/focus=45573

My initial implementation following proposal is bellow for review and 
comments. I also changed timestamps for ALSA timers to use monotonic 
clocks (can be switched back using a module parameter).

					Jaroslav

diff -r 5e8cab953031 core/pcm_lib.c
--- a/core/pcm_lib.c	Mon Nov 26 09:00:56 2007 +0100
+++ b/core/pcm_lib.c	Mon Nov 26 14:50:01 2007 +0100
@@ -188,7 +188,7 @@ static inline int snd_pcm_update_hw_ptr_
 	snd_pcm_sframes_t delta;
 
 	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_MMAP)
-		getnstimeofday((struct timespec *)&runtime->status->tstamp);
+		snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
 	pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
 	if (pos == SNDRV_PCM_POS_XRUN) {
 		xrun(substream);
diff -r 5e8cab953031 core/pcm_native.c
--- a/core/pcm_native.c	Mon Nov 26 09:00:56 2007 +0100
+++ b/core/pcm_native.c	Mon Nov 26 15:19:22 2007 +0100
@@ -598,9 +598,9 @@ int snd_pcm_status(struct snd_pcm_substr
 		if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_MMAP)
 			status->tstamp = runtime->status->tstamp;
 		else
-			getnstimeofday(&status->tstamp);
+			snd_pcm_gettime(runtime, &status->tstamp);
 	} else
-		getnstimeofday(&status->tstamp);
+		snd_pcm_gettime(runtime, &status->tstamp);
 	status->appl_ptr = runtime->control->appl_ptr;
 	status->hw_ptr = runtime->status->hw_ptr;
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -688,7 +688,7 @@ static void snd_pcm_trigger_tstamp(struc
 	if (runtime->trigger_master == NULL)
 		return;
 	if (runtime->trigger_master == substream) {
-		getnstimeofday(&runtime->trigger_tstamp);
+		snd_pcm_gettime(runtime, &runtime->trigger_tstamp);
 	} else {
 		snd_pcm_trigger_tstamp(runtime->trigger_master);
 		runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp;
@@ -2519,6 +2519,21 @@ static int snd_pcm_sync_ptr(struct snd_p
 		return -EFAULT;
 	return 0;
 }
+
+static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int arg;
+	
+	if (get_user(arg, _arg))
+		return -EFAULT;
+	if (arg < 0 || arg > SNDRV_PCM_TSTAMP_TYPE_LAST)
+		return -EINVAL;
+	runtime->tstamp_type = SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
+	if (arg == SNDRV_PCM_TSTAMP_TYPE_MONOTONIC)
+		runtime->tstamp_type = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC;
+	return 0;
+}
 		
 static int snd_pcm_common_ioctl1(struct file *file,
 				 struct snd_pcm_substream *substream,
@@ -2531,8 +2546,8 @@ static int snd_pcm_common_ioctl1(struct 
 		return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0;
 	case SNDRV_PCM_IOCTL_INFO:
 		return snd_pcm_info_user(substream, arg);
-	case SNDRV_PCM_IOCTL_TSTAMP: /* just for compatibility */
-		return 0;
+	case SNDRV_PCM_IOCTL_TSTAMP:
+		return snd_pcm_tstamp(substream, arg);
 	case SNDRV_PCM_IOCTL_HW_REFINE:
 		return snd_pcm_hw_refine_user(substream, arg);
 	case SNDRV_PCM_IOCTL_HW_PARAMS:
diff -r 5e8cab953031 core/timer.c
--- a/core/timer.c	Mon Nov 26 09:00:56 2007 +0100
+++ b/core/timer.c	Mon Nov 26 14:59:33 2007 +0100
@@ -44,11 +44,14 @@
 #endif
 
 static int timer_limit = DEFAULT_TIMER_LIMIT;
+static int timer_tstamp_monotonic = 1;
 MODULE_AUTHOR("Jaroslav Kysela <perex at perex.cz>, Takashi Iwai <tiwai at suse.de>");
 MODULE_DESCRIPTION("ALSA timer interface");
 MODULE_LICENSE("GPL");
 module_param(timer_limit, int, 0444);
 MODULE_PARM_DESC(timer_limit, "Maximum global timers in system.");
+module_param(timer_tstamp_monotonic, int, 0444);
+MODULE_PARM_DESC(timer_tstamp_monotonic, "Use posix monotonic clock source for timestamps (default).");
 
 struct snd_timer_user {
 	struct snd_timer_instance *timeri;
@@ -381,7 +384,10 @@ static void snd_timer_notify1(struct snd
 	struct snd_timer_instance *ts;
 	struct timespec tstamp;
 
-	getnstimeofday(&tstamp);
+	if (timer_tstamp_monotonic)
+		do_posix_clock_monotonic_gettime(&tstamp);
+	else
+		getnstimeofday(&tstamp);
 	snd_assert(event >= SNDRV_TIMER_EVENT_START &&
 		   event <= SNDRV_TIMER_EVENT_PAUSE, return);
 	if (event == SNDRV_TIMER_EVENT_START ||
@@ -1182,8 +1188,12 @@ static void snd_timer_user_tinterrupt(st
 		spin_unlock(&tu->qlock);
 		return;
 	}
-	if (tu->last_resolution != resolution || ticks > 0)
-		getnstimeofday(&tstamp);
+	if (tu->last_resolution != resolution || ticks > 0) {
+		if (timer_tstamp_monotonic)
+			do_posix_clock_monotonic_gettime(&tstamp);
+		else
+			getnstimeofday(&tstamp);
+	}
 	if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) &&
 	    tu->last_resolution != resolution) {
 		r1.event = SNDRV_TIMER_EVENT_RESOLUTION;
diff -r 5e8cab953031 include/asound.h
--- a/include/asound.h	Mon Nov 26 09:00:56 2007 +0100
+++ b/include/asound.h	Mon Nov 26 15:02:57 2007 +0100
@@ -435,6 +435,13 @@ struct snd_xfern {
 };
 
 enum {
+	SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0,	/* gettimeofday equivalent */
+	SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY1,	/* for compatibility, equal to zero */
+	SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,	/* posix_clock_monotonic equivalent */
+	SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
+};
+
+enum {
 	SNDRV_PCM_IOCTL_PVERSION = _IOR('A', 0x00, int),
 	SNDRV_PCM_IOCTL_INFO = _IOR('A', 0x01, struct snd_pcm_info),
 	SNDRV_PCM_IOCTL_TSTAMP = _IOW('A', 0x02, int),
diff -r 5e8cab953031 include/pcm.h
--- a/include/pcm.h	Mon Nov 26 09:00:56 2007 +0100
+++ b/include/pcm.h	Mon Nov 26 15:20:22 2007 +0100
@@ -323,6 +323,7 @@ struct snd_pcm_runtime {
 
 	/* -- timer -- */
 	unsigned int timer_resolution;	/* timer resolution */
+	int tstamp_type;		/* timestamp type */
 
 	/* -- DMA -- */           
 	unsigned char *dma_area;	/* DMA area */
@@ -952,6 +953,15 @@ void snd_pcm_timer_init(struct snd_pcm_s
 void snd_pcm_timer_init(struct snd_pcm_substream *substream);
 void snd_pcm_timer_done(struct snd_pcm_substream *substream);
 
+static inline void snd_pcm_gettime(struct snd_pcm_runtime *runtime,
+				   struct timespec *tv)
+{
+	if (runtime->tstamp_type == SNDRV_PCM_TSTAMP_TYPE_MONOTONIC)
+		do_posix_clock_monotonic_gettime(tv);
+	else
+		getnstimeofday(tv);
+}
+
 /*
  *  Memory
  */

-----
Jaroslav Kysela <perex at perex.cz>
Linux Kernel Sound Maintainer
ALSA Project


More information about the Alsa-devel mailing list