aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2007-12-13 04:19:42 -0500
committerJaroslav Kysela <perex@perex.cz>2008-01-31 11:29:31 -0500
commitb751eef1fdffca5532344285f2fad0c60d2f0158 (patch)
treed504104c6315a8abc4b3f657f8f4828fb55a8795 /sound/core
parent25543fa785a32ce22e7374ba403eb6d38854d037 (diff)
[ALSA] Use posix clock monotonic for PCM and timer timestamps
We need an accurate and continuous (monotonic) time sources to do accurate synchronization among more timing sources. This patch allows to enable monotonic timestamps for ALSA PCM devices and enables monotonic timestamps for ALSA timer devices. Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/pcm_lib.c2
-rw-r--r--sound/core/pcm_native.c25
-rw-r--r--sound/core/timer.c16
3 files changed, 34 insertions, 9 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 93d7ca50273..db3d7e934ec 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -188,7 +188,7 @@ static inline int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *subs
188 snd_pcm_sframes_t delta; 188 snd_pcm_sframes_t delta;
189 189
190 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_MMAP) 190 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_MMAP)
191 getnstimeofday((struct timespec *)&runtime->status->tstamp); 191 snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
192 pos = snd_pcm_update_hw_ptr_pos(substream, runtime); 192 pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
193 if (pos == SNDRV_PCM_POS_XRUN) { 193 if (pos == SNDRV_PCM_POS_XRUN) {
194 xrun(substream); 194 xrun(substream);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 6245bdaffa6..cdeae7c46e3 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -598,9 +598,9 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
598 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_MMAP) 598 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_MMAP)
599 status->tstamp = runtime->status->tstamp; 599 status->tstamp = runtime->status->tstamp;
600 else 600 else
601 getnstimeofday(&status->tstamp); 601 snd_pcm_gettime(runtime, &status->tstamp);
602 } else 602 } else
603 getnstimeofday(&status->tstamp); 603 snd_pcm_gettime(runtime, &status->tstamp);
604 status->appl_ptr = runtime->control->appl_ptr; 604 status->appl_ptr = runtime->control->appl_ptr;
605 status->hw_ptr = runtime->status->hw_ptr; 605 status->hw_ptr = runtime->status->hw_ptr;
606 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 606 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -688,7 +688,7 @@ static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream)
688 if (runtime->trigger_master == NULL) 688 if (runtime->trigger_master == NULL)
689 return; 689 return;
690 if (runtime->trigger_master == substream) { 690 if (runtime->trigger_master == substream) {
691 getnstimeofday(&runtime->trigger_tstamp); 691 snd_pcm_gettime(runtime, &runtime->trigger_tstamp);
692 } else { 692 } else {
693 snd_pcm_trigger_tstamp(runtime->trigger_master); 693 snd_pcm_trigger_tstamp(runtime->trigger_master);
694 runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp; 694 runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp;
@@ -2519,6 +2519,21 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
2519 return -EFAULT; 2519 return -EFAULT;
2520 return 0; 2520 return 0;
2521} 2521}
2522
2523static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg)
2524{
2525 struct snd_pcm_runtime *runtime = substream->runtime;
2526 int arg;
2527
2528 if (get_user(arg, _arg))
2529 return -EFAULT;
2530 if (arg < 0 || arg > SNDRV_PCM_TSTAMP_TYPE_LAST)
2531 return -EINVAL;
2532 runtime->tstamp_type = SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
2533 if (arg == SNDRV_PCM_TSTAMP_TYPE_MONOTONIC)
2534 runtime->tstamp_type = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC;
2535 return 0;
2536}
2522 2537
2523static int snd_pcm_common_ioctl1(struct file *file, 2538static int snd_pcm_common_ioctl1(struct file *file,
2524 struct snd_pcm_substream *substream, 2539 struct snd_pcm_substream *substream,
@@ -2531,8 +2546,8 @@ static int snd_pcm_common_ioctl1(struct file *file,
2531 return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0; 2546 return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0;
2532 case SNDRV_PCM_IOCTL_INFO: 2547 case SNDRV_PCM_IOCTL_INFO:
2533 return snd_pcm_info_user(substream, arg); 2548 return snd_pcm_info_user(substream, arg);
2534 case SNDRV_PCM_IOCTL_TSTAMP: /* just for compatibility */ 2549 case SNDRV_PCM_IOCTL_TTSTAMP:
2535 return 0; 2550 return snd_pcm_tstamp(substream, arg);
2536 case SNDRV_PCM_IOCTL_HW_REFINE: 2551 case SNDRV_PCM_IOCTL_HW_REFINE:
2537 return snd_pcm_hw_refine_user(substream, arg); 2552 return snd_pcm_hw_refine_user(substream, arg);
2538 case SNDRV_PCM_IOCTL_HW_PARAMS: 2553 case SNDRV_PCM_IOCTL_HW_PARAMS:
diff --git a/sound/core/timer.c b/sound/core/timer.c
index e7dc56ca4b9..7e5fe2d9166 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -44,11 +44,14 @@
44#endif 44#endif
45 45
46static int timer_limit = DEFAULT_TIMER_LIMIT; 46static int timer_limit = DEFAULT_TIMER_LIMIT;
47static int timer_tstamp_monotonic = 1;
47MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>"); 48MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>");
48MODULE_DESCRIPTION("ALSA timer interface"); 49MODULE_DESCRIPTION("ALSA timer interface");
49MODULE_LICENSE("GPL"); 50MODULE_LICENSE("GPL");
50module_param(timer_limit, int, 0444); 51module_param(timer_limit, int, 0444);
51MODULE_PARM_DESC(timer_limit, "Maximum global timers in system."); 52MODULE_PARM_DESC(timer_limit, "Maximum global timers in system.");
53module_param(timer_tstamp_monotonic, int, 0444);
54MODULE_PARM_DESC(timer_tstamp_monotonic, "Use posix monotonic clock source for timestamps (default).");
52 55
53struct snd_timer_user { 56struct snd_timer_user {
54 struct snd_timer_instance *timeri; 57 struct snd_timer_instance *timeri;
@@ -381,7 +384,10 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
381 struct snd_timer_instance *ts; 384 struct snd_timer_instance *ts;
382 struct timespec tstamp; 385 struct timespec tstamp;
383 386
384 getnstimeofday(&tstamp); 387 if (timer_tstamp_monotonic)
388 do_posix_clock_monotonic_gettime(&tstamp);
389 else
390 getnstimeofday(&tstamp);
385 snd_assert(event >= SNDRV_TIMER_EVENT_START && 391 snd_assert(event >= SNDRV_TIMER_EVENT_START &&
386 event <= SNDRV_TIMER_EVENT_PAUSE, return); 392 event <= SNDRV_TIMER_EVENT_PAUSE, return);
387 if (event == SNDRV_TIMER_EVENT_START || 393 if (event == SNDRV_TIMER_EVENT_START ||
@@ -1182,8 +1188,12 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
1182 spin_unlock(&tu->qlock); 1188 spin_unlock(&tu->qlock);
1183 return; 1189 return;
1184 } 1190 }
1185 if (tu->last_resolution != resolution || ticks > 0) 1191 if (tu->last_resolution != resolution || ticks > 0) {
1186 getnstimeofday(&tstamp); 1192 if (timer_tstamp_monotonic)
1193 do_posix_clock_monotonic_gettime(&tstamp);
1194 else
1195 getnstimeofday(&tstamp);
1196 }
1187 if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && 1197 if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) &&
1188 tu->last_resolution != resolution) { 1198 tu->last_resolution != resolution) {
1189 r1.event = SNDRV_TIMER_EVENT_RESOLUTION; 1199 r1.event = SNDRV_TIMER_EVENT_RESOLUTION;