summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/portaudio/qa/paqa_devs.c
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/portaudio/qa/paqa_devs.c')
-rw-r--r--3rdparty/portaudio/qa/paqa_devs.c902
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;
}