patest_suggested_vs_streaminfo_latency.c (10139B)
1 /** @file patest_suggested_vs_streaminfo_latency.c 2 @ingroup test_src 3 @brief Print suggested vs. PaStreamInfo reported actual latency 4 @author Ross Bencina <rossb@audiomulch.com> 5 6 Opens streams with a sequence of suggested latency values 7 from 0 to 2 seconds in .5ms intervals and gathers the resulting actual 8 latency values. Output a csv file and graph suggested vs. actual. Run 9 with framesPerBuffer unspecified, powers of 2 and multiples of 50 and 10 prime number buffer sizes. 11 */ 12 /* 13 * $Id: patest_sine.c 1368 2008-03-01 00:38:27Z rossb $ 14 * 15 * This program uses the PortAudio Portable Audio Library. 16 * For more information see: http://www.portaudio.com/ 17 * Copyright (c) 1999-2000 Ross Bencina and Phil Burk 18 * 19 * Permission is hereby granted, free of charge, to any person obtaining 20 * a copy of this software and associated documentation files 21 * (the "Software"), to deal in the Software without restriction, 22 * including without limitation the rights to use, copy, modify, merge, 23 * publish, distribute, sublicense, and/or sell copies of the Software, 24 * and to permit persons to whom the Software is furnished to do so, 25 * subject to the following conditions: 26 * 27 * The above copyright notice and this permission notice shall be 28 * included in all copies or substantial portions of the Software. 29 * 30 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 31 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 32 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 33 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 34 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 35 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 36 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 37 */ 38 39 /* 40 * The text above constitutes the entire PortAudio license; however, 41 * the PortAudio community also makes the following non-binding requests: 42 * 43 * Any person wishing to distribute modifications to the Software is 44 * requested to send the modifications to the original developer so that 45 * they can be incorporated into the canonical version. It is also 46 * requested that these non-binding requests be included along with the 47 * license above. 48 */ 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <math.h> 53 #include "portaudio.h" 54 55 #define SAMPLE_RATE (44100) 56 #define FRAMES_PER_BUFFER 2//(128) 57 #define NUM_CHANNELS (2) 58 59 #define SUGGESTED_LATENCY_START_SECONDS (0.0) 60 #define SUGGESTED_LATENCY_END_SECONDS (2.0) 61 #define SUGGESTED_LATENCY_INCREMENT_SECONDS (0.0005) /* half a millisecond increments */ 62 63 64 /* dummy callback. does nothing. never gets called */ 65 static int patestCallback( const void *inputBuffer, void *outputBuffer, 66 unsigned long framesPerBuffer, 67 const PaStreamCallbackTimeInfo* timeInfo, 68 PaStreamCallbackFlags statusFlags, 69 void *userData ) 70 { 71 return paContinue; 72 } 73 74 /*******************************************************************/ 75 static void usage() 76 { 77 int i; 78 const PaDeviceInfo *deviceInfo; 79 const char *channelString; 80 81 fprintf( stderr, "PortAudio suggested (requested) vs. resulting (reported) stream latency test\n" ); 82 fprintf( stderr, "Usage: x.exe input-device-index output-device-index sample-rate frames-per-buffer\n" ); 83 fprintf( stderr, "Use -1 for default device index, or use one of these:\n" ); 84 for( i=0; i < Pa_GetDeviceCount(); ++i ){ 85 deviceInfo = Pa_GetDeviceInfo(i); 86 if( deviceInfo->maxInputChannels > 0 && deviceInfo->maxOutputChannels > 0 ) 87 channelString = "full-duplex"; 88 else if( deviceInfo->maxInputChannels > 0 ) 89 channelString = "input only"; 90 else 91 channelString = "output only"; 92 93 fprintf( stderr, "%d (%s, %s, %s)\n", i, deviceInfo->name, Pa_GetHostApiInfo(deviceInfo->hostApi)->name, channelString ); 94 } 95 Pa_Terminate(); 96 exit(-1); 97 } 98 99 int main( int argc, const char* argv[] ); 100 int main( int argc, const char* argv[] ) 101 { 102 PaStreamParameters inputParameters, outputParameters; 103 PaStream *stream; 104 PaError err; 105 PaTime suggestedLatency; 106 const PaStreamInfo *streamInfo; 107 const PaDeviceInfo *deviceInfo; 108 float sampleRate = SAMPLE_RATE; 109 int framesPerBuffer = FRAMES_PER_BUFFER; 110 err = Pa_Initialize(); 111 if( err != paNoError ) goto error; 112 113 if( argc > 1 && strcmp(argv[1],"-h") == 0 ) 114 usage(); 115 116 if( argc > 3 ){ 117 sampleRate = atoi(argv[3]); 118 } 119 120 if( argc > 4 ){ 121 framesPerBuffer = atoi(argv[4]); 122 } 123 124 printf("# sample rate=%f, frames per buffer=%d\n", (float)sampleRate, framesPerBuffer ); 125 126 inputParameters.device = -1; 127 if( argc > 1 ) 128 inputParameters.device = atoi(argv[1]); 129 if( inputParameters.device == -1 ){ 130 inputParameters.device = Pa_GetDefaultInputDevice(); 131 if (inputParameters.device == paNoDevice) { 132 fprintf(stderr,"Error: No default input device available.\n"); 133 goto error; 134 } 135 }else{ 136 deviceInfo = Pa_GetDeviceInfo(inputParameters.device); 137 if( !deviceInfo ){ 138 fprintf(stderr,"Error: Invalid input device index.\n"); 139 usage(); 140 } 141 if( deviceInfo->maxInputChannels == 0 ){ 142 fprintf(stderr,"Error: Specified input device has no input channels (an output only device?).\n"); 143 usage(); 144 } 145 } 146 147 inputParameters.channelCount = NUM_CHANNELS; 148 inputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ 149 inputParameters.hostApiSpecificStreamInfo = NULL; 150 151 deviceInfo = Pa_GetDeviceInfo(inputParameters.device); 152 printf( "# using input device id %d (%s, %s)\n", inputParameters.device, deviceInfo->name, Pa_GetHostApiInfo(deviceInfo->hostApi)->name ); 153 154 155 outputParameters.device = -1; 156 if( argc > 2 ) 157 outputParameters.device = atoi(argv[2]); 158 if( outputParameters.device == -1 ){ 159 outputParameters.device = Pa_GetDefaultOutputDevice(); 160 if (outputParameters.device == paNoDevice) { 161 fprintf(stderr,"Error: No default output device available.\n"); 162 goto error; 163 } 164 }else{ 165 deviceInfo = Pa_GetDeviceInfo(outputParameters.device); 166 if( !deviceInfo ){ 167 fprintf(stderr,"Error: Invalid output device index.\n"); 168 usage(); 169 } 170 if( deviceInfo->maxOutputChannels == 0 ){ 171 fprintf(stderr,"Error: Specified output device has no output channels (an input only device?).\n"); 172 usage(); 173 } 174 } 175 176 outputParameters.channelCount = NUM_CHANNELS; 177 outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ 178 outputParameters.hostApiSpecificStreamInfo = NULL; 179 180 deviceInfo = Pa_GetDeviceInfo(outputParameters.device); 181 printf( "# using output device id %d (%s, %s)\n", outputParameters.device, deviceInfo->name, Pa_GetHostApiInfo(deviceInfo->hostApi)->name ); 182 183 184 printf( "# suggested latency, half duplex PaStreamInfo::outputLatency, half duplex PaStreamInfo::inputLatency, full duplex PaStreamInfo::outputLatency, full duplex PaStreamInfo::inputLatency\n" ); 185 suggestedLatency = SUGGESTED_LATENCY_START_SECONDS; 186 while( suggestedLatency <= SUGGESTED_LATENCY_END_SECONDS ){ 187 188 outputParameters.suggestedLatency = suggestedLatency; 189 inputParameters.suggestedLatency = suggestedLatency; 190 191 printf( "%f, ", suggestedLatency ); 192 193 /* ------------------------------ output ------------------------------ */ 194 195 err = Pa_OpenStream( 196 &stream, 197 NULL, /* no input */ 198 &outputParameters, 199 sampleRate, 200 framesPerBuffer, 201 paClipOff, /* we won't output out of range samples so don't bother clipping them */ 202 patestCallback, 203 0 ); 204 if( err != paNoError ) goto error; 205 206 streamInfo = Pa_GetStreamInfo( stream ); 207 208 printf( "%f,", streamInfo->outputLatency ); 209 210 err = Pa_CloseStream( stream ); 211 if( err != paNoError ) goto error; 212 213 /* ------------------------------ input ------------------------------ */ 214 215 err = Pa_OpenStream( 216 &stream, 217 &inputParameters, 218 NULL, /* no output */ 219 sampleRate, 220 framesPerBuffer, 221 paClipOff, /* we won't output out of range samples so don't bother clipping them */ 222 patestCallback, 223 0 ); 224 if( err != paNoError ) goto error; 225 226 streamInfo = Pa_GetStreamInfo( stream ); 227 228 printf( "%f,", streamInfo->inputLatency ); 229 230 err = Pa_CloseStream( stream ); 231 if( err != paNoError ) goto error; 232 233 /* ------------------------------ full duplex ------------------------------ */ 234 235 err = Pa_OpenStream( 236 &stream, 237 &inputParameters, 238 &outputParameters, 239 sampleRate, 240 framesPerBuffer, 241 paClipOff, /* we won't output out of range samples so don't bother clipping them */ 242 patestCallback, 243 0 ); 244 if( err != paNoError ) goto error; 245 246 streamInfo = Pa_GetStreamInfo( stream ); 247 248 printf( "%f,%f", streamInfo->outputLatency, streamInfo->inputLatency ); 249 250 err = Pa_CloseStream( stream ); 251 if( err != paNoError ) goto error; 252 253 /* ------------------------------------------------------------ */ 254 255 printf( "\n" ); 256 suggestedLatency += SUGGESTED_LATENCY_INCREMENT_SECONDS; 257 } 258 259 Pa_Terminate(); 260 printf("# Test finished.\n"); 261 262 return err; 263 error: 264 Pa_Terminate(); 265 fprintf( stderr, "An error occured while using the portaudio stream\n" ); 266 fprintf( stderr, "Error number: %d\n", err ); 267 fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); 268 return err; 269 }