test: time out in patest_sine_time.c (#585)

On ALSA the StreamTime was not advancing so the while()
loop never exited. Now it will time out if it plays for much
longer than expected without the stream time changing.

Also measure timestamp latency from callback info.
This commit is contained in:
Phil Burk 2021-06-08 17:19:14 -07:00 committed by GitHub
commit 8ef5021a9d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -48,7 +48,9 @@
#include "portaudio.h" #include "portaudio.h"
#include "pa_util.h" #include "pa_util.h"
#define NUM_SECONDS (8) /* Total time. */
#define NUM_SECONDS (8.0)
#define NUM_LOOPS (2)
#define SAMPLE_RATE (44100) #define SAMPLE_RATE (44100)
#define FRAMES_PER_BUFFER (64) #define FRAMES_PER_BUFFER (64)
@ -63,7 +65,9 @@ typedef struct
{ {
double left_phase; double left_phase;
double right_phase; double right_phase;
volatile PaTime latency;
volatile PaTime outTime; volatile PaTime outTime;
volatile long frameCount;
} }
paTestData; paTestData;
@ -91,6 +95,7 @@ static int patestCallback( const void *inputBuffer, void *outputBuffer,
(void) inputBuffer; (void) inputBuffer;
data->outTime = timeInfo->outputBufferDacTime; data->outTime = timeInfo->outputBufferDacTime;
data->latency = timeInfo->outputBufferDacTime - timeInfo->currentTime;
for( i=0; i<framesPerBuffer; i++ ) for( i=0; i<framesPerBuffer; i++ )
{ {
@ -105,6 +110,7 @@ static int patestCallback( const void *inputBuffer, void *outputBuffer,
data->left_phase = left_phase; data->left_phase = left_phase;
data->right_phase = right_phase; data->right_phase = right_phase;
data->frameCount += framesPerBuffer;
return paContinue; return paContinue;
} }
@ -113,7 +119,7 @@ static int patestCallback( const void *inputBuffer, void *outputBuffer,
static void ReportStreamTime( PaStream *stream, paTestData *data ); static void ReportStreamTime( PaStream *stream, paTestData *data );
static void ReportStreamTime( PaStream *stream, paTestData *data ) static void ReportStreamTime( PaStream *stream, paTestData *data )
{ {
PaTime streamTime, latency, outTime; PaTime streamTime, outTime;
streamTime = Pa_GetStreamTime( stream ); streamTime = Pa_GetStreamTime( stream );
outTime = data->outTime; outTime = data->outTime;
@ -123,9 +129,8 @@ static void ReportStreamTime( PaStream *stream, paTestData *data )
} }
else else
{ {
latency = outTime - streamTime; printf("Stream time = %8.4f, outTime = %8.4f, latency = %8.4f, frames = %ld\n",
printf("Stream time = %8.4f, outTime = %8.4f, latency = %8.4f\n", streamTime, outTime, data->latency, data->frameCount );
streamTime, outTime, latency );
} }
fflush(stdout); fflush(stdout);
} }
@ -137,13 +142,13 @@ int main(void)
PaStreamParameters outputParameters; PaStreamParameters outputParameters;
PaStream *stream; PaStream *stream;
PaError err; PaError err;
paTestData data; paTestData data = {0};
PaTime startTime; PaTime startTime;
long maxFrameCount;
double secondsPerLoop;
printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
data.left_phase = data.right_phase = 0;
err = Pa_Initialize(); err = Pa_Initialize();
if( err != paNoError ) goto error; if( err != paNoError ) goto error;
@ -168,52 +173,52 @@ int main(void)
&data ); &data );
if( err != paNoError ) goto error; if( err != paNoError ) goto error;
/* Watch until sound is halfway finished. */ for (int i = 0; i < 2; i++) {
printf("Play for %d seconds.\n", NUM_SECONDS/2 ); fflush(stdout); secondsPerLoop = NUM_SECONDS / NUM_LOOPS;
/* Watch until sound loop is finished. */
printf("Play for %3.1f seconds.\n", secondsPerLoop); fflush(stdout);
data.outTime = -1.0; /* mark time for callback as undefined */ data.outTime = -1.0; /* mark time for callback as undefined */
data.frameCount = 0;
err = Pa_StartStream( stream ); err = Pa_StartStream( stream );
if( err != paNoError ) goto error; if( err != paNoError ) goto error;
/* Record time at start so we can stop after a few seconds. */
startTime = Pa_GetStreamTime( stream ); startTime = Pa_GetStreamTime( stream );
maxFrameCount = SAMPLE_RATE * (secondsPerLoop + 2); /* Longer than expected. */
do do
{ {
ReportStreamTime( stream, &data ); ReportStreamTime( stream, &data );
Pa_Sleep(100); Pa_Sleep(100);
} while( (Pa_GetStreamTime( stream ) - startTime) < (NUM_SECONDS/2) ); /* Check the frameCount in case the StreamTime is dead. */
if ( data.frameCount > maxFrameCount ) {
fprintf( stderr, "Time not advancing fast enough!\n" );
err = paTimedOut;
goto error;
}
} while( (Pa_GetStreamTime( stream ) - startTime) < secondsPerLoop );
/* Stop sound for 2 seconds. */ /* Stop sound for 2 seconds. */
err = Pa_StopStream( stream ); err = Pa_StopStream( stream );
if( err != paNoError ) goto error; if( err != paNoError ) goto error;
if (i < (NUM_LOOPS - 1))
printf("Pause for 2 seconds.\n"); fflush(stdout); printf("Pause for 2 seconds.\n"); fflush(stdout);
Pa_Sleep( 2000 ); Pa_Sleep( 2000 );
}
data.outTime = -1.0; /* mark time for callback as undefined */
err = Pa_StartStream( stream );
if( err != paNoError ) goto error;
startTime = Pa_GetStreamTime( stream );
printf("Play until sound is finished.\n"); fflush(stdout);
do
{
ReportStreamTime( stream, &data );
Pa_Sleep(100);
} while( (Pa_GetStreamTime( stream ) - startTime) < (NUM_SECONDS/2) );
err = Pa_CloseStream( stream ); err = Pa_CloseStream( stream );
if( err != paNoError ) goto error; if( err != paNoError ) goto error;
Pa_Terminate(); Pa_Terminate();
printf("Test finished.\n"); printf("Test PASSED.\n");
return err; return 0;
error: error:
Pa_Terminate(); Pa_Terminate();
fprintf( stderr, "An error occurred while using the portaudio stream\n" ); fprintf( stderr, "An error occurred while using the portaudio stream\n" );
fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
return err; printf("Test FAILED.\n");
return 1;
} }