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