annotate src/portaudio_20161030_catalina_patch/test/patest_stop_playout.c @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents 4edcd14160a5
children
rev   line source
Chris@4 1 /** @file patest_stop_playout.c
Chris@4 2 @ingroup test_src
Chris@4 3 @brief Test whether all queued samples are played when Pa_StopStream()
Chris@4 4 is used with a callback or read/write stream, or when the callback
Chris@4 5 returns paComplete.
Chris@4 6 @author Ross Bencina <rossb@audiomulch.com>
Chris@4 7 */
Chris@4 8 /*
Chris@55 9 * $Id$
Chris@4 10 *
Chris@4 11 * This program uses the PortAudio Portable Audio Library.
Chris@4 12 * For more information see: http://www.portaudio.com/
Chris@4 13 * Copyright (c) 1999-2004 Ross Bencina and Phil Burk
Chris@4 14 *
Chris@4 15 * Permission is hereby granted, free of charge, to any person obtaining
Chris@4 16 * a copy of this software and associated documentation files
Chris@4 17 * (the "Software"), to deal in the Software without restriction,
Chris@4 18 * including without limitation the rights to use, copy, modify, merge,
Chris@4 19 * publish, distribute, sublicense, and/or sell copies of the Software,
Chris@4 20 * and to permit persons to whom the Software is furnished to do so,
Chris@4 21 * subject to the following conditions:
Chris@4 22 *
Chris@4 23 * The above copyright notice and this permission notice shall be
Chris@4 24 * included in all copies or substantial portions of the Software.
Chris@4 25 *
Chris@4 26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Chris@4 27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Chris@4 28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
Chris@4 29 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
Chris@4 30 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
Chris@4 31 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
Chris@4 32 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Chris@4 33 */
Chris@4 34
Chris@4 35 /*
Chris@4 36 * The text above constitutes the entire PortAudio license; however,
Chris@4 37 * the PortAudio community also makes the following non-binding requests:
Chris@4 38 *
Chris@4 39 * Any person wishing to distribute modifications to the Software is
Chris@4 40 * requested to send the modifications to the original developer so that
Chris@4 41 * they can be incorporated into the canonical version. It is also
Chris@4 42 * requested that these non-binding requests be included along with the
Chris@4 43 * license above.
Chris@4 44 */
Chris@4 45 #include <stdio.h>
Chris@4 46 #include <math.h>
Chris@4 47 #include "portaudio.h"
Chris@4 48
Chris@4 49 #define SAMPLE_RATE (44100)
Chris@4 50 #define FRAMES_PER_BUFFER (1024)
Chris@4 51
Chris@4 52 #define TONE_SECONDS (1) /* long tone */
Chris@4 53 #define TONE_FADE_SECONDS (.04) /* fades at start and end of long tone */
Chris@4 54 #define GAP_SECONDS (.25) /* gap between long tone and blip */
Chris@4 55 #define BLIP_SECONDS (.035) /* short blip */
Chris@4 56
Chris@4 57 #define NUM_REPEATS (3)
Chris@4 58
Chris@4 59 #ifndef M_PI
Chris@4 60 #define M_PI (3.14159265)
Chris@4 61 #endif
Chris@4 62
Chris@4 63 #define TABLE_SIZE (2048)
Chris@4 64 typedef struct
Chris@4 65 {
Chris@4 66 float sine[TABLE_SIZE+1];
Chris@4 67
Chris@4 68 int repeatCount;
Chris@4 69
Chris@4 70 double phase;
Chris@4 71 double lowIncrement, highIncrement;
Chris@4 72
Chris@4 73 int gap1Length, toneLength, toneFadesLength, gap2Length, blipLength;
Chris@4 74 int gap1Countdown, toneCountdown, gap2Countdown, blipCountdown;
Chris@4 75 }
Chris@4 76 TestData;
Chris@4 77
Chris@4 78
Chris@4 79 static void RetriggerTestSignalGenerator( TestData *data )
Chris@4 80 {
Chris@4 81 data->phase = 0.;
Chris@4 82 data->gap1Countdown = data->gap1Length;
Chris@4 83 data->toneCountdown = data->toneLength;
Chris@4 84 data->gap2Countdown = data->gap2Length;
Chris@4 85 data->blipCountdown = data->blipLength;
Chris@4 86 }
Chris@4 87
Chris@4 88
Chris@4 89 static void ResetTestSignalGenerator( TestData *data )
Chris@4 90 {
Chris@4 91 data->repeatCount = 0;
Chris@4 92 RetriggerTestSignalGenerator( data );
Chris@4 93 }
Chris@4 94
Chris@4 95
Chris@4 96 static void InitTestSignalGenerator( TestData *data )
Chris@4 97 {
Chris@4 98 int signalLengthModBufferLength, i;
Chris@4 99
Chris@4 100 /* initialise sinusoidal wavetable */
Chris@4 101 for( i=0; i<TABLE_SIZE; i++ )
Chris@4 102 {
Chris@4 103 data->sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
Chris@4 104 }
Chris@4 105 data->sine[TABLE_SIZE] = data->sine[0]; /* guard point for linear interpolation */
Chris@4 106
Chris@4 107
Chris@4 108
Chris@4 109 data->lowIncrement = (330. / SAMPLE_RATE) * TABLE_SIZE;
Chris@4 110 data->highIncrement = (1760. / SAMPLE_RATE) * TABLE_SIZE;
Chris@4 111
Chris@4 112 data->gap1Length = GAP_SECONDS * SAMPLE_RATE;
Chris@4 113 data->toneLength = TONE_SECONDS * SAMPLE_RATE;
Chris@4 114 data->toneFadesLength = TONE_FADE_SECONDS * SAMPLE_RATE;
Chris@4 115 data->gap2Length = GAP_SECONDS * SAMPLE_RATE;
Chris@4 116 data->blipLength = BLIP_SECONDS * SAMPLE_RATE;
Chris@4 117
Chris@4 118 /* adjust signal length to be a multiple of the buffer length */
Chris@4 119 signalLengthModBufferLength = (data->gap1Length + data->toneLength + data->gap2Length + data->blipLength) % FRAMES_PER_BUFFER;
Chris@4 120 if( signalLengthModBufferLength > 0 )
Chris@4 121 data->toneLength += signalLengthModBufferLength;
Chris@4 122
Chris@4 123 ResetTestSignalGenerator( data );
Chris@4 124 }
Chris@4 125
Chris@4 126
Chris@4 127 #define MIN( a, b ) (((a)<(b))?(a):(b))
Chris@4 128
Chris@4 129 static void GenerateTestSignal( TestData *data, float *stereo, int frameCount )
Chris@4 130 {
Chris@4 131 int framesGenerated = 0;
Chris@4 132 float output;
Chris@4 133 long index;
Chris@4 134 float fraction;
Chris@4 135 int count, i;
Chris@4 136
Chris@4 137 while( framesGenerated < frameCount && data->repeatCount < NUM_REPEATS )
Chris@4 138 {
Chris@4 139 if( framesGenerated < frameCount && data->gap1Countdown > 0 ){
Chris@4 140 count = MIN( frameCount - framesGenerated, data->gap1Countdown );
Chris@4 141 for( i=0; i < count; ++i )
Chris@4 142 {
Chris@4 143 *stereo++ = 0.f;
Chris@4 144 *stereo++ = 0.f;
Chris@4 145 }
Chris@4 146
Chris@4 147 data->gap1Countdown -= count;
Chris@4 148 framesGenerated += count;
Chris@4 149 }
Chris@4 150
Chris@4 151 if( framesGenerated < frameCount && data->toneCountdown > 0 ){
Chris@4 152 count = MIN( frameCount - framesGenerated, data->toneCountdown );
Chris@4 153 for( i=0; i < count; ++i )
Chris@4 154 {
Chris@4 155 /* tone with data->lowIncrement phase increment */
Chris@4 156 index = (long)data->phase;
Chris@4 157 fraction = data->phase - index;
Chris@4 158 output = data->sine[ index ] + (data->sine[ index + 1 ] - data->sine[ index ]) * fraction;
Chris@4 159
Chris@4 160 data->phase += data->lowIncrement;
Chris@4 161 while( data->phase >= TABLE_SIZE )
Chris@4 162 data->phase -= TABLE_SIZE;
Chris@4 163
Chris@4 164 /* apply fade to ends */
Chris@4 165
Chris@4 166 if( data->toneCountdown < data->toneFadesLength )
Chris@4 167 {
Chris@4 168 /* cosine-bell fade out at end */
Chris@4 169 output *= (-cos(((float)data->toneCountdown / (float)data->toneFadesLength) * M_PI) + 1.) * .5;
Chris@4 170 }
Chris@4 171 else if( data->toneCountdown > data->toneLength - data->toneFadesLength )
Chris@4 172 {
Chris@4 173 /* cosine-bell fade in at start */
Chris@4 174 output *= (cos(((float)(data->toneCountdown - (data->toneLength - data->toneFadesLength)) / (float)data->toneFadesLength) * M_PI) + 1.) * .5;
Chris@4 175 }
Chris@4 176
Chris@4 177 output *= .5; /* play tone half as loud as blip */
Chris@4 178
Chris@4 179 *stereo++ = output;
Chris@4 180 *stereo++ = output;
Chris@4 181
Chris@4 182 data->toneCountdown--;
Chris@4 183 }
Chris@4 184
Chris@4 185 framesGenerated += count;
Chris@4 186 }
Chris@4 187
Chris@4 188 if( framesGenerated < frameCount && data->gap2Countdown > 0 ){
Chris@4 189 count = MIN( frameCount - framesGenerated, data->gap2Countdown );
Chris@4 190 for( i=0; i < count; ++i )
Chris@4 191 {
Chris@4 192 *stereo++ = 0.f;
Chris@4 193 *stereo++ = 0.f;
Chris@4 194 }
Chris@4 195
Chris@4 196 data->gap2Countdown -= count;
Chris@4 197 framesGenerated += count;
Chris@4 198 }
Chris@4 199
Chris@4 200 if( framesGenerated < frameCount && data->blipCountdown > 0 ){
Chris@4 201 count = MIN( frameCount - framesGenerated, data->blipCountdown );
Chris@4 202 for( i=0; i < count; ++i )
Chris@4 203 {
Chris@4 204 /* tone with data->highIncrement phase increment */
Chris@4 205 index = (long)data->phase;
Chris@4 206 fraction = data->phase - index;
Chris@4 207 output = data->sine[ index ] + (data->sine[ index + 1 ] - data->sine[ index ]) * fraction;
Chris@4 208
Chris@4 209 data->phase += data->highIncrement;
Chris@4 210 while( data->phase >= TABLE_SIZE )
Chris@4 211 data->phase -= TABLE_SIZE;
Chris@4 212
Chris@4 213 /* cosine-bell envelope over whole blip */
Chris@4 214 output *= (-cos( ((float)data->blipCountdown / (float)data->blipLength) * 2. * M_PI) + 1.) * .5;
Chris@4 215
Chris@4 216 *stereo++ = output;
Chris@4 217 *stereo++ = output;
Chris@4 218
Chris@4 219 data->blipCountdown--;
Chris@4 220 }
Chris@4 221
Chris@4 222 framesGenerated += count;
Chris@4 223 }
Chris@4 224
Chris@4 225
Chris@4 226 if( data->blipCountdown == 0 )
Chris@4 227 {
Chris@4 228 RetriggerTestSignalGenerator( data );
Chris@4 229 data->repeatCount++;
Chris@4 230 }
Chris@4 231 }
Chris@4 232
Chris@4 233 if( framesGenerated < frameCount )
Chris@4 234 {
Chris@4 235 count = frameCount - framesGenerated;
Chris@4 236 for( i=0; i < count; ++i )
Chris@4 237 {
Chris@4 238 *stereo++ = 0.f;
Chris@4 239 *stereo++ = 0.f;
Chris@4 240 }
Chris@4 241 }
Chris@4 242 }
Chris@4 243
Chris@4 244
Chris@4 245 static int IsTestSignalFinished( TestData *data )
Chris@4 246 {
Chris@4 247 if( data->repeatCount >= NUM_REPEATS )
Chris@4 248 return 1;
Chris@4 249 else
Chris@4 250 return 0;
Chris@4 251 }
Chris@4 252
Chris@4 253
Chris@4 254 static int TestCallback1( const void *inputBuffer, void *outputBuffer,
Chris@4 255 unsigned long frameCount,
Chris@4 256 const PaStreamCallbackTimeInfo* timeInfo,
Chris@4 257 PaStreamCallbackFlags statusFlags,
Chris@4 258 void *userData )
Chris@4 259 {
Chris@4 260 (void) inputBuffer; /* Prevent unused variable warnings. */
Chris@4 261 (void) timeInfo;
Chris@4 262 (void) statusFlags;
Chris@4 263
Chris@4 264 GenerateTestSignal( (TestData*)userData, (float*)outputBuffer, frameCount );
Chris@4 265
Chris@4 266 if( IsTestSignalFinished( (TestData*)userData ) )
Chris@4 267 return paComplete;
Chris@4 268 else
Chris@4 269 return paContinue;
Chris@4 270 }
Chris@4 271
Chris@4 272
Chris@4 273 volatile int testCallback2Finished = 0;
Chris@4 274
Chris@4 275 static int TestCallback2( const void *inputBuffer, void *outputBuffer,
Chris@4 276 unsigned long frameCount,
Chris@4 277 const PaStreamCallbackTimeInfo* timeInfo,
Chris@4 278 PaStreamCallbackFlags statusFlags,
Chris@4 279 void *userData )
Chris@4 280 {
Chris@4 281 (void) inputBuffer; /* Prevent unused variable warnings. */
Chris@4 282 (void) timeInfo;
Chris@4 283 (void) statusFlags;
Chris@4 284
Chris@4 285 GenerateTestSignal( (TestData*)userData, (float*)outputBuffer, frameCount );
Chris@4 286
Chris@4 287 if( IsTestSignalFinished( (TestData*)userData ) )
Chris@4 288 testCallback2Finished = 1;
Chris@4 289
Chris@4 290 return paContinue;
Chris@4 291 }
Chris@4 292
Chris@4 293 /*******************************************************************/
Chris@4 294 int main(void);
Chris@4 295 int main(void)
Chris@4 296 {
Chris@4 297 PaStreamParameters outputParameters;
Chris@4 298 PaStream *stream;
Chris@4 299 PaError err;
Chris@4 300 TestData data;
Chris@4 301 float writeBuffer[ FRAMES_PER_BUFFER * 2 ];
Chris@4 302
Chris@4 303 printf("PortAudio Test: check that stopping stream plays out all queued samples. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
Chris@4 304
Chris@4 305 InitTestSignalGenerator( &data );
Chris@4 306
Chris@4 307 err = Pa_Initialize();
Chris@4 308 if( err != paNoError ) goto error;
Chris@4 309
Chris@4 310 outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
Chris@4 311 outputParameters.channelCount = 2; /* stereo output */
Chris@4 312 outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */
Chris@4 313 outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
Chris@4 314 outputParameters.hostApiSpecificStreamInfo = NULL;
Chris@4 315
Chris@4 316 /* test paComplete ---------------------------------------------------------- */
Chris@4 317
Chris@4 318 ResetTestSignalGenerator( &data );
Chris@4 319
Chris@4 320 err = Pa_OpenStream(
Chris@4 321 &stream,
Chris@4 322 NULL, /* no input */
Chris@4 323 &outputParameters,
Chris@4 324 SAMPLE_RATE,
Chris@4 325 FRAMES_PER_BUFFER,
Chris@4 326 paClipOff, /* we won't output out of range samples so don't bother clipping them */
Chris@4 327 TestCallback1,
Chris@4 328 &data );
Chris@4 329 if( err != paNoError ) goto error;
Chris@4 330
Chris@4 331 err = Pa_StartStream( stream );
Chris@4 332 if( err != paNoError ) goto error;
Chris@4 333
Chris@4 334 printf("\nPlaying 'tone-blip' %d times using callback, stops by returning paComplete from callback.\n", NUM_REPEATS );
Chris@4 335 printf("If final blip is not intact, callback+paComplete implementation may be faulty.\n\n" );
Chris@4 336
Chris@4 337 while( (err = Pa_IsStreamActive( stream )) == 1 )
Chris@4 338 Pa_Sleep( 2 );
Chris@4 339
Chris@4 340 if( err != 0 ) goto error;
Chris@4 341
Chris@4 342 err = Pa_StopStream( stream );
Chris@4 343 if( err != paNoError ) goto error;
Chris@4 344
Chris@4 345 err = Pa_CloseStream( stream );
Chris@4 346 if( err != paNoError ) goto error;
Chris@4 347
Chris@4 348 Pa_Sleep( 500 );
Chris@4 349
Chris@4 350
Chris@4 351 /* test paComplete ---------------------------------------------------------- */
Chris@4 352
Chris@4 353 ResetTestSignalGenerator( &data );
Chris@4 354
Chris@4 355 err = Pa_OpenStream(
Chris@4 356 &stream,
Chris@4 357 NULL, /* no input */
Chris@4 358 &outputParameters,
Chris@4 359 SAMPLE_RATE,
Chris@4 360 FRAMES_PER_BUFFER,
Chris@4 361 paClipOff, /* we won't output out of range samples so don't bother clipping them */
Chris@4 362 TestCallback1,
Chris@4 363 &data );
Chris@4 364 if( err != paNoError ) goto error;
Chris@4 365
Chris@4 366 err = Pa_StartStream( stream );
Chris@4 367 if( err != paNoError ) goto error;
Chris@4 368
Chris@4 369 printf("\nPlaying 'tone-blip' %d times using callback, stops by returning paComplete from callback.\n", NUM_REPEATS );
Chris@4 370 printf("If final blip is not intact or is followed by garbage, callback+paComplete implementation may be faulty.\n\n" );
Chris@4 371
Chris@4 372 while( (err = Pa_IsStreamActive( stream )) == 1 )
Chris@4 373 Pa_Sleep( 5 );
Chris@4 374
Chris@4 375 printf("Waiting 5 seconds after paComplete before stopping the stream. Tests that buffers are flushed correctly.\n");
Chris@4 376 Pa_Sleep( 5000 );
Chris@4 377
Chris@4 378 if( err != 0 ) goto error;
Chris@4 379
Chris@4 380 err = Pa_StopStream( stream );
Chris@4 381 if( err != paNoError ) goto error;
Chris@4 382
Chris@4 383 err = Pa_CloseStream( stream );
Chris@4 384 if( err != paNoError ) goto error;
Chris@4 385
Chris@4 386 Pa_Sleep( 500 );
Chris@4 387
Chris@4 388
Chris@4 389 /* test Pa_StopStream() with callback --------------------------------------- */
Chris@4 390
Chris@4 391 ResetTestSignalGenerator( &data );
Chris@4 392
Chris@4 393 testCallback2Finished = 0;
Chris@4 394
Chris@4 395 err = Pa_OpenStream(
Chris@4 396 &stream,
Chris@4 397 NULL, /* no input */
Chris@4 398 &outputParameters,
Chris@4 399 SAMPLE_RATE,
Chris@4 400 FRAMES_PER_BUFFER,
Chris@4 401 paClipOff, /* we won't output out of range samples so don't bother clipping them */
Chris@4 402 TestCallback2,
Chris@4 403 &data );
Chris@4 404 if( err != paNoError ) goto error;
Chris@4 405
Chris@4 406 err = Pa_StartStream( stream );
Chris@4 407 if( err != paNoError ) goto error;
Chris@4 408
Chris@4 409
Chris@4 410 printf("\nPlaying 'tone-blip' %d times using callback, stops by calling Pa_StopStream.\n", NUM_REPEATS );
Chris@4 411 printf("If final blip is not intact, callback+Pa_StopStream implementation may be faulty.\n\n" );
Chris@4 412
Chris@4 413 /* note that polling a volatile flag is not a good way to synchronise with
Chris@4 414 the callback, but it's the best we can do portably. */
Chris@4 415 while( !testCallback2Finished )
Chris@4 416 Pa_Sleep( 2 );
Chris@4 417
Chris@4 418 Pa_Sleep( 500 );
Chris@4 419
Chris@4 420 err = Pa_StopStream( stream );
Chris@4 421 if( err != paNoError ) goto error;
Chris@4 422
Chris@4 423
Chris@4 424 err = Pa_CloseStream( stream );
Chris@4 425 if( err != paNoError ) goto error;
Chris@4 426
Chris@4 427 Pa_Sleep( 500 );
Chris@4 428
Chris@4 429 /* test Pa_StopStream() with Pa_WriteStream --------------------------------- */
Chris@4 430
Chris@4 431 ResetTestSignalGenerator( &data );
Chris@4 432
Chris@4 433 err = Pa_OpenStream(
Chris@4 434 &stream,
Chris@4 435 NULL, /* no input */
Chris@4 436 &outputParameters,
Chris@4 437 SAMPLE_RATE,
Chris@4 438 FRAMES_PER_BUFFER,
Chris@4 439 paClipOff, /* we won't output out of range samples so don't bother clipping them */
Chris@4 440 NULL, /* no callback, use blocking API */
Chris@4 441 NULL ); /* no callback, so no callback userData */
Chris@4 442 if( err != paNoError ) goto error;
Chris@4 443
Chris@4 444 err = Pa_StartStream( stream );
Chris@4 445 if( err != paNoError ) goto error;
Chris@4 446
Chris@4 447
Chris@4 448 printf("\nPlaying 'tone-blip' %d times using Pa_WriteStream, stops by calling Pa_StopStream.\n", NUM_REPEATS );
Chris@4 449 printf("If final blip is not intact, Pa_WriteStream+Pa_StopStream implementation may be faulty.\n\n" );
Chris@4 450
Chris@4 451 do{
Chris@4 452 GenerateTestSignal( &data, writeBuffer, FRAMES_PER_BUFFER );
Chris@4 453 err = Pa_WriteStream( stream, writeBuffer, FRAMES_PER_BUFFER );
Chris@4 454 if( err != paNoError ) goto error;
Chris@4 455
Chris@4 456 }while( !IsTestSignalFinished( &data ) );
Chris@4 457
Chris@4 458 err = Pa_StopStream( stream );
Chris@4 459 if( err != paNoError ) goto error;
Chris@4 460
Chris@4 461
Chris@4 462 err = Pa_CloseStream( stream );
Chris@4 463 if( err != paNoError ) goto error;
Chris@4 464
Chris@4 465 /* -------------------------------------------------------------------------- */
Chris@4 466
Chris@4 467 Pa_Terminate();
Chris@4 468 printf("Test finished.\n");
Chris@4 469
Chris@4 470 return err;
Chris@4 471
Chris@4 472 error:
Chris@4 473 Pa_Terminate();
Chris@4 474 fprintf( stderr, "An error occured while using the portaudio stream\n" );
Chris@4 475 fprintf( stderr, "Error number: %d\n", err );
Chris@4 476 fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
Chris@4 477 return err;
Chris@4 478 }