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