]> Repos - portaudio/commitdiff
Add test for paInt8 to loopback test.
authorphilburk <philburk@0f58301d-fd10-0410-b4af-bbb618454e57>
Thu, 3 Mar 2011 01:18:39 +0000 (01:18 +0000)
committerphilburk <philburk@0f58301d-fd10-0410-b4af-bbb618454e57>
Thu, 3 Mar 2011 01:18:39 +0000 (01:18 +0000)
Add separate input and output latency setting options.
Add timeout when waiting for stream to finish.

qa/loopback/src/paqa.c
qa/loopback/src/paqa_tools.c

index a4fac2820e5a1f31b0e425873e146fba9f10a63e..29f9f6ca0fc817df6dba3c822cee1a6fe7b8c3d8 100644 (file)
@@ -57,7 +57,6 @@ int g_testsFailed = 0;
 #define MAX_BACKGROUND_NOISE_RMS             (0.0004)
 #define LOOPBACK_DETECTION_DURATION_SECONDS  (0.8)
 #define DEFAULT_FRAMES_PER_BUFFER            (0)
-#define DEFAULT_HIGH_LATENCY_MSEC            (100)
 #define PAQA_WAIT_STREAM_MSEC                (100)
 #define PAQA_TEST_DURATION                   (1.2)
 
@@ -116,7 +115,8 @@ typedef struct UserOptions_s
 {
        int           sampleRate;
        int           framesPerBuffer;
-       int           latency;
+       int           inputLatency;
+       int           outputLatency;
        int           saveBadWaves;
        int           verbose;
        int           waveFileCount;
@@ -257,6 +257,33 @@ error:
        return err;     
 }
 
+/*******************************************************************/
+/** 
+ * Open two audio streams, one for input and one for output.
+ * Generate sine waves on the output channels and record the input channels.
+ * Then close the stream.
+ * @return 0 if OK or paTimedOut.
+ */
+
+int PaQa_WaitForStream( LoopbackContext *loopbackContext )
+{
+       int timeoutMSec = 1000 * PAQA_TEST_DURATION * 2;
+       
+       // Wait for stream to finish or timeout.
+       while( (loopbackContext->done == 0) && (timeoutMSec > 0) )
+       {
+               Pa_Sleep(PAQA_WAIT_STREAM_MSEC);
+               timeoutMSec -= PAQA_WAIT_STREAM_MSEC;
+       }
+       
+       if( loopbackContext->done == 0 )
+       {
+               printf("ERROR - stream completion timed out!");
+               return paTimedOut;
+       }
+       return 0;
+}
+
 /*******************************************************************/
 /** 
  * Open two audio streams, one for input and one for output.
@@ -269,6 +296,7 @@ int PaQa_RunLoopbackHalfDuplex( LoopbackContext *loopbackContext )
        PaStream *inStream = NULL;
        PaStream *outStream = NULL;
        PaError err = 0;
+       int timedOut = 0;
        TestParameters *test = loopbackContext->test;
        loopbackContext->done = 0;
        
@@ -301,11 +329,7 @@ int PaQa_RunLoopbackHalfDuplex( LoopbackContext *loopbackContext )
        err = Pa_StartStream( outStream );
        if( err != paNoError ) goto error;
        
-       // Wait for stream to finish.
-       while( loopbackContext->done == 0  )
-       {
-               Pa_Sleep(PAQA_WAIT_STREAM_MSEC);
-       }
+       timedOut = PaQa_WaitForStream( loopbackContext );
        
        err = Pa_StopStream( inStream );
        if( err != paNoError ) goto error;
@@ -319,7 +343,7 @@ int PaQa_RunLoopbackHalfDuplex( LoopbackContext *loopbackContext )
        err = Pa_CloseStream( outStream );
        if( err != paNoError ) goto error;
        
-       return 0;
+       return timedOut;
        
 error:
        return err;     
@@ -337,6 +361,7 @@ int PaQa_RunInputOnly( LoopbackContext *loopbackContext )
 {
        PaStream *inStream = NULL;
        PaError err = 0;
+       int timedOut = 0;
        TestParameters *test = loopbackContext->test;
        loopbackContext->done = 0;
        
@@ -355,11 +380,7 @@ int PaQa_RunInputOnly( LoopbackContext *loopbackContext )
        err = Pa_StartStream( inStream );
        if( err != paNoError ) goto error;
        
-       // Wait for stream to finish.
-       while( loopbackContext->done == 0 )
-       {
-               Pa_Sleep(PAQA_WAIT_STREAM_MSEC);
-       }
+       timedOut = PaQa_WaitForStream( loopbackContext );
        
        err = Pa_StopStream( inStream );
        if( err != paNoError ) goto error;
@@ -367,7 +388,7 @@ int PaQa_RunInputOnly( LoopbackContext *loopbackContext )
        err = Pa_CloseStream( inStream );
        if( err != paNoError ) goto error;
        
-       return 0;
+       return timedOut;
        
 error:
        return err;     
@@ -620,7 +641,7 @@ static int PaQa_SaveTestResultToWaveFile( UserOptions *userOptions, PaQaRecordin
        if( userOptions->saveBadWaves )
        {
                char filename[256];
-               snprintf( filename, sizeof(filename), "%s/test_%d.wav", userOptions->waveFilePath, userOptions->waveFileCount++ );
+               snprintf( filename, sizeof(filename), "%s/paloopback_%d.wav", userOptions->waveFilePath, userOptions->waveFileCount++ );
                printf( "\"%s\", ", filename );
                return PaQa_SaveRecordingToWaveFile( recording, filename );
        }
@@ -819,12 +840,12 @@ static void PaQa_SetDefaultTestParameters( TestParameters *testParamsPtr, PaDevi
        testParamsPtr->inputParameters.device = inputDevice;
        testParamsPtr->inputParameters.sampleFormat = paFloat32;
        testParamsPtr->inputParameters.channelCount = testParamsPtr->samplesPerFrame;
-       testParamsPtr->inputParameters.suggestedLatency = DEFAULT_HIGH_LATENCY_MSEC * 0.001;
+       testParamsPtr->inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputDevice )->defaultHighInputLatency;
        
        testParamsPtr->outputParameters.device = outputDevice;
        testParamsPtr->outputParameters.sampleFormat = paFloat32;
        testParamsPtr->outputParameters.channelCount = testParamsPtr->samplesPerFrame;
-       testParamsPtr->outputParameters.suggestedLatency = DEFAULT_HIGH_LATENCY_MSEC * 0.001;
+       testParamsPtr->outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputDevice )->defaultHighOutputLatency;
 }
 
 /*******************************************************************/
@@ -840,10 +861,13 @@ static void PaQa_OverrideTestParameters( TestParameters *testParamsPtr,  UserOpt
        {
                testParamsPtr->framesPerBuffer = userOptions->framesPerBuffer;
        }
-       if( userOptions->latency >= 0 )
+       if( userOptions->inputLatency >= 0 )
        {
-               testParamsPtr->inputParameters.suggestedLatency = userOptions->latency * 0.001;
-               testParamsPtr->outputParameters.suggestedLatency = userOptions->latency * 0.001;
+               testParamsPtr->inputParameters.suggestedLatency = userOptions->inputLatency * 0.001;
+       }
+       if( userOptions->outputLatency >= 0 )
+       {
+               testParamsPtr->outputParameters.suggestedLatency = userOptions->outputLatency * 0.001;
        }
        printf( "    running with suggested latency (msec): input = %5.2f, out = %5.2f\n",
                (testParamsPtr->inputParameters.suggestedLatency * 1000.0),
@@ -879,11 +903,12 @@ static int PaQa_AnalyzeLoopbackConnection( UserOptions *userOptions, PaDeviceInd
        double sampleRates[] = { 8000.0, 11025.0, 16000.0, 22050.0, 32000.0, 44100.0, 48000.0, 96000.0 };
        int numRates = (sizeof(sampleRates)/sizeof(double));
        
-       int framesPerBuffers[] = { 16, 32, 40, 64, 100, 128, 256, 512, 1024 };
+       // framesPerBuffer==0 means PA decides on the buffer size.
+       int framesPerBuffers[] = { 0, 16, 32, 40, 64, 100, 128, 256, 512, 1024 };
        int numBufferSizes = (sizeof(framesPerBuffers)/sizeof(int));
        
-       PaSampleFormat sampleFormats[] = { paUInt8, paInt16, paInt32 };
-       const char *sampleFormatNames[] = { "paUInt8", "paInt16", "paInt32" };
+       PaSampleFormat sampleFormats[] = { paUInt8, paInt8, paInt16, paInt32 };
+       const char *sampleFormatNames[] = { "paUInt8", "paInt8", "paInt16", "paInt32" };
        int numSampleFormats = (sizeof(sampleFormats)/sizeof(PaSampleFormat));
        
        PaQa_SetDefaultTestParameters( &testParams, inputDevice, outputDevice );
@@ -899,7 +924,7 @@ static int PaQa_AnalyzeLoopbackConnection( UserOptions *userOptions, PaDeviceInd
                printf( "\n************ Mode = %s ************\n",
                           (( testParams.flags & 1 ) ? s_FlagOnNames[0] : s_FlagOffNames[0]) );
                printf("|-   requested  -|- measured ----------------------------------------------->\n");
-               printf("|-sRate-|-fr/buf-|- frm/buf -|-latency-|-channel results--------------------|\n");
+               printf("|-sRate-|-fr/buf-|- frm/buf -|-latency-|-channel results-------------------->\n");
 
                // Loop though various sample rates.
                if( userOptions->sampleRate < 0 )
@@ -957,6 +982,7 @@ static int PaQa_AnalyzeLoopbackConnection( UserOptions *userOptions, PaDeviceInd
                totalBadChannels += numBadChannels;                     
        }
        printf( "\n" );
+       printf( "****************************************\n");
        
        return totalBadChannels;
 }
@@ -1053,8 +1079,8 @@ int PaQa_CheckForLoopBack( UserOptions *userOptions, PaDeviceIndex inputDevice,
                (inputDeviceInfo->defaultLowInputLatency * 1000.0),
                (inputDeviceInfo->defaultHighInputLatency * 1000.0) );
        printf( "    default suggested output latency (msec): low = %5.2f, high = %5.2f\n",
-               (outputDeviceInfo->defaultLowInputLatency * 1000.0),
-               (outputDeviceInfo->defaultHighInputLatency * 1000.0) );
+               (outputDeviceInfo->defaultLowOutputLatency * 1000.0),
+               (outputDeviceInfo->defaultHighOutputLatency * 1000.0) );
                
        PaQa_SetDefaultTestParameters( &testParams, inputDevice, outputDevice );
        
@@ -1218,7 +1244,8 @@ int TestSampleFormatConversion( void )
 {
        int i;
        const float floatInput[] = { 1.0, 0.5, -0.5, -1.0 };
-
+       
+       const char charInput[] = { 127, 64, -64, -128 };
        const unsigned char ucharInput[] = { 255, 128+64, 64, 0 };
        const short shortInput[] = { 32767, 32768/2, -32768/2, -32768 };
        const int intInput[] = { 2147483647, 2147483647/2, -2147483648/2, -2147483648 };
@@ -1227,6 +1254,7 @@ int TestSampleFormatConversion( void )
        short shortOutput[4];
        int intOutput[4];       
        unsigned char ucharOutput[4];
+       char charOutput[4];
        
        QA_ASSERT_EQUALS("int must be 32-bit", 4, (int) sizeof(int) );
        QA_ASSERT_EQUALS("short must be 16-bit", 2, (int) sizeof(short) );
@@ -1235,7 +1263,13 @@ int TestSampleFormatConversion( void )
        PaQa_ConvertFromFloat( floatInput, 4, paUInt8, ucharOutput );
        for( i=0; i<4; i++ )
        {
-               QA_ASSERT_CLOSE( "paFloat32 -> paUint8 -> error", ucharInput[i], ucharOutput[i], 1 );
+               QA_ASSERT_CLOSE( "paFloat32 -> paUInt8 -> error", ucharInput[i], ucharOutput[i], 1 );
+       }
+       
+       PaQa_ConvertFromFloat( floatInput, 4, paInt8, charOutput );
+       for( i=0; i<4; i++ )
+       {
+               QA_ASSERT_CLOSE( "paFloat32 -> paInt8 -> error", charInput[i], charOutput[i], 1 );
        }
        
        PaQa_ConvertFromFloat( floatInput, 4, paInt16, shortOutput );
@@ -1259,6 +1293,13 @@ int TestSampleFormatConversion( void )
                QA_ASSERT_CLOSE( "paUInt8 -> paFloat32 error", floatInput[i], floatOutput[i], 0.01 );
        }
        
+       memset( floatOutput, 0, sizeof(floatOutput) );
+       PaQa_ConvertToFloat( charInput, 4, paInt8, floatOutput );
+       for( i=0; i<4; i++ )
+       {
+               QA_ASSERT_CLOSE( "paInt8 -> paFloat32 error", floatInput[i], floatOutput[i], 0.01 );
+       }
+       
        memset( floatOutput, 0, sizeof(floatOutput) );
        PaQa_ConvertToFloat( shortInput, 4, paInt16, floatOutput );
        for( i=0; i<4; i++ )
@@ -1284,15 +1325,17 @@ error:
 void usage( const char *name )
 {
        printf("%s [-i# -o# -l# -r# -s# -m -w -dDir]\n", name);
-       printf("  -i# Input device ID. Will scan for loopback cable if not specified.\n");
-       printf("  -o# Output device ID. Will scan for loopback if not specified.\n");
-       printf("  -l# Latency in milliseconds.\n");
-       printf("  -r# Sample Rate in Hz.  Will use multiple common rates if not specified.\n");
-       printf("  -s# Size of callback buffer in frames, framesPerBuffer. Will use common values if not specified.\n");
-       printf("  -w  Save bad recordings in a WAV file.\n");
-       printf("  -dDir  Path for Directory for WAV files. Default is current directory.\n");
-       printf("  -m  Just test the DSP Math code and not the audio devices.\n");
-       printf("  -v  Verbose reports.\n");
+       printf("  -i# - Input device ID. Will scan for loopback cable if not specified.\n");
+       printf("  -o# - Output device ID. Will scan for loopback if not specified.\n");
+       printf("  -l# - Latency for both input and output in milliseconds.\n");
+       printf("  --inputLatency # Input latency in milliseconds.\n");  
+       printf("  --outputLatency # Output latency in milliseconds.\n");
+       printf("  -r# - Sample Rate in Hz.  Will use multiple common rates if not specified.\n");
+       printf("  -s# - Size of callback buffer in frames, framesPerBuffer. Will use common values if not specified.\n");
+       printf("  -w  - Save bad recordings in a WAV file.\n");
+       printf("  -dDir - Path for Directory for WAV files. Default is current directory.\n");
+       printf("  -m  - Just test the DSP Math code and not the audio devices.\n");
+       printf("  -v  - Verbose reports.\n");
 }
 
 /*******************************************************************/
@@ -1309,12 +1352,14 @@ int main( int argc, char **argv )
        userOptions.outputDevice = paNoDevice;
        userOptions.sampleRate = -1;
        userOptions.framesPerBuffer = -1;
-       userOptions.latency = -1;
+       userOptions.inputLatency = -1;
+       userOptions.outputLatency = -1;
        userOptions.waveFilePath = ".";
        
        // Process arguments. Skip name of executable.
        char *name = argv[0];
-       for( i=1; i<argc; i++ )
+       i = 1;
+       while( i<argc )
        {
                char *arg = argv[i];
                if( arg[0] == '-' )
@@ -1328,7 +1373,7 @@ int main( int argc, char **argv )
                                        userOptions.outputDevice = atoi(&arg[2]);
                                        break;
                                case 'l':
-                                       userOptions.latency = atoi(&arg[2]);
+                                       userOptions.inputLatency = userOptions.outputLatency = atoi(&arg[2]);
                                        break;
                                case 'r':
                                        userOptions.sampleRate = atoi(&arg[2]);
@@ -1355,11 +1400,36 @@ int main( int argc, char **argv )
                                        
                                case 'h':
                                        usage( name );
-                                       return(0);
+                                       exit(0);
+                                       break;
+                                       
+                               case '-':
+                               {
+                                       if( strcmp( &arg[2], "inputLatency" ) == 0 )
+                                       {
+                                               i += 1;
+                                               userOptions.inputLatency = atoi(argv[i]);
+                                       }
+                                       else if( strcmp( &arg[2], "outputLatency" ) == 0 )
+                                       {
+                                               i += 1;
+                                               userOptions.outputLatency = atoi(argv[i]);                                      
+                                       }
+                                       else
+                                       {
+                                               printf("Illegal option: %s\n", arg);
+                                               usage( name );
+                                               exit(1);
+                                       }
+
+                               }
                                        break;
+                                       
+                                       
                                default:
                                        printf("Illegal option: %s\n", arg);
                                        usage( name );
+                                       exit(1);
                                        break;
                        }
                }
@@ -1367,7 +1437,10 @@ int main( int argc, char **argv )
                {
                        printf("Illegal argument: %s\n", arg);
                        usage( name );
+                       exit(1);
+
                }
+               i += 1;
        }
                
        result = PaQa_TestAnalyzer();
index 2dc80a5997717321cad6cecd2189516c13abd5af..36703a976d89802fee59eb0d0718e5a44a697932 100644 (file)
@@ -74,6 +74,17 @@ void PaQa_ConvertToFloat( const void *input, int numSamples, PaSampleFormat inFo
                }
                        break;
                        
+               case paInt8:
+               {
+                       char *data = (char *)input;
+                       for( i=0; i<numSamples; i++ )
+                       {
+                               int value = *data++;
+                               *output++ = value / 128.0f;
+                       }
+               }
+                       break;
+                       
                case paInt16:
                {
                        short *data = (short *)input;
@@ -118,6 +129,18 @@ void PaQa_ConvertFromFloat( const float *input, int numSamples, PaSampleFormat o
                }
                        break;
                        
+               case paInt8:
+               {
+                       char *data = (char *)output;
+                       for( i=0; i<numSamples; i++ )
+                       {
+                               float value = *input++;
+                               int byte = (int) (value * 127);
+                               *data++ = (char) byte;
+                       }
+               }
+                       break;
+                       
                case paInt16:
                {
                        short *data = (short *)output;