int g_testsPassed = 0;
int g_testsFailed = 0;
-#define MAX_NUM_GENERATORS (8)
-#define MAX_NUM_RECORDINGS (8)
-#define MAX_BACKGROUND_NOISE_RMS (0.0004)
+#define MAX_NUM_GENERATORS (8)
+#define MAX_NUM_RECORDINGS (8)
+#define MAX_BACKGROUND_NOISE_RMS (0.0004)
#define LOOPBACK_DETECTION_DURATION_SECONDS (0.8)
-#define DEFAULT_FRAMES_PER_BUFFER (64)
-#define PAQA_WAIT_STREAM_MSEC (100)
+#define DEFAULT_FRAMES_PER_BUFFER (128)
+#define DEFAULT_HIGH_LATENCY_MSEC (100)
+#define PAQA_WAIT_STREAM_MSEC (100)
// Use two separate streams instead of one full duplex stream.
#define PAQA_FLAG_TWO_STREAMS (1<<0)
int outputUnderflowCount;
int inputOverflowCount;
int outputOverflowCount;
+ int minFramesPerBuffer;
+ int maxFramesPerBuffer;
int primingCount;
TestParameters *test;
volatile int done;
if( statusFlags & paOutputUnderflow ) loopbackContext->outputUnderflowCount += 1;
if( statusFlags & paOutputOverflow ) loopbackContext->outputOverflowCount += 1;
if( statusFlags & paPrimingOutput ) loopbackContext->primingCount += 1;
-
+ if( framesPerBuffer > loopbackContext->maxFramesPerBuffer )
+ {
+ loopbackContext->maxFramesPerBuffer = framesPerBuffer;
+ }
+ if( framesPerBuffer < loopbackContext->minFramesPerBuffer )
+ {
+ loopbackContext->minFramesPerBuffer = framesPerBuffer;
+ }
+
/* This may get called with NULL inputBuffer during initial setup.
* We may also use the same callback with output only streams.
*/
// Wait for stream to finish.
while( loopbackContext->done == 0 )
{
- Pa_Sleep(50);
+ Pa_Sleep(PAQA_WAIT_STREAM_MSEC);
}
err = Pa_StopStream( inStream );
// Wait for stream to finish.
while( loopbackContext->done == 0 )
{
- Pa_Sleep(50);
+ Pa_Sleep(PAQA_WAIT_STREAM_MSEC);
}
err = Pa_StopStream( inStream );
PaQa_SetupSineGenerator( &loopbackContextPtr->generators[i], PaQa_GetNthFrequency( testParams->baseFrequency, i ),
testParams->amplitude, testParams->sampleRate );
}
+ loopbackContextPtr->minFramesPerBuffer = 0x0FFFFFFF;
return 0;
error:
return -1;
static void PaQa_TeardownLoopbackContext( LoopbackContext *loopbackContextPtr )
{
int i;
- for( i=0; i<loopbackContextPtr->test->samplesPerFrame; i++ )
+ if( loopbackContextPtr->test != NULL )
{
- PaQa_TerminateRecording( &loopbackContextPtr->recordings[i] );
- }
+ for( i=0; i<loopbackContextPtr->test->samplesPerFrame; i++ )
+ {
+ PaQa_TerminateRecording( &loopbackContextPtr->recordings[i] );
+ }
+ }
}
/*******************************************************************/
printf( "\n" );
+ // Sleep to see if this lets the audio drivers stabilize.
Pa_Sleep( 500 );
PaQa_TeardownLoopbackContext( &loopbackContext );
error:
PaQa_TeardownLoopbackContext( &loopbackContext );
printf( "\n" );
+ g_testsFailed += 1;
return err;
}
{
memset( testParamsPtr, 0, sizeof(TestParameters) );
-
testParamsPtr->samplesPerFrame = 2;
testParamsPtr->amplitude = 0.5;
testParamsPtr->sampleRate = 44100;
testParamsPtr->inputParameters.device = inputDevice;
testParamsPtr->inputParameters.sampleFormat = paFloat32;
testParamsPtr->inputParameters.channelCount = testParamsPtr->samplesPerFrame;
- testParamsPtr->inputParameters.suggestedLatency =
- Pa_GetDeviceInfo( inputDevice )->defaultLowInputLatency;
+ testParamsPtr->inputParameters.suggestedLatency = DEFAULT_HIGH_LATENCY_MSEC * 0.001;
testParamsPtr->outputParameters.device = outputDevice;
testParamsPtr->outputParameters.sampleFormat = paFloat32;
testParamsPtr->outputParameters.channelCount = testParamsPtr->samplesPerFrame;
- testParamsPtr->outputParameters.suggestedLatency =
- Pa_GetDeviceInfo( outputDevice )->defaultLowOutputLatency;
+ testParamsPtr->outputParameters.suggestedLatency = DEFAULT_HIGH_LATENCY_MSEC * 0.001;
+}
+
+/*******************************************************************/
+static void PaQa_OverrideTestParameters( TestParameters *testParamsPtr, UserOptions *userOptions )
+{
+ // Check to see if a specific value was requested.
+ if( userOptions->sampleRate >= 0 )
+ {
+ testParamsPtr->sampleRate = userOptions->sampleRate;
+ }
+ if( userOptions->framesPerBuffer >= 0 )
+ {
+ testParamsPtr->framesPerBuffer = userOptions->framesPerBuffer;
+ }
+ if( userOptions->latency >= 0 )
+ {
+ testParamsPtr->inputParameters.suggestedLatency = userOptions->latency * 0.001;
+ testParamsPtr->outputParameters.suggestedLatency = userOptions->latency * 0.001;
+ }
+ printf( " running with suggested latency (msec): input = %5.2f, out = %5.2f\n",
+ (testParamsPtr->inputParameters.suggestedLatency * 1000.0),
+ (testParamsPtr->outputParameters.suggestedLatency * 1000.0) );
}
/*******************************************************************/
int iSize;
int iFormat;
int totalBadChannels = 0;
+ int savedValue;
TestParameters testParams;
const PaDeviceInfo *inputDeviceInfo;
const PaDeviceInfo *outputDeviceInfo;
inputDeviceInfo = Pa_GetDeviceInfo( inputDevice );
outputDeviceInfo = Pa_GetDeviceInfo( outputDevice );
- double bestSampleRate = 44100.0;
- int bestBufferSize = DEFAULT_FRAMES_PER_BUFFER;
-
printf( "=============== Analysing Loopback %d to %d ====================\n", outputDevice, inputDevice );
printf( " Devices: %s => %s\n", outputDeviceInfo->name, inputDeviceInfo->name);
// test half duplex first because it is more likely to work.
int flagSettings[] = { PAQA_FLAG_TWO_STREAMS, 0 };
int numFlagSettings = (sizeof(flagSettings)/sizeof(int));
-
+
double sampleRates[] = { 8000.0, 11025.0, 16000.0, 22050.0, 32000.0, 44100.0, 48000.0, 96000.0 };
int numRates = (sizeof(sampleRates)/sizeof(double));
const char *sampleFormatNames[] = { "paUInt8", "paInt16", "paInt32" };
int numSampleFormats = (sizeof(sampleFormats)/sizeof(PaSampleFormat));
- // Check to see if a specific value was requested.
- if( userOptions->sampleRate > 0 )
- {
- sampleRates[0] = userOptions->sampleRate;
- bestSampleRate = userOptions->sampleRate;
- numRates = 1;
- }
- if( userOptions->framesPerBuffer > 0 )
- {
- framesPerBuffers[0] = userOptions->framesPerBuffer;
- bestBufferSize = userOptions->framesPerBuffer;
- numBufferSizes = 1;
- }
-
PaQa_SetDefaultTestParameters( &testParams, inputDevice, outputDevice );
- testParams.maxFrames = (int) (0.5 * testParams.sampleRate);
+
+ PaQa_OverrideTestParameters( &testParams, userOptions );
// Loop though combinations of audio parameters.
for( iFlags=0; iFlags<numFlagSettings; iFlags++ )
(( testParams.flags & 1 ) ? s_FlagOnNames[0] : s_FlagOffNames[0]) );
printf("|-sRate-|-buffer-|-latency-|-channel results--------------------|\n");
- // Loop though combinations of audio parameters.
- testParams.framesPerBuffer = bestBufferSize;
+ // Loop though various sample rates.
+ savedValue = testParams.sampleRate;
for( iRate=0; iRate<numRates; iRate++ )
{
// SAMPLE RATE
int numBadChannels = PaQa_SingleLoopBackTest( userOptions, &testParams );
totalBadChannels += numBadChannels;
}
+ testParams.sampleRate = savedValue;
+ testParams.maxFrames = (int) (1.2 * testParams.sampleRate);
printf( "\n" );
- testParams.sampleRate = bestSampleRate;
- testParams.maxFrames = (int) (1.2 * testParams.sampleRate);
+ // Loop through various buffer sizes.
+ savedValue = testParams.framesPerBuffer;
for( iSize=0; iSize<numBufferSizes; iSize++ )
{
// BUFFER SIZE
int numBadChannels = PaQa_SingleLoopBackTest( userOptions, &testParams );
totalBadChannels += numBadChannels;
}
+ testParams.framesPerBuffer = savedValue;
printf( "\n" );
}
printf("Test Sample Formats using Half Duplex IO -----\n" );
testParams.flags = PAQA_FLAG_TWO_STREAMS;
- testParams.sampleRate = bestSampleRate;
- testParams.framesPerBuffer = bestBufferSize;
for( iFormat=0; iFormat<numSampleFormats; iFormat++ )
{
*
* @return 1 if loopback connected, 0 if not, or negative error.
*/
-int PaQa_CheckForLoopBack( PaDeviceIndex inputDevice, PaDeviceIndex outputDevice )
+int PaQa_CheckForLoopBack( UserOptions *userOptions, PaDeviceIndex inputDevice, PaDeviceIndex outputDevice )
{
TestParameters testParams;
- LoopbackContext loopbackContext;
+ LoopbackContext loopbackContext = { 0 };
const PaDeviceInfo *inputDeviceInfo;
const PaDeviceInfo *outputDeviceInfo;
PaError err = paNoError;
double minAmplitude;
inputDeviceInfo = Pa_GetDeviceInfo( inputDevice );
+ QA_ASSERT_TRUE( "Pa_GetDeviceInfo for input returned NULL.", (inputDeviceInfo != NULL) );
if( inputDeviceInfo->maxInputChannels < 2 )
{
return 0;
}
outputDeviceInfo = Pa_GetDeviceInfo( outputDevice );
+ QA_ASSERT_TRUE( "Pa_GetDeviceInfo for output returned NULL.", (outputDeviceInfo != NULL) );
if( outputDeviceInfo->maxOutputChannels < 2 )
{
return 0;
printf( "Look for loopback cable between \"%s\" => \"%s\"\n", outputDeviceInfo->name, inputDeviceInfo->name);
+ printf( " default suggested input latency (msec): low = %5.2f, high = %5.2f\n",
+ (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) );
+
PaQa_SetDefaultTestParameters( &testParams, inputDevice, outputDevice );
+
+ PaQa_OverrideTestParameters( &testParams, userOptions );
+
testParams.maxFrames = (int) (LOOPBACK_DETECTION_DURATION_SECONDS * testParams.sampleRate);
minAmplitude = testParams.amplitude / 2.0;
{
printf( "Output not supported for this format!\n" );
return 0;
- }
+ }!
PaQa_SetupLoopbackContext( &loopbackContext, &testParams );
loopbackConnected = 0;
}
else if( rms > MAX_BACKGROUND_NOISE_RMS )
- { printf("ERROR - There is too much background noise on this input!\n");
+ {
+ printf("ERROR - There is too much background noise on this input!\n");
loopbackConnected = 0;
}
-
-
}
PaQa_TeardownLoopbackContext( &loopbackContext );
static int CheckLoopbackAndScan( UserOptions *userOptions,
PaDeviceIndex iIn, PaDeviceIndex iOut )
{
- int loopbackConnected = PaQa_CheckForLoopBack( iIn, iOut );
+ int loopbackConnected = PaQa_CheckForLoopBack( userOptions, iIn, iOut );
if( loopbackConnected > 0 )
{
PaQa_AnalyzeLoopbackConnection( userOptions, iIn, iOut );
else if (userOptions->outputDevice >= 0)
{
// Just scan for input.
+ QA_ASSERT_TRUE( "No good loopback cable found.", (numLoopbacks > 0) );
for( iIn=0; iIn<numDevices; iIn++ )
{
numLoopbacks += CheckLoopbackAndScan( userOptions, iIn, userOptions->outputDevice );
for( iOut=0; iOut<numDevices; iOut++ )
{
+ QA_ASSERT_TRUE( "No good loopback cable found.", (numLoopbacks > 0) );
for( iIn=0; iIn<numDevices; iIn++ )
{
numLoopbacks += CheckLoopbackAndScan( userOptions, iIn, iOut );
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(" -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");
memset(&userOptions, 0, sizeof(userOptions));
userOptions.inputDevice = paNoDevice;
userOptions.outputDevice = paNoDevice;
+ userOptions.sampleRate = -1;
+ userOptions.framesPerBuffer = -1;
+ userOptions.latency = -1;
userOptions.waveFilePath = ".";
// Process arguments. Skip name of executable.
break;
case 'm':
+ userOptions.framesPerBuffer = -1;
printf("Option -m set so just testing math and not the audio devices.\n");
justMath = 1;
break;