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