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