comparison src/portaudio_20161030_catalina_patch/qa/paqa_devs.c @ 162:d43aab368df9

Duplicate for patch testing
author Chris Cannam <cannam@all-day-breakfast.com>
date Wed, 30 Oct 2019 11:25:10 +0000
parents
children
comparison
equal deleted inserted replaced
161:4797bbf470e7 162:d43aab368df9
1 /** @file paqa_devs.c
2 @ingroup qa_src
3 @brief Self Testing Quality Assurance app for PortAudio
4 Try to open each device and run through all the
5 possible configurations. This test does not verify
6 that the configuration works well. It just verifies
7 that it does not crash. It requires a human to listen to
8 the outputs.
9
10 @author Phil Burk http://www.softsynth.com
11
12 Pieter adapted to V19 API. Test now relies heavily on
13 Pa_IsFormatSupported(). Uses same 'standard' sample rates
14 as in test pa_devs.c.
15 */
16 /*
17 * $Id$
18 *
19 * This program uses the PortAudio Portable Audio Library.
20 * For more information see: http://www.portaudio.com
21 * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
22 *
23 * Permission is hereby granted, free of charge, to any person obtaining
24 * a copy of this software and associated documentation files
25 * (the "Software"), to deal in the Software without restriction,
26 * including without limitation the rights to use, copy, modify, merge,
27 * publish, distribute, sublicense, and/or sell copies of the Software,
28 * and to permit persons to whom the Software is furnished to do so,
29 * subject to the following conditions:
30 *
31 * The above copyright notice and this permission notice shall be
32 * included in all copies or substantial portions of the Software.
33 *
34 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
35 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
36 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
37 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
38 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
39 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
40 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41 */
42
43 /*
44 * The text above constitutes the entire PortAudio license; however,
45 * the PortAudio community also makes the following non-binding requests:
46 *
47 * Any person wishing to distribute modifications to the Software is
48 * requested to send the modifications to the original developer so that
49 * they can be incorporated into the canonical version. It is also
50 * requested that these non-binding requests be included along with the
51 * license above.
52 */
53
54 #include <stdio.h>
55 #include <math.h>
56 #include "portaudio.h"
57 #include "pa_trace.h"
58
59 /****************************************** Definitions ***********/
60 #define MODE_INPUT (0)
61 #define MODE_OUTPUT (1)
62 #define MAX_TEST_CHANNELS 4
63
64 typedef struct PaQaData
65 {
66 unsigned long framesLeft;
67 int numChannels;
68 int bytesPerSample;
69 int mode;
70 short sawPhase;
71 PaSampleFormat format;
72 }
73 PaQaData;
74
75 /****************************************** Prototypes ***********/
76 static void TestDevices( int mode );
77 static void TestFormats( int mode, PaDeviceIndex deviceID, double sampleRate,
78 int numChannels );
79 static int TestAdvance( int mode, PaDeviceIndex deviceID, double sampleRate,
80 int numChannels, PaSampleFormat format );
81 static int QaCallback( const void *inputBuffer, void *outputBuffer,
82 unsigned long framesPerBuffer,
83 const PaStreamCallbackTimeInfo* timeInfo,
84 PaStreamCallbackFlags statusFlags,
85 void *userData );
86
87 /****************************************** Globals ***********/
88 static int gNumPassed = 0;
89 static int gNumFailed = 0;
90
91 /****************************************** Macros ***********/
92 /* Print ERROR if it fails. Tally success or failure. */
93 /* Odd do-while wrapper seems to be needed for some compilers. */
94 #define EXPECT(_exp) \
95 do \
96 { \
97 if ((_exp)) {\
98 /* printf("SUCCESS for %s\n", #_exp ); */ \
99 gNumPassed++; \
100 } \
101 else { \
102 printf("ERROR - 0x%x - %s for %s\n", result, \
103 ((result == 0) ? "-" : Pa_GetErrorText(result)), \
104 #_exp ); \
105 gNumFailed++; \
106 goto error; \
107 } \
108 } while(0)
109
110 /*******************************************************************/
111 /* This routine will be called by the PortAudio engine when audio is needed.
112 ** It may be called at interrupt level on some machines so don't do anything
113 ** that could mess up the system like calling malloc() or free().
114 */
115 static int QaCallback( const void *inputBuffer, void *outputBuffer,
116 unsigned long framesPerBuffer,
117 const PaStreamCallbackTimeInfo* timeInfo,
118 PaStreamCallbackFlags statusFlags,
119 void *userData )
120 {
121 unsigned long i;
122 short phase;
123 PaQaData *data = (PaQaData *) userData;
124 (void) inputBuffer;
125
126 /* Play simple sawtooth wave. */
127 if( data->mode == MODE_OUTPUT )
128 {
129 phase = data->sawPhase;
130 switch( data->format )
131 {
132 case paFloat32:
133 {
134 float *out = (float *) outputBuffer;
135 for( i=0; i<framesPerBuffer; i++ )
136 {
137 phase += 0x123;
138 *out++ = (float) (phase * (1.0 / 32768.0));
139 if( data->numChannels == 2 )
140 {
141 *out++ = (float) (phase * (1.0 / 32768.0));
142 }
143 }
144 }
145 break;
146
147 case paInt32:
148 {
149 int *out = (int *) outputBuffer;
150 for( i=0; i<framesPerBuffer; i++ )
151 {
152 phase += 0x123;
153 *out++ = ((int) phase ) << 16;
154 if( data->numChannels == 2 )
155 {
156 *out++ = ((int) phase ) << 16;
157 }
158 }
159 }
160 break;
161
162 case paInt16:
163 {
164 short *out = (short *) outputBuffer;
165 for( i=0; i<framesPerBuffer; i++ )
166 {
167 phase += 0x123;
168 *out++ = phase;
169 if( data->numChannels == 2 )
170 {
171 *out++ = phase;
172 }
173 }
174 }
175 break;
176
177 default:
178 {
179 unsigned char *out = (unsigned char *) outputBuffer;
180 unsigned long numBytes = framesPerBuffer * data->numChannels * data->bytesPerSample;
181 for( i=0; i<numBytes; i++ )
182 {
183 *out++ = 0;
184 }
185 }
186 break;
187 }
188 data->sawPhase = phase;
189 }
190 /* Are we through yet? */
191 if( data->framesLeft > framesPerBuffer )
192 {
193 PaUtil_AddTraceMessage("QaCallback: running. framesLeft", data->framesLeft );
194 data->framesLeft -= framesPerBuffer;
195 return 0;
196 }
197 else
198 {
199 PaUtil_AddTraceMessage("QaCallback: DONE! framesLeft", data->framesLeft );
200 data->framesLeft = 0;
201 return 1;
202 }
203 }
204
205 /*******************************************************************/
206 int main(void);
207 int main(void)
208 {
209 PaError result;
210 EXPECT( ((result=Pa_Initialize()) == 0) );
211 printf("Test OUTPUT ---------------\n");
212 TestDevices( MODE_OUTPUT );
213 printf("Test INPUT ---------------\n");
214 TestDevices( MODE_INPUT );
215 error:
216 Pa_Terminate();
217 printf("QA Report: %d passed, %d failed.\n", gNumPassed, gNumFailed );
218 return (gNumFailed > 0) ? 1 : 0;
219 }
220
221 /*******************************************************************
222 * Try each output device, through its full range of capabilities. */
223 static void TestDevices( int mode )
224 {
225 int id, jc, i;
226 int maxChannels;
227 const PaDeviceInfo *pdi;
228 static double standardSampleRates[] = { 8000.0, 9600.0, 11025.0, 12000.0,
229 16000.0, 22050.0, 24000.0,
230 32000.0, 44100.0, 48000.0,
231 88200.0, 96000.0,
232 -1.0 }; /* Negative terminated list. */
233 int numDevices = Pa_GetDeviceCount();
234 for( id=0; id<numDevices; id++ ) /* Iterate through all devices. */
235 {
236 pdi = Pa_GetDeviceInfo( id );
237 /* Try 1 to maxChannels on each device. */
238 maxChannels = (( mode == MODE_INPUT ) ? pdi->maxInputChannels : pdi->maxOutputChannels);
239 if( maxChannels > MAX_TEST_CHANNELS )
240 maxChannels = MAX_TEST_CHANNELS;
241
242 for( jc=1; jc<=maxChannels; jc++ )
243 {
244 printf("\n========================================================================\n");
245 printf(" Device = %s\n", pdi->name );
246 printf("========================================================================\n");
247 /* Try each standard sample rate. */
248 for( i=0; standardSampleRates[i] > 0; i++ )
249 {
250 TestFormats( mode, (PaDeviceIndex)id, standardSampleRates[i], jc );
251 }
252 }
253 }
254 }
255
256 /*******************************************************************/
257 static void TestFormats( int mode, PaDeviceIndex deviceID, double sampleRate,
258 int numChannels )
259 {
260 TestAdvance( mode, deviceID, sampleRate, numChannels, paFloat32 );
261 TestAdvance( mode, deviceID, sampleRate, numChannels, paInt16 );
262 TestAdvance( mode, deviceID, sampleRate, numChannels, paInt32 );
263 /* TestAdvance( mode, deviceID, sampleRate, numChannels, paInt24 ); */
264 }
265
266 /*******************************************************************/
267 static int TestAdvance( int mode, PaDeviceIndex deviceID, double sampleRate,
268 int numChannels, PaSampleFormat format )
269 {
270 PaStreamParameters inputParameters, outputParameters, *ipp, *opp;
271 PaStream *stream = NULL;
272 PaError result = paNoError;
273 PaQaData myData;
274 #define FRAMES_PER_BUFFER (64)
275 const int kNumSeconds = 100;
276
277 /* Setup data for synthesis thread. */
278 myData.framesLeft = (unsigned long) (sampleRate * kNumSeconds);
279 myData.numChannels = numChannels;
280 myData.mode = mode;
281 myData.format = format;
282 switch( format )
283 {
284 case paFloat32:
285 case paInt32:
286 case paInt24:
287 myData.bytesPerSample = 4;
288 break;
289 /* case paPackedInt24:
290 myData.bytesPerSample = 3;
291 break; */
292 default:
293 myData.bytesPerSample = 2;
294 break;
295 }
296
297 if( mode == MODE_INPUT )
298 {
299 inputParameters.device = deviceID;
300 inputParameters.channelCount = numChannels;
301 inputParameters.sampleFormat = format;
302 inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
303 inputParameters.hostApiSpecificStreamInfo = NULL;
304 ipp = &inputParameters;
305 }
306 else
307 {
308 ipp = NULL;
309 }
310
311 if( mode == MODE_OUTPUT )
312 {
313 outputParameters.device = deviceID;
314 outputParameters.channelCount = numChannels;
315 outputParameters.sampleFormat = format;
316 outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
317 outputParameters.hostApiSpecificStreamInfo = NULL;
318 opp = &outputParameters;
319 }
320 else
321 {
322 opp = NULL;
323 }
324
325 if(paFormatIsSupported == Pa_IsFormatSupported( ipp, opp, sampleRate ))
326 {
327 printf("------ TestAdvance: %s, device = %d, rate = %g, numChannels = %d, format = %lu -------\n",
328 ( mode == MODE_INPUT ) ? "INPUT" : "OUTPUT",
329 deviceID, sampleRate, numChannels, (unsigned long)format);
330 EXPECT( ((result = Pa_OpenStream( &stream,
331 ipp,
332 opp,
333 sampleRate,
334 FRAMES_PER_BUFFER,
335 paClipOff, /* we won't output out of range samples so don't bother clipping them */
336 QaCallback,
337 &myData ) ) == 0) );
338 if( stream )
339 {
340 PaTime oldStamp, newStamp;
341 unsigned long oldFrames;
342 int minDelay = ( mode == MODE_INPUT ) ? 1000 : 400;
343 /* Was:
344 int minNumBuffers = Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate );
345 int msec = (int) ((minNumBuffers * 3 * 1000.0 * FRAMES_PER_BUFFER) / sampleRate);
346 */
347 int msec = (int)( 3.0 *
348 (( mode == MODE_INPUT ) ? inputParameters.suggestedLatency : outputParameters.suggestedLatency ));
349 if( msec < minDelay ) msec = minDelay;
350 printf("msec = %d\n", msec); /**/
351 EXPECT( ((result=Pa_StartStream( stream )) == 0) );
352 /* Check to make sure PortAudio is advancing timeStamp. */
353 oldStamp = Pa_GetStreamTime(stream);
354 Pa_Sleep(msec);
355 newStamp = Pa_GetStreamTime(stream);
356 printf("oldStamp = %9.6f, newStamp = %9.6f\n", oldStamp, newStamp ); /**/
357 EXPECT( (oldStamp < newStamp) );
358 /* Check to make sure callback is decrementing framesLeft. */
359 oldFrames = myData.framesLeft;
360 Pa_Sleep(msec);
361 printf("oldFrames = %lu, myData.framesLeft = %lu\n", oldFrames, myData.framesLeft ); /**/
362 EXPECT( (oldFrames > myData.framesLeft) );
363 EXPECT( ((result=Pa_CloseStream( stream )) == 0) );
364 stream = NULL;
365 }
366 }
367 return 0;
368 error:
369 if( stream != NULL ) Pa_CloseStream( stream );
370 return -1;
371 }