diff options
Diffstat (limited to '3rdparty/portaudio/qa/paqa_devs.c')
-rw-r--r-- | 3rdparty/portaudio/qa/paqa_devs.c | 902 |
1 files changed, 687 insertions, 215 deletions
diff --git a/3rdparty/portaudio/qa/paqa_devs.c b/3rdparty/portaudio/qa/paqa_devs.c index 721b07f14fc..1a70e842d89 100644 --- a/3rdparty/portaudio/qa/paqa_devs.c +++ b/3rdparty/portaudio/qa/paqa_devs.c @@ -1,15 +1,16 @@ /** @file paqa_devs.c - @ingroup qa_src + @ingroup qa_src @brief Self Testing Quality Assurance app for PortAudio - Try to open each device and run through all the - possible configurations. This test does not verify - that the configuration works well. It just verifies - that it does not crash. It requires a human to listen to - the outputs. - - @author Phil Burk http://www.softsynth.com - - Pieter adapted to V19 API. Test now relies heavily on + Try to open devices and run through all possible configurations. + By default, open only the default devices. Command line options support + opening every device, or all input devices, or all output devices. + This test does not verify that the configuration works well. + It just verifies that it does not crash. It requires a human to + listen to the sine wave outputs. + + @author Phil Burk http://www.softsynth.com + + Pieter adapted to V19 API. Test now relies heavily on Pa_IsFormatSupported(). Uses same 'standard' sample rates as in test pa_devs.c. */ @@ -41,104 +42,215 @@ */ /* - * The text above constitutes the entire PortAudio license; however, + * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the * license above. */ +#include <stdint.h> #include <stdio.h> +#include <stdlib.h> /* for EXIT_SUCCESS and EXIT_FAILURE */ +#include <string.h> +#define _USE_MATH_DEFINES #include <math.h> #include "portaudio.h" #include "pa_trace.h" +#include "paqa_macros.h" /****************************************** Definitions ***********/ -#define MODE_INPUT (0) -#define MODE_OUTPUT (1) -#define MAX_TEST_CHANNELS 4 +#define RUN_TIME_SECONDS (1.2) +#define BYPASS_TESTS (0) /* If 1 then skip actual tests and just iterate. */ + +#define MODE_INPUT (0) +#define MODE_OUTPUT (1) +#define MAX_TEST_CHANNELS (4) +#define LOWEST_FREQUENCY (300.0) +#define SINE_AMPLITUDE (0.2) +#define MILLIS_PER_SECOND (1000.0) +#define DEFAULT_FRAMES_PER_BUFFER (128) + +#define TEST_LEVEL_QUICK (0) +#define TEST_LEVEL_NORMAL (1) +#define TEST_LEVEL_EXHAUSTIVE (2) + +PAQA_INSTANTIATE_GLOBALS + +typedef struct PaSineOscillator +{ + float phase; + float phaseIncrement; +} PaSineOscillator; +/* Parameters that cover all options for a test. + */ +typedef struct PaQaTestParameters +{ + PaDeviceIndex deviceID; + PaSampleFormat format; + double sampleRate; + double durationSeconds; + double suggestedLatency; + int framesPerBuffer; + int numInputChannels; + int numOutputChannels; + int mode; + int useCallback; + int useNonInterleaved; /* Test paNonInterleaved flag */ +} PaQaTestParameters; + +PaQaTestParameters kDefaultTestParameters = { + 0, /* deviceId */ + paFloat32, + 44100, + RUN_TIME_SECONDS, + 0.020, + DEFAULT_FRAMES_PER_BUFFER, + 0, /* numInputChannels */ + 1, /* numOutputChannels */ + MODE_OUTPUT, + 1, /* useCallback */ + 0, /* useNonInterleaved */ +}; + +/* Runtime data used during the test. */ typedef struct PaQaData { - unsigned long framesLeft; - int numChannels; - int bytesPerSample; - int mode; - short sawPhase; - PaSampleFormat format; -} -PaQaData; + const PaQaTestParameters *parameters; + // Dynamic state. + int bytesPerSample; + volatile unsigned long frameCounter; + volatile unsigned long framesLeft; + unsigned long framesPerBurst; + unsigned long minFramesPerBuffer; + unsigned long maxFramesPerBuffer; + unsigned long framesDuration; + PaSineOscillator sineOscillators[MAX_TEST_CHANNELS]; + void *audioBuffer; +} PaQaData; /****************************************** Prototypes ***********/ -static void TestDevices( int mode ); -static void TestFormats( int mode, PaDeviceIndex deviceID, double sampleRate, - int numChannels ); -static int TestAdvance( int mode, PaDeviceIndex deviceID, double sampleRate, - int numChannels, PaSampleFormat format ); +static int TestSingleStreamParameters(PaQaTestParameters parameters); static int QaCallback( const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData ); -/****************************************** Globals ***********/ -static int gNumPassed = 0; -static int gNumFailed = 0; - -/****************************************** Macros ***********/ -/* Print ERROR if it fails. Tally success or failure. */ -/* Odd do-while wrapper seems to be needed for some compilers. */ -#define EXPECT(_exp) \ - do \ - { \ - if ((_exp)) {\ - /* printf("SUCCESS for %s\n", #_exp ); */ \ - gNumPassed++; \ - } \ - else { \ - printf("ERROR - 0x%x - %s for %s\n", result, \ - ((result == 0) ? "-" : Pa_GetErrorText(result)), \ - #_exp ); \ - gNumFailed++; \ - goto error; \ - } \ - } while(0) +static void PaQaSetupData(PaQaData *myData, + const PaQaTestParameters *parameters) +{ + memset(myData, 0, sizeof(PaQaData)); + + myData->parameters = parameters; + myData->frameCounter = 0; + myData->framesLeft = (unsigned long) (parameters->sampleRate * parameters->durationSeconds); + + myData->minFramesPerBuffer = UINT32_MAX; + myData->maxFramesPerBuffer = 0; + + for (int channelIndex = 0; channelIndex < MAX_TEST_CHANNELS; channelIndex++) + { + myData->sineOscillators[channelIndex].phase = 0.0f; + myData->sineOscillators[channelIndex].phaseIncrement = + (2.0 * M_PI * LOWEST_FREQUENCY / parameters->sampleRate); + } + + switch( parameters->format ) + { + case paFloat32: + case paInt32: + case paInt24: + myData->bytesPerSample = 4; + break; + /* case paPackedInt24: + myData->bytesPerSample = 3; + break; */ + default: + myData->bytesPerSample = 2; + break; + } + myData->framesPerBurst = (parameters->framesPerBuffer == 0) ? 128 : parameters->framesPerBuffer; + if (parameters->useCallback == 0) { + /* We need our own buffer for blocking IO. */ + int numChannels = (parameters->mode == MODE_OUTPUT) + ? parameters->numOutputChannels + : parameters->numInputChannels; + myData->audioBuffer = malloc(myData->bytesPerSample * numChannels * myData->framesPerBurst); + } +} + +static void PaQaTeardownData(PaQaData *myData, + const PaQaTestParameters *parameters) +{ + (void) parameters; + free(myData->audioBuffer); +} + +static float NextSineSample( PaSineOscillator *sineOscillator ) +{ + float phase = sineOscillator->phase + sineOscillator->phaseIncrement; + if( phase > (float)M_PI ) phase -= (float)(2.0 * M_PI); + sineOscillator->phase = phase; + return sinf(phase) * SINE_AMPLITUDE; +} + +#define SETUP_BUFFERS(_data_type) \ + _data_type *out; \ + int stride; \ + if (parameters->useNonInterleaved) { \ + /* outputData points to an array of pointers to the buffers. */ \ + void **buffers = (void **)outputData; \ + out = (_data_type *)buffers[channelIndex]; \ + stride = 1; \ + } else { \ + out = &((_data_type *) outputData)[channelIndex]; \ + stride = parameters->numOutputChannels; \ + } /*******************************************************************/ /* This routine will be called by the PortAudio engine when audio is needed. ** It may be called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ -static int QaCallback( const void *inputBuffer, void *outputBuffer, +static int QaCallback( const void *inputData, + void *outputData, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData ) { - unsigned long i; - short phase; + unsigned long frameIndex; + int channelIndex; + float sample; PaQaData *data = (PaQaData *) userData; - (void) inputBuffer; + const PaQaTestParameters *parameters = data->parameters; + (void) inputData; + + data->minFramesPerBuffer = (framesPerBuffer < data->minFramesPerBuffer) + ? framesPerBuffer : data->minFramesPerBuffer; + data->maxFramesPerBuffer = (framesPerBuffer > data->maxFramesPerBuffer) + ? framesPerBuffer : data->maxFramesPerBuffer; - /* Play simple sawtooth wave. */ - if( data->mode == MODE_OUTPUT ) + /* Play simple sine wave. */ + if( parameters->mode == MODE_OUTPUT ) { - phase = data->sawPhase; - switch( data->format ) + switch( parameters->format ) { case paFloat32: { - float *out = (float *) outputBuffer; - for( i=0; i<framesPerBuffer; i++ ) + for( channelIndex = 0; channelIndex < parameters->numOutputChannels; channelIndex++ ) { - phase += 0x123; - *out++ = (float) (phase * (1.0 / 32768.0)); - if( data->numChannels == 2 ) + SETUP_BUFFERS(float); + for( frameIndex = 0; frameIndex < framesPerBuffer; frameIndex++ ) { - *out++ = (float) (phase * (1.0 / 32768.0)); + sample = NextSineSample( &data->sineOscillators[channelIndex] ); + *out = sample; + out += stride; } } } @@ -146,29 +258,29 @@ static int QaCallback( const void *inputBuffer, void *outputBuffer, case paInt32: { - int *out = (int *) outputBuffer; - for( i=0; i<framesPerBuffer; i++ ) + for( channelIndex = 0; channelIndex < parameters->numOutputChannels; channelIndex++ ) { - phase += 0x123; - *out++ = ((int) phase ) << 16; - if( data->numChannels == 2 ) + SETUP_BUFFERS(int32_t); + for( frameIndex = 0; frameIndex < framesPerBuffer; frameIndex++ ) { - *out++ = ((int) phase ) << 16; + sample = NextSineSample( &data->sineOscillators[channelIndex] ); + *out = ((int32_t)(sample * 8388607)) << 8; + out += stride; } } } break; - + case paInt16: { - short *out = (short *) outputBuffer; - for( i=0; i<framesPerBuffer; i++ ) + for( channelIndex = 0; channelIndex < parameters->numOutputChannels; channelIndex++ ) { - phase += 0x123; - *out++ = phase; - if( data->numChannels == 2 ) + SETUP_BUFFERS(int16_t); + for( frameIndex = 0; frameIndex < framesPerBuffer; frameIndex++ ) { - *out++ = phase; + sample = NextSineSample( &data->sineOscillators[channelIndex] ); + *out = (int16_t)(sample * 32767); + out += stride; } } } @@ -176,196 +288,556 @@ static int QaCallback( const void *inputBuffer, void *outputBuffer, default: { - unsigned char *out = (unsigned char *) outputBuffer; - unsigned long numBytes = framesPerBuffer * data->numChannels * data->bytesPerSample; - for( i=0; i<numBytes; i++ ) - { - *out++ = 0; - } + unsigned char *out = (unsigned char *) outputData; + unsigned long numBytes = framesPerBuffer * parameters->numOutputChannels * data->bytesPerSample; + memset(out, 0, numBytes); } break; } - data->sawPhase = phase; } + + data->frameCounter += framesPerBuffer; + /* Are we through yet? */ if( data->framesLeft > framesPerBuffer ) { PaUtil_AddTraceMessage("QaCallback: running. framesLeft", data->framesLeft ); data->framesLeft -= framesPerBuffer; - return 0; + return paContinue; } else { PaUtil_AddTraceMessage("QaCallback: DONE! framesLeft", data->framesLeft ); data->framesLeft = 0; - return 1; + return paComplete; + } +} + +static PaError CheckBlockingIO(PaStream *stream, + PaQaData *data, + int millis) { + PaError result = paNoError; + double elapsedTime = 0.0; + double millisPerBurst = MILLIS_PER_SECOND * data->framesPerBurst / data->parameters->sampleRate; + while (elapsedTime < millis) { + int callbackResult; + if (data->parameters->mode == MODE_OUTPUT) { + callbackResult = QaCallback(NULL /*inputBuffer */, + data->audioBuffer, + data->framesPerBurst, + NULL /* timeInfo */, // TODO + 0, // stream flags + data); + if (callbackResult == 0) { + result = Pa_WriteStream(stream, data->audioBuffer, data->framesPerBurst); + ASSERT_EQ(paNoError, result); + } + } else if (data->parameters->mode == MODE_INPUT) { + result = Pa_ReadStream(stream, data->audioBuffer, data->framesPerBurst); + ASSERT_EQ(paNoError, result); + callbackResult = QaCallback(data->audioBuffer, + NULL /*outputBuffer */, + data->framesPerBurst, + NULL /* timeInfo */, // TODO + 0, // stream flags + data); + } + elapsedTime += millisPerBurst; } +error: + return result; +} + +static void CheckDefaultCallbackRun(PaStream *stream, + PaQaData *data) { + PaError result = paNoError; + PaTime oldStreamTimeMillis = 0.0; + PaTime startStreamTimeMillis = 0.0; + unsigned long oldFramesLeft = INT32_MAX; + + oldStreamTimeMillis = Pa_GetStreamTime(stream) * MILLIS_PER_SECOND; + + ASSERT_EQ(0, Pa_IsStreamActive(stream)); + ASSERT_EQ(1, Pa_IsStreamStopped(stream)); + + ASSERT_EQ(paNoError, result = Pa_StartStream( stream )); + startStreamTimeMillis = Pa_GetStreamTime(stream) * MILLIS_PER_SECOND; + + ASSERT_EQ(1, Pa_IsStreamActive(stream)); + ASSERT_EQ(0, Pa_IsStreamStopped(stream)); + + /* Sleep long enough for the stream callback to have stopped itself. */ + while ((oldStreamTimeMillis - startStreamTimeMillis) < ((RUN_TIME_SECONDS + 0.5) * MILLIS_PER_SECOND) + && (data->framesLeft > 0)) + { + if (data->parameters->useCallback) { + Pa_Sleep(200); + } else { + result = CheckBlockingIO(stream, + data, + 200); + ASSERT_EQ(paNoError, result); + } + + PaTime newStreamTime = Pa_GetStreamTime(stream) * MILLIS_PER_SECOND; + //printf("oldStreamTime = %9.6f, newStreamTime = %9.6f\n", oldStreamTime, newStreamTime ); /**/ + ASSERT_LE(oldStreamTimeMillis, newStreamTime); + + /* Check to make sure callback is decrementing framesLeft. */ + unsigned long newFramesLeft = data->framesLeft; + //printf("oldFrames = %lu, newFrames = %lu\n", oldFramesLeft, newFramesLeft ); + ASSERT_GE(oldFramesLeft, newFramesLeft); + + oldStreamTimeMillis = newStreamTime; + oldFramesLeft = newFramesLeft; + } + + ASSERT_EQ(0, data->framesLeft); + ASSERT_LE((1 * data->parameters->sampleRate), data->frameCounter); + + if (data->parameters->framesPerBuffer > 0) { + ASSERT_EQ(data->parameters->framesPerBuffer, data->minFramesPerBuffer); + ASSERT_EQ(data->parameters->framesPerBuffer, data->maxFramesPerBuffer); + } else { + ASSERT_GT(data->minFramesPerBuffer, 0); + ASSERT_LT(data->maxFramesPerBuffer, data->parameters->sampleRate); + } + + ASSERT_EQ(data->parameters->useCallback ? 0 : 1, Pa_IsStreamActive(stream)); + ASSERT_EQ(0, Pa_IsStreamStopped(stream)); + + ASSERT_EQ(paNoError, result = Pa_StopStream( stream )); + + ASSERT_EQ(0, Pa_IsStreamActive(stream)); + ASSERT_EQ(1, Pa_IsStreamStopped(stream)); + + ASSERT_EQ(paNoError, result = Pa_CloseStream( stream )); + return; + +error: + printf("result = %d = for %s\n", result, Pa_GetErrorText(result)); + Pa_CloseStream(stream); + return; } /*******************************************************************/ -int main(void); -int main(void) +static int TestSingleStreamParameters(PaQaTestParameters testParameters) { - PaError result; - EXPECT( ((result=Pa_Initialize()) == 0) ); - printf("Test OUTPUT ---------------\n"); - TestDevices( MODE_OUTPUT ); - printf("Test INPUT ---------------\n"); - TestDevices( MODE_INPUT ); + PaStreamParameters inputParameters, outputParameters, *ipp, *opp; + PaStream *stream = NULL; + PaQaData myData; + int numChannels = 0; + + if( testParameters.mode == MODE_INPUT ) + { + opp = NULL; + numChannels = testParameters.numInputChannels; + inputParameters.device = testParameters.deviceID; + inputParameters.channelCount = testParameters.numInputChannels; + inputParameters.sampleFormat = testParameters.format + | (testParameters.useNonInterleaved ? paNonInterleaved : 0); + inputParameters.suggestedLatency = testParameters.suggestedLatency; + inputParameters.hostApiSpecificStreamInfo = NULL; + ipp = &inputParameters; + } + else if( testParameters.mode == MODE_OUTPUT ) + { + ipp = NULL; + numChannels = testParameters.numOutputChannels; + outputParameters.device = testParameters.deviceID; + outputParameters.channelCount = testParameters.numOutputChannels; + outputParameters.sampleFormat = testParameters.format + | (testParameters.useNonInterleaved ? paNonInterleaved : 0); + outputParameters.suggestedLatency = testParameters.suggestedLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + opp = &outputParameters; + } + + printf("------ Test: %s, device = %d" + ", #ch = %d" + ", rate = %5g" + ", format = %lu" + ", %s, %s\n", + ( testParameters.mode == MODE_INPUT ) ? "INPUT" : "OUTPUT", + testParameters.deviceID, + numChannels, + testParameters.sampleRate, + (unsigned long)testParameters.format, + testParameters.useCallback ? "CALLBACK" : "BLOCKING", + testParameters.useNonInterleaved ? "NON-INT" : "INTER" + ); + + if (BYPASS_TESTS) return 0; + + /* Setup data for callback thread. */ + PaQaSetupData(&myData, &testParameters); + + if(paFormatIsSupported == Pa_IsFormatSupported( ipp, opp, testParameters.sampleRate )) + { + PaError resultOpen = Pa_OpenStream( &stream, + ipp, + opp, + testParameters.sampleRate, + testParameters.framesPerBuffer, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + testParameters.useCallback ? QaCallback : NULL, + &myData + ); + + if (resultOpen != paNoError) { + printf("Pa_OpenStream() returned = %d = for %s\n", + resultOpen, Pa_GetErrorText(resultOpen)); + } + ASSERT_EQ(paNoError, resultOpen); + ASSERT_TRUE(stream != NULL); + + { + const PaStreamInfo *streamInfo = Pa_GetStreamInfo(stream); + ASSERT_EQ((int)(testParameters.sampleRate), (int)(streamInfo->sampleRate)); + if (testParameters.mode == MODE_INPUT) { + ASSERT_EQ(0, (int)(streamInfo->outputLatency * 1000)); + } else { + ASSERT_EQ(0, (int)(streamInfo->inputLatency * 1000)); + } + } + CheckDefaultCallbackRun(stream, &myData); + + } else { + printf(" Parameters NOT supported.\n"); + } + PaQaTeardownData(&myData, &testParameters); + return 0; + error: - Pa_Terminate(); - printf("QA Report: %d passed, %d failed.\n", gNumPassed, gNumFailed ); - return (gNumFailed > 0) ? 1 : 0; + if( stream != NULL ) Pa_CloseStream( stream ); + PaQaTeardownData(&myData, &testParameters); + return -1; +} + + +static void RunQuickTest() +{ + PaQaTestParameters parameters = kDefaultTestParameters; + +#if 1 + printf("\n=========== INPUT ==============\n"); + parameters.mode = MODE_INPUT; + parameters.deviceID = Pa_GetDefaultInputDevice(); + parameters.format = paFloat32; + + parameters.sampleRate = 44100; + parameters.numInputChannels = 1; + TestSingleStreamParameters(parameters); + parameters.sampleRate = 22050; + TestSingleStreamParameters(parameters); + + parameters.sampleRate = 44100; + parameters.numInputChannels = 2; + TestSingleStreamParameters(parameters); + + parameters.useCallback = 0; + TestSingleStreamParameters(parameters); /* Blocking */ + parameters.useNonInterleaved = 1; + TestSingleStreamParameters(parameters); /* Blocking, NonInterleaved */ + parameters.useCallback = 1; + TestSingleStreamParameters(parameters); /* NonInterleaved */ + parameters.useCallback = 1; +#endif + + printf("\n=========== OUTPUT =============\n"); + parameters = kDefaultTestParameters; + parameters.mode = MODE_OUTPUT; + parameters.deviceID = Pa_GetDefaultOutputDevice(); + parameters.sampleRate = 48000; + parameters.numOutputChannels = 1; + parameters.format = paFloat32; + parameters.useCallback = 0; + TestSingleStreamParameters(parameters); + + /* Interleaved */ + parameters = kDefaultTestParameters; + parameters.deviceID = Pa_GetDefaultOutputDevice(); + parameters.useNonInterleaved = 0; + parameters.numOutputChannels = 1; + parameters.useCallback = 1; + parameters.format = paFloat32; + TestSingleStreamParameters(parameters); + parameters.useCallback = 0; + parameters.format = paFloat32; + TestSingleStreamParameters(parameters); /* Blocking */ + parameters.useCallback = 1; + + parameters.sampleRate = 44100; + parameters.numOutputChannels = 2; + parameters.format = paFloat32; + TestSingleStreamParameters(parameters); + + parameters.sampleRate = 22050; + parameters.numOutputChannels = 2; + parameters.format = paInt16; + TestSingleStreamParameters(parameters); + + /* Non-Interleaved */ + parameters = kDefaultTestParameters; + parameters.deviceID = Pa_GetDefaultOutputDevice(); + parameters.useNonInterleaved = 1; + parameters.numOutputChannels = 2; + parameters.format = paFloat32; + parameters.useCallback = 0; + TestSingleStreamParameters(parameters); /* Blocking */ + parameters.useCallback = 1; + TestSingleStreamParameters(parameters); /* Blocking */ + parameters.format = paInt16; + TestSingleStreamParameters(parameters); + parameters.format = paInt32; + TestSingleStreamParameters(parameters); +} + +static const double constStandardSampleRates_[] = { + 8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, + 24000.0, 32000.0, 44100.0, 48000.0, 88200.0, 96000.0, + -1.0 }; /* Negative terminated list. */ + +static const PaSampleFormat constFormatsToTest_[] = { + paFloat32, paInt32, paInt16, 0 +}; /* Zero terminated list. */ + +/** + * Iterate through each option with other options set to default. + */ +static void TestNormal( int mode, int allDevices ) +{ + PaQaTestParameters parameters = kDefaultTestParameters; + int id, jc, i; + int maxChannels; + int isDefault; + const PaDeviceInfo *pdi; + int numDevices = Pa_GetDeviceCount(); + parameters.mode = mode; + + for( id=0; id<numDevices; id++ ) /* Iterate through all devices. */ + { + parameters.deviceID = id; + + pdi = Pa_GetDeviceInfo( id ); + + if( mode == MODE_INPUT ) { + maxChannels = pdi->maxInputChannels; + isDefault = ( id == Pa_GetDefaultInputDevice()); + } else { + maxChannels = pdi->maxOutputChannels; + isDefault = ( id == Pa_GetDefaultOutputDevice()); + } + if( maxChannels > MAX_TEST_CHANNELS ) + maxChannels = MAX_TEST_CHANNELS; + if (maxChannels == 0) continue; // skip this device, wrong direction + + if (!allDevices && !isDefault) continue; // skip this device + + printf("\n===========================================================\n"); + printf(" Device = %s\n", pdi->name ); + printf("===========================================================\n"); + for( jc=1; jc<=maxChannels; jc++ ) + { + if (mode == MODE_INPUT) { + parameters.numInputChannels = jc; + } else { + parameters.numOutputChannels = jc; + } + TestSingleStreamParameters(parameters); + } + + /* Try each standard sample rate. */ + for( i=0; constStandardSampleRates_[i] > 0; i++ ) + { + parameters.sampleRate = constStandardSampleRates_[i]; + TestSingleStreamParameters(parameters); + } + parameters.sampleRate = pdi->defaultSampleRate; + + if (mode == MODE_INPUT) { + parameters.suggestedLatency = pdi->defaultHighInputLatency; + TestSingleStreamParameters(parameters); + parameters.suggestedLatency = pdi->defaultLowInputLatency; + TestSingleStreamParameters(parameters); + } else { + parameters.suggestedLatency = pdi->defaultHighOutputLatency; + TestSingleStreamParameters(parameters); + parameters.suggestedLatency = pdi->defaultLowOutputLatency; + TestSingleStreamParameters(parameters); + } + + for (int callback = 0; callback < 2; callback++) { + parameters.useCallback = callback; + for (int nonInterleaved = 0; nonInterleaved < 2; nonInterleaved++) { + parameters.useNonInterleaved = nonInterleaved; + TestSingleStreamParameters(parameters); + } + } + parameters.useCallback = 1; + parameters.useNonInterleaved = 0; + + for (int jf = 0; constFormatsToTest_[jf] > 0; jf++) { + parameters.format = constFormatsToTest_[jf]; + TestSingleStreamParameters(parameters); + } + } } /******************************************************************* -* Try each output device, through its full range of capabilities. */ -static void TestDevices( int mode ) +* Test each output device, through its full range of capabilities. */ +static void TestExhaustive( int mode, int allDevices ) { + PaQaTestParameters parameters = kDefaultTestParameters; int id, jc, i; int maxChannels; + int isDefault; const PaDeviceInfo *pdi; - static double standardSampleRates[] = { 8000.0, 9600.0, 11025.0, 12000.0, - 16000.0, 22050.0, 24000.0, - 32000.0, 44100.0, 48000.0, - 88200.0, 96000.0, - -1.0 }; /* Negative terminated list. */ int numDevices = Pa_GetDeviceCount(); + parameters.mode = mode; + for( id=0; id<numDevices; id++ ) /* Iterate through all devices. */ { + parameters.deviceID = id; + pdi = Pa_GetDeviceInfo( id ); - /* Try 1 to maxChannels on each device. */ - maxChannels = (( mode == MODE_INPUT ) ? pdi->maxInputChannels : pdi->maxOutputChannels); + + if( mode == MODE_INPUT ) { + maxChannels = pdi->maxInputChannels; + isDefault = ( id == Pa_GetDefaultInputDevice()); + } else { + maxChannels = pdi->maxOutputChannels; + isDefault = ( id == Pa_GetDefaultOutputDevice()); + } if( maxChannels > MAX_TEST_CHANNELS ) maxChannels = MAX_TEST_CHANNELS; - + if (maxChannels == 0) continue; // skip this device, wrong direction + + if (!allDevices && !isDefault) continue; // skip this device + + printf("\n===========================================================\n"); + printf(" Device = %s\n", pdi->name ); + printf("===========================================================\n"); for( jc=1; jc<=maxChannels; jc++ ) { - printf("\n========================================================================\n"); - printf(" Device = %s\n", pdi->name ); - printf("========================================================================\n"); + printf("\n---------------------- NumChannels = %d ------------\n", jc ); + if (mode == MODE_INPUT) { + parameters.numInputChannels = jc; + } else { + parameters.numOutputChannels = jc; + } /* Try each standard sample rate. */ - for( i=0; standardSampleRates[i] > 0; i++ ) + for( i=0; constStandardSampleRates_[i] > 0; i++ ) { - TestFormats( mode, (PaDeviceIndex)id, standardSampleRates[i], jc ); + parameters.sampleRate = constStandardSampleRates_[i]; + for (int callback = 0; callback < 2; callback++) { + parameters.useCallback = callback; + for (int nonInterleaved = 0; nonInterleaved < 2; nonInterleaved++) { + parameters.useNonInterleaved = nonInterleaved; + for (int jf = 0; constFormatsToTest_[jf] > 0; jf++) { + parameters.format = constFormatsToTest_[jf]; + TestSingleStreamParameters(parameters); + } + } + } } } } } /*******************************************************************/ -static void TestFormats( int mode, PaDeviceIndex deviceID, double sampleRate, - int numChannels ) +static void usage( const char *name ) { - TestAdvance( mode, deviceID, sampleRate, numChannels, paFloat32 ); - TestAdvance( mode, deviceID, sampleRate, numChannels, paInt16 ); - TestAdvance( mode, deviceID, sampleRate, numChannels, paInt32 ); - /* TestAdvance( mode, deviceID, sampleRate, numChannels, paInt24 ); */ + printf("%s [-a] {-tN}\n", name); + printf(" -a - Test ALL devices, otherwise just the default devices.\n"); + printf(" -i - test INPUT only.\n"); + printf(" -o - test OUTPUT only.\n"); + printf(" -t - Test level, 0=Quick, 1=Normal, 2=Exhaustive\n"); + printf(" -? - Help\n"); } /*******************************************************************/ -static int TestAdvance( int mode, PaDeviceIndex deviceID, double sampleRate, - int numChannels, PaSampleFormat format ) +int main( int argc, char **argv ); +int main( int argc, char **argv ) { - PaStreamParameters inputParameters, outputParameters, *ipp, *opp; - PaStream *stream = NULL; - PaError result = paNoError; - PaQaData myData; - #define FRAMES_PER_BUFFER (64) - const int kNumSeconds = 100; - - /* Setup data for synthesis thread. */ - myData.framesLeft = (unsigned long) (sampleRate * kNumSeconds); - myData.numChannels = numChannels; - myData.mode = mode; - myData.format = format; - switch( format ) - { - case paFloat32: - case paInt32: - case paInt24: - myData.bytesPerSample = 4; - break; -/* case paPackedInt24: - myData.bytesPerSample = 3; - break; */ - default: - myData.bytesPerSample = 2; - break; - } + int i; + PaError result; + int allDevices = 0; + int testOutput = 1; + int testInput = 1; + int testLevel = TEST_LEVEL_NORMAL; + char *executableName = argv[0]; - if( mode == MODE_INPUT ) - { - inputParameters.device = deviceID; - inputParameters.channelCount = numChannels; - inputParameters.sampleFormat = format; - inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency; - inputParameters.hostApiSpecificStreamInfo = NULL; - ipp = &inputParameters; - } - else + /* Parse command line parameters. */ + i = 1; + while( i<argc ) { - ipp = NULL; - } - - if( mode == MODE_OUTPUT ) - { - outputParameters.device = deviceID; - outputParameters.channelCount = numChannels; - outputParameters.sampleFormat = format; - outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; - outputParameters.hostApiSpecificStreamInfo = NULL; - opp = &outputParameters; + char *arg = argv[i]; + if( arg[0] == '-' ) + { + switch(arg[1]) + { + case 'a': + allDevices = 1; + break; + case 'i': + testOutput = 0; + break; + case 'o': + testInput = 0; + break; + case 't': + testLevel = atoi(&arg[2]); + break; + + default: + printf("Illegal option: %s\n", arg); + case '?': + usage( executableName ); + exit(1); + break; + } + } + else + { + printf("Illegal argument: %s\n", arg); + usage( executableName ); + return 1; + } + i += 1; } - else - { - opp = NULL; - } - - if(paFormatIsSupported == Pa_IsFormatSupported( ipp, opp, sampleRate )) - { - printf("------ TestAdvance: %s, device = %d, rate = %g, numChannels = %d, format = %lu -------\n", - ( mode == MODE_INPUT ) ? "INPUT" : "OUTPUT", - deviceID, sampleRate, numChannels, (unsigned long)format); - EXPECT( ((result = Pa_OpenStream( &stream, - ipp, - opp, - sampleRate, - FRAMES_PER_BUFFER, - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - QaCallback, - &myData ) ) == 0) ); - if( stream ) + + ASSERT_EQ(2, sizeof(short)); /* The callback assumes we have 16-bit shorts. */ + ASSERT_EQ(4, sizeof(int)); /* The callback assumes we have 32-bit ints. */ + ASSERT_EQ(paNoError, (result=Pa_Initialize())); + + if (testLevel == TEST_LEVEL_QUICK) { + printf("\n---- Quick Test ---------------\n"); + RunQuickTest(); + } else { + if( testInput ) + { + printf("\n---- Test INPUT ---------------\n"); + if (testLevel == TEST_LEVEL_NORMAL) { + TestNormal( MODE_INPUT, allDevices ); + } else { + TestExhaustive( MODE_INPUT, allDevices ); + } + } + if( testOutput ) { - PaTime oldStamp, newStamp; - unsigned long oldFrames; - int minDelay = ( mode == MODE_INPUT ) ? 1000 : 400; - /* Was: - int minNumBuffers = Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate ); - int msec = (int) ((minNumBuffers * 3 * 1000.0 * FRAMES_PER_BUFFER) / sampleRate); - */ - int msec = (int)( 3.0 * - (( mode == MODE_INPUT ) ? inputParameters.suggestedLatency : outputParameters.suggestedLatency )); - if( msec < minDelay ) msec = minDelay; - printf("msec = %d\n", msec); /**/ - EXPECT( ((result=Pa_StartStream( stream )) == 0) ); - /* Check to make sure PortAudio is advancing timeStamp. */ - oldStamp = Pa_GetStreamTime(stream); - Pa_Sleep(msec); - newStamp = Pa_GetStreamTime(stream); - printf("oldStamp = %9.6f, newStamp = %9.6f\n", oldStamp, newStamp ); /**/ - EXPECT( (oldStamp < newStamp) ); - /* Check to make sure callback is decrementing framesLeft. */ - oldFrames = myData.framesLeft; - Pa_Sleep(msec); - printf("oldFrames = %lu, myData.framesLeft = %lu\n", oldFrames, myData.framesLeft ); /**/ - EXPECT( (oldFrames > myData.framesLeft) ); - EXPECT( ((result=Pa_CloseStream( stream )) == 0) ); - stream = NULL; + printf("\n---- Test OUTPUT ---------------\n"); + if (testLevel == TEST_LEVEL_NORMAL) { + TestNormal( MODE_OUTPUT, allDevices ); + } else { + TestExhaustive( MODE_OUTPUT, allDevices ); + } } } - return 0; + error: - if( stream != NULL ) Pa_CloseStream( stream ); - return -1; + ASSERT_EQ(paNoError, Pa_Terminate()); + + PAQA_PRINT_RESULT; + return PAQA_EXIT_RESULT; } |