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