Alsa: Use hires timestamps (#560)
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.
This commit is contained in:
parent
9faca9b95b
commit
9413fa051f
1 changed files with 37 additions and 22 deletions
|
|
@ -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, ×tamp );
|
||||
}
|
||||
else
|
||||
{
|
||||
alsa_snd_pcm_status_get_htstamp( status, ×tamp );
|
||||
}
|
||||
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, ×tamp );
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue