]> Repos - portaudio/commitdiff
Alsa: Use hires timestamps (#560)
authorTrent Piepho <35062987+xyzzy42@users.noreply.github.com>
Thu, 3 Jun 2021 01:03:42 +0000 (18:03 -0700)
committerGitHub <noreply@github.com>
Thu, 3 Jun 2021 01:03:42 +0000 (18:03 -0700)
ALSA added nanosecond timestamps in library version 0.9.1.  Use these
instead of microsecond timestamps for reporting audio timestamps as well
as underrun/overrun times.

alsa-lib version 0.9.1 was released on Mar 11 2003.  I had fallback code
to use non-hires timestamps, but after 18 years it didn't seem
necessary, and I removed it from this commit.

src/hostapi/alsa/pa_linux_alsa.c

index 80b46975d92cc4cb32585651e70fd5a78521edf4..a6d2aec9c51134f633e7c77e5e969db7c5ffa4c3 100644 (file)
@@ -220,8 +220,10 @@ _PA_DEFINE_FUNC(snd_config_update_free_global);
 _PA_DEFINE_FUNC(snd_pcm_status);
 _PA_DEFINE_FUNC(snd_pcm_status_sizeof);
 _PA_DEFINE_FUNC(snd_pcm_status_get_tstamp);
+_PA_DEFINE_FUNC(snd_pcm_status_get_htstamp);
 _PA_DEFINE_FUNC(snd_pcm_status_get_state);
 _PA_DEFINE_FUNC(snd_pcm_status_get_trigger_tstamp);
+_PA_DEFINE_FUNC(snd_pcm_status_get_trigger_htstamp);
 _PA_DEFINE_FUNC(snd_pcm_status_get_delay);
 #define alsa_snd_pcm_status_alloca(ptr) __alsa_snd_alloca(ptr, snd_pcm_status)
 
@@ -499,8 +501,10 @@ static int PaAlsa_LoadLibrary()
     _PA_LOAD_FUNC(snd_pcm_status);
     _PA_LOAD_FUNC(snd_pcm_status_sizeof);
     _PA_LOAD_FUNC(snd_pcm_status_get_tstamp);
+    _PA_LOAD_FUNC(snd_pcm_status_get_htstamp);
     _PA_LOAD_FUNC(snd_pcm_status_get_state);
     _PA_LOAD_FUNC(snd_pcm_status_get_trigger_tstamp);
+    _PA_LOAD_FUNC(snd_pcm_status_get_trigger_htstamp);
     _PA_LOAD_FUNC(snd_pcm_status_get_delay);
 
     _PA_LOAD_FUNC(snd_card_next);
@@ -3156,6 +3160,28 @@ static PaError IsStreamActive( PaStream *s )
     return stream->isActive;
 }
 
+/** Extract audio/trigger htstamp from status and convert into PaTime (seconds).
+ *
+ * trigger is boolean:  trigger stampstamp vs audio timestamp.  If delay is non-NULL, return delay in
+ * frames.  */
+static PaTime StatusToTime( const snd_pcm_status_t *status, int trigger, snd_pcm_uframes_t* delay )
+{
+    snd_htimestamp_t timestamp;
+    if ( trigger )
+    {
+        alsa_snd_pcm_status_get_trigger_htstamp( status, &timestamp );
+    }
+    else
+    {
+        alsa_snd_pcm_status_get_htstamp( status, &timestamp );
+    }
+    if ( delay )
+    {
+        *delay = alsa_snd_pcm_status_get_delay( status );
+    }
+    return timestamp.tv_sec + ( (PaTime)timestamp.tv_nsec * 1e-9 );
+}
+
 static PaTime GetStreamTime( PaStream *s )
 {
     PaAlsaStream *stream = (PaAlsaStream*)s;
@@ -3179,8 +3205,7 @@ static PaTime GetStreamTime( PaStream *s )
         alsa_snd_pcm_status( stream->playback.pcm, status );
     }
 
-    alsa_snd_pcm_status_get_tstamp( status, &timestamp );
-    return timestamp.tv_sec + (PaTime)timestamp.tv_usec / 1e6;
+    return StatusToTime( status, 0, NULL );
 }
 
 static double GetStreamCpuLoad( PaStream* s )
@@ -3276,7 +3301,7 @@ static PaError PaAlsaStream_HandleXrun( PaAlsaStream *self )
         if( alsa_snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN )
         {
             alsa_snd_pcm_status_get_trigger_tstamp( st, &t );
-            self->underrun = now * 1000 - ( (PaTime)t.tv_sec * 1000 + (PaTime)t.tv_usec / 1000 );
+            self->underrun = ( now - StatusToTime( st, 1, NULL ) ) * 1000;
 
             if( !self->playback.canMmap )
             {
@@ -3295,8 +3320,7 @@ static PaError PaAlsaStream_HandleXrun( PaAlsaStream *self )
         alsa_snd_pcm_status( self->capture.pcm, st );
         if( alsa_snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN )
         {
-            alsa_snd_pcm_status_get_trigger_tstamp( st, &t );
-            self->overrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);
+            self->overrun = ( now - StatusToTime( st, 1, NULL ) ) * 1000;
 
             if (!self->capture.canMmap)
             {
@@ -3408,37 +3432,29 @@ static void OnExit( void *data )
 
 static void CalculateTimeInfo( PaAlsaStream *stream, PaStreamCallbackTimeInfo *timeInfo )
 {
-    snd_pcm_status_t *capture_status, *playback_status;
-    snd_timestamp_t capture_timestamp, playback_timestamp;
+    snd_pcm_status_t *status;
     PaTime capture_time = 0., playback_time = 0.;
 
-    alsa_snd_pcm_status_alloca( &capture_status );
-    alsa_snd_pcm_status_alloca( &playback_status );
+    alsa_snd_pcm_status_alloca( &status );
 
     if( stream->capture.pcm )
     {
         snd_pcm_sframes_t capture_delay;
 
-        alsa_snd_pcm_status( stream->capture.pcm, capture_status );
-        alsa_snd_pcm_status_get_tstamp( capture_status, &capture_timestamp );
+        alsa_snd_pcm_status( stream->capture.pcm, status );
+        capture_time = StatusToTime( status, 0, &capture_delay );
 
-        capture_time = capture_timestamp.tv_sec +
-            ( (PaTime)capture_timestamp.tv_usec / 1000000.0 );
         timeInfo->currentTime = capture_time;
-
-        capture_delay = alsa_snd_pcm_status_get_delay( capture_status );
-        timeInfo->inputBufferAdcTime = timeInfo->currentTime -
+        timeInfo->inputBufferAdcTime = capture_time -
             (PaTime)capture_delay / stream->streamRepresentation.streamInfo.sampleRate;
     }
     if( stream->playback.pcm )
     {
         snd_pcm_sframes_t playback_delay;
+        PaTime playback_time;
 
-        alsa_snd_pcm_status( stream->playback.pcm, playback_status );
-        alsa_snd_pcm_status_get_tstamp( playback_status, &playback_timestamp );
-
-        playback_time = playback_timestamp.tv_sec +
-            ((PaTime)playback_timestamp.tv_usec / 1000000.0);
+        alsa_snd_pcm_status( stream->playback.pcm, status );
+        playback_time = StatusToTime( status, 0, &playback_delay );
 
         if( stream->capture.pcm ) /* Full duplex */
         {
@@ -3450,7 +3466,6 @@ static void CalculateTimeInfo( PaAlsaStream *stream, PaStreamCallbackTimeInfo *t
         else
             timeInfo->currentTime = playback_time;
 
-        playback_delay = alsa_snd_pcm_status_get_delay( playback_status );
         timeInfo->outputBufferDacTime = timeInfo->currentTime +
             (PaTime)playback_delay / stream->streamRepresentation.streamInfo.sampleRate;
     }