1 /** @file patest_unplug.c
2 	@ingroup test_src
3 	@brief Debug a crash involving unplugging a USB device.
4 	@author Phil Burk  http://www.softsynth.com
5 */
6 /*
7  * $Id$
8  *
9  * This program uses the PortAudio Portable Audio Library.
10  * For more information see: http://www.portaudio.com
11  * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
12  *
13  * Permission is hereby granted, free of charge, to any person obtaining
14  * a copy of this software and associated documentation files
15  * (the "Software"), to deal in the Software without restriction,
16  * including without limitation the rights to use, copy, modify, merge,
17  * publish, distribute, sublicense, and/or sell copies of the Software,
18  * and to permit persons to whom the Software is furnished to do so,
19  * subject to the following conditions:
20  *
21  * The above copyright notice and this permission notice shall be
22  * included in all copies or substantial portions of the Software.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
28  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
29  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31  */
32 
33 /*
34  * The text above constitutes the entire PortAudio license; however,
35  * the PortAudio community also makes the following non-binding requests:
36  *
37  * Any person wishing to distribute modifications to the Software is
38  * requested to send the modifications to the original developer so that
39  * they can be incorporated into the canonical version. It is also
40  * requested that these non-binding requests be included along with the
41  * license above.
42  */
43 
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <memory.h>
47 #include <math.h>
48 #include "portaudio.h"
49 
50 #define NUM_SECONDS   (8)
51 #define SAMPLE_RATE   (44100)
52 #ifndef M_PI
53 #define M_PI  (3.14159265)
54 #endif
55 #define TABLE_SIZE        (200)
56 #define FRAMES_PER_BUFFER  (64)
57 #define MAX_CHANNELS        (8)
58 
59 typedef struct
60 {
61     short sine[TABLE_SIZE];
62     int32_t phases[MAX_CHANNELS];
63     int32_t numChannels;
64     int32_t sampsToGo;
65 }
66 paTestData;
67 
68 
inputCallback(const void * inputBuffer,void * outputBuffer,unsigned long framesPerBuffer,const PaStreamCallbackTimeInfo * timeInfo,PaStreamCallbackFlags statusFlags,void * userData)69 static int inputCallback( const void *inputBuffer, void *outputBuffer,
70                           unsigned long framesPerBuffer,
71                           const PaStreamCallbackTimeInfo* timeInfo,
72                           PaStreamCallbackFlags statusFlags,
73                           void *userData )
74 {
75     paTestData *data = (paTestData*)userData;
76     int finished = 0;
77     (void) inputBuffer; /* Prevent "unused variable" warnings. */
78     (void) outputBuffer; /* Prevent "unused variable" warnings. */
79 
80     data->sampsToGo -= framesPerBuffer;
81     if (data->sampsToGo <= 0)
82     {
83         data->sampsToGo = 0;
84         finished = 1;
85     }
86     return finished;
87 }
88 
outputCallback(const void * inputBuffer,void * outputBuffer,unsigned long framesPerBuffer,const PaStreamCallbackTimeInfo * timeInfo,PaStreamCallbackFlags statusFlags,void * userData)89 static int outputCallback( const void *inputBuffer, void *outputBuffer,
90                             unsigned long framesPerBuffer,
91                             const PaStreamCallbackTimeInfo* timeInfo,
92                             PaStreamCallbackFlags statusFlags,
93                             void *userData )
94 {
95     paTestData *data = (paTestData*)userData;
96     short *out = (short*)outputBuffer;
97     unsigned int i;
98     int finished = 0;
99     (void) inputBuffer; /* Prevent "unused variable" warnings. */
100 
101     for( i=0; i<framesPerBuffer; i++ )
102     {
103         for (int channelIndex = 0; channelIndex < data->numChannels; channelIndex++)
104         {
105             int phase = data->phases[channelIndex];
106             *out++ = data->sine[phase];
107             phase += channelIndex + 2;
108             if( phase >= TABLE_SIZE ) phase -= TABLE_SIZE;
109             data->phases[channelIndex] = phase;
110         }
111     }
112     return finished;
113 }
114 
115 /*******************************************************************/
116 int main(int argc, char **args);
main(int argc,char ** args)117 int main(int argc, char **args)
118 {
119     PaStreamParameters inputParameters;
120     PaStreamParameters outputParameters;
121     PaStream *inputStream;
122     PaStream *outputStream;
123     const PaDeviceInfo *deviceInfo;
124     PaError err;
125     paTestData data;
126     int i;
127     int totalSamps;
128     int inputDevice = -1;
129     int outputDevice = -1;
130 
131     printf("Test unplugging a USB device.\n");
132 
133     if( argc > 1 ) {
134        inputDevice = outputDevice = atoi( args[1] );
135        printf("Using device number %d.\n\n", inputDevice );
136     } else {
137        printf("Using default device.\n\n" );
138     }
139 
140     memset(&data, 0, sizeof(data));
141 
142     /* initialise sinusoidal wavetable */
143     for( i=0; i<TABLE_SIZE; i++ )
144     {
145         data.sine[i] = (short) (32767.0 * sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ));
146     }
147     data.numChannels = 2;
148     data.sampsToGo = totalSamps =  NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
149 
150 
151     err = Pa_Initialize();
152     if( err != paNoError ) goto error;
153 
154     if( inputDevice == -1 )
155         inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
156     else
157         inputParameters.device = inputDevice ;
158 
159     if (inputParameters.device == paNoDevice) {
160         fprintf(stderr,"Error: No default input device.\n");
161         goto error;
162     }
163 
164     if( outputDevice == -1 )
165         outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
166     else
167         outputParameters.device = outputDevice ;
168 
169     if (outputParameters.device == paNoDevice) {
170         fprintf(stderr,"Error: No default output device.\n");
171         goto error;
172     }
173 
174     inputParameters.channelCount = 2;
175     inputParameters.sampleFormat = paInt16;
176     deviceInfo = Pa_GetDeviceInfo( inputParameters.device );
177     if( deviceInfo == NULL )
178     {
179         fprintf( stderr, "No matching input device.\n" );
180         goto error;
181     }
182     inputParameters.suggestedLatency = deviceInfo->defaultLowInputLatency;
183     inputParameters.hostApiSpecificStreamInfo = NULL;
184     err = Pa_OpenStream(
185                 &inputStream,
186                 &inputParameters,
187                 NULL,
188                 SAMPLE_RATE,
189                 FRAMES_PER_BUFFER,
190                 0,
191                 inputCallback,
192                 &data );
193     if( err != paNoError ) goto error;
194 
195     outputParameters.channelCount = 2;
196     outputParameters.sampleFormat = paInt16;
197     deviceInfo = Pa_GetDeviceInfo( outputParameters.device );
198     if( deviceInfo == NULL )
199     {
200         fprintf( stderr, "No matching output device.\n" );
201         goto error;
202     }
203     outputParameters.suggestedLatency = deviceInfo->defaultLowOutputLatency;
204     outputParameters.hostApiSpecificStreamInfo = NULL;
205     err = Pa_OpenStream(
206                 &outputStream,
207                 NULL,
208                 &outputParameters,
209                 SAMPLE_RATE,
210                 FRAMES_PER_BUFFER,
211                 (paClipOff | paDitherOff),
212                 outputCallback,
213                 &data );
214     if( err != paNoError ) goto error;
215 
216     err = Pa_StartStream( inputStream );
217     if( err != paNoError ) goto error;
218     err = Pa_StartStream( outputStream );
219     if( err != paNoError ) goto error;
220 
221     printf("When you hear sound, unplug the USB device.\n");
222     do
223     {
224         Pa_Sleep(500);
225         printf("Frames remaining = %d\n", data.sampsToGo);
226         printf("Pa_IsStreamActive(inputStream) = %d\n", Pa_IsStreamActive(inputStream));
227         printf("Pa_IsStreamActive(outputStream) = %d\n", Pa_IsStreamActive(outputStream));
228     } while( Pa_IsStreamActive(inputStream) && Pa_IsStreamActive(outputStream) );
229 
230     err = Pa_CloseStream( inputStream );
231     if( err != paNoError ) goto error;
232     err = Pa_CloseStream( outputStream );
233     if( err != paNoError ) goto error;
234     Pa_Terminate();
235     return paNoError;
236 error:
237     Pa_Terminate();
238     fprintf( stderr, "An error occured while using the portaudio stream\n" );
239     fprintf( stderr, "Error number: %d\n", err );
240     fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
241     fprintf( stderr, "Host Error message: %s\n", Pa_GetLastHostErrorInfo()->errorText );
242     return err;
243 }
244