]> Repos - portaudio/commitdiff
Have PaUtil_GetTime() use monotonic time on Unix (#559)
authorTrent Piepho <35062987+xyzzy42@users.noreply.github.com>
Wed, 9 Jun 2021 00:52:32 +0000 (17:52 -0700)
committerGitHub <noreply@github.com>
Wed, 9 Jun 2021 00:52:32 +0000 (17:52 -0700)
The currently used clock, CLOCK_REALTIME, will have discontinuous jumps, forward
and backward, when the system clock is adjusted.  This is bad for synchronizing
audio.  CLOCK_MONOTONIC does not have jumps, and never moves backward, but does
have the continuous adjustments done by NTP to increase clock accuracy.

Since kernel 2.6.25 ALSA has use CLOCK_MONOTONIC by default for timestamps
(commit b751eef1 from Dec 13 2007).  This change means the timestamps provided
in the PA callbacks can be compared to PaUtil_GetTime(), which currently does
not work.

The function used on MacOS, mach_absolute_time(), behaves like CLOCK_MONOTONIC.

If the system does not have CLOCK_MONOTONIC, fallback to CLOCK_REALTIME, which
is what alsa-lib does for such systems.  Which at this point would need to be
very old.

* Use clock monotonic for condition variable

This is necessary to match PaUtil_GetTime() also using the monotonic
clock.  Otherwise the wait time, derived from that function, will be
completely incorrect.

This will also fix an obscure flaw if the system clock is adjust while
waiting for the stream to open, it might not wait at all and fail or
wait (effectively) forever instead of timing out, depend on the
adjustment direction.

src/os/unix/pa_unix_util.c

index 459b2bef3eaccf52a892933ac42601327ca8d289..f234c646a248a904ad820f18fd51498a1c19b5d8 100644 (file)
@@ -160,7 +160,11 @@ PaTime PaUtil_GetTime( void )
     return mach_absolute_time() * machSecondsConversionScaler_;
 #elif defined(HAVE_CLOCK_GETTIME)
     struct timespec tp;
+#if defined(CLOCK_MONOTONIC)
+    clock_gettime(CLOCK_MONOTONIC, &tp);
+#else
     clock_gettime(CLOCK_REALTIME, &tp);
+#endif
     return (PaTime)(tp.tv_sec + tp.tv_nsec * 1e-9);
 #else
     struct timeval tv;
@@ -270,11 +274,16 @@ PaError PaUnixThread_New( PaUnixThread* self, void* (*threadFunc)( void* ), void
 {
     PaError result = paNoError;
     pthread_attr_t attr;
+    pthread_condattr_t cattr;
     int started = 0;
 
     memset( self, 0, sizeof (PaUnixThread) );
     PaUnixMutex_Initialize( &self->mtx );
-    PA_ASSERT_CALL( pthread_cond_init( &self->cond, NULL ), 0 );
+    PA_ASSERT_CALL( pthread_condattr_init( &cattr ), 0 );
+#if defined(CLOCK_MONOTONIC) && !defined(__APPLE__)
+    PA_ASSERT_CALL( pthread_condattr_setclock( &cattr, CLOCK_MONOTONIC ), 0 );
+#endif
+    PA_ASSERT_CALL( pthread_cond_init( &self->cond, &cattr), 0 );
 
     self->parentWaiting = 0 != waitForChild;