Version 2.1.1
[rtaudio-cdist.git] / RtAudio.cpp
1 /************************************************************************/
2 /*! \class RtAudio
3     \brief Realtime audio i/o C++ class.
4
5     RtAudio provides a common API (Application Programming Interface)
6     for realtime audio input/output across Linux (native ALSA and
7     OSS), SGI, Macintosh OS X (CoreAudio), and Windows (DirectSound
8     and ASIO) operating systems.
9
10     RtAudio WWW site: http://www-ccrma.stanford.edu/~gary/rtaudio/
11
12     RtAudio: a realtime audio i/o C++ class
13     Copyright (c) 2001-2002 Gary P. Scavone
14
15     Permission is hereby granted, free of charge, to any person
16     obtaining a copy of this software and associated documentation files
17     (the "Software"), to deal in the Software without restriction,
18     including without limitation the rights to use, copy, modify, merge,
19     publish, distribute, sublicense, and/or sell copies of the Software,
20     and to permit persons to whom the Software is furnished to do so,
21     subject to the following conditions:
22
23     The above copyright notice and this permission notice shall be
24     included in all copies or substantial portions of the Software.
25
26     Any person wishing to distribute modifications to the Software is
27     requested to send the modifications to the original developer so that
28     they can be incorporated into the canonical version.
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 // RtAudio: Version 2.1.1, 24 October 2002
41
42 #include "RtAudio.h"
43 #include <vector>
44 #include <stdio.h>
45 #include <iostream.h>
46
47 // Static variable definitions.
48 const unsigned int RtAudio :: SAMPLE_RATES[] = {
49   4000, 5512, 8000, 9600, 11025, 16000, 22050,
50   32000, 44100, 48000, 88200, 96000, 176400, 192000
51 };
52 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT8 = 1;
53 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT16 = 2;
54 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT24 = 4;
55 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT32 = 8;
56 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT32 = 16;
57 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT64 = 32;
58
59 #if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__)
60   #define MUTEX_INITIALIZE(A) InitializeCriticalSection(A)
61   #define MUTEX_LOCK(A)       EnterCriticalSection(A)
62   #define MUTEX_UNLOCK(A)     LeaveCriticalSection(A)
63 #else // pthread API
64   #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL)
65   #define MUTEX_LOCK(A)       pthread_mutex_lock(A)
66   #define MUTEX_UNLOCK(A)     pthread_mutex_unlock(A)
67 #endif
68
69 // *************************************************** //
70 //
71 // Public common (OS-independent) methods.
72 //
73 // *************************************************** //
74
75 RtAudio :: RtAudio()
76 {
77   initialize();
78
79   if (nDevices <= 0) {
80     sprintf(message, "RtAudio: no audio devices found!");
81     error(RtError::NO_DEVICES_FOUND);
82  }
83 }
84
85 RtAudio :: RtAudio(int *streamId,
86                    int outputDevice, int outputChannels,
87                    int inputDevice, int inputChannels,
88                    RTAUDIO_FORMAT format, int sampleRate,
89                    int *bufferSize, int numberOfBuffers)
90 {
91   initialize();
92
93   if (nDevices <= 0) {
94     sprintf(message, "RtAudio: no audio devices found!");
95     error(RtError::NO_DEVICES_FOUND);
96   }
97
98   try {
99     *streamId = openStream(outputDevice, outputChannels, inputDevice, inputChannels,
100                            format, sampleRate, bufferSize, numberOfBuffers);
101   }
102   catch (RtError &exception) {
103     // deallocate the RTAUDIO_DEVICE structures
104     if (devices) free(devices);
105     throw exception;
106   }
107 }
108
109 RtAudio :: ~RtAudio()
110 {
111   // close any existing streams
112   while ( streams.size() )
113     closeStream( streams.begin()->first );
114
115   // deallocate the RTAUDIO_DEVICE structures
116   if (devices) free(devices);
117 }
118
119 int RtAudio :: openStream(int outputDevice, int outputChannels,
120                           int inputDevice, int inputChannels,
121                           RTAUDIO_FORMAT format, int sampleRate,
122                           int *bufferSize, int numberOfBuffers)
123 {
124   static int streamKey = 0; // Unique stream identifier ... OK for multiple instances.
125
126   if (outputChannels < 1 && inputChannels < 1) {
127     sprintf(message,"RtAudio: one or both 'channel' parameters must be greater than zero.");
128     error(RtError::INVALID_PARAMETER);
129   }
130
131   if ( formatBytes(format) == 0 ) {
132     sprintf(message,"RtAudio: 'format' parameter value is undefined.");
133     error(RtError::INVALID_PARAMETER);
134   }
135
136   if ( outputChannels > 0 ) {
137     if (outputDevice > nDevices || outputDevice < 0) {
138       sprintf(message,"RtAudio: 'outputDevice' parameter value (%d) is invalid.", outputDevice);
139       error(RtError::INVALID_PARAMETER);
140     }
141   }
142
143   if ( inputChannels > 0 ) {
144     if (inputDevice > nDevices || inputDevice < 0) {
145       sprintf(message,"RtAudio: 'inputDevice' parameter value (%d) is invalid.", inputDevice);
146       error(RtError::INVALID_PARAMETER);
147     }
148   }
149
150   // Allocate a new stream structure.
151   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) calloc(1, sizeof(RTAUDIO_STREAM));
152   if (stream == NULL) {
153     sprintf(message, "RtAudio: memory allocation error!");
154     error(RtError::MEMORY_ERROR);
155   }
156   stream->mode = UNINITIALIZED;
157   MUTEX_INITIALIZE(&stream->mutex);
158
159   bool result = FAILURE;
160   int device, defaultDevice = 0;
161   STREAM_MODE mode;
162   int channels;
163   if ( outputChannels > 0 ) {
164
165     mode = OUTPUT;
166     channels = outputChannels;
167
168     if ( outputDevice == 0 ) { // Try default device first.
169       defaultDevice = getDefaultOutputDevice();
170       device = defaultDevice;
171     }
172     else
173       device = outputDevice - 1;
174
175     for (int i=-1; i<nDevices; i++) {
176       if (i >= 0 ) { 
177         if ( i == defaultDevice ) continue;
178         device = i;
179       }
180       if (devices[device].probed == false) {
181         // If the device wasn't successfully probed before, try it
182         // again now.
183         clearDeviceInfo(&devices[device]);
184         probeDeviceInfo(&devices[device]);
185       }
186       if ( devices[device].probed )
187         result = probeDeviceOpen(device, stream, mode, channels, sampleRate,
188                                  format, bufferSize, numberOfBuffers);
189       if (result == SUCCESS) break;
190       if ( outputDevice > 0 ) break;
191     }
192   }
193
194   if ( inputChannels > 0 && ( result == SUCCESS || outputChannels <= 0 ) ) {
195
196     mode = INPUT;
197     channels = inputChannels;
198
199     if ( inputDevice == 0 ) { // Try default device first.
200       defaultDevice = getDefaultInputDevice();
201       device = defaultDevice;
202     }
203     else
204       device = inputDevice - 1;
205
206     for (int i=-1; i<nDevices; i++) {
207       if (i >= 0 ) { 
208         if ( i == defaultDevice ) continue;
209         device = i;
210       }
211       if (devices[device].probed == false) {
212         // If the device wasn't successfully probed before, try it
213         // again now.
214         clearDeviceInfo(&devices[device]);
215         probeDeviceInfo(&devices[device]);
216       }
217       if ( devices[device].probed )
218         result = probeDeviceOpen(device, stream, mode, channels, sampleRate,
219                                  format, bufferSize, numberOfBuffers);
220       if (result == SUCCESS) break;
221       if ( outputDevice > 0 ) break;
222     }
223   }
224
225   streams[++streamKey] = (void *) stream;
226   if ( result == SUCCESS )
227     return streamKey;
228
229   // If we get here, all attempted probes failed.  Close any opened
230   // devices and delete the allocated stream.
231   closeStream(streamKey);
232   if ( ( outputDevice == 0 && outputChannels > 0 )
233        || ( inputDevice == 0 && inputChannels > 0 ) )
234     sprintf(message,"RtAudio: no devices found for given parameters.");
235   else
236     sprintf(message,"RtAudio: unable to open specified device(s) with given stream parameters.");
237   error(RtError::INVALID_PARAMETER);
238
239   return -1;
240 }
241
242 int RtAudio :: getDeviceCount(void)
243 {
244   return nDevices;
245 }
246
247 void RtAudio :: getDeviceInfo(int device, RTAUDIO_DEVICE *info)
248 {
249   if (device > nDevices || device < 1) {
250     sprintf(message, "RtAudio: invalid device specifier (%d)!", device);
251     error(RtError::INVALID_DEVICE);
252   }
253
254   int deviceIndex = device - 1;
255
256   // If the device wasn't successfully probed before, try it now (or again).
257   if (devices[deviceIndex].probed == false) {
258     clearDeviceInfo(&devices[deviceIndex]);
259     probeDeviceInfo(&devices[deviceIndex]);
260   }
261
262   // Clear the info structure.
263   memset(info, 0, sizeof(RTAUDIO_DEVICE));
264
265   strncpy(info->name, devices[deviceIndex].name, 128);
266   info->probed = devices[deviceIndex].probed;
267   if ( info->probed == true ) {
268     info->maxOutputChannels = devices[deviceIndex].maxOutputChannels;
269     info->maxInputChannels = devices[deviceIndex].maxInputChannels;
270     info->maxDuplexChannels = devices[deviceIndex].maxDuplexChannels;
271     info->minOutputChannels = devices[deviceIndex].minOutputChannels;
272     info->minInputChannels = devices[deviceIndex].minInputChannels;
273     info->minDuplexChannels = devices[deviceIndex].minDuplexChannels;
274     info->hasDuplexSupport = devices[deviceIndex].hasDuplexSupport;
275     info->nSampleRates = devices[deviceIndex].nSampleRates;
276     if (info->nSampleRates == -1) {
277       info->sampleRates[0] = devices[deviceIndex].sampleRates[0];
278       info->sampleRates[1] = devices[deviceIndex].sampleRates[1];
279     }
280     else {
281       for (int i=0; i<info->nSampleRates; i++)
282         info->sampleRates[i] = devices[deviceIndex].sampleRates[i];
283     }
284     info->nativeFormats = devices[deviceIndex].nativeFormats;
285     if ( deviceIndex == getDefaultOutputDevice() ||
286          deviceIndex == getDefaultInputDevice() )
287       info->isDefault = true;
288   }
289
290   return;
291 }
292
293 char * const RtAudio :: getStreamBuffer(int streamId)
294 {
295   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
296
297   return stream->userBuffer;
298 }
299
300 #if defined(__LINUX_ALSA__) || defined(__LINUX_OSS__) || defined(__IRIX_AL__)
301
302 extern "C" void *callbackHandler(void * ptr);
303
304 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
305 {
306   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
307
308   CALLBACK_INFO *info = (CALLBACK_INFO *) &stream->callbackInfo;
309   if ( info->usingCallback ) {
310     sprintf(message, "RtAudio: A callback is already set for this stream!");
311     error(RtError::WARNING);
312     return;
313   }
314
315   info->callback = (void *) callback;
316   info->userData = userData;
317   info->usingCallback = true;
318   info->object = (void *) this;
319   info->streamId = streamId;
320
321   int err = pthread_create(&info->thread, NULL, callbackHandler, &stream->callbackInfo);
322
323   if (err) {
324     info->usingCallback = false;
325     sprintf(message, "RtAudio: error starting callback thread!");
326     error(RtError::THREAD_ERROR);
327   }
328 }
329
330 void RtAudio :: cancelStreamCallback(int streamId)
331 {
332   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
333
334   if (stream->callbackInfo.usingCallback) {
335
336     if (stream->state == STREAM_RUNNING)
337       stopStream( streamId );
338
339     MUTEX_LOCK(&stream->mutex);
340
341     stream->callbackInfo.usingCallback = false;
342     pthread_cancel(stream->callbackInfo.thread);
343     pthread_join(stream->callbackInfo.thread, NULL);
344     stream->callbackInfo.thread = 0;
345     stream->callbackInfo.callback = NULL;
346     stream->callbackInfo.userData = NULL;
347
348     MUTEX_UNLOCK(&stream->mutex);
349   }
350 }
351
352 #endif
353
354 // *************************************************** //
355 //
356 // OS/API-specific methods.
357 //
358 // *************************************************** //
359
360 #if defined(__MACOSX_CORE__)
361
362 // The OS X CoreAudio API is designed to use a separate callback
363 // procedure for each of its audio devices.  A single RtAudio duplex
364 // stream using two different devices is supported here, though it
365 // cannot be guaranteed to always behave correctly because we cannot
366 // synchronize these two callbacks.  This same functionality can be
367 // achieved with better synchrony by opening two separate streams for
368 // the devices and using RtAudio blocking calls (i.e. tickStream()).
369 //
370 // The possibility of having multiple RtAudio streams accessing the
371 // same CoreAudio device is not currently supported.  The problem
372 // involves the inability to install our callbackHandler function for
373 // the same device more than once.  I experimented with a workaround
374 // for this, but it requires an additional buffer for mixing output
375 // data before filling the CoreAudio device buffer.  In the end, I
376 // decided it wasn't worth supporting.
377 //
378 // Property listeners are currently not used.  The issue is what could
379 // be done if a critical stream parameter (buffer size, sample rate,
380 // device disconnect) notification arrived.  The listeners entail
381 // quite a bit of extra code and most likely, a user program wouldn't
382 // be prepared for the result anyway.  Some initial listener code is
383 // commented out.
384
385 void RtAudio :: initialize(void)
386 {
387   OSStatus err = noErr;
388   UInt32 dataSize;
389   AudioDeviceID *deviceList = NULL;
390   nDevices = 0;
391
392   // Find out how many audio devices there are, if any.
393   err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &dataSize, NULL);
394   if (err != noErr) {
395     sprintf(message, "RtAudio: OSX error getting device info!");
396     error(RtError::SYSTEM_ERROR);
397   }
398
399   nDevices = dataSize / sizeof(AudioDeviceID);
400   if (nDevices == 0) return;
401
402   //  Allocate the RTAUDIO_DEVICE structures.
403   devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
404   if (devices == NULL) {
405     sprintf(message, "RtAudio: memory allocation error!");
406     error(RtError::MEMORY_ERROR);
407   }
408
409   // Make space for the devices we are about to get.
410   deviceList = (AudioDeviceID   *) malloc( dataSize );
411   if (deviceList == NULL) {
412     sprintf(message, "RtAudio: memory allocation error!");
413     error(RtError::MEMORY_ERROR);
414   }
415
416   // Get the array of AudioDeviceIDs.
417   err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &dataSize, (void *) deviceList);
418   if (err != noErr) {
419     free(deviceList);
420     sprintf(message, "RtAudio: OSX error getting device properties!");
421     error(RtError::SYSTEM_ERROR);
422   }
423
424   // Write device identifiers to device structures and then
425   // probe the device capabilities.
426   for (int i=0; i<nDevices; i++) {
427     devices[i].id[0] = deviceList[i];
428     //probeDeviceInfo(&devices[i]);
429   }
430
431   free(deviceList);
432 }
433
434 int RtAudio :: getDefaultInputDevice(void)
435 {
436   AudioDeviceID id;
437   UInt32 dataSize = sizeof( AudioDeviceID );
438
439   OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultInputDevice,
440                                               &dataSize, &id );
441
442   if (result != noErr) {
443     sprintf( message, "RtAudio: OSX error getting default input device." );
444     error(RtError::WARNING);
445     return 0;
446   }
447
448   for ( int i=0; i<nDevices; i++ ) {
449     if ( id == devices[i].id[0] ) return i;
450   }
451
452   return 0;
453 }
454
455 int RtAudio :: getDefaultOutputDevice(void)
456 {
457   AudioDeviceID id;
458   UInt32 dataSize = sizeof( AudioDeviceID );
459
460   OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice,
461                                               &dataSize, &id );
462
463   if (result != noErr) {
464     sprintf( message, "RtAudio: OSX error getting default output device." );
465     error(RtError::WARNING);
466     return 0;
467   }
468
469   for ( int i=0; i<nDevices; i++ ) {
470     if ( id == devices[i].id[0] ) return i;
471   }
472
473   return 0;
474 }
475
476 static bool deviceSupportsFormat( AudioDeviceID id, bool isInput,
477                                   AudioStreamBasicDescription   *desc, bool isDuplex )
478 {
479   OSStatus result = noErr;
480   UInt32 dataSize = sizeof( AudioStreamBasicDescription );
481
482   result = AudioDeviceGetProperty( id, 0, isInput,
483                                    kAudioDevicePropertyStreamFormatSupported,
484                                    &dataSize, desc );
485
486   if (result == kAudioHardwareNoError) {
487     if ( isDuplex ) {
488       result = AudioDeviceGetProperty( id, 0, true,
489                                        kAudioDevicePropertyStreamFormatSupported,
490                                        &dataSize, desc );
491
492
493       if (result != kAudioHardwareNoError)
494         return false;
495     }
496     return true;
497   }
498
499   return false;
500 }
501
502 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
503 {
504   OSStatus err = noErr;
505
506   // Get the device manufacturer and name.
507   char  name[256];
508   char  fullname[512];
509   UInt32 dataSize = 256;
510   err = AudioDeviceGetProperty( info->id[0], 0, false,
511                                 kAudioDevicePropertyDeviceManufacturer,
512                                 &dataSize, name );
513   if (err != noErr) {
514     sprintf( message, "RtAudio: OSX error getting device manufacturer." );
515     error(RtError::DEBUG_WARNING);
516     return;
517   }
518   strncpy(fullname, name, 256);
519   strcat(fullname, ": " );
520
521   dataSize = 256;
522   err = AudioDeviceGetProperty( info->id[0], 0, false,
523                                 kAudioDevicePropertyDeviceName,
524                                 &dataSize, name );
525   if (err != noErr) {
526     sprintf( message, "RtAudio: OSX error getting device name." );
527     error(RtError::DEBUG_WARNING);
528     return;
529   }
530   strncat(fullname, name, 254);
531   strncat(info->name, fullname, 128);
532
533   // Get output channel information.
534   unsigned int i, minChannels, maxChannels, nStreams = 0;
535   AudioBufferList       *bufferList = nil;
536   err = AudioDeviceGetPropertyInfo( info->id[0], 0, false,
537                                     kAudioDevicePropertyStreamConfiguration,
538                                     &dataSize, NULL );
539   if (err == noErr && dataSize > 0) {
540     bufferList = (AudioBufferList *) malloc( dataSize );
541     if (bufferList == NULL) {
542       sprintf(message, "RtAudio: memory allocation error!");
543       error(RtError::DEBUG_WARNING);
544       return;
545     }
546
547     err = AudioDeviceGetProperty( info->id[0], 0, false,
548                                   kAudioDevicePropertyStreamConfiguration,
549                                   &dataSize, bufferList );
550     if (err == noErr) {
551       maxChannels = 0;
552       minChannels = 1000;
553       nStreams = bufferList->mNumberBuffers;
554       for ( i=0; i<nStreams; i++ ) {
555         maxChannels += bufferList->mBuffers[i].mNumberChannels;
556         if ( bufferList->mBuffers[i].mNumberChannels < minChannels )
557           minChannels = bufferList->mBuffers[i].mNumberChannels;
558       }
559     }
560   }
561   if (err != noErr || dataSize <= 0) {
562     sprintf( message, "RtAudio: OSX error getting output channels for device (%s).", info->name );
563     error(RtError::DEBUG_WARNING);
564     return;
565   }
566
567   free (bufferList);
568   if ( nStreams ) {
569     if ( maxChannels > 0 )
570       info->maxOutputChannels = maxChannels;
571     if ( minChannels > 0 )
572       info->minOutputChannels = minChannels;
573   }
574
575   // Get input channel information.
576   bufferList = nil;
577   err = AudioDeviceGetPropertyInfo( info->id[0], 0, true,
578                                     kAudioDevicePropertyStreamConfiguration,
579                                     &dataSize, NULL );
580   if (err == noErr && dataSize > 0) {
581     bufferList = (AudioBufferList *) malloc( dataSize );
582     if (bufferList == NULL) {
583       sprintf(message, "RtAudio: memory allocation error!");
584       error(RtError::DEBUG_WARNING);
585       return;
586     }
587     err = AudioDeviceGetProperty( info->id[0], 0, true,
588                                   kAudioDevicePropertyStreamConfiguration,
589                                   &dataSize, bufferList );
590     if (err == noErr) {
591       maxChannels = 0;
592       minChannels = 1000;
593       nStreams = bufferList->mNumberBuffers;
594       for ( i=0; i<nStreams; i++ ) {
595         if ( bufferList->mBuffers[i].mNumberChannels < minChannels )
596           minChannels = bufferList->mBuffers[i].mNumberChannels;
597         maxChannels += bufferList->mBuffers[i].mNumberChannels;
598       }
599     }
600   }
601   if (err != noErr || dataSize <= 0) {
602     sprintf( message, "RtAudio: OSX error getting input channels for device (%s).", info->name );
603     error(RtError::DEBUG_WARNING);
604     return;
605   }
606
607   free (bufferList);
608   if ( nStreams ) {
609     if ( maxChannels > 0 )
610       info->maxInputChannels = maxChannels;
611     if ( minChannels > 0 )
612       info->minInputChannels = minChannels;
613   }
614
615   // If device opens for both playback and capture, we determine the channels.
616   if (info->maxOutputChannels > 0 && info->maxInputChannels > 0) {
617     info->hasDuplexSupport = true;
618     info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
619       info->maxInputChannels : info->maxOutputChannels;
620     info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
621       info->minInputChannels : info->minOutputChannels;
622   }
623
624   // Probe the device sample rate and data format parameters.  The
625   // core audio query mechanism is performed on a "stream"
626   // description, which can have a variable number of channels and
627   // apply to input or output only.
628
629   // Create a stream description structure.
630   AudioStreamBasicDescription   description;
631   dataSize = sizeof( AudioStreamBasicDescription );
632   memset(&description, 0, sizeof(AudioStreamBasicDescription));
633   bool isInput = false;
634   if ( info->maxOutputChannels == 0 ) isInput = true;
635   bool isDuplex = false;
636   if ( info->maxDuplexChannels > 0 ) isDuplex = true;
637
638   // Determine the supported sample rates.
639   info->nSampleRates = 0;
640   for (i=0; i<MAX_SAMPLE_RATES; i++) {
641     description.mSampleRate = (double) SAMPLE_RATES[i];
642     if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
643       info->sampleRates[info->nSampleRates++] = SAMPLE_RATES[i];
644   }
645
646   if (info->nSampleRates == 0) {
647     sprintf( message, "RtAudio: No supported sample rates found for OSX device (%s).", info->name );
648     error(RtError::DEBUG_WARNING);
649     return;
650   }
651
652   // Check for continuous sample rate support.
653   description.mSampleRate = kAudioStreamAnyRate;
654   if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) {
655     info->sampleRates[1] = info->sampleRates[info->nSampleRates-1];
656     info->nSampleRates = -1;
657   }
658
659   // Determine the supported data formats.
660   info->nativeFormats = 0;
661   description.mFormatID = kAudioFormatLinearPCM;
662   description.mBitsPerChannel = 8;
663   description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian;
664   if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
665     info->nativeFormats |= RTAUDIO_SINT8;
666   else {
667     description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
668     if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
669       info->nativeFormats |= RTAUDIO_SINT8;
670   }
671
672   description.mBitsPerChannel = 16;
673   description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
674   if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
675     info->nativeFormats |= RTAUDIO_SINT16;
676   else {
677     description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
678     if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
679       info->nativeFormats |= RTAUDIO_SINT16;
680   }
681
682   description.mBitsPerChannel = 32;
683   description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
684   if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
685     info->nativeFormats |= RTAUDIO_SINT32;
686   else {
687     description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
688     if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
689       info->nativeFormats |= RTAUDIO_SINT32;
690   }
691
692   description.mBitsPerChannel = 24;
693   description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsAlignedHigh | kLinearPCMFormatFlagIsBigEndian;
694   if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
695     info->nativeFormats |= RTAUDIO_SINT24;
696   else {
697     description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
698     if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
699       info->nativeFormats |= RTAUDIO_SINT24;
700   }
701
702   description.mBitsPerChannel = 32;
703   description.mFormatFlags = kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian;
704   if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
705     info->nativeFormats |= RTAUDIO_FLOAT32;
706   else {
707     description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
708     if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
709       info->nativeFormats |= RTAUDIO_FLOAT32;
710   }
711
712   description.mBitsPerChannel = 64;
713   description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
714   if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
715     info->nativeFormats |= RTAUDIO_FLOAT64;
716   else {
717     description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
718     if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
719       info->nativeFormats |= RTAUDIO_FLOAT64;
720   }
721
722   // Check that we have at least one supported format.
723   if (info->nativeFormats == 0) {
724     sprintf(message, "RtAudio: OSX PCM device (%s) data format not supported by RtAudio.",
725             info->name);
726     error(RtError::DEBUG_WARNING);
727     return;
728   }
729
730   info->probed = true;
731 }
732
733 OSStatus callbackHandler(AudioDeviceID inDevice,
734                          const AudioTimeStamp* inNow,
735                          const AudioBufferList* inInputData,
736                          const AudioTimeStamp* inInputTime,
737                          AudioBufferList* outOutputData,
738                          const AudioTimeStamp* inOutputTime, 
739                          void* infoPointer)
740 {
741   CALLBACK_INFO *info = (CALLBACK_INFO *) infoPointer;
742
743   RtAudio *object = (RtAudio *) info->object;
744   try {
745     object->callbackEvent( info->streamId, inDevice, (void *)inInputData, (void *)outOutputData );
746   }
747   catch (RtError &exception) {
748     fprintf(stderr, "\nCallback handler error (%s)!\n\n", exception.getMessage());
749     return kAudioHardwareUnspecifiedError;
750   }
751
752   return kAudioHardwareNoError;
753 }
754
755 /*
756 OSStatus deviceListener(AudioDeviceID inDevice,
757                         UInt32 channel,
758                         Boolean isInput,
759                         AudioDevicePropertyID propertyID,
760                         void* infoPointer)
761 {
762   CALLBACK_INFO *info = (CALLBACK_INFO *) infoPointer;
763
764   RtAudio *object = (RtAudio *) info->object;
765   try {
766     object->settingChange( info->streamId );
767   }
768   catch (RtError &exception) {
769     fprintf(stderr, "\nDevice listener error (%s)!\n\n", exception.getMessage());
770     return kAudioHardwareUnspecifiedError;
771   }
772
773   return kAudioHardwareNoError;
774 }
775 */
776
777 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
778                                 STREAM_MODE mode, int channels, 
779                                 int sampleRate, RTAUDIO_FORMAT format,
780                                 int *bufferSize, int numberOfBuffers)
781 {
782   // Check to make sure we don't already have a stream accessing this device.
783   RTAUDIO_STREAM *streamPtr;
784   std::map<int, void *>::const_iterator i;
785   for ( i=streams.begin(); i!=streams.end(); ++i ) {
786     streamPtr = (RTAUDIO_STREAM *) i->second;
787     if ( streamPtr->device[0] == device || streamPtr->device[1] == device ) {
788       sprintf(message, "RtAudio: no current OS X support for multiple streams accessing the same device!");
789       error(RtError::WARNING);
790       return FAILURE;
791     }
792   }
793
794   // Setup for stream mode.
795   bool isInput = false;
796   AudioDeviceID id = devices[device].id[0];
797   if ( mode == INPUT ) isInput = true;
798
799   // Search for a stream which contains the desired number of channels.
800   OSStatus err = noErr;
801   UInt32 dataSize;
802   unsigned int deviceChannels, nStreams;
803   UInt32 iChannel = 0, iStream = 0;
804   AudioBufferList       *bufferList = nil;
805   err = AudioDeviceGetPropertyInfo( id, 0, isInput,
806                                     kAudioDevicePropertyStreamConfiguration,
807                                     &dataSize, NULL );
808
809   if (err == noErr && dataSize > 0) {
810     bufferList = (AudioBufferList *) malloc( dataSize );
811     if (bufferList == NULL) {
812       sprintf(message, "RtAudio: memory allocation error!");
813       error(RtError::DEBUG_WARNING);
814       return FAILURE;
815     }
816     err = AudioDeviceGetProperty( id, 0, isInput,
817                                   kAudioDevicePropertyStreamConfiguration,
818                                   &dataSize, bufferList );
819
820     if (err == noErr) {
821       stream->deInterleave[mode] = false;
822       nStreams = bufferList->mNumberBuffers;
823       for ( iStream=0; iStream<nStreams; iStream++ ) {
824         if ( bufferList->mBuffers[iStream].mNumberChannels >= (unsigned int) channels ) break;
825         iChannel += bufferList->mBuffers[iStream].mNumberChannels;
826       }
827       // If we didn't find a single stream above, see if we can meet
828       // the channel specification in mono mode (i.e. using separate
829       // non-interleaved buffers).  This can only work if there are N
830       // consecutive one-channel streams, where N is the number of
831       // desired channels.
832       iChannel = 0;
833       if ( iStream >= nStreams && nStreams >= (unsigned int) channels ) {
834         int counter = 0;
835         for ( iStream=0; iStream<nStreams; iStream++ ) {
836           if ( bufferList->mBuffers[iStream].mNumberChannels == 1 )
837             counter++;
838           else
839             counter = 0;
840           if ( counter == channels ) {
841             iStream -= channels - 1;
842             iChannel -= channels - 1;
843             stream->deInterleave[mode] = true;
844             break;
845           }
846           iChannel += bufferList->mBuffers[iStream].mNumberChannels;
847         }
848       }
849     }
850   }
851   if (err != noErr || dataSize <= 0) {
852     if ( bufferList ) free( bufferList );
853     sprintf( message, "RtAudio: OSX error getting channels for device (%s).", devices[device].name );
854     error(RtError::DEBUG_WARNING);
855     return FAILURE;
856   }
857
858   if (iStream >= nStreams) {
859     free (bufferList);
860     sprintf( message, "RtAudio: unable to find OSX audio stream on device (%s) for requested channels (%d).",
861              devices[device].name, channels );
862     error(RtError::DEBUG_WARNING);
863     return FAILURE;
864   }
865
866   // This is ok even for mono mode ... it gets updated later.
867   deviceChannels = bufferList->mBuffers[iStream].mNumberChannels;
868   free (bufferList);
869
870   // Determine the buffer size.
871   AudioValueRange       bufferRange;
872   dataSize = sizeof(AudioValueRange);
873   err = AudioDeviceGetProperty( id, 0, isInput,
874                                 kAudioDevicePropertyBufferSizeRange,
875                                 &dataSize, &bufferRange);
876   if (err != noErr) {
877     sprintf( message, "RtAudio: OSX error getting buffer size range for device (%s).",
878              devices[device].name );
879     error(RtError::DEBUG_WARNING);
880     return FAILURE;
881   }
882
883   long bufferBytes = *bufferSize * deviceChannels * formatBytes(RTAUDIO_FLOAT32);
884   if (bufferRange.mMinimum > bufferBytes) bufferBytes = (int) bufferRange.mMinimum;
885   else if (bufferRange.mMaximum < bufferBytes) bufferBytes = (int) bufferRange.mMaximum;
886
887   // Set the buffer size.  For mono mode, I'm assuming we only need to
888   // make this setting for the first channel.
889   UInt32 theSize = (UInt32) bufferBytes;
890   dataSize = sizeof( UInt32);
891   err = AudioDeviceSetProperty(id, NULL, 0, isInput,
892                                kAudioDevicePropertyBufferSize,
893                                dataSize, &theSize);
894   if (err != noErr) {
895     sprintf( message, "RtAudio: OSX error setting the buffer size for device (%s).",
896              devices[device].name );
897     error(RtError::DEBUG_WARNING);
898     return FAILURE;
899   }
900
901   // If attempting to setup a duplex stream, the bufferSize parameter
902   // MUST be the same in both directions!
903   *bufferSize = bufferBytes / ( deviceChannels * formatBytes(RTAUDIO_FLOAT32) );
904   if ( stream->mode == OUTPUT && mode == INPUT && *bufferSize != stream->bufferSize ) {
905     sprintf( message, "RtAudio: OSX error setting buffer size for duplex stream on device (%s).",
906              devices[device].name );
907     error(RtError::DEBUG_WARNING);
908     return FAILURE;
909   }
910
911   stream->bufferSize = *bufferSize;
912   stream->nBuffers = 1;
913
914   // Set the stream format description.  Do for each channel in mono mode.
915   AudioStreamBasicDescription   description;
916   dataSize = sizeof( AudioStreamBasicDescription );
917   if ( stream->deInterleave[mode] ) nStreams = channels;
918   else nStreams = 1;
919   for ( unsigned int i=0; i<nStreams; i++, iChannel++ ) {
920
921     err = AudioDeviceGetProperty( id, iChannel, isInput,
922                                   kAudioDevicePropertyStreamFormat,
923                                   &dataSize, &description );
924     if (err != noErr) {
925       sprintf( message, "RtAudio: OSX error getting stream format for device (%s).", devices[device].name );
926       error(RtError::DEBUG_WARNING);
927       return FAILURE;
928     }
929
930     // Set the sample rate and data format id.
931     description.mSampleRate = (double) sampleRate;
932     description.mFormatID = kAudioFormatLinearPCM;
933     err = AudioDeviceSetProperty( id, NULL, iChannel, isInput,
934                                   kAudioDevicePropertyStreamFormat,
935                                   dataSize, &description );
936     if (err != noErr) {
937       sprintf( message, "RtAudio: OSX error setting sample rate or data format for device (%s).", devices[device].name );
938       error(RtError::DEBUG_WARNING);
939       return FAILURE;
940     }
941   }
942
943   // Check whether we need byte-swapping (assuming OS X host is big-endian).
944   iChannel -= nStreams;
945   err = AudioDeviceGetProperty( id, iChannel, isInput,
946                                 kAudioDevicePropertyStreamFormat,
947                                 &dataSize, &description );
948   if (err != noErr) {
949     sprintf( message, "RtAudio: OSX error getting stream format for device (%s).", devices[device].name );
950     error(RtError::DEBUG_WARNING);
951     return FAILURE;
952   }
953
954   stream->doByteSwap[mode] = false;
955   if ( !description.mFormatFlags & kLinearPCMFormatFlagIsBigEndian )
956     stream->doByteSwap[mode] = true;
957
958   // From the CoreAudio documentation, PCM data must be supplied as
959   // 32-bit floats.
960   stream->userFormat = format;
961   stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
962
963   if ( stream->deInterleave[mode] )
964     stream->nDeviceChannels[mode] = channels;
965   else
966     stream->nDeviceChannels[mode] = description.mChannelsPerFrame;
967   stream->nUserChannels[mode] = channels;
968
969   // Set handle and flags for buffer conversion.
970   stream->handle[mode] = iStream;
971   stream->doConvertBuffer[mode] = false;
972   if (stream->userFormat != stream->deviceFormat[mode])
973     stream->doConvertBuffer[mode] = true;
974   if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
975     stream->doConvertBuffer[mode] = true;
976   if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode])
977     stream->doConvertBuffer[mode] = true;
978
979   // Allocate necessary internal buffers.
980   if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
981
982     long buffer_bytes;
983     if (stream->nUserChannels[0] >= stream->nUserChannels[1])
984       buffer_bytes = stream->nUserChannels[0];
985     else
986       buffer_bytes = stream->nUserChannels[1];
987
988     buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
989     if (stream->userBuffer) free(stream->userBuffer);
990     stream->userBuffer = (char *) calloc(buffer_bytes, 1);
991     if (stream->userBuffer == NULL)
992       goto memory_error;
993   }
994
995   if ( stream->deInterleave[mode] ) {
996
997     long buffer_bytes;
998     bool makeBuffer = true;
999     if ( mode == OUTPUT )
1000       buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1001     else { // mode == INPUT
1002       buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
1003       if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
1004         long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1005         if ( buffer_bytes < bytes_out ) makeBuffer = false;
1006       }
1007     }
1008
1009     if ( makeBuffer ) {
1010       buffer_bytes *= *bufferSize;
1011       if (stream->deviceBuffer) free(stream->deviceBuffer);
1012       stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
1013       if (stream->deviceBuffer == NULL)
1014         goto memory_error;
1015
1016       // If not de-interleaving, we point stream->deviceBuffer to the
1017       // OS X supplied device buffer before doing any necessary data
1018       // conversions.  This presents a problem if we have a duplex
1019       // stream using one device which needs de-interleaving and
1020       // another device which doesn't.  So, save a pointer to our own
1021       // device buffer in the CALLBACK_INFO structure.
1022       stream->callbackInfo.buffers = stream->deviceBuffer;
1023     }
1024   }
1025
1026   stream->sampleRate = sampleRate;
1027   stream->device[mode] = device;
1028   stream->state = STREAM_STOPPED;
1029   stream->callbackInfo.object = (void *) this;
1030   stream->callbackInfo.waitTime = (unsigned long) (200000.0 * stream->bufferSize / stream->sampleRate);
1031   stream->callbackInfo.device[mode] = id;
1032   if ( stream->mode == OUTPUT && mode == INPUT && stream->device[0] == device )
1033     // Only one callback procedure per device.
1034     stream->mode = DUPLEX;
1035   else {
1036     err = AudioDeviceAddIOProc( id, callbackHandler, (void *) &stream->callbackInfo );
1037     if (err != noErr) {
1038       sprintf( message, "RtAudio: OSX error setting callback for device (%s).", devices[device].name );
1039       error(RtError::DEBUG_WARNING);
1040       return FAILURE;
1041     }
1042     if ( stream->mode == OUTPUT && mode == INPUT )
1043       stream->mode = DUPLEX;
1044     else
1045       stream->mode = mode;
1046   }
1047
1048   // If we wanted to use property listeners, they would be setup here.
1049
1050   return SUCCESS;
1051
1052  memory_error:
1053   if (stream->userBuffer) {
1054     free(stream->userBuffer);
1055     stream->userBuffer = 0;
1056   }
1057   sprintf(message, "RtAudio: OSX error allocating buffer memory (%s).", devices[device].name);
1058   error(RtError::WARNING);
1059   return FAILURE;
1060 }
1061
1062 void RtAudio :: cancelStreamCallback(int streamId)
1063 {
1064   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1065
1066   if (stream->callbackInfo.usingCallback) {
1067
1068     if (stream->state == STREAM_RUNNING)
1069       stopStream( streamId );
1070
1071     MUTEX_LOCK(&stream->mutex);
1072
1073     stream->callbackInfo.usingCallback = false;
1074     stream->callbackInfo.userData = NULL;
1075     stream->state = STREAM_STOPPED;
1076     stream->callbackInfo.callback = NULL;
1077
1078     MUTEX_UNLOCK(&stream->mutex);
1079   }
1080 }
1081
1082 void RtAudio :: closeStream(int streamId)
1083 {
1084   // We don't want an exception to be thrown here because this
1085   // function is called by our class destructor.  So, do our own
1086   // streamId check.
1087   if ( streams.find( streamId ) == streams.end() ) {
1088     sprintf(message, "RtAudio: invalid stream identifier!");
1089     error(RtError::WARNING);
1090     return;
1091   }
1092
1093   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
1094
1095   AudioDeviceID id;
1096   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
1097     id = devices[stream->device[0]].id[0];
1098     if (stream->state == STREAM_RUNNING)
1099       AudioDeviceStop( id, callbackHandler );
1100     AudioDeviceRemoveIOProc( id, callbackHandler );
1101   }
1102
1103   if (stream->mode == INPUT || ( stream->mode == DUPLEX && stream->device[0] != stream->device[1]) ) {
1104     id = devices[stream->device[1]].id[0];
1105     if (stream->state == STREAM_RUNNING)
1106       AudioDeviceStop( id, callbackHandler );
1107     AudioDeviceRemoveIOProc( id, callbackHandler );
1108   }
1109
1110   pthread_mutex_destroy(&stream->mutex);
1111
1112   if (stream->userBuffer)
1113     free(stream->userBuffer);
1114
1115   if ( stream->deInterleave[0] || stream->deInterleave[1] )
1116     free(stream->callbackInfo.buffers);
1117
1118   free(stream);
1119   streams.erase(streamId);
1120 }
1121
1122 void RtAudio :: startStream(int streamId)
1123 {
1124   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1125
1126   MUTEX_LOCK(&stream->mutex);
1127
1128   if (stream->state == STREAM_RUNNING)
1129     goto unlock;
1130
1131   OSStatus err;
1132   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
1133
1134     err = AudioDeviceStart(devices[stream->device[0]].id[0], callbackHandler);
1135     if (err != noErr) {
1136       sprintf(message, "RtAudio: OSX error starting callback procedure on device (%s).",
1137               devices[stream->device[0]].name);
1138       MUTEX_UNLOCK(&stream->mutex);
1139       error(RtError::DRIVER_ERROR);
1140     }
1141   }
1142
1143   if (stream->mode == INPUT || ( stream->mode == DUPLEX && stream->device[0] != stream->device[1]) ) {
1144
1145     err = AudioDeviceStart(devices[stream->device[1]].id[0], callbackHandler);
1146     if (err != noErr) {
1147       sprintf(message, "RtAudio: OSX error starting input callback procedure on device (%s).",
1148               devices[stream->device[0]].name);
1149       MUTEX_UNLOCK(&stream->mutex);
1150       error(RtError::DRIVER_ERROR);
1151     }
1152   }
1153
1154   stream->callbackInfo.streamId = streamId;
1155   stream->state = STREAM_RUNNING;
1156   stream->callbackInfo.blockTick = true;
1157   stream->callbackInfo.stopStream = false;
1158
1159  unlock:
1160   MUTEX_UNLOCK(&stream->mutex);
1161 }
1162
1163 void RtAudio :: stopStream(int streamId)
1164 {
1165   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1166
1167   MUTEX_LOCK(&stream->mutex);
1168
1169   if (stream->state == STREAM_STOPPED)
1170     goto unlock;
1171
1172   OSStatus err;
1173   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
1174
1175     err = AudioDeviceStop(devices[stream->device[0]].id[0], callbackHandler);
1176     if (err != noErr) {
1177       sprintf(message, "RtAudio: OSX error stopping callback procedure on device (%s).",
1178               devices[stream->device[0]].name);
1179       MUTEX_UNLOCK(&stream->mutex);
1180       error(RtError::DRIVER_ERROR);
1181     }
1182   }
1183
1184   if (stream->mode == INPUT || ( stream->mode == DUPLEX && stream->device[0] != stream->device[1]) ) {
1185
1186     err = AudioDeviceStop(devices[stream->device[1]].id[0], callbackHandler);
1187     if (err != noErr) {
1188       sprintf(message, "RtAudio: OSX error stopping input callback procedure on device (%s).",
1189               devices[stream->device[0]].name);
1190       MUTEX_UNLOCK(&stream->mutex);
1191       error(RtError::DRIVER_ERROR);
1192     }
1193   }
1194
1195   stream->state = STREAM_STOPPED;
1196
1197  unlock:
1198   MUTEX_UNLOCK(&stream->mutex);
1199 }
1200
1201 void RtAudio :: abortStream(int streamId)
1202 {
1203   stopStream( streamId );
1204 }
1205
1206 // I don't know how this function can be implemented.
1207 int RtAudio :: streamWillBlock(int streamId)
1208 {
1209   sprintf(message, "RtAudio: streamWillBlock() cannot be implemented for OS X.");
1210   error(RtError::WARNING);
1211   return 0;
1212 }
1213
1214 void RtAudio :: tickStream(int streamId)
1215 {
1216   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1217
1218   if (stream->state == STREAM_STOPPED)
1219     return;
1220
1221   if (stream->callbackInfo.usingCallback) {
1222     sprintf(message, "RtAudio: tickStream() should not be used when a callback function is set!");
1223     error(RtError::WARNING);
1224     return;
1225   }
1226
1227   // Block waiting here until the user data is processed in callbackEvent().
1228   while ( stream->callbackInfo.blockTick )
1229     usleep(stream->callbackInfo.waitTime);
1230
1231   MUTEX_LOCK(&stream->mutex);
1232
1233   stream->callbackInfo.blockTick = true;
1234
1235   MUTEX_UNLOCK(&stream->mutex);
1236 }
1237
1238 void RtAudio :: callbackEvent( int streamId, DEVICE_ID deviceId, void *inData, void *outData )
1239 {
1240   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1241
1242   CALLBACK_INFO *info;
1243   AudioBufferList *inBufferList = (AudioBufferList *) inData;
1244   AudioBufferList *outBufferList = (AudioBufferList *) outData;
1245
1246   if (stream->state == STREAM_STOPPED) return;
1247
1248   info = (CALLBACK_INFO *) &stream->callbackInfo;
1249   if ( !info->usingCallback ) {
1250     // Block waiting here until we get new user data in tickStream().
1251     while ( !info->blockTick )
1252       usleep(info->waitTime);
1253   }
1254   else if ( info->stopStream ) {
1255     // Check if the stream should be stopped (via the previous user
1256     // callback return value).  We stop the stream here, rather than
1257     // after the function call, so that output data can first be
1258     // processed.
1259     this->stopStream(info->streamId);
1260     return;
1261   }
1262
1263   MUTEX_LOCK(&stream->mutex);
1264
1265   // Invoke user callback first, to get fresh output data.  Don't
1266   // invoke the user callback if duplex mode, the input/output devices
1267   // are different, and this function is called for the input device.
1268   if ( info->usingCallback && (stream->mode != DUPLEX || deviceId == info->device[0] ) ) {
1269     RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) info->callback;
1270     info->stopStream = callback(stream->userBuffer, stream->bufferSize, info->userData);
1271   }
1272
1273   if ( stream->mode == OUTPUT || ( stream->mode == DUPLEX && deviceId == info->device[0] ) ) {
1274
1275     if (stream->doConvertBuffer[0]) {
1276
1277       if ( !stream->deInterleave[0] )
1278         stream->deviceBuffer = (char *) outBufferList->mBuffers[stream->handle[0]].mData;
1279       else
1280         stream->deviceBuffer = (char *) stream->callbackInfo.buffers;
1281
1282       convertStreamBuffer(stream, OUTPUT);
1283       if ( stream->doByteSwap[0] )
1284         byteSwapBuffer(stream->deviceBuffer,
1285                        stream->bufferSize * stream->nDeviceChannels[0],
1286                        stream->deviceFormat[0]);
1287
1288       if ( stream->deInterleave[0] ) {
1289         int bufferBytes = outBufferList->mBuffers[stream->handle[0]].mDataByteSize;
1290         for ( int i=0; i<stream->nDeviceChannels[0]; i++ ) {
1291           memcpy(outBufferList->mBuffers[stream->handle[0]+i].mData,
1292                  &stream->deviceBuffer[i*bufferBytes], bufferBytes );
1293         }
1294       }
1295
1296     }
1297     else {
1298       if (stream->doByteSwap[0])
1299         byteSwapBuffer(stream->userBuffer,
1300                        stream->bufferSize * stream->nUserChannels[0],
1301                        stream->userFormat);
1302
1303       memcpy(outBufferList->mBuffers[stream->handle[0]].mData,
1304              stream->userBuffer,
1305              outBufferList->mBuffers[stream->handle[0]].mDataByteSize );
1306     }
1307   }
1308
1309   if ( stream->mode == INPUT || ( stream->mode == DUPLEX && deviceId == info->device[1] ) ) {
1310
1311     if (stream->doConvertBuffer[1]) {
1312
1313       if ( stream->deInterleave[1] ) {
1314         stream->deviceBuffer = (char *) stream->callbackInfo.buffers;
1315         int bufferBytes = inBufferList->mBuffers[stream->handle[1]].mDataByteSize;
1316         for ( int i=0; i<stream->nDeviceChannels[1]; i++ ) {
1317           memcpy(&stream->deviceBuffer[i*bufferBytes],
1318                  inBufferList->mBuffers[stream->handle[1]+i].mData, bufferBytes );
1319         }
1320       }
1321       else
1322         stream->deviceBuffer = (char *) inBufferList->mBuffers[stream->handle[1]].mData;
1323
1324       if ( stream->doByteSwap[1] )
1325         byteSwapBuffer(stream->deviceBuffer,
1326                        stream->bufferSize * stream->nDeviceChannels[1],
1327                        stream->deviceFormat[1]);
1328       convertStreamBuffer(stream, INPUT);
1329
1330     }
1331     else {
1332       memcpy(stream->userBuffer,
1333              inBufferList->mBuffers[stream->handle[1]].mData,
1334              inBufferList->mBuffers[stream->handle[1]].mDataByteSize );
1335
1336       if (stream->doByteSwap[1])
1337         byteSwapBuffer(stream->userBuffer,
1338                        stream->bufferSize * stream->nUserChannels[1],
1339                        stream->userFormat);
1340     }
1341   }
1342
1343   if ( !info->usingCallback && (stream->mode != DUPLEX || deviceId == info->device[1] ) )
1344     info->blockTick = false;
1345
1346   MUTEX_UNLOCK(&stream->mutex);
1347
1348 }
1349
1350 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
1351 {
1352   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1353
1354   stream->callbackInfo.callback = (void *) callback;
1355   stream->callbackInfo.userData = userData;
1356   stream->callbackInfo.usingCallback = true;
1357 }
1358
1359 //******************** End of __MACOSX_CORE__ *********************//
1360
1361 #elif defined(__LINUX_ALSA__)
1362
1363 #define MAX_DEVICES 16
1364
1365 void RtAudio :: initialize(void)
1366 {
1367   int card, result, device;
1368   char name[32];
1369   const char *cardId;
1370   char deviceNames[MAX_DEVICES][32];
1371   snd_ctl_t *handle;
1372   snd_ctl_card_info_t *info;
1373   snd_ctl_card_info_alloca(&info);
1374
1375   // Count cards and devices
1376   nDevices = 0;
1377   card = -1;
1378   snd_card_next(&card);
1379   while ( card >= 0 ) {
1380     sprintf(name, "hw:%d", card);
1381     result = snd_ctl_open(&handle, name, 0);
1382     if (result < 0) {
1383       sprintf(message, "RtAudio: ALSA control open (%i): %s.", card, snd_strerror(result));
1384       error(RtError::DEBUG_WARNING);
1385       goto next_card;
1386                 }
1387     result = snd_ctl_card_info(handle, info);
1388                 if (result < 0) {
1389       sprintf(message, "RtAudio: ALSA control hardware info (%i): %s.", card, snd_strerror(result));
1390       error(RtError::DEBUG_WARNING);
1391       goto next_card;
1392                 }
1393     cardId = snd_ctl_card_info_get_id(info);
1394                 device = -1;
1395                 while (1) {
1396       result = snd_ctl_pcm_next_device(handle, &device);
1397                         if (result < 0) {
1398         sprintf(message, "RtAudio: ALSA control next device (%i): %s.", card, snd_strerror(result));
1399         error(RtError::DEBUG_WARNING);
1400         break;
1401       }
1402                         if (device < 0)
1403         break;
1404       if ( strlen(cardId) )
1405         sprintf( deviceNames[nDevices++], "hw:%s,%d", cardId, device );
1406       else
1407         sprintf( deviceNames[nDevices++], "hw:%d,%d", card, device );
1408       if ( nDevices > MAX_DEVICES ) break;
1409     }
1410     if ( nDevices > MAX_DEVICES ) break;
1411   next_card:
1412     snd_ctl_close(handle);
1413     snd_card_next(&card);
1414   }
1415
1416   if (nDevices == 0) return;
1417
1418   //  Allocate the RTAUDIO_DEVICE structures.
1419   devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
1420   if (devices == NULL) {
1421     sprintf(message, "RtAudio: memory allocation error!");
1422     error(RtError::MEMORY_ERROR);
1423   }
1424
1425   // Write device ascii identifiers to device structures and then
1426   // probe the device capabilities.
1427   for (int i=0; i<nDevices; i++) {
1428     strncpy(devices[i].name, deviceNames[i], 32);
1429     //probeDeviceInfo(&devices[i]);
1430   }
1431 }
1432
1433 int RtAudio :: getDefaultInputDevice(void)
1434 {
1435   // No ALSA API functions for default devices.
1436   return 0;
1437 }
1438
1439 int RtAudio :: getDefaultOutputDevice(void)
1440 {
1441   // No ALSA API functions for default devices.
1442   return 0;
1443 }
1444
1445 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
1446 {
1447   int err;
1448   int open_mode = SND_PCM_ASYNC;
1449   snd_pcm_t *handle;
1450   snd_ctl_t *chandle;
1451   snd_pcm_stream_t stream;
1452         snd_pcm_info_t *pcminfo;
1453         snd_pcm_info_alloca(&pcminfo);
1454   snd_pcm_hw_params_t *params;
1455   snd_pcm_hw_params_alloca(&params);
1456   char name[32];
1457   char *card;
1458
1459   // Open the control interface for this card.
1460   strncpy( name, info->name, 32 );
1461   card = strtok(name, ",");
1462   err = snd_ctl_open(&chandle, card, 0);
1463   if (err < 0) {
1464     sprintf(message, "RtAudio: ALSA control open (%s): %s.", card, snd_strerror(err));
1465     error(RtError::DEBUG_WARNING);
1466     return;
1467   }
1468   unsigned int dev = (unsigned int) atoi( strtok(NULL, ",") );
1469
1470   // First try for playback
1471   stream = SND_PCM_STREAM_PLAYBACK;
1472   snd_pcm_info_set_device(pcminfo, dev);
1473   snd_pcm_info_set_subdevice(pcminfo, 0);
1474   snd_pcm_info_set_stream(pcminfo, stream);
1475
1476   if ((err = snd_ctl_pcm_info(chandle, pcminfo)) < 0) {
1477     if (err == -ENOENT) {
1478       sprintf(message, "RtAudio: ALSA pcm device (%s) doesn't handle output!", info->name);
1479       error(RtError::DEBUG_WARNING);
1480     }
1481     else {
1482       sprintf(message, "RtAudio: ALSA snd_ctl_pcm_info error for device (%s) output: %s",
1483               info->name, snd_strerror(err));
1484       error(RtError::DEBUG_WARNING);
1485     }
1486     goto capture_probe;
1487   }
1488
1489   err = snd_pcm_open(&handle, info->name, stream, open_mode | SND_PCM_NONBLOCK );
1490   if (err < 0) {
1491     if ( err == EBUSY )
1492       sprintf(message, "RtAudio: ALSA pcm playback device (%s) is busy: %s.",
1493               info->name, snd_strerror(err));
1494     else
1495       sprintf(message, "RtAudio: ALSA pcm playback open (%s) error: %s.",
1496               info->name, snd_strerror(err));
1497     error(RtError::DEBUG_WARNING);
1498     goto capture_probe;
1499   }
1500
1501   // We have an open device ... allocate the parameter structure.
1502   err = snd_pcm_hw_params_any(handle, params);
1503   if (err < 0) {
1504     snd_pcm_close(handle);
1505     sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.",
1506             info->name, snd_strerror(err));
1507     error(RtError::WARNING);
1508     goto capture_probe;
1509   }
1510
1511   // Get output channel information.
1512   info->minOutputChannels = snd_pcm_hw_params_get_channels_min(params);
1513   info->maxOutputChannels = snd_pcm_hw_params_get_channels_max(params);
1514
1515   snd_pcm_close(handle);
1516
1517  capture_probe:
1518   // Now try for capture
1519   stream = SND_PCM_STREAM_CAPTURE;
1520   snd_pcm_info_set_stream(pcminfo, stream);
1521
1522   err = snd_ctl_pcm_info(chandle, pcminfo);
1523   snd_ctl_close(chandle);
1524   if ( err < 0 ) {
1525     if (err == -ENOENT) {
1526       sprintf(message, "RtAudio: ALSA pcm device (%s) doesn't handle input!", info->name);
1527       error(RtError::DEBUG_WARNING);
1528     }
1529     else {
1530       sprintf(message, "RtAudio: ALSA snd_ctl_pcm_info error for device (%s) input: %s",
1531               info->name, snd_strerror(err));
1532       error(RtError::DEBUG_WARNING);
1533     }
1534     if (info->maxOutputChannels == 0)
1535       // didn't open for playback either ... device invalid
1536       return;
1537     goto probe_parameters;
1538   }
1539
1540   err = snd_pcm_open(&handle, info->name, stream, open_mode | SND_PCM_NONBLOCK);
1541   if (err < 0) {
1542     if ( err == EBUSY )
1543       sprintf(message, "RtAudio: ALSA pcm capture device (%s) is busy: %s.",
1544               info->name, snd_strerror(err));
1545     else
1546       sprintf(message, "RtAudio: ALSA pcm capture open (%s) error: %s.",
1547               info->name, snd_strerror(err));
1548     error(RtError::DEBUG_WARNING);
1549     if (info->maxOutputChannels == 0)
1550       // didn't open for playback either ... device invalid
1551       return;
1552     goto probe_parameters;
1553   }
1554
1555   // We have an open capture device ... allocate the parameter structure.
1556   err = snd_pcm_hw_params_any(handle, params);
1557   if (err < 0) {
1558     snd_pcm_close(handle);
1559     sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.",
1560             info->name, snd_strerror(err));
1561     error(RtError::WARNING);
1562     if (info->maxOutputChannels > 0)
1563       goto probe_parameters;
1564     else
1565       return;
1566   }
1567
1568   // Get input channel information.
1569   info->minInputChannels = snd_pcm_hw_params_get_channels_min(params);
1570   info->maxInputChannels = snd_pcm_hw_params_get_channels_max(params);
1571
1572   snd_pcm_close(handle);
1573
1574   // If device opens for both playback and capture, we determine the channels.
1575   if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
1576     goto probe_parameters;
1577
1578   info->hasDuplexSupport = true;
1579   info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
1580     info->maxInputChannels : info->maxOutputChannels;
1581   info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
1582     info->minInputChannels : info->minOutputChannels;
1583
1584  probe_parameters:
1585   // At this point, we just need to figure out the supported data
1586   // formats and sample rates.  We'll proceed by opening the device in
1587   // the direction with the maximum number of channels, or playback if
1588   // they are equal.  This might limit our sample rate options, but so
1589   // be it.
1590
1591   if (info->maxOutputChannels >= info->maxInputChannels)
1592     stream = SND_PCM_STREAM_PLAYBACK;
1593   else
1594     stream = SND_PCM_STREAM_CAPTURE;
1595
1596   err = snd_pcm_open(&handle, info->name, stream, open_mode);
1597   if (err < 0) {
1598     sprintf(message, "RtAudio: ALSA pcm (%s) won't reopen during probe: %s.",
1599             info->name, snd_strerror(err));
1600     error(RtError::WARNING);
1601     return;
1602   }
1603
1604   // We have an open device ... allocate the parameter structure.
1605   err = snd_pcm_hw_params_any(handle, params);
1606   if (err < 0) {
1607     snd_pcm_close(handle);
1608     sprintf(message, "RtAudio: ALSA hardware reopen probe error (%s): %s.",
1609             info->name, snd_strerror(err));
1610     error(RtError::WARNING);
1611     return;
1612   }
1613
1614   // Test a non-standard sample rate to see if continuous rate is supported.
1615   int dir = 0;
1616   if (snd_pcm_hw_params_test_rate(handle, params, 35500, dir) == 0) {
1617     // It appears that continuous sample rate support is available.
1618     info->nSampleRates = -1;
1619     info->sampleRates[0] = snd_pcm_hw_params_get_rate_min(params, &dir);
1620     info->sampleRates[1] = snd_pcm_hw_params_get_rate_max(params, &dir);
1621   }
1622   else {
1623     // No continuous rate support ... test our discrete set of sample rate values.
1624     info->nSampleRates = 0;
1625     for (int i=0; i<MAX_SAMPLE_RATES; i++) {
1626       if (snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0) {
1627         info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
1628         info->nSampleRates++;
1629       }
1630     }
1631     if (info->nSampleRates == 0) {
1632       snd_pcm_close(handle);
1633       return;
1634     }
1635   }
1636
1637   // Probe the supported data formats ... we don't care about endian-ness just yet
1638   snd_pcm_format_t format;
1639   info->nativeFormats = 0;
1640   format = SND_PCM_FORMAT_S8;
1641   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1642     info->nativeFormats |= RTAUDIO_SINT8;
1643   format = SND_PCM_FORMAT_S16;
1644   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1645     info->nativeFormats |= RTAUDIO_SINT16;
1646   format = SND_PCM_FORMAT_S24;
1647   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1648     info->nativeFormats |= RTAUDIO_SINT24;
1649   format = SND_PCM_FORMAT_S32;
1650   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1651     info->nativeFormats |= RTAUDIO_SINT32;
1652   format = SND_PCM_FORMAT_FLOAT;
1653   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1654     info->nativeFormats |= RTAUDIO_FLOAT32;
1655   format = SND_PCM_FORMAT_FLOAT64;
1656   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1657     info->nativeFormats |= RTAUDIO_FLOAT64;
1658
1659   // Check that we have at least one supported format
1660   if (info->nativeFormats == 0) {
1661     snd_pcm_close(handle);
1662     sprintf(message, "RtAudio: ALSA PCM device (%s) data format not supported by RtAudio.",
1663             info->name);
1664     error(RtError::WARNING);
1665     return;
1666   }
1667
1668   // That's all ... close the device and return
1669   snd_pcm_close(handle);
1670   info->probed = true;
1671   return;
1672 }
1673
1674 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
1675                                 STREAM_MODE mode, int channels, 
1676                                 int sampleRate, RTAUDIO_FORMAT format,
1677                                 int *bufferSize, int numberOfBuffers)
1678 {
1679 #if defined(__RTAUDIO_DEBUG__)
1680   snd_output_t *out;
1681   snd_output_stdio_attach(&out, stderr, 0);
1682 #endif
1683
1684   // I'm not using the "plug" interface ... too much inconsistent behavior.
1685   const char *name = devices[device].name;
1686
1687   snd_pcm_stream_t alsa_stream;
1688   if (mode == OUTPUT)
1689     alsa_stream = SND_PCM_STREAM_PLAYBACK;
1690   else
1691     alsa_stream = SND_PCM_STREAM_CAPTURE;
1692
1693   int err;
1694   snd_pcm_t *handle;
1695   int alsa_open_mode = SND_PCM_ASYNC;
1696   err = snd_pcm_open(&handle, name, alsa_stream, alsa_open_mode);
1697   if (err < 0) {
1698     sprintf(message,"RtAudio: ALSA pcm device (%s) won't open: %s.",
1699             name, snd_strerror(err));
1700     error(RtError::WARNING);
1701     return FAILURE;
1702   }
1703
1704   // Fill the parameter structure.
1705   snd_pcm_hw_params_t *hw_params;
1706   snd_pcm_hw_params_alloca(&hw_params);
1707   err = snd_pcm_hw_params_any(handle, hw_params);
1708   if (err < 0) {
1709     snd_pcm_close(handle);
1710     sprintf(message, "RtAudio: ALSA error getting parameter handle (%s): %s.",
1711             name, snd_strerror(err));
1712     error(RtError::WARNING);
1713     return FAILURE;
1714   }
1715
1716 #if defined(__RTAUDIO_DEBUG__)
1717   fprintf(stderr, "\nRtAudio: ALSA dump hardware params just after device open:\n\n");
1718   snd_pcm_hw_params_dump(hw_params, out);
1719 #endif
1720
1721
1722   // Set access ... try interleaved access first, then non-interleaved
1723   if ( !snd_pcm_hw_params_test_access( handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) ) {
1724     err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
1725   }
1726   else if ( !snd_pcm_hw_params_test_access( handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED) ) {
1727                 err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED);
1728     stream->deInterleave[mode] = true;
1729   }
1730   else {
1731     snd_pcm_close(handle);
1732     sprintf(message, "RtAudio: ALSA device (%s) access not supported by RtAudio.", name);
1733     error(RtError::WARNING);
1734     return FAILURE;
1735   }
1736
1737   if (err < 0) {
1738     snd_pcm_close(handle);
1739     sprintf(message, "RtAudio: ALSA error setting access ( (%s): %s.", name, snd_strerror(err));
1740     error(RtError::WARNING);
1741     return FAILURE;
1742   }
1743
1744   // Determine how to set the device format.
1745   stream->userFormat = format;
1746   snd_pcm_format_t device_format;
1747
1748   if (format == RTAUDIO_SINT8)
1749     device_format = SND_PCM_FORMAT_S8;
1750   else if (format == RTAUDIO_SINT16)
1751     device_format = SND_PCM_FORMAT_S16;
1752   else if (format == RTAUDIO_SINT24)
1753     device_format = SND_PCM_FORMAT_S24;
1754   else if (format == RTAUDIO_SINT32)
1755     device_format = SND_PCM_FORMAT_S32;
1756   else if (format == RTAUDIO_FLOAT32)
1757     device_format = SND_PCM_FORMAT_FLOAT;
1758   else if (format == RTAUDIO_FLOAT64)
1759     device_format = SND_PCM_FORMAT_FLOAT64;
1760
1761   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1762     stream->deviceFormat[mode] = format;
1763     goto set_format;
1764   }
1765
1766   // The user requested format is not natively supported by the device.
1767   device_format = SND_PCM_FORMAT_FLOAT64;
1768   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1769     stream->deviceFormat[mode] = RTAUDIO_FLOAT64;
1770     goto set_format;
1771   }
1772
1773   device_format = SND_PCM_FORMAT_FLOAT;
1774   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1775     stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
1776     goto set_format;
1777   }
1778
1779   device_format = SND_PCM_FORMAT_S32;
1780   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1781     stream->deviceFormat[mode] = RTAUDIO_SINT32;
1782     goto set_format;
1783   }
1784
1785   device_format = SND_PCM_FORMAT_S24;
1786   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1787     stream->deviceFormat[mode] = RTAUDIO_SINT24;
1788     goto set_format;
1789   }
1790
1791   device_format = SND_PCM_FORMAT_S16;
1792   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1793     stream->deviceFormat[mode] = RTAUDIO_SINT16;
1794     goto set_format;
1795   }
1796
1797   device_format = SND_PCM_FORMAT_S8;
1798   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1799     stream->deviceFormat[mode] = RTAUDIO_SINT8;
1800     goto set_format;
1801   }
1802
1803   // If we get here, no supported format was found.
1804   sprintf(message,"RtAudio: ALSA pcm device (%s) data format not supported by RtAudio.", name);
1805   snd_pcm_close(handle);
1806   error(RtError::WARNING);
1807   return FAILURE;
1808
1809  set_format:
1810   err = snd_pcm_hw_params_set_format(handle, hw_params, device_format);
1811   if (err < 0) {
1812     snd_pcm_close(handle);
1813     sprintf(message, "RtAudio: ALSA error setting format (%s): %s.",
1814             name, snd_strerror(err));
1815     error(RtError::WARNING);
1816     return FAILURE;
1817   }
1818
1819   // Determine whether byte-swaping is necessary.
1820   stream->doByteSwap[mode] = false;
1821   if (device_format != SND_PCM_FORMAT_S8) {
1822     err = snd_pcm_format_cpu_endian(device_format);
1823     if (err == 0)
1824       stream->doByteSwap[mode] = true;
1825     else if (err < 0) {
1826       snd_pcm_close(handle);
1827       sprintf(message, "RtAudio: ALSA error getting format endian-ness (%s): %s.",
1828               name, snd_strerror(err));
1829       error(RtError::WARNING);
1830       return FAILURE;
1831     }
1832   }
1833
1834   // Set the sample rate.
1835   err = snd_pcm_hw_params_set_rate(handle, hw_params, (unsigned int)sampleRate, 0);
1836   if (err < 0) {
1837     snd_pcm_close(handle);
1838     sprintf(message, "RtAudio: ALSA error setting sample rate (%d) on device (%s): %s.",
1839             sampleRate, name, snd_strerror(err));
1840     error(RtError::WARNING);
1841     return FAILURE;
1842   }
1843
1844   // Determine the number of channels for this device.  We support a possible
1845   // minimum device channel number > than the value requested by the user.
1846   stream->nUserChannels[mode] = channels;
1847   int device_channels = snd_pcm_hw_params_get_channels_max(hw_params);
1848   if (device_channels < channels) {
1849     snd_pcm_close(handle);
1850     sprintf(message, "RtAudio: channels (%d) not supported by device (%s).",
1851             channels, name);
1852     error(RtError::WARNING);
1853     return FAILURE;
1854   }
1855
1856   device_channels = snd_pcm_hw_params_get_channels_min(hw_params);
1857   if (device_channels < channels) device_channels = channels;
1858   stream->nDeviceChannels[mode] = device_channels;
1859
1860   // Set the device channels.
1861   err = snd_pcm_hw_params_set_channels(handle, hw_params, device_channels);
1862   if (err < 0) {
1863     snd_pcm_close(handle);
1864     sprintf(message, "RtAudio: ALSA error setting channels (%d) on device (%s): %s.",
1865             device_channels, name, snd_strerror(err));
1866     error(RtError::WARNING);
1867     return FAILURE;
1868   }
1869
1870   // Set the buffer number, which in ALSA is referred to as the "period".
1871   int dir;
1872   int periods = numberOfBuffers;
1873   // Even though the hardware might allow 1 buffer, it won't work reliably.
1874   if (periods < 2) periods = 2;
1875   err = snd_pcm_hw_params_get_periods_min(hw_params, &dir);
1876   if (err > periods) periods = err;
1877   err = snd_pcm_hw_params_get_periods_max(hw_params, &dir);
1878   if (err < periods) periods = err;
1879
1880   err = snd_pcm_hw_params_set_periods(handle, hw_params, periods, 0);
1881   if (err < 0) {
1882     snd_pcm_close(handle);
1883     sprintf(message, "RtAudio: ALSA error setting periods (%s): %s.",
1884             name, snd_strerror(err));
1885     error(RtError::WARNING);
1886     return FAILURE;
1887   }
1888
1889   // Set the buffer (or period) size.
1890   err = snd_pcm_hw_params_get_period_size_min(hw_params, &dir);
1891   if (err > *bufferSize) *bufferSize = err;
1892
1893   err = snd_pcm_hw_params_set_period_size(handle, hw_params, *bufferSize, 0);
1894   if (err < 0) {
1895     snd_pcm_close(handle);
1896     sprintf(message, "RtAudio: ALSA error setting period size (%s): %s.",
1897             name, snd_strerror(err));
1898     error(RtError::WARNING);
1899     return FAILURE;
1900   }
1901
1902   // If attempting to setup a duplex stream, the bufferSize parameter
1903   // MUST be the same in both directions!
1904   if ( stream->mode == OUTPUT && mode == INPUT && *bufferSize != stream->bufferSize ) {
1905     sprintf( message, "RtAudio: ALSA error setting buffer size for duplex stream on device (%s).",
1906              name );
1907     error(RtError::DEBUG_WARNING);
1908     return FAILURE;
1909   }
1910
1911   stream->bufferSize = *bufferSize;
1912
1913   // Install the hardware configuration
1914   err = snd_pcm_hw_params(handle, hw_params);
1915   if (err < 0) {
1916     snd_pcm_close(handle);
1917     sprintf(message, "RtAudio: ALSA error installing hardware configuration (%s): %s.",
1918             name, snd_strerror(err));
1919     error(RtError::WARNING);
1920     return FAILURE;
1921   }
1922
1923 #if defined(__RTAUDIO_DEBUG__)
1924   fprintf(stderr, "\nRtAudio: ALSA dump hardware params after installation:\n\n");
1925   snd_pcm_hw_params_dump(hw_params, out);
1926 #endif
1927
1928   /*
1929   // Install the software configuration
1930   snd_pcm_sw_params_t *sw_params = NULL;
1931   snd_pcm_sw_params_alloca(&sw_params);
1932   snd_pcm_sw_params_current(handle, sw_params);
1933   err = snd_pcm_sw_params(handle, sw_params);
1934   if (err < 0) {
1935     snd_pcm_close(handle);
1936     sprintf(message, "RtAudio: ALSA error installing software configuration (%s): %s.",
1937             name, snd_strerror(err));
1938     error(RtError::WARNING);
1939     return FAILURE;
1940   }
1941   */
1942
1943   // Set handle and flags for buffer conversion
1944   stream->handle[mode] = handle;
1945   stream->doConvertBuffer[mode] = false;
1946   if (stream->userFormat != stream->deviceFormat[mode])
1947     stream->doConvertBuffer[mode] = true;
1948   if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
1949     stream->doConvertBuffer[mode] = true;
1950   if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode])
1951     stream->doConvertBuffer[mode] = true;
1952
1953   // Allocate necessary internal buffers
1954   if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
1955
1956     long buffer_bytes;
1957     if (stream->nUserChannels[0] >= stream->nUserChannels[1])
1958       buffer_bytes = stream->nUserChannels[0];
1959     else
1960       buffer_bytes = stream->nUserChannels[1];
1961
1962     buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
1963     if (stream->userBuffer) free(stream->userBuffer);
1964     stream->userBuffer = (char *) calloc(buffer_bytes, 1);
1965     if (stream->userBuffer == NULL)
1966       goto memory_error;
1967   }
1968
1969   if ( stream->doConvertBuffer[mode] ) {
1970
1971     long buffer_bytes;
1972     bool makeBuffer = true;
1973     if ( mode == OUTPUT )
1974       buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1975     else { // mode == INPUT
1976       buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
1977       if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
1978         long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1979         if ( buffer_bytes < bytes_out ) makeBuffer = false;
1980       }
1981     }
1982
1983     if ( makeBuffer ) {
1984       buffer_bytes *= *bufferSize;
1985       if (stream->deviceBuffer) free(stream->deviceBuffer);
1986       stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
1987       if (stream->deviceBuffer == NULL)
1988         goto memory_error;
1989     }
1990   }
1991
1992   stream->device[mode] = device;
1993   stream->state = STREAM_STOPPED;
1994   if ( stream->mode == OUTPUT && mode == INPUT )
1995     // We had already set up an output stream.
1996     stream->mode = DUPLEX;
1997   else
1998     stream->mode = mode;
1999   stream->nBuffers = periods;
2000   stream->sampleRate = sampleRate;
2001
2002   return SUCCESS;
2003
2004  memory_error:
2005   if (stream->handle[0]) {
2006     snd_pcm_close(stream->handle[0]);
2007     stream->handle[0] = 0;
2008   }
2009   if (stream->handle[1]) {
2010     snd_pcm_close(stream->handle[1]);
2011     stream->handle[1] = 0;
2012   }
2013   if (stream->userBuffer) {
2014     free(stream->userBuffer);
2015     stream->userBuffer = 0;
2016   }
2017   sprintf(message, "RtAudio: ALSA error allocating buffer memory (%s).", name);
2018   error(RtError::WARNING);
2019   return FAILURE;
2020 }
2021
2022 void RtAudio :: closeStream(int streamId)
2023 {
2024   // We don't want an exception to be thrown here because this
2025   // function is called by our class destructor.  So, do our own
2026   // streamId check.
2027   if ( streams.find( streamId ) == streams.end() ) {
2028     sprintf(message, "RtAudio: invalid stream identifier!");
2029     error(RtError::WARNING);
2030     return;
2031   }
2032
2033   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
2034
2035   if (stream->callbackInfo.usingCallback) {
2036     pthread_cancel(stream->callbackInfo.thread);
2037     pthread_join(stream->callbackInfo.thread, NULL);
2038   }
2039
2040   if (stream->state == STREAM_RUNNING) {
2041     if (stream->mode == OUTPUT || stream->mode == DUPLEX)
2042       snd_pcm_drop(stream->handle[0]);
2043     if (stream->mode == INPUT || stream->mode == DUPLEX)
2044       snd_pcm_drop(stream->handle[1]);
2045   }
2046
2047   pthread_mutex_destroy(&stream->mutex);
2048
2049   if (stream->handle[0])
2050     snd_pcm_close(stream->handle[0]);
2051
2052   if (stream->handle[1])
2053     snd_pcm_close(stream->handle[1]);
2054
2055   if (stream->userBuffer)
2056     free(stream->userBuffer);
2057
2058   if (stream->deviceBuffer)
2059     free(stream->deviceBuffer);
2060
2061   free(stream);
2062   streams.erase(streamId);
2063 }
2064
2065 void RtAudio :: startStream(int streamId)
2066 {
2067   // This method calls snd_pcm_prepare if the device isn't already in that state.
2068
2069   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2070
2071   MUTEX_LOCK(&stream->mutex);
2072
2073   if (stream->state == STREAM_RUNNING)
2074     goto unlock;
2075
2076   int err;
2077   snd_pcm_state_t state;
2078   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2079     state = snd_pcm_state(stream->handle[0]);
2080     if (state != SND_PCM_STATE_PREPARED) {
2081       err = snd_pcm_prepare(stream->handle[0]);
2082       if (err < 0) {
2083         sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.",
2084                 devices[stream->device[0]].name, snd_strerror(err));
2085         MUTEX_UNLOCK(&stream->mutex);
2086         error(RtError::DRIVER_ERROR);
2087       }
2088     }
2089   }
2090
2091   if (stream->mode == INPUT || stream->mode == DUPLEX) {
2092     state = snd_pcm_state(stream->handle[1]);
2093     if (state != SND_PCM_STATE_PREPARED) {
2094       err = snd_pcm_prepare(stream->handle[1]);
2095       if (err < 0) {
2096         sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.",
2097                 devices[stream->device[1]].name, snd_strerror(err));
2098         MUTEX_UNLOCK(&stream->mutex);
2099         error(RtError::DRIVER_ERROR);
2100       }
2101     }
2102   }
2103   stream->state = STREAM_RUNNING;
2104
2105  unlock:
2106   MUTEX_UNLOCK(&stream->mutex);
2107 }
2108
2109 void RtAudio :: stopStream(int streamId)
2110 {
2111   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2112
2113   MUTEX_LOCK(&stream->mutex);
2114
2115   if (stream->state == STREAM_STOPPED)
2116     goto unlock;
2117
2118   int err;
2119   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2120     err = snd_pcm_drain(stream->handle[0]);
2121     if (err < 0) {
2122       sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
2123               devices[stream->device[0]].name, snd_strerror(err));
2124       MUTEX_UNLOCK(&stream->mutex);
2125       error(RtError::DRIVER_ERROR);
2126     }
2127   }
2128
2129   if (stream->mode == INPUT || stream->mode == DUPLEX) {
2130     err = snd_pcm_drain(stream->handle[1]);
2131     if (err < 0) {
2132       sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
2133               devices[stream->device[1]].name, snd_strerror(err));
2134       MUTEX_UNLOCK(&stream->mutex);
2135       error(RtError::DRIVER_ERROR);
2136     }
2137   }
2138   stream->state = STREAM_STOPPED;
2139
2140  unlock:
2141   MUTEX_UNLOCK(&stream->mutex);
2142 }
2143
2144 void RtAudio :: abortStream(int streamId)
2145 {
2146   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2147
2148   MUTEX_LOCK(&stream->mutex);
2149
2150   if (stream->state == STREAM_STOPPED)
2151     goto unlock;
2152
2153   int err;
2154   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2155     err = snd_pcm_drop(stream->handle[0]);
2156     if (err < 0) {
2157       sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
2158               devices[stream->device[0]].name, snd_strerror(err));
2159       MUTEX_UNLOCK(&stream->mutex);
2160       error(RtError::DRIVER_ERROR);
2161     }
2162   }
2163
2164   if (stream->mode == INPUT || stream->mode == DUPLEX) {
2165     err = snd_pcm_drop(stream->handle[1]);
2166     if (err < 0) {
2167       sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
2168               devices[stream->device[1]].name, snd_strerror(err));
2169       MUTEX_UNLOCK(&stream->mutex);
2170       error(RtError::DRIVER_ERROR);
2171     }
2172   }
2173   stream->state = STREAM_STOPPED;
2174
2175  unlock:
2176   MUTEX_UNLOCK(&stream->mutex);
2177 }
2178
2179 int RtAudio :: streamWillBlock(int streamId)
2180 {
2181   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2182
2183   MUTEX_LOCK(&stream->mutex);
2184
2185   int err = 0, frames = 0;
2186   if (stream->state == STREAM_STOPPED)
2187     goto unlock;
2188
2189   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2190     err = snd_pcm_avail_update(stream->handle[0]);
2191     if (err < 0) {
2192       sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.",
2193               devices[stream->device[0]].name, snd_strerror(err));
2194       MUTEX_UNLOCK(&stream->mutex);
2195       error(RtError::DRIVER_ERROR);
2196     }
2197   }
2198
2199   frames = err;
2200
2201   if (stream->mode == INPUT || stream->mode == DUPLEX) {
2202     err = snd_pcm_avail_update(stream->handle[1]);
2203     if (err < 0) {
2204       sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.",
2205               devices[stream->device[1]].name, snd_strerror(err));
2206       MUTEX_UNLOCK(&stream->mutex);
2207       error(RtError::DRIVER_ERROR);
2208     }
2209     if (frames > err) frames = err;
2210   }
2211
2212   frames = stream->bufferSize - frames;
2213   if (frames < 0) frames = 0;
2214
2215  unlock:
2216   MUTEX_UNLOCK(&stream->mutex);
2217   return frames;
2218 }
2219
2220 void RtAudio :: tickStream(int streamId)
2221 {
2222   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2223
2224   int stopStream = 0;
2225   if (stream->state == STREAM_STOPPED) {
2226     if (stream->callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
2227     return;
2228   }
2229   else if (stream->callbackInfo.usingCallback) {
2230     RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
2231     stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
2232   }
2233
2234   MUTEX_LOCK(&stream->mutex);
2235
2236   // The state might change while waiting on a mutex.
2237   if (stream->state == STREAM_STOPPED)
2238     goto unlock;
2239
2240   int err;
2241   char *buffer;
2242   int channels;
2243   RTAUDIO_FORMAT format;
2244   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2245
2246     // Setup parameters and do buffer conversion if necessary.
2247     if (stream->doConvertBuffer[0]) {
2248       convertStreamBuffer(stream, OUTPUT);
2249       buffer = stream->deviceBuffer;
2250       channels = stream->nDeviceChannels[0];
2251       format = stream->deviceFormat[0];
2252     }
2253     else {
2254       buffer = stream->userBuffer;
2255       channels = stream->nUserChannels[0];
2256       format = stream->userFormat;
2257     }
2258
2259     // Do byte swapping if necessary.
2260     if (stream->doByteSwap[0])
2261       byteSwapBuffer(buffer, stream->bufferSize * channels, format);
2262
2263     // Write samples to device in interleaved/non-interleaved format.
2264     if (stream->deInterleave[0]) {
2265       void *bufs[channels];
2266       size_t offset = stream->bufferSize * formatBytes(format);
2267       for (int i=0; i<channels; i++)
2268         bufs[i] = (void *) (buffer + (i * offset));
2269       err = snd_pcm_writen(stream->handle[0], bufs, stream->bufferSize);
2270     }
2271     else
2272       err = snd_pcm_writei(stream->handle[0], buffer, stream->bufferSize);
2273
2274     if (err < stream->bufferSize) {
2275       // Either an error or underrun occured.
2276       if (err == -EPIPE) {
2277         snd_pcm_state_t state = snd_pcm_state(stream->handle[0]);
2278         if (state == SND_PCM_STATE_XRUN) {
2279           sprintf(message, "RtAudio: ALSA underrun detected.");
2280           error(RtError::WARNING);
2281           err = snd_pcm_prepare(stream->handle[0]);
2282           if (err < 0) {
2283             sprintf(message, "RtAudio: ALSA error preparing handle after underrun: %s.",
2284                     snd_strerror(err));
2285             MUTEX_UNLOCK(&stream->mutex);
2286             error(RtError::DRIVER_ERROR);
2287           }
2288         }
2289         else {
2290           sprintf(message, "RtAudio: ALSA error, current state is %s.",
2291                   snd_pcm_state_name(state));
2292           MUTEX_UNLOCK(&stream->mutex);
2293           error(RtError::DRIVER_ERROR);
2294         }
2295         goto unlock;
2296       }
2297       else {
2298         sprintf(message, "RtAudio: ALSA audio write error for device (%s): %s.",
2299                 devices[stream->device[0]].name, snd_strerror(err));
2300         MUTEX_UNLOCK(&stream->mutex);
2301         error(RtError::DRIVER_ERROR);
2302       }
2303     }
2304   }
2305
2306   if (stream->mode == INPUT || stream->mode == DUPLEX) {
2307
2308     // Setup parameters.
2309     if (stream->doConvertBuffer[1]) {
2310       buffer = stream->deviceBuffer;
2311       channels = stream->nDeviceChannels[1];
2312       format = stream->deviceFormat[1];
2313     }
2314     else {
2315       buffer = stream->userBuffer;
2316       channels = stream->nUserChannels[1];
2317       format = stream->userFormat;
2318     }
2319
2320     // Read samples from device in interleaved/non-interleaved format.
2321     if (stream->deInterleave[1]) {
2322       void *bufs[channels];
2323       size_t offset = stream->bufferSize * formatBytes(format);
2324       for (int i=0; i<channels; i++)
2325         bufs[i] = (void *) (buffer + (i * offset));
2326       err = snd_pcm_readn(stream->handle[1], bufs, stream->bufferSize);
2327     }
2328     else
2329       err = snd_pcm_readi(stream->handle[1], buffer, stream->bufferSize);
2330
2331     if (err < stream->bufferSize) {
2332       // Either an error or underrun occured.
2333       if (err == -EPIPE) {
2334         snd_pcm_state_t state = snd_pcm_state(stream->handle[1]);
2335         if (state == SND_PCM_STATE_XRUN) {
2336           sprintf(message, "RtAudio: ALSA overrun detected.");
2337           error(RtError::WARNING);
2338           err = snd_pcm_prepare(stream->handle[1]);
2339           if (err < 0) {
2340             sprintf(message, "RtAudio: ALSA error preparing handle after overrun: %s.",
2341                     snd_strerror(err));
2342             MUTEX_UNLOCK(&stream->mutex);
2343             error(RtError::DRIVER_ERROR);
2344           }
2345         }
2346         else {
2347           sprintf(message, "RtAudio: ALSA error, current state is %s.",
2348                   snd_pcm_state_name(state));
2349           MUTEX_UNLOCK(&stream->mutex);
2350           error(RtError::DRIVER_ERROR);
2351         }
2352         goto unlock;
2353       }
2354       else {
2355         sprintf(message, "RtAudio: ALSA audio read error for device (%s): %s.",
2356                 devices[stream->device[1]].name, snd_strerror(err));
2357         MUTEX_UNLOCK(&stream->mutex);
2358         error(RtError::DRIVER_ERROR);
2359       }
2360     }
2361
2362     // Do byte swapping if necessary.
2363     if (stream->doByteSwap[1])
2364       byteSwapBuffer(buffer, stream->bufferSize * channels, format);
2365
2366     // Do buffer conversion if necessary.
2367     if (stream->doConvertBuffer[1])
2368       convertStreamBuffer(stream, INPUT);
2369   }
2370
2371  unlock:
2372   MUTEX_UNLOCK(&stream->mutex);
2373
2374   if (stream->callbackInfo.usingCallback && stopStream)
2375     this->stopStream(streamId);
2376 }
2377
2378 extern "C" void *callbackHandler(void *ptr)
2379 {
2380   CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
2381   RtAudio *object = (RtAudio *) info->object;
2382   int stream = info->streamId;
2383   bool *usingCallback = &info->usingCallback;
2384
2385   while ( *usingCallback ) {
2386     pthread_testcancel();
2387     try {
2388       object->tickStream(stream);
2389     }
2390     catch (RtError &exception) {
2391       fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
2392               exception.getMessage());
2393       break;
2394     }
2395   }
2396
2397   return 0;
2398 }
2399
2400 //******************** End of __LINUX_ALSA__ *********************//
2401
2402 #elif defined(__LINUX_OSS__)
2403
2404 #include <sys/stat.h>
2405 #include <sys/types.h>
2406 #include <sys/ioctl.h>
2407 #include <unistd.h>
2408 #include <fcntl.h>
2409 #include <sys/soundcard.h>
2410 #include <errno.h>
2411 #include <math.h>
2412
2413 #define DAC_NAME "/dev/dsp"
2414 #define MAX_DEVICES 16
2415 #define MAX_CHANNELS 16
2416
2417 void RtAudio :: initialize(void)
2418 {
2419   // Count cards and devices
2420   nDevices = 0;
2421
2422   // We check /dev/dsp before probing devices.  /dev/dsp is supposed to
2423   // be a link to the "default" audio device, of the form /dev/dsp0,
2424   // /dev/dsp1, etc...  However, I've seen many cases where /dev/dsp was a
2425   // real device, so we need to check for that.  Also, sometimes the
2426   // link is to /dev/dspx and other times just dspx.  I'm not sure how
2427   // the latter works, but it does.
2428   char device_name[16];
2429   struct stat dspstat;
2430   int dsplink = -1;
2431   int i = 0;
2432   if (lstat(DAC_NAME, &dspstat) == 0) {
2433     if (S_ISLNK(dspstat.st_mode)) {
2434       i = readlink(DAC_NAME, device_name, sizeof(device_name));
2435       if (i > 0) {
2436         device_name[i] = '\0';
2437         if (i > 8) { // check for "/dev/dspx"
2438           if (!strncmp(DAC_NAME, device_name, 8))
2439             dsplink = atoi(&device_name[8]);
2440         }
2441         else if (i > 3) { // check for "dspx"
2442           if (!strncmp("dsp", device_name, 3))
2443             dsplink = atoi(&device_name[3]);
2444         }
2445       }
2446       else {
2447         sprintf(message, "RtAudio: cannot read value of symbolic link %s.", DAC_NAME);
2448         error(RtError::SYSTEM_ERROR);
2449       }
2450     }
2451   }
2452   else {
2453     sprintf(message, "RtAudio: cannot stat %s.", DAC_NAME);
2454     error(RtError::SYSTEM_ERROR);
2455   }
2456
2457   // The OSS API doesn't provide a routine for determining the number
2458   // of devices.  Thus, we'll just pursue a brute force method.  The
2459   // idea is to start with /dev/dsp(0) and continue with higher device
2460   // numbers until we reach MAX_DSP_DEVICES.  This should tell us how
2461   // many devices we have ... it is not a fullproof scheme, but hopefully
2462   // it will work most of the time.
2463
2464   int fd = 0;
2465   char names[MAX_DEVICES][16];
2466   for (i=-1; i<MAX_DEVICES; i++) {
2467
2468     // Probe /dev/dsp first, since it is supposed to be the default device.
2469     if (i == -1)
2470       sprintf(device_name, "%s", DAC_NAME);
2471     else if (i == dsplink)
2472       continue; // We've aready probed this device via /dev/dsp link ... try next device.
2473     else
2474       sprintf(device_name, "%s%d", DAC_NAME, i);
2475
2476     // First try to open the device for playback, then record mode.
2477     fd = open(device_name, O_WRONLY | O_NONBLOCK);
2478     if (fd == -1) {
2479       // Open device for playback failed ... either busy or doesn't exist.
2480       if (errno != EBUSY && errno != EAGAIN) {
2481         // Try to open for capture
2482         fd = open(device_name, O_RDONLY | O_NONBLOCK);
2483         if (fd == -1) {
2484           // Open device for record failed.
2485           if (errno != EBUSY && errno != EAGAIN)
2486             continue;
2487           else {
2488             sprintf(message, "RtAudio: OSS record device (%s) is busy.", device_name);
2489             error(RtError::WARNING);
2490             // still count it for now
2491           }
2492         }
2493       }
2494       else {
2495         sprintf(message, "RtAudio: OSS playback device (%s) is busy.", device_name);
2496         error(RtError::WARNING);
2497         // still count it for now
2498       }
2499     }
2500
2501     if (fd >= 0) close(fd);
2502     strncpy(names[nDevices], device_name, 16);
2503     nDevices++;
2504   }
2505
2506   if (nDevices == 0) return;
2507
2508   //  Allocate the RTAUDIO_DEVICE structures.
2509   devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
2510   if (devices == NULL) {
2511     sprintf(message, "RtAudio: memory allocation error!");
2512     error(RtError::MEMORY_ERROR);
2513   }
2514
2515   // Write device ascii identifiers to device control structure and then probe capabilities.
2516   for (i=0; i<nDevices; i++) {
2517     strncpy(devices[i].name, names[i], 16);
2518     //probeDeviceInfo(&devices[i]);
2519   }
2520
2521   return;
2522 }
2523
2524 int RtAudio :: getDefaultInputDevice(void)
2525 {
2526   // No OSS API functions for default devices.
2527   return 0;
2528 }
2529
2530 int RtAudio :: getDefaultOutputDevice(void)
2531 {
2532   // No OSS API functions for default devices.
2533   return 0;
2534 }
2535
2536 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
2537 {
2538   int i, fd, channels, mask;
2539
2540   // The OSS API doesn't provide a means for probing the capabilities
2541   // of devices.  Thus, we'll just pursue a brute force method.
2542
2543   // First try for playback
2544   fd = open(info->name, O_WRONLY | O_NONBLOCK);
2545   if (fd == -1) {
2546     // Open device failed ... either busy or doesn't exist
2547     if (errno == EBUSY || errno == EAGAIN)
2548       sprintf(message, "RtAudio: OSS playback device (%s) is busy and cannot be probed.",
2549               info->name);
2550     else
2551       sprintf(message, "RtAudio: OSS playback device (%s) open error.", info->name);
2552     error(RtError::DEBUG_WARNING);
2553     goto capture_probe;
2554   }
2555
2556   // We have an open device ... see how many channels it can handle
2557   for (i=MAX_CHANNELS; i>0; i--) {
2558     channels = i;
2559     if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
2560       // This would normally indicate some sort of hardware error, but under ALSA's
2561       // OSS emulation, it sometimes indicates an invalid channel value.  Further,
2562       // the returned channel value is not changed. So, we'll ignore the possible
2563       // hardware error.
2564       continue; // try next channel number
2565     }
2566     // Check to see whether the device supports the requested number of channels
2567     if (channels != i ) continue; // try next channel number
2568     // If here, we found the largest working channel value
2569     break;
2570   }
2571   info->maxOutputChannels = i;
2572
2573   // Now find the minimum number of channels it can handle
2574   for (i=1; i<=info->maxOutputChannels; i++) {
2575     channels = i;
2576     if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
2577       continue; // try next channel number
2578     // If here, we found the smallest working channel value
2579     break;
2580   }
2581   info->minOutputChannels = i;
2582   close(fd);
2583
2584  capture_probe:
2585   // Now try for capture
2586   fd = open(info->name, O_RDONLY | O_NONBLOCK);
2587   if (fd == -1) {
2588     // Open device for capture failed ... either busy or doesn't exist
2589     if (errno == EBUSY || errno == EAGAIN)
2590       sprintf(message, "RtAudio: OSS capture device (%s) is busy and cannot be probed.",
2591               info->name);
2592     else
2593       sprintf(message, "RtAudio: OSS capture device (%s) open error.", info->name);
2594     error(RtError::DEBUG_WARNING);
2595     if (info->maxOutputChannels == 0)
2596       // didn't open for playback either ... device invalid
2597       return;
2598     goto probe_parameters;
2599   }
2600
2601   // We have the device open for capture ... see how many channels it can handle
2602   for (i=MAX_CHANNELS; i>0; i--) {
2603     channels = i;
2604     if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
2605       continue; // as above
2606     }
2607     // If here, we found a working channel value
2608     break;
2609   }
2610   info->maxInputChannels = i;
2611
2612   // Now find the minimum number of channels it can handle
2613   for (i=1; i<=info->maxInputChannels; i++) {
2614     channels = i;
2615     if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
2616       continue; // try next channel number
2617     // If here, we found the smallest working channel value
2618     break;
2619   }
2620   info->minInputChannels = i;
2621   close(fd);
2622
2623   if (info->maxOutputChannels == 0 && info->maxInputChannels == 0) {
2624     sprintf(message, "RtAudio: OSS device (%s) reports zero channels for input and output.",
2625             info->name);
2626     error(RtError::DEBUG_WARNING);
2627     return;
2628   }
2629
2630   // If device opens for both playback and capture, we determine the channels.
2631   if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
2632     goto probe_parameters;
2633
2634   fd = open(info->name, O_RDWR | O_NONBLOCK);
2635   if (fd == -1)
2636     goto probe_parameters;
2637
2638   ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
2639   ioctl(fd, SNDCTL_DSP_GETCAPS, &mask);
2640   if (mask & DSP_CAP_DUPLEX) {
2641     info->hasDuplexSupport = true;
2642     // We have the device open for duplex ... see how many channels it can handle
2643     for (i=MAX_CHANNELS; i>0; i--) {
2644       channels = i;
2645       if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
2646         continue; // as above
2647       // If here, we found a working channel value
2648       break;
2649     }
2650     info->maxDuplexChannels = i;
2651
2652     // Now find the minimum number of channels it can handle
2653     for (i=1; i<=info->maxDuplexChannels; i++) {
2654       channels = i;
2655       if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
2656         continue; // try next channel number
2657       // If here, we found the smallest working channel value
2658       break;
2659     }
2660     info->minDuplexChannels = i;
2661   }
2662   close(fd);
2663
2664  probe_parameters:
2665   // At this point, we need to figure out the supported data formats
2666   // and sample rates.  We'll proceed by openning the device in the
2667   // direction with the maximum number of channels, or playback if
2668   // they are equal.  This might limit our sample rate options, but so
2669   // be it.
2670
2671   if (info->maxOutputChannels >= info->maxInputChannels) {
2672     fd = open(info->name, O_WRONLY | O_NONBLOCK);
2673     channels = info->maxOutputChannels;
2674   }
2675   else {
2676     fd = open(info->name, O_RDONLY | O_NONBLOCK);
2677     channels = info->maxInputChannels;
2678   }
2679
2680   if (fd == -1) {
2681     // We've got some sort of conflict ... abort
2682     sprintf(message, "RtAudio: OSS device (%s) won't reopen during probe.",
2683             info->name);
2684     error(RtError::DEBUG_WARNING);
2685     return;
2686   }
2687
2688   // We have an open device ... set to maximum channels.
2689   i = channels;
2690   if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
2691     // We've got some sort of conflict ... abort
2692     close(fd);
2693     sprintf(message, "RtAudio: OSS device (%s) won't revert to previous channel setting.",
2694             info->name);
2695     error(RtError::DEBUG_WARNING);
2696     return;
2697   }
2698
2699   if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
2700     close(fd);
2701     sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.",
2702             info->name);
2703     error(RtError::DEBUG_WARNING);
2704     return;
2705   }
2706
2707   // Probe the supported data formats ... we don't care about endian-ness just yet.
2708   int format;
2709   info->nativeFormats = 0;
2710 #if defined (AFMT_S32_BE)
2711   // This format does not seem to be in the 2.4 kernel version of OSS soundcard.h
2712   if (mask & AFMT_S32_BE) {
2713     format = AFMT_S32_BE;
2714     info->nativeFormats |= RTAUDIO_SINT32;
2715   }
2716 #endif
2717 #if defined (AFMT_S32_LE)
2718   /* This format is not in the 2.4.4 kernel version of OSS soundcard.h */
2719   if (mask & AFMT_S32_LE) {
2720     format = AFMT_S32_LE;
2721     info->nativeFormats |= RTAUDIO_SINT32;
2722   }
2723 #endif
2724   if (mask & AFMT_S8) {
2725     format = AFMT_S8;
2726     info->nativeFormats |= RTAUDIO_SINT8;
2727   }
2728   if (mask & AFMT_S16_BE) {
2729     format = AFMT_S16_BE;
2730     info->nativeFormats |= RTAUDIO_SINT16;
2731   }
2732   if (mask & AFMT_S16_LE) {
2733     format = AFMT_S16_LE;
2734     info->nativeFormats |= RTAUDIO_SINT16;
2735   }
2736
2737   // Check that we have at least one supported format
2738   if (info->nativeFormats == 0) {
2739     close(fd);
2740     sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.",
2741             info->name);
2742     error(RtError::DEBUG_WARNING);
2743     return;
2744   }
2745
2746   // Set the format
2747   i = format;
2748   if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1 || format != i) {
2749     close(fd);
2750     sprintf(message, "RtAudio: OSS device (%s) error setting data format.",
2751             info->name);
2752     error(RtError::DEBUG_WARNING);
2753     return;
2754   }
2755
2756   // Probe the supported sample rates ... first get lower limit
2757   int speed = 1;
2758   if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) {
2759     // If we get here, we're probably using an ALSA driver with OSS-emulation,
2760     // which doesn't conform to the OSS specification.  In this case,
2761     // we'll probe our predefined list of sample rates for working values.
2762     info->nSampleRates = 0;
2763     for (i=0; i<MAX_SAMPLE_RATES; i++) {
2764       speed = SAMPLE_RATES[i];
2765       if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) != -1) {
2766         info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
2767         info->nSampleRates++;
2768       }
2769     }
2770     if (info->nSampleRates == 0) {
2771       close(fd);
2772       return;
2773     }
2774     goto finished;
2775   }
2776   info->sampleRates[0] = speed;
2777
2778   // Now get upper limit
2779   speed = 1000000;
2780   if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) {
2781     close(fd);
2782     sprintf(message, "RtAudio: OSS device (%s) error setting sample rate.",
2783             info->name);
2784     error(RtError::DEBUG_WARNING);
2785     return;
2786   }
2787   info->sampleRates[1] = speed;
2788   info->nSampleRates = -1;
2789
2790  finished: // That's all ... close the device and return
2791   close(fd);
2792   info->probed = true;
2793   return;
2794 }
2795
2796 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
2797                                 STREAM_MODE mode, int channels, 
2798                                 int sampleRate, RTAUDIO_FORMAT format,
2799                                 int *bufferSize, int numberOfBuffers)
2800 {
2801   int buffers, buffer_bytes, device_channels, device_format;
2802   int srate, temp, fd;
2803
2804   const char *name = devices[device].name;
2805
2806   if (mode == OUTPUT)
2807     fd = open(name, O_WRONLY | O_NONBLOCK);
2808   else { // mode == INPUT
2809     if (stream->mode == OUTPUT && stream->device[0] == device) {
2810       // We just set the same device for playback ... close and reopen for duplex (OSS only).
2811       close(stream->handle[0]);
2812       stream->handle[0] = 0;
2813       // First check that the number previously set channels is the same.
2814       if (stream->nUserChannels[0] != channels) {
2815         sprintf(message, "RtAudio: input/output channels must be equal for OSS duplex device (%s).", name);
2816         goto error;
2817       }
2818       fd = open(name, O_RDWR | O_NONBLOCK);
2819     }
2820     else
2821       fd = open(name, O_RDONLY | O_NONBLOCK);
2822   }
2823
2824   if (fd == -1) {
2825     if (errno == EBUSY || errno == EAGAIN)
2826       sprintf(message, "RtAudio: OSS device (%s) is busy and cannot be opened.",
2827               name);
2828     else
2829       sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name);
2830     goto error;
2831   }
2832
2833   // Now reopen in blocking mode.
2834   close(fd);
2835   if (mode == OUTPUT)
2836     fd = open(name, O_WRONLY | O_SYNC);
2837   else { // mode == INPUT
2838     if (stream->mode == OUTPUT && stream->device[0] == device)
2839       fd = open(name, O_RDWR | O_SYNC);
2840     else
2841       fd = open(name, O_RDONLY | O_SYNC);
2842   }
2843
2844   if (fd == -1) {
2845     sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name);
2846     goto error;
2847   }
2848
2849   // Get the sample format mask
2850   int mask;
2851   if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
2852     close(fd);
2853     sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.",
2854             name);
2855     goto error;
2856   }
2857
2858   // Determine how to set the device format.
2859   stream->userFormat = format;
2860   device_format = -1;
2861   stream->doByteSwap[mode] = false;
2862   if (format == RTAUDIO_SINT8) {
2863     if (mask & AFMT_S8) {
2864       device_format = AFMT_S8;
2865       stream->deviceFormat[mode] = RTAUDIO_SINT8;
2866     }
2867   }
2868   else if (format == RTAUDIO_SINT16) {
2869     if (mask & AFMT_S16_NE) {
2870       device_format = AFMT_S16_NE;
2871       stream->deviceFormat[mode] = RTAUDIO_SINT16;
2872     }
2873 #if BYTE_ORDER == LITTLE_ENDIAN
2874     else if (mask & AFMT_S16_BE) {
2875       device_format = AFMT_S16_BE;
2876       stream->deviceFormat[mode] = RTAUDIO_SINT16;
2877       stream->doByteSwap[mode] = true;
2878     }
2879 #else
2880     else if (mask & AFMT_S16_LE) {
2881       device_format = AFMT_S16_LE;
2882       stream->deviceFormat[mode] = RTAUDIO_SINT16;
2883       stream->doByteSwap[mode] = true;
2884     }
2885 #endif
2886   }
2887 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
2888   else if (format == RTAUDIO_SINT32) {
2889     if (mask & AFMT_S32_NE) {
2890       device_format = AFMT_S32_NE;
2891       stream->deviceFormat[mode] = RTAUDIO_SINT32;
2892     }
2893 #if BYTE_ORDER == LITTLE_ENDIAN
2894     else if (mask & AFMT_S32_BE) {
2895       device_format = AFMT_S32_BE;
2896       stream->deviceFormat[mode] = RTAUDIO_SINT32;
2897       stream->doByteSwap[mode] = true;
2898     }
2899 #else
2900     else if (mask & AFMT_S32_LE) {
2901       device_format = AFMT_S32_LE;
2902       stream->deviceFormat[mode] = RTAUDIO_SINT32;
2903       stream->doByteSwap[mode] = true;
2904     }
2905 #endif
2906   }
2907 #endif
2908
2909   if (device_format == -1) {
2910     // The user requested format is not natively supported by the device.
2911     if (mask & AFMT_S16_NE) {
2912       device_format = AFMT_S16_NE;
2913       stream->deviceFormat[mode] = RTAUDIO_SINT16;
2914     }
2915 #if BYTE_ORDER == LITTLE_ENDIAN
2916     else if (mask & AFMT_S16_BE) {
2917       device_format = AFMT_S16_BE;
2918       stream->deviceFormat[mode] = RTAUDIO_SINT16;
2919       stream->doByteSwap[mode] = true;
2920     }
2921 #else
2922     else if (mask & AFMT_S16_LE) {
2923       device_format = AFMT_S16_LE;
2924       stream->deviceFormat[mode] = RTAUDIO_SINT16;
2925       stream->doByteSwap[mode] = true;
2926     }
2927 #endif
2928 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
2929     else if (mask & AFMT_S32_NE) {
2930       device_format = AFMT_S32_NE;
2931       stream->deviceFormat[mode] = RTAUDIO_SINT32;
2932     }
2933 #if BYTE_ORDER == LITTLE_ENDIAN
2934     else if (mask & AFMT_S32_BE) {
2935       device_format = AFMT_S32_BE;
2936       stream->deviceFormat[mode] = RTAUDIO_SINT32;
2937       stream->doByteSwap[mode] = true;
2938     }
2939 #else
2940     else if (mask & AFMT_S32_LE) {
2941       device_format = AFMT_S32_LE;
2942       stream->deviceFormat[mode] = RTAUDIO_SINT32;
2943       stream->doByteSwap[mode] = true;
2944     }
2945 #endif
2946 #endif
2947     else if (mask & AFMT_S8) {
2948       device_format = AFMT_S8;
2949       stream->deviceFormat[mode] = RTAUDIO_SINT8;
2950     }
2951   }
2952
2953   if (stream->deviceFormat[mode] == 0) {
2954     // This really shouldn't happen ...
2955     close(fd);
2956     sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.",
2957             name);
2958     goto error;
2959   }
2960
2961   // Determine the number of channels for this device.  Note that the
2962   // channel value requested by the user might be < min_X_Channels.
2963   stream->nUserChannels[mode] = channels;
2964   device_channels = channels;
2965   if (mode == OUTPUT) {
2966     if (channels < devices[device].minOutputChannels)
2967       device_channels = devices[device].minOutputChannels;
2968   }
2969   else { // mode == INPUT
2970     if (stream->mode == OUTPUT && stream->device[0] == device) {
2971       // We're doing duplex setup here.
2972       if (channels < devices[device].minDuplexChannels)
2973         device_channels = devices[device].minDuplexChannels;
2974     }
2975     else {
2976       if (channels < devices[device].minInputChannels)
2977         device_channels = devices[device].minInputChannels;
2978     }
2979   }
2980   stream->nDeviceChannels[mode] = device_channels;
2981
2982   // Attempt to set the buffer size.  According to OSS, the minimum
2983   // number of buffers is two.  The supposed minimum buffer size is 16
2984   // bytes, so that will be our lower bound.  The argument to this
2985   // call is in the form 0xMMMMSSSS (hex), where the buffer size (in
2986   // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM.
2987   // We'll check the actual value used near the end of the setup
2988   // procedure.
2989   buffer_bytes = *bufferSize * formatBytes(stream->deviceFormat[mode]) * device_channels;
2990   if (buffer_bytes < 16) buffer_bytes = 16;
2991   buffers = numberOfBuffers;
2992   if (buffers < 2) buffers = 2;
2993   temp = ((int) buffers << 16) + (int)(log10((double)buffer_bytes)/log10(2.0));
2994   if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &temp)) {
2995     close(fd);
2996     sprintf(message, "RtAudio: OSS error setting fragment size for device (%s).",
2997             name);
2998     goto error;
2999   }
3000   stream->nBuffers = buffers;
3001
3002   // Set the data format.
3003   temp = device_format;
3004   if (ioctl(fd, SNDCTL_DSP_SETFMT, &device_format) == -1 || device_format != temp) {
3005     close(fd);
3006     sprintf(message, "RtAudio: OSS error setting data format for device (%s).",
3007             name);
3008     goto error;
3009   }
3010
3011   // Set the number of channels.
3012   temp = device_channels;
3013   if (ioctl(fd, SNDCTL_DSP_CHANNELS, &device_channels) == -1 || device_channels != temp) {
3014     close(fd);
3015     sprintf(message, "RtAudio: OSS error setting %d channels on device (%s).",
3016             temp, name);
3017     goto error;
3018   }
3019
3020   // Set the sample rate.
3021   srate = sampleRate;
3022   temp = srate;
3023   if (ioctl(fd, SNDCTL_DSP_SPEED, &srate) == -1) {
3024     close(fd);
3025     sprintf(message, "RtAudio: OSS error setting sample rate = %d on device (%s).",
3026             temp, name);
3027     goto error;
3028   }
3029
3030   // Verify the sample rate setup worked.
3031   if (abs(srate - temp) > 100) {
3032     close(fd);
3033     sprintf(message, "RtAudio: OSS error ... audio device (%s) doesn't support sample rate of %d.",
3034             name, temp);
3035     goto error;
3036   }
3037   stream->sampleRate = sampleRate;
3038
3039   if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &buffer_bytes) == -1) {
3040     close(fd);
3041     sprintf(message, "RtAudio: OSS error getting buffer size for device (%s).",
3042             name);
3043     goto error;
3044   }
3045
3046   // Save buffer size (in sample frames).
3047   *bufferSize = buffer_bytes / (formatBytes(stream->deviceFormat[mode]) * device_channels);
3048   stream->bufferSize = *bufferSize;
3049
3050   if (mode == INPUT && stream->mode == OUTPUT &&
3051       stream->device[0] == device) {
3052     // We're doing duplex setup here.
3053     stream->deviceFormat[0] = stream->deviceFormat[1];
3054     stream->nDeviceChannels[0] = device_channels;
3055   }
3056
3057   // Set flags for buffer conversion
3058   stream->doConvertBuffer[mode] = false;
3059   if (stream->userFormat != stream->deviceFormat[mode])
3060     stream->doConvertBuffer[mode] = true;
3061   if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
3062     stream->doConvertBuffer[mode] = true;
3063
3064   // Allocate necessary internal buffers
3065   if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
3066
3067     long buffer_bytes;
3068     if (stream->nUserChannels[0] >= stream->nUserChannels[1])
3069       buffer_bytes = stream->nUserChannels[0];
3070     else
3071       buffer_bytes = stream->nUserChannels[1];
3072
3073     buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
3074     if (stream->userBuffer) free(stream->userBuffer);
3075     stream->userBuffer = (char *) calloc(buffer_bytes, 1);
3076     if (stream->userBuffer == NULL) {
3077       close(fd);
3078       sprintf(message, "RtAudio: OSS error allocating user buffer memory (%s).",
3079               name);
3080       goto error;
3081     }
3082   }
3083
3084   if ( stream->doConvertBuffer[mode] ) {
3085
3086     long buffer_bytes;
3087     bool makeBuffer = true;
3088     if ( mode == OUTPUT )
3089       buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
3090     else { // mode == INPUT
3091       buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
3092       if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
3093         long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
3094         if ( buffer_bytes < bytes_out ) makeBuffer = false;
3095       }
3096     }
3097
3098     if ( makeBuffer ) {
3099       buffer_bytes *= *bufferSize;
3100       if (stream->deviceBuffer) free(stream->deviceBuffer);
3101       stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
3102       if (stream->deviceBuffer == NULL) {
3103         close(fd);
3104         free(stream->userBuffer);
3105         sprintf(message, "RtAudio: OSS error allocating device buffer memory (%s).",
3106                 name);
3107         goto error;
3108       }
3109     }
3110   }
3111
3112   stream->device[mode] = device;
3113   stream->handle[mode] = fd;
3114   stream->state = STREAM_STOPPED;
3115   if ( stream->mode == OUTPUT && mode == INPUT ) {
3116     stream->mode = DUPLEX;
3117     if (stream->device[0] == device)
3118       stream->handle[0] = fd;
3119   }
3120   else
3121     stream->mode = mode;
3122
3123   return SUCCESS;
3124
3125  error:
3126   if (stream->handle[0]) {
3127     close(stream->handle[0]);
3128     stream->handle[0] = 0;
3129   }
3130   error(RtError::WARNING);
3131   return FAILURE;
3132 }
3133
3134 void RtAudio :: closeStream(int streamId)
3135 {
3136   // We don't want an exception to be thrown here because this
3137   // function is called by our class destructor.  So, do our own
3138   // streamId check.
3139   if ( streams.find( streamId ) == streams.end() ) {
3140     sprintf(message, "RtAudio: invalid stream identifier!");
3141     error(RtError::WARNING);
3142     return;
3143   }
3144
3145   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
3146
3147   if (stream->callbackInfo.usingCallback) {
3148     pthread_cancel(stream->callbackInfo.thread);
3149     pthread_join(stream->callbackInfo.thread, NULL);
3150   }
3151
3152   if (stream->state == STREAM_RUNNING) {
3153     if (stream->mode == OUTPUT || stream->mode == DUPLEX)
3154       ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0);
3155     if (stream->mode == INPUT || stream->mode == DUPLEX)
3156       ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0);
3157   }
3158
3159   pthread_mutex_destroy(&stream->mutex);
3160
3161   if (stream->handle[0])
3162     close(stream->handle[0]);
3163
3164   if (stream->handle[1])
3165     close(stream->handle[1]);
3166
3167   if (stream->userBuffer)
3168     free(stream->userBuffer);
3169
3170   if (stream->deviceBuffer)
3171     free(stream->deviceBuffer);
3172
3173   free(stream);
3174   streams.erase(streamId);
3175 }
3176
3177 void RtAudio :: startStream(int streamId)
3178 {
3179   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3180
3181   MUTEX_LOCK(&stream->mutex);
3182
3183   stream->state = STREAM_RUNNING;
3184
3185   // No need to do anything else here ... OSS automatically starts
3186   // when fed samples.
3187
3188   MUTEX_UNLOCK(&stream->mutex);
3189 }
3190
3191 void RtAudio :: stopStream(int streamId)
3192 {
3193   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3194
3195   MUTEX_LOCK(&stream->mutex);
3196
3197   if (stream->state == STREAM_STOPPED)
3198     goto unlock;
3199
3200   int err;
3201   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
3202     err = ioctl(stream->handle[0], SNDCTL_DSP_SYNC, 0);
3203     if (err < -1) {
3204       sprintf(message, "RtAudio: OSS error stopping device (%s).",
3205               devices[stream->device[0]].name);
3206       error(RtError::DRIVER_ERROR);
3207     }
3208   }
3209   else {
3210     err = ioctl(stream->handle[1], SNDCTL_DSP_SYNC, 0);
3211     if (err < -1) {
3212       sprintf(message, "RtAudio: OSS error stopping device (%s).",
3213               devices[stream->device[1]].name);
3214       error(RtError::DRIVER_ERROR);
3215     }
3216   }
3217   stream->state = STREAM_STOPPED;
3218
3219  unlock:
3220   MUTEX_UNLOCK(&stream->mutex);
3221 }
3222
3223 void RtAudio :: abortStream(int streamId)
3224 {
3225   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3226
3227   MUTEX_LOCK(&stream->mutex);
3228
3229   if (stream->state == STREAM_STOPPED)
3230     goto unlock;
3231
3232   int err;
3233   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
3234     err = ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0);
3235     if (err < -1) {
3236       sprintf(message, "RtAudio: OSS error aborting device (%s).",
3237               devices[stream->device[0]].name);
3238       error(RtError::DRIVER_ERROR);
3239     }
3240   }
3241   else {
3242     err = ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0);
3243     if (err < -1) {
3244       sprintf(message, "RtAudio: OSS error aborting device (%s).",
3245               devices[stream->device[1]].name);
3246       error(RtError::DRIVER_ERROR);
3247     }
3248   }
3249   stream->state = STREAM_STOPPED;
3250
3251  unlock:
3252   MUTEX_UNLOCK(&stream->mutex);
3253 }
3254
3255 int RtAudio :: streamWillBlock(int streamId)
3256 {
3257   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3258
3259   MUTEX_LOCK(&stream->mutex);
3260
3261   int bytes = 0, channels = 0, frames = 0;
3262   if (stream->state == STREAM_STOPPED)
3263     goto unlock;
3264
3265   audio_buf_info info;
3266   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
3267     ioctl(stream->handle[0], SNDCTL_DSP_GETOSPACE, &info);
3268     bytes = info.bytes;
3269     channels = stream->nDeviceChannels[0];
3270   }
3271
3272   if (stream->mode == INPUT || stream->mode == DUPLEX) {
3273     ioctl(stream->handle[1], SNDCTL_DSP_GETISPACE, &info);
3274     if (stream->mode == DUPLEX ) {
3275       bytes = (bytes < info.bytes) ? bytes : info.bytes;
3276       channels = stream->nDeviceChannels[0];
3277     }
3278     else {
3279       bytes = info.bytes;
3280       channels = stream->nDeviceChannels[1];
3281     }
3282   }
3283
3284   frames = (int) (bytes / (channels * formatBytes(stream->deviceFormat[0])));
3285   frames -= stream->bufferSize;
3286   if (frames < 0) frames = 0;
3287
3288  unlock:
3289   MUTEX_UNLOCK(&stream->mutex);
3290   return frames;
3291 }
3292
3293 void RtAudio :: tickStream(int streamId)
3294 {
3295   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3296
3297   int stopStream = 0;
3298   if (stream->state == STREAM_STOPPED) {
3299     if (stream->callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
3300     return;
3301   }
3302   else if (stream->callbackInfo.usingCallback) {
3303     RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
3304     stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
3305   }
3306
3307   MUTEX_LOCK(&stream->mutex);
3308
3309   // The state might change while waiting on a mutex.
3310   if (stream->state == STREAM_STOPPED)
3311     goto unlock;
3312
3313   int result;
3314   char *buffer;
3315   int samples;
3316   RTAUDIO_FORMAT format;
3317   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
3318
3319     // Setup parameters and do buffer conversion if necessary.
3320     if (stream->doConvertBuffer[0]) {
3321       convertStreamBuffer(stream, OUTPUT);
3322       buffer = stream->deviceBuffer;
3323       samples = stream->bufferSize * stream->nDeviceChannels[0];
3324       format = stream->deviceFormat[0];
3325     }
3326     else {
3327       buffer = stream->userBuffer;
3328       samples = stream->bufferSize * stream->nUserChannels[0];
3329       format = stream->userFormat;
3330     }
3331
3332     // Do byte swapping if necessary.
3333     if (stream->doByteSwap[0])
3334       byteSwapBuffer(buffer, samples, format);
3335
3336     // Write samples to device.
3337     result = write(stream->handle[0], buffer, samples * formatBytes(format));
3338
3339     if (result == -1) {
3340       // This could be an underrun, but the basic OSS API doesn't provide a means for determining that.
3341       sprintf(message, "RtAudio: OSS audio write error for device (%s).",
3342               devices[stream->device[0]].name);
3343       error(RtError::DRIVER_ERROR);
3344     }
3345   }
3346
3347   if (stream->mode == INPUT || stream->mode == DUPLEX) {
3348
3349     // Setup parameters.
3350     if (stream->doConvertBuffer[1]) {
3351       buffer = stream->deviceBuffer;
3352       samples = stream->bufferSize * stream->nDeviceChannels[1];
3353       format = stream->deviceFormat[1];
3354     }
3355     else {
3356       buffer = stream->userBuffer;
3357       samples = stream->bufferSize * stream->nUserChannels[1];
3358       format = stream->userFormat;
3359     }
3360
3361     // Read samples from device.
3362     result = read(stream->handle[1], buffer, samples * formatBytes(format));
3363
3364     if (result == -1) {
3365       // This could be an overrun, but the basic OSS API doesn't provide a means for determining that.
3366       sprintf(message, "RtAudio: OSS audio read error for device (%s).",
3367               devices[stream->device[1]].name);
3368       error(RtError::DRIVER_ERROR);
3369     }
3370
3371     // Do byte swapping if necessary.
3372     if (stream->doByteSwap[1])
3373       byteSwapBuffer(buffer, samples, format);
3374
3375     // Do buffer conversion if necessary.
3376     if (stream->doConvertBuffer[1])
3377       convertStreamBuffer(stream, INPUT);
3378   }
3379
3380  unlock:
3381   MUTEX_UNLOCK(&stream->mutex);
3382
3383   if (stream->callbackInfo.usingCallback && stopStream)
3384     this->stopStream(streamId);
3385 }
3386
3387 extern "C" void *callbackHandler(void *ptr)
3388 {
3389   CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
3390   RtAudio *object = (RtAudio *) info->object;
3391   int stream = info->streamId;
3392   bool *usingCallback = &info->usingCallback;
3393
3394   while ( *usingCallback ) {
3395     pthread_testcancel();
3396     try {
3397       object->tickStream(stream);
3398     }
3399     catch (RtError &exception) {
3400       fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
3401               exception.getMessage());
3402       break;
3403     }
3404   }
3405
3406   return 0;
3407 }
3408
3409
3410 //******************** End of __LINUX_OSS__ *********************//
3411
3412 #elif defined(__WINDOWS_ASIO__) // ASIO API on Windows
3413
3414 // The ASIO API is designed around a callback scheme, so this
3415 // implementation is similar to that used for OS X CoreAudio.  The
3416 // primary constraint with ASIO is that it only allows access to a
3417 // single driver at a time.  Thus, it is not possible to have more
3418 // than one simultaneous RtAudio stream.
3419 //
3420 // This implementation also requires a number of external ASIO files
3421 // and a few global variables.  The ASIO callback scheme does not
3422 // allow for the passing of user data, so we must create a global
3423 // pointer to our callbackInfo structure.
3424
3425 #include "asio/asiosys.h"
3426 #include "asio/asio.h"
3427 #include "asio/asiodrivers.h"
3428 #include <math.h>
3429
3430 AsioDrivers drivers;
3431 ASIOCallbacks asioCallbacks;
3432 CALLBACK_INFO *asioCallbackInfo;
3433 ASIODriverInfo driverInfo;
3434
3435 void RtAudio :: initialize(void)
3436 {
3437   nDevices = drivers.asioGetNumDev();
3438   if (nDevices <= 0) return;
3439
3440   //  Allocate the RTAUDIO_DEVICE structures.
3441   devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
3442   if (devices == NULL) {
3443     sprintf(message, "RtAudio: memory allocation error!");
3444     error(RtError::MEMORY_ERROR);
3445   }
3446
3447   // Write device driver names to device structures and then probe the
3448   // device capabilities.
3449   for (int i=0; i<nDevices; i++) {
3450     if ( drivers.asioGetDriverName( i, devices[i].name, 128 ) == 0 )
3451       //probeDeviceInfo(&devices[i]);
3452       ;
3453     else {
3454       sprintf(message, "RtAudio: error getting ASIO driver name for device index %d!", i);
3455       error(RtError::WARNING);
3456     }
3457   }
3458
3459   drivers.removeCurrentDriver();
3460   driverInfo.asioVersion = 2;
3461   // See note in DirectSound implementation about GetDesktopWindow().
3462   driverInfo.sysRef = GetForegroundWindow();
3463 }
3464
3465 int RtAudio :: getDefaultInputDevice(void)
3466 {
3467   return 0;
3468 }
3469
3470 int RtAudio :: getDefaultOutputDevice(void)
3471 {
3472   return 0;
3473 }
3474
3475 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
3476 {
3477   // Don't probe if a stream is already open.
3478   if ( streams.size() > 0 ) {
3479     sprintf(message, "RtAudio: unable to probe ASIO driver while a stream is open.");
3480     error(RtError::DEBUG_WARNING);
3481     return;
3482   }
3483
3484   if ( !drivers.loadDriver( info->name ) ) {
3485     sprintf(message, "RtAudio: ASIO error loading driver (%s).", info->name);
3486     error(RtError::DEBUG_WARNING);
3487     return;
3488   }
3489
3490   ASIOError result = ASIOInit( &driverInfo );
3491   if ( result != ASE_OK ) {
3492     char details[32];
3493     if ( result == ASE_HWMalfunction )
3494       sprintf(details, "hardware malfunction");
3495     else if ( result == ASE_NoMemory )
3496       sprintf(details, "no memory");
3497     else if ( result == ASE_NotPresent )
3498       sprintf(details, "driver/hardware not present");
3499     else
3500       sprintf(details, "unspecified");
3501     sprintf(message, "RtAudio: ASIO error (%s) initializing driver (%s).", details, info->name);
3502     error(RtError::DEBUG_WARNING);
3503     return;
3504   }
3505
3506   // Determine the device channel information.
3507   long inputChannels, outputChannels;
3508   result = ASIOGetChannels( &inputChannels, &outputChannels );
3509   if ( result != ASE_OK ) {
3510     drivers.removeCurrentDriver();
3511     sprintf(message, "RtAudio: ASIO error getting input/output channel count (%s).", info->name);
3512     error(RtError::DEBUG_WARNING);
3513     return;
3514   }
3515
3516   info->maxOutputChannels = outputChannels;
3517   if ( outputChannels > 0 ) info->minOutputChannels = 1;
3518
3519   info->maxInputChannels = inputChannels;
3520   if ( inputChannels > 0 ) info->minInputChannels = 1;
3521
3522   // If device opens for both playback and capture, we determine the channels.
3523   if (info->maxOutputChannels > 0 && info->maxInputChannels > 0) {
3524     info->hasDuplexSupport = true;
3525     info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
3526       info->maxInputChannels : info->maxOutputChannels;
3527     info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
3528       info->minInputChannels : info->minOutputChannels;
3529   }
3530
3531   // Determine the supported sample rates.
3532   info->nSampleRates = 0;
3533   for (int i=0; i<MAX_SAMPLE_RATES; i++) {
3534     result = ASIOCanSampleRate( (ASIOSampleRate) SAMPLE_RATES[i] );
3535     if ( result == ASE_OK )
3536       info->sampleRates[info->nSampleRates++] = SAMPLE_RATES[i];
3537   }
3538
3539   if (info->nSampleRates == 0) {
3540     drivers.removeCurrentDriver();
3541     sprintf( message, "RtAudio: No supported sample rates found for ASIO driver (%s).", info->name );
3542     error(RtError::DEBUG_WARNING);
3543     return;
3544   }
3545
3546   // Determine supported data types ... just check first channel and assume rest are the same.
3547   ASIOChannelInfo channelInfo;
3548   channelInfo.channel = 0;
3549   channelInfo.isInput = true;
3550   if ( info->maxInputChannels <= 0 ) channelInfo.isInput = false;
3551   result = ASIOGetChannelInfo( &channelInfo );
3552   if ( result != ASE_OK ) {
3553     drivers.removeCurrentDriver();
3554     sprintf(message, "RtAudio: ASIO error getting driver (%s) channel information.", info->name);
3555     error(RtError::DEBUG_WARNING);
3556     return;
3557   }
3558
3559   if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB )
3560     info->nativeFormats |= RTAUDIO_SINT16;
3561   else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB )
3562     info->nativeFormats |= RTAUDIO_SINT32;
3563   else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB )
3564     info->nativeFormats |= RTAUDIO_FLOAT32;
3565   else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB )
3566     info->nativeFormats |= RTAUDIO_FLOAT64;
3567
3568         // Check that we have at least one supported format.
3569   if (info->nativeFormats == 0) {
3570     drivers.removeCurrentDriver();
3571     sprintf(message, "RtAudio: ASIO driver (%s) data format not supported by RtAudio.",
3572             info->name);
3573     error(RtError::DEBUG_WARNING);
3574     return;
3575   }
3576
3577   info->probed = true;
3578   drivers.removeCurrentDriver();
3579 }
3580
3581 void bufferSwitch(long index, ASIOBool processNow)
3582 {
3583   RtAudio *object = (RtAudio *) asioCallbackInfo->object;
3584   try {
3585     object->callbackEvent( asioCallbackInfo->streamId, index, (void *)NULL, (void *)NULL );
3586   }
3587   catch (RtError &exception) {
3588     fprintf(stderr, "\nCallback handler error (%s)!\n\n", exception.getMessage());
3589     return;
3590   }
3591
3592   return;
3593 }
3594
3595 void sampleRateChanged(ASIOSampleRate sRate)
3596 {
3597   // The ASIO documentation says that this usually only happens during
3598   // external sync.  Audio processing is not stopped by the driver,
3599   // actual sample rate might not have even changed, maybe only the
3600   // sample rate status of an AES/EBU or S/PDIF digital input at the
3601   // audio device.
3602
3603   RtAudio *object = (RtAudio *) asioCallbackInfo->object;
3604   try {
3605     object->stopStream( asioCallbackInfo->streamId );
3606   }
3607   catch (RtError &exception) {
3608     fprintf(stderr, "\nRtAudio: sampleRateChanged() error (%s)!\n\n", exception.getMessage());
3609     return;
3610   }
3611
3612   fprintf(stderr, "\nRtAudio: ASIO driver reports sample rate changed to %d ... stream stopped!!!", (int) sRate);
3613 }
3614
3615 long asioMessages(long selector, long value, void* message, double* opt)
3616 {
3617   long ret = 0;
3618   switch(selector) {
3619   case kAsioSelectorSupported:
3620     if(value == kAsioResetRequest
3621        || value == kAsioEngineVersion
3622        || value == kAsioResyncRequest
3623        || value == kAsioLatenciesChanged
3624        // The following three were added for ASIO 2.0, you don't
3625        // necessarily have to support them.
3626        || value == kAsioSupportsTimeInfo
3627        || value == kAsioSupportsTimeCode
3628        || value == kAsioSupportsInputMonitor)
3629       ret = 1L;
3630     break;
3631   case kAsioResetRequest:
3632     // Defer the task and perform the reset of the driver during the
3633     // next "safe" situation.  You cannot reset the driver right now,
3634     // as this code is called from the driver.  Reset the driver is
3635     // done by completely destruct is. I.e. ASIOStop(),
3636     // ASIODisposeBuffers(), Destruction Afterwards you initialize the
3637     // driver again.
3638     fprintf(stderr, "\nRtAudio: ASIO driver reset requested!!!");
3639     ret = 1L;
3640     break;
3641   case kAsioResyncRequest:
3642     // This informs the application that the driver encountered some
3643     // non-fatal data loss.  It is used for synchronization purposes
3644     // of different media.  Added mainly to work around the Win16Mutex
3645     // problems in Windows 95/98 with the Windows Multimedia system,
3646     // which could lose data because the Mutex was held too long by
3647     // another thread.  However a driver can issue it in other
3648     // situations, too.
3649     fprintf(stderr, "\nRtAudio: ASIO driver resync requested!!!");
3650     ret = 1L;
3651     break;
3652   case kAsioLatenciesChanged:
3653     // This will inform the host application that the drivers were
3654     // latencies changed.  Beware, it this does not mean that the
3655     // buffer sizes have changed!  You might need to update internal
3656     // delay data.
3657     fprintf(stderr, "\nRtAudio: ASIO driver latency may have changed!!!");
3658     ret = 1L;
3659     break;
3660   case kAsioEngineVersion:
3661     // Return the supported ASIO version of the host application.  If
3662     // a host application does not implement this selector, ASIO 1.0
3663     // is assumed by the driver.
3664     ret = 2L;
3665     break;
3666   case kAsioSupportsTimeInfo:
3667     // Informs the driver whether the
3668     // asioCallbacks.bufferSwitchTimeInfo() callback is supported.
3669     // For compatibility with ASIO 1.0 drivers the host application
3670     // should always support the "old" bufferSwitch method, too.
3671     ret = 0;
3672     break;
3673   case kAsioSupportsTimeCode:
3674     // Informs the driver wether application is interested in time
3675     // code info.  If an application does not need to know about time
3676     // code, the driver has less work to do.
3677     ret = 0;
3678     break;
3679   }
3680   return ret;
3681 }
3682
3683 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
3684                                 STREAM_MODE mode, int channels, 
3685                                 int sampleRate, RTAUDIO_FORMAT format,
3686                                 int *bufferSize, int numberOfBuffers)
3687 {
3688   // Don't attempt to load another driver if a stream is already open.
3689   if ( streams.size() > 0 ) {
3690     sprintf(message, "RtAudio: unable to load ASIO driver while a stream is open.");
3691     error(RtError::WARNING);
3692     return FAILURE;
3693   }
3694
3695   // For ASIO, a duplex stream MUST use the same driver.
3696   if ( mode == INPUT && stream->mode == OUTPUT && stream->device[0] != device ) {
3697     sprintf(message, "RtAudio: ASIO duplex stream must use the same device for input and output.");
3698     error(RtError::WARNING);
3699     return FAILURE;
3700   }
3701
3702   // Only load the driver once for duplex stream.
3703   ASIOError result;
3704   if ( mode != INPUT || stream->mode != OUTPUT ) {
3705     if ( !drivers.loadDriver( devices[device].name ) ) {
3706       sprintf(message, "RtAudio: ASIO error loading driver (%s).", devices[device].name);
3707       error(RtError::DEBUG_WARNING);
3708       return FAILURE;
3709     }
3710
3711     result = ASIOInit( &driverInfo );
3712     if ( result != ASE_OK ) {
3713       char details[32];
3714       if ( result == ASE_HWMalfunction )
3715         sprintf(details, "hardware malfunction");
3716       else if ( result == ASE_NoMemory )
3717         sprintf(details, "no memory");
3718       else if ( result == ASE_NotPresent )
3719         sprintf(details, "driver/hardware not present");
3720       else
3721         sprintf(details, "unspecified");
3722       sprintf(message, "RtAudio: ASIO error (%s) initializing driver (%s).", details, devices[device].name);
3723       error(RtError::DEBUG_WARNING);
3724       return FAILURE;
3725     }
3726   }
3727
3728   // Check the device channel count.
3729   long inputChannels, outputChannels;
3730   result = ASIOGetChannels( &inputChannels, &outputChannels );
3731   if ( result != ASE_OK ) {
3732     drivers.removeCurrentDriver();
3733     sprintf(message, "RtAudio: ASIO error getting input/output channel count (%s).",
3734             devices[device].name);
3735     error(RtError::DEBUG_WARNING);
3736     return FAILURE;
3737   }
3738
3739   if ( ( mode == OUTPUT && channels > outputChannels) ||
3740        ( mode == INPUT && channels > inputChannels) ) {
3741     drivers.removeCurrentDriver();
3742     sprintf(message, "RtAudio: ASIO driver (%s) does not support requested channel count (%d).",
3743             devices[device].name, channels);
3744     error(RtError::DEBUG_WARNING);
3745     return FAILURE;
3746   }
3747   stream->nDeviceChannels[mode] = channels;
3748   stream->nUserChannels[mode] = channels;
3749
3750   // Verify the sample rate is supported.
3751   result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate );
3752   if ( result != ASE_OK ) {
3753     drivers.removeCurrentDriver();
3754     sprintf(message, "RtAudio: ASIO driver (%s) does not support requested sample rate (%d).",
3755             devices[device].name, sampleRate);
3756     error(RtError::DEBUG_WARNING);
3757     return FAILURE;
3758   }
3759
3760   // Set the sample rate.
3761   result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );
3762   if ( result != ASE_OK ) {
3763     drivers.removeCurrentDriver();
3764     sprintf(message, "RtAudio: ASIO driver (%s) error setting sample rate (%d).",
3765             devices[device].name, sampleRate);
3766     error(RtError::DEBUG_WARNING);
3767     return FAILURE;
3768   }
3769
3770   // Determine the driver data type.
3771   ASIOChannelInfo channelInfo;
3772   channelInfo.channel = 0;
3773   if ( mode == OUTPUT ) channelInfo.isInput = false;
3774   else channelInfo.isInput = true;
3775   result = ASIOGetChannelInfo( &channelInfo );
3776   if ( result != ASE_OK ) {
3777     drivers.removeCurrentDriver();
3778     sprintf(message, "RtAudio: ASIO driver (%s) error getting data format.",
3779             devices[device].name);
3780     error(RtError::DEBUG_WARNING);
3781     return FAILURE;
3782   }
3783
3784   // Assuming WINDOWS host is always little-endian.
3785   stream->doByteSwap[mode] = false;
3786   stream->userFormat = format;
3787   stream->deviceFormat[mode] = 0;
3788   if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB ) {
3789     stream->deviceFormat[mode] = RTAUDIO_SINT16;
3790     if ( channelInfo.type == ASIOSTInt16MSB ) stream->doByteSwap[mode] = true;
3791   }
3792   else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB ) {
3793     stream->deviceFormat[mode] = RTAUDIO_SINT32;
3794     if ( channelInfo.type == ASIOSTInt32MSB ) stream->doByteSwap[mode] = true;
3795   }
3796   else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB ) {
3797     stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
3798     if ( channelInfo.type == ASIOSTFloat32MSB ) stream->doByteSwap[mode] = true;
3799   }
3800   else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB ) {
3801     stream->deviceFormat[mode] = RTAUDIO_FLOAT64;
3802     if ( channelInfo.type == ASIOSTFloat64MSB ) stream->doByteSwap[mode] = true;
3803   }
3804
3805   if ( stream->deviceFormat[mode] == 0 ) {
3806     drivers.removeCurrentDriver();
3807     sprintf(message, "RtAudio: ASIO driver (%s) data format not supported by RtAudio.",
3808             devices[device].name);
3809     error(RtError::DEBUG_WARNING);
3810     return FAILURE;
3811   }
3812
3813   // Set the buffer size.  For a duplex stream, this will end up
3814   // setting the buffer size based on the input constraints, which
3815   // should be ok.
3816   long minSize, maxSize, preferSize, granularity;
3817   result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity );
3818   if ( result != ASE_OK ) {
3819     drivers.removeCurrentDriver();
3820     sprintf(message, "RtAudio: ASIO driver (%s) error getting buffer size.",
3821             devices[device].name);
3822     error(RtError::DEBUG_WARNING);
3823     return FAILURE;
3824   }
3825
3826   if ( *bufferSize < minSize ) *bufferSize = minSize;
3827   else if ( *bufferSize > maxSize ) *bufferSize = maxSize;
3828   else if ( granularity == -1 ) {
3829     // Make sure bufferSize is a power of two.
3830     double power = log10( *bufferSize ) / log10( 2.0 );
3831     *bufferSize = pow( 2.0, floor(power+0.5) );
3832     if ( *bufferSize < minSize ) *bufferSize = minSize;
3833     else if ( *bufferSize > maxSize ) *bufferSize = maxSize;
3834     else *bufferSize = preferSize;
3835   }
3836
3837   if ( mode == INPUT && stream->mode == OUTPUT && stream->bufferSize != *bufferSize )
3838     cout << "possible input/output buffersize discrepancy" << endl;
3839
3840   stream->bufferSize = *bufferSize;
3841   stream->nBuffers = 2;
3842
3843   // ASIO always uses deinterleaved channels.
3844   stream->deInterleave[mode] = true;
3845
3846   // Create the ASIO internal buffers.  Since RtAudio sets up input
3847   // and output separately, we'll have to dispose of previously
3848   // created output buffers for a duplex stream.
3849   if ( mode == INPUT && stream->mode == OUTPUT ) {
3850     free(stream->callbackInfo.buffers);
3851     result = ASIODisposeBuffers();
3852     if ( result != ASE_OK ) {
3853       drivers.removeCurrentDriver();
3854       sprintf(message, "RtAudio: ASIO driver (%s) error disposing previously allocated buffers.",
3855               devices[device].name);
3856       error(RtError::DEBUG_WARNING);
3857       return FAILURE;
3858     }
3859   }
3860
3861   // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure.
3862   int i, nChannels = stream->nDeviceChannels[0] + stream->nDeviceChannels[1];
3863   stream->callbackInfo.buffers = 0;
3864   ASIOBufferInfo *bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) );
3865   stream->callbackInfo.buffers = (void *) bufferInfos;
3866   ASIOBufferInfo *infos = bufferInfos;
3867   for ( i=0; i<stream->nDeviceChannels[1]; i++, infos++ ) {
3868     infos->isInput = ASIOTrue;
3869     infos->channelNum = i;
3870     infos->buffers[0] = infos->buffers[1] = 0;
3871   }
3872
3873   for ( i=0; i<stream->nDeviceChannels[0]; i++, infos++ ) {
3874     infos->isInput = ASIOFalse;
3875     infos->channelNum = i;
3876     infos->buffers[0] = infos->buffers[1] = 0;
3877   }
3878
3879   // Set up the ASIO callback structure and create the ASIO data buffers.
3880   asioCallbacks.bufferSwitch = &bufferSwitch;
3881   asioCallbacks.sampleRateDidChange = &sampleRateChanged;
3882   asioCallbacks.asioMessage = &asioMessages;
3883   asioCallbacks.bufferSwitchTimeInfo = NULL;
3884   result = ASIOCreateBuffers( bufferInfos, nChannels, stream->bufferSize, &asioCallbacks);
3885   if ( result != ASE_OK ) {
3886     drivers.removeCurrentDriver();
3887     sprintf(message, "RtAudio: ASIO driver (%s) error creating buffers.",
3888             devices[device].name);
3889     error(RtError::DEBUG_WARNING);
3890     return FAILURE;
3891   }
3892
3893   // Set flags for buffer conversion.
3894   stream->doConvertBuffer[mode] = false;
3895   if (stream->userFormat != stream->deviceFormat[mode])
3896     stream->doConvertBuffer[mode] = true;
3897   if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
3898     stream->doConvertBuffer[mode] = true;
3899   if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode])
3900     stream->doConvertBuffer[mode] = true;
3901
3902   // Allocate necessary internal buffers
3903   if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
3904
3905     long buffer_bytes;
3906     if (stream->nUserChannels[0] >= stream->nUserChannels[1])
3907       buffer_bytes = stream->nUserChannels[0];
3908     else
3909       buffer_bytes = stream->nUserChannels[1];
3910
3911     buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
3912     if (stream->userBuffer) free(stream->userBuffer);
3913     stream->userBuffer = (char *) calloc(buffer_bytes, 1);
3914     if (stream->userBuffer == NULL)
3915       goto memory_error;
3916   }
3917
3918   if ( stream->doConvertBuffer[mode] ) {
3919
3920     long buffer_bytes;
3921     bool makeBuffer = true;
3922     if ( mode == OUTPUT )
3923       buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
3924     else { // mode == INPUT
3925       buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
3926       if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
3927         long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
3928         if ( buffer_bytes < bytes_out ) makeBuffer = false;
3929       }
3930     }
3931
3932     if ( makeBuffer ) {
3933       buffer_bytes *= *bufferSize;
3934       if (stream->deviceBuffer) free(stream->deviceBuffer);
3935       stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
3936       if (stream->deviceBuffer == NULL)
3937         goto memory_error;
3938     }
3939   }
3940
3941   stream->device[mode] = device;
3942   stream->state = STREAM_STOPPED;
3943   if ( stream->mode == OUTPUT && mode == INPUT )
3944     // We had already set up an output stream.
3945     stream->mode = DUPLEX;
3946   else
3947     stream->mode = mode;
3948   stream->sampleRate = sampleRate;
3949   asioCallbackInfo = &stream->callbackInfo;
3950   stream->callbackInfo.object = (void *) this;
3951   stream->callbackInfo.waitTime = (unsigned long) (200.0 * stream->bufferSize / stream->sampleRate);
3952
3953   return SUCCESS;
3954
3955  memory_error:
3956   ASIODisposeBuffers();
3957   drivers.removeCurrentDriver();
3958
3959   if (stream->callbackInfo.buffers)
3960     free(stream->callbackInfo.buffers);
3961   stream->callbackInfo.buffers = 0;
3962
3963   if (stream->userBuffer) {
3964     free(stream->userBuffer);
3965     stream->userBuffer = 0;
3966   }
3967   sprintf(message, "RtAudio: error allocating buffer memory (%s).",
3968           devices[device].name);
3969   error(RtError::WARNING);
3970   return FAILURE;
3971 }
3972
3973 void RtAudio :: cancelStreamCallback(int streamId)
3974 {
3975   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3976
3977   if (stream->callbackInfo.usingCallback) {
3978
3979     if (stream->state == STREAM_RUNNING)
3980       stopStream( streamId );
3981
3982     MUTEX_LOCK(&stream->mutex);
3983
3984     stream->callbackInfo.usingCallback = false;
3985     stream->callbackInfo.userData = NULL;
3986     stream->state = STREAM_STOPPED;
3987     stream->callbackInfo.callback = NULL;
3988
3989     MUTEX_UNLOCK(&stream->mutex);
3990   }
3991 }
3992
3993 void RtAudio :: closeStream(int streamId)
3994 {
3995   // We don't want an exception to be thrown here because this
3996   // function is called by our class destructor.  So, do our own
3997   // streamId check.
3998   if ( streams.find( streamId ) == streams.end() ) {
3999     sprintf(message, "RtAudio: invalid stream identifier!");
4000     error(RtError::WARNING);
4001     return;
4002   }
4003
4004   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
4005
4006   if (stream->state == STREAM_RUNNING)
4007     ASIOStop();
4008
4009   ASIODisposeBuffers();
4010   //ASIOExit();
4011   drivers.removeCurrentDriver();
4012
4013   DeleteCriticalSection(&stream->mutex);
4014
4015   if (stream->callbackInfo.buffers)
4016     free(stream->callbackInfo.buffers);
4017
4018   if (stream->userBuffer)
4019     free(stream->userBuffer);
4020
4021   if (stream->deviceBuffer)
4022     free(stream->deviceBuffer);
4023
4024   free(stream);
4025   streams.erase(streamId);
4026 }
4027
4028 void RtAudio :: startStream(int streamId)
4029 {
4030   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4031
4032   MUTEX_LOCK(&stream->mutex);
4033
4034   if (stream->state == STREAM_RUNNING) {
4035     MUTEX_UNLOCK(&stream->mutex);
4036     return;
4037   }
4038
4039   stream->callbackInfo.blockTick = true;
4040   stream->callbackInfo.stopStream = false;
4041   stream->callbackInfo.streamId = streamId;
4042   ASIOError result = ASIOStart();
4043   if ( result != ASE_OK ) {
4044     sprintf(message, "RtAudio: ASIO error starting device (%s).",
4045               devices[stream->device[0]].name);
4046     MUTEX_UNLOCK(&stream->mutex);
4047     error(RtError::DRIVER_ERROR);
4048   }
4049   stream->state = STREAM_RUNNING;
4050
4051   MUTEX_UNLOCK(&stream->mutex);
4052 }
4053
4054 void RtAudio :: stopStream(int streamId)
4055 {
4056   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4057
4058   MUTEX_LOCK(&stream->mutex);
4059
4060   if (stream->state == STREAM_STOPPED) {
4061     MUTEX_UNLOCK(&stream->mutex);
4062     return;
4063   }
4064
4065   ASIOError result = ASIOStop();
4066   if ( result != ASE_OK ) {
4067     sprintf(message, "RtAudio: ASIO error stopping device (%s).",
4068               devices[stream->device[0]].name);
4069     MUTEX_UNLOCK(&stream->mutex);
4070     error(RtError::DRIVER_ERROR);
4071   }
4072   stream->state = STREAM_STOPPED;
4073
4074   MUTEX_UNLOCK(&stream->mutex);
4075 }
4076
4077 void RtAudio :: abortStream(int streamId)
4078 {
4079   stopStream( streamId );
4080 }
4081
4082 // I don't know how this function can be implemented.
4083 int RtAudio :: streamWillBlock(int streamId)
4084 {
4085   sprintf(message, "RtAudio: streamWillBlock() cannot be implemented for ASIO.");
4086   error(RtError::WARNING);
4087   return 0;
4088 }
4089
4090 void RtAudio :: tickStream(int streamId)
4091 {
4092   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4093
4094   if (stream->state == STREAM_STOPPED)
4095     return;
4096
4097   if (stream->callbackInfo.usingCallback) {
4098     sprintf(message, "RtAudio: tickStream() should not be used when a callback function is set!");
4099     error(RtError::WARNING);
4100     return;
4101   }
4102
4103   // Block waiting here until the user data is processed in callbackEvent().
4104   while ( stream->callbackInfo.blockTick )
4105     Sleep(stream->callbackInfo.waitTime);
4106
4107   MUTEX_LOCK(&stream->mutex);
4108
4109   stream->callbackInfo.blockTick = true;
4110
4111   MUTEX_UNLOCK(&stream->mutex);
4112 }
4113
4114 void RtAudio :: callbackEvent(int streamId, int bufferIndex, void *inData, void *outData)
4115 {
4116   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4117
4118   CALLBACK_INFO *info = asioCallbackInfo;
4119   if ( !info->usingCallback ) {
4120     // Block waiting here until we get new user data in tickStream().
4121     while ( !info->blockTick )
4122       Sleep(info->waitTime);
4123   }
4124   else if ( info->stopStream ) {
4125     // Check if the stream should be stopped (via the previous user
4126     // callback return value).  We stop the stream here, rather than
4127     // after the function call, so that output data can first be
4128     // processed.
4129     this->stopStream(asioCallbackInfo->streamId);
4130     return;
4131   }
4132
4133   MUTEX_LOCK(&stream->mutex);
4134
4135   // Invoke user callback first, to get fresh output data.
4136   if ( info->usingCallback ) {
4137     RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) info->callback;
4138     if ( callback(stream->userBuffer, stream->bufferSize, info->userData) )
4139       info->stopStream = true;
4140   }
4141
4142   int nChannels = stream->nDeviceChannels[0] + stream->nDeviceChannels[1];
4143   int bufferBytes;
4144   ASIOBufferInfo *bufferInfos = (ASIOBufferInfo *) info->buffers;
4145   if ( stream->mode == OUTPUT || stream->mode == DUPLEX ) {
4146
4147     bufferBytes = stream->bufferSize * formatBytes(stream->deviceFormat[0]);
4148     if (stream->doConvertBuffer[0]) {
4149
4150       convertStreamBuffer(stream, OUTPUT);
4151       if ( stream->doByteSwap[0] )
4152         byteSwapBuffer(stream->deviceBuffer,
4153                        stream->bufferSize * stream->nDeviceChannels[0],
4154                        stream->deviceFormat[0]);
4155
4156       // Always de-interleave ASIO output data.
4157       for ( int i=0; i<stream->nDeviceChannels[0]; i++, bufferInfos++ ) {
4158         memcpy(bufferInfos->buffers[bufferIndex],
4159                &stream->deviceBuffer[i*bufferBytes], bufferBytes );
4160       }
4161     }
4162     else { // single channel only
4163
4164       if (stream->doByteSwap[0])
4165         byteSwapBuffer(stream->userBuffer,
4166                        stream->bufferSize * stream->nUserChannels[0],
4167                        stream->userFormat);
4168
4169       memcpy(bufferInfos->buffers[bufferIndex], stream->userBuffer, bufferBytes );
4170     }
4171   }
4172
4173   if ( stream->mode == INPUT || stream->mode == DUPLEX ) {
4174
4175     bufferBytes = stream->bufferSize * formatBytes(stream->deviceFormat[1]);
4176     if (stream->doConvertBuffer[1]) {
4177
4178       // Always interleave ASIO input data.
4179       for ( int i=0; i<stream->nDeviceChannels[1]; i++, bufferInfos++ )
4180         memcpy(&stream->deviceBuffer[i*bufferBytes], bufferInfos->buffers[bufferIndex], bufferBytes );
4181
4182       if ( stream->doByteSwap[1] )
4183         byteSwapBuffer(stream->deviceBuffer,
4184                        stream->bufferSize * stream->nDeviceChannels[1],
4185                        stream->deviceFormat[1]);
4186       convertStreamBuffer(stream, INPUT);
4187
4188     }
4189     else { // single channel only
4190       memcpy(stream->userBuffer, bufferInfos->buffers[bufferIndex], bufferBytes );
4191
4192       if (stream->doByteSwap[1])
4193         byteSwapBuffer(stream->userBuffer,
4194                        stream->bufferSize * stream->nUserChannels[1],
4195                        stream->userFormat);
4196     }
4197   }
4198
4199   if ( !info->usingCallback )
4200     info->blockTick = false;
4201
4202   MUTEX_UNLOCK(&stream->mutex);
4203 }
4204
4205 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
4206 {
4207   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4208
4209   stream->callbackInfo.callback = (void *) callback;
4210   stream->callbackInfo.userData = userData;
4211   stream->callbackInfo.usingCallback = true;
4212 }
4213
4214 //******************** End of __WINDOWS_ASIO__ *********************//
4215
4216 #elif defined(__WINDOWS_DS__) // Windows DirectSound API
4217
4218 #include <dsound.h>
4219
4220 // Declarations for utility functions, callbacks, and structures
4221 // specific to the DirectSound implementation.
4222 static bool CALLBACK deviceCountCallback(LPGUID lpguid,
4223                                          LPCSTR lpcstrDescription,
4224                                          LPCSTR lpcstrModule,
4225                                          LPVOID lpContext);
4226
4227 static bool CALLBACK deviceInfoCallback(LPGUID lpguid,
4228                                         LPCSTR lpcstrDescription,
4229                                         LPCSTR lpcstrModule,
4230                                         LPVOID lpContext);
4231
4232 static bool CALLBACK defaultDeviceCallback(LPGUID lpguid,
4233                                            LPCSTR lpcstrDescription,
4234                                            LPCSTR lpcstrModule,
4235                                            LPVOID lpContext);
4236
4237 static bool CALLBACK deviceIdCallback(LPGUID lpguid,
4238                                       LPCSTR lpcstrDescription,
4239                                       LPCSTR lpcstrModule,
4240                                       LPVOID lpContext);
4241
4242 static char* getErrorString(int code);
4243
4244 struct enum_info {
4245   char name[64];
4246   LPGUID id;
4247   bool isInput;
4248   bool isValid;
4249 };
4250
4251 int RtAudio :: getDefaultInputDevice(void)
4252 {
4253   enum_info info;
4254   info.name[0] = '\0';
4255
4256   // Enumerate through devices to find the default output.
4257   HRESULT result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)defaultDeviceCallback, &info);
4258   if ( FAILED(result) ) {
4259     sprintf(message, "RtAudio: Error performing default input device enumeration: %s.",
4260             getErrorString(result));
4261     error(RtError::WARNING);
4262     return 0;
4263   }
4264
4265   for ( int i=0; i<nDevices; i++ )
4266     if ( strncmp( devices[i].name, info.name, 64 ) == 0 ) return i;
4267
4268   return 0;
4269 }
4270
4271 int RtAudio :: getDefaultOutputDevice(void)
4272 {
4273   enum_info info;
4274   info.name[0] = '\0';
4275
4276   // Enumerate through devices to find the default output.
4277   HRESULT result = DirectSoundEnumerate((LPDSENUMCALLBACK)defaultDeviceCallback, &info);
4278   if ( FAILED(result) ) {
4279     sprintf(message, "RtAudio: Error performing default output device enumeration: %s.",
4280             getErrorString(result));
4281     error(RtError::WARNING);
4282     return 0;
4283   }
4284
4285   for ( int i=0; i<nDevices; i++ )
4286     if ( strncmp(devices[i].name, info.name, 64 ) == 0 ) return i;
4287
4288   return 0;
4289 }
4290
4291 void RtAudio :: initialize(void)
4292 {
4293   int i, ins = 0, outs = 0, count = 0;
4294   HRESULT result;
4295   nDevices = 0;
4296
4297   // Count DirectSound devices.
4298   result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &outs);
4299   if ( FAILED(result) ) {
4300     sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.",
4301             getErrorString(result));
4302     error(RtError::DRIVER_ERROR);
4303   }
4304
4305   // Count DirectSoundCapture devices.
4306   result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &ins);
4307   if ( FAILED(result) ) {
4308     sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.",
4309             getErrorString(result));
4310     error(RtError::DRIVER_ERROR);
4311   }
4312
4313   count = ins + outs;
4314   if (count == 0) return;
4315
4316   std::vector<enum_info> info(count);
4317   for (i=0; i<count; i++) {
4318     info[i].name[0] = '\0';
4319     if (i < outs) info[i].isInput = false;
4320     else info[i].isInput = true;
4321   }
4322
4323   // Get playback device info and check capabilities.
4324   result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]);
4325   if ( FAILED(result) ) {
4326     sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.",
4327             getErrorString(result));
4328     error(RtError::DRIVER_ERROR);
4329   }
4330
4331   // Get capture device info and check capabilities.
4332   result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]);
4333   if ( FAILED(result) ) {
4334     sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.",
4335             getErrorString(result));
4336     error(RtError::DRIVER_ERROR);
4337   }
4338
4339   // Parse the devices and check validity.  Devices are considered
4340   // invalid if they cannot be opened, they report < 1 supported
4341   // channels, or they report no supported data (capture only).
4342   for (i=0; i<count; i++)
4343     if ( info[i].isValid ) nDevices++;
4344
4345   if (nDevices == 0) return;
4346
4347   //  Allocate the RTAUDIO_DEVICE structures.
4348   devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
4349   if (devices == NULL) {
4350     sprintf(message, "RtAudio: memory allocation error!");
4351     error(RtError::MEMORY_ERROR);
4352   }
4353
4354   // Copy the names to our devices structures.
4355   int index = 0;
4356   for (i=0; i<count; i++) {
4357     if ( info[i].isValid )
4358       strncpy(devices[index++].name, info[i].name, 64);
4359   }
4360
4361   //for (i=0;i<nDevices; i++)
4362   //probeDeviceInfo(&devices[i]);
4363
4364   return;
4365 }
4366
4367 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
4368 {
4369   enum_info dsinfo;
4370   strncpy( dsinfo.name, info->name, 64 );
4371   dsinfo.isValid = false;
4372
4373   // Enumerate through input devices to find the id (if it exists).
4374   HRESULT result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
4375   if ( FAILED(result) ) {
4376     sprintf(message, "RtAudio: Error performing input device id enumeration: %s.",
4377             getErrorString(result));
4378     error(RtError::WARNING);
4379     return;
4380   }
4381
4382   // Do capture probe first.
4383   if ( dsinfo.isValid == false )
4384     goto playback_probe;
4385
4386   LPDIRECTSOUNDCAPTURE  input;
4387   result = DirectSoundCaptureCreate( dsinfo.id, &input, NULL );
4388   if ( FAILED(result) ) {
4389     sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.",
4390             info->name, getErrorString(result));
4391     error(RtError::WARNING);
4392     goto playback_probe;
4393   }
4394
4395   DSCCAPS in_caps;
4396   in_caps.dwSize = sizeof(in_caps);
4397   result = input->GetCaps( &in_caps );
4398   if ( FAILED(result) ) {
4399     input->Release();
4400     sprintf(message, "RtAudio: Could not get DirectSound capture capabilities (%s): %s.",
4401             info->name, getErrorString(result));
4402     error(RtError::WARNING);
4403     goto playback_probe;
4404   }
4405
4406   // Get input channel information.
4407   info->minInputChannels = 1;
4408   info->maxInputChannels = in_caps.dwChannels;
4409
4410   // Get sample rate and format information.
4411   if( in_caps.dwChannels == 2 ) {
4412     if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->nativeFormats |= RTAUDIO_SINT16;
4413     if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->nativeFormats |= RTAUDIO_SINT16;
4414     if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->nativeFormats |= RTAUDIO_SINT16;
4415     if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->nativeFormats |= RTAUDIO_SINT8;
4416     if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->nativeFormats |= RTAUDIO_SINT8;
4417     if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->nativeFormats |= RTAUDIO_SINT8;
4418
4419     if ( info->nativeFormats & RTAUDIO_SINT16 ) {
4420       if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->sampleRates[info->nSampleRates++] = 11025;
4421       if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->sampleRates[info->nSampleRates++] = 22050;
4422       if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->sampleRates[info->nSampleRates++] = 44100;
4423     }
4424     else if ( info->nativeFormats & RTAUDIO_SINT8 ) {
4425       if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->sampleRates[info->nSampleRates++] = 11025;
4426       if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->sampleRates[info->nSampleRates++] = 22050;
4427       if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->sampleRates[info->nSampleRates++] = 44100;
4428     }
4429   }
4430   else if ( in_caps.dwChannels == 1 ) {
4431     if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->nativeFormats |= RTAUDIO_SINT16;
4432     if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->nativeFormats |= RTAUDIO_SINT16;
4433     if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->nativeFormats |= RTAUDIO_SINT16;
4434     if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->nativeFormats |= RTAUDIO_SINT8;
4435     if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->nativeFormats |= RTAUDIO_SINT8;
4436     if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->nativeFormats |= RTAUDIO_SINT8;
4437
4438     if ( info->nativeFormats & RTAUDIO_SINT16 ) {
4439       if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->sampleRates[info->nSampleRates++] = 11025;
4440       if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->sampleRates[info->nSampleRates++] = 22050;
4441       if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->sampleRates[info->nSampleRates++] = 44100;
4442     }
4443     else if ( info->nativeFormats & RTAUDIO_SINT8 ) {
4444       if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->sampleRates[info->nSampleRates++] = 11025;
4445       if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->sampleRates[info->nSampleRates++] = 22050;
4446       if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->sampleRates[info->nSampleRates++] = 44100;
4447     }
4448   }
4449   else info->minInputChannels = 0; // technically, this would be an error
4450
4451   input->Release();
4452
4453  playback_probe:
4454
4455   dsinfo.isValid = false;
4456
4457   // Enumerate through output devices to find the id (if it exists).
4458   result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
4459   if ( FAILED(result) ) {
4460     sprintf(message, "RtAudio: Error performing output device id enumeration: %s.",
4461             getErrorString(result));
4462     error(RtError::WARNING);
4463     return;
4464   }
4465
4466   // Now do playback probe.
4467   if ( dsinfo.isValid == false )
4468     goto check_parameters;
4469
4470   LPDIRECTSOUND  output;
4471   DSCAPS out_caps;
4472   result = DirectSoundCreate( dsinfo.id, &output, NULL );
4473   if ( FAILED(result) ) {
4474     sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.",
4475             info->name, getErrorString(result));
4476     error(RtError::WARNING);
4477     goto check_parameters;
4478   }
4479
4480   out_caps.dwSize = sizeof(out_caps);
4481   result = output->GetCaps( &out_caps );
4482   if ( FAILED(result) ) {
4483     output->Release();
4484     sprintf(message, "RtAudio: Could not get DirectSound playback capabilities (%s): %s.",
4485             info->name, getErrorString(result));
4486     error(RtError::WARNING);
4487     goto check_parameters;
4488   }
4489
4490   // Get output channel information.
4491   info->minOutputChannels = 1;
4492   info->maxOutputChannels = ( out_caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
4493
4494   // Get sample rate information.  Use capture device rate information
4495   // if it exists.
4496   if ( info->nSampleRates == 0 ) {
4497     info->sampleRates[0] = (int) out_caps.dwMinSecondarySampleRate;
4498     info->sampleRates[1] = (int) out_caps.dwMaxSecondarySampleRate;
4499     if ( out_caps.dwFlags & DSCAPS_CONTINUOUSRATE )
4500       info->nSampleRates = -1;
4501     else if ( out_caps.dwMinSecondarySampleRate == out_caps.dwMaxSecondarySampleRate ) {
4502       if ( out_caps.dwMinSecondarySampleRate == 0 ) {
4503         // This is a bogus driver report ... fake the range and cross
4504         // your fingers.
4505         info->sampleRates[0] = 11025;
4506                                 info->sampleRates[1] = 48000;
4507         info->nSampleRates = -1; /* continuous range */
4508         sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using defaults (%s).",
4509                 info->name);
4510         error(RtError::DEBUG_WARNING);
4511       }
4512       else {
4513         info->nSampleRates = 1;
4514                         }
4515     }
4516     else if ( (out_caps.dwMinSecondarySampleRate < 1000.0) &&
4517               (out_caps.dwMaxSecondarySampleRate > 50000.0) ) {
4518       // This is a bogus driver report ... support for only two
4519       // distant rates.  We'll assume this is a range.
4520       info->nSampleRates = -1;
4521       sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using range (%s).",
4522               info->name);
4523       error(RtError::WARNING);
4524     }
4525     else info->nSampleRates = 2;
4526   }
4527   else {
4528     // Check input rates against output rate range
4529     for ( int i=info->nSampleRates-1; i>=0; i-- ) {
4530       if ( info->sampleRates[i] <= out_caps.dwMaxSecondarySampleRate )
4531         break;
4532       info->nSampleRates--;
4533     }
4534     while ( info->sampleRates[0] < out_caps.dwMinSecondarySampleRate ) {
4535       info->nSampleRates--;
4536       for ( int i=0; i<info->nSampleRates; i++)
4537         info->sampleRates[i] = info->sampleRates[i+1];
4538       if ( info->nSampleRates <= 0 ) break;
4539     }
4540   }
4541
4542   // Get format information.
4543   if ( out_caps.dwFlags & DSCAPS_PRIMARY16BIT ) info->nativeFormats |= RTAUDIO_SINT16;
4544   if ( out_caps.dwFlags & DSCAPS_PRIMARY8BIT ) info->nativeFormats |= RTAUDIO_SINT8;
4545
4546   output->Release();
4547
4548  check_parameters:
4549   if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 )
4550     return;
4551   if ( info->nSampleRates == 0 || info->nativeFormats == 0 )
4552     return;
4553
4554   // Determine duplex status.
4555   if (info->maxInputChannels < info->maxOutputChannels)
4556     info->maxDuplexChannels = info->maxInputChannels;
4557   else
4558     info->maxDuplexChannels = info->maxOutputChannels;
4559   if (info->minInputChannels < info->minOutputChannels)
4560     info->minDuplexChannels = info->minInputChannels;
4561   else
4562     info->minDuplexChannels = info->minOutputChannels;
4563
4564   if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true;
4565   else info->hasDuplexSupport = false;
4566
4567   info->probed = true;
4568
4569   return;
4570 }
4571
4572 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
4573                                 STREAM_MODE mode, int channels, 
4574                                 int sampleRate, RTAUDIO_FORMAT format,
4575                                 int *bufferSize, int numberOfBuffers)
4576 {
4577   HRESULT result;
4578   HWND hWnd = GetForegroundWindow();
4579   // According to a note in PortAudio, using GetDesktopWindow()
4580   // instead of GetForegroundWindow() is supposed to avoid problems
4581   // that occur when the application's window is not the foreground
4582   // window.  Also, if the application window closes before the
4583   // DirectSound buffer, DirectSound can crash.  However, for console
4584   // applications, no sound was produced when using GetDesktopWindow().
4585   long buffer_size;
4586   LPVOID audioPtr;
4587   DWORD dataLen;
4588   int nBuffers;
4589
4590   // Check the numberOfBuffers parameter and limit the lowest value to
4591   // two.  This is a judgement call and a value of two is probably too
4592   // low for capture, but it should work for playback.
4593   if (numberOfBuffers < 2)
4594     nBuffers = 2;
4595   else
4596     nBuffers = numberOfBuffers;
4597
4598   // Define the wave format structure (16-bit PCM, srate, channels)
4599   WAVEFORMATEX waveFormat;
4600   ZeroMemory(&waveFormat, sizeof(WAVEFORMATEX));
4601   waveFormat.wFormatTag = WAVE_FORMAT_PCM;
4602   waveFormat.nChannels = channels;
4603   waveFormat.nSamplesPerSec = (unsigned long) sampleRate;
4604
4605   // Determine the data format.
4606   if ( devices[device].nativeFormats ) { // 8-bit and/or 16-bit support
4607     if ( format == RTAUDIO_SINT8 ) {
4608       if ( devices[device].nativeFormats & RTAUDIO_SINT8 )
4609         waveFormat.wBitsPerSample = 8;
4610       else
4611         waveFormat.wBitsPerSample = 16;
4612     }
4613     else {
4614       if ( devices[device].nativeFormats & RTAUDIO_SINT16 )
4615         waveFormat.wBitsPerSample = 16;
4616       else
4617         waveFormat.wBitsPerSample = 8;
4618     }
4619   }
4620   else {
4621     sprintf(message, "RtAudio: no reported data formats for DirectSound device (%s).",
4622             devices[device].name);
4623     error(RtError::DEBUG_WARNING);
4624     return FAILURE;
4625   }
4626
4627   waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
4628   waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
4629
4630   enum_info dsinfo;
4631   strncpy( dsinfo.name, devices[device].name, 64 );
4632   dsinfo.isValid = false;
4633   if ( mode == OUTPUT ) {
4634
4635     if ( devices[device].maxOutputChannels < channels )
4636       return FAILURE;
4637
4638     // Enumerate through output devices to find the id (if it exists).
4639     result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
4640     if ( FAILED(result) ) {
4641       sprintf(message, "RtAudio: Error performing output device id enumeration: %s.",
4642               getErrorString(result));
4643       error(RtError::DEBUG_WARNING);
4644       return FAILURE;
4645     }
4646
4647     if ( dsinfo.isValid == false ) {
4648       sprintf(message, "RtAudio: DS output device (%s) id not found!", devices[device].name);
4649       error(RtError::DEBUG_WARNING);
4650       return FAILURE;
4651     }
4652
4653     LPGUID id = dsinfo.id;
4654     LPDIRECTSOUND  object;
4655     LPDIRECTSOUNDBUFFER buffer;
4656     DSBUFFERDESC bufferDescription;
4657     
4658     result = DirectSoundCreate( id, &object, NULL );
4659     if ( FAILED(result) ) {
4660       sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.",
4661               devices[device].name, getErrorString(result));
4662       error(RtError::DEBUG_WARNING);
4663       return FAILURE;
4664     }
4665
4666     // Set cooperative level to DSSCL_EXCLUSIVE
4667     result = object->SetCooperativeLevel(hWnd, DSSCL_EXCLUSIVE);
4668     if ( FAILED(result) ) {
4669       object->Release();
4670       sprintf(message, "RtAudio: Unable to set DirectSound cooperative level (%s): %s.",
4671               devices[device].name, getErrorString(result));
4672       error(RtError::WARNING);
4673       return FAILURE;
4674     }
4675
4676     // Even though we will write to the secondary buffer, we need to
4677     // access the primary buffer to set the correct output format.
4678     // The default is 8-bit, 22 kHz!
4679     // Setup the DS primary buffer description.
4680     ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
4681     bufferDescription.dwSize = sizeof(DSBUFFERDESC);
4682     bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
4683     // Obtain the primary buffer
4684     result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
4685     if ( FAILED(result) ) {
4686       object->Release();
4687       sprintf(message, "RtAudio: Unable to access DS primary buffer (%s): %s.",
4688               devices[device].name, getErrorString(result));
4689       error(RtError::WARNING);
4690       return FAILURE;
4691     }
4692
4693     // Set the primary DS buffer sound format.
4694     result = buffer->SetFormat(&waveFormat);
4695     if ( FAILED(result) ) {
4696       object->Release();
4697       sprintf(message, "RtAudio: Unable to set DS primary buffer format (%s): %s.",
4698               devices[device].name, getErrorString(result));
4699       error(RtError::WARNING);
4700       return FAILURE;
4701     }
4702
4703     // Setup the secondary DS buffer description.
4704     buffer_size = channels * *bufferSize * nBuffers * waveFormat.wBitsPerSample / 8;
4705     ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
4706     bufferDescription.dwSize = sizeof(DSBUFFERDESC);
4707     bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
4708                                   DSBCAPS_GETCURRENTPOSITION2 |
4709                                   DSBCAPS_LOCHARDWARE );  // Force hardware mixing
4710     bufferDescription.dwBufferBytes = buffer_size;
4711     bufferDescription.lpwfxFormat = &waveFormat;
4712
4713     // Try to create the secondary DS buffer.  If that doesn't work,
4714     // try to use software mixing.  Otherwise, there's a problem.
4715     result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
4716     if ( FAILED(result) ) {
4717       bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
4718                                     DSBCAPS_GETCURRENTPOSITION2 |
4719                                     DSBCAPS_LOCSOFTWARE );  // Force software mixing
4720       result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
4721       if ( FAILED(result) ) {
4722         object->Release();
4723         sprintf(message, "RtAudio: Unable to create secondary DS buffer (%s): %s.",
4724                 devices[device].name, getErrorString(result));
4725         error(RtError::WARNING);
4726         return FAILURE;
4727       }
4728     }
4729
4730     // Get the buffer size ... might be different from what we specified.
4731     DSBCAPS dsbcaps;
4732     dsbcaps.dwSize = sizeof(DSBCAPS);
4733     buffer->GetCaps(&dsbcaps);
4734     buffer_size = dsbcaps.dwBufferBytes;
4735
4736     // Lock the DS buffer
4737     result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0);
4738     if ( FAILED(result) ) {
4739       object->Release();
4740       sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.",
4741               devices[device].name, getErrorString(result));
4742       error(RtError::WARNING);
4743       return FAILURE;
4744     }
4745
4746     // Zero the DS buffer
4747     ZeroMemory(audioPtr, dataLen);
4748
4749     // Unlock the DS buffer
4750     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
4751     if ( FAILED(result) ) {
4752       object->Release();
4753       sprintf(message, "RtAudio: Unable to unlock DS buffer(%s): %s.",
4754               devices[device].name, getErrorString(result));
4755       error(RtError::WARNING);
4756       return FAILURE;
4757     }
4758
4759     stream->handle[0].object = (void *) object;
4760     stream->handle[0].buffer = (void *) buffer;
4761     stream->nDeviceChannels[0] = channels;
4762   }
4763
4764   if ( mode == INPUT ) {
4765
4766     if ( devices[device].maxInputChannels < channels )
4767       return FAILURE;
4768
4769     // Enumerate through input devices to find the id (if it exists).
4770     result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
4771     if ( FAILED(result) ) {
4772       sprintf(message, "RtAudio: Error performing input device id enumeration: %s.",
4773               getErrorString(result));
4774       error(RtError::DEBUG_WARNING);
4775       return FAILURE;
4776     }
4777
4778     if ( dsinfo.isValid == false ) {
4779       sprintf(message, "RtAudio: DS input device (%s) id not found!", devices[device].name);
4780       error(RtError::DEBUG_WARNING);
4781       return FAILURE;
4782     }
4783
4784     LPGUID id = dsinfo.id;
4785     LPDIRECTSOUNDCAPTURE  object;
4786     LPDIRECTSOUNDCAPTUREBUFFER buffer;
4787     DSCBUFFERDESC bufferDescription;
4788
4789     result = DirectSoundCaptureCreate( id, &object, NULL );
4790     if ( FAILED(result) ) {
4791       sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.",
4792               devices[device].name, getErrorString(result));
4793       error(RtError::WARNING);
4794       return FAILURE;
4795     }
4796
4797     // Setup the secondary DS buffer description.
4798     buffer_size = channels * *bufferSize * nBuffers * waveFormat.wBitsPerSample / 8;
4799     ZeroMemory(&bufferDescription, sizeof(DSCBUFFERDESC));
4800     bufferDescription.dwSize = sizeof(DSCBUFFERDESC);
4801     bufferDescription.dwFlags = 0;
4802     bufferDescription.dwReserved = 0;
4803     bufferDescription.dwBufferBytes = buffer_size;
4804     bufferDescription.lpwfxFormat = &waveFormat;
4805
4806     // Create the capture buffer.
4807     result = object->CreateCaptureBuffer(&bufferDescription, &buffer, NULL);
4808     if ( FAILED(result) ) {
4809       object->Release();
4810       sprintf(message, "RtAudio: Unable to create DS capture buffer (%s): %s.",
4811               devices[device].name, getErrorString(result));
4812       error(RtError::WARNING);
4813       return FAILURE;
4814     }
4815
4816     // Lock the capture buffer
4817     result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0);
4818     if ( FAILED(result) ) {
4819       object->Release();
4820       sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
4821               devices[device].name, getErrorString(result));
4822       error(RtError::WARNING);
4823       return FAILURE;
4824     }
4825
4826     // Zero the buffer
4827     ZeroMemory(audioPtr, dataLen);
4828
4829     // Unlock the buffer
4830     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
4831     if ( FAILED(result) ) {
4832       object->Release();
4833       sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
4834               devices[device].name, getErrorString(result));
4835       error(RtError::WARNING);
4836       return FAILURE;
4837     }
4838
4839     stream->handle[1].object = (void *) object;
4840     stream->handle[1].buffer = (void *) buffer;
4841     stream->nDeviceChannels[1] = channels;
4842   }
4843
4844   stream->userFormat = format;
4845   if ( waveFormat.wBitsPerSample == 8 )
4846     stream->deviceFormat[mode] = RTAUDIO_SINT8;
4847   else
4848     stream->deviceFormat[mode] = RTAUDIO_SINT16;
4849   stream->nUserChannels[mode] = channels;
4850   *bufferSize = buffer_size / (channels * nBuffers * waveFormat.wBitsPerSample / 8);
4851   stream->bufferSize = *bufferSize;
4852
4853   // Set flags for buffer conversion
4854   stream->doConvertBuffer[mode] = false;
4855   if (stream->userFormat != stream->deviceFormat[mode])
4856     stream->doConvertBuffer[mode] = true;
4857   if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
4858     stream->doConvertBuffer[mode] = true;
4859
4860   // Allocate necessary internal buffers
4861   if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
4862
4863     long buffer_bytes;
4864     if (stream->nUserChannels[0] >= stream->nUserChannels[1])
4865       buffer_bytes = stream->nUserChannels[0];
4866     else
4867       buffer_bytes = stream->nUserChannels[1];
4868
4869     buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
4870     if (stream->userBuffer) free(stream->userBuffer);
4871     stream->userBuffer = (char *) calloc(buffer_bytes, 1);
4872     if (stream->userBuffer == NULL)
4873       goto memory_error;
4874   }
4875
4876   if ( stream->doConvertBuffer[mode] ) {
4877
4878     long buffer_bytes;
4879     bool makeBuffer = true;
4880     if ( mode == OUTPUT )
4881       buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
4882     else { // mode == INPUT
4883       buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
4884       if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
4885         long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
4886         if ( buffer_bytes < bytes_out ) makeBuffer = false;
4887       }
4888     }
4889
4890     if ( makeBuffer ) {
4891       buffer_bytes *= *bufferSize;
4892       if (stream->deviceBuffer) free(stream->deviceBuffer);
4893       stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
4894       if (stream->deviceBuffer == NULL)
4895         goto memory_error;
4896     }
4897   }
4898
4899   stream->device[mode] = device;
4900   stream->state = STREAM_STOPPED;
4901   if ( stream->mode == OUTPUT && mode == INPUT )
4902     // We had already set up an output stream.
4903     stream->mode = DUPLEX;
4904   else
4905     stream->mode = mode;
4906   stream->nBuffers = nBuffers;
4907   stream->sampleRate = sampleRate;
4908
4909   return SUCCESS;
4910
4911  memory_error:
4912   if (stream->handle[0].object) {
4913     LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object;
4914     LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
4915     if (buffer) {
4916       buffer->Release();
4917       stream->handle[0].buffer = NULL;
4918     }
4919     object->Release();
4920     stream->handle[0].object = NULL;
4921   }
4922   if (stream->handle[1].object) {
4923     LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object;
4924     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
4925     if (buffer) {
4926       buffer->Release();
4927       stream->handle[1].buffer = NULL;
4928     }
4929     object->Release();
4930     stream->handle[1].object = NULL;
4931   }
4932   if (stream->userBuffer) {
4933     free(stream->userBuffer);
4934     stream->userBuffer = 0;
4935   }
4936   sprintf(message, "RtAudio: error allocating buffer memory (%s).",
4937           devices[device].name);
4938   error(RtError::WARNING);
4939   return FAILURE;
4940 }
4941
4942 void RtAudio :: cancelStreamCallback(int streamId)
4943 {
4944   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4945
4946   if (stream->callbackInfo.usingCallback) {
4947
4948     if (stream->state == STREAM_RUNNING)
4949       stopStream( streamId );
4950
4951     MUTEX_LOCK(&stream->mutex);
4952
4953     stream->callbackInfo.usingCallback = false;
4954     WaitForSingleObject( (HANDLE)stream->callbackInfo.thread, INFINITE );
4955     CloseHandle( (HANDLE)stream->callbackInfo.thread );
4956     stream->callbackInfo.thread = 0;
4957     stream->callbackInfo.callback = NULL;
4958     stream->callbackInfo.userData = NULL;
4959
4960     MUTEX_UNLOCK(&stream->mutex);
4961   }
4962 }
4963
4964 void RtAudio :: closeStream(int streamId)
4965 {
4966   // We don't want an exception to be thrown here because this
4967   // function is called by our class destructor.  So, do our own
4968   // streamId check.
4969   if ( streams.find( streamId ) == streams.end() ) {
4970     sprintf(message, "RtAudio: invalid stream identifier!");
4971     error(RtError::WARNING);
4972     return;
4973   }
4974
4975   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
4976
4977   if (stream->callbackInfo.usingCallback) {
4978     stream->callbackInfo.usingCallback = false;
4979     WaitForSingleObject( (HANDLE)stream->callbackInfo.thread, INFINITE );
4980     CloseHandle( (HANDLE)stream->callbackInfo.thread );
4981   }
4982
4983   DeleteCriticalSection(&stream->mutex);
4984
4985   if (stream->handle[0].object) {
4986     LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object;
4987     LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
4988     if (buffer) {
4989       buffer->Stop();
4990       buffer->Release();
4991     }
4992     object->Release();
4993   }
4994
4995   if (stream->handle[1].object) {
4996     LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object;
4997     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
4998     if (buffer) {
4999       buffer->Stop();
5000       buffer->Release();
5001     }
5002     object->Release();
5003   }
5004
5005   if (stream->userBuffer)
5006     free(stream->userBuffer);
5007
5008   if (stream->deviceBuffer)
5009     free(stream->deviceBuffer);
5010
5011   free(stream);
5012   streams.erase(streamId);
5013 }
5014
5015 void RtAudio :: startStream(int streamId)
5016 {
5017   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5018
5019   MUTEX_LOCK(&stream->mutex);
5020
5021   if (stream->state == STREAM_RUNNING)
5022     goto unlock;
5023
5024   HRESULT result;
5025   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5026     LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5027     result = buffer->Play(0, 0, DSBPLAY_LOOPING );
5028     if ( FAILED(result) ) {
5029       sprintf(message, "RtAudio: Unable to start DS buffer (%s): %s.",
5030               devices[stream->device[0]].name, getErrorString(result));
5031       error(RtError::DRIVER_ERROR);
5032     }
5033   }
5034
5035   if (stream->mode == INPUT || stream->mode == DUPLEX) {
5036     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5037     result = buffer->Start(DSCBSTART_LOOPING );
5038     if ( FAILED(result) ) {
5039       sprintf(message, "RtAudio: Unable to start DS capture buffer (%s): %s.",
5040               devices[stream->device[1]].name, getErrorString(result));
5041       error(RtError::DRIVER_ERROR);
5042     }
5043   }
5044   stream->state = STREAM_RUNNING;
5045
5046  unlock:
5047   MUTEX_UNLOCK(&stream->mutex);
5048 }
5049
5050 void RtAudio :: stopStream(int streamId)
5051 {
5052   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5053
5054   MUTEX_LOCK(&stream->mutex);
5055
5056   if (stream->state == STREAM_STOPPED) {
5057     MUTEX_UNLOCK(&stream->mutex);
5058     return;
5059   }
5060
5061   // There is no specific DirectSound API call to "drain" a buffer
5062   // before stopping.  We can hack this for playback by writing zeroes
5063   // for another bufferSize * nBuffers frames.  For capture, the
5064   // concept is less clear so we'll repeat what we do in the
5065   // abortStream() case.
5066   HRESULT result;
5067   DWORD dsBufferSize;
5068   LPVOID buffer1 = NULL;
5069   LPVOID buffer2 = NULL;
5070   DWORD bufferSize1 = 0;
5071   DWORD bufferSize2 = 0;
5072   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5073
5074     DWORD currentPos, safePos;
5075     long buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0];
5076     buffer_bytes *= formatBytes(stream->deviceFormat[0]);
5077
5078     LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5079     UINT nextWritePos = stream->handle[0].bufferPointer;
5080     dsBufferSize = buffer_bytes * stream->nBuffers;
5081
5082     // Write zeroes for nBuffer counts.
5083     for (int i=0; i<stream->nBuffers; i++) {
5084
5085       // Find out where the read and "safe write" pointers are.
5086       result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
5087       if ( FAILED(result) ) {
5088         sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5089                 devices[stream->device[0]].name, getErrorString(result));
5090         error(RtError::DRIVER_ERROR);
5091       }
5092
5093       if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5094       DWORD endWrite = nextWritePos + buffer_bytes;
5095
5096       // Check whether the entire write region is behind the play pointer.
5097       while ( currentPos < endWrite ) {
5098         float millis = (endWrite - currentPos) * 900.0;
5099         millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate);
5100         if ( millis < 1.0 ) millis = 1.0;
5101         Sleep( (DWORD) millis );
5102
5103         // Wake up, find out where we are now
5104         result = dsBuffer->GetCurrentPosition( &currentPos, &safePos );
5105         if ( FAILED(result) ) {
5106           sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5107                   devices[stream->device[0]].name, getErrorString(result));
5108           error(RtError::DRIVER_ERROR);
5109         }
5110         if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5111       }
5112
5113       // Lock free space in the buffer
5114       result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1,
5115                                &bufferSize1, &buffer2, &bufferSize2, 0);
5116       if ( FAILED(result) ) {
5117         sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.",
5118                 devices[stream->device[0]].name, getErrorString(result));
5119         error(RtError::DRIVER_ERROR);
5120       }
5121
5122       // Zero the free space
5123       ZeroMemory(buffer1, bufferSize1);
5124       if (buffer2 != NULL) ZeroMemory(buffer2, bufferSize2);
5125
5126       // Update our buffer offset and unlock sound buffer
5127       dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
5128       if ( FAILED(result) ) {
5129         sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.",
5130                 devices[stream->device[0]].name, getErrorString(result));
5131         error(RtError::DRIVER_ERROR);
5132       }
5133       nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize;
5134       stream->handle[0].bufferPointer = nextWritePos;
5135     }
5136
5137     // If we play again, start at the beginning of the buffer.
5138     stream->handle[0].bufferPointer = 0;
5139   }
5140
5141   if (stream->mode == INPUT || stream->mode == DUPLEX) {
5142     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5143     buffer1 = NULL;
5144     bufferSize1 = 0;
5145
5146     result = buffer->Stop();
5147     if ( FAILED(result) ) {
5148       sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s",
5149               devices[stream->device[1]].name, getErrorString(result));
5150       error(RtError::DRIVER_ERROR);
5151     }
5152
5153     dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1];
5154     dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
5155
5156     // Lock the buffer and clear it so that if we start to play again,
5157     // we won't have old data playing.
5158     result = buffer->Lock(0, dsBufferSize, &buffer1, &bufferSize1, NULL, NULL, 0);
5159     if ( FAILED(result) ) {
5160       sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
5161               devices[stream->device[1]].name, getErrorString(result));
5162       error(RtError::DRIVER_ERROR);
5163     }
5164
5165     // Zero the DS buffer
5166     ZeroMemory(buffer1, bufferSize1);
5167
5168     // Unlock the DS buffer
5169     result = buffer->Unlock(buffer1, bufferSize1, NULL, 0);
5170     if ( FAILED(result) ) {
5171       sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
5172               devices[stream->device[1]].name, getErrorString(result));
5173       error(RtError::DRIVER_ERROR);
5174     }
5175
5176     // If we start recording again, we must begin at beginning of buffer.
5177     stream->handle[1].bufferPointer = 0;
5178   }
5179   stream->state = STREAM_STOPPED;
5180
5181   MUTEX_UNLOCK(&stream->mutex);
5182 }
5183
5184 void RtAudio :: abortStream(int streamId)
5185 {
5186   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5187
5188   MUTEX_LOCK(&stream->mutex);
5189
5190   if (stream->state == STREAM_STOPPED)
5191     goto unlock;
5192
5193   HRESULT result;
5194   long dsBufferSize;
5195   LPVOID audioPtr;
5196   DWORD dataLen;
5197   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5198     LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5199     result = buffer->Stop();
5200     if ( FAILED(result) ) {
5201       sprintf(message, "RtAudio: Unable to stop DS buffer (%s): %s",
5202               devices[stream->device[0]].name, getErrorString(result));
5203       error(RtError::DRIVER_ERROR);
5204     }
5205
5206     dsBufferSize = stream->bufferSize * stream->nDeviceChannels[0];
5207     dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers;
5208
5209     // Lock the buffer and clear it so that if we start to play again,
5210     // we won't have old data playing.
5211     result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0);
5212     if ( FAILED(result) ) {
5213       sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.",
5214               devices[stream->device[0]].name, getErrorString(result));
5215       error(RtError::DRIVER_ERROR);
5216     }
5217
5218     // Zero the DS buffer
5219     ZeroMemory(audioPtr, dataLen);
5220
5221     // Unlock the DS buffer
5222     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
5223     if ( FAILED(result) ) {
5224       sprintf(message, "RtAudio: Unable to unlock DS buffer (%s): %s.",
5225               devices[stream->device[0]].name, getErrorString(result));
5226       error(RtError::DRIVER_ERROR);
5227     }
5228
5229     // If we start playing again, we must begin at beginning of buffer.
5230     stream->handle[0].bufferPointer = 0;
5231   }
5232
5233   if (stream->mode == INPUT || stream->mode == DUPLEX) {
5234     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5235     audioPtr = NULL;
5236     dataLen = 0;
5237
5238     result = buffer->Stop();
5239     if ( FAILED(result) ) {
5240       sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s",
5241               devices[stream->device[1]].name, getErrorString(result));
5242       error(RtError::DRIVER_ERROR);
5243     }
5244
5245     dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1];
5246     dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
5247
5248     // Lock the buffer and clear it so that if we start to play again,
5249     // we won't have old data playing.
5250     result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0);
5251     if ( FAILED(result) ) {
5252       sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
5253               devices[stream->device[1]].name, getErrorString(result));
5254       error(RtError::DRIVER_ERROR);
5255     }
5256
5257     // Zero the DS buffer
5258     ZeroMemory(audioPtr, dataLen);
5259
5260     // Unlock the DS buffer
5261     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
5262     if ( FAILED(result) ) {
5263       sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
5264               devices[stream->device[1]].name, getErrorString(result));
5265       error(RtError::DRIVER_ERROR);
5266     }
5267
5268     // If we start recording again, we must begin at beginning of buffer.
5269     stream->handle[1].bufferPointer = 0;
5270   }
5271   stream->state = STREAM_STOPPED;
5272
5273  unlock:
5274   MUTEX_UNLOCK(&stream->mutex);
5275 }
5276
5277 int RtAudio :: streamWillBlock(int streamId)
5278 {
5279   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5280
5281   MUTEX_LOCK(&stream->mutex);
5282
5283   int channels;
5284   int frames = 0;
5285   if (stream->state == STREAM_STOPPED)
5286     goto unlock;
5287
5288   HRESULT result;
5289   DWORD currentPos, safePos;
5290   channels = 1;
5291   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5292
5293     LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5294     UINT nextWritePos = stream->handle[0].bufferPointer;
5295     channels = stream->nDeviceChannels[0];
5296     DWORD dsBufferSize = stream->bufferSize * channels;
5297     dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers;
5298
5299     // Find out where the read and "safe write" pointers are.
5300     result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
5301     if ( FAILED(result) ) {
5302       sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5303               devices[stream->device[0]].name, getErrorString(result));
5304       error(RtError::DRIVER_ERROR);
5305     }
5306
5307     if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5308     frames = currentPos - nextWritePos;
5309     frames /= channels * formatBytes(stream->deviceFormat[0]);
5310   }
5311
5312   if (stream->mode == INPUT || stream->mode == DUPLEX) {
5313
5314     LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5315     UINT nextReadPos = stream->handle[1].bufferPointer;
5316     channels = stream->nDeviceChannels[1];
5317     DWORD dsBufferSize = stream->bufferSize * channels;
5318     dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
5319
5320     // Find out where the write and "safe read" pointers are.
5321     result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
5322     if ( FAILED(result) ) {
5323       sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
5324               devices[stream->device[1]].name, getErrorString(result));
5325       error(RtError::DRIVER_ERROR);
5326     }
5327
5328     if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
5329
5330     if (stream->mode == DUPLEX ) {
5331       // Take largest value of the two.
5332       int temp = safePos - nextReadPos;
5333       temp /= channels * formatBytes(stream->deviceFormat[1]);
5334       frames = ( temp > frames ) ? temp : frames;
5335     }
5336     else {
5337       frames = safePos - nextReadPos;
5338       frames /= channels * formatBytes(stream->deviceFormat[1]);
5339     }
5340   }
5341
5342   frames = stream->bufferSize - frames;
5343   if (frames < 0) frames = 0;
5344
5345  unlock:
5346   MUTEX_UNLOCK(&stream->mutex);
5347   return frames;
5348 }
5349
5350 void RtAudio :: tickStream(int streamId)
5351 {
5352   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5353
5354   int stopStream = 0;
5355   if (stream->state == STREAM_STOPPED) {
5356     if (stream->callbackInfo.usingCallback) Sleep(50); // sleep 50 milliseconds
5357     return;
5358   }
5359   else if (stream->callbackInfo.usingCallback) {
5360     RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
5361     stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
5362   }
5363
5364   MUTEX_LOCK(&stream->mutex);
5365
5366   // The state might change while waiting on a mutex.
5367   if (stream->state == STREAM_STOPPED) {
5368     MUTEX_UNLOCK(&stream->mutex);
5369     return;
5370   }
5371
5372   HRESULT result;
5373   DWORD currentPos, safePos;
5374   LPVOID buffer1 = NULL;
5375   LPVOID buffer2 = NULL;
5376   DWORD bufferSize1 = 0;
5377   DWORD bufferSize2 = 0;
5378   char *buffer;
5379   long buffer_bytes;
5380   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5381
5382     // Setup parameters and do buffer conversion if necessary.
5383     if (stream->doConvertBuffer[0]) {
5384       convertStreamBuffer(stream, OUTPUT);
5385       buffer = stream->deviceBuffer;
5386       buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0];
5387       buffer_bytes *= formatBytes(stream->deviceFormat[0]);
5388     }
5389     else {
5390       buffer = stream->userBuffer;
5391       buffer_bytes = stream->bufferSize * stream->nUserChannels[0];
5392       buffer_bytes *= formatBytes(stream->userFormat);
5393     }
5394
5395     // No byte swapping necessary in DirectSound implementation.
5396
5397     LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5398     UINT nextWritePos = stream->handle[0].bufferPointer;
5399     DWORD dsBufferSize = buffer_bytes * stream->nBuffers;
5400
5401     // Find out where the read and "safe write" pointers are.
5402     result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
5403     if ( FAILED(result) ) {
5404       sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5405               devices[stream->device[0]].name, getErrorString(result));
5406       error(RtError::DRIVER_ERROR);
5407     }
5408
5409     if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5410     DWORD endWrite = nextWritePos + buffer_bytes;
5411
5412     // Check whether the entire write region is behind the play pointer.
5413     while ( currentPos < endWrite ) {
5414       // If we are here, then we must wait until the play pointer gets
5415       // beyond the write region.  The approach here is to use the
5416       // Sleep() function to suspend operation until safePos catches
5417       // up. Calculate number of milliseconds to wait as:
5418       //   time = distance * (milliseconds/second) * fudgefactor /
5419       //          ((bytes/sample) * (samples/second))
5420       // A "fudgefactor" less than 1 is used because it was found
5421       // that sleeping too long was MUCH worse than sleeping for
5422       // several shorter periods.
5423       float millis = (endWrite - currentPos) * 900.0;
5424       millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate);
5425       if ( millis < 1.0 ) millis = 1.0;
5426       Sleep( (DWORD) millis );
5427
5428       // Wake up, find out where we are now
5429       result = dsBuffer->GetCurrentPosition( &currentPos, &safePos );
5430       if ( FAILED(result) ) {
5431         sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5432               devices[stream->device[0]].name, getErrorString(result));
5433         error(RtError::DRIVER_ERROR);
5434       }
5435       if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5436     }
5437
5438     // Lock free space in the buffer
5439     result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1,
5440                              &bufferSize1, &buffer2, &bufferSize2, 0);
5441     if ( FAILED(result) ) {
5442       sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.",
5443               devices[stream->device[0]].name, getErrorString(result));
5444       error(RtError::DRIVER_ERROR);
5445     }
5446
5447     // Copy our buffer into the DS buffer
5448     CopyMemory(buffer1, buffer, bufferSize1);
5449     if (buffer2 != NULL) CopyMemory(buffer2, buffer+bufferSize1, bufferSize2);
5450
5451     // Update our buffer offset and unlock sound buffer
5452     dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
5453     if ( FAILED(result) ) {
5454       sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.",
5455               devices[stream->device[0]].name, getErrorString(result));
5456       error(RtError::DRIVER_ERROR);
5457     }
5458     nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize;
5459     stream->handle[0].bufferPointer = nextWritePos;
5460   }
5461
5462   if (stream->mode == INPUT || stream->mode == DUPLEX) {
5463
5464     // Setup parameters.
5465     if (stream->doConvertBuffer[1]) {
5466       buffer = stream->deviceBuffer;
5467       buffer_bytes = stream->bufferSize * stream->nDeviceChannels[1];
5468       buffer_bytes *= formatBytes(stream->deviceFormat[1]);
5469     }
5470     else {
5471       buffer = stream->userBuffer;
5472       buffer_bytes = stream->bufferSize * stream->nUserChannels[1];
5473       buffer_bytes *= formatBytes(stream->userFormat);
5474     }
5475
5476     LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5477     UINT nextReadPos = stream->handle[1].bufferPointer;
5478     DWORD dsBufferSize = buffer_bytes * stream->nBuffers;
5479
5480     // Find out where the write and "safe read" pointers are.
5481     result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
5482     if ( FAILED(result) ) {
5483       sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
5484               devices[stream->device[1]].name, getErrorString(result));
5485       error(RtError::DRIVER_ERROR);
5486     }
5487
5488     if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
5489     DWORD endRead = nextReadPos + buffer_bytes;
5490
5491     // Check whether the entire write region is behind the play pointer.
5492     while ( safePos < endRead ) {
5493       // See comments for playback.
5494       float millis = (endRead - safePos) * 900.0;
5495       millis /= ( formatBytes(stream->deviceFormat[1]) * stream->sampleRate);
5496       if ( millis < 1.0 ) millis = 1.0;
5497       Sleep( (DWORD) millis );
5498
5499       // Wake up, find out where we are now
5500       result = dsBuffer->GetCurrentPosition( &currentPos, &safePos );
5501       if ( FAILED(result) ) {
5502         sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
5503                 devices[stream->device[1]].name, getErrorString(result));
5504         error(RtError::DRIVER_ERROR);
5505       }
5506       
5507       if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
5508     }
5509
5510     // Lock free space in the buffer
5511     result = dsBuffer->Lock (nextReadPos, buffer_bytes, &buffer1,
5512                              &bufferSize1, &buffer2, &bufferSize2, 0);
5513     if ( FAILED(result) ) {
5514       sprintf(message, "RtAudio: Unable to lock DS buffer during capture (%s): %s.",
5515               devices[stream->device[1]].name, getErrorString(result));
5516       error(RtError::DRIVER_ERROR);
5517     }
5518
5519     // Copy our buffer into the DS buffer
5520     CopyMemory(buffer, buffer1, bufferSize1);
5521     if (buffer2 != NULL) CopyMemory(buffer+bufferSize1, buffer2, bufferSize2);
5522
5523     // Update our buffer offset and unlock sound buffer
5524     nextReadPos = (nextReadPos + bufferSize1 + bufferSize2) % dsBufferSize;
5525     dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
5526     if ( FAILED(result) ) {
5527       sprintf(message, "RtAudio: Unable to unlock DS buffer during capture (%s): %s.",
5528               devices[stream->device[1]].name, getErrorString(result));
5529       error(RtError::DRIVER_ERROR);
5530     }
5531     stream->handle[1].bufferPointer = nextReadPos;
5532
5533     // No byte swapping necessary in DirectSound implementation.
5534
5535     // Do buffer conversion if necessary.
5536     if (stream->doConvertBuffer[1])
5537       convertStreamBuffer(stream, INPUT);
5538   }
5539
5540   MUTEX_UNLOCK(&stream->mutex);
5541
5542   if (stream->callbackInfo.usingCallback && stopStream)
5543     this->stopStream(streamId);
5544 }
5545
5546 // Definitions for utility functions and callbacks
5547 // specific to the DirectSound implementation.
5548
5549 extern "C" unsigned __stdcall callbackHandler(void *ptr)
5550 {
5551   CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
5552   RtAudio *object = (RtAudio *) info->object;
5553   int stream = info->streamId;
5554   bool *usingCallback = &info->usingCallback;
5555
5556   while ( *usingCallback ) {
5557     try {
5558       object->tickStream(stream);
5559     }
5560     catch (RtError &exception) {
5561       fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
5562               exception.getMessage());
5563       break;
5564     }
5565   }
5566
5567   _endthreadex( 0 );
5568   return 0;
5569 }
5570
5571 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
5572 {
5573   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5574
5575   CALLBACK_INFO *info = (CALLBACK_INFO *) &stream->callbackInfo;
5576   if ( info->usingCallback ) {
5577     sprintf(message, "RtAudio: A callback is already set for this stream!");
5578     error(RtError::WARNING);
5579     return;
5580   }
5581
5582   info->callback = (void *) callback;
5583   info->userData = userData;
5584   info->usingCallback = true;
5585   info->object = (void *) this;
5586   info->streamId = streamId;
5587
5588   unsigned thread_id;
5589   info->thread = _beginthreadex(NULL, 0, &callbackHandler,
5590                                 &stream->callbackInfo, 0, &thread_id);
5591   if (info->thread == 0) {
5592     info->usingCallback = false;
5593     sprintf(message, "RtAudio: error starting callback thread!");
5594     error(RtError::THREAD_ERROR);
5595   }
5596
5597   // When spawning multiple threads in quick succession, it appears to be
5598   // necessary to wait a bit for each to initialize ... another windoism!
5599   Sleep(1);
5600 }
5601
5602 static bool CALLBACK deviceCountCallback(LPGUID lpguid,
5603                                          LPCSTR lpcstrDescription,
5604                                          LPCSTR lpcstrModule,
5605                                          LPVOID lpContext)
5606 {
5607   int *pointer = ((int *) lpContext);
5608   (*pointer)++;
5609
5610   return true;
5611 }
5612
5613 static bool CALLBACK deviceInfoCallback(LPGUID lpguid,
5614                                         LPCSTR lpcstrDescription,
5615                                         LPCSTR lpcstrModule,
5616                                         LPVOID lpContext)
5617 {
5618   enum_info *info = ((enum_info *) lpContext);
5619   while (strlen(info->name) > 0) info++;
5620
5621   strncpy(info->name, lpcstrDescription, 64);
5622   info->id = lpguid;
5623
5624         HRESULT    hr;
5625   info->isValid = false;
5626   if (info->isInput == true) {
5627     DSCCAPS               caps;
5628     LPDIRECTSOUNDCAPTURE  object;
5629
5630     hr = DirectSoundCaptureCreate(  lpguid, &object,   NULL );
5631     if( hr != DS_OK ) return true;
5632
5633     caps.dwSize = sizeof(caps);
5634     hr = object->GetCaps( &caps );
5635     if( hr == DS_OK ) {
5636       if (caps.dwChannels > 0 && caps.dwFormats > 0)
5637         info->isValid = true;
5638     }
5639     object->Release();
5640   }
5641   else {
5642     DSCAPS         caps;
5643     LPDIRECTSOUND  object;
5644     hr = DirectSoundCreate(  lpguid, &object,   NULL );
5645     if( hr != DS_OK ) return true;
5646
5647     caps.dwSize = sizeof(caps);
5648     hr = object->GetCaps( &caps );
5649     if( hr == DS_OK ) {
5650       if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO )
5651         info->isValid = true;
5652     }
5653     object->Release();
5654   }
5655
5656   return true;
5657 }
5658
5659 static bool CALLBACK defaultDeviceCallback(LPGUID lpguid,
5660                                            LPCSTR lpcstrDescription,
5661                                            LPCSTR lpcstrModule,
5662                                            LPVOID lpContext)
5663 {
5664   enum_info *info = ((enum_info *) lpContext);
5665
5666   if ( lpguid == NULL ) {
5667     strncpy(info->name, lpcstrDescription, 64);
5668     return false;
5669   }
5670
5671   return true;
5672 }
5673
5674 static bool CALLBACK deviceIdCallback(LPGUID lpguid,
5675                                       LPCSTR lpcstrDescription,
5676                                       LPCSTR lpcstrModule,
5677                                       LPVOID lpContext)
5678 {
5679   enum_info *info = ((enum_info *) lpContext);
5680
5681   if ( strncmp( info->name, lpcstrDescription, 64 ) == 0 ) {
5682     info->id = lpguid;
5683     info->isValid = true;
5684     return false;
5685   }
5686
5687   return true;
5688 }
5689
5690 static char* getErrorString(int code)
5691 {
5692         switch (code) {
5693
5694   case DSERR_ALLOCATED:
5695     return "Direct Sound already allocated";
5696
5697   case DSERR_CONTROLUNAVAIL:
5698     return "Direct Sound control unavailable";
5699
5700   case DSERR_INVALIDPARAM:
5701     return "Direct Sound invalid parameter";
5702
5703   case DSERR_INVALIDCALL:
5704     return "Direct Sound invalid call";
5705
5706   case DSERR_GENERIC:
5707     return "Direct Sound generic error";
5708
5709   case DSERR_PRIOLEVELNEEDED:
5710     return "Direct Sound Priority level needed";
5711
5712   case DSERR_OUTOFMEMORY:
5713     return "Direct Sound out of memory";
5714
5715   case DSERR_BADFORMAT:
5716     return "Direct Sound bad format";
5717
5718   case DSERR_UNSUPPORTED:
5719     return "Direct Sound unsupported error";
5720
5721   case DSERR_NODRIVER:
5722     return "Direct Sound no driver error";
5723
5724   case DSERR_ALREADYINITIALIZED:
5725     return "Direct Sound already initialized";
5726
5727   case DSERR_NOAGGREGATION:
5728     return "Direct Sound no aggregation";
5729
5730   case DSERR_BUFFERLOST:
5731     return "Direct Sound buffer lost";
5732
5733   case DSERR_OTHERAPPHASPRIO:
5734     return "Direct Sound other app has priority";
5735
5736   case DSERR_UNINITIALIZED:
5737     return "Direct Sound uninitialized";
5738
5739   default:
5740     return "Direct Sound unknown error";
5741         }
5742 }
5743
5744 //******************** End of __WINDOWS_DS__ *********************//
5745
5746 #elif defined(__IRIX_AL__) // SGI's AL API for IRIX
5747
5748 #include <unistd.h>
5749 #include <errno.h>
5750
5751 void RtAudio :: initialize(void)
5752 {
5753   // Count cards and devices
5754   nDevices = 0;
5755
5756   // Determine the total number of input and output devices.
5757   nDevices = alQueryValues(AL_SYSTEM, AL_DEVICES, 0, 0, 0, 0);
5758   if (nDevices < 0) {
5759     sprintf(message, "RtAudio: AL error counting devices: %s.",
5760             alGetErrorString(oserror()));
5761     error(RtError::DRIVER_ERROR);
5762   }
5763
5764   if (nDevices <= 0) return;
5765
5766   ALvalue *vls = (ALvalue *) new ALvalue[nDevices];
5767
5768   //  Allocate the RTAUDIO_DEVICE structures.
5769   devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
5770   if (devices == NULL) {
5771     sprintf(message, "RtAudio: memory allocation error!");
5772     error(RtError::MEMORY_ERROR);
5773   }
5774
5775   // Write device ascii identifiers and resource ids to device info
5776   // structure.
5777   char name[32];
5778   int outs, ins, i;
5779   ALpv pvs[1];
5780   pvs[0].param = AL_NAME;
5781   pvs[0].value.ptr = name;
5782   pvs[0].sizeIn = 32;
5783
5784   outs = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, vls, nDevices, 0, 0);
5785   if (outs < 0) {
5786     sprintf(message, "RtAudio: AL error getting output devices: %s.",
5787             alGetErrorString(oserror()));
5788     error(RtError::DRIVER_ERROR);
5789   }
5790
5791   for (i=0; i<outs; i++) {
5792     if (alGetParams(vls[i].i, pvs, 1) < 0) {
5793       sprintf(message, "RtAudio: AL error querying output devices: %s.",
5794               alGetErrorString(oserror()));
5795       error(RtError::DRIVER_ERROR);
5796     }
5797     strncpy(devices[i].name, name, 32);
5798     devices[i].id[0] = vls[i].i;
5799   }
5800
5801   ins = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &vls[outs], nDevices-outs, 0, 0);
5802   if (ins < 0) {
5803     sprintf(message, "RtAudio: AL error getting input devices: %s.",
5804             alGetErrorString(oserror()));
5805     error(RtError::DRIVER_ERROR);
5806   }
5807
5808   for (i=outs; i<ins+outs; i++) {
5809     if (alGetParams(vls[i].i, pvs, 1) < 0) {
5810       sprintf(message, "RtAudio: AL error querying input devices: %s.",
5811               alGetErrorString(oserror()));
5812       error(RtError::DRIVER_ERROR);
5813     }
5814     strncpy(devices[i].name, name, 32);
5815     devices[i].id[1] = vls[i].i;
5816   }
5817
5818   delete [] vls;
5819
5820   return;
5821 }
5822
5823 int RtAudio :: getDefaultInputDevice(void)
5824 {
5825   ALvalue value;
5826   int result = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &value, 1, 0, 0);
5827   if (result < 0) {
5828     sprintf(message, "RtAudio: AL error getting default input device id: %s.",
5829             alGetErrorString(oserror()));
5830     error(RtError::WARNING);
5831   }
5832   else {
5833     for ( int i=0; i<nDevices; i++ )
5834       if ( devices[i].id[1] == value.i ) return i;
5835   }
5836
5837   return 0;
5838 }
5839
5840 int RtAudio :: getDefaultOutputDevice(void)
5841 {
5842   ALvalue value;
5843   int result = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, &value, 1, 0, 0);
5844   if (result < 0) {
5845     sprintf(message, "RtAudio: AL error getting default output device id: %s.",
5846             alGetErrorString(oserror()));
5847     error(RtError::WARNING);
5848   }
5849   else {
5850     for ( int i=0; i<nDevices; i++ )
5851       if ( devices[i].id[0] == value.i ) return i;
5852   }
5853
5854   return 0;
5855 }
5856
5857 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
5858 {
5859   int resource, result, i;
5860   ALvalue value;
5861   ALparamInfo pinfo;
5862
5863   // Get output resource ID if it exists.
5864   resource = info->id[0];
5865   if (resource > 0) {
5866
5867     // Probe output device parameters.
5868     result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0);
5869     if (result < 0) {
5870       sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.",
5871               info->name, alGetErrorString(oserror()));
5872       error(RtError::WARNING);
5873     }
5874     else {
5875       info->maxOutputChannels = value.i;
5876       info->minOutputChannels = 1;
5877     }
5878
5879     result = alGetParamInfo(resource, AL_RATE, &pinfo);
5880     if (result < 0) {
5881       sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.",
5882               info->name, alGetErrorString(oserror()));
5883       error(RtError::WARNING);
5884     }
5885     else {
5886       info->nSampleRates = 0;
5887       for (i=0; i<MAX_SAMPLE_RATES; i++) {
5888         if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) {
5889           info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
5890           info->nSampleRates++;
5891         }
5892       }
5893     }
5894
5895     // The AL library supports all our formats, except 24-bit and 32-bit ints.
5896     info->nativeFormats = (RTAUDIO_FORMAT) 51;
5897   }
5898
5899   // Now get input resource ID if it exists.
5900   resource = info->id[1];
5901   if (resource > 0) {
5902
5903     // Probe input device parameters.
5904     result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0);
5905     if (result < 0) {
5906       sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.",
5907               info->name, alGetErrorString(oserror()));
5908       error(RtError::WARNING);
5909     }
5910     else {
5911       info->maxInputChannels = value.i;
5912       info->minInputChannels = 1;
5913     }
5914
5915     result = alGetParamInfo(resource, AL_RATE, &pinfo);
5916     if (result < 0) {
5917       sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.",
5918               info->name, alGetErrorString(oserror()));
5919       error(RtError::WARNING);
5920     }
5921     else {
5922       // In the case of the default device, these values will
5923       // overwrite the rates determined for the output device.  Since
5924       // the input device is most likely to be more limited than the
5925       // output device, this is ok.
5926       info->nSampleRates = 0;
5927       for (i=0; i<MAX_SAMPLE_RATES; i++) {
5928         if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) {
5929           info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
5930           info->nSampleRates++;
5931         }
5932       }
5933     }
5934
5935     // The AL library supports all our formats, except 24-bit and 32-bit ints.
5936     info->nativeFormats = (RTAUDIO_FORMAT) 51;
5937   }
5938
5939   if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 )
5940     return;
5941   if ( info->nSampleRates == 0 )
5942     return;
5943
5944   // Determine duplex status.
5945   if (info->maxInputChannels < info->maxOutputChannels)
5946     info->maxDuplexChannels = info->maxInputChannels;
5947   else
5948     info->maxDuplexChannels = info->maxOutputChannels;
5949   if (info->minInputChannels < info->minOutputChannels)
5950     info->minDuplexChannels = info->minInputChannels;
5951   else
5952     info->minDuplexChannels = info->minOutputChannels;
5953
5954   if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true;
5955   else info->hasDuplexSupport = false;
5956
5957   info->probed = true;
5958
5959   return;
5960 }
5961
5962 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
5963                                 STREAM_MODE mode, int channels, 
5964                                 int sampleRate, RTAUDIO_FORMAT format,
5965                                 int *bufferSize, int numberOfBuffers)
5966 {
5967   int result, resource, nBuffers;
5968   ALconfig al_config;
5969   ALport port;
5970   ALpv pvs[2];
5971
5972   // Get a new ALconfig structure.
5973   al_config = alNewConfig();
5974   if ( !al_config ) {
5975     sprintf(message,"RtAudio: can't get AL config: %s.",
5976             alGetErrorString(oserror()));
5977     error(RtError::WARNING);
5978     return FAILURE;
5979   }
5980
5981   // Set the channels.
5982   result = alSetChannels(al_config, channels);
5983   if ( result < 0 ) {
5984     sprintf(message,"RtAudio: can't set %d channels in AL config: %s.",
5985             channels, alGetErrorString(oserror()));
5986     error(RtError::WARNING);
5987     return FAILURE;
5988   }
5989
5990   // Attempt to set the queue size.  The al API doesn't provide a
5991   // means for querying the minimum/maximum buffer size of a device,
5992   // so if the specified size doesn't work, take whatever the
5993   // al_config structure returns.
5994   if ( numberOfBuffers < 1 )
5995     nBuffers = 1;
5996   else
5997     nBuffers = numberOfBuffers;
5998   long buffer_size = *bufferSize * nBuffers;
5999   result = alSetQueueSize(al_config, buffer_size); // in sample frames
6000   if ( result < 0 ) {
6001     // Get the buffer size specified by the al_config and try that.
6002     buffer_size = alGetQueueSize(al_config);
6003     result = alSetQueueSize(al_config, buffer_size);
6004     if ( result < 0 ) {
6005       sprintf(message,"RtAudio: can't set buffer size (%ld) in AL config: %s.",
6006               buffer_size, alGetErrorString(oserror()));
6007       error(RtError::WARNING);
6008       return FAILURE;
6009     }
6010     *bufferSize = buffer_size / nBuffers;
6011   }
6012
6013   // Set the data format.
6014   stream->userFormat = format;
6015   stream->deviceFormat[mode] = format;
6016   if (format == RTAUDIO_SINT8) {
6017     result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP);
6018     result = alSetWidth(al_config, AL_SAMPLE_8);
6019   }
6020   else if (format == RTAUDIO_SINT16) {
6021     result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP);
6022     result = alSetWidth(al_config, AL_SAMPLE_16);
6023   }
6024   else if (format == RTAUDIO_SINT24) {
6025     // Our 24-bit format assumes the upper 3 bytes of a 4 byte word.
6026     // The AL library uses the lower 3 bytes, so we'll need to do our
6027     // own conversion.
6028     result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
6029     stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
6030   }
6031   else if (format == RTAUDIO_SINT32) {
6032     // The AL library doesn't seem to support the 32-bit integer
6033     // format, so we'll need to do our own conversion.
6034     result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
6035     stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
6036   }
6037   else if (format == RTAUDIO_FLOAT32)
6038     result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
6039   else if (format == RTAUDIO_FLOAT64)
6040     result = alSetSampFmt(al_config, AL_SAMPFMT_DOUBLE);
6041
6042   if ( result == -1 ) {
6043     sprintf(message,"RtAudio: AL error setting sample format in AL config: %s.",
6044             alGetErrorString(oserror()));
6045     error(RtError::WARNING);
6046     return FAILURE;
6047   }
6048
6049   if (mode == OUTPUT) {
6050
6051     // Set our device.
6052     if (device == 0)
6053       resource = AL_DEFAULT_OUTPUT;
6054     else
6055       resource = devices[device].id[0];
6056     result = alSetDevice(al_config, resource);
6057     if ( result == -1 ) {
6058       sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.",
6059               devices[device].name, alGetErrorString(oserror()));
6060       error(RtError::WARNING);
6061       return FAILURE;
6062     }
6063
6064     // Open the port.
6065     port = alOpenPort("RtAudio Output Port", "w", al_config);
6066     if( !port ) {
6067       sprintf(message,"RtAudio: AL error opening output port: %s.",
6068               alGetErrorString(oserror()));
6069       error(RtError::WARNING);
6070       return FAILURE;
6071     }
6072
6073     // Set the sample rate
6074     pvs[0].param = AL_MASTER_CLOCK;
6075     pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
6076     pvs[1].param = AL_RATE;
6077     pvs[1].value.ll = alDoubleToFixed((double)sampleRate);
6078     result = alSetParams(resource, pvs, 2);
6079     if ( result < 0 ) {
6080       alClosePort(port);
6081       sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.",
6082               sampleRate, devices[device].name, alGetErrorString(oserror()));
6083       error(RtError::WARNING);
6084       return FAILURE;
6085     }
6086   }
6087   else { // mode == INPUT
6088
6089     // Set our device.
6090     if (device == 0)
6091       resource = AL_DEFAULT_INPUT;
6092     else
6093       resource = devices[device].id[1];
6094     result = alSetDevice(al_config, resource);
6095     if ( result == -1 ) {
6096       sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.",
6097               devices[device].name, alGetErrorString(oserror()));
6098       error(RtError::WARNING);
6099       return FAILURE;
6100     }
6101
6102     // Open the port.
6103     port = alOpenPort("RtAudio Output Port", "r", al_config);
6104     if( !port ) {
6105       sprintf(message,"RtAudio: AL error opening input port: %s.",
6106               alGetErrorString(oserror()));
6107       error(RtError::WARNING);
6108       return FAILURE;
6109     }
6110
6111     // Set the sample rate
6112     pvs[0].param = AL_MASTER_CLOCK;
6113     pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
6114     pvs[1].param = AL_RATE;
6115     pvs[1].value.ll = alDoubleToFixed((double)sampleRate);
6116     result = alSetParams(resource, pvs, 2);
6117     if ( result < 0 ) {
6118       alClosePort(port);
6119       sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.",
6120               sampleRate, devices[device].name, alGetErrorString(oserror()));
6121       error(RtError::WARNING);
6122       return FAILURE;
6123     }
6124   }
6125
6126   alFreeConfig(al_config);
6127
6128   stream->nUserChannels[mode] = channels;
6129   stream->nDeviceChannels[mode] = channels;
6130
6131   // Set handle and flags for buffer conversion
6132   stream->handle[mode] = port;
6133   stream->doConvertBuffer[mode] = false;
6134   if (stream->userFormat != stream->deviceFormat[mode])
6135     stream->doConvertBuffer[mode] = true;
6136
6137   // Allocate necessary internal buffers
6138   if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
6139
6140     long buffer_bytes;
6141     if (stream->nUserChannels[0] >= stream->nUserChannels[1])
6142       buffer_bytes = stream->nUserChannels[0];
6143     else
6144       buffer_bytes = stream->nUserChannels[1];
6145
6146     buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
6147     if (stream->userBuffer) free(stream->userBuffer);
6148     stream->userBuffer = (char *) calloc(buffer_bytes, 1);
6149     if (stream->userBuffer == NULL)
6150       goto memory_error;
6151   }
6152
6153   if ( stream->doConvertBuffer[mode] ) {
6154
6155     long buffer_bytes;
6156     bool makeBuffer = true;
6157     if ( mode == OUTPUT )
6158       buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
6159     else { // mode == INPUT
6160       buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
6161       if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
6162         long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
6163         if ( buffer_bytes < bytes_out ) makeBuffer = false;
6164       }
6165     }
6166
6167     if ( makeBuffer ) {
6168       buffer_bytes *= *bufferSize;
6169       if (stream->deviceBuffer) free(stream->deviceBuffer);
6170       stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
6171       if (stream->deviceBuffer == NULL)
6172         goto memory_error;
6173     }
6174   }
6175
6176   stream->device[mode] = device;
6177   stream->state = STREAM_STOPPED;
6178   if ( stream->mode == OUTPUT && mode == INPUT )
6179     // We had already set up an output stream.
6180     stream->mode = DUPLEX;
6181   else
6182     stream->mode = mode;
6183   stream->nBuffers = nBuffers;
6184   stream->bufferSize = *bufferSize;
6185   stream->sampleRate = sampleRate;
6186
6187   return SUCCESS;
6188
6189  memory_error:
6190   if (stream->handle[0]) {
6191     alClosePort(stream->handle[0]);
6192     stream->handle[0] = 0;
6193   }
6194   if (stream->handle[1]) {
6195     alClosePort(stream->handle[1]);
6196     stream->handle[1] = 0;
6197   }
6198   if (stream->userBuffer) {
6199     free(stream->userBuffer);
6200     stream->userBuffer = 0;
6201   }
6202   sprintf(message, "RtAudio: ALSA error allocating buffer memory for device (%s).",
6203           devices[device].name);
6204   error(RtError::WARNING);
6205   return FAILURE;
6206 }
6207
6208 void RtAudio :: closeStream(int streamId)
6209 {
6210   // We don't want an exception to be thrown here because this
6211   // function is called by our class destructor.  So, do our own
6212   // streamId check.
6213   if ( streams.find( streamId ) == streams.end() ) {
6214     sprintf(message, "RtAudio: invalid stream identifier!");
6215     error(RtError::WARNING);
6216     return;
6217   }
6218
6219   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
6220
6221   if (stream->callbackInfo.usingCallback) {
6222     pthread_cancel(stream->callbackInfo.thread);
6223     pthread_join(stream->callbackInfo.thread, NULL);
6224   }
6225
6226   pthread_mutex_destroy(&stream->mutex);
6227
6228   if (stream->handle[0])
6229     alClosePort(stream->handle[0]);
6230
6231   if (stream->handle[1])
6232     alClosePort(stream->handle[1]);
6233
6234   if (stream->userBuffer)
6235     free(stream->userBuffer);
6236
6237   if (stream->deviceBuffer)
6238     free(stream->deviceBuffer);
6239
6240   free(stream);
6241   streams.erase(streamId);
6242 }
6243
6244 void RtAudio :: startStream(int streamId)
6245 {
6246   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6247
6248   if (stream->state == STREAM_RUNNING)
6249     return;
6250
6251   // The AL port is ready as soon as it is opened.
6252   stream->state = STREAM_RUNNING;
6253 }
6254
6255 void RtAudio :: stopStream(int streamId)
6256 {
6257   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6258
6259   MUTEX_LOCK(&stream->mutex);
6260
6261   if (stream->state == STREAM_STOPPED)
6262     goto unlock;
6263
6264   int result;
6265   int buffer_size = stream->bufferSize * stream->nBuffers;
6266
6267   if (stream->mode == OUTPUT || stream->mode == DUPLEX)
6268     alZeroFrames(stream->handle[0], buffer_size);
6269
6270   if (stream->mode == INPUT || stream->mode == DUPLEX) {
6271     result = alDiscardFrames(stream->handle[1], buffer_size);
6272     if (result == -1) {
6273       sprintf(message, "RtAudio: AL error draining stream device (%s): %s.",
6274               devices[stream->device[1]].name, alGetErrorString(oserror()));
6275       error(RtError::DRIVER_ERROR);
6276     }
6277   }
6278   stream->state = STREAM_STOPPED;
6279
6280  unlock:
6281   MUTEX_UNLOCK(&stream->mutex);
6282 }
6283
6284 void RtAudio :: abortStream(int streamId)
6285 {
6286   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6287
6288   MUTEX_LOCK(&stream->mutex);
6289
6290   if (stream->state == STREAM_STOPPED)
6291     goto unlock;
6292
6293   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
6294
6295     int buffer_size = stream->bufferSize * stream->nBuffers;
6296     int result = alDiscardFrames(stream->handle[0], buffer_size);
6297     if (result == -1) {
6298       sprintf(message, "RtAudio: AL error aborting stream device (%s): %s.",
6299               devices[stream->device[0]].name, alGetErrorString(oserror()));
6300       error(RtError::DRIVER_ERROR);
6301     }
6302   }
6303
6304   // There is no clear action to take on the input stream, since the
6305   // port will continue to run in any event.
6306   stream->state = STREAM_STOPPED;
6307
6308  unlock:
6309   MUTEX_UNLOCK(&stream->mutex);
6310 }
6311
6312 int RtAudio :: streamWillBlock(int streamId)
6313 {
6314   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6315
6316   MUTEX_LOCK(&stream->mutex);
6317
6318   int frames = 0;
6319   if (stream->state == STREAM_STOPPED)
6320     goto unlock;
6321
6322   int err = 0;
6323   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
6324     err = alGetFillable(stream->handle[0]);
6325     if (err < 0) {
6326       sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.",
6327               devices[stream->device[0]].name, alGetErrorString(oserror()));
6328       error(RtError::DRIVER_ERROR);
6329     }
6330   }
6331
6332   frames = err;
6333
6334   if (stream->mode == INPUT || stream->mode == DUPLEX) {
6335     err = alGetFilled(stream->handle[1]);
6336     if (err < 0) {
6337       sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.",
6338               devices[stream->device[1]].name, alGetErrorString(oserror()));
6339       error(RtError::DRIVER_ERROR);
6340     }
6341     if (frames > err) frames = err;
6342   }
6343
6344   frames = stream->bufferSize - frames;
6345   if (frames < 0) frames = 0;
6346
6347  unlock:
6348   MUTEX_UNLOCK(&stream->mutex);
6349   return frames;
6350 }
6351
6352 void RtAudio :: tickStream(int streamId)
6353 {
6354   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6355
6356   int stopStream = 0;
6357   if (stream->state == STREAM_STOPPED) {
6358     if (stream->callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
6359     return;
6360   }
6361   else if (stream->callbackInfo.usingCallback) {
6362     RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
6363     stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
6364   }
6365
6366   MUTEX_LOCK(&stream->mutex);
6367
6368   // The state might change while waiting on a mutex.
6369   if (stream->state == STREAM_STOPPED)
6370     goto unlock;
6371
6372   char *buffer;
6373   int channels;
6374   RTAUDIO_FORMAT format;
6375   if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
6376
6377     // Setup parameters and do buffer conversion if necessary.
6378     if (stream->doConvertBuffer[0]) {
6379       convertStreamBuffer(stream, OUTPUT);
6380       buffer = stream->deviceBuffer;
6381       channels = stream->nDeviceChannels[0];
6382       format = stream->deviceFormat[0];
6383     }
6384     else {
6385       buffer = stream->userBuffer;
6386       channels = stream->nUserChannels[0];
6387       format = stream->userFormat;
6388     }
6389
6390     // Do byte swapping if necessary.
6391     if (stream->doByteSwap[0])
6392       byteSwapBuffer(buffer, stream->bufferSize * channels, format);
6393
6394     // Write interleaved samples to device.
6395     alWriteFrames(stream->handle[0], buffer, stream->bufferSize);
6396   }
6397
6398   if (stream->mode == INPUT || stream->mode == DUPLEX) {
6399
6400     // Setup parameters.
6401     if (stream->doConvertBuffer[1]) {
6402       buffer = stream->deviceBuffer;
6403       channels = stream->nDeviceChannels[1];
6404       format = stream->deviceFormat[1];
6405     }
6406     else {
6407       buffer = stream->userBuffer;
6408       channels = stream->nUserChannels[1];
6409       format = stream->userFormat;
6410     }
6411
6412     // Read interleaved samples from device.
6413     alReadFrames(stream->handle[1], buffer, stream->bufferSize);
6414
6415     // Do byte swapping if necessary.
6416     if (stream->doByteSwap[1])
6417       byteSwapBuffer(buffer, stream->bufferSize * channels, format);
6418
6419     // Do buffer conversion if necessary.
6420     if (stream->doConvertBuffer[1])
6421       convertStreamBuffer(stream, INPUT);
6422   }
6423
6424  unlock:
6425   MUTEX_UNLOCK(&stream->mutex);
6426
6427   if (stream->callbackInfo.usingCallback && stopStream)
6428     this->stopStream(streamId);
6429 }
6430
6431 extern "C" void *callbackHandler(void *ptr)
6432 {
6433   CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
6434   RtAudio *object = (RtAudio *) info->object;
6435   int stream = info->streamId;
6436   bool *usingCallback = &info->usingCallback;
6437
6438   while ( *usingCallback ) {
6439     pthread_testcancel();
6440     try {
6441       object->tickStream(stream);
6442     }
6443     catch (RtError &exception) {
6444       fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
6445               exception.getMessage());
6446       break;
6447     }
6448   }
6449
6450   return 0;
6451 }
6452
6453 //******************** End of __IRIX_AL__ *********************//
6454
6455 #endif
6456
6457
6458 // *************************************************** //
6459 //
6460 // Private common (OS-independent) RtAudio methods.
6461 //
6462 // *************************************************** //
6463
6464 // This method can be modified to control the behavior of error
6465 // message reporting and throwing.
6466 void RtAudio :: error(RtError::TYPE type)
6467 {
6468   if (type == RtError::WARNING) {
6469     fprintf(stderr, "\n%s\n\n", message);
6470   }
6471   else if (type == RtError::DEBUG_WARNING) {
6472 #if defined(__RTAUDIO_DEBUG__)
6473     fprintf(stderr, "\n%s\n\n", message);
6474 #endif
6475   }
6476   else {
6477     fprintf(stderr, "\n%s\n\n", message);
6478     throw RtError(message, type);
6479   }
6480 }
6481
6482 void *RtAudio :: verifyStream(int streamId)
6483 {
6484   // Verify the stream key.
6485   if ( streams.find( streamId ) == streams.end() ) {
6486     sprintf(message, "RtAudio: invalid stream identifier!");
6487     error(RtError::INVALID_STREAM);
6488   }
6489
6490   return streams[streamId];
6491 }
6492
6493 void RtAudio :: clearDeviceInfo(RTAUDIO_DEVICE *info)
6494 {
6495   // Don't clear the name or DEVICE_ID fields here ... they are
6496   // typically set prior to a call of this function.
6497   info->probed = false;
6498   info->maxOutputChannels = 0;
6499   info->maxInputChannels = 0;
6500   info->maxDuplexChannels = 0;
6501   info->minOutputChannels = 0;
6502   info->minInputChannels = 0;
6503   info->minDuplexChannels = 0;
6504   info->hasDuplexSupport = false;
6505   info->nSampleRates = 0;
6506   for (int i=0; i<MAX_SAMPLE_RATES; i++)
6507     info->sampleRates[i] = 0;
6508   info->nativeFormats = 0;
6509 }
6510
6511 int RtAudio :: formatBytes(RTAUDIO_FORMAT format)
6512 {
6513   if (format == RTAUDIO_SINT16)
6514     return 2;
6515   else if (format == RTAUDIO_SINT24 || format == RTAUDIO_SINT32 ||
6516            format == RTAUDIO_FLOAT32)
6517     return 4;
6518   else if (format == RTAUDIO_FLOAT64)
6519     return 8;
6520   else if (format == RTAUDIO_SINT8)
6521     return 1;
6522
6523   sprintf(message,"RtAudio: undefined format in formatBytes().");
6524   error(RtError::WARNING);
6525
6526   return 0;
6527 }
6528
6529 void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
6530 {
6531   // This method does format conversion, input/output channel compensation, and
6532   // data interleaving/deinterleaving.  24-bit integers are assumed to occupy
6533   // the upper three bytes of a 32-bit integer.
6534
6535   int j, jump_in, jump_out, channels;
6536   RTAUDIO_FORMAT format_in, format_out;
6537   char *input, *output;
6538
6539   if (mode == INPUT) { // convert device to user buffer
6540     input = stream->deviceBuffer;
6541     output = stream->userBuffer;
6542     jump_in = stream->nDeviceChannels[1];
6543     jump_out = stream->nUserChannels[1];
6544     format_in = stream->deviceFormat[1];
6545     format_out = stream->userFormat;
6546   }
6547   else { // convert user to device buffer
6548     input = stream->userBuffer;
6549     output = stream->deviceBuffer;
6550     jump_in = stream->nUserChannels[0];
6551     jump_out = stream->nDeviceChannels[0];
6552     format_in = stream->userFormat;
6553     format_out = stream->deviceFormat[0];
6554
6555     // clear our device buffer when in/out duplex device channels are different
6556     if ( stream->mode == DUPLEX &&
6557          stream->nDeviceChannels[0] != stream->nDeviceChannels[1] )
6558       memset(output, 0, stream->bufferSize * jump_out * formatBytes(format_out));
6559   }
6560
6561   channels = (jump_in < jump_out) ? jump_in : jump_out;
6562
6563   // Set up the interleave/deinterleave offsets
6564   std::vector<int> offset_in(channels);
6565   std::vector<int> offset_out(channels);
6566   if (mode == INPUT && stream->deInterleave[1]) {
6567     for (int k=0; k<channels; k++) {
6568       offset_in[k] = k * stream->bufferSize;
6569       offset_out[k] = k;
6570       jump_in = 1;
6571     }
6572   }
6573   else if (mode == OUTPUT && stream->deInterleave[0]) {
6574     for (int k=0; k<channels; k++) {
6575       offset_in[k] = k;
6576       offset_out[k] = k * stream->bufferSize;
6577       jump_out = 1;
6578     }
6579   }
6580   else {
6581     for (int k=0; k<channels; k++) {
6582       offset_in[k] = k;
6583       offset_out[k] = k;
6584     }
6585   }
6586
6587   if (format_out == RTAUDIO_FLOAT64) {
6588     FLOAT64 scale;
6589     FLOAT64 *out = (FLOAT64 *)output;
6590
6591     if (format_in == RTAUDIO_SINT8) {
6592       signed char *in = (signed char *)input;
6593       scale = 1.0 / 128.0;
6594       for (int i=0; i<stream->bufferSize; i++) {
6595         for (j=0; j<channels; j++) {
6596           out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
6597           out[offset_out[j]] *= scale;
6598         }
6599         in += jump_in;
6600         out += jump_out;
6601       }
6602     }
6603     else if (format_in == RTAUDIO_SINT16) {
6604       INT16 *in = (INT16 *)input;
6605       scale = 1.0 / 32768.0;
6606       for (int i=0; i<stream->bufferSize; i++) {
6607         for (j=0; j<channels; j++) {
6608           out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
6609           out[offset_out[j]] *= scale;
6610         }
6611         in += jump_in;
6612         out += jump_out;
6613       }
6614     }
6615     else if (format_in == RTAUDIO_SINT24) {
6616       INT32 *in = (INT32 *)input;
6617       scale = 1.0 / 2147483648.0;
6618       for (int i=0; i<stream->bufferSize; i++) {
6619         for (j=0; j<channels; j++) {
6620           out[offset_out[j]] = (FLOAT64) (in[offset_in[j]] & 0xffffff00);
6621           out[offset_out[j]] *= scale;
6622         }
6623         in += jump_in;
6624         out += jump_out;
6625       }
6626     }
6627     else if (format_in == RTAUDIO_SINT32) {
6628       INT32 *in = (INT32 *)input;
6629       scale = 1.0 / 2147483648.0;
6630       for (int i=0; i<stream->bufferSize; i++) {
6631         for (j=0; j<channels; j++) {
6632           out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
6633           out[offset_out[j]] *= scale;
6634         }
6635         in += jump_in;
6636         out += jump_out;
6637       }
6638     }
6639     else if (format_in == RTAUDIO_FLOAT32) {
6640       FLOAT32 *in = (FLOAT32 *)input;
6641       for (int i=0; i<stream->bufferSize; i++) {
6642         for (j=0; j<channels; j++) {
6643           out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
6644         }
6645         in += jump_in;
6646         out += jump_out;
6647       }
6648     }
6649     else if (format_in == RTAUDIO_FLOAT64) {
6650       // Channel compensation and/or (de)interleaving only.
6651       FLOAT64 *in = (FLOAT64 *)input;
6652       for (int i=0; i<stream->bufferSize; i++) {
6653         for (j=0; j<channels; j++) {
6654           out[offset_out[j]] = in[offset_in[j]];
6655         }
6656         in += jump_in;
6657         out += jump_out;
6658       }
6659     }
6660   }
6661   else if (format_out == RTAUDIO_FLOAT32) {
6662     FLOAT32 scale;
6663     FLOAT32 *out = (FLOAT32 *)output;
6664
6665     if (format_in == RTAUDIO_SINT8) {
6666       signed char *in = (signed char *)input;
6667       scale = 1.0 / 128.0;
6668       for (int i=0; i<stream->bufferSize; i++) {
6669         for (j=0; j<channels; j++) {
6670           out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
6671           out[offset_out[j]] *= scale;
6672         }
6673         in += jump_in;
6674         out += jump_out;
6675       }
6676     }
6677     else if (format_in == RTAUDIO_SINT16) {
6678       INT16 *in = (INT16 *)input;
6679       scale = 1.0 / 32768.0;
6680       for (int i=0; i<stream->bufferSize; i++) {
6681         for (j=0; j<channels; j++) {
6682           out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
6683           out[offset_out[j]] *= scale;
6684         }
6685         in += jump_in;
6686         out += jump_out;
6687       }
6688     }
6689     else if (format_in == RTAUDIO_SINT24) {
6690       INT32 *in = (INT32 *)input;
6691       scale = 1.0 / 2147483648.0;
6692       for (int i=0; i<stream->bufferSize; i++) {
6693         for (j=0; j<channels; j++) {
6694           out[offset_out[j]] = (FLOAT32) (in[offset_in[j]] & 0xffffff00);
6695           out[offset_out[j]] *= scale;
6696         }
6697         in += jump_in;
6698         out += jump_out;
6699       }
6700     }
6701     else if (format_in == RTAUDIO_SINT32) {
6702       INT32 *in = (INT32 *)input;
6703       scale = 1.0 / 2147483648.0;
6704       for (int i=0; i<stream->bufferSize; i++) {
6705         for (j=0; j<channels; j++) {
6706           out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
6707           out[offset_out[j]] *= scale;
6708         }
6709         in += jump_in;
6710         out += jump_out;
6711       }
6712     }
6713     else if (format_in == RTAUDIO_FLOAT32) {
6714       // Channel compensation and/or (de)interleaving only.
6715       FLOAT32 *in = (FLOAT32 *)input;
6716       for (int i=0; i<stream->bufferSize; i++) {
6717         for (j=0; j<channels; j++) {
6718           out[offset_out[j]] = in[offset_in[j]];
6719         }
6720         in += jump_in;
6721         out += jump_out;
6722       }
6723     }
6724     else if (format_in == RTAUDIO_FLOAT64) {
6725       FLOAT64 *in = (FLOAT64 *)input;
6726       for (int i=0; i<stream->bufferSize; i++) {
6727         for (j=0; j<channels; j++) {
6728           out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
6729         }
6730         in += jump_in;
6731         out += jump_out;
6732       }
6733     }
6734   }
6735   else if (format_out == RTAUDIO_SINT32) {
6736     INT32 *out = (INT32 *)output;
6737     if (format_in == RTAUDIO_SINT8) {
6738       signed char *in = (signed char *)input;
6739       for (int i=0; i<stream->bufferSize; i++) {
6740         for (j=0; j<channels; j++) {
6741           out[offset_out[j]] = (INT32) in[offset_in[j]];
6742           out[offset_out[j]] <<= 24;
6743         }
6744         in += jump_in;
6745         out += jump_out;
6746       }
6747     }
6748     else if (format_in == RTAUDIO_SINT16) {
6749       INT16 *in = (INT16 *)input;
6750       for (int i=0; i<stream->bufferSize; i++) {
6751         for (j=0; j<channels; j++) {
6752           out[offset_out[j]] = (INT32) in[offset_in[j]];
6753           out[offset_out[j]] <<= 16;
6754         }
6755         in += jump_in;
6756         out += jump_out;
6757       }
6758     }
6759     else if (format_in == RTAUDIO_SINT24) {
6760       INT32 *in = (INT32 *)input;
6761       for (int i=0; i<stream->bufferSize; i++) {
6762         for (j=0; j<channels; j++) {
6763           out[offset_out[j]] = (INT32) in[offset_in[j]];
6764         }
6765         in += jump_in;
6766         out += jump_out;
6767       }
6768     }
6769     else if (format_in == RTAUDIO_SINT32) {
6770       // Channel compensation and/or (de)interleaving only.
6771       INT32 *in = (INT32 *)input;
6772       for (int i=0; i<stream->bufferSize; i++) {
6773         for (j=0; j<channels; j++) {
6774           out[offset_out[j]] = in[offset_in[j]];
6775         }
6776         in += jump_in;
6777         out += jump_out;
6778       }
6779     }
6780     else if (format_in == RTAUDIO_FLOAT32) {
6781       FLOAT32 *in = (FLOAT32 *)input;
6782       for (int i=0; i<stream->bufferSize; i++) {
6783         for (j=0; j<channels; j++) {
6784           out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
6785         }
6786         in += jump_in;
6787         out += jump_out;
6788       }
6789     }
6790     else if (format_in == RTAUDIO_FLOAT64) {
6791       FLOAT64 *in = (FLOAT64 *)input;
6792       for (int i=0; i<stream->bufferSize; i++) {
6793         for (j=0; j<channels; j++) {
6794           out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
6795         }
6796         in += jump_in;
6797         out += jump_out;
6798       }
6799     }
6800   }
6801   else if (format_out == RTAUDIO_SINT24) {
6802     INT32 *out = (INT32 *)output;
6803     if (format_in == RTAUDIO_SINT8) {
6804       signed char *in = (signed char *)input;
6805       for (int i=0; i<stream->bufferSize; i++) {
6806         for (j=0; j<channels; j++) {
6807           out[offset_out[j]] = (INT32) in[offset_in[j]];
6808           out[offset_out[j]] <<= 24;
6809         }
6810         in += jump_in;
6811         out += jump_out;
6812       }
6813     }
6814     else if (format_in == RTAUDIO_SINT16) {
6815       INT16 *in = (INT16 *)input;
6816       for (int i=0; i<stream->bufferSize; i++) {
6817         for (j=0; j<channels; j++) {
6818           out[offset_out[j]] = (INT32) in[offset_in[j]];
6819           out[offset_out[j]] <<= 16;
6820         }
6821         in += jump_in;
6822         out += jump_out;
6823       }
6824     }
6825     else if (format_in == RTAUDIO_SINT24) {
6826       // Channel compensation and/or (de)interleaving only.
6827       INT32 *in = (INT32 *)input;
6828       for (int i=0; i<stream->bufferSize; i++) {
6829         for (j=0; j<channels; j++) {
6830           out[offset_out[j]] = in[offset_in[j]];
6831         }
6832         in += jump_in;
6833         out += jump_out;
6834       }
6835     }
6836     else if (format_in == RTAUDIO_SINT32) {
6837       INT32 *in = (INT32 *)input;
6838       for (int i=0; i<stream->bufferSize; i++) {
6839         for (j=0; j<channels; j++) {
6840           out[offset_out[j]] = (INT32) (in[offset_in[j]] & 0xffffff00);
6841         }
6842         in += jump_in;
6843         out += jump_out;
6844       }
6845     }
6846     else if (format_in == RTAUDIO_FLOAT32) {
6847       FLOAT32 *in = (FLOAT32 *)input;
6848       for (int i=0; i<stream->bufferSize; i++) {
6849         for (j=0; j<channels; j++) {
6850           out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
6851         }
6852         in += jump_in;
6853         out += jump_out;
6854       }
6855     }
6856     else if (format_in == RTAUDIO_FLOAT64) {
6857       FLOAT64 *in = (FLOAT64 *)input;
6858       for (int i=0; i<stream->bufferSize; i++) {
6859         for (j=0; j<channels; j++) {
6860           out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
6861         }
6862         in += jump_in;
6863         out += jump_out;
6864       }
6865     }
6866   }
6867   else if (format_out == RTAUDIO_SINT16) {
6868     INT16 *out = (INT16 *)output;
6869     if (format_in == RTAUDIO_SINT8) {
6870       signed char *in = (signed char *)input;
6871       for (int i=0; i<stream->bufferSize; i++) {
6872         for (j=0; j<channels; j++) {
6873           out[offset_out[j]] = (INT16) in[offset_in[j]];
6874           out[offset_out[j]] <<= 8;
6875         }
6876         in += jump_in;
6877         out += jump_out;
6878       }
6879     }
6880     else if (format_in == RTAUDIO_SINT16) {
6881       // Channel compensation and/or (de)interleaving only.
6882       INT16 *in = (INT16 *)input;
6883       for (int i=0; i<stream->bufferSize; i++) {
6884         for (j=0; j<channels; j++) {
6885           out[offset_out[j]] = in[offset_in[j]];
6886         }
6887         in += jump_in;
6888         out += jump_out;
6889       }
6890     }
6891     else if (format_in == RTAUDIO_SINT24) {
6892       INT32 *in = (INT32 *)input;
6893       for (int i=0; i<stream->bufferSize; i++) {
6894         for (j=0; j<channels; j++) {
6895           out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff);
6896         }
6897         in += jump_in;
6898         out += jump_out;
6899       }
6900     }
6901     else if (format_in == RTAUDIO_SINT32) {
6902       INT32 *in = (INT32 *)input;
6903       for (int i=0; i<stream->bufferSize; i++) {
6904         for (j=0; j<channels; j++) {
6905           out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff);
6906         }
6907         in += jump_in;
6908         out += jump_out;
6909       }
6910     }
6911     else if (format_in == RTAUDIO_FLOAT32) {
6912       FLOAT32 *in = (FLOAT32 *)input;
6913       for (int i=0; i<stream->bufferSize; i++) {
6914         for (j=0; j<channels; j++) {
6915           out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0);
6916         }
6917         in += jump_in;
6918         out += jump_out;
6919       }
6920     }
6921     else if (format_in == RTAUDIO_FLOAT64) {
6922       FLOAT64 *in = (FLOAT64 *)input;
6923       for (int i=0; i<stream->bufferSize; i++) {
6924         for (j=0; j<channels; j++) {
6925           out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0);
6926         }
6927         in += jump_in;
6928         out += jump_out;
6929       }
6930     }
6931   }
6932   else if (format_out == RTAUDIO_SINT8) {
6933     signed char *out = (signed char *)output;
6934     if (format_in == RTAUDIO_SINT8) {
6935       // Channel compensation and/or (de)interleaving only.
6936       signed char *in = (signed char *)input;
6937       for (int i=0; i<stream->bufferSize; i++) {
6938         for (j=0; j<channels; j++) {
6939           out[offset_out[j]] = in[offset_in[j]];
6940         }
6941         in += jump_in;
6942         out += jump_out;
6943       }
6944     }
6945     if (format_in == RTAUDIO_SINT16) {
6946       INT16 *in = (INT16 *)input;
6947       for (int i=0; i<stream->bufferSize; i++) {
6948         for (j=0; j<channels; j++) {
6949           out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 8) & 0x00ff);
6950         }
6951         in += jump_in;
6952         out += jump_out;
6953       }
6954     }
6955     else if (format_in == RTAUDIO_SINT24) {
6956       INT32 *in = (INT32 *)input;
6957       for (int i=0; i<stream->bufferSize; i++) {
6958         for (j=0; j<channels; j++) {
6959           out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff);
6960         }
6961         in += jump_in;
6962         out += jump_out;
6963       }
6964     }
6965     else if (format_in == RTAUDIO_SINT32) {
6966       INT32 *in = (INT32 *)input;
6967       for (int i=0; i<stream->bufferSize; i++) {
6968         for (j=0; j<channels; j++) {
6969           out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff);
6970         }
6971         in += jump_in;
6972         out += jump_out;
6973       }
6974     }
6975     else if (format_in == RTAUDIO_FLOAT32) {
6976       FLOAT32 *in = (FLOAT32 *)input;
6977       for (int i=0; i<stream->bufferSize; i++) {
6978         for (j=0; j<channels; j++) {
6979           out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0);
6980         }
6981         in += jump_in;
6982         out += jump_out;
6983       }
6984     }
6985     else if (format_in == RTAUDIO_FLOAT64) {
6986       FLOAT64 *in = (FLOAT64 *)input;
6987       for (int i=0; i<stream->bufferSize; i++) {
6988         for (j=0; j<channels; j++) {
6989           out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0);
6990         }
6991         in += jump_in;
6992         out += jump_out;
6993       }
6994     }
6995   }
6996 }
6997
6998 void RtAudio :: byteSwapBuffer(char *buffer, int samples, RTAUDIO_FORMAT format)
6999 {
7000   register char val;
7001   register char *ptr;
7002
7003   ptr = buffer;
7004   if (format == RTAUDIO_SINT16) {
7005     for (int i=0; i<samples; i++) {
7006       // Swap 1st and 2nd bytes.
7007       val = *(ptr);
7008       *(ptr) = *(ptr+1);
7009       *(ptr+1) = val;
7010
7011       // Increment 2 bytes.
7012       ptr += 2;
7013     }
7014   }
7015   else if (format == RTAUDIO_SINT24 ||
7016            format == RTAUDIO_SINT32 ||
7017            format == RTAUDIO_FLOAT32) {
7018     for (int i=0; i<samples; i++) {
7019       // Swap 1st and 4th bytes.
7020       val = *(ptr);
7021       *(ptr) = *(ptr+3);
7022       *(ptr+3) = val;
7023
7024       // Swap 2nd and 3rd bytes.
7025       ptr += 1;
7026       val = *(ptr);
7027       *(ptr) = *(ptr+1);
7028       *(ptr+1) = val;
7029
7030       // Increment 4 bytes.
7031       ptr += 4;
7032     }
7033   }
7034   else if (format == RTAUDIO_FLOAT64) {
7035     for (int i=0; i<samples; i++) {
7036       // Swap 1st and 8th bytes
7037       val = *(ptr);
7038       *(ptr) = *(ptr+7);
7039       *(ptr+7) = val;
7040
7041       // Swap 2nd and 7th bytes
7042       ptr += 1;
7043       val = *(ptr);
7044       *(ptr) = *(ptr+5);
7045       *(ptr+5) = val;
7046
7047       // Swap 3rd and 6th bytes
7048       ptr += 1;
7049       val = *(ptr);
7050       *(ptr) = *(ptr+3);
7051       *(ptr+3) = val;
7052
7053       // Swap 4th and 5th bytes
7054       ptr += 1;
7055       val = *(ptr);
7056       *(ptr) = *(ptr+1);
7057       *(ptr+1) = val;
7058
7059       // Increment 8 bytes.
7060       ptr += 8;
7061     }
7062   }
7063 }
7064
7065
7066 // *************************************************** //
7067 //
7068 // RtError class definition.
7069 //
7070 // *************************************************** //
7071
7072 RtError :: RtError(const char *p, TYPE tipe)
7073 {
7074   type = tipe;
7075   strncpy(error_message, p, 256);
7076 }
7077
7078 RtError :: ~RtError()
7079 {
7080 }
7081
7082 void RtError :: printMessage()
7083 {
7084   printf("\n%s\n\n", error_message);
7085 }