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