Round floats by using roundf in order to round correctly.
[rtaudio.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), Macintosh OS X (CoreAudio and Jack), and Windows
8     (DirectSound, ASIO and WASAPI) 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-2017 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 5.0.0
42
43 #include "RtAudio.h"
44 #include <iostream>
45 #include <cstdlib>
46 #include <cstring>
47 #include <climits>
48 #include <cmath>
49 #include <algorithm>
50
51 // Static variable definitions.
52 const unsigned int RtApi::MAX_SAMPLE_RATES = 14;
53 const unsigned int RtApi::SAMPLE_RATES[] = {
54   4000, 5512, 8000, 9600, 11025, 16000, 22050,
55   32000, 44100, 48000, 88200, 96000, 176400, 192000
56 };
57
58 #if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__) || defined(__WINDOWS_WASAPI__)
59   #define MUTEX_INITIALIZE(A) InitializeCriticalSection(A)
60   #define MUTEX_DESTROY(A)    DeleteCriticalSection(A)
61   #define MUTEX_LOCK(A)       EnterCriticalSection(A)
62   #define MUTEX_UNLOCK(A)     LeaveCriticalSection(A)
63
64   #include "tchar.h"
65
66   static std::string convertCharPointerToStdString(const char *text)
67   {
68     return std::string(text);
69   }
70
71   static std::string convertCharPointerToStdString(const wchar_t *text)
72   {
73     int length = WideCharToMultiByte(CP_UTF8, 0, text, -1, NULL, 0, NULL, NULL);
74     std::string s( length-1, '\0' );
75     WideCharToMultiByte(CP_UTF8, 0, text, -1, &s[0], length, NULL, NULL);
76     return s;
77   }
78
79 #elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__)
80   // pthread API
81   #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL)
82   #define MUTEX_DESTROY(A)    pthread_mutex_destroy(A)
83   #define MUTEX_LOCK(A)       pthread_mutex_lock(A)
84   #define MUTEX_UNLOCK(A)     pthread_mutex_unlock(A)
85 #else
86   #define MUTEX_INITIALIZE(A) abs(*A) // dummy definitions
87   #define MUTEX_DESTROY(A)    abs(*A) // dummy definitions
88 #endif
89
90 // *************************************************** //
91 //
92 // RtAudio definitions.
93 //
94 // *************************************************** //
95
96 std::string RtAudio :: getVersion( void )
97 {
98   return RTAUDIO_VERSION;
99 }
100
101 void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis )
102 {
103   apis.clear();
104
105   // The order here will control the order of RtAudio's API search in
106   // the constructor.
107 #if defined(__UNIX_JACK__)
108   apis.push_back( UNIX_JACK );
109 #endif
110 #if defined(__LINUX_ALSA__)
111   apis.push_back( LINUX_ALSA );
112 #endif
113 #if defined(__LINUX_PULSE__)
114   apis.push_back( LINUX_PULSE );
115 #endif
116 #if defined(__LINUX_OSS__)
117   apis.push_back( LINUX_OSS );
118 #endif
119 #if defined(__WINDOWS_ASIO__)
120   apis.push_back( WINDOWS_ASIO );
121 #endif
122 #if defined(__WINDOWS_WASAPI__)
123   apis.push_back( WINDOWS_WASAPI );
124 #endif
125 #if defined(__WINDOWS_DS__)
126   apis.push_back( WINDOWS_DS );
127 #endif
128 #if defined(__MACOSX_CORE__)
129   apis.push_back( MACOSX_CORE );
130 #endif
131 #if defined(__RTAUDIO_DUMMY__)
132   apis.push_back( RTAUDIO_DUMMY );
133 #endif
134 }
135
136 void RtAudio :: openRtApi( RtAudio::Api api )
137 {
138   if ( rtapi_ )
139     delete rtapi_;
140   rtapi_ = 0;
141
142 #if defined(__UNIX_JACK__)
143   if ( api == UNIX_JACK )
144     rtapi_ = new RtApiJack();
145 #endif
146 #if defined(__LINUX_ALSA__)
147   if ( api == LINUX_ALSA )
148     rtapi_ = new RtApiAlsa();
149 #endif
150 #if defined(__LINUX_PULSE__)
151   if ( api == LINUX_PULSE )
152     rtapi_ = new RtApiPulse();
153 #endif
154 #if defined(__LINUX_OSS__)
155   if ( api == LINUX_OSS )
156     rtapi_ = new RtApiOss();
157 #endif
158 #if defined(__WINDOWS_ASIO__)
159   if ( api == WINDOWS_ASIO )
160     rtapi_ = new RtApiAsio();
161 #endif
162 #if defined(__WINDOWS_WASAPI__)
163   if ( api == WINDOWS_WASAPI )
164     rtapi_ = new RtApiWasapi();
165 #endif
166 #if defined(__WINDOWS_DS__)
167   if ( api == WINDOWS_DS )
168     rtapi_ = new RtApiDs();
169 #endif
170 #if defined(__MACOSX_CORE__)
171   if ( api == MACOSX_CORE )
172     rtapi_ = new RtApiCore();
173 #endif
174 #if defined(__RTAUDIO_DUMMY__)
175   if ( api == RTAUDIO_DUMMY )
176     rtapi_ = new RtApiDummy();
177 #endif
178 }
179
180 RtAudio :: RtAudio( RtAudio::Api api )
181 {
182   rtapi_ = 0;
183
184   if ( api != UNSPECIFIED ) {
185     // Attempt to open the specified API.
186     openRtApi( api );
187     if ( rtapi_ ) return;
188
189     // No compiled support for specified API value.  Issue a debug
190     // warning and continue as if no API was specified.
191     std::cerr << "\nRtAudio: no compiled support for specified API argument!\n" << std::endl;
192   }
193
194   // Iterate through the compiled APIs and return as soon as we find
195   // one with at least one device or we reach the end of the list.
196   std::vector< RtAudio::Api > apis;
197   getCompiledApi( apis );
198   for ( unsigned int i=0; i<apis.size(); i++ ) {
199     openRtApi( apis[i] );
200     if ( rtapi_ && rtapi_->getDeviceCount() ) break;
201   }
202
203   if ( rtapi_ ) return;
204
205   // It should not be possible to get here because the preprocessor
206   // definition __RTAUDIO_DUMMY__ is automatically defined if no
207   // API-specific definitions are passed to the compiler. But just in
208   // case something weird happens, we'll thow an error.
209   std::string errorText = "\nRtAudio: no compiled API support found ... critical error!!\n\n";
210   throw( RtAudioError( errorText, RtAudioError::UNSPECIFIED ) );
211 }
212
213 RtAudio :: ~RtAudio()
214 {
215   if ( rtapi_ )
216     delete rtapi_;
217 }
218
219 void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters,
220                             RtAudio::StreamParameters *inputParameters,
221                             RtAudioFormat format, unsigned int sampleRate,
222                             unsigned int *bufferFrames,
223                             RtAudioCallback callback, void *userData,
224                             RtAudio::StreamOptions *options,
225                             RtAudioErrorCallback errorCallback )
226 {
227   return rtapi_->openStream( outputParameters, inputParameters, format,
228                              sampleRate, bufferFrames, callback,
229                              userData, options, errorCallback );
230 }
231
232 // *************************************************** //
233 //
234 // Public RtApi definitions (see end of file for
235 // private or protected utility functions).
236 //
237 // *************************************************** //
238
239 RtApi :: RtApi()
240 {
241   stream_.state = STREAM_CLOSED;
242   stream_.mode = UNINITIALIZED;
243   stream_.apiHandle = 0;
244   stream_.userBuffer[0] = 0;
245   stream_.userBuffer[1] = 0;
246   MUTEX_INITIALIZE( &stream_.mutex );
247   showWarnings_ = true;
248   firstErrorOccurred_ = false;
249 }
250
251 RtApi :: ~RtApi()
252 {
253   MUTEX_DESTROY( &stream_.mutex );
254 }
255
256 void RtApi :: openStream( RtAudio::StreamParameters *oParams,
257                           RtAudio::StreamParameters *iParams,
258                           RtAudioFormat format, unsigned int sampleRate,
259                           unsigned int *bufferFrames,
260                           RtAudioCallback callback, void *userData,
261                           RtAudio::StreamOptions *options,
262                           RtAudioErrorCallback errorCallback )
263 {
264   if ( stream_.state != STREAM_CLOSED ) {
265     errorText_ = "RtApi::openStream: a stream is already open!";
266     error( RtAudioError::INVALID_USE );
267     return;
268   }
269
270   // Clear stream information potentially left from a previously open stream.
271   clearStreamInfo();
272
273   if ( oParams && oParams->nChannels < 1 ) {
274     errorText_ = "RtApi::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one.";
275     error( RtAudioError::INVALID_USE );
276     return;
277   }
278
279   if ( iParams && iParams->nChannels < 1 ) {
280     errorText_ = "RtApi::openStream: a non-NULL input StreamParameters structure cannot have an nChannels value less than one.";
281     error( RtAudioError::INVALID_USE );
282     return;
283   }
284
285   if ( oParams == NULL && iParams == NULL ) {
286     errorText_ = "RtApi::openStream: input and output StreamParameters structures are both NULL!";
287     error( RtAudioError::INVALID_USE );
288     return;
289   }
290
291   if ( formatBytes(format) == 0 ) {
292     errorText_ = "RtApi::openStream: 'format' parameter value is undefined.";
293     error( RtAudioError::INVALID_USE );
294     return;
295   }
296
297   unsigned int nDevices = getDeviceCount();
298   unsigned int oChannels = 0;
299   if ( oParams ) {
300     oChannels = oParams->nChannels;
301     if ( oParams->deviceId >= nDevices ) {
302       errorText_ = "RtApi::openStream: output device parameter value is invalid.";
303       error( RtAudioError::INVALID_USE );
304       return;
305     }
306   }
307
308   unsigned int iChannels = 0;
309   if ( iParams ) {
310     iChannels = iParams->nChannels;
311     if ( iParams->deviceId >= nDevices ) {
312       errorText_ = "RtApi::openStream: input device parameter value is invalid.";
313       error( RtAudioError::INVALID_USE );
314       return;
315     }
316   }
317
318   bool result;
319
320   if ( oChannels > 0 ) {
321
322     result = probeDeviceOpen( oParams->deviceId, OUTPUT, oChannels, oParams->firstChannel,
323                               sampleRate, format, bufferFrames, options );
324     if ( result == false ) {
325       error( RtAudioError::SYSTEM_ERROR );
326       return;
327     }
328   }
329
330   if ( iChannels > 0 ) {
331
332     result = probeDeviceOpen( iParams->deviceId, INPUT, iChannels, iParams->firstChannel,
333                               sampleRate, format, bufferFrames, options );
334     if ( result == false ) {
335       if ( oChannels > 0 ) closeStream();
336       error( RtAudioError::SYSTEM_ERROR );
337       return;
338     }
339   }
340
341   stream_.callbackInfo.callback = (void *) callback;
342   stream_.callbackInfo.userData = userData;
343   stream_.callbackInfo.errorCallback = (void *) errorCallback;
344
345   if ( options ) options->numberOfBuffers = stream_.nBuffers;
346   stream_.state = STREAM_STOPPED;
347 }
348
349 unsigned int RtApi :: getDefaultInputDevice( void )
350 {
351   // Should be implemented in subclasses if possible.
352   return 0;
353 }
354
355 unsigned int RtApi :: getDefaultOutputDevice( void )
356 {
357   // Should be implemented in subclasses if possible.
358   return 0;
359 }
360
361 void RtApi :: closeStream( void )
362 {
363   // MUST be implemented in subclasses!
364   return;
365 }
366
367 bool RtApi :: probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/,
368                                unsigned int /*firstChannel*/, unsigned int /*sampleRate*/,
369                                RtAudioFormat /*format*/, unsigned int * /*bufferSize*/,
370                                RtAudio::StreamOptions * /*options*/ )
371 {
372   // MUST be implemented in subclasses!
373   return FAILURE;
374 }
375
376 void RtApi :: tickStreamTime( void )
377 {
378   // Subclasses that do not provide their own implementation of
379   // getStreamTime should call this function once per buffer I/O to
380   // provide basic stream time support.
381
382   stream_.streamTime += ( stream_.bufferSize * 1.0 / stream_.sampleRate );
383
384 #if defined( HAVE_GETTIMEOFDAY )
385   gettimeofday( &stream_.lastTickTimestamp, NULL );
386 #endif
387 }
388
389 long RtApi :: getStreamLatency( void )
390 {
391   verifyStream();
392
393   long totalLatency = 0;
394   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )
395     totalLatency = stream_.latency[0];
396   if ( stream_.mode == INPUT || stream_.mode == DUPLEX )
397     totalLatency += stream_.latency[1];
398
399   return totalLatency;
400 }
401
402 double RtApi :: getStreamTime( void )
403 {
404   verifyStream();
405
406 #if defined( HAVE_GETTIMEOFDAY )
407   // Return a very accurate estimate of the stream time by
408   // adding in the elapsed time since the last tick.
409   struct timeval then;
410   struct timeval now;
411
412   if ( stream_.state != STREAM_RUNNING || stream_.streamTime == 0.0 )
413     return stream_.streamTime;
414
415   gettimeofday( &now, NULL );
416   then = stream_.lastTickTimestamp;
417   return stream_.streamTime +
418     ((now.tv_sec + 0.000001 * now.tv_usec) -
419      (then.tv_sec + 0.000001 * then.tv_usec));     
420 #else
421   return stream_.streamTime;
422 #endif
423 }
424
425 void RtApi :: setStreamTime( double time )
426 {
427   verifyStream();
428
429   if ( time >= 0.0 )
430     stream_.streamTime = time;
431 #if defined( HAVE_GETTIMEOFDAY )
432   gettimeofday( &stream_.lastTickTimestamp, NULL );
433 #endif
434 }
435
436 unsigned int RtApi :: getStreamSampleRate( void )
437 {
438  verifyStream();
439
440  return stream_.sampleRate;
441 }
442
443
444 // *************************************************** //
445 //
446 // OS/API-specific methods.
447 //
448 // *************************************************** //
449
450 #if defined(__MACOSX_CORE__)
451
452 // The OS X CoreAudio API is designed to use a separate callback
453 // procedure for each of its audio devices.  A single RtAudio duplex
454 // stream using two different devices is supported here, though it
455 // cannot be guaranteed to always behave correctly because we cannot
456 // synchronize these two callbacks.
457 //
458 // A property listener is installed for over/underrun information.
459 // However, no functionality is currently provided to allow property
460 // listeners to trigger user handlers because it is unclear what could
461 // be done if a critical stream parameter (buffer size, sample rate,
462 // device disconnect) notification arrived.  The listeners entail
463 // quite a bit of extra code and most likely, a user program wouldn't
464 // be prepared for the result anyway.  However, we do provide a flag
465 // to the client callback function to inform of an over/underrun.
466
467 // A structure to hold various information related to the CoreAudio API
468 // implementation.
469 struct CoreHandle {
470   AudioDeviceID id[2];    // device ids
471 #if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
472   AudioDeviceIOProcID procId[2];
473 #endif
474   UInt32 iStream[2];      // device stream index (or first if using multiple)
475   UInt32 nStreams[2];     // number of streams to use
476   bool xrun[2];
477   char *deviceBuffer;
478   pthread_cond_t condition;
479   int drainCounter;       // Tracks callback counts when draining
480   bool internalDrain;     // Indicates if stop is initiated from callback or not.
481
482   CoreHandle()
483     :deviceBuffer(0), drainCounter(0), internalDrain(false) { nStreams[0] = 1; nStreams[1] = 1; id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }
484 };
485
486 RtApiCore:: RtApiCore()
487 {
488 #if defined( AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER )
489   // This is a largely undocumented but absolutely necessary
490   // requirement starting with OS-X 10.6.  If not called, queries and
491   // updates to various audio device properties are not handled
492   // correctly.
493   CFRunLoopRef theRunLoop = NULL;
494   AudioObjectPropertyAddress property = { kAudioHardwarePropertyRunLoop,
495                                           kAudioObjectPropertyScopeGlobal,
496                                           kAudioObjectPropertyElementMaster };
497   OSStatus result = AudioObjectSetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
498   if ( result != noErr ) {
499     errorText_ = "RtApiCore::RtApiCore: error setting run loop property!";
500     error( RtAudioError::WARNING );
501   }
502 #endif
503 }
504
505 RtApiCore :: ~RtApiCore()
506 {
507   // The subclass destructor gets called before the base class
508   // destructor, so close an existing stream before deallocating
509   // apiDeviceId memory.
510   if ( stream_.state != STREAM_CLOSED ) closeStream();
511 }
512
513 unsigned int RtApiCore :: getDeviceCount( void )
514 {
515   // Find out how many audio devices there are, if any.
516   UInt32 dataSize;
517   AudioObjectPropertyAddress propertyAddress = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
518   OSStatus result = AudioObjectGetPropertyDataSize( kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize );
519   if ( result != noErr ) {
520     errorText_ = "RtApiCore::getDeviceCount: OS-X error getting device info!";
521     error( RtAudioError::WARNING );
522     return 0;
523   }
524
525   return dataSize / sizeof( AudioDeviceID );
526 }
527
528 unsigned int RtApiCore :: getDefaultInputDevice( void )
529 {
530   unsigned int nDevices = getDeviceCount();
531   if ( nDevices <= 1 ) return 0;
532
533   AudioDeviceID id;
534   UInt32 dataSize = sizeof( AudioDeviceID );
535   AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
536   OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &id );
537   if ( result != noErr ) {
538     errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device.";
539     error( RtAudioError::WARNING );
540     return 0;
541   }
542
543   dataSize *= nDevices;
544   AudioDeviceID deviceList[ nDevices ];
545   property.mSelector = kAudioHardwarePropertyDevices;
546   result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList );
547   if ( result != noErr ) {
548     errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device IDs.";
549     error( RtAudioError::WARNING );
550     return 0;
551   }
552
553   for ( unsigned int i=0; i<nDevices; i++ )
554     if ( id == deviceList[i] ) return i;
555
556   errorText_ = "RtApiCore::getDefaultInputDevice: No default device found!";
557   error( RtAudioError::WARNING );
558   return 0;
559 }
560
561 unsigned int RtApiCore :: getDefaultOutputDevice( void )
562 {
563   unsigned int nDevices = getDeviceCount();
564   if ( nDevices <= 1 ) return 0;
565
566   AudioDeviceID id;
567   UInt32 dataSize = sizeof( AudioDeviceID );
568   AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
569   OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &id );
570   if ( result != noErr ) {
571     errorText_ = "RtApiCore::getDefaultOutputDevice: OS-X system error getting device.";
572     error( RtAudioError::WARNING );
573     return 0;
574   }
575
576   dataSize = sizeof( AudioDeviceID ) * nDevices;
577   AudioDeviceID deviceList[ nDevices ];
578   property.mSelector = kAudioHardwarePropertyDevices;
579   result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList );
580   if ( result != noErr ) {
581     errorText_ = "RtApiCore::getDefaultOutputDevice: OS-X system error getting device IDs.";
582     error( RtAudioError::WARNING );
583     return 0;
584   }
585
586   for ( unsigned int i=0; i<nDevices; i++ )
587     if ( id == deviceList[i] ) return i;
588
589   errorText_ = "RtApiCore::getDefaultOutputDevice: No default device found!";
590   error( RtAudioError::WARNING );
591   return 0;
592 }
593
594 RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
595 {
596   RtAudio::DeviceInfo info;
597   info.probed = false;
598
599   // Get device ID
600   unsigned int nDevices = getDeviceCount();
601   if ( nDevices == 0 ) {
602     errorText_ = "RtApiCore::getDeviceInfo: no devices found!";
603     error( RtAudioError::INVALID_USE );
604     return info;
605   }
606
607   if ( device >= nDevices ) {
608     errorText_ = "RtApiCore::getDeviceInfo: device ID is invalid!";
609     error( RtAudioError::INVALID_USE );
610     return info;
611   }
612
613   AudioDeviceID deviceList[ nDevices ];
614   UInt32 dataSize = sizeof( AudioDeviceID ) * nDevices;
615   AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,
616                                           kAudioObjectPropertyScopeGlobal,
617                                           kAudioObjectPropertyElementMaster };
618   OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property,
619                                                 0, NULL, &dataSize, (void *) &deviceList );
620   if ( result != noErr ) {
621     errorText_ = "RtApiCore::getDeviceInfo: OS-X system error getting device IDs.";
622     error( RtAudioError::WARNING );
623     return info;
624   }
625
626   AudioDeviceID id = deviceList[ device ];
627
628   // Get the device name.
629   info.name.erase();
630   CFStringRef cfname;
631   dataSize = sizeof( CFStringRef );
632   property.mSelector = kAudioObjectPropertyManufacturer;
633   result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &cfname );
634   if ( result != noErr ) {
635     errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device manufacturer.";
636     errorText_ = errorStream_.str();
637     error( RtAudioError::WARNING );
638     return info;
639   }
640
641   //const char *mname = CFStringGetCStringPtr( cfname, CFStringGetSystemEncoding() );
642   int length = CFStringGetLength(cfname);
643   char *mname = (char *)malloc(length * 3 + 1);
644 #if defined( UNICODE ) || defined( _UNICODE )
645   CFStringGetCString(cfname, mname, length * 3 + 1, kCFStringEncodingUTF8);
646 #else
647   CFStringGetCString(cfname, mname, length * 3 + 1, CFStringGetSystemEncoding());
648 #endif
649   info.name.append( (const char *)mname, strlen(mname) );
650   info.name.append( ": " );
651   CFRelease( cfname );
652   free(mname);
653
654   property.mSelector = kAudioObjectPropertyName;
655   result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &cfname );
656   if ( result != noErr ) {
657     errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device name.";
658     errorText_ = errorStream_.str();
659     error( RtAudioError::WARNING );
660     return info;
661   }
662
663   //const char *name = CFStringGetCStringPtr( cfname, CFStringGetSystemEncoding() );
664   length = CFStringGetLength(cfname);
665   char *name = (char *)malloc(length * 3 + 1);
666 #if defined( UNICODE ) || defined( _UNICODE )
667   CFStringGetCString(cfname, name, length * 3 + 1, kCFStringEncodingUTF8);
668 #else
669   CFStringGetCString(cfname, name, length * 3 + 1, CFStringGetSystemEncoding());
670 #endif
671   info.name.append( (const char *)name, strlen(name) );
672   CFRelease( cfname );
673   free(name);
674
675   // Get the output stream "configuration".
676   AudioBufferList       *bufferList = nil;
677   property.mSelector = kAudioDevicePropertyStreamConfiguration;
678   property.mScope = kAudioDevicePropertyScopeOutput;
679   //  property.mElement = kAudioObjectPropertyElementWildcard;
680   dataSize = 0;
681   result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );
682   if ( result != noErr || dataSize == 0 ) {
683     errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration info for device (" << device << ").";
684     errorText_ = errorStream_.str();
685     error( RtAudioError::WARNING );
686     return info;
687   }
688
689   // Allocate the AudioBufferList.
690   bufferList = (AudioBufferList *) malloc( dataSize );
691   if ( bufferList == NULL ) {
692     errorText_ = "RtApiCore::getDeviceInfo: memory error allocating output AudioBufferList.";
693     error( RtAudioError::WARNING );
694     return info;
695   }
696
697   result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList );
698   if ( result != noErr || dataSize == 0 ) {
699     free( bufferList );
700     errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration for device (" << device << ").";
701     errorText_ = errorStream_.str();
702     error( RtAudioError::WARNING );
703     return info;
704   }
705
706   // Get output channel information.
707   unsigned int i, nStreams = bufferList->mNumberBuffers;
708   for ( i=0; i<nStreams; i++ )
709     info.outputChannels += bufferList->mBuffers[i].mNumberChannels;
710   free( bufferList );
711
712   // Get the input stream "configuration".
713   property.mScope = kAudioDevicePropertyScopeInput;
714   result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );
715   if ( result != noErr || dataSize == 0 ) {
716     errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration info for device (" << device << ").";
717     errorText_ = errorStream_.str();
718     error( RtAudioError::WARNING );
719     return info;
720   }
721
722   // Allocate the AudioBufferList.
723   bufferList = (AudioBufferList *) malloc( dataSize );
724   if ( bufferList == NULL ) {
725     errorText_ = "RtApiCore::getDeviceInfo: memory error allocating input AudioBufferList.";
726     error( RtAudioError::WARNING );
727     return info;
728   }
729
730   result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList );
731   if (result != noErr || dataSize == 0) {
732     free( bufferList );
733     errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration for device (" << device << ").";
734     errorText_ = errorStream_.str();
735     error( RtAudioError::WARNING );
736     return info;
737   }
738
739   // Get input channel information.
740   nStreams = bufferList->mNumberBuffers;
741   for ( i=0; i<nStreams; i++ )
742     info.inputChannels += bufferList->mBuffers[i].mNumberChannels;
743   free( bufferList );
744
745   // If device opens for both playback and capture, we determine the channels.
746   if ( info.outputChannels > 0 && info.inputChannels > 0 )
747     info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
748
749   // Probe the device sample rates.
750   bool isInput = false;
751   if ( info.outputChannels == 0 ) isInput = true;
752
753   // Determine the supported sample rates.
754   property.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
755   if ( isInput == false ) property.mScope = kAudioDevicePropertyScopeOutput;
756   result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );
757   if ( result != kAudioHardwareNoError || dataSize == 0 ) {
758     errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rate info.";
759     errorText_ = errorStream_.str();
760     error( RtAudioError::WARNING );
761     return info;
762   }
763
764   UInt32 nRanges = dataSize / sizeof( AudioValueRange );
765   AudioValueRange rangeList[ nRanges ];
766   result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &rangeList );
767   if ( result != kAudioHardwareNoError ) {
768     errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rates.";
769     errorText_ = errorStream_.str();
770     error( RtAudioError::WARNING );
771     return info;
772   }
773
774   // The sample rate reporting mechanism is a bit of a mystery.  It
775   // seems that it can either return individual rates or a range of
776   // rates.  I assume that if the min / max range values are the same,
777   // then that represents a single supported rate and if the min / max
778   // range values are different, the device supports an arbitrary
779   // range of values (though there might be multiple ranges, so we'll
780   // use the most conservative range).
781   Float64 minimumRate = 1.0, maximumRate = 10000000000.0;
782   bool haveValueRange = false;
783   info.sampleRates.clear();
784   for ( UInt32 i=0; i<nRanges; i++ ) {
785     if ( rangeList[i].mMinimum == rangeList[i].mMaximum ) {
786       unsigned int tmpSr = (unsigned int) rangeList[i].mMinimum;
787       info.sampleRates.push_back( tmpSr );
788
789       if ( !info.preferredSampleRate || ( tmpSr <= 48000 && tmpSr > info.preferredSampleRate ) )
790         info.preferredSampleRate = tmpSr;
791
792     } else {
793       haveValueRange = true;
794       if ( rangeList[i].mMinimum > minimumRate ) minimumRate = rangeList[i].mMinimum;
795       if ( rangeList[i].mMaximum < maximumRate ) maximumRate = rangeList[i].mMaximum;
796     }
797   }
798
799   if ( haveValueRange ) {
800     for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
801       if ( SAMPLE_RATES[k] >= (unsigned int) minimumRate && SAMPLE_RATES[k] <= (unsigned int) maximumRate ) {
802         info.sampleRates.push_back( SAMPLE_RATES[k] );
803
804         if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )
805           info.preferredSampleRate = SAMPLE_RATES[k];
806       }
807     }
808   }
809
810   // Sort and remove any redundant values
811   std::sort( info.sampleRates.begin(), info.sampleRates.end() );
812   info.sampleRates.erase( unique( info.sampleRates.begin(), info.sampleRates.end() ), info.sampleRates.end() );
813
814   if ( info.sampleRates.size() == 0 ) {
815     errorStream_ << "RtApiCore::probeDeviceInfo: No supported sample rates found for device (" << device << ").";
816     errorText_ = errorStream_.str();
817     error( RtAudioError::WARNING );
818     return info;
819   }
820
821   // CoreAudio always uses 32-bit floating point data for PCM streams.
822   // Thus, any other "physical" formats supported by the device are of
823   // no interest to the client.
824   info.nativeFormats = RTAUDIO_FLOAT32;
825
826   if ( info.outputChannels > 0 )
827     if ( getDefaultOutputDevice() == device ) info.isDefaultOutput = true;
828   if ( info.inputChannels > 0 )
829     if ( getDefaultInputDevice() == device ) info.isDefaultInput = true;
830
831   info.probed = true;
832   return info;
833 }
834
835 static OSStatus callbackHandler( AudioDeviceID inDevice,
836                                  const AudioTimeStamp* /*inNow*/,
837                                  const AudioBufferList* inInputData,
838                                  const AudioTimeStamp* /*inInputTime*/,
839                                  AudioBufferList* outOutputData,
840                                  const AudioTimeStamp* /*inOutputTime*/,
841                                  void* infoPointer )
842 {
843   CallbackInfo *info = (CallbackInfo *) infoPointer;
844
845   RtApiCore *object = (RtApiCore *) info->object;
846   if ( object->callbackEvent( inDevice, inInputData, outOutputData ) == false )
847     return kAudioHardwareUnspecifiedError;
848   else
849     return kAudioHardwareNoError;
850 }
851
852 static OSStatus xrunListener( AudioObjectID /*inDevice*/,
853                               UInt32 nAddresses,
854                               const AudioObjectPropertyAddress properties[],
855                               void* handlePointer )
856 {
857   CoreHandle *handle = (CoreHandle *) handlePointer;
858   for ( UInt32 i=0; i<nAddresses; i++ ) {
859     if ( properties[i].mSelector == kAudioDeviceProcessorOverload ) {
860       if ( properties[i].mScope == kAudioDevicePropertyScopeInput )
861         handle->xrun[1] = true;
862       else
863         handle->xrun[0] = true;
864     }
865   }
866
867   return kAudioHardwareNoError;
868 }
869
870 static OSStatus rateListener( AudioObjectID inDevice,
871                               UInt32 /*nAddresses*/,
872                               const AudioObjectPropertyAddress /*properties*/[],
873                               void* ratePointer )
874 {
875   Float64 *rate = (Float64 *) ratePointer;
876   UInt32 dataSize = sizeof( Float64 );
877   AudioObjectPropertyAddress property = { kAudioDevicePropertyNominalSampleRate,
878                                           kAudioObjectPropertyScopeGlobal,
879                                           kAudioObjectPropertyElementMaster };
880   AudioObjectGetPropertyData( inDevice, &property, 0, NULL, &dataSize, rate );
881   return kAudioHardwareNoError;
882 }
883
884 bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
885                                    unsigned int firstChannel, unsigned int sampleRate,
886                                    RtAudioFormat format, unsigned int *bufferSize,
887                                    RtAudio::StreamOptions *options )
888 {
889   // Get device ID
890   unsigned int nDevices = getDeviceCount();
891   if ( nDevices == 0 ) {
892     // This should not happen because a check is made before this function is called.
893     errorText_ = "RtApiCore::probeDeviceOpen: no devices found!";
894     return FAILURE;
895   }
896
897   if ( device >= nDevices ) {
898     // This should not happen because a check is made before this function is called.
899     errorText_ = "RtApiCore::probeDeviceOpen: device ID is invalid!";
900     return FAILURE;
901   }
902
903   AudioDeviceID deviceList[ nDevices ];
904   UInt32 dataSize = sizeof( AudioDeviceID ) * nDevices;
905   AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,
906                                           kAudioObjectPropertyScopeGlobal,
907                                           kAudioObjectPropertyElementMaster };
908   OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property,
909                                                 0, NULL, &dataSize, (void *) &deviceList );
910   if ( result != noErr ) {
911     errorText_ = "RtApiCore::probeDeviceOpen: OS-X system error getting device IDs.";
912     return FAILURE;
913   }
914
915   AudioDeviceID id = deviceList[ device ];
916
917   // Setup for stream mode.
918   bool isInput = false;
919   if ( mode == INPUT ) {
920     isInput = true;
921     property.mScope = kAudioDevicePropertyScopeInput;
922   }
923   else
924     property.mScope = kAudioDevicePropertyScopeOutput;
925
926   // Get the stream "configuration".
927   AudioBufferList       *bufferList = nil;
928   dataSize = 0;
929   property.mSelector = kAudioDevicePropertyStreamConfiguration;
930   result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );
931   if ( result != noErr || dataSize == 0 ) {
932     errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream configuration info for device (" << device << ").";
933     errorText_ = errorStream_.str();
934     return FAILURE;
935   }
936
937   // Allocate the AudioBufferList.
938   bufferList = (AudioBufferList *) malloc( dataSize );
939   if ( bufferList == NULL ) {
940     errorText_ = "RtApiCore::probeDeviceOpen: memory error allocating AudioBufferList.";
941     return FAILURE;
942   }
943
944   result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList );
945   if (result != noErr || dataSize == 0) {
946     free( bufferList );
947     errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream configuration for device (" << device << ").";
948     errorText_ = errorStream_.str();
949     return FAILURE;
950   }
951
952   // Search for one or more streams that contain the desired number of
953   // channels. CoreAudio devices can have an arbitrary number of
954   // streams and each stream can have an arbitrary number of channels.
955   // For each stream, a single buffer of interleaved samples is
956   // provided.  RtAudio prefers the use of one stream of interleaved
957   // data or multiple consecutive single-channel streams.  However, we
958   // now support multiple consecutive multi-channel streams of
959   // interleaved data as well.
960   UInt32 iStream, offsetCounter = firstChannel;
961   UInt32 nStreams = bufferList->mNumberBuffers;
962   bool monoMode = false;
963   bool foundStream = false;
964
965   // First check that the device supports the requested number of
966   // channels.
967   UInt32 deviceChannels = 0;
968   for ( iStream=0; iStream<nStreams; iStream++ )
969     deviceChannels += bufferList->mBuffers[iStream].mNumberChannels;
970
971   if ( deviceChannels < ( channels + firstChannel ) ) {
972     free( bufferList );
973     errorStream_ << "RtApiCore::probeDeviceOpen: the device (" << device << ") does not support the requested channel count.";
974     errorText_ = errorStream_.str();
975     return FAILURE;
976   }
977
978   // Look for a single stream meeting our needs.
979   UInt32 firstStream, streamCount = 1, streamChannels = 0, channelOffset = 0;
980   for ( iStream=0; iStream<nStreams; iStream++ ) {
981     streamChannels = bufferList->mBuffers[iStream].mNumberChannels;
982     if ( streamChannels >= channels + offsetCounter ) {
983       firstStream = iStream;
984       channelOffset = offsetCounter;
985       foundStream = true;
986       break;
987     }
988     if ( streamChannels > offsetCounter ) break;
989     offsetCounter -= streamChannels;
990   }
991
992   // If we didn't find a single stream above, then we should be able
993   // to meet the channel specification with multiple streams.
994   if ( foundStream == false ) {
995     monoMode = true;
996     offsetCounter = firstChannel;
997     for ( iStream=0; iStream<nStreams; iStream++ ) {
998       streamChannels = bufferList->mBuffers[iStream].mNumberChannels;
999       if ( streamChannels > offsetCounter ) break;
1000       offsetCounter -= streamChannels;
1001     }
1002
1003     firstStream = iStream;
1004     channelOffset = offsetCounter;
1005     Int32 channelCounter = channels + offsetCounter - streamChannels;
1006
1007     if ( streamChannels > 1 ) monoMode = false;
1008     while ( channelCounter > 0 ) {
1009       streamChannels = bufferList->mBuffers[++iStream].mNumberChannels;
1010       if ( streamChannels > 1 ) monoMode = false;
1011       channelCounter -= streamChannels;
1012       streamCount++;
1013     }
1014   }
1015
1016   free( bufferList );
1017
1018   // Determine the buffer size.
1019   AudioValueRange       bufferRange;
1020   dataSize = sizeof( AudioValueRange );
1021   property.mSelector = kAudioDevicePropertyBufferFrameSizeRange;
1022   result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &bufferRange );
1023
1024   if ( result != noErr ) {
1025     errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting buffer size range for device (" << device << ").";
1026     errorText_ = errorStream_.str();
1027     return FAILURE;
1028   }
1029
1030   if ( bufferRange.mMinimum > *bufferSize ) *bufferSize = (unsigned long) bufferRange.mMinimum;
1031   else if ( bufferRange.mMaximum < *bufferSize ) *bufferSize = (unsigned long) bufferRange.mMaximum;
1032   if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) *bufferSize = (unsigned long) bufferRange.mMinimum;
1033
1034   // Set the buffer size.  For multiple streams, I'm assuming we only
1035   // need to make this setting for the master channel.
1036   UInt32 theSize = (UInt32) *bufferSize;
1037   dataSize = sizeof( UInt32 );
1038   property.mSelector = kAudioDevicePropertyBufferFrameSize;
1039   result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &theSize );
1040
1041   if ( result != noErr ) {
1042     errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting the buffer size for device (" << device << ").";
1043     errorText_ = errorStream_.str();
1044     return FAILURE;
1045   }
1046
1047   // If attempting to setup a duplex stream, the bufferSize parameter
1048   // MUST be the same in both directions!
1049   *bufferSize = theSize;
1050   if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) {
1051     errorStream_ << "RtApiCore::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << device << ").";
1052     errorText_ = errorStream_.str();
1053     return FAILURE;
1054   }
1055
1056   stream_.bufferSize = *bufferSize;
1057   stream_.nBuffers = 1;
1058
1059   // Try to set "hog" mode ... it's not clear to me this is working.
1060   if ( options && options->flags & RTAUDIO_HOG_DEVICE ) {
1061     pid_t hog_pid;
1062     dataSize = sizeof( hog_pid );
1063     property.mSelector = kAudioDevicePropertyHogMode;
1064     result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &hog_pid );
1065     if ( result != noErr ) {
1066       errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting 'hog' state!";
1067       errorText_ = errorStream_.str();
1068       return FAILURE;
1069     }
1070
1071     if ( hog_pid != getpid() ) {
1072       hog_pid = getpid();
1073       result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &hog_pid );
1074       if ( result != noErr ) {
1075         errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting 'hog' state!";
1076         errorText_ = errorStream_.str();
1077         return FAILURE;
1078       }
1079     }
1080   }
1081
1082   // Check and if necessary, change the sample rate for the device.
1083   Float64 nominalRate;
1084   dataSize = sizeof( Float64 );
1085   property.mSelector = kAudioDevicePropertyNominalSampleRate;
1086   result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &nominalRate );
1087   if ( result != noErr ) {
1088     errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting current sample rate.";
1089     errorText_ = errorStream_.str();
1090     return FAILURE;
1091   }
1092
1093   // Only change the sample rate if off by more than 1 Hz.
1094   if ( fabs( nominalRate - (double)sampleRate ) > 1.0 ) {
1095
1096     // Set a property listener for the sample rate change
1097     Float64 reportedRate = 0.0;
1098     AudioObjectPropertyAddress tmp = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
1099     result = AudioObjectAddPropertyListener( id, &tmp, rateListener, (void *) &reportedRate );
1100     if ( result != noErr ) {
1101       errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate property listener for device (" << device << ").";
1102       errorText_ = errorStream_.str();
1103       return FAILURE;
1104     }
1105
1106     nominalRate = (Float64) sampleRate;
1107     result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &nominalRate );
1108     if ( result != noErr ) {
1109       AudioObjectRemovePropertyListener( id, &tmp, rateListener, (void *) &reportedRate );
1110       errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate for device (" << device << ").";
1111       errorText_ = errorStream_.str();
1112       return FAILURE;
1113     }
1114
1115     // Now wait until the reported nominal rate is what we just set.
1116     UInt32 microCounter = 0;
1117     while ( reportedRate != nominalRate ) {
1118       microCounter += 5000;
1119       if ( microCounter > 5000000 ) break;
1120       usleep( 5000 );
1121     }
1122
1123     // Remove the property listener.
1124     AudioObjectRemovePropertyListener( id, &tmp, rateListener, (void *) &reportedRate );
1125
1126     if ( microCounter > 5000000 ) {
1127       errorStream_ << "RtApiCore::probeDeviceOpen: timeout waiting for sample rate update for device (" << device << ").";
1128       errorText_ = errorStream_.str();
1129       return FAILURE;
1130     }
1131   }
1132
1133   // Now set the stream format for all streams.  Also, check the
1134   // physical format of the device and change that if necessary.
1135   AudioStreamBasicDescription   description;
1136   dataSize = sizeof( AudioStreamBasicDescription );
1137   property.mSelector = kAudioStreamPropertyVirtualFormat;
1138   result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &description );
1139   if ( result != noErr ) {
1140     errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream format for device (" << device << ").";
1141     errorText_ = errorStream_.str();
1142     return FAILURE;
1143   }
1144
1145   // Set the sample rate and data format id.  However, only make the
1146   // change if the sample rate is not within 1.0 of the desired
1147   // rate and the format is not linear pcm.
1148   bool updateFormat = false;
1149   if ( fabs( description.mSampleRate - (Float64)sampleRate ) > 1.0 ) {
1150     description.mSampleRate = (Float64) sampleRate;
1151     updateFormat = true;
1152   }
1153
1154   if ( description.mFormatID != kAudioFormatLinearPCM ) {
1155     description.mFormatID = kAudioFormatLinearPCM;
1156     updateFormat = true;
1157   }
1158
1159   if ( updateFormat ) {
1160     result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &description );
1161     if ( result != noErr ) {
1162       errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate or data format for device (" << device << ").";
1163       errorText_ = errorStream_.str();
1164       return FAILURE;
1165     }
1166   }
1167
1168   // Now check the physical format.
1169   property.mSelector = kAudioStreamPropertyPhysicalFormat;
1170   result = AudioObjectGetPropertyData( id, &property, 0, NULL,  &dataSize, &description );
1171   if ( result != noErr ) {
1172     errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream physical format for device (" << device << ").";
1173     errorText_ = errorStream_.str();
1174     return FAILURE;
1175   }
1176
1177   //std::cout << "Current physical stream format:" << std::endl;
1178   //std::cout << "   mBitsPerChan = " << description.mBitsPerChannel << std::endl;
1179   //std::cout << "   aligned high = " << (description.mFormatFlags & kAudioFormatFlagIsAlignedHigh) << ", isPacked = " << (description.mFormatFlags & kAudioFormatFlagIsPacked) << std::endl;
1180   //std::cout << "   bytesPerFrame = " << description.mBytesPerFrame << std::endl;
1181   //std::cout << "   sample rate = " << description.mSampleRate << std::endl;
1182
1183   if ( description.mFormatID != kAudioFormatLinearPCM || description.mBitsPerChannel < 16 ) {
1184     description.mFormatID = kAudioFormatLinearPCM;
1185     //description.mSampleRate = (Float64) sampleRate;
1186     AudioStreamBasicDescription testDescription = description;
1187     UInt32 formatFlags;
1188
1189     // We'll try higher bit rates first and then work our way down.
1190     std::vector< std::pair<UInt32, UInt32>  > physicalFormats;
1191     formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsFloat) & ~kLinearPCMFormatFlagIsSignedInteger;
1192     physicalFormats.push_back( std::pair<Float32, UInt32>( 32, formatFlags ) );
1193     formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat;
1194     physicalFormats.push_back( std::pair<Float32, UInt32>( 32, formatFlags ) );
1195     physicalFormats.push_back( std::pair<Float32, UInt32>( 24, formatFlags ) );   // 24-bit packed
1196     formatFlags &= ~( kAudioFormatFlagIsPacked | kAudioFormatFlagIsAlignedHigh );
1197     physicalFormats.push_back( std::pair<Float32, UInt32>( 24.2, formatFlags ) ); // 24-bit in 4 bytes, aligned low
1198     formatFlags |= kAudioFormatFlagIsAlignedHigh;
1199     physicalFormats.push_back( std::pair<Float32, UInt32>( 24.4, formatFlags ) ); // 24-bit in 4 bytes, aligned high
1200     formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat;
1201     physicalFormats.push_back( std::pair<Float32, UInt32>( 16, formatFlags ) );
1202     physicalFormats.push_back( std::pair<Float32, UInt32>( 8, formatFlags ) );
1203
1204     bool setPhysicalFormat = false;
1205     for( unsigned int i=0; i<physicalFormats.size(); i++ ) {
1206       testDescription = description;
1207       testDescription.mBitsPerChannel = (UInt32) physicalFormats[i].first;
1208       testDescription.mFormatFlags = physicalFormats[i].second;
1209       if ( (24 == (UInt32)physicalFormats[i].first) && ~( physicalFormats[i].second & kAudioFormatFlagIsPacked ) )
1210         testDescription.mBytesPerFrame =  4 * testDescription.mChannelsPerFrame;
1211       else
1212         testDescription.mBytesPerFrame =  testDescription.mBitsPerChannel/8 * testDescription.mChannelsPerFrame;
1213       testDescription.mBytesPerPacket = testDescription.mBytesPerFrame * testDescription.mFramesPerPacket;
1214       result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &testDescription );
1215       if ( result == noErr ) {
1216         setPhysicalFormat = true;
1217         //std::cout << "Updated physical stream format:" << std::endl;
1218         //std::cout << "   mBitsPerChan = " << testDescription.mBitsPerChannel << std::endl;
1219         //std::cout << "   aligned high = " << (testDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) << ", isPacked = " << (testDescription.mFormatFlags & kAudioFormatFlagIsPacked) << std::endl;
1220         //std::cout << "   bytesPerFrame = " << testDescription.mBytesPerFrame << std::endl;
1221         //std::cout << "   sample rate = " << testDescription.mSampleRate << std::endl;
1222         break;
1223       }
1224     }
1225
1226     if ( !setPhysicalFormat ) {
1227       errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting physical data format for device (" << device << ").";
1228       errorText_ = errorStream_.str();
1229       return FAILURE;
1230     }
1231   } // done setting virtual/physical formats.
1232
1233   // Get the stream / device latency.
1234   UInt32 latency;
1235   dataSize = sizeof( UInt32 );
1236   property.mSelector = kAudioDevicePropertyLatency;
1237   if ( AudioObjectHasProperty( id, &property ) == true ) {
1238     result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &latency );
1239     if ( result == kAudioHardwareNoError ) stream_.latency[ mode ] = latency;
1240     else {
1241       errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting device latency for device (" << device << ").";
1242       errorText_ = errorStream_.str();
1243       error( RtAudioError::WARNING );
1244     }
1245   }
1246
1247   // Byte-swapping: According to AudioHardware.h, the stream data will
1248   // always be presented in native-endian format, so we should never
1249   // need to byte swap.
1250   stream_.doByteSwap[mode] = false;
1251
1252   // From the CoreAudio documentation, PCM data must be supplied as
1253   // 32-bit floats.
1254   stream_.userFormat = format;
1255   stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
1256
1257   if ( streamCount == 1 )
1258     stream_.nDeviceChannels[mode] = description.mChannelsPerFrame;
1259   else // multiple streams
1260     stream_.nDeviceChannels[mode] = channels;
1261   stream_.nUserChannels[mode] = channels;
1262   stream_.channelOffset[mode] = channelOffset;  // offset within a CoreAudio stream
1263   if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;
1264   else stream_.userInterleaved = true;
1265   stream_.deviceInterleaved[mode] = true;
1266   if ( monoMode == true ) stream_.deviceInterleaved[mode] = false;
1267
1268   // Set flags for buffer conversion.
1269   stream_.doConvertBuffer[mode] = false;
1270   if ( stream_.userFormat != stream_.deviceFormat[mode] )
1271     stream_.doConvertBuffer[mode] = true;
1272   if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )
1273     stream_.doConvertBuffer[mode] = true;
1274   if ( streamCount == 1 ) {
1275     if ( stream_.nUserChannels[mode] > 1 &&
1276          stream_.userInterleaved != stream_.deviceInterleaved[mode] )
1277       stream_.doConvertBuffer[mode] = true;
1278   }
1279   else if ( monoMode && stream_.userInterleaved )
1280     stream_.doConvertBuffer[mode] = true;
1281
1282   // Allocate our CoreHandle structure for the stream.
1283   CoreHandle *handle = 0;
1284   if ( stream_.apiHandle == 0 ) {
1285     try {
1286       handle = new CoreHandle;
1287     }
1288     catch ( std::bad_alloc& ) {
1289       errorText_ = "RtApiCore::probeDeviceOpen: error allocating CoreHandle memory.";
1290       goto error;
1291     }
1292
1293     if ( pthread_cond_init( &handle->condition, NULL ) ) {
1294       errorText_ = "RtApiCore::probeDeviceOpen: error initializing pthread condition variable.";
1295       goto error;
1296     }
1297     stream_.apiHandle = (void *) handle;
1298   }
1299   else
1300     handle = (CoreHandle *) stream_.apiHandle;
1301   handle->iStream[mode] = firstStream;
1302   handle->nStreams[mode] = streamCount;
1303   handle->id[mode] = id;
1304
1305   // Allocate necessary internal buffers.
1306   unsigned long bufferBytes;
1307   bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
1308   //  stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
1309   stream_.userBuffer[mode] = (char *) malloc( bufferBytes * sizeof(char) );
1310   memset( stream_.userBuffer[mode], 0, bufferBytes * sizeof(char) );
1311   if ( stream_.userBuffer[mode] == NULL ) {
1312     errorText_ = "RtApiCore::probeDeviceOpen: error allocating user buffer memory.";
1313     goto error;
1314   }
1315
1316   // If possible, we will make use of the CoreAudio stream buffers as
1317   // "device buffers".  However, we can't do this if using multiple
1318   // streams.
1319   if ( stream_.doConvertBuffer[mode] && handle->nStreams[mode] > 1 ) {
1320
1321     bool makeBuffer = true;
1322     bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
1323     if ( mode == INPUT ) {
1324       if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
1325         unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
1326         if ( bufferBytes <= bytesOut ) makeBuffer = false;
1327       }
1328     }
1329
1330     if ( makeBuffer ) {
1331       bufferBytes *= *bufferSize;
1332       if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
1333       stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
1334       if ( stream_.deviceBuffer == NULL ) {
1335         errorText_ = "RtApiCore::probeDeviceOpen: error allocating device buffer memory.";
1336         goto error;
1337       }
1338     }
1339   }
1340
1341   stream_.sampleRate = sampleRate;
1342   stream_.device[mode] = device;
1343   stream_.state = STREAM_STOPPED;
1344   stream_.callbackInfo.object = (void *) this;
1345
1346   // Setup the buffer conversion information structure.
1347   if ( stream_.doConvertBuffer[mode] ) {
1348     if ( streamCount > 1 ) setConvertInfo( mode, 0 );
1349     else setConvertInfo( mode, channelOffset );
1350   }
1351
1352   if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] == device )
1353     // Only one callback procedure per device.
1354     stream_.mode = DUPLEX;
1355   else {
1356 #if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
1357     result = AudioDeviceCreateIOProcID( id, callbackHandler, (void *) &stream_.callbackInfo, &handle->procId[mode] );
1358 #else
1359     // deprecated in favor of AudioDeviceCreateIOProcID()
1360     result = AudioDeviceAddIOProc( id, callbackHandler, (void *) &stream_.callbackInfo );
1361 #endif
1362     if ( result != noErr ) {
1363       errorStream_ << "RtApiCore::probeDeviceOpen: system error setting callback for device (" << device << ").";
1364       errorText_ = errorStream_.str();
1365       goto error;
1366     }
1367     if ( stream_.mode == OUTPUT && mode == INPUT )
1368       stream_.mode = DUPLEX;
1369     else
1370       stream_.mode = mode;
1371   }
1372
1373   // Setup the device property listener for over/underload.
1374   property.mSelector = kAudioDeviceProcessorOverload;
1375   property.mScope = kAudioObjectPropertyScopeGlobal;
1376   result = AudioObjectAddPropertyListener( id, &property, xrunListener, (void *) handle );
1377
1378   return SUCCESS;
1379
1380  error:
1381   if ( handle ) {
1382     pthread_cond_destroy( &handle->condition );
1383     delete handle;
1384     stream_.apiHandle = 0;
1385   }
1386
1387   for ( int i=0; i<2; i++ ) {
1388     if ( stream_.userBuffer[i] ) {
1389       free( stream_.userBuffer[i] );
1390       stream_.userBuffer[i] = 0;
1391     }
1392   }
1393
1394   if ( stream_.deviceBuffer ) {
1395     free( stream_.deviceBuffer );
1396     stream_.deviceBuffer = 0;
1397   }
1398
1399   stream_.state = STREAM_CLOSED;
1400   return FAILURE;
1401 }
1402
1403 void RtApiCore :: closeStream( void )
1404 {
1405   if ( stream_.state == STREAM_CLOSED ) {
1406     errorText_ = "RtApiCore::closeStream(): no open stream to close!";
1407     error( RtAudioError::WARNING );
1408     return;
1409   }
1410
1411   CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
1412   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
1413     if (handle) {
1414       AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,
1415         kAudioObjectPropertyScopeGlobal,
1416         kAudioObjectPropertyElementMaster };
1417
1418       property.mSelector = kAudioDeviceProcessorOverload;
1419       property.mScope = kAudioObjectPropertyScopeGlobal;
1420       if (AudioObjectRemovePropertyListener( handle->id[0], &property, xrunListener, (void *) handle ) != noErr) {
1421         errorText_ = "RtApiCore::closeStream(): error removing property listener!";
1422         error( RtAudioError::WARNING );
1423       }
1424     }
1425     if ( stream_.state == STREAM_RUNNING )
1426       AudioDeviceStop( handle->id[0], callbackHandler );
1427 #if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
1428     AudioDeviceDestroyIOProcID( handle->id[0], handle->procId[0] );
1429 #else
1430     // deprecated in favor of AudioDeviceDestroyIOProcID()
1431     AudioDeviceRemoveIOProc( handle->id[0], callbackHandler );
1432 #endif
1433   }
1434
1435   if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {
1436     if (handle) {
1437       AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,
1438         kAudioObjectPropertyScopeGlobal,
1439         kAudioObjectPropertyElementMaster };
1440
1441       property.mSelector = kAudioDeviceProcessorOverload;
1442       property.mScope = kAudioObjectPropertyScopeGlobal;
1443       if (AudioObjectRemovePropertyListener( handle->id[1], &property, xrunListener, (void *) handle ) != noErr) {
1444         errorText_ = "RtApiCore::closeStream(): error removing property listener!";
1445         error( RtAudioError::WARNING );
1446       }
1447     }
1448     if ( stream_.state == STREAM_RUNNING )
1449       AudioDeviceStop( handle->id[1], callbackHandler );
1450 #if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
1451     AudioDeviceDestroyIOProcID( handle->id[1], handle->procId[1] );
1452 #else
1453     // deprecated in favor of AudioDeviceDestroyIOProcID()
1454     AudioDeviceRemoveIOProc( handle->id[1], callbackHandler );
1455 #endif
1456   }
1457
1458   for ( int i=0; i<2; i++ ) {
1459     if ( stream_.userBuffer[i] ) {
1460       free( stream_.userBuffer[i] );
1461       stream_.userBuffer[i] = 0;
1462     }
1463   }
1464
1465   if ( stream_.deviceBuffer ) {
1466     free( stream_.deviceBuffer );
1467     stream_.deviceBuffer = 0;
1468   }
1469
1470   // Destroy pthread condition variable.
1471   pthread_cond_destroy( &handle->condition );
1472   delete handle;
1473   stream_.apiHandle = 0;
1474
1475   stream_.mode = UNINITIALIZED;
1476   stream_.state = STREAM_CLOSED;
1477 }
1478
1479 void RtApiCore :: startStream( void )
1480 {
1481   verifyStream();
1482   if ( stream_.state == STREAM_RUNNING ) {
1483     errorText_ = "RtApiCore::startStream(): the stream is already running!";
1484     error( RtAudioError::WARNING );
1485     return;
1486   }
1487
1488   OSStatus result = noErr;
1489   CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
1490   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
1491
1492     result = AudioDeviceStart( handle->id[0], callbackHandler );
1493     if ( result != noErr ) {
1494       errorStream_ << "RtApiCore::startStream: system error (" << getErrorCode( result ) << ") starting callback procedure on device (" << stream_.device[0] << ").";
1495       errorText_ = errorStream_.str();
1496       goto unlock;
1497     }
1498   }
1499
1500   if ( stream_.mode == INPUT ||
1501        ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {
1502
1503     result = AudioDeviceStart( handle->id[1], callbackHandler );
1504     if ( result != noErr ) {
1505       errorStream_ << "RtApiCore::startStream: system error starting input callback procedure on device (" << stream_.device[1] << ").";
1506       errorText_ = errorStream_.str();
1507       goto unlock;
1508     }
1509   }
1510
1511   handle->drainCounter = 0;
1512   handle->internalDrain = false;
1513   stream_.state = STREAM_RUNNING;
1514
1515  unlock:
1516   if ( result == noErr ) return;
1517   error( RtAudioError::SYSTEM_ERROR );
1518 }
1519
1520 void RtApiCore :: stopStream( void )
1521 {
1522   verifyStream();
1523   if ( stream_.state == STREAM_STOPPED ) {
1524     errorText_ = "RtApiCore::stopStream(): the stream is already stopped!";
1525     error( RtAudioError::WARNING );
1526     return;
1527   }
1528
1529   OSStatus result = noErr;
1530   CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
1531   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
1532
1533     if ( handle->drainCounter == 0 ) {
1534       handle->drainCounter = 2;
1535       pthread_cond_wait( &handle->condition, &stream_.mutex ); // block until signaled
1536     }
1537
1538     result = AudioDeviceStop( handle->id[0], callbackHandler );
1539     if ( result != noErr ) {
1540       errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping callback procedure on device (" << stream_.device[0] << ").";
1541       errorText_ = errorStream_.str();
1542       goto unlock;
1543     }
1544   }
1545
1546   if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {
1547
1548     result = AudioDeviceStop( handle->id[1], callbackHandler );
1549     if ( result != noErr ) {
1550       errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping input callback procedure on device (" << stream_.device[1] << ").";
1551       errorText_ = errorStream_.str();
1552       goto unlock;
1553     }
1554   }
1555
1556   stream_.state = STREAM_STOPPED;
1557
1558  unlock:
1559   if ( result == noErr ) return;
1560   error( RtAudioError::SYSTEM_ERROR );
1561 }
1562
1563 void RtApiCore :: abortStream( void )
1564 {
1565   verifyStream();
1566   if ( stream_.state == STREAM_STOPPED ) {
1567     errorText_ = "RtApiCore::abortStream(): the stream is already stopped!";
1568     error( RtAudioError::WARNING );
1569     return;
1570   }
1571
1572   CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
1573   handle->drainCounter = 2;
1574
1575   stopStream();
1576 }
1577
1578 // This function will be called by a spawned thread when the user
1579 // callback function signals that the stream should be stopped or
1580 // aborted.  It is better to handle it this way because the
1581 // callbackEvent() function probably should return before the AudioDeviceStop()
1582 // function is called.
1583 static void *coreStopStream( void *ptr )
1584 {
1585   CallbackInfo *info = (CallbackInfo *) ptr;
1586   RtApiCore *object = (RtApiCore *) info->object;
1587
1588   object->stopStream();
1589   pthread_exit( NULL );
1590 }
1591
1592 bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,
1593                                  const AudioBufferList *inBufferList,
1594                                  const AudioBufferList *outBufferList )
1595 {
1596   if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;
1597   if ( stream_.state == STREAM_CLOSED ) {
1598     errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";
1599     error( RtAudioError::WARNING );
1600     return FAILURE;
1601   }
1602
1603   CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
1604   CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
1605
1606   // Check if we were draining the stream and signal is finished.
1607   if ( handle->drainCounter > 3 ) {
1608     ThreadHandle threadId;
1609
1610     stream_.state = STREAM_STOPPING;
1611     if ( handle->internalDrain == true )
1612       pthread_create( &threadId, NULL, coreStopStream, info );
1613     else // external call to stopStream()
1614       pthread_cond_signal( &handle->condition );
1615     return SUCCESS;
1616   }
1617
1618   AudioDeviceID outputDevice = handle->id[0];
1619
1620   // Invoke user callback to get fresh output data UNLESS we are
1621   // draining stream or duplex mode AND the input/output devices are
1622   // different AND this function is called for the input device.
1623   if ( handle->drainCounter == 0 && ( stream_.mode != DUPLEX || deviceId == outputDevice ) ) {
1624     RtAudioCallback callback = (RtAudioCallback) info->callback;
1625     double streamTime = getStreamTime();
1626     RtAudioStreamStatus status = 0;
1627     if ( stream_.mode != INPUT && handle->xrun[0] == true ) {
1628       status |= RTAUDIO_OUTPUT_UNDERFLOW;
1629       handle->xrun[0] = false;
1630     }
1631     if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {
1632       status |= RTAUDIO_INPUT_OVERFLOW;
1633       handle->xrun[1] = false;
1634     }
1635
1636     int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],
1637                                   stream_.bufferSize, streamTime, status, info->userData );
1638     if ( cbReturnValue == 2 ) {
1639       stream_.state = STREAM_STOPPING;
1640       handle->drainCounter = 2;
1641       abortStream();
1642       return SUCCESS;
1643     }
1644     else if ( cbReturnValue == 1 ) {
1645       handle->drainCounter = 1;
1646       handle->internalDrain = true;
1647     }
1648   }
1649
1650   if ( stream_.mode == OUTPUT || ( stream_.mode == DUPLEX && deviceId == outputDevice ) ) {
1651
1652     if ( handle->drainCounter > 1 ) { // write zeros to the output stream
1653
1654       if ( handle->nStreams[0] == 1 ) {
1655         memset( outBufferList->mBuffers[handle->iStream[0]].mData,
1656                 0,
1657                 outBufferList->mBuffers[handle->iStream[0]].mDataByteSize );
1658       }
1659       else { // fill multiple streams with zeros
1660         for ( unsigned int i=0; i<handle->nStreams[0]; i++ ) {
1661           memset( outBufferList->mBuffers[handle->iStream[0]+i].mData,
1662                   0,
1663                   outBufferList->mBuffers[handle->iStream[0]+i].mDataByteSize );
1664         }
1665       }
1666     }
1667     else if ( handle->nStreams[0] == 1 ) {
1668       if ( stream_.doConvertBuffer[0] ) { // convert directly to CoreAudio stream buffer
1669         convertBuffer( (char *) outBufferList->mBuffers[handle->iStream[0]].mData,
1670                        stream_.userBuffer[0], stream_.convertInfo[0] );
1671       }
1672       else { // copy from user buffer
1673         memcpy( outBufferList->mBuffers[handle->iStream[0]].mData,
1674                 stream_.userBuffer[0],
1675                 outBufferList->mBuffers[handle->iStream[0]].mDataByteSize );
1676       }
1677     }
1678     else { // fill multiple streams
1679       Float32 *inBuffer = (Float32 *) stream_.userBuffer[0];
1680       if ( stream_.doConvertBuffer[0] ) {
1681         convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] );
1682         inBuffer = (Float32 *) stream_.deviceBuffer;
1683       }
1684
1685       if ( stream_.deviceInterleaved[0] == false ) { // mono mode
1686         UInt32 bufferBytes = outBufferList->mBuffers[handle->iStream[0]].mDataByteSize;
1687         for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {
1688           memcpy( outBufferList->mBuffers[handle->iStream[0]+i].mData,
1689                   (void *)&inBuffer[i*stream_.bufferSize], bufferBytes );
1690         }
1691       }
1692       else { // fill multiple multi-channel streams with interleaved data
1693         UInt32 streamChannels, channelsLeft, inJump, outJump, inOffset;
1694         Float32 *out, *in;
1695
1696         bool inInterleaved = ( stream_.userInterleaved ) ? true : false;
1697         UInt32 inChannels = stream_.nUserChannels[0];
1698         if ( stream_.doConvertBuffer[0] ) {
1699           inInterleaved = true; // device buffer will always be interleaved for nStreams > 1 and not mono mode
1700           inChannels = stream_.nDeviceChannels[0];
1701         }
1702
1703         if ( inInterleaved ) inOffset = 1;
1704         else inOffset = stream_.bufferSize;
1705
1706         channelsLeft = inChannels;
1707         for ( unsigned int i=0; i<handle->nStreams[0]; i++ ) {
1708           in = inBuffer;
1709           out = (Float32 *) outBufferList->mBuffers[handle->iStream[0]+i].mData;
1710           streamChannels = outBufferList->mBuffers[handle->iStream[0]+i].mNumberChannels;
1711
1712           outJump = 0;
1713           // Account for possible channel offset in first stream
1714           if ( i == 0 && stream_.channelOffset[0] > 0 ) {
1715             streamChannels -= stream_.channelOffset[0];
1716             outJump = stream_.channelOffset[0];
1717             out += outJump;
1718           }
1719
1720           // Account for possible unfilled channels at end of the last stream
1721           if ( streamChannels > channelsLeft ) {
1722             outJump = streamChannels - channelsLeft;
1723             streamChannels = channelsLeft;
1724           }
1725
1726           // Determine input buffer offsets and skips
1727           if ( inInterleaved ) {
1728             inJump = inChannels;
1729             in += inChannels - channelsLeft;
1730           }
1731           else {
1732             inJump = 1;
1733             in += (inChannels - channelsLeft) * inOffset;
1734           }
1735
1736           for ( unsigned int i=0; i<stream_.bufferSize; i++ ) {
1737             for ( unsigned int j=0; j<streamChannels; j++ ) {
1738               *out++ = in[j*inOffset];
1739             }
1740             out += outJump;
1741             in += inJump;
1742           }
1743           channelsLeft -= streamChannels;
1744         }
1745       }
1746     }
1747   }
1748
1749   // Don't bother draining input
1750   if ( handle->drainCounter ) {
1751     handle->drainCounter++;
1752     goto unlock;
1753   }
1754
1755   AudioDeviceID inputDevice;
1756   inputDevice = handle->id[1];
1757   if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && deviceId == inputDevice ) ) {
1758
1759     if ( handle->nStreams[1] == 1 ) {
1760       if ( stream_.doConvertBuffer[1] ) { // convert directly from CoreAudio stream buffer
1761         convertBuffer( stream_.userBuffer[1],
1762                        (char *) inBufferList->mBuffers[handle->iStream[1]].mData,
1763                        stream_.convertInfo[1] );
1764       }
1765       else { // copy to user buffer
1766         memcpy( stream_.userBuffer[1],
1767                 inBufferList->mBuffers[handle->iStream[1]].mData,
1768                 inBufferList->mBuffers[handle->iStream[1]].mDataByteSize );
1769       }
1770     }
1771     else { // read from multiple streams
1772       Float32 *outBuffer = (Float32 *) stream_.userBuffer[1];
1773       if ( stream_.doConvertBuffer[1] ) outBuffer = (Float32 *) stream_.deviceBuffer;
1774
1775       if ( stream_.deviceInterleaved[1] == false ) { // mono mode
1776         UInt32 bufferBytes = inBufferList->mBuffers[handle->iStream[1]].mDataByteSize;
1777         for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {
1778           memcpy( (void *)&outBuffer[i*stream_.bufferSize],
1779                   inBufferList->mBuffers[handle->iStream[1]+i].mData, bufferBytes );
1780         }
1781       }
1782       else { // read from multiple multi-channel streams
1783         UInt32 streamChannels, channelsLeft, inJump, outJump, outOffset;
1784         Float32 *out, *in;
1785
1786         bool outInterleaved = ( stream_.userInterleaved ) ? true : false;
1787         UInt32 outChannels = stream_.nUserChannels[1];
1788         if ( stream_.doConvertBuffer[1] ) {
1789           outInterleaved = true; // device buffer will always be interleaved for nStreams > 1 and not mono mode
1790           outChannels = stream_.nDeviceChannels[1];
1791         }
1792
1793         if ( outInterleaved ) outOffset = 1;
1794         else outOffset = stream_.bufferSize;
1795
1796         channelsLeft = outChannels;
1797         for ( unsigned int i=0; i<handle->nStreams[1]; i++ ) {
1798           out = outBuffer;
1799           in = (Float32 *) inBufferList->mBuffers[handle->iStream[1]+i].mData;
1800           streamChannels = inBufferList->mBuffers[handle->iStream[1]+i].mNumberChannels;
1801
1802           inJump = 0;
1803           // Account for possible channel offset in first stream
1804           if ( i == 0 && stream_.channelOffset[1] > 0 ) {
1805             streamChannels -= stream_.channelOffset[1];
1806             inJump = stream_.channelOffset[1];
1807             in += inJump;
1808           }
1809
1810           // Account for possible unread channels at end of the last stream
1811           if ( streamChannels > channelsLeft ) {
1812             inJump = streamChannels - channelsLeft;
1813             streamChannels = channelsLeft;
1814           }
1815
1816           // Determine output buffer offsets and skips
1817           if ( outInterleaved ) {
1818             outJump = outChannels;
1819             out += outChannels - channelsLeft;
1820           }
1821           else {
1822             outJump = 1;
1823             out += (outChannels - channelsLeft) * outOffset;
1824           }
1825
1826           for ( unsigned int i=0; i<stream_.bufferSize; i++ ) {
1827             for ( unsigned int j=0; j<streamChannels; j++ ) {
1828               out[j*outOffset] = *in++;
1829             }
1830             out += outJump;
1831             in += inJump;
1832           }
1833           channelsLeft -= streamChannels;
1834         }
1835       }
1836       
1837       if ( stream_.doConvertBuffer[1] ) { // convert from our internal "device" buffer
1838         convertBuffer( stream_.userBuffer[1],
1839                        stream_.deviceBuffer,
1840                        stream_.convertInfo[1] );
1841       }
1842     }
1843   }
1844
1845  unlock:
1846   //MUTEX_UNLOCK( &stream_.mutex );
1847
1848   RtApi::tickStreamTime();
1849   return SUCCESS;
1850 }
1851
1852 const char* RtApiCore :: getErrorCode( OSStatus code )
1853 {
1854   switch( code ) {
1855
1856   case kAudioHardwareNotRunningError:
1857     return "kAudioHardwareNotRunningError";
1858
1859   case kAudioHardwareUnspecifiedError:
1860     return "kAudioHardwareUnspecifiedError";
1861
1862   case kAudioHardwareUnknownPropertyError:
1863     return "kAudioHardwareUnknownPropertyError";
1864
1865   case kAudioHardwareBadPropertySizeError:
1866     return "kAudioHardwareBadPropertySizeError";
1867
1868   case kAudioHardwareIllegalOperationError:
1869     return "kAudioHardwareIllegalOperationError";
1870
1871   case kAudioHardwareBadObjectError:
1872     return "kAudioHardwareBadObjectError";
1873
1874   case kAudioHardwareBadDeviceError:
1875     return "kAudioHardwareBadDeviceError";
1876
1877   case kAudioHardwareBadStreamError:
1878     return "kAudioHardwareBadStreamError";
1879
1880   case kAudioHardwareUnsupportedOperationError:
1881     return "kAudioHardwareUnsupportedOperationError";
1882
1883   case kAudioDeviceUnsupportedFormatError:
1884     return "kAudioDeviceUnsupportedFormatError";
1885
1886   case kAudioDevicePermissionsError:
1887     return "kAudioDevicePermissionsError";
1888
1889   default:
1890     return "CoreAudio unknown error";
1891   }
1892 }
1893
1894   //******************** End of __MACOSX_CORE__ *********************//
1895 #endif
1896
1897 #if defined(__UNIX_JACK__)
1898
1899 // JACK is a low-latency audio server, originally written for the
1900 // GNU/Linux operating system and now also ported to OS-X. It can
1901 // connect a number of different applications to an audio device, as
1902 // well as allowing them to share audio between themselves.
1903 //
1904 // When using JACK with RtAudio, "devices" refer to JACK clients that
1905 // have ports connected to the server.  The JACK server is typically
1906 // started in a terminal as follows:
1907 //
1908 // .jackd -d alsa -d hw:0
1909 //
1910 // or through an interface program such as qjackctl.  Many of the
1911 // parameters normally set for a stream are fixed by the JACK server
1912 // and can be specified when the JACK server is started.  In
1913 // particular,
1914 //
1915 // .jackd -d alsa -d hw:0 -r 44100 -p 512 -n 4
1916 //
1917 // specifies a sample rate of 44100 Hz, a buffer size of 512 sample
1918 // frames, and number of buffers = 4.  Once the server is running, it
1919 // is not possible to override these values.  If the values are not
1920 // specified in the command-line, the JACK server uses default values.
1921 //
1922 // The JACK server does not have to be running when an instance of
1923 // RtApiJack is created, though the function getDeviceCount() will
1924 // report 0 devices found until JACK has been started.  When no
1925 // devices are available (i.e., the JACK server is not running), a
1926 // stream cannot be opened.
1927
1928 #include <jack/jack.h>
1929 #include <unistd.h>
1930 #include <cstdio>
1931
1932 // A structure to hold various information related to the Jack API
1933 // implementation.
1934 struct JackHandle {
1935   jack_client_t *client;
1936   jack_port_t **ports[2];
1937   std::string deviceName[2];
1938   bool xrun[2];
1939   pthread_cond_t condition;
1940   int drainCounter;       // Tracks callback counts when draining
1941   bool internalDrain;     // Indicates if stop is initiated from callback or not.
1942
1943   JackHandle()
1944     :client(0), drainCounter(0), internalDrain(false) { ports[0] = 0; ports[1] = 0; xrun[0] = false; xrun[1] = false; }
1945 };
1946
1947 #if !defined(__RTAUDIO_DEBUG__)
1948 static void jackSilentError( const char * ) {};
1949 #endif
1950
1951 RtApiJack :: RtApiJack()
1952     :shouldAutoconnect_(true) {
1953   // Nothing to do here.
1954 #if !defined(__RTAUDIO_DEBUG__)
1955   // Turn off Jack's internal error reporting.
1956   jack_set_error_function( &jackSilentError );
1957 #endif
1958 }
1959
1960 RtApiJack :: ~RtApiJack()
1961 {
1962   if ( stream_.state != STREAM_CLOSED ) closeStream();
1963 }
1964
1965 unsigned int RtApiJack :: getDeviceCount( void )
1966 {
1967   // See if we can become a jack client.
1968   jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption;
1969   jack_status_t *status = NULL;
1970   jack_client_t *client = jack_client_open( "RtApiJackCount", options, status );
1971   if ( client == 0 ) return 0;
1972
1973   const char **ports;
1974   std::string port, previousPort;
1975   unsigned int nChannels = 0, nDevices = 0;
1976   ports = jack_get_ports( client, NULL, NULL, 0 );
1977   if ( ports ) {
1978     // Parse the port names up to the first colon (:).
1979     size_t iColon = 0;
1980     do {
1981       port = (char *) ports[ nChannels ];
1982       iColon = port.find(":");
1983       if ( iColon != std::string::npos ) {
1984         port = port.substr( 0, iColon + 1 );
1985         if ( port != previousPort ) {
1986           nDevices++;
1987           previousPort = port;
1988         }
1989       }
1990     } while ( ports[++nChannels] );
1991     free( ports );
1992   }
1993
1994   jack_client_close( client );
1995   return nDevices;
1996 }
1997
1998 RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
1999 {
2000   RtAudio::DeviceInfo info;
2001   info.probed = false;
2002
2003   jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption
2004   jack_status_t *status = NULL;
2005   jack_client_t *client = jack_client_open( "RtApiJackInfo", options, status );
2006   if ( client == 0 ) {
2007     errorText_ = "RtApiJack::getDeviceInfo: Jack server not found or connection error!";
2008     error( RtAudioError::WARNING );
2009     return info;
2010   }
2011
2012   const char **ports;
2013   std::string port, previousPort;
2014   unsigned int nPorts = 0, nDevices = 0;
2015   ports = jack_get_ports( client, NULL, NULL, 0 );
2016   if ( ports ) {
2017     // Parse the port names up to the first colon (:).
2018     size_t iColon = 0;
2019     do {
2020       port = (char *) ports[ nPorts ];
2021       iColon = port.find(":");
2022       if ( iColon != std::string::npos ) {
2023         port = port.substr( 0, iColon );
2024         if ( port != previousPort ) {
2025           if ( nDevices == device ) info.name = port;
2026           nDevices++;
2027           previousPort = port;
2028         }
2029       }
2030     } while ( ports[++nPorts] );
2031     free( ports );
2032   }
2033
2034   if ( device >= nDevices ) {
2035     jack_client_close( client );
2036     errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!";
2037     error( RtAudioError::INVALID_USE );
2038     return info;
2039   }
2040
2041   // Get the current jack server sample rate.
2042   info.sampleRates.clear();
2043
2044   info.preferredSampleRate = jack_get_sample_rate( client );
2045   info.sampleRates.push_back( info.preferredSampleRate );
2046
2047   // Count the available ports containing the client name as device
2048   // channels.  Jack "input ports" equal RtAudio output channels.
2049   unsigned int nChannels = 0;
2050   ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsInput );
2051   if ( ports ) {
2052     while ( ports[ nChannels ] ) nChannels++;
2053     free( ports );
2054     info.outputChannels = nChannels;
2055   }
2056
2057   // Jack "output ports" equal RtAudio input channels.
2058   nChannels = 0;
2059   ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsOutput );
2060   if ( ports ) {
2061     while ( ports[ nChannels ] ) nChannels++;
2062     free( ports );
2063     info.inputChannels = nChannels;
2064   }
2065
2066   if ( info.outputChannels == 0 && info.inputChannels == 0 ) {
2067     jack_client_close(client);
2068     errorText_ = "RtApiJack::getDeviceInfo: error determining Jack input/output channels!";
2069     error( RtAudioError::WARNING );
2070     return info;
2071   }
2072
2073   // If device opens for both playback and capture, we determine the channels.
2074   if ( info.outputChannels > 0 && info.inputChannels > 0 )
2075     info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
2076
2077   // Jack always uses 32-bit floats.
2078   info.nativeFormats = RTAUDIO_FLOAT32;
2079
2080   // Jack doesn't provide default devices so we'll use the first available one.
2081   if ( device == 0 && info.outputChannels > 0 )
2082     info.isDefaultOutput = true;
2083   if ( device == 0 && info.inputChannels > 0 )
2084     info.isDefaultInput = true;
2085
2086   jack_client_close(client);
2087   info.probed = true;
2088   return info;
2089 }
2090
2091 static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )
2092 {
2093   CallbackInfo *info = (CallbackInfo *) infoPointer;
2094
2095   RtApiJack *object = (RtApiJack *) info->object;
2096   if ( object->callbackEvent( (unsigned long) nframes ) == false ) return 1;
2097
2098   return 0;
2099 }
2100
2101 // This function will be called by a spawned thread when the Jack
2102 // server signals that it is shutting down.  It is necessary to handle
2103 // it this way because the jackShutdown() function must return before
2104 // the jack_deactivate() function (in closeStream()) will return.
2105 static void *jackCloseStream( void *ptr )
2106 {
2107   CallbackInfo *info = (CallbackInfo *) ptr;
2108   RtApiJack *object = (RtApiJack *) info->object;
2109
2110   object->closeStream();
2111
2112   pthread_exit( NULL );
2113 }
2114 static void jackShutdown( void *infoPointer )
2115 {
2116   CallbackInfo *info = (CallbackInfo *) infoPointer;
2117   RtApiJack *object = (RtApiJack *) info->object;
2118
2119   // Check current stream state.  If stopped, then we'll assume this
2120   // was called as a result of a call to RtApiJack::stopStream (the
2121   // deactivation of a client handle causes this function to be called).
2122   // If not, we'll assume the Jack server is shutting down or some
2123   // other problem occurred and we should close the stream.
2124   if ( object->isStreamRunning() == false ) return;
2125
2126   ThreadHandle threadId;
2127   pthread_create( &threadId, NULL, jackCloseStream, info );
2128   std::cerr << "\nRtApiJack: the Jack server is shutting down this client ... stream stopped and closed!!\n" << std::endl;
2129 }
2130
2131 static int jackXrun( void *infoPointer )
2132 {
2133   JackHandle *handle = (JackHandle *) infoPointer;
2134
2135   if ( handle->ports[0] ) handle->xrun[0] = true;
2136   if ( handle->ports[1] ) handle->xrun[1] = true;
2137
2138   return 0;
2139 }
2140
2141 bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
2142                                    unsigned int firstChannel, unsigned int sampleRate,
2143                                    RtAudioFormat format, unsigned int *bufferSize,
2144                                    RtAudio::StreamOptions *options )
2145 {
2146   JackHandle *handle = (JackHandle *) stream_.apiHandle;
2147
2148   // Look for jack server and try to become a client (only do once per stream).
2149   jack_client_t *client = 0;
2150   if ( mode == OUTPUT || ( mode == INPUT && stream_.mode != OUTPUT ) ) {
2151     jack_options_t jackoptions = (jack_options_t) ( JackNoStartServer ); //JackNullOption;
2152     jack_status_t *status = NULL;
2153     if ( options && !options->streamName.empty() )
2154       client = jack_client_open( options->streamName.c_str(), jackoptions, status );
2155     else
2156       client = jack_client_open( "RtApiJack", jackoptions, status );
2157     if ( client == 0 ) {
2158       errorText_ = "RtApiJack::probeDeviceOpen: Jack server not found or connection error!";
2159       error( RtAudioError::WARNING );
2160       return FAILURE;
2161     }
2162   }
2163   else {
2164     // The handle must have been created on an earlier pass.
2165     client = handle->client;
2166   }
2167
2168   const char **ports;
2169   std::string port, previousPort, deviceName;
2170   unsigned int nPorts = 0, nDevices = 0;
2171   ports = jack_get_ports( client, NULL, NULL, 0 );
2172   if ( ports ) {
2173     // Parse the port names up to the first colon (:).
2174     size_t iColon = 0;
2175     do {
2176       port = (char *) ports[ nPorts ];
2177       iColon = port.find(":");
2178       if ( iColon != std::string::npos ) {
2179         port = port.substr( 0, iColon );
2180         if ( port != previousPort ) {
2181           if ( nDevices == device ) deviceName = port;
2182           nDevices++;
2183           previousPort = port;
2184         }
2185       }
2186     } while ( ports[++nPorts] );
2187     free( ports );
2188   }
2189
2190   if ( device >= nDevices ) {
2191     errorText_ = "RtApiJack::probeDeviceOpen: device ID is invalid!";
2192     return FAILURE;
2193   }
2194
2195   // Count the available ports containing the client name as device
2196   // channels.  Jack "input ports" equal RtAudio output channels.
2197   unsigned int nChannels = 0;
2198   unsigned long flag = JackPortIsInput;
2199   if ( mode == INPUT ) flag = JackPortIsOutput;
2200   ports = jack_get_ports( client, deviceName.c_str(), NULL, flag );
2201   if ( ports ) {
2202     while ( ports[ nChannels ] ) nChannels++;
2203     free( ports );
2204   }
2205
2206   // Compare the jack ports for specified client to the requested number of channels.
2207   if ( nChannels < (channels + firstChannel) ) {
2208     errorStream_ << "RtApiJack::probeDeviceOpen: requested number of channels (" << channels << ") + offset (" << firstChannel << ") not found for specified device (" << device << ":" << deviceName << ").";
2209     errorText_ = errorStream_.str();
2210     return FAILURE;
2211   }
2212
2213   // Check the jack server sample rate.
2214   unsigned int jackRate = jack_get_sample_rate( client );
2215   if ( sampleRate != jackRate ) {
2216     jack_client_close( client );
2217     errorStream_ << "RtApiJack::probeDeviceOpen: the requested sample rate (" << sampleRate << ") is different than the JACK server rate (" << jackRate << ").";
2218     errorText_ = errorStream_.str();
2219     return FAILURE;
2220   }
2221   stream_.sampleRate = jackRate;
2222
2223   // Get the latency of the JACK port.
2224   ports = jack_get_ports( client, deviceName.c_str(), NULL, flag );
2225   if ( ports[ firstChannel ] ) {
2226     // Added by Ge Wang
2227     jack_latency_callback_mode_t cbmode = (mode == INPUT ? JackCaptureLatency : JackPlaybackLatency);
2228     // the range (usually the min and max are equal)
2229     jack_latency_range_t latrange; latrange.min = latrange.max = 0;
2230     // get the latency range
2231     jack_port_get_latency_range( jack_port_by_name( client, ports[firstChannel] ), cbmode, &latrange );
2232     // be optimistic, use the min!
2233     stream_.latency[mode] = latrange.min;
2234     //stream_.latency[mode] = jack_port_get_latency( jack_port_by_name( client, ports[ firstChannel ] ) );
2235   }
2236   free( ports );
2237
2238   // The jack server always uses 32-bit floating-point data.
2239   stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
2240   stream_.userFormat = format;
2241
2242   if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;
2243   else stream_.userInterleaved = true;
2244
2245   // Jack always uses non-interleaved buffers.
2246   stream_.deviceInterleaved[mode] = false;
2247
2248   // Jack always provides host byte-ordered data.
2249   stream_.doByteSwap[mode] = false;
2250
2251   // Get the buffer size.  The buffer size and number of buffers
2252   // (periods) is set when the jack server is started.
2253   stream_.bufferSize = (int) jack_get_buffer_size( client );
2254   *bufferSize = stream_.bufferSize;
2255
2256   stream_.nDeviceChannels[mode] = channels;
2257   stream_.nUserChannels[mode] = channels;
2258
2259   // Set flags for buffer conversion.
2260   stream_.doConvertBuffer[mode] = false;
2261   if ( stream_.userFormat != stream_.deviceFormat[mode] )
2262     stream_.doConvertBuffer[mode] = true;
2263   if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
2264        stream_.nUserChannels[mode] > 1 )
2265     stream_.doConvertBuffer[mode] = true;
2266
2267   // Allocate our JackHandle structure for the stream.
2268   if ( handle == 0 ) {
2269     try {
2270       handle = new JackHandle;
2271     }
2272     catch ( std::bad_alloc& ) {
2273       errorText_ = "RtApiJack::probeDeviceOpen: error allocating JackHandle memory.";
2274       goto error;
2275     }
2276
2277     if ( pthread_cond_init(&handle->condition, NULL) ) {
2278       errorText_ = "RtApiJack::probeDeviceOpen: error initializing pthread condition variable.";
2279       goto error;
2280     }
2281     stream_.apiHandle = (void *) handle;
2282     handle->client = client;
2283   }
2284   handle->deviceName[mode] = deviceName;
2285
2286   // Allocate necessary internal buffers.
2287   unsigned long bufferBytes;
2288   bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
2289   stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
2290   if ( stream_.userBuffer[mode] == NULL ) {
2291     errorText_ = "RtApiJack::probeDeviceOpen: error allocating user buffer memory.";
2292     goto error;
2293   }
2294
2295   if ( stream_.doConvertBuffer[mode] ) {
2296
2297     bool makeBuffer = true;
2298     if ( mode == OUTPUT )
2299       bufferBytes = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
2300     else { // mode == INPUT
2301       bufferBytes = stream_.nDeviceChannels[1] * formatBytes( stream_.deviceFormat[1] );
2302       if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
2303         unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
2304         if ( bufferBytes < bytesOut ) makeBuffer = false;
2305       }
2306     }
2307
2308     if ( makeBuffer ) {
2309       bufferBytes *= *bufferSize;
2310       if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
2311       stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
2312       if ( stream_.deviceBuffer == NULL ) {
2313         errorText_ = "RtApiJack::probeDeviceOpen: error allocating device buffer memory.";
2314         goto error;
2315       }
2316     }
2317   }
2318
2319   // Allocate memory for the Jack ports (channels) identifiers.
2320   handle->ports[mode] = (jack_port_t **) malloc ( sizeof (jack_port_t *) * channels );
2321   if ( handle->ports[mode] == NULL )  {
2322     errorText_ = "RtApiJack::probeDeviceOpen: error allocating port memory.";
2323     goto error;
2324   }
2325
2326   stream_.device[mode] = device;
2327   stream_.channelOffset[mode] = firstChannel;
2328   stream_.state = STREAM_STOPPED;
2329   stream_.callbackInfo.object = (void *) this;
2330
2331   if ( stream_.mode == OUTPUT && mode == INPUT )
2332     // We had already set up the stream for output.
2333     stream_.mode = DUPLEX;
2334   else {
2335     stream_.mode = mode;
2336     jack_set_process_callback( handle->client, jackCallbackHandler, (void *) &stream_.callbackInfo );
2337     jack_set_xrun_callback( handle->client, jackXrun, (void *) &handle );
2338     jack_on_shutdown( handle->client, jackShutdown, (void *) &stream_.callbackInfo );
2339   }
2340
2341   // Register our ports.
2342   char label[64];
2343   if ( mode == OUTPUT ) {
2344     for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {
2345       snprintf( label, 64, "outport %d", i );
2346       handle->ports[0][i] = jack_port_register( handle->client, (const char *)label,
2347                                                 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
2348     }
2349   }
2350   else {
2351     for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {
2352       snprintf( label, 64, "inport %d", i );
2353       handle->ports[1][i] = jack_port_register( handle->client, (const char *)label,
2354                                                 JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 );
2355     }
2356   }
2357
2358   // Setup the buffer conversion information structure.  We don't use
2359   // buffers to do channel offsets, so we override that parameter
2360   // here.
2361   if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, 0 );
2362
2363   if ( options && options->flags & RTAUDIO_JACK_DONT_CONNECT ) shouldAutoconnect_ = false;
2364
2365   return SUCCESS;
2366
2367  error:
2368   if ( handle ) {
2369     pthread_cond_destroy( &handle->condition );
2370     jack_client_close( handle->client );
2371
2372     if ( handle->ports[0] ) free( handle->ports[0] );
2373     if ( handle->ports[1] ) free( handle->ports[1] );
2374
2375     delete handle;
2376     stream_.apiHandle = 0;
2377   }
2378
2379   for ( int i=0; i<2; i++ ) {
2380     if ( stream_.userBuffer[i] ) {
2381       free( stream_.userBuffer[i] );
2382       stream_.userBuffer[i] = 0;
2383     }
2384   }
2385
2386   if ( stream_.deviceBuffer ) {
2387     free( stream_.deviceBuffer );
2388     stream_.deviceBuffer = 0;
2389   }
2390
2391   return FAILURE;
2392 }
2393
2394 void RtApiJack :: closeStream( void )
2395 {
2396   if ( stream_.state == STREAM_CLOSED ) {
2397     errorText_ = "RtApiJack::closeStream(): no open stream to close!";
2398     error( RtAudioError::WARNING );
2399     return;
2400   }
2401
2402   JackHandle *handle = (JackHandle *) stream_.apiHandle;
2403   if ( handle ) {
2404
2405     if ( stream_.state == STREAM_RUNNING )
2406       jack_deactivate( handle->client );
2407
2408     jack_client_close( handle->client );
2409   }
2410
2411   if ( handle ) {
2412     if ( handle->ports[0] ) free( handle->ports[0] );
2413     if ( handle->ports[1] ) free( handle->ports[1] );
2414     pthread_cond_destroy( &handle->condition );
2415     delete handle;
2416     stream_.apiHandle = 0;
2417   }
2418
2419   for ( int i=0; i<2; i++ ) {
2420     if ( stream_.userBuffer[i] ) {
2421       free( stream_.userBuffer[i] );
2422       stream_.userBuffer[i] = 0;
2423     }
2424   }
2425
2426   if ( stream_.deviceBuffer ) {
2427     free( stream_.deviceBuffer );
2428     stream_.deviceBuffer = 0;
2429   }
2430
2431   stream_.mode = UNINITIALIZED;
2432   stream_.state = STREAM_CLOSED;
2433 }
2434
2435 void RtApiJack :: startStream( void )
2436 {
2437   verifyStream();
2438   if ( stream_.state == STREAM_RUNNING ) {
2439     errorText_ = "RtApiJack::startStream(): the stream is already running!";
2440     error( RtAudioError::WARNING );
2441     return;
2442   }
2443
2444   JackHandle *handle = (JackHandle *) stream_.apiHandle;
2445   int result = jack_activate( handle->client );
2446   if ( result ) {
2447     errorText_ = "RtApiJack::startStream(): unable to activate JACK client!";
2448     goto unlock;
2449   }
2450
2451   const char **ports;
2452
2453   // Get the list of available ports.
2454   if ( shouldAutoconnect_ && (stream_.mode == OUTPUT || stream_.mode == DUPLEX) ) {
2455     result = 1;
2456     ports = jack_get_ports( handle->client, handle->deviceName[0].c_str(), NULL, JackPortIsInput);
2457     if ( ports == NULL) {
2458       errorText_ = "RtApiJack::startStream(): error determining available JACK input ports!";
2459       goto unlock;
2460     }
2461
2462     // Now make the port connections.  Since RtAudio wasn't designed to
2463     // allow the user to select particular channels of a device, we'll
2464     // just open the first "nChannels" ports with offset.
2465     for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {
2466       result = 1;
2467       if ( ports[ stream_.channelOffset[0] + i ] )
2468         result = jack_connect( handle->client, jack_port_name( handle->ports[0][i] ), ports[ stream_.channelOffset[0] + i ] );
2469       if ( result ) {
2470         free( ports );
2471         errorText_ = "RtApiJack::startStream(): error connecting output ports!";
2472         goto unlock;
2473       }
2474     }
2475     free(ports);
2476   }
2477
2478   if ( shouldAutoconnect_ && (stream_.mode == INPUT || stream_.mode == DUPLEX) ) {
2479     result = 1;
2480     ports = jack_get_ports( handle->client, handle->deviceName[1].c_str(), NULL, JackPortIsOutput );
2481     if ( ports == NULL) {
2482       errorText_ = "RtApiJack::startStream(): error determining available JACK output ports!";
2483       goto unlock;
2484     }
2485
2486     // Now make the port connections.  See note above.
2487     for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {
2488       result = 1;
2489       if ( ports[ stream_.channelOffset[1] + i ] )
2490         result = jack_connect( handle->client, ports[ stream_.channelOffset[1] + i ], jack_port_name( handle->ports[1][i] ) );
2491       if ( result ) {
2492         free( ports );
2493         errorText_ = "RtApiJack::startStream(): error connecting input ports!";
2494         goto unlock;
2495       }
2496     }
2497     free(ports);
2498   }
2499
2500   handle->drainCounter = 0;
2501   handle->internalDrain = false;
2502   stream_.state = STREAM_RUNNING;
2503
2504  unlock:
2505   if ( result == 0 ) return;
2506   error( RtAudioError::SYSTEM_ERROR );
2507 }
2508
2509 void RtApiJack :: stopStream( void )
2510 {
2511   verifyStream();
2512   if ( stream_.state == STREAM_STOPPED ) {
2513     errorText_ = "RtApiJack::stopStream(): the stream is already stopped!";
2514     error( RtAudioError::WARNING );
2515     return;
2516   }
2517
2518   JackHandle *handle = (JackHandle *) stream_.apiHandle;
2519   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
2520
2521     if ( handle->drainCounter == 0 ) {
2522       handle->drainCounter = 2;
2523       pthread_cond_wait( &handle->condition, &stream_.mutex ); // block until signaled
2524     }
2525   }
2526
2527   jack_deactivate( handle->client );
2528   stream_.state = STREAM_STOPPED;
2529 }
2530
2531 void RtApiJack :: abortStream( void )
2532 {
2533   verifyStream();
2534   if ( stream_.state == STREAM_STOPPED ) {
2535     errorText_ = "RtApiJack::abortStream(): the stream is already stopped!";
2536     error( RtAudioError::WARNING );
2537     return;
2538   }
2539
2540   JackHandle *handle = (JackHandle *) stream_.apiHandle;
2541   handle->drainCounter = 2;
2542
2543   stopStream();
2544 }
2545
2546 // This function will be called by a spawned thread when the user
2547 // callback function signals that the stream should be stopped or
2548 // aborted.  It is necessary to handle it this way because the
2549 // callbackEvent() function must return before the jack_deactivate()
2550 // function will return.
2551 static void *jackStopStream( void *ptr )
2552 {
2553   CallbackInfo *info = (CallbackInfo *) ptr;
2554   RtApiJack *object = (RtApiJack *) info->object;
2555
2556   object->stopStream();
2557   pthread_exit( NULL );
2558 }
2559
2560 bool RtApiJack :: callbackEvent( unsigned long nframes )
2561 {
2562   if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;
2563   if ( stream_.state == STREAM_CLOSED ) {
2564     errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";
2565     error( RtAudioError::WARNING );
2566     return FAILURE;
2567   }
2568   if ( stream_.bufferSize != nframes ) {
2569     errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size has changed ... cannot process!";
2570     error( RtAudioError::WARNING );
2571     return FAILURE;
2572   }
2573
2574   CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
2575   JackHandle *handle = (JackHandle *) stream_.apiHandle;
2576
2577   // Check if we were draining the stream and signal is finished.
2578   if ( handle->drainCounter > 3 ) {
2579     ThreadHandle threadId;
2580
2581     stream_.state = STREAM_STOPPING;
2582     if ( handle->internalDrain == true )
2583       pthread_create( &threadId, NULL, jackStopStream, info );
2584     else
2585       pthread_cond_signal( &handle->condition );
2586     return SUCCESS;
2587   }
2588
2589   // Invoke user callback first, to get fresh output data.
2590   if ( handle->drainCounter == 0 ) {
2591     RtAudioCallback callback = (RtAudioCallback) info->callback;
2592     double streamTime = getStreamTime();
2593     RtAudioStreamStatus status = 0;
2594     if ( stream_.mode != INPUT && handle->xrun[0] == true ) {
2595       status |= RTAUDIO_OUTPUT_UNDERFLOW;
2596       handle->xrun[0] = false;
2597     }
2598     if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {
2599       status |= RTAUDIO_INPUT_OVERFLOW;
2600       handle->xrun[1] = false;
2601     }
2602     int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],
2603                                   stream_.bufferSize, streamTime, status, info->userData );
2604     if ( cbReturnValue == 2 ) {
2605       stream_.state = STREAM_STOPPING;
2606       handle->drainCounter = 2;
2607       ThreadHandle id;
2608       pthread_create( &id, NULL, jackStopStream, info );
2609       return SUCCESS;
2610     }
2611     else if ( cbReturnValue == 1 ) {
2612       handle->drainCounter = 1;
2613       handle->internalDrain = true;
2614     }
2615   }
2616
2617   jack_default_audio_sample_t *jackbuffer;
2618   unsigned long bufferBytes = nframes * sizeof( jack_default_audio_sample_t );
2619   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
2620
2621     if ( handle->drainCounter > 1 ) { // write zeros to the output stream
2622
2623       for ( unsigned int i=0; i<stream_.nDeviceChannels[0]; i++ ) {
2624         jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );
2625         memset( jackbuffer, 0, bufferBytes );
2626       }
2627
2628     }
2629     else if ( stream_.doConvertBuffer[0] ) {
2630
2631       convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] );
2632
2633       for ( unsigned int i=0; i<stream_.nDeviceChannels[0]; i++ ) {
2634         jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );
2635         memcpy( jackbuffer, &stream_.deviceBuffer[i*bufferBytes], bufferBytes );
2636       }
2637     }
2638     else { // no buffer conversion
2639       for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {
2640         jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );
2641         memcpy( jackbuffer, &stream_.userBuffer[0][i*bufferBytes], bufferBytes );
2642       }
2643     }
2644   }
2645
2646   // Don't bother draining input
2647   if ( handle->drainCounter ) {
2648     handle->drainCounter++;
2649     goto unlock;
2650   }
2651
2652   if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
2653
2654     if ( stream_.doConvertBuffer[1] ) {
2655       for ( unsigned int i=0; i<stream_.nDeviceChannels[1]; i++ ) {
2656         jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[1][i], (jack_nframes_t) nframes );
2657         memcpy( &stream_.deviceBuffer[i*bufferBytes], jackbuffer, bufferBytes );
2658       }
2659       convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
2660     }
2661     else { // no buffer conversion
2662       for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {
2663         jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[1][i], (jack_nframes_t) nframes );
2664         memcpy( &stream_.userBuffer[1][i*bufferBytes], jackbuffer, bufferBytes );
2665       }
2666     }
2667   }
2668
2669  unlock:
2670   RtApi::tickStreamTime();
2671   return SUCCESS;
2672 }
2673   //******************** End of __UNIX_JACK__ *********************//
2674 #endif
2675
2676 #if defined(__WINDOWS_ASIO__) // ASIO API on Windows
2677
2678 // The ASIO API is designed around a callback scheme, so this
2679 // implementation is similar to that used for OS-X CoreAudio and Linux
2680 // Jack.  The primary constraint with ASIO is that it only allows
2681 // access to a single driver at a time.  Thus, it is not possible to
2682 // have more than one simultaneous RtAudio stream.
2683 //
2684 // This implementation also requires a number of external ASIO files
2685 // and a few global variables.  The ASIO callback scheme does not
2686 // allow for the passing of user data, so we must create a global
2687 // pointer to our callbackInfo structure.
2688 //
2689 // On unix systems, we make use of a pthread condition variable.
2690 // Since there is no equivalent in Windows, I hacked something based
2691 // on information found in
2692 // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html.
2693
2694 #include "asiosys.h"
2695 #include "asio.h"
2696 #include "iasiothiscallresolver.h"
2697 #include "asiodrivers.h"
2698 #include <cmath>
2699
2700 static AsioDrivers drivers;
2701 static ASIOCallbacks asioCallbacks;
2702 static ASIODriverInfo driverInfo;
2703 static CallbackInfo *asioCallbackInfo;
2704 static bool asioXRun;
2705
2706 struct AsioHandle {
2707   int drainCounter;       // Tracks callback counts when draining
2708   bool internalDrain;     // Indicates if stop is initiated from callback or not.
2709   ASIOBufferInfo *bufferInfos;
2710   HANDLE condition;
2711
2712   AsioHandle()
2713     :drainCounter(0), internalDrain(false), bufferInfos(0) {}
2714 };
2715
2716 // Function declarations (definitions at end of section)
2717 static const char* getAsioErrorString( ASIOError result );
2718 static void sampleRateChanged( ASIOSampleRate sRate );
2719 static long asioMessages( long selector, long value, void* message, double* opt );
2720
2721 RtApiAsio :: RtApiAsio()
2722 {
2723   // ASIO cannot run on a multi-threaded appartment. You can call
2724   // CoInitialize beforehand, but it must be for appartment threading
2725   // (in which case, CoInitilialize will return S_FALSE here).
2726   coInitialized_ = false;
2727   HRESULT hr = CoInitialize( NULL ); 
2728   if ( FAILED(hr) ) {
2729     errorText_ = "RtApiAsio::ASIO requires a single-threaded appartment. Call CoInitializeEx(0,COINIT_APARTMENTTHREADED)";
2730     error( RtAudioError::WARNING );
2731   }
2732   coInitialized_ = true;
2733
2734   drivers.removeCurrentDriver();
2735   driverInfo.asioVersion = 2;
2736
2737   // See note in DirectSound implementation about GetDesktopWindow().
2738   driverInfo.sysRef = GetForegroundWindow();
2739 }
2740
2741 RtApiAsio :: ~RtApiAsio()
2742 {
2743   if ( stream_.state != STREAM_CLOSED ) closeStream();
2744   if ( coInitialized_ ) CoUninitialize();
2745 }
2746
2747 unsigned int RtApiAsio :: getDeviceCount( void )
2748 {
2749   return (unsigned int) drivers.asioGetNumDev();
2750 }
2751
2752 RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
2753 {
2754   RtAudio::DeviceInfo info;
2755   info.probed = false;
2756
2757   // Get device ID
2758   unsigned int nDevices = getDeviceCount();
2759   if ( nDevices == 0 ) {
2760     errorText_ = "RtApiAsio::getDeviceInfo: no devices found!";
2761     error( RtAudioError::INVALID_USE );
2762     return info;
2763   }
2764
2765   if ( device >= nDevices ) {
2766     errorText_ = "RtApiAsio::getDeviceInfo: device ID is invalid!";
2767     error( RtAudioError::INVALID_USE );
2768     return info;
2769   }
2770
2771   // If a stream is already open, we cannot probe other devices.  Thus, use the saved results.
2772   if ( stream_.state != STREAM_CLOSED ) {
2773     if ( device >= devices_.size() ) {
2774       errorText_ = "RtApiAsio::getDeviceInfo: device ID was not present before stream was opened.";
2775       error( RtAudioError::WARNING );
2776       return info;
2777     }
2778     return devices_[ device ];
2779   }
2780
2781   char driverName[32];
2782   ASIOError result = drivers.asioGetDriverName( (int) device, driverName, 32 );
2783   if ( result != ASE_OK ) {
2784     errorStream_ << "RtApiAsio::getDeviceInfo: unable to get driver name (" << getAsioErrorString( result ) << ").";
2785     errorText_ = errorStream_.str();
2786     error( RtAudioError::WARNING );
2787     return info;
2788   }
2789
2790   info.name = driverName;
2791
2792   if ( !drivers.loadDriver( driverName ) ) {
2793     errorStream_ << "RtApiAsio::getDeviceInfo: unable to load driver (" << driverName << ").";
2794     errorText_ = errorStream_.str();
2795     error( RtAudioError::WARNING );
2796     return info;
2797   }
2798
2799   result = ASIOInit( &driverInfo );
2800   if ( result != ASE_OK ) {
2801     errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") initializing driver (" << driverName << ").";
2802     errorText_ = errorStream_.str();
2803     error( RtAudioError::WARNING );
2804     return info;
2805   }
2806
2807   // Determine the device channel information.
2808   long inputChannels, outputChannels;
2809   result = ASIOGetChannels( &inputChannels, &outputChannels );
2810   if ( result != ASE_OK ) {
2811     drivers.removeCurrentDriver();
2812     errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ").";
2813     errorText_ = errorStream_.str();
2814     error( RtAudioError::WARNING );
2815     return info;
2816   }
2817
2818   info.outputChannels = outputChannels;
2819   info.inputChannels = inputChannels;
2820   if ( info.outputChannels > 0 && info.inputChannels > 0 )
2821     info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
2822
2823   // Determine the supported sample rates.
2824   info.sampleRates.clear();
2825   for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {
2826     result = ASIOCanSampleRate( (ASIOSampleRate) SAMPLE_RATES[i] );
2827     if ( result == ASE_OK ) {
2828       info.sampleRates.push_back( SAMPLE_RATES[i] );
2829
2830       if ( !info.preferredSampleRate || ( SAMPLE_RATES[i] <= 48000 && SAMPLE_RATES[i] > info.preferredSampleRate ) )
2831         info.preferredSampleRate = SAMPLE_RATES[i];
2832     }
2833   }
2834
2835   // Determine supported data types ... just check first channel and assume rest are the same.
2836   ASIOChannelInfo channelInfo;
2837   channelInfo.channel = 0;
2838   channelInfo.isInput = true;
2839   if ( info.inputChannels <= 0 ) channelInfo.isInput = false;
2840   result = ASIOGetChannelInfo( &channelInfo );
2841   if ( result != ASE_OK ) {
2842     drivers.removeCurrentDriver();
2843     errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") getting driver channel info (" << driverName << ").";
2844     errorText_ = errorStream_.str();
2845     error( RtAudioError::WARNING );
2846     return info;
2847   }
2848
2849   info.nativeFormats = 0;
2850   if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB )
2851     info.nativeFormats |= RTAUDIO_SINT16;
2852   else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB )
2853     info.nativeFormats |= RTAUDIO_SINT32;
2854   else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB )
2855     info.nativeFormats |= RTAUDIO_FLOAT32;
2856   else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB )
2857     info.nativeFormats |= RTAUDIO_FLOAT64;
2858   else if ( channelInfo.type == ASIOSTInt24MSB || channelInfo.type == ASIOSTInt24LSB )
2859     info.nativeFormats |= RTAUDIO_SINT24;
2860
2861   if ( info.outputChannels > 0 )
2862     if ( getDefaultOutputDevice() == device ) info.isDefaultOutput = true;
2863   if ( info.inputChannels > 0 )
2864     if ( getDefaultInputDevice() == device ) info.isDefaultInput = true;
2865
2866   info.probed = true;
2867   drivers.removeCurrentDriver();
2868   return info;
2869 }
2870
2871 static void bufferSwitch( long index, ASIOBool /*processNow*/ )
2872 {
2873   RtApiAsio *object = (RtApiAsio *) asioCallbackInfo->object;
2874   object->callbackEvent( index );
2875 }
2876
2877 void RtApiAsio :: saveDeviceInfo( void )
2878 {
2879   devices_.clear();
2880
2881   unsigned int nDevices = getDeviceCount();
2882   devices_.resize( nDevices );
2883   for ( unsigned int i=0; i<nDevices; i++ )
2884     devices_[i] = getDeviceInfo( i );
2885 }
2886
2887 bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
2888                                    unsigned int firstChannel, unsigned int sampleRate,
2889                                    RtAudioFormat format, unsigned int *bufferSize,
2890                                    RtAudio::StreamOptions *options )
2891 {////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2892
2893   bool isDuplexInput =  mode == INPUT && stream_.mode == OUTPUT;
2894
2895   // For ASIO, a duplex stream MUST use the same driver.
2896   if ( isDuplexInput && stream_.device[0] != device ) {
2897     errorText_ = "RtApiAsio::probeDeviceOpen: an ASIO duplex stream must use the same device for input and output!";
2898     return FAILURE;
2899   }
2900
2901   char driverName[32];
2902   ASIOError result = drivers.asioGetDriverName( (int) device, driverName, 32 );
2903   if ( result != ASE_OK ) {
2904     errorStream_ << "RtApiAsio::probeDeviceOpen: unable to get driver name (" << getAsioErrorString( result ) << ").";
2905     errorText_ = errorStream_.str();
2906     return FAILURE;
2907   }
2908
2909   // Only load the driver once for duplex stream.
2910   if ( !isDuplexInput ) {
2911     // The getDeviceInfo() function will not work when a stream is open
2912     // because ASIO does not allow multiple devices to run at the same
2913     // time.  Thus, we'll probe the system before opening a stream and
2914     // save the results for use by getDeviceInfo().
2915     this->saveDeviceInfo();
2916
2917     if ( !drivers.loadDriver( driverName ) ) {
2918       errorStream_ << "RtApiAsio::probeDeviceOpen: unable to load driver (" << driverName << ").";
2919       errorText_ = errorStream_.str();
2920       return FAILURE;
2921     }
2922
2923     result = ASIOInit( &driverInfo );
2924     if ( result != ASE_OK ) {
2925       errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") initializing driver (" << driverName << ").";
2926       errorText_ = errorStream_.str();
2927       return FAILURE;
2928     }
2929   }
2930
2931   // keep them before any "goto error", they are used for error cleanup + goto device boundary checks
2932   bool buffersAllocated = false;
2933   AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
2934   unsigned int nChannels;
2935
2936
2937   // Check the device channel count.
2938   long inputChannels, outputChannels;
2939   result = ASIOGetChannels( &inputChannels, &outputChannels );
2940   if ( result != ASE_OK ) {
2941     errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ").";
2942     errorText_ = errorStream_.str();
2943     goto error;
2944   }
2945
2946   if ( ( mode == OUTPUT && (channels+firstChannel) > (unsigned int) outputChannels) ||
2947        ( mode == INPUT && (channels+firstChannel) > (unsigned int) inputChannels) ) {
2948     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested channel count (" << channels << ") + offset (" << firstChannel << ").";
2949     errorText_ = errorStream_.str();
2950     goto error;
2951   }
2952   stream_.nDeviceChannels[mode] = channels;
2953   stream_.nUserChannels[mode] = channels;
2954   stream_.channelOffset[mode] = firstChannel;
2955
2956   // Verify the sample rate is supported.
2957   result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate );
2958   if ( result != ASE_OK ) {
2959     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested sample rate (" << sampleRate << ").";
2960     errorText_ = errorStream_.str();
2961     goto error;
2962   }
2963
2964   // Get the current sample rate
2965   ASIOSampleRate currentRate;
2966   result = ASIOGetSampleRate( &currentRate );
2967   if ( result != ASE_OK ) {
2968     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error getting sample rate.";
2969     errorText_ = errorStream_.str();
2970     goto error;
2971   }
2972
2973   // Set the sample rate only if necessary
2974   if ( currentRate != sampleRate ) {
2975     result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );
2976     if ( result != ASE_OK ) {
2977       errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error setting sample rate (" << sampleRate << ").";
2978       errorText_ = errorStream_.str();
2979       goto error;
2980     }
2981   }
2982
2983   // Determine the driver data type.
2984   ASIOChannelInfo channelInfo;
2985   channelInfo.channel = 0;
2986   if ( mode == OUTPUT ) channelInfo.isInput = false;
2987   else channelInfo.isInput = true;
2988   result = ASIOGetChannelInfo( &channelInfo );
2989   if ( result != ASE_OK ) {
2990     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting data format.";
2991     errorText_ = errorStream_.str();
2992     goto error;
2993   }
2994
2995   // Assuming WINDOWS host is always little-endian.
2996   stream_.doByteSwap[mode] = false;
2997   stream_.userFormat = format;
2998   stream_.deviceFormat[mode] = 0;
2999   if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB ) {
3000     stream_.deviceFormat[mode] = RTAUDIO_SINT16;
3001     if ( channelInfo.type == ASIOSTInt16MSB ) stream_.doByteSwap[mode] = true;
3002   }
3003   else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB ) {
3004     stream_.deviceFormat[mode] = RTAUDIO_SINT32;
3005     if ( channelInfo.type == ASIOSTInt32MSB ) stream_.doByteSwap[mode] = true;
3006   }
3007   else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB ) {
3008     stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
3009     if ( channelInfo.type == ASIOSTFloat32MSB ) stream_.doByteSwap[mode] = true;
3010   }
3011   else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB ) {
3012     stream_.deviceFormat[mode] = RTAUDIO_FLOAT64;
3013     if ( channelInfo.type == ASIOSTFloat64MSB ) stream_.doByteSwap[mode] = true;
3014   }
3015   else if ( channelInfo.type == ASIOSTInt24MSB || channelInfo.type == ASIOSTInt24LSB ) {
3016     stream_.deviceFormat[mode] = RTAUDIO_SINT24;
3017     if ( channelInfo.type == ASIOSTInt24MSB ) stream_.doByteSwap[mode] = true;
3018   }
3019
3020   if ( stream_.deviceFormat[mode] == 0 ) {
3021     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") data format not supported by RtAudio.";
3022     errorText_ = errorStream_.str();
3023     goto error;
3024   }
3025
3026   // Set the buffer size.  For a duplex stream, this will end up
3027   // setting the buffer size based on the input constraints, which
3028   // should be ok.
3029   long minSize, maxSize, preferSize, granularity;
3030   result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity );
3031   if ( result != ASE_OK ) {
3032     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting buffer size.";
3033     errorText_ = errorStream_.str();
3034     goto error;
3035   }
3036
3037   if ( isDuplexInput ) {
3038     // When this is the duplex input (output was opened before), then we have to use the same
3039     // buffersize as the output, because it might use the preferred buffer size, which most
3040     // likely wasn't passed as input to this. The buffer sizes have to be identically anyway,
3041     // So instead of throwing an error, make them equal. The caller uses the reference
3042     // to the "bufferSize" param as usual to set up processing buffers.
3043
3044     *bufferSize = stream_.bufferSize;
3045
3046   } else {
3047     if ( *bufferSize == 0 ) *bufferSize = preferSize;
3048     else if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;
3049     else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;
3050     else if ( granularity == -1 ) {
3051       // Make sure bufferSize is a power of two.
3052       int log2_of_min_size = 0;
3053       int log2_of_max_size = 0;
3054
3055       for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) {
3056         if ( minSize & ((long)1 << i) ) log2_of_min_size = i;
3057         if ( maxSize & ((long)1 << i) ) log2_of_max_size = i;
3058       }
3059
3060       long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) );
3061       int min_delta_num = log2_of_min_size;
3062
3063       for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) {
3064         long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) );
3065         if (current_delta < min_delta) {
3066           min_delta = current_delta;
3067           min_delta_num = i;
3068         }
3069       }
3070
3071       *bufferSize = ( (unsigned int)1 << min_delta_num );
3072       if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;
3073       else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;
3074     }
3075     else if ( granularity != 0 ) {
3076       // Set to an even multiple of granularity, rounding up.
3077       *bufferSize = (*bufferSize + granularity-1) / granularity * granularity;
3078     }
3079   }
3080
3081   /*
3082   // we don't use it anymore, see above!
3083   // Just left it here for the case...
3084   if ( isDuplexInput && stream_.bufferSize != *bufferSize ) {
3085     errorText_ = "RtApiAsio::probeDeviceOpen: input/output buffersize discrepancy!";
3086     goto error;
3087   }
3088   */
3089
3090   stream_.bufferSize = *bufferSize;
3091   stream_.nBuffers = 2;
3092
3093   if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;
3094   else stream_.userInterleaved = true;
3095
3096   // ASIO always uses non-interleaved buffers.
3097   stream_.deviceInterleaved[mode] = false;
3098
3099   // Allocate, if necessary, our AsioHandle structure for the stream.
3100   if ( handle == 0 ) {
3101     try {
3102       handle = new AsioHandle;
3103     }
3104     catch ( std::bad_alloc& ) {
3105       errorText_ = "RtApiAsio::probeDeviceOpen: error allocating AsioHandle memory.";
3106       goto error;
3107     }
3108     handle->bufferInfos = 0;
3109
3110     // Create a manual-reset event.
3111     handle->condition = CreateEvent( NULL,   // no security
3112                                      TRUE,   // manual-reset
3113                                      FALSE,  // non-signaled initially
3114                                      NULL ); // unnamed
3115     stream_.apiHandle = (void *) handle;
3116   }
3117
3118   // Create the ASIO internal buffers.  Since RtAudio sets up input
3119   // and output separately, we'll have to dispose of previously
3120   // created output buffers for a duplex stream.
3121   if ( mode == INPUT && stream_.mode == OUTPUT ) {
3122     ASIODisposeBuffers();
3123     if ( handle->bufferInfos ) free( handle->bufferInfos );
3124   }
3125
3126   // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure.
3127   unsigned int i;
3128   nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];
3129   handle->bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) );
3130   if ( handle->bufferInfos == NULL ) {
3131     errorStream_ << "RtApiAsio::probeDeviceOpen: error allocating bufferInfo memory for driver (" << driverName << ").";
3132     errorText_ = errorStream_.str();
3133     goto error;
3134   }
3135
3136   ASIOBufferInfo *infos;
3137   infos = handle->bufferInfos;
3138   for ( i=0; i<stream_.nDeviceChannels[0]; i++, infos++ ) {
3139     infos->isInput = ASIOFalse;
3140     infos->channelNum = i + stream_.channelOffset[0];
3141     infos->buffers[0] = infos->buffers[1] = 0;
3142   }
3143   for ( i=0; i<stream_.nDeviceChannels[1]; i++, infos++ ) {
3144     infos->isInput = ASIOTrue;
3145     infos->channelNum = i + stream_.channelOffset[1];
3146     infos->buffers[0] = infos->buffers[1] = 0;
3147   }
3148
3149   // prepare for callbacks
3150   stream_.sampleRate = sampleRate;
3151   stream_.device[mode] = device;
3152   stream_.mode = isDuplexInput ? DUPLEX : mode;
3153
3154   // store this class instance before registering callbacks, that are going to use it
3155   asioCallbackInfo = &stream_.callbackInfo;
3156   stream_.callbackInfo.object = (void *) this;
3157
3158   // Set up the ASIO callback structure and create the ASIO data buffers.
3159   asioCallbacks.bufferSwitch = &bufferSwitch;
3160   asioCallbacks.sampleRateDidChange = &sampleRateChanged;
3161   asioCallbacks.asioMessage = &asioMessages;
3162   asioCallbacks.bufferSwitchTimeInfo = NULL;
3163   result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks );
3164   if ( result != ASE_OK ) {
3165     // Standard method failed. This can happen with strict/misbehaving drivers that return valid buffer size ranges
3166     // but only accept the preferred buffer size as parameter for ASIOCreateBuffers. eg. Creatives ASIO driver
3167     // in that case, let's be naïve and try that instead
3168     *bufferSize = preferSize;
3169     stream_.bufferSize = *bufferSize;
3170     result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks );
3171   }
3172
3173   if ( result != ASE_OK ) {
3174     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") creating buffers.";
3175     errorText_ = errorStream_.str();
3176     goto error;
3177   }
3178   buffersAllocated = true;  
3179   stream_.state = STREAM_STOPPED;
3180
3181   // Set flags for buffer conversion.
3182   stream_.doConvertBuffer[mode] = false;
3183   if ( stream_.userFormat != stream_.deviceFormat[mode] )
3184     stream_.doConvertBuffer[mode] = true;
3185   if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
3186        stream_.nUserChannels[mode] > 1 )
3187     stream_.doConvertBuffer[mode] = true;
3188
3189   // Allocate necessary internal buffers
3190   unsigned long bufferBytes;
3191   bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
3192   stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
3193   if ( stream_.userBuffer[mode] == NULL ) {
3194     errorText_ = "RtApiAsio::probeDeviceOpen: error allocating user buffer memory.";
3195     goto error;
3196   }
3197
3198   if ( stream_.doConvertBuffer[mode] ) {
3199
3200     bool makeBuffer = true;
3201     bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
3202     if ( isDuplexInput && stream_.deviceBuffer ) {
3203       unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
3204       if ( bufferBytes <= bytesOut ) makeBuffer = false;
3205     }
3206
3207     if ( makeBuffer ) {
3208       bufferBytes *= *bufferSize;
3209       if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
3210       stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
3211       if ( stream_.deviceBuffer == NULL ) {
3212         errorText_ = "RtApiAsio::probeDeviceOpen: error allocating device buffer memory.";
3213         goto error;
3214       }
3215     }
3216   }
3217
3218   // Determine device latencies
3219   long inputLatency, outputLatency;
3220   result = ASIOGetLatencies( &inputLatency, &outputLatency );
3221   if ( result != ASE_OK ) {
3222     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting latency.";
3223     errorText_ = errorStream_.str();
3224     error( RtAudioError::WARNING); // warn but don't fail
3225   }
3226   else {
3227     stream_.latency[0] = outputLatency;
3228     stream_.latency[1] = inputLatency;
3229   }
3230
3231   // Setup the buffer conversion information structure.  We don't use
3232   // buffers to do channel offsets, so we override that parameter
3233   // here.
3234   if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, 0 );
3235
3236   return SUCCESS;
3237
3238  error:
3239   if ( !isDuplexInput ) {
3240     // the cleanup for error in the duplex input, is done by RtApi::openStream
3241     // So we clean up for single channel only
3242
3243     if ( buffersAllocated )
3244       ASIODisposeBuffers();
3245
3246     drivers.removeCurrentDriver();
3247
3248     if ( handle ) {
3249       CloseHandle( handle->condition );
3250       if ( handle->bufferInfos )
3251         free( handle->bufferInfos );
3252
3253       delete handle;
3254       stream_.apiHandle = 0;
3255     }
3256
3257
3258     if ( stream_.userBuffer[mode] ) {
3259       free( stream_.userBuffer[mode] );
3260       stream_.userBuffer[mode] = 0;
3261     }
3262
3263     if ( stream_.deviceBuffer ) {
3264       free( stream_.deviceBuffer );
3265       stream_.deviceBuffer = 0;
3266     }
3267   }
3268
3269   return FAILURE;
3270 }////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3271
3272 void RtApiAsio :: closeStream()
3273 {
3274   if ( stream_.state == STREAM_CLOSED ) {
3275     errorText_ = "RtApiAsio::closeStream(): no open stream to close!";
3276     error( RtAudioError::WARNING );
3277     return;
3278   }
3279
3280   if ( stream_.state == STREAM_RUNNING ) {
3281     stream_.state = STREAM_STOPPED;
3282     ASIOStop();
3283   }
3284   ASIODisposeBuffers();
3285   drivers.removeCurrentDriver();
3286
3287   AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
3288   if ( handle ) {
3289     CloseHandle( handle->condition );
3290     if ( handle->bufferInfos )
3291       free( handle->bufferInfos );
3292     delete handle;
3293     stream_.apiHandle = 0;
3294   }
3295
3296   for ( int i=0; i<2; i++ ) {
3297     if ( stream_.userBuffer[i] ) {
3298       free( stream_.userBuffer[i] );
3299       stream_.userBuffer[i] = 0;
3300     }
3301   }
3302
3303   if ( stream_.deviceBuffer ) {
3304     free( stream_.deviceBuffer );
3305     stream_.deviceBuffer = 0;
3306   }
3307
3308   stream_.mode = UNINITIALIZED;
3309   stream_.state = STREAM_CLOSED;
3310 }
3311
3312 bool stopThreadCalled = false;
3313
3314 void RtApiAsio :: startStream()
3315 {
3316   verifyStream();
3317   if ( stream_.state == STREAM_RUNNING ) {
3318     errorText_ = "RtApiAsio::startStream(): the stream is already running!";
3319     error( RtAudioError::WARNING );
3320     return;
3321   }
3322
3323   AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
3324   ASIOError result = ASIOStart();
3325   if ( result != ASE_OK ) {
3326     errorStream_ << "RtApiAsio::startStream: error (" << getAsioErrorString( result ) << ") starting device.";
3327     errorText_ = errorStream_.str();
3328     goto unlock;
3329   }
3330
3331   handle->drainCounter = 0;
3332   handle->internalDrain = false;
3333   ResetEvent( handle->condition );
3334   stream_.state = STREAM_RUNNING;
3335   asioXRun = false;
3336
3337  unlock:
3338   stopThreadCalled = false;
3339
3340   if ( result == ASE_OK ) return;
3341   error( RtAudioError::SYSTEM_ERROR );
3342 }
3343
3344 void RtApiAsio :: stopStream()
3345 {
3346   verifyStream();
3347   if ( stream_.state == STREAM_STOPPED ) {
3348     errorText_ = "RtApiAsio::stopStream(): the stream is already stopped!";
3349     error( RtAudioError::WARNING );
3350     return;
3351   }
3352
3353   AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
3354   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
3355     if ( handle->drainCounter == 0 ) {
3356       handle->drainCounter = 2;
3357       WaitForSingleObject( handle->condition, INFINITE );  // block until signaled
3358     }
3359   }
3360
3361   stream_.state = STREAM_STOPPED;
3362
3363   ASIOError result = ASIOStop();
3364   if ( result != ASE_OK ) {
3365     errorStream_ << "RtApiAsio::stopStream: error (" << getAsioErrorString( result ) << ") stopping device.";
3366     errorText_ = errorStream_.str();
3367   }
3368
3369   if ( result == ASE_OK ) return;
3370   error( RtAudioError::SYSTEM_ERROR );
3371 }
3372
3373 void RtApiAsio :: abortStream()
3374 {
3375   verifyStream();
3376   if ( stream_.state == STREAM_STOPPED ) {
3377     errorText_ = "RtApiAsio::abortStream(): the stream is already stopped!";
3378     error( RtAudioError::WARNING );
3379     return;
3380   }
3381
3382   // The following lines were commented-out because some behavior was
3383   // noted where the device buffers need to be zeroed to avoid
3384   // continuing sound, even when the device buffers are completely
3385   // disposed.  So now, calling abort is the same as calling stop.
3386   // AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
3387   // handle->drainCounter = 2;
3388   stopStream();
3389 }
3390
3391 // This function will be called by a spawned thread when the user
3392 // callback function signals that the stream should be stopped or
3393 // aborted.  It is necessary to handle it this way because the
3394 // callbackEvent() function must return before the ASIOStop()
3395 // function will return.
3396 static unsigned __stdcall asioStopStream( void *ptr )
3397 {
3398   CallbackInfo *info = (CallbackInfo *) ptr;
3399   RtApiAsio *object = (RtApiAsio *) info->object;
3400
3401   object->stopStream();
3402   _endthreadex( 0 );
3403   return 0;
3404 }
3405
3406 bool RtApiAsio :: callbackEvent( long bufferIndex )
3407 {
3408   if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;
3409   if ( stream_.state == STREAM_CLOSED ) {
3410     errorText_ = "RtApiAsio::callbackEvent(): the stream is closed ... this shouldn't happen!";
3411     error( RtAudioError::WARNING );
3412     return FAILURE;
3413   }
3414
3415   CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
3416   AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
3417
3418   // Check if we were draining the stream and signal if finished.
3419   if ( handle->drainCounter > 3 ) {
3420
3421     stream_.state = STREAM_STOPPING;
3422     if ( handle->internalDrain == false )
3423       SetEvent( handle->condition );
3424     else { // spawn a thread to stop the stream
3425       unsigned threadId;
3426       stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &asioStopStream,
3427                                                     &stream_.callbackInfo, 0, &threadId );
3428     }
3429     return SUCCESS;
3430   }
3431
3432   // Invoke user callback to get fresh output data UNLESS we are
3433   // draining stream.
3434   if ( handle->drainCounter == 0 ) {
3435     RtAudioCallback callback = (RtAudioCallback) info->callback;
3436     double streamTime = getStreamTime();
3437     RtAudioStreamStatus status = 0;
3438     if ( stream_.mode != INPUT && asioXRun == true ) {
3439       status |= RTAUDIO_OUTPUT_UNDERFLOW;
3440       asioXRun = false;
3441     }
3442     if ( stream_.mode != OUTPUT && asioXRun == true ) {
3443       status |= RTAUDIO_INPUT_OVERFLOW;
3444       asioXRun = false;
3445     }
3446     int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],
3447                                      stream_.bufferSize, streamTime, status, info->userData );
3448     if ( cbReturnValue == 2 ) {
3449       stream_.state = STREAM_STOPPING;
3450       handle->drainCounter = 2;
3451       unsigned threadId;
3452       stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &asioStopStream,
3453                                                     &stream_.callbackInfo, 0, &threadId );
3454       return SUCCESS;
3455     }
3456     else if ( cbReturnValue == 1 ) {
3457       handle->drainCounter = 1;
3458       handle->internalDrain = true;
3459     }
3460   }
3461
3462   unsigned int nChannels, bufferBytes, i, j;
3463   nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];
3464   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
3465
3466     bufferBytes = stream_.bufferSize * formatBytes( stream_.deviceFormat[0] );
3467
3468     if ( handle->drainCounter > 1 ) { // write zeros to the output stream
3469
3470       for ( i=0, j=0; i<nChannels; i++ ) {
3471         if ( handle->bufferInfos[i].isInput != ASIOTrue )
3472           memset( handle->bufferInfos[i].buffers[bufferIndex], 0, bufferBytes );
3473       }
3474
3475     }
3476     else if ( stream_.doConvertBuffer[0] ) {
3477
3478       convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] );
3479       if ( stream_.doByteSwap[0] )
3480         byteSwapBuffer( stream_.deviceBuffer,
3481                         stream_.bufferSize * stream_.nDeviceChannels[0],
3482                         stream_.deviceFormat[0] );
3483
3484       for ( i=0, j=0; i<nChannels; i++ ) {
3485         if ( handle->bufferInfos[i].isInput != ASIOTrue )
3486           memcpy( handle->bufferInfos[i].buffers[bufferIndex],
3487                   &stream_.deviceBuffer[j++*bufferBytes], bufferBytes );
3488       }
3489
3490     }
3491     else {
3492
3493       if ( stream_.doByteSwap[0] )
3494         byteSwapBuffer( stream_.userBuffer[0],
3495                         stream_.bufferSize * stream_.nUserChannels[0],
3496                         stream_.userFormat );
3497
3498       for ( i=0, j=0; i<nChannels; i++ ) {
3499         if ( handle->bufferInfos[i].isInput != ASIOTrue )
3500           memcpy( handle->bufferInfos[i].buffers[bufferIndex],
3501                   &stream_.userBuffer[0][bufferBytes*j++], bufferBytes );
3502       }
3503
3504     }
3505   }
3506
3507   // Don't bother draining input
3508   if ( handle->drainCounter ) {
3509     handle->drainCounter++;
3510     goto unlock;
3511   }
3512
3513   if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
3514
3515     bufferBytes = stream_.bufferSize * formatBytes(stream_.deviceFormat[1]);
3516
3517     if (stream_.doConvertBuffer[1]) {
3518
3519       // Always interleave ASIO input data.
3520       for ( i=0, j=0; i<nChannels; i++ ) {
3521         if ( handle->bufferInfos[i].isInput == ASIOTrue )
3522           memcpy( &stream_.deviceBuffer[j++*bufferBytes],
3523                   handle->bufferInfos[i].buffers[bufferIndex],
3524                   bufferBytes );
3525       }
3526
3527       if ( stream_.doByteSwap[1] )
3528         byteSwapBuffer( stream_.deviceBuffer,
3529                         stream_.bufferSize * stream_.nDeviceChannels[1],
3530                         stream_.deviceFormat[1] );
3531       convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
3532
3533     }
3534     else {
3535       for ( i=0, j=0; i<nChannels; i++ ) {
3536         if ( handle->bufferInfos[i].isInput == ASIOTrue ) {
3537           memcpy( &stream_.userBuffer[1][bufferBytes*j++],
3538                   handle->bufferInfos[i].buffers[bufferIndex],
3539                   bufferBytes );
3540         }
3541       }
3542
3543       if ( stream_.doByteSwap[1] )
3544         byteSwapBuffer( stream_.userBuffer[1],
3545                         stream_.bufferSize * stream_.nUserChannels[1],
3546                         stream_.userFormat );
3547     }
3548   }
3549
3550  unlock:
3551   // The following call was suggested by Malte Clasen.  While the API
3552   // documentation indicates it should not be required, some device
3553   // drivers apparently do not function correctly without it.
3554   ASIOOutputReady();
3555
3556   RtApi::tickStreamTime();
3557   return SUCCESS;
3558 }
3559
3560 static void sampleRateChanged( ASIOSampleRate sRate )
3561 {
3562   // The ASIO documentation says that this usually only happens during
3563   // external sync.  Audio processing is not stopped by the driver,
3564   // actual sample rate might not have even changed, maybe only the
3565   // sample rate status of an AES/EBU or S/PDIF digital input at the
3566   // audio device.
3567
3568   RtApi *object = (RtApi *) asioCallbackInfo->object;
3569   try {
3570     object->stopStream();
3571   }
3572   catch ( RtAudioError &exception ) {
3573     std::cerr << "\nRtApiAsio: sampleRateChanged() error (" << exception.getMessage() << ")!\n" << std::endl;
3574     return;
3575   }
3576
3577   std::cerr << "\nRtApiAsio: driver reports sample rate changed to " << sRate << " ... stream stopped!!!\n" << std::endl;
3578 }
3579
3580 static long asioMessages( long selector, long value, void* /*message*/, double* /*opt*/ )
3581 {
3582   long ret = 0;
3583
3584   switch( selector ) {
3585   case kAsioSelectorSupported:
3586     if ( value == kAsioResetRequest
3587          || value == kAsioEngineVersion
3588          || value == kAsioResyncRequest
3589          || value == kAsioLatenciesChanged
3590          // The following three were added for ASIO 2.0, you don't
3591          // necessarily have to support them.
3592          || value == kAsioSupportsTimeInfo
3593          || value == kAsioSupportsTimeCode
3594          || value == kAsioSupportsInputMonitor)
3595       ret = 1L;
3596     break;
3597   case kAsioResetRequest:
3598     // Defer the task and perform the reset of the driver during the
3599     // next "safe" situation.  You cannot reset the driver right now,
3600     // as this code is called from the driver.  Reset the driver is
3601     // done by completely destruct is. I.e. ASIOStop(),
3602     // ASIODisposeBuffers(), Destruction Afterwards you initialize the
3603     // driver again.
3604     std::cerr << "\nRtApiAsio: driver reset requested!!!" << std::endl;
3605     ret = 1L;
3606     break;
3607   case kAsioResyncRequest:
3608     // This informs the application that the driver encountered some
3609     // non-fatal data loss.  It is used for synchronization purposes
3610     // of different media.  Added mainly to work around the Win16Mutex
3611     // problems in Windows 95/98 with the Windows Multimedia system,
3612     // which could lose data because the Mutex was held too long by
3613     // another thread.  However a driver can issue it in other
3614     // situations, too.
3615     // std::cerr << "\nRtApiAsio: driver resync requested!!!" << std::endl;
3616     asioXRun = true;
3617     ret = 1L;
3618     break;
3619   case kAsioLatenciesChanged:
3620     // This will inform the host application that the drivers were
3621     // latencies changed.  Beware, it this does not mean that the
3622     // buffer sizes have changed!  You might need to update internal
3623     // delay data.
3624     std::cerr << "\nRtApiAsio: driver latency may have changed!!!" << std::endl;
3625     ret = 1L;
3626     break;
3627   case kAsioEngineVersion:
3628     // Return the supported ASIO version of the host application.  If
3629     // a host application does not implement this selector, ASIO 1.0
3630     // is assumed by the driver.
3631     ret = 2L;
3632     break;
3633   case kAsioSupportsTimeInfo:
3634     // Informs the driver whether the
3635     // asioCallbacks.bufferSwitchTimeInfo() callback is supported.
3636     // For compatibility with ASIO 1.0 drivers the host application
3637     // should always support the "old" bufferSwitch method, too.
3638     ret = 0;
3639     break;
3640   case kAsioSupportsTimeCode:
3641     // Informs the driver whether application is interested in time
3642     // code info.  If an application does not need to know about time
3643     // code, the driver has less work to do.
3644     ret = 0;
3645     break;
3646   }
3647   return ret;
3648 }
3649
3650 static const char* getAsioErrorString( ASIOError result )
3651 {
3652   struct Messages 
3653   {
3654     ASIOError value;
3655     const char*message;
3656   };
3657
3658   static const Messages m[] = 
3659     {
3660       {   ASE_NotPresent,    "Hardware input or output is not present or available." },
3661       {   ASE_HWMalfunction,  "Hardware is malfunctioning." },
3662       {   ASE_InvalidParameter, "Invalid input parameter." },
3663       {   ASE_InvalidMode,      "Invalid mode." },
3664       {   ASE_SPNotAdvancing,     "Sample position not advancing." },
3665       {   ASE_NoClock,            "Sample clock or rate cannot be determined or is not present." },
3666       {   ASE_NoMemory,           "Not enough memory to complete the request." }
3667     };
3668
3669   for ( unsigned int i = 0; i < sizeof(m)/sizeof(m[0]); ++i )
3670     if ( m[i].value == result ) return m[i].message;
3671
3672   return "Unknown error.";
3673 }
3674
3675 //******************** End of __WINDOWS_ASIO__ *********************//
3676 #endif
3677
3678
3679 #if defined(__WINDOWS_WASAPI__) // Windows WASAPI API
3680
3681 // Authored by Marcus Tomlinson <themarcustomlinson@gmail.com>, April 2014
3682 // - Introduces support for the Windows WASAPI API
3683 // - Aims to deliver bit streams to and from hardware at the lowest possible latency, via the absolute minimum buffer sizes required
3684 // - Provides flexible stream configuration to an otherwise strict and inflexible WASAPI interface
3685 // - Includes automatic internal conversion of sample rate and buffer size between hardware and the user
3686
3687 #ifndef INITGUID
3688   #define INITGUID
3689 #endif
3690 #include <audioclient.h>
3691 #include <avrt.h>
3692 #include <mmdeviceapi.h>
3693 #include <functiondiscoverykeys_devpkey.h>
3694
3695 //=============================================================================
3696
3697 #define SAFE_RELEASE( objectPtr )\
3698 if ( objectPtr )\
3699 {\
3700   objectPtr->Release();\
3701   objectPtr = NULL;\
3702 }
3703
3704 typedef HANDLE ( __stdcall *TAvSetMmThreadCharacteristicsPtr )( LPCWSTR TaskName, LPDWORD TaskIndex );
3705
3706 //-----------------------------------------------------------------------------
3707
3708 // WASAPI dictates stream sample rate, format, channel count, and in some cases, buffer size.
3709 // Therefore we must perform all necessary conversions to user buffers in order to satisfy these
3710 // requirements. WasapiBuffer ring buffers are used between HwIn->UserIn and UserOut->HwOut to
3711 // provide intermediate storage for read / write synchronization.
3712 class WasapiBuffer
3713 {
3714 public:
3715   WasapiBuffer()
3716     : buffer_( NULL ),
3717       bufferSize_( 0 ),
3718       inIndex_( 0 ),
3719       outIndex_( 0 ) {}
3720
3721   ~WasapiBuffer() {
3722     free( buffer_ );
3723   }
3724
3725   // sets the length of the internal ring buffer
3726   void setBufferSize( unsigned int bufferSize, unsigned int formatBytes ) {
3727     free( buffer_ );
3728
3729     buffer_ = ( char* ) calloc( bufferSize, formatBytes );
3730
3731     bufferSize_ = bufferSize;
3732     inIndex_ = 0;
3733     outIndex_ = 0;
3734   }
3735
3736   // attempt to push a buffer into the ring buffer at the current "in" index
3737   bool pushBuffer( char* buffer, unsigned int bufferSize, RtAudioFormat format )
3738   {
3739     if ( !buffer ||                 // incoming buffer is NULL
3740          bufferSize == 0 ||         // incoming buffer has no data
3741          bufferSize > bufferSize_ ) // incoming buffer too large
3742     {
3743       return false;
3744     }
3745
3746     unsigned int relOutIndex = outIndex_;
3747     unsigned int inIndexEnd = inIndex_ + bufferSize;
3748     if ( relOutIndex < inIndex_ && inIndexEnd >= bufferSize_ ) {
3749       relOutIndex += bufferSize_;
3750     }
3751
3752     // "in" index can end on the "out" index but cannot begin at it
3753     if ( inIndex_ <= relOutIndex && inIndexEnd > relOutIndex ) {
3754       return false; // not enough space between "in" index and "out" index
3755     }
3756
3757     // copy buffer from external to internal
3758     int fromZeroSize = inIndex_ + bufferSize - bufferSize_;
3759     fromZeroSize = fromZeroSize < 0 ? 0 : fromZeroSize;
3760     int fromInSize = bufferSize - fromZeroSize;
3761
3762     switch( format )
3763       {
3764       case RTAUDIO_SINT8:
3765         memcpy( &( ( char* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( char ) );
3766         memcpy( buffer_, &( ( char* ) buffer )[fromInSize], fromZeroSize * sizeof( char ) );
3767         break;
3768       case RTAUDIO_SINT16:
3769         memcpy( &( ( short* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( short ) );
3770         memcpy( buffer_, &( ( short* ) buffer )[fromInSize], fromZeroSize * sizeof( short ) );
3771         break;
3772       case RTAUDIO_SINT24:
3773         memcpy( &( ( S24* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( S24 ) );
3774         memcpy( buffer_, &( ( S24* ) buffer )[fromInSize], fromZeroSize * sizeof( S24 ) );
3775         break;
3776       case RTAUDIO_SINT32:
3777         memcpy( &( ( int* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( int ) );
3778         memcpy( buffer_, &( ( int* ) buffer )[fromInSize], fromZeroSize * sizeof( int ) );
3779         break;
3780       case RTAUDIO_FLOAT32:
3781         memcpy( &( ( float* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( float ) );
3782         memcpy( buffer_, &( ( float* ) buffer )[fromInSize], fromZeroSize * sizeof( float ) );
3783         break;
3784       case RTAUDIO_FLOAT64:
3785         memcpy( &( ( double* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( double ) );
3786         memcpy( buffer_, &( ( double* ) buffer )[fromInSize], fromZeroSize * sizeof( double ) );
3787         break;
3788     }
3789
3790     // update "in" index
3791     inIndex_ += bufferSize;
3792     inIndex_ %= bufferSize_;
3793
3794     return true;
3795   }
3796
3797   // attempt to pull a buffer from the ring buffer from the current "out" index
3798   bool pullBuffer( char* buffer, unsigned int bufferSize, RtAudioFormat format )
3799   {
3800     if ( !buffer ||                 // incoming buffer is NULL
3801          bufferSize == 0 ||         // incoming buffer has no data
3802          bufferSize > bufferSize_ ) // incoming buffer too large
3803     {
3804       return false;
3805     }
3806
3807     unsigned int relInIndex = inIndex_;
3808     unsigned int outIndexEnd = outIndex_ + bufferSize;
3809     if ( relInIndex < outIndex_ && outIndexEnd >= bufferSize_ ) {
3810       relInIndex += bufferSize_;
3811     }
3812
3813     // "out" index can begin at and end on the "in" index
3814     if ( outIndex_ < relInIndex && outIndexEnd > relInIndex ) {
3815       return false; // not enough space between "out" index and "in" index
3816     }
3817
3818     // copy buffer from internal to external
3819     int fromZeroSize = outIndex_ + bufferSize - bufferSize_;
3820     fromZeroSize = fromZeroSize < 0 ? 0 : fromZeroSize;
3821     int fromOutSize = bufferSize - fromZeroSize;
3822
3823     switch( format )
3824     {
3825       case RTAUDIO_SINT8:
3826         memcpy( buffer, &( ( char* ) buffer_ )[outIndex_], fromOutSize * sizeof( char ) );
3827         memcpy( &( ( char* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( char ) );
3828         break;
3829       case RTAUDIO_SINT16:
3830         memcpy( buffer, &( ( short* ) buffer_ )[outIndex_], fromOutSize * sizeof( short ) );
3831         memcpy( &( ( short* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( short ) );
3832         break;
3833       case RTAUDIO_SINT24:
3834         memcpy( buffer, &( ( S24* ) buffer_ )[outIndex_], fromOutSize * sizeof( S24 ) );
3835         memcpy( &( ( S24* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( S24 ) );
3836         break;
3837       case RTAUDIO_SINT32:
3838         memcpy( buffer, &( ( int* ) buffer_ )[outIndex_], fromOutSize * sizeof( int ) );
3839         memcpy( &( ( int* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( int ) );
3840         break;
3841       case RTAUDIO_FLOAT32:
3842         memcpy( buffer, &( ( float* ) buffer_ )[outIndex_], fromOutSize * sizeof( float ) );
3843         memcpy( &( ( float* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( float ) );
3844         break;
3845       case RTAUDIO_FLOAT64:
3846         memcpy( buffer, &( ( double* ) buffer_ )[outIndex_], fromOutSize * sizeof( double ) );
3847         memcpy( &( ( double* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( double ) );
3848         break;
3849     }
3850
3851     // update "out" index
3852     outIndex_ += bufferSize;
3853     outIndex_ %= bufferSize_;
3854
3855     return true;
3856   }
3857
3858 private:
3859   char* buffer_;
3860   unsigned int bufferSize_;
3861   unsigned int inIndex_;
3862   unsigned int outIndex_;
3863 };
3864
3865 //-----------------------------------------------------------------------------
3866
3867 // In order to satisfy WASAPI's buffer requirements, we need a means of converting sample rate
3868 // between HW and the user. The convertBufferWasapi function is used to perform this conversion
3869 // between HwIn->UserIn and UserOut->HwOut during the stream callback loop.
3870 // This sample rate converter works best with conversions between one rate and its multiple.
3871 void convertBufferWasapi( char* outBuffer,
3872                           const char* inBuffer,
3873                           const unsigned int& channelCount,
3874                           const unsigned int& inSampleRate,
3875                           const unsigned int& outSampleRate,
3876                           const unsigned int& inSampleCount,
3877                           unsigned int& outSampleCount,
3878                           const RtAudioFormat& format )
3879 {
3880   // calculate the new outSampleCount and relative sampleStep
3881   float sampleRatio = ( float ) outSampleRate / inSampleRate;
3882   float sampleRatioInv = ( float ) 1 / sampleRatio;
3883   float sampleStep = 1.0f / sampleRatio;
3884   float inSampleFraction = 0.0f;
3885
3886   outSampleCount = ( unsigned int ) std::roundf( inSampleCount * sampleRatio );
3887
3888   // if inSampleRate is a multiple of outSampleRate (or vice versa) there's no need to interpolate
3889   if ( floor( sampleRatio ) == sampleRatio || floor( sampleRatioInv ) == sampleRatioInv )
3890   {
3891     // frame-by-frame, copy each relative input sample into it's corresponding output sample
3892     for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )
3893     {
3894       unsigned int inSample = ( unsigned int ) inSampleFraction;
3895
3896       switch ( format )
3897       {
3898         case RTAUDIO_SINT8:
3899           memcpy( &( ( char* ) outBuffer )[ outSample * channelCount ], &( ( char* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( char ) );
3900           break;
3901         case RTAUDIO_SINT16:
3902           memcpy( &( ( short* ) outBuffer )[ outSample * channelCount ], &( ( short* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( short ) );
3903           break;
3904         case RTAUDIO_SINT24:
3905           memcpy( &( ( S24* ) outBuffer )[ outSample * channelCount ], &( ( S24* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( S24 ) );
3906           break;
3907         case RTAUDIO_SINT32:
3908           memcpy( &( ( int* ) outBuffer )[ outSample * channelCount ], &( ( int* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( int ) );
3909           break;
3910         case RTAUDIO_FLOAT32:
3911           memcpy( &( ( float* ) outBuffer )[ outSample * channelCount ], &( ( float* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( float ) );
3912           break;
3913         case RTAUDIO_FLOAT64:
3914           memcpy( &( ( double* ) outBuffer )[ outSample * channelCount ], &( ( double* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( double ) );
3915           break;
3916       }
3917
3918       // jump to next in sample
3919       inSampleFraction += sampleStep;
3920     }
3921   }
3922   else // else interpolate
3923   {
3924     // frame-by-frame, copy each relative input sample into it's corresponding output sample
3925     for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )
3926     {
3927       unsigned int inSample = ( unsigned int ) inSampleFraction;
3928       float inSampleDec = inSampleFraction - inSample;
3929       unsigned int frameInSample = inSample * channelCount;
3930       unsigned int frameOutSample = outSample * channelCount;
3931
3932       switch ( format )
3933       {
3934         case RTAUDIO_SINT8:
3935         {
3936           for ( unsigned int channel = 0; channel < channelCount; channel++ )
3937           {
3938             char fromSample = ( ( char* ) inBuffer )[ frameInSample + channel ];
3939             char toSample = ( ( char* ) inBuffer )[ frameInSample + channelCount + channel ];
3940             char sampleDiff = ( char ) ( ( toSample - fromSample ) * inSampleDec );
3941             ( ( char* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
3942           }
3943           break;
3944         }
3945         case RTAUDIO_SINT16:
3946         {
3947           for ( unsigned int channel = 0; channel < channelCount; channel++ )
3948           {
3949             short fromSample = ( ( short* ) inBuffer )[ frameInSample + channel ];
3950             short toSample = ( ( short* ) inBuffer )[ frameInSample + channelCount + channel ];
3951             short sampleDiff = ( short ) ( ( toSample - fromSample ) * inSampleDec );
3952             ( ( short* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
3953           }
3954           break;
3955         }
3956         case RTAUDIO_SINT24:
3957         {
3958           for ( unsigned int channel = 0; channel < channelCount; channel++ )
3959           {
3960             int fromSample = ( ( S24* ) inBuffer )[ frameInSample + channel ].asInt();
3961             int toSample = ( ( S24* ) inBuffer )[ frameInSample + channelCount + channel ].asInt();
3962             int sampleDiff = ( int ) ( ( toSample - fromSample ) * inSampleDec );
3963             ( ( S24* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
3964           }
3965           break;
3966         }
3967         case RTAUDIO_SINT32:
3968         {
3969           for ( unsigned int channel = 0; channel < channelCount; channel++ )
3970           {
3971             int fromSample = ( ( int* ) inBuffer )[ frameInSample + channel ];
3972             int toSample = ( ( int* ) inBuffer )[ frameInSample + channelCount + channel ];
3973             int sampleDiff = ( int ) ( ( toSample - fromSample ) * inSampleDec );
3974             ( ( int* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
3975           }
3976           break;
3977         }
3978         case RTAUDIO_FLOAT32:
3979         {
3980           for ( unsigned int channel = 0; channel < channelCount; channel++ )
3981           {
3982             float fromSample = ( ( float* ) inBuffer )[ frameInSample + channel ];
3983             float toSample = ( ( float* ) inBuffer )[ frameInSample + channelCount + channel ];
3984             float sampleDiff = ( toSample - fromSample ) * inSampleDec;
3985             ( ( float* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
3986           }
3987           break;
3988         }
3989         case RTAUDIO_FLOAT64:
3990         {
3991           for ( unsigned int channel = 0; channel < channelCount; channel++ )
3992           {
3993             double fromSample = ( ( double* ) inBuffer )[ frameInSample + channel ];
3994             double toSample = ( ( double* ) inBuffer )[ frameInSample + channelCount + channel ];
3995             double sampleDiff = ( toSample - fromSample ) * inSampleDec;
3996             ( ( double* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
3997           }
3998           break;
3999         }
4000       }
4001
4002       // jump to next in sample
4003       inSampleFraction += sampleStep;
4004     }
4005   }
4006 }
4007
4008 //-----------------------------------------------------------------------------
4009
4010 // A structure to hold various information related to the WASAPI implementation.
4011 struct WasapiHandle
4012 {
4013   IAudioClient* captureAudioClient;
4014   IAudioClient* renderAudioClient;
4015   IAudioCaptureClient* captureClient;
4016   IAudioRenderClient* renderClient;
4017   HANDLE captureEvent;
4018   HANDLE renderEvent;
4019
4020   WasapiHandle()
4021   : captureAudioClient( NULL ),
4022     renderAudioClient( NULL ),
4023     captureClient( NULL ),
4024     renderClient( NULL ),
4025     captureEvent( NULL ),
4026     renderEvent( NULL ) {}
4027 };
4028
4029 //=============================================================================
4030
4031 RtApiWasapi::RtApiWasapi()
4032   : coInitialized_( false ), deviceEnumerator_( NULL )
4033 {
4034   // WASAPI can run either apartment or multi-threaded
4035   HRESULT hr = CoInitialize( NULL );
4036   if ( !FAILED( hr ) )
4037     coInitialized_ = true;
4038
4039   // Instantiate device enumerator
4040   hr = CoCreateInstance( __uuidof( MMDeviceEnumerator ), NULL,
4041                          CLSCTX_ALL, __uuidof( IMMDeviceEnumerator ),
4042                          ( void** ) &deviceEnumerator_ );
4043
4044   if ( FAILED( hr ) ) {
4045     errorText_ = "RtApiWasapi::RtApiWasapi: Unable to instantiate device enumerator";
4046     error( RtAudioError::DRIVER_ERROR );
4047   }
4048 }
4049
4050 //-----------------------------------------------------------------------------
4051
4052 RtApiWasapi::~RtApiWasapi()
4053 {
4054   if ( stream_.state != STREAM_CLOSED )
4055     closeStream();
4056
4057   SAFE_RELEASE( deviceEnumerator_ );
4058
4059   // If this object previously called CoInitialize()
4060   if ( coInitialized_ )
4061     CoUninitialize();
4062 }
4063
4064 //=============================================================================
4065
4066 unsigned int RtApiWasapi::getDeviceCount( void )
4067 {
4068   unsigned int captureDeviceCount = 0;
4069   unsigned int renderDeviceCount = 0;
4070
4071   IMMDeviceCollection* captureDevices = NULL;
4072   IMMDeviceCollection* renderDevices = NULL;
4073
4074   // Count capture devices
4075   errorText_.clear();
4076   HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
4077   if ( FAILED( hr ) ) {
4078     errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device collection.";
4079     goto Exit;
4080   }
4081
4082   hr = captureDevices->GetCount( &captureDeviceCount );
4083   if ( FAILED( hr ) ) {
4084     errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device count.";
4085     goto Exit;
4086   }
4087
4088   // Count render devices
4089   hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );
4090   if ( FAILED( hr ) ) {
4091     errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device collection.";
4092     goto Exit;
4093   }
4094
4095   hr = renderDevices->GetCount( &renderDeviceCount );
4096   if ( FAILED( hr ) ) {
4097     errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device count.";
4098     goto Exit;
4099   }
4100
4101 Exit:
4102   // release all references
4103   SAFE_RELEASE( captureDevices );
4104   SAFE_RELEASE( renderDevices );
4105
4106   if ( errorText_.empty() )
4107     return captureDeviceCount + renderDeviceCount;
4108
4109   error( RtAudioError::DRIVER_ERROR );
4110   return 0;
4111 }
4112
4113 //-----------------------------------------------------------------------------
4114
4115 RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device )
4116 {
4117   RtAudio::DeviceInfo info;
4118   unsigned int captureDeviceCount = 0;
4119   unsigned int renderDeviceCount = 0;
4120   std::string defaultDeviceName;
4121   bool isCaptureDevice = false;
4122
4123   PROPVARIANT deviceNameProp;
4124   PROPVARIANT defaultDeviceNameProp;
4125
4126   IMMDeviceCollection* captureDevices = NULL;
4127   IMMDeviceCollection* renderDevices = NULL;
4128   IMMDevice* devicePtr = NULL;
4129   IMMDevice* defaultDevicePtr = NULL;
4130   IAudioClient* audioClient = NULL;
4131   IPropertyStore* devicePropStore = NULL;
4132   IPropertyStore* defaultDevicePropStore = NULL;
4133
4134   WAVEFORMATEX* deviceFormat = NULL;
4135   WAVEFORMATEX* closestMatchFormat = NULL;
4136
4137   // probed
4138   info.probed = false;
4139
4140   // Count capture devices
4141   errorText_.clear();
4142   RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;
4143   HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
4144   if ( FAILED( hr ) ) {
4145     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device collection.";
4146     goto Exit;
4147   }
4148
4149   hr = captureDevices->GetCount( &captureDeviceCount );
4150   if ( FAILED( hr ) ) {
4151     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device count.";
4152     goto Exit;
4153   }
4154
4155   // Count render devices
4156   hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );
4157   if ( FAILED( hr ) ) {
4158     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device collection.";
4159     goto Exit;
4160   }
4161
4162   hr = renderDevices->GetCount( &renderDeviceCount );
4163   if ( FAILED( hr ) ) {
4164     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device count.";
4165     goto Exit;
4166   }
4167
4168   // validate device index
4169   if ( device >= captureDeviceCount + renderDeviceCount ) {
4170     errorText_ = "RtApiWasapi::getDeviceInfo: Invalid device index.";
4171     errorType = RtAudioError::INVALID_USE;
4172     goto Exit;
4173   }
4174
4175   // determine whether index falls within capture or render devices
4176   if ( device >= renderDeviceCount ) {
4177     hr = captureDevices->Item( device - renderDeviceCount, &devicePtr );
4178     if ( FAILED( hr ) ) {
4179       errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device handle.";
4180       goto Exit;
4181     }
4182     isCaptureDevice = true;
4183   }
4184   else {
4185     hr = renderDevices->Item( device, &devicePtr );
4186     if ( FAILED( hr ) ) {
4187       errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device handle.";
4188       goto Exit;
4189     }
4190     isCaptureDevice = false;
4191   }
4192
4193   // get default device name
4194   if ( isCaptureDevice ) {
4195     hr = deviceEnumerator_->GetDefaultAudioEndpoint( eCapture, eConsole, &defaultDevicePtr );
4196     if ( FAILED( hr ) ) {
4197       errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default capture device handle.";
4198       goto Exit;
4199     }
4200   }
4201   else {
4202     hr = deviceEnumerator_->GetDefaultAudioEndpoint( eRender, eConsole, &defaultDevicePtr );
4203     if ( FAILED( hr ) ) {
4204       errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default render device handle.";
4205       goto Exit;
4206     }
4207   }
4208
4209   hr = defaultDevicePtr->OpenPropertyStore( STGM_READ, &defaultDevicePropStore );
4210   if ( FAILED( hr ) ) {
4211     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open default device property store.";
4212     goto Exit;
4213   }
4214   PropVariantInit( &defaultDeviceNameProp );
4215
4216   hr = defaultDevicePropStore->GetValue( PKEY_Device_FriendlyName, &defaultDeviceNameProp );
4217   if ( FAILED( hr ) ) {
4218     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default device property: PKEY_Device_FriendlyName.";
4219     goto Exit;
4220   }
4221
4222   defaultDeviceName = convertCharPointerToStdString(defaultDeviceNameProp.pwszVal);
4223
4224   // name
4225   hr = devicePtr->OpenPropertyStore( STGM_READ, &devicePropStore );
4226   if ( FAILED( hr ) ) {
4227     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open device property store.";
4228     goto Exit;
4229   }
4230
4231   PropVariantInit( &deviceNameProp );
4232
4233   hr = devicePropStore->GetValue( PKEY_Device_FriendlyName, &deviceNameProp );
4234   if ( FAILED( hr ) ) {
4235     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device property: PKEY_Device_FriendlyName.";
4236     goto Exit;
4237   }
4238
4239   info.name =convertCharPointerToStdString(deviceNameProp.pwszVal);
4240
4241   // is default
4242   if ( isCaptureDevice ) {
4243     info.isDefaultInput = info.name == defaultDeviceName;
4244     info.isDefaultOutput = false;
4245   }
4246   else {
4247     info.isDefaultInput = false;
4248     info.isDefaultOutput = info.name == defaultDeviceName;
4249   }
4250
4251   // channel count
4252   hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL, NULL, ( void** ) &audioClient );
4253   if ( FAILED( hr ) ) {
4254     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device audio client.";
4255     goto Exit;
4256   }
4257
4258   hr = audioClient->GetMixFormat( &deviceFormat );
4259   if ( FAILED( hr ) ) {
4260     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device mix format.";
4261     goto Exit;
4262   }
4263
4264   if ( isCaptureDevice ) {
4265     info.inputChannels = deviceFormat->nChannels;
4266     info.outputChannels = 0;
4267     info.duplexChannels = 0;
4268   }
4269   else {
4270     info.inputChannels = 0;
4271     info.outputChannels = deviceFormat->nChannels;
4272     info.duplexChannels = 0;
4273   }
4274
4275   // sample rates
4276   info.sampleRates.clear();
4277
4278   // allow support for all sample rates as we have a built-in sample rate converter
4279   for ( unsigned int i = 0; i < MAX_SAMPLE_RATES; i++ ) {
4280     info.sampleRates.push_back( SAMPLE_RATES[i] );
4281   }
4282   info.preferredSampleRate = deviceFormat->nSamplesPerSec;
4283
4284   // native format
4285   info.nativeFormats = 0;
4286
4287   if ( deviceFormat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
4288        ( deviceFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
4289          ( ( WAVEFORMATEXTENSIBLE* ) deviceFormat )->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT ) )
4290   {
4291     if ( deviceFormat->wBitsPerSample == 32 ) {
4292       info.nativeFormats |= RTAUDIO_FLOAT32;
4293     }
4294     else if ( deviceFormat->wBitsPerSample == 64 ) {
4295       info.nativeFormats |= RTAUDIO_FLOAT64;
4296     }
4297   }
4298   else if ( deviceFormat->wFormatTag == WAVE_FORMAT_PCM ||
4299            ( deviceFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
4300              ( ( WAVEFORMATEXTENSIBLE* ) deviceFormat )->SubFormat == KSDATAFORMAT_SUBTYPE_PCM ) )
4301   {
4302     if ( deviceFormat->wBitsPerSample == 8 ) {
4303       info.nativeFormats |= RTAUDIO_SINT8;
4304     }
4305     else if ( deviceFormat->wBitsPerSample == 16 ) {
4306       info.nativeFormats |= RTAUDIO_SINT16;
4307     }
4308     else if ( deviceFormat->wBitsPerSample == 24 ) {
4309       info.nativeFormats |= RTAUDIO_SINT24;
4310     }
4311     else if ( deviceFormat->wBitsPerSample == 32 ) {
4312       info.nativeFormats |= RTAUDIO_SINT32;
4313     }
4314   }
4315
4316   // probed
4317   info.probed = true;
4318
4319 Exit:
4320   // release all references
4321   PropVariantClear( &deviceNameProp );
4322   PropVariantClear( &defaultDeviceNameProp );
4323
4324   SAFE_RELEASE( captureDevices );
4325   SAFE_RELEASE( renderDevices );
4326   SAFE_RELEASE( devicePtr );
4327   SAFE_RELEASE( defaultDevicePtr );
4328   SAFE_RELEASE( audioClient );
4329   SAFE_RELEASE( devicePropStore );
4330   SAFE_RELEASE( defaultDevicePropStore );
4331
4332   CoTaskMemFree( deviceFormat );
4333   CoTaskMemFree( closestMatchFormat );
4334
4335   if ( !errorText_.empty() )
4336     error( errorType );
4337   return info;
4338 }
4339
4340 //-----------------------------------------------------------------------------
4341
4342 unsigned int RtApiWasapi::getDefaultOutputDevice( void )
4343 {
4344   for ( unsigned int i = 0; i < getDeviceCount(); i++ ) {
4345     if ( getDeviceInfo( i ).isDefaultOutput ) {
4346       return i;
4347     }
4348   }
4349
4350   return 0;
4351 }
4352
4353 //-----------------------------------------------------------------------------
4354
4355 unsigned int RtApiWasapi::getDefaultInputDevice( void )
4356 {
4357   for ( unsigned int i = 0; i < getDeviceCount(); i++ ) {
4358     if ( getDeviceInfo( i ).isDefaultInput ) {
4359       return i;
4360     }
4361   }
4362
4363   return 0;
4364 }
4365
4366 //-----------------------------------------------------------------------------
4367
4368 void RtApiWasapi::closeStream( void )
4369 {
4370   if ( stream_.state == STREAM_CLOSED ) {
4371     errorText_ = "RtApiWasapi::closeStream: No open stream to close.";
4372     error( RtAudioError::WARNING );
4373     return;
4374   }
4375
4376   if ( stream_.state != STREAM_STOPPED )
4377     stopStream();
4378
4379   // clean up stream memory
4380   SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient )
4381   SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient )
4382
4383   SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->captureClient )
4384   SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->renderClient )
4385
4386   if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent )
4387     CloseHandle( ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent );
4388
4389   if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent )
4390     CloseHandle( ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent );
4391
4392   delete ( WasapiHandle* ) stream_.apiHandle;
4393   stream_.apiHandle = NULL;
4394
4395   for ( int i = 0; i < 2; i++ ) {
4396     if ( stream_.userBuffer[i] ) {
4397       free( stream_.userBuffer[i] );
4398       stream_.userBuffer[i] = 0;
4399     }
4400   }
4401
4402   if ( stream_.deviceBuffer ) {
4403     free( stream_.deviceBuffer );
4404     stream_.deviceBuffer = 0;
4405   }
4406
4407   // update stream state
4408   stream_.state = STREAM_CLOSED;
4409 }
4410
4411 //-----------------------------------------------------------------------------
4412
4413 void RtApiWasapi::startStream( void )
4414 {
4415   verifyStream();
4416
4417   if ( stream_.state == STREAM_RUNNING ) {
4418     errorText_ = "RtApiWasapi::startStream: The stream is already running.";
4419     error( RtAudioError::WARNING );
4420     return;
4421   }
4422
4423   // update stream state
4424   stream_.state = STREAM_RUNNING;
4425
4426   // create WASAPI stream thread
4427   stream_.callbackInfo.thread = ( ThreadHandle ) CreateThread( NULL, 0, runWasapiThread, this, CREATE_SUSPENDED, NULL );
4428
4429   if ( !stream_.callbackInfo.thread ) {
4430     errorText_ = "RtApiWasapi::startStream: Unable to instantiate callback thread.";
4431     error( RtAudioError::THREAD_ERROR );
4432   }
4433   else {
4434     SetThreadPriority( ( void* ) stream_.callbackInfo.thread, stream_.callbackInfo.priority );
4435     ResumeThread( ( void* ) stream_.callbackInfo.thread );
4436   }
4437 }
4438
4439 //-----------------------------------------------------------------------------
4440
4441 void RtApiWasapi::stopStream( void )
4442 {
4443   verifyStream();
4444
4445   if ( stream_.state == STREAM_STOPPED ) {
4446     errorText_ = "RtApiWasapi::stopStream: The stream is already stopped.";
4447     error( RtAudioError::WARNING );
4448     return;
4449   }
4450
4451   // inform stream thread by setting stream state to STREAM_STOPPING
4452   stream_.state = STREAM_STOPPING;
4453
4454   // wait until stream thread is stopped
4455   while( stream_.state != STREAM_STOPPED ) {
4456     Sleep( 1 );
4457   }
4458
4459   // Wait for the last buffer to play before stopping.
4460   Sleep( 1000 * stream_.bufferSize / stream_.sampleRate );
4461
4462   // stop capture client if applicable
4463   if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) {
4464     HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop();
4465     if ( FAILED( hr ) ) {
4466       errorText_ = "RtApiWasapi::stopStream: Unable to stop capture stream.";
4467       error( RtAudioError::DRIVER_ERROR );
4468       return;
4469     }
4470   }
4471
4472   // stop render client if applicable
4473   if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) {
4474     HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop();
4475     if ( FAILED( hr ) ) {
4476       errorText_ = "RtApiWasapi::stopStream: Unable to stop render stream.";
4477       error( RtAudioError::DRIVER_ERROR );
4478       return;
4479     }
4480   }
4481
4482   // close thread handle
4483   if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) {
4484     errorText_ = "RtApiWasapi::stopStream: Unable to close callback thread.";
4485     error( RtAudioError::THREAD_ERROR );
4486     return;
4487   }
4488
4489   stream_.callbackInfo.thread = (ThreadHandle) NULL;
4490 }
4491
4492 //-----------------------------------------------------------------------------
4493
4494 void RtApiWasapi::abortStream( void )
4495 {
4496   verifyStream();
4497
4498   if ( stream_.state == STREAM_STOPPED ) {
4499     errorText_ = "RtApiWasapi::abortStream: The stream is already stopped.";
4500     error( RtAudioError::WARNING );
4501     return;
4502   }
4503
4504   // inform stream thread by setting stream state to STREAM_STOPPING
4505   stream_.state = STREAM_STOPPING;
4506
4507   // wait until stream thread is stopped
4508   while ( stream_.state != STREAM_STOPPED ) {
4509     Sleep( 1 );
4510   }
4511
4512   // stop capture client if applicable
4513   if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) {
4514     HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop();
4515     if ( FAILED( hr ) ) {
4516       errorText_ = "RtApiWasapi::abortStream: Unable to stop capture stream.";
4517       error( RtAudioError::DRIVER_ERROR );
4518       return;
4519     }
4520   }
4521
4522   // stop render client if applicable
4523   if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) {
4524     HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop();
4525     if ( FAILED( hr ) ) {
4526       errorText_ = "RtApiWasapi::abortStream: Unable to stop render stream.";
4527       error( RtAudioError::DRIVER_ERROR );
4528       return;
4529     }
4530   }
4531
4532   // close thread handle
4533   if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) {
4534     errorText_ = "RtApiWasapi::abortStream: Unable to close callback thread.";
4535     error( RtAudioError::THREAD_ERROR );
4536     return;
4537   }
4538
4539   stream_.callbackInfo.thread = (ThreadHandle) NULL;
4540 }
4541
4542 //-----------------------------------------------------------------------------
4543
4544 bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
4545                                    unsigned int firstChannel, unsigned int sampleRate,
4546                                    RtAudioFormat format, unsigned int* bufferSize,
4547                                    RtAudio::StreamOptions* options )
4548 {
4549   bool methodResult = FAILURE;
4550   unsigned int captureDeviceCount = 0;
4551   unsigned int renderDeviceCount = 0;
4552
4553   IMMDeviceCollection* captureDevices = NULL;
4554   IMMDeviceCollection* renderDevices = NULL;
4555   IMMDevice* devicePtr = NULL;
4556   WAVEFORMATEX* deviceFormat = NULL;
4557   unsigned int bufferBytes;
4558   stream_.state = STREAM_STOPPED;
4559
4560   // create API Handle if not already created
4561   if ( !stream_.apiHandle )
4562     stream_.apiHandle = ( void* ) new WasapiHandle();
4563
4564   // Count capture devices
4565   errorText_.clear();
4566   RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;
4567   HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
4568   if ( FAILED( hr ) ) {
4569     errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device collection.";
4570     goto Exit;
4571   }
4572
4573   hr = captureDevices->GetCount( &captureDeviceCount );
4574   if ( FAILED( hr ) ) {
4575     errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device count.";
4576     goto Exit;
4577   }
4578
4579   // Count render devices
4580   hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );
4581   if ( FAILED( hr ) ) {
4582     errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device collection.";
4583     goto Exit;
4584   }
4585
4586   hr = renderDevices->GetCount( &renderDeviceCount );
4587   if ( FAILED( hr ) ) {
4588     errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device count.";
4589     goto Exit;
4590   }
4591
4592   // validate device index
4593   if ( device >= captureDeviceCount + renderDeviceCount ) {
4594     errorType = RtAudioError::INVALID_USE;
4595     errorText_ = "RtApiWasapi::probeDeviceOpen: Invalid device index.";
4596     goto Exit;
4597   }
4598
4599   // determine whether index falls within capture or render devices
4600   if ( device >= renderDeviceCount ) {
4601     if ( mode != INPUT ) {
4602       errorType = RtAudioError::INVALID_USE;
4603       errorText_ = "RtApiWasapi::probeDeviceOpen: Capture device selected as output device.";
4604       goto Exit;
4605     }
4606
4607     // retrieve captureAudioClient from devicePtr
4608     IAudioClient*& captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient;
4609
4610     hr = captureDevices->Item( device - renderDeviceCount, &devicePtr );
4611     if ( FAILED( hr ) ) {
4612       errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device handle.";
4613       goto Exit;
4614     }
4615
4616     hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,
4617                               NULL, ( void** ) &captureAudioClient );
4618     if ( FAILED( hr ) ) {
4619       errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";
4620       goto Exit;
4621     }
4622
4623     hr = captureAudioClient->GetMixFormat( &deviceFormat );
4624     if ( FAILED( hr ) ) {
4625       errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";
4626       goto Exit;
4627     }
4628
4629     stream_.nDeviceChannels[mode] = deviceFormat->nChannels;
4630     captureAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );
4631   }
4632   else {
4633     if ( mode != OUTPUT ) {
4634       errorType = RtAudioError::INVALID_USE;
4635       errorText_ = "RtApiWasapi::probeDeviceOpen: Render device selected as input device.";
4636       goto Exit;
4637     }
4638
4639     // retrieve renderAudioClient from devicePtr
4640     IAudioClient*& renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;
4641
4642     hr = renderDevices->Item( device, &devicePtr );
4643     if ( FAILED( hr ) ) {
4644       errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device handle.";
4645       goto Exit;
4646     }
4647
4648     hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,
4649                               NULL, ( void** ) &renderAudioClient );
4650     if ( FAILED( hr ) ) {
4651       errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";
4652       goto Exit;
4653     }
4654
4655     hr = renderAudioClient->GetMixFormat( &deviceFormat );
4656     if ( FAILED( hr ) ) {
4657       errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";
4658       goto Exit;
4659     }
4660
4661     stream_.nDeviceChannels[mode] = deviceFormat->nChannels;
4662     renderAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );
4663   }
4664
4665   // fill stream data
4666   if ( ( stream_.mode == OUTPUT && mode == INPUT ) ||
4667        ( stream_.mode == INPUT && mode == OUTPUT ) ) {
4668     stream_.mode = DUPLEX;
4669   }
4670   else {
4671     stream_.mode = mode;
4672   }
4673
4674   stream_.device[mode] = device;
4675   stream_.doByteSwap[mode] = false;
4676   stream_.sampleRate = sampleRate;
4677   stream_.bufferSize = *bufferSize;
4678   stream_.nBuffers = 1;
4679   stream_.nUserChannels[mode] = channels;
4680   stream_.channelOffset[mode] = firstChannel;
4681   stream_.userFormat = format;
4682   stream_.deviceFormat[mode] = getDeviceInfo( device ).nativeFormats;
4683
4684   if ( options && options->flags & RTAUDIO_NONINTERLEAVED )
4685     stream_.userInterleaved = false;
4686   else
4687     stream_.userInterleaved = true;
4688   stream_.deviceInterleaved[mode] = true;
4689
4690   // Set flags for buffer conversion.
4691   stream_.doConvertBuffer[mode] = false;
4692   if ( stream_.userFormat != stream_.deviceFormat[mode] ||
4693        stream_.nUserChannels != stream_.nDeviceChannels )
4694     stream_.doConvertBuffer[mode] = true;
4695   else if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
4696             stream_.nUserChannels[mode] > 1 )
4697     stream_.doConvertBuffer[mode] = true;
4698
4699   if ( stream_.doConvertBuffer[mode] )
4700     setConvertInfo( mode, 0 );
4701
4702   // Allocate necessary internal buffers
4703   bufferBytes = stream_.nUserChannels[mode] * stream_.bufferSize * formatBytes( stream_.userFormat );
4704
4705   stream_.userBuffer[mode] = ( char* ) calloc( bufferBytes, 1 );
4706   if ( !stream_.userBuffer[mode] ) {
4707     errorType = RtAudioError::MEMORY_ERROR;
4708     errorText_ = "RtApiWasapi::probeDeviceOpen: Error allocating user buffer memory.";
4709     goto Exit;
4710   }
4711
4712   if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME )
4713     stream_.callbackInfo.priority = 15;
4714   else
4715     stream_.callbackInfo.priority = 0;
4716
4717   ///! TODO: RTAUDIO_MINIMIZE_LATENCY // Provide stream buffers directly to callback
4718   ///! TODO: RTAUDIO_HOG_DEVICE       // Exclusive mode
4719
4720   methodResult = SUCCESS;
4721
4722 Exit:
4723   //clean up
4724   SAFE_RELEASE( captureDevices );
4725   SAFE_RELEASE( renderDevices );
4726   SAFE_RELEASE( devicePtr );
4727   CoTaskMemFree( deviceFormat );
4728
4729   // if method failed, close the stream
4730   if ( methodResult == FAILURE )
4731     closeStream();
4732
4733   if ( !errorText_.empty() )
4734     error( errorType );
4735   return methodResult;
4736 }
4737
4738 //=============================================================================
4739
4740 DWORD WINAPI RtApiWasapi::runWasapiThread( void* wasapiPtr )
4741 {
4742   if ( wasapiPtr )
4743     ( ( RtApiWasapi* ) wasapiPtr )->wasapiThread();
4744
4745   return 0;
4746 }
4747
4748 DWORD WINAPI RtApiWasapi::stopWasapiThread( void* wasapiPtr )
4749 {
4750   if ( wasapiPtr )
4751     ( ( RtApiWasapi* ) wasapiPtr )->stopStream();
4752
4753   return 0;
4754 }
4755
4756 DWORD WINAPI RtApiWasapi::abortWasapiThread( void* wasapiPtr )
4757 {
4758   if ( wasapiPtr )
4759     ( ( RtApiWasapi* ) wasapiPtr )->abortStream();
4760
4761   return 0;
4762 }
4763
4764 //-----------------------------------------------------------------------------
4765
4766 void RtApiWasapi::wasapiThread()
4767 {
4768   // as this is a new thread, we must CoInitialize it
4769   CoInitialize( NULL );
4770
4771   HRESULT hr;
4772
4773   IAudioClient* captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient;
4774   IAudioClient* renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;
4775   IAudioCaptureClient* captureClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureClient;
4776   IAudioRenderClient* renderClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderClient;
4777   HANDLE captureEvent = ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent;
4778   HANDLE renderEvent = ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent;
4779
4780   WAVEFORMATEX* captureFormat = NULL;
4781   WAVEFORMATEX* renderFormat = NULL;
4782   float captureSrRatio = 0.0f;
4783   float renderSrRatio = 0.0f;
4784   WasapiBuffer captureBuffer;
4785   WasapiBuffer renderBuffer;
4786
4787   // declare local stream variables
4788   RtAudioCallback callback = ( RtAudioCallback ) stream_.callbackInfo.callback;
4789   BYTE* streamBuffer = NULL;
4790   unsigned long captureFlags = 0;
4791   unsigned int bufferFrameCount = 0;
4792   unsigned int numFramesPadding = 0;
4793   unsigned int convBufferSize = 0;
4794   bool callbackPushed = false;
4795   bool callbackPulled = false;
4796   bool callbackStopped = false;
4797   int callbackResult = 0;
4798
4799   // convBuffer is used to store converted buffers between WASAPI and the user
4800   char* convBuffer = NULL;
4801   unsigned int convBuffSize = 0;
4802   unsigned int deviceBuffSize = 0;
4803
4804   errorText_.clear();
4805   RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;
4806
4807   // Attempt to assign "Pro Audio" characteristic to thread
4808   HMODULE AvrtDll = LoadLibrary( (LPCTSTR) "AVRT.dll" );
4809   if ( AvrtDll ) {
4810     DWORD taskIndex = 0;
4811     TAvSetMmThreadCharacteristicsPtr AvSetMmThreadCharacteristicsPtr = ( TAvSetMmThreadCharacteristicsPtr ) GetProcAddress( AvrtDll, "AvSetMmThreadCharacteristicsW" );
4812     AvSetMmThreadCharacteristicsPtr( L"Pro Audio", &taskIndex );
4813     FreeLibrary( AvrtDll );
4814   }
4815
4816   // start capture stream if applicable
4817   if ( captureAudioClient ) {
4818     hr = captureAudioClient->GetMixFormat( &captureFormat );
4819     if ( FAILED( hr ) ) {
4820       errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";
4821       goto Exit;
4822     }
4823
4824     captureSrRatio = ( ( float ) captureFormat->nSamplesPerSec / stream_.sampleRate );
4825
4826     // initialize capture stream according to desire buffer size
4827     float desiredBufferSize = stream_.bufferSize * captureSrRatio;
4828     REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) desiredBufferSize * 10000000 / captureFormat->nSamplesPerSec );
4829
4830     if ( !captureClient ) {
4831       hr = captureAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED,
4832                                            AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
4833                                            desiredBufferPeriod,
4834                                            desiredBufferPeriod,
4835                                            captureFormat,
4836                                            NULL );
4837       if ( FAILED( hr ) ) {
4838         errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize capture audio client.";
4839         goto Exit;
4840       }
4841
4842       hr = captureAudioClient->GetService( __uuidof( IAudioCaptureClient ),
4843                                            ( void** ) &captureClient );
4844       if ( FAILED( hr ) ) {
4845         errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture client handle.";
4846         goto Exit;
4847       }
4848
4849       // configure captureEvent to trigger on every available capture buffer
4850       captureEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
4851       if ( !captureEvent ) {
4852         errorType = RtAudioError::SYSTEM_ERROR;
4853         errorText_ = "RtApiWasapi::wasapiThread: Unable to create capture event.";
4854         goto Exit;
4855       }
4856
4857       hr = captureAudioClient->SetEventHandle( captureEvent );
4858       if ( FAILED( hr ) ) {
4859         errorText_ = "RtApiWasapi::wasapiThread: Unable to set capture event handle.";
4860         goto Exit;
4861       }
4862
4863       ( ( WasapiHandle* ) stream_.apiHandle )->captureClient = captureClient;
4864       ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent = captureEvent;
4865     }
4866
4867     unsigned int inBufferSize = 0;
4868     hr = captureAudioClient->GetBufferSize( &inBufferSize );
4869     if ( FAILED( hr ) ) {
4870       errorText_ = "RtApiWasapi::wasapiThread: Unable to get capture buffer size.";
4871       goto Exit;
4872     }
4873
4874     // scale outBufferSize according to stream->user sample rate ratio
4875     unsigned int outBufferSize = ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT];
4876     inBufferSize *= stream_.nDeviceChannels[INPUT];
4877
4878     // set captureBuffer size
4879     captureBuffer.setBufferSize( inBufferSize + outBufferSize, formatBytes( stream_.deviceFormat[INPUT] ) );
4880
4881     // reset the capture stream
4882     hr = captureAudioClient->Reset();
4883     if ( FAILED( hr ) ) {
4884       errorText_ = "RtApiWasapi::wasapiThread: Unable to reset capture stream.";
4885       goto Exit;
4886     }
4887
4888     // start the capture stream
4889     hr = captureAudioClient->Start();
4890     if ( FAILED( hr ) ) {
4891       errorText_ = "RtApiWasapi::wasapiThread: Unable to start capture stream.";
4892       goto Exit;
4893     }
4894   }
4895
4896   // start render stream if applicable
4897   if ( renderAudioClient ) {
4898     hr = renderAudioClient->GetMixFormat( &renderFormat );
4899     if ( FAILED( hr ) ) {
4900       errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";
4901       goto Exit;
4902     }
4903
4904     renderSrRatio = ( ( float ) renderFormat->nSamplesPerSec / stream_.sampleRate );
4905
4906     // initialize render stream according to desire buffer size
4907     float desiredBufferSize = stream_.bufferSize * renderSrRatio;
4908     REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) desiredBufferSize * 10000000 / renderFormat->nSamplesPerSec );
4909
4910     if ( !renderClient ) {
4911       hr = renderAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED,
4912                                           AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
4913                                           desiredBufferPeriod,
4914                                           desiredBufferPeriod,
4915                                           renderFormat,
4916                                           NULL );
4917       if ( FAILED( hr ) ) {
4918         errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize render audio client.";
4919         goto Exit;
4920       }
4921
4922       hr = renderAudioClient->GetService( __uuidof( IAudioRenderClient ),
4923                                           ( void** ) &renderClient );
4924       if ( FAILED( hr ) ) {
4925         errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render client handle.";
4926         goto Exit;
4927       }
4928
4929       // configure renderEvent to trigger on every available render buffer
4930       renderEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
4931       if ( !renderEvent ) {
4932         errorType = RtAudioError::SYSTEM_ERROR;
4933         errorText_ = "RtApiWasapi::wasapiThread: Unable to create render event.";
4934         goto Exit;
4935       }
4936
4937       hr = renderAudioClient->SetEventHandle( renderEvent );
4938       if ( FAILED( hr ) ) {
4939         errorText_ = "RtApiWasapi::wasapiThread: Unable to set render event handle.";
4940         goto Exit;
4941       }
4942
4943       ( ( WasapiHandle* ) stream_.apiHandle )->renderClient = renderClient;
4944       ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent = renderEvent;
4945     }
4946
4947     unsigned int outBufferSize = 0;
4948     hr = renderAudioClient->GetBufferSize( &outBufferSize );
4949     if ( FAILED( hr ) ) {
4950       errorText_ = "RtApiWasapi::wasapiThread: Unable to get render buffer size.";
4951       goto Exit;
4952     }
4953
4954     // scale inBufferSize according to user->stream sample rate ratio
4955     unsigned int inBufferSize = ( unsigned int ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT];
4956     outBufferSize *= stream_.nDeviceChannels[OUTPUT];
4957
4958     // set renderBuffer size
4959     renderBuffer.setBufferSize( inBufferSize + outBufferSize, formatBytes( stream_.deviceFormat[OUTPUT] ) );
4960
4961     // reset the render stream
4962     hr = renderAudioClient->Reset();
4963     if ( FAILED( hr ) ) {
4964       errorText_ = "RtApiWasapi::wasapiThread: Unable to reset render stream.";
4965       goto Exit;
4966     }
4967
4968     // start the render stream
4969     hr = renderAudioClient->Start();
4970     if ( FAILED( hr ) ) {
4971       errorText_ = "RtApiWasapi::wasapiThread: Unable to start render stream.";
4972       goto Exit;
4973     }
4974   }
4975
4976   if ( stream_.mode == INPUT ) {
4977     convBuffSize = ( size_t ) std::roundf( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] );
4978     deviceBuffSize = stream_.bufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] );
4979   }
4980   else if ( stream_.mode == OUTPUT ) {
4981     convBuffSize = ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] );
4982     deviceBuffSize = stream_.bufferSize * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] );
4983   }
4984   else if ( stream_.mode == DUPLEX ) {
4985     convBuffSize = std::max( ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),
4986                              ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) );
4987     deviceBuffSize = std::max( stream_.bufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),
4988                                stream_.bufferSize * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) );
4989   }
4990
4991   convBuffer = ( char* ) malloc( convBuffSize );
4992   stream_.deviceBuffer = ( char* ) malloc( deviceBuffSize );
4993   if ( !convBuffer || !stream_.deviceBuffer ) {
4994     errorType = RtAudioError::MEMORY_ERROR;
4995     errorText_ = "RtApiWasapi::wasapiThread: Error allocating device buffer memory.";
4996     goto Exit;
4997   }
4998
4999   // stream process loop
5000   while ( stream_.state != STREAM_STOPPING ) {
5001     if ( !callbackPulled ) {
5002       // Callback Input
5003       // ==============
5004       // 1. Pull callback buffer from inputBuffer
5005       // 2. If 1. was successful: Convert callback buffer to user sample rate and channel count
5006       //                          Convert callback buffer to user format
5007
5008       if ( captureAudioClient ) {
5009         // Pull callback buffer from inputBuffer
5010         callbackPulled = captureBuffer.pullBuffer( convBuffer,
5011                                                    ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT],
5012                                                    stream_.deviceFormat[INPUT] );
5013
5014         if ( callbackPulled ) {
5015           // Convert callback buffer to user sample rate
5016           convertBufferWasapi( stream_.deviceBuffer,
5017                                convBuffer,
5018                                stream_.nDeviceChannels[INPUT],
5019                                captureFormat->nSamplesPerSec,
5020                                stream_.sampleRate,
5021                                ( unsigned int ) ( stream_.bufferSize * captureSrRatio ),
5022                                convBufferSize,
5023                                stream_.deviceFormat[INPUT] );
5024
5025           if ( stream_.doConvertBuffer[INPUT] ) {
5026             // Convert callback buffer to user format
5027             convertBuffer( stream_.userBuffer[INPUT],
5028                            stream_.deviceBuffer,
5029                            stream_.convertInfo[INPUT] );
5030           }
5031           else {
5032             // no further conversion, simple copy deviceBuffer to userBuffer
5033             memcpy( stream_.userBuffer[INPUT],
5034                     stream_.deviceBuffer,
5035                     stream_.bufferSize * stream_.nUserChannels[INPUT] * formatBytes( stream_.userFormat ) );
5036           }
5037         }
5038       }
5039       else {
5040         // if there is no capture stream, set callbackPulled flag
5041         callbackPulled = true;
5042       }
5043
5044       // Execute Callback
5045       // ================
5046       // 1. Execute user callback method
5047       // 2. Handle return value from callback
5048
5049       // if callback has not requested the stream to stop
5050       if ( callbackPulled && !callbackStopped ) {
5051         // Execute user callback method
5052         callbackResult = callback( stream_.userBuffer[OUTPUT],
5053                                    stream_.userBuffer[INPUT],
5054                                    stream_.bufferSize,
5055                                    getStreamTime(),
5056                                    captureFlags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY ? RTAUDIO_INPUT_OVERFLOW : 0,
5057                                    stream_.callbackInfo.userData );
5058
5059         // Handle return value from callback
5060         if ( callbackResult == 1 ) {
5061           // instantiate a thread to stop this thread
5062           HANDLE threadHandle = CreateThread( NULL, 0, stopWasapiThread, this, 0, NULL );
5063           if ( !threadHandle ) {
5064             errorType = RtAudioError::THREAD_ERROR;
5065             errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream stop thread.";
5066             goto Exit;
5067           }
5068           else if ( !CloseHandle( threadHandle ) ) {
5069             errorType = RtAudioError::THREAD_ERROR;
5070             errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream stop thread handle.";
5071             goto Exit;
5072           }
5073
5074           callbackStopped = true;
5075         }
5076         else if ( callbackResult == 2 ) {
5077           // instantiate a thread to stop this thread
5078           HANDLE threadHandle = CreateThread( NULL, 0, abortWasapiThread, this, 0, NULL );
5079           if ( !threadHandle ) {
5080             errorType = RtAudioError::THREAD_ERROR;
5081             errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream abort thread.";
5082             goto Exit;
5083           }
5084           else if ( !CloseHandle( threadHandle ) ) {
5085             errorType = RtAudioError::THREAD_ERROR;
5086             errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream abort thread handle.";
5087             goto Exit;
5088           }
5089
5090           callbackStopped = true;
5091         }
5092       }
5093     }
5094
5095     // Callback Output
5096     // ===============
5097     // 1. Convert callback buffer to stream format
5098     // 2. Convert callback buffer to stream sample rate and channel count
5099     // 3. Push callback buffer into outputBuffer
5100
5101     if ( renderAudioClient && callbackPulled ) {
5102       if ( stream_.doConvertBuffer[OUTPUT] ) {
5103         // Convert callback buffer to stream format
5104         convertBuffer( stream_.deviceBuffer,
5105                        stream_.userBuffer[OUTPUT],
5106                        stream_.convertInfo[OUTPUT] );
5107
5108       }
5109
5110       // Convert callback buffer to stream sample rate
5111       convertBufferWasapi( convBuffer,
5112                            stream_.deviceBuffer,
5113                            stream_.nDeviceChannels[OUTPUT],
5114                            stream_.sampleRate,
5115                            renderFormat->nSamplesPerSec,
5116                            stream_.bufferSize,
5117                            convBufferSize,
5118                            stream_.deviceFormat[OUTPUT] );
5119
5120       // Push callback buffer into outputBuffer
5121       callbackPushed = renderBuffer.pushBuffer( convBuffer,
5122                                                 convBufferSize * stream_.nDeviceChannels[OUTPUT],
5123                                                 stream_.deviceFormat[OUTPUT] );
5124     }
5125     else {
5126       // if there is no render stream, set callbackPushed flag
5127       callbackPushed = true;
5128     }
5129
5130     // Stream Capture
5131     // ==============
5132     // 1. Get capture buffer from stream
5133     // 2. Push capture buffer into inputBuffer
5134     // 3. If 2. was successful: Release capture buffer
5135
5136     if ( captureAudioClient ) {
5137       // if the callback input buffer was not pulled from captureBuffer, wait for next capture event
5138       if ( !callbackPulled ) {
5139         WaitForSingleObject( captureEvent, INFINITE );
5140       }
5141
5142       // Get capture buffer from stream
5143       hr = captureClient->GetBuffer( &streamBuffer,
5144                                      &bufferFrameCount,
5145                                      &captureFlags, NULL, NULL );
5146       if ( FAILED( hr ) ) {
5147         errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture buffer.";
5148         goto Exit;
5149       }
5150
5151       if ( bufferFrameCount != 0 ) {
5152         // Push capture buffer into inputBuffer
5153         if ( captureBuffer.pushBuffer( ( char* ) streamBuffer,
5154                                        bufferFrameCount * stream_.nDeviceChannels[INPUT],
5155                                        stream_.deviceFormat[INPUT] ) )
5156         {
5157           // Release capture buffer
5158           hr = captureClient->ReleaseBuffer( bufferFrameCount );
5159           if ( FAILED( hr ) ) {
5160             errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
5161             goto Exit;
5162           }
5163         }
5164         else
5165         {
5166           // Inform WASAPI that capture was unsuccessful
5167           hr = captureClient->ReleaseBuffer( 0 );
5168           if ( FAILED( hr ) ) {
5169             errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
5170             goto Exit;
5171           }
5172         }
5173       }
5174       else
5175       {
5176         // Inform WASAPI that capture was unsuccessful
5177         hr = captureClient->ReleaseBuffer( 0 );
5178         if ( FAILED( hr ) ) {
5179           errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
5180           goto Exit;
5181         }
5182       }
5183     }
5184
5185     // Stream Render
5186     // =============
5187     // 1. Get render buffer from stream
5188     // 2. Pull next buffer from outputBuffer
5189     // 3. If 2. was successful: Fill render buffer with next buffer
5190     //                          Release render buffer
5191
5192     if ( renderAudioClient ) {
5193       // if the callback output buffer was not pushed to renderBuffer, wait for next render event
5194       if ( callbackPulled && !callbackPushed ) {
5195         WaitForSingleObject( renderEvent, INFINITE );
5196       }
5197
5198       // Get render buffer from stream
5199       hr = renderAudioClient->GetBufferSize( &bufferFrameCount );
5200       if ( FAILED( hr ) ) {
5201         errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer size.";
5202         goto Exit;
5203       }
5204
5205       hr = renderAudioClient->GetCurrentPadding( &numFramesPadding );
5206       if ( FAILED( hr ) ) {
5207         errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer padding.";
5208         goto Exit;
5209       }
5210
5211       bufferFrameCount -= numFramesPadding;
5212
5213       if ( bufferFrameCount != 0 ) {
5214         hr = renderClient->GetBuffer( bufferFrameCount, &streamBuffer );
5215         if ( FAILED( hr ) ) {
5216           errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer.";
5217           goto Exit;
5218         }
5219
5220         // Pull next buffer from outputBuffer
5221         // Fill render buffer with next buffer
5222         if ( renderBuffer.pullBuffer( ( char* ) streamBuffer,
5223                                       bufferFrameCount * stream_.nDeviceChannels[OUTPUT],
5224                                       stream_.deviceFormat[OUTPUT] ) )
5225         {
5226           // Release render buffer
5227           hr = renderClient->ReleaseBuffer( bufferFrameCount, 0 );
5228           if ( FAILED( hr ) ) {
5229             errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
5230             goto Exit;
5231           }
5232         }
5233         else
5234         {
5235           // Inform WASAPI that render was unsuccessful
5236           hr = renderClient->ReleaseBuffer( 0, 0 );
5237           if ( FAILED( hr ) ) {
5238             errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
5239             goto Exit;
5240           }
5241         }
5242       }
5243       else
5244       {
5245         // Inform WASAPI that render was unsuccessful
5246         hr = renderClient->ReleaseBuffer( 0, 0 );
5247         if ( FAILED( hr ) ) {
5248           errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
5249           goto Exit;
5250         }
5251       }
5252     }
5253
5254     // if the callback buffer was pushed renderBuffer reset callbackPulled flag
5255     if ( callbackPushed ) {
5256       callbackPulled = false;
5257       // tick stream time
5258       RtApi::tickStreamTime();
5259     }
5260
5261   }
5262
5263 Exit:
5264   // clean up
5265   CoTaskMemFree( captureFormat );
5266   CoTaskMemFree( renderFormat );
5267
5268   free ( convBuffer );
5269
5270   CoUninitialize();
5271
5272   // update stream state
5273   stream_.state = STREAM_STOPPED;
5274
5275   if ( errorText_.empty() )
5276     return;
5277   else
5278     error( errorType );
5279 }
5280
5281 //******************** End of __WINDOWS_WASAPI__ *********************//
5282 #endif
5283
5284
5285 #if defined(__WINDOWS_DS__) // Windows DirectSound API
5286
5287 // Modified by Robin Davies, October 2005
5288 // - Improvements to DirectX pointer chasing. 
5289 // - Bug fix for non-power-of-two Asio granularity used by Edirol PCR-A30.
5290 // - Auto-call CoInitialize for DSOUND and ASIO platforms.
5291 // Various revisions for RtAudio 4.0 by Gary Scavone, April 2007
5292 // Changed device query structure for RtAudio 4.0.7, January 2010
5293
5294 #include <mmsystem.h>
5295 #include <mmreg.h>
5296 #include <dsound.h>
5297 #include <assert.h>
5298 #include <algorithm>
5299
5300 #if defined(__MINGW32__)
5301   // missing from latest mingw winapi
5302 #define WAVE_FORMAT_96M08 0x00010000 /* 96 kHz, Mono, 8-bit */
5303 #define WAVE_FORMAT_96S08 0x00020000 /* 96 kHz, Stereo, 8-bit */
5304 #define WAVE_FORMAT_96M16 0x00040000 /* 96 kHz, Mono, 16-bit */
5305 #define WAVE_FORMAT_96S16 0x00080000 /* 96 kHz, Stereo, 16-bit */
5306 #endif
5307
5308 #define MINIMUM_DEVICE_BUFFER_SIZE 32768
5309
5310 #ifdef _MSC_VER // if Microsoft Visual C++
5311 #pragma comment( lib, "winmm.lib" ) // then, auto-link winmm.lib. Otherwise, it has to be added manually.
5312 #endif
5313
5314 static inline DWORD dsPointerBetween( DWORD pointer, DWORD laterPointer, DWORD earlierPointer, DWORD bufferSize )
5315 {
5316   if ( pointer > bufferSize ) pointer -= bufferSize;
5317   if ( laterPointer < earlierPointer ) laterPointer += bufferSize;
5318   if ( pointer < earlierPointer ) pointer += bufferSize;
5319   return pointer >= earlierPointer && pointer < laterPointer;
5320 }
5321
5322 // A structure to hold various information related to the DirectSound
5323 // API implementation.
5324 struct DsHandle {
5325   unsigned int drainCounter; // Tracks callback counts when draining
5326   bool internalDrain;        // Indicates if stop is initiated from callback or not.
5327   void *id[2];
5328   void *buffer[2];
5329   bool xrun[2];
5330   UINT bufferPointer[2];  
5331   DWORD dsBufferSize[2];
5332   DWORD dsPointerLeadTime[2]; // the number of bytes ahead of the safe pointer to lead by.
5333   HANDLE condition;
5334
5335   DsHandle()
5336     :drainCounter(0), internalDrain(false) { id[0] = 0; id[1] = 0; buffer[0] = 0; buffer[1] = 0; xrun[0] = false; xrun[1] = false; bufferPointer[0] = 0; bufferPointer[1] = 0; }
5337 };
5338
5339 // Declarations for utility functions, callbacks, and structures
5340 // specific to the DirectSound implementation.
5341 static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
5342                                           LPCTSTR description,
5343                                           LPCTSTR module,
5344                                           LPVOID lpContext );
5345
5346 static const char* getErrorString( int code );
5347
5348 static unsigned __stdcall callbackHandler( void *ptr );
5349
5350 struct DsDevice {
5351   LPGUID id[2];
5352   bool validId[2];
5353   bool found;
5354   std::string name;
5355
5356   DsDevice()
5357   : found(false) { validId[0] = false; validId[1] = false; }
5358 };
5359
5360 struct DsProbeData {
5361   bool isInput;
5362   std::vector<struct DsDevice>* dsDevices;
5363 };
5364
5365 RtApiDs :: RtApiDs()
5366 {
5367   // Dsound will run both-threaded. If CoInitialize fails, then just
5368   // accept whatever the mainline chose for a threading model.
5369   coInitialized_ = false;
5370   HRESULT hr = CoInitialize( NULL );
5371   if ( !FAILED( hr ) ) coInitialized_ = true;
5372 }
5373
5374 RtApiDs :: ~RtApiDs()
5375 {
5376   if ( stream_.state != STREAM_CLOSED ) closeStream();
5377   if ( coInitialized_ ) CoUninitialize(); // balanced call.
5378 }
5379
5380 // The DirectSound default output is always the first device.
5381 unsigned int RtApiDs :: getDefaultOutputDevice( void )
5382 {
5383   return 0;
5384 }
5385
5386 // The DirectSound default input is always the first input device,
5387 // which is the first capture device enumerated.
5388 unsigned int RtApiDs :: getDefaultInputDevice( void )
5389 {
5390   return 0;
5391 }
5392
5393 unsigned int RtApiDs :: getDeviceCount( void )
5394 {
5395   // Set query flag for previously found devices to false, so that we
5396   // can check for any devices that have disappeared.
5397   for ( unsigned int i=0; i<dsDevices.size(); i++ )
5398     dsDevices[i].found = false;
5399
5400   // Query DirectSound devices.
5401   struct DsProbeData probeInfo;
5402   probeInfo.isInput = false;
5403   probeInfo.dsDevices = &dsDevices;
5404   HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );
5405   if ( FAILED( result ) ) {
5406     errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating output devices!";
5407     errorText_ = errorStream_.str();
5408     error( RtAudioError::WARNING );
5409   }
5410
5411   // Query DirectSoundCapture devices.
5412   probeInfo.isInput = true;
5413   result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );
5414   if ( FAILED( result ) ) {
5415     errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating input devices!";
5416     errorText_ = errorStream_.str();
5417     error( RtAudioError::WARNING );
5418   }
5419
5420   // Clean out any devices that may have disappeared (code update submitted by Eli Zehngut).
5421   for ( unsigned int i=0; i<dsDevices.size(); ) {
5422     if ( dsDevices[i].found == false ) dsDevices.erase( dsDevices.begin() + i );
5423     else i++;
5424   }
5425
5426   return static_cast<unsigned int>(dsDevices.size());
5427 }
5428
5429 RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
5430 {
5431   RtAudio::DeviceInfo info;
5432   info.probed = false;
5433
5434   if ( dsDevices.size() == 0 ) {
5435     // Force a query of all devices
5436     getDeviceCount();
5437     if ( dsDevices.size() == 0 ) {
5438       errorText_ = "RtApiDs::getDeviceInfo: no devices found!";
5439       error( RtAudioError::INVALID_USE );
5440       return info;
5441     }
5442   }
5443
5444   if ( device >= dsDevices.size() ) {
5445     errorText_ = "RtApiDs::getDeviceInfo: device ID is invalid!";
5446     error( RtAudioError::INVALID_USE );
5447     return info;
5448   }
5449
5450   HRESULT result;
5451   if ( dsDevices[ device ].validId[0] == false ) goto probeInput;
5452
5453   LPDIRECTSOUND output;
5454   DSCAPS outCaps;
5455   result = DirectSoundCreate( dsDevices[ device ].id[0], &output, NULL );
5456   if ( FAILED( result ) ) {
5457     errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!";
5458     errorText_ = errorStream_.str();
5459     error( RtAudioError::WARNING );
5460     goto probeInput;
5461   }
5462
5463   outCaps.dwSize = sizeof( outCaps );
5464   result = output->GetCaps( &outCaps );
5465   if ( FAILED( result ) ) {
5466     output->Release();
5467     errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting capabilities!";
5468     errorText_ = errorStream_.str();
5469     error( RtAudioError::WARNING );
5470     goto probeInput;
5471   }
5472
5473   // Get output channel information.
5474   info.outputChannels = ( outCaps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
5475
5476   // Get sample rate information.
5477   info.sampleRates.clear();
5478   for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
5479     if ( SAMPLE_RATES[k] >= (unsigned int) outCaps.dwMinSecondarySampleRate &&
5480          SAMPLE_RATES[k] <= (unsigned int) outCaps.dwMaxSecondarySampleRate ) {
5481       info.sampleRates.push_back( SAMPLE_RATES[k] );
5482
5483       if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )
5484         info.preferredSampleRate = SAMPLE_RATES[k];
5485     }
5486   }
5487
5488   // Get format information.
5489   if ( outCaps.dwFlags & DSCAPS_PRIMARY16BIT ) info.nativeFormats |= RTAUDIO_SINT16;
5490   if ( outCaps.dwFlags & DSCAPS_PRIMARY8BIT ) info.nativeFormats |= RTAUDIO_SINT8;
5491
5492   output->Release();
5493
5494   if ( getDefaultOutputDevice() == device )
5495     info.isDefaultOutput = true;
5496
5497   if ( dsDevices[ device ].validId[1] == false ) {
5498     info.name = dsDevices[ device ].name;
5499     info.probed = true;
5500     return info;
5501   }
5502
5503  probeInput:
5504
5505   LPDIRECTSOUNDCAPTURE input;
5506   result = DirectSoundCaptureCreate( dsDevices[ device ].id[1], &input, NULL );
5507   if ( FAILED( result ) ) {
5508     errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!";
5509     errorText_ = errorStream_.str();
5510     error( RtAudioError::WARNING );
5511     return info;
5512   }
5513
5514   DSCCAPS inCaps;
5515   inCaps.dwSize = sizeof( inCaps );
5516   result = input->GetCaps( &inCaps );
5517   if ( FAILED( result ) ) {
5518     input->Release();
5519     errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting object capabilities (" << dsDevices[ device ].name << ")!";
5520     errorText_ = errorStream_.str();
5521     error( RtAudioError::WARNING );
5522     return info;
5523   }
5524
5525   // Get input channel information.
5526   info.inputChannels = inCaps.dwChannels;
5527
5528   // Get sample rate and format information.
5529   std::vector<unsigned int> rates;
5530   if ( inCaps.dwChannels >= 2 ) {
5531     if ( inCaps.dwFormats & WAVE_FORMAT_1S16 ) info.nativeFormats |= RTAUDIO_SINT16;
5532     if ( inCaps.dwFormats & WAVE_FORMAT_2S16 ) info.nativeFormats |= RTAUDIO_SINT16;
5533     if ( inCaps.dwFormats & WAVE_FORMAT_4S16 ) info.nativeFormats |= RTAUDIO_SINT16;
5534     if ( inCaps.dwFormats & WAVE_FORMAT_96S16 ) info.nativeFormats |= RTAUDIO_SINT16;
5535     if ( inCaps.dwFormats & WAVE_FORMAT_1S08 ) info.nativeFormats |= RTAUDIO_SINT8;
5536     if ( inCaps.dwFormats & WAVE_FORMAT_2S08 ) info.nativeFormats |= RTAUDIO_SINT8;
5537     if ( inCaps.dwFormats & WAVE_FORMAT_4S08 ) info.nativeFormats |= RTAUDIO_SINT8;
5538     if ( inCaps.dwFormats & WAVE_FORMAT_96S08 ) info.nativeFormats |= RTAUDIO_SINT8;
5539
5540     if ( info.nativeFormats & RTAUDIO_SINT16 ) {
5541       if ( inCaps.dwFormats & WAVE_FORMAT_1S16 ) rates.push_back( 11025 );
5542       if ( inCaps.dwFormats & WAVE_FORMAT_2S16 ) rates.push_back( 22050 );
5543       if ( inCaps.dwFormats & WAVE_FORMAT_4S16 ) rates.push_back( 44100 );
5544       if ( inCaps.dwFormats & WAVE_FORMAT_96S16 ) rates.push_back( 96000 );
5545     }
5546     else if ( info.nativeFormats & RTAUDIO_SINT8 ) {
5547       if ( inCaps.dwFormats & WAVE_FORMAT_1S08 ) rates.push_back( 11025 );
5548       if ( inCaps.dwFormats & WAVE_FORMAT_2S08 ) rates.push_back( 22050 );
5549       if ( inCaps.dwFormats & WAVE_FORMAT_4S08 ) rates.push_back( 44100 );
5550       if ( inCaps.dwFormats & WAVE_FORMAT_96S08 ) rates.push_back( 96000 );
5551     }
5552   }
5553   else if ( inCaps.dwChannels == 1 ) {
5554     if ( inCaps.dwFormats & WAVE_FORMAT_1M16 ) info.nativeFormats |= RTAUDIO_SINT16;
5555     if ( inCaps.dwFormats & WAVE_FORMAT_2M16 ) info.nativeFormats |= RTAUDIO_SINT16;
5556     if ( inCaps.dwFormats & WAVE_FORMAT_4M16 ) info.nativeFormats |= RTAUDIO_SINT16;
5557     if ( inCaps.dwFormats & WAVE_FORMAT_96M16 ) info.nativeFormats |= RTAUDIO_SINT16;
5558     if ( inCaps.dwFormats & WAVE_FORMAT_1M08 ) info.nativeFormats |= RTAUDIO_SINT8;
5559     if ( inCaps.dwFormats & WAVE_FORMAT_2M08 ) info.nativeFormats |= RTAUDIO_SINT8;
5560     if ( inCaps.dwFormats & WAVE_FORMAT_4M08 ) info.nativeFormats |= RTAUDIO_SINT8;
5561     if ( inCaps.dwFormats & WAVE_FORMAT_96M08 ) info.nativeFormats |= RTAUDIO_SINT8;
5562
5563     if ( info.nativeFormats & RTAUDIO_SINT16 ) {
5564       if ( inCaps.dwFormats & WAVE_FORMAT_1M16 ) rates.push_back( 11025 );
5565       if ( inCaps.dwFormats & WAVE_FORMAT_2M16 ) rates.push_back( 22050 );
5566       if ( inCaps.dwFormats & WAVE_FORMAT_4M16 ) rates.push_back( 44100 );
5567       if ( inCaps.dwFormats & WAVE_FORMAT_96M16 ) rates.push_back( 96000 );
5568     }
5569     else if ( info.nativeFormats & RTAUDIO_SINT8 ) {
5570       if ( inCaps.dwFormats & WAVE_FORMAT_1M08 ) rates.push_back( 11025 );
5571       if ( inCaps.dwFormats & WAVE_FORMAT_2M08 ) rates.push_back( 22050 );
5572       if ( inCaps.dwFormats & WAVE_FORMAT_4M08 ) rates.push_back( 44100 );
5573       if ( inCaps.dwFormats & WAVE_FORMAT_96M08 ) rates.push_back( 96000 );
5574     }
5575   }
5576   else info.inputChannels = 0; // technically, this would be an error
5577
5578   input->Release();
5579
5580   if ( info.inputChannels == 0 ) return info;
5581
5582   // Copy the supported rates to the info structure but avoid duplication.
5583   bool found;
5584   for ( unsigned int i=0; i<rates.size(); i++ ) {
5585     found = false;
5586     for ( unsigned int j=0; j<info.sampleRates.size(); j++ ) {
5587       if ( rates[i] == info.sampleRates[j] ) {
5588         found = true;
5589         break;
5590       }
5591     }
5592     if ( found == false ) info.sampleRates.push_back( rates[i] );
5593   }
5594   std::sort( info.sampleRates.begin(), info.sampleRates.end() );
5595
5596   // If device opens for both playback and capture, we determine the channels.
5597   if ( info.outputChannels > 0 && info.inputChannels > 0 )
5598     info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
5599
5600   if ( device == 0 ) info.isDefaultInput = true;
5601
5602   // Copy name and return.
5603   info.name = dsDevices[ device ].name;
5604   info.probed = true;
5605   return info;
5606 }
5607
5608 bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
5609                                  unsigned int firstChannel, unsigned int sampleRate,
5610                                  RtAudioFormat format, unsigned int *bufferSize,
5611                                  RtAudio::StreamOptions *options )
5612 {
5613   if ( channels + firstChannel > 2 ) {
5614     errorText_ = "RtApiDs::probeDeviceOpen: DirectSound does not support more than 2 channels per device.";
5615     return FAILURE;
5616   }
5617
5618   size_t nDevices = dsDevices.size();
5619   if ( nDevices == 0 ) {
5620     // This should not happen because a check is made before this function is called.
5621     errorText_ = "RtApiDs::probeDeviceOpen: no devices found!";
5622     return FAILURE;
5623   }
5624
5625   if ( device >= nDevices ) {
5626     // This should not happen because a check is made before this function is called.
5627     errorText_ = "RtApiDs::probeDeviceOpen: device ID is invalid!";
5628     return FAILURE;
5629   }
5630
5631   if ( mode == OUTPUT ) {
5632     if ( dsDevices[ device ].validId[0] == false ) {
5633       errorStream_ << "RtApiDs::probeDeviceOpen: device (" << device << ") does not support output!";
5634       errorText_ = errorStream_.str();
5635       return FAILURE;
5636     }
5637   }
5638   else { // mode == INPUT
5639     if ( dsDevices[ device ].validId[1] == false ) {
5640       errorStream_ << "RtApiDs::probeDeviceOpen: device (" << device << ") does not support input!";
5641       errorText_ = errorStream_.str();
5642       return FAILURE;
5643     }
5644   }
5645
5646   // According to a note in PortAudio, using GetDesktopWindow()
5647   // instead of GetForegroundWindow() is supposed to avoid problems
5648   // that occur when the application's window is not the foreground
5649   // window.  Also, if the application window closes before the
5650   // DirectSound buffer, DirectSound can crash.  In the past, I had
5651   // problems when using GetDesktopWindow() but it seems fine now
5652   // (January 2010).  I'll leave it commented here.
5653   // HWND hWnd = GetForegroundWindow();
5654   HWND hWnd = GetDesktopWindow();
5655
5656   // Check the numberOfBuffers parameter and limit the lowest value to
5657   // two.  This is a judgement call and a value of two is probably too
5658   // low for capture, but it should work for playback.
5659   int nBuffers = 0;
5660   if ( options ) nBuffers = options->numberOfBuffers;
5661   if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) nBuffers = 2;
5662   if ( nBuffers < 2 ) nBuffers = 3;
5663
5664   // Check the lower range of the user-specified buffer size and set
5665   // (arbitrarily) to a lower bound of 32.
5666   if ( *bufferSize < 32 ) *bufferSize = 32;
5667
5668   // Create the wave format structure.  The data format setting will
5669   // be determined later.
5670   WAVEFORMATEX waveFormat;
5671   ZeroMemory( &waveFormat, sizeof(WAVEFORMATEX) );
5672   waveFormat.wFormatTag = WAVE_FORMAT_PCM;
5673   waveFormat.nChannels = channels + firstChannel;
5674   waveFormat.nSamplesPerSec = (unsigned long) sampleRate;
5675
5676   // Determine the device buffer size. By default, we'll use the value
5677   // defined above (32K), but we will grow it to make allowances for
5678   // very large software buffer sizes.
5679   DWORD dsBufferSize = MINIMUM_DEVICE_BUFFER_SIZE;
5680   DWORD dsPointerLeadTime = 0;
5681
5682   void *ohandle = 0, *bhandle = 0;
5683   HRESULT result;
5684   if ( mode == OUTPUT ) {
5685
5686     LPDIRECTSOUND output;
5687     result = DirectSoundCreate( dsDevices[ device ].id[0], &output, NULL );
5688     if ( FAILED( result ) ) {
5689       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!";
5690       errorText_ = errorStream_.str();
5691       return FAILURE;
5692     }
5693
5694     DSCAPS outCaps;
5695     outCaps.dwSize = sizeof( outCaps );
5696     result = output->GetCaps( &outCaps );
5697     if ( FAILED( result ) ) {
5698       output->Release();
5699       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting capabilities (" << dsDevices[ device ].name << ")!";
5700       errorText_ = errorStream_.str();
5701       return FAILURE;
5702     }
5703
5704     // Check channel information.
5705     if ( channels + firstChannel == 2 && !( outCaps.dwFlags & DSCAPS_PRIMARYSTEREO ) ) {
5706       errorStream_ << "RtApiDs::getDeviceInfo: the output device (" << dsDevices[ device ].name << ") does not support stereo playback.";
5707       errorText_ = errorStream_.str();
5708       return FAILURE;
5709     }
5710
5711     // Check format information.  Use 16-bit format unless not
5712     // supported or user requests 8-bit.
5713     if ( outCaps.dwFlags & DSCAPS_PRIMARY16BIT &&
5714          !( format == RTAUDIO_SINT8 && outCaps.dwFlags & DSCAPS_PRIMARY8BIT ) ) {
5715       waveFormat.wBitsPerSample = 16;
5716       stream_.deviceFormat[mode] = RTAUDIO_SINT16;
5717     }
5718     else {
5719       waveFormat.wBitsPerSample = 8;
5720       stream_.deviceFormat[mode] = RTAUDIO_SINT8;
5721     }
5722     stream_.userFormat = format;
5723
5724     // Update wave format structure and buffer information.
5725     waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
5726     waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
5727     dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels;
5728
5729     // If the user wants an even bigger buffer, increase the device buffer size accordingly.
5730     while ( dsPointerLeadTime * 2U > dsBufferSize )
5731       dsBufferSize *= 2;
5732
5733     // Set cooperative level to DSSCL_EXCLUSIVE ... sound stops when window focus changes.
5734     // result = output->SetCooperativeLevel( hWnd, DSSCL_EXCLUSIVE );
5735     // Set cooperative level to DSSCL_PRIORITY ... sound remains when window focus changes.
5736     result = output->SetCooperativeLevel( hWnd, DSSCL_PRIORITY );
5737     if ( FAILED( result ) ) {
5738       output->Release();
5739       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting cooperative level (" << dsDevices[ device ].name << ")!";
5740       errorText_ = errorStream_.str();
5741       return FAILURE;
5742     }
5743
5744     // Even though we will write to the secondary buffer, we need to
5745     // access the primary buffer to set the correct output format
5746     // (since the default is 8-bit, 22 kHz!).  Setup the DS primary
5747     // buffer description.
5748     DSBUFFERDESC bufferDescription;
5749     ZeroMemory( &bufferDescription, sizeof( DSBUFFERDESC ) );
5750     bufferDescription.dwSize = sizeof( DSBUFFERDESC );
5751     bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
5752
5753     // Obtain the primary buffer
5754     LPDIRECTSOUNDBUFFER buffer;
5755     result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );
5756     if ( FAILED( result ) ) {
5757       output->Release();
5758       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") accessing primary buffer (" << dsDevices[ device ].name << ")!";
5759       errorText_ = errorStream_.str();
5760       return FAILURE;
5761     }
5762
5763     // Set the primary DS buffer sound format.
5764     result = buffer->SetFormat( &waveFormat );
5765     if ( FAILED( result ) ) {
5766       output->Release();
5767       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting primary buffer format (" << dsDevices[ device ].name << ")!";
5768       errorText_ = errorStream_.str();
5769       return FAILURE;
5770     }
5771
5772     // Setup the secondary DS buffer description.
5773     ZeroMemory( &bufferDescription, sizeof( DSBUFFERDESC ) );
5774     bufferDescription.dwSize = sizeof( DSBUFFERDESC );
5775     bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
5776                                   DSBCAPS_GLOBALFOCUS |
5777                                   DSBCAPS_GETCURRENTPOSITION2 |
5778                                   DSBCAPS_LOCHARDWARE );  // Force hardware mixing
5779     bufferDescription.dwBufferBytes = dsBufferSize;
5780     bufferDescription.lpwfxFormat = &waveFormat;
5781
5782     // Try to create the secondary DS buffer.  If that doesn't work,
5783     // try to use software mixing.  Otherwise, there's a problem.
5784     result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );
5785     if ( FAILED( result ) ) {
5786       bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
5787                                     DSBCAPS_GLOBALFOCUS |
5788                                     DSBCAPS_GETCURRENTPOSITION2 |
5789                                     DSBCAPS_LOCSOFTWARE );  // Force software mixing
5790       result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );
5791       if ( FAILED( result ) ) {
5792         output->Release();
5793         errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating secondary buffer (" << dsDevices[ device ].name << ")!";
5794         errorText_ = errorStream_.str();
5795         return FAILURE;
5796       }
5797     }
5798
5799     // Get the buffer size ... might be different from what we specified.
5800     DSBCAPS dsbcaps;
5801     dsbcaps.dwSize = sizeof( DSBCAPS );
5802     result = buffer->GetCaps( &dsbcaps );
5803     if ( FAILED( result ) ) {
5804       output->Release();
5805       buffer->Release();
5806       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsDevices[ device ].name << ")!";
5807       errorText_ = errorStream_.str();
5808       return FAILURE;
5809     }
5810
5811     dsBufferSize = dsbcaps.dwBufferBytes;
5812
5813     // Lock the DS buffer
5814     LPVOID audioPtr;
5815     DWORD dataLen;
5816     result = buffer->Lock( 0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0 );
5817     if ( FAILED( result ) ) {
5818       output->Release();
5819       buffer->Release();
5820       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") locking buffer (" << dsDevices[ device ].name << ")!";
5821       errorText_ = errorStream_.str();
5822       return FAILURE;
5823     }
5824
5825     // Zero the DS buffer
5826     ZeroMemory( audioPtr, dataLen );
5827
5828     // Unlock the DS buffer
5829     result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );
5830     if ( FAILED( result ) ) {
5831       output->Release();
5832       buffer->Release();
5833       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking buffer (" << dsDevices[ device ].name << ")!";
5834       errorText_ = errorStream_.str();
5835       return FAILURE;
5836     }
5837
5838     ohandle = (void *) output;
5839     bhandle = (void *) buffer;
5840   }
5841
5842   if ( mode == INPUT ) {
5843
5844     LPDIRECTSOUNDCAPTURE input;
5845     result = DirectSoundCaptureCreate( dsDevices[ device ].id[1], &input, NULL );
5846     if ( FAILED( result ) ) {
5847       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!";
5848       errorText_ = errorStream_.str();
5849       return FAILURE;
5850     }
5851
5852     DSCCAPS inCaps;
5853     inCaps.dwSize = sizeof( inCaps );
5854     result = input->GetCaps( &inCaps );
5855     if ( FAILED( result ) ) {
5856       input->Release();
5857       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting input capabilities (" << dsDevices[ device ].name << ")!";
5858       errorText_ = errorStream_.str();
5859       return FAILURE;
5860     }
5861
5862     // Check channel information.
5863     if ( inCaps.dwChannels < channels + firstChannel ) {
5864       errorText_ = "RtApiDs::getDeviceInfo: the input device does not support requested input channels.";
5865       return FAILURE;
5866     }
5867
5868     // Check format information.  Use 16-bit format unless user
5869     // requests 8-bit.
5870     DWORD deviceFormats;
5871     if ( channels + firstChannel == 2 ) {
5872       deviceFormats = WAVE_FORMAT_1S08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_96S08;
5873       if ( format == RTAUDIO_SINT8 && inCaps.dwFormats & deviceFormats ) {
5874         waveFormat.wBitsPerSample = 8;
5875         stream_.deviceFormat[mode] = RTAUDIO_SINT8;
5876       }
5877       else { // assume 16-bit is supported
5878         waveFormat.wBitsPerSample = 16;
5879         stream_.deviceFormat[mode] = RTAUDIO_SINT16;
5880       }
5881     }
5882     else { // channel == 1
5883       deviceFormats = WAVE_FORMAT_1M08 | WAVE_FORMAT_2M08 | WAVE_FORMAT_4M08 | WAVE_FORMAT_96M08;
5884       if ( format == RTAUDIO_SINT8 && inCaps.dwFormats & deviceFormats ) {
5885         waveFormat.wBitsPerSample = 8;
5886         stream_.deviceFormat[mode] = RTAUDIO_SINT8;
5887       }
5888       else { // assume 16-bit is supported
5889         waveFormat.wBitsPerSample = 16;
5890         stream_.deviceFormat[mode] = RTAUDIO_SINT16;
5891       }
5892     }
5893     stream_.userFormat = format;
5894
5895     // Update wave format structure and buffer information.
5896     waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
5897     waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
5898     dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels;
5899
5900     // If the user wants an even bigger buffer, increase the device buffer size accordingly.
5901     while ( dsPointerLeadTime * 2U > dsBufferSize )
5902       dsBufferSize *= 2;
5903
5904     // Setup the secondary DS buffer description.
5905     DSCBUFFERDESC bufferDescription;
5906     ZeroMemory( &bufferDescription, sizeof( DSCBUFFERDESC ) );
5907     bufferDescription.dwSize = sizeof( DSCBUFFERDESC );
5908     bufferDescription.dwFlags = 0;
5909     bufferDescription.dwReserved = 0;
5910     bufferDescription.dwBufferBytes = dsBufferSize;
5911     bufferDescription.lpwfxFormat = &waveFormat;
5912
5913     // Create the capture buffer.
5914     LPDIRECTSOUNDCAPTUREBUFFER buffer;
5915     result = input->CreateCaptureBuffer( &bufferDescription, &buffer, NULL );
5916     if ( FAILED( result ) ) {
5917       input->Release();
5918       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating input buffer (" << dsDevices[ device ].name << ")!";
5919       errorText_ = errorStream_.str();
5920       return FAILURE;
5921     }
5922
5923     // Get the buffer size ... might be different from what we specified.
5924     DSCBCAPS dscbcaps;
5925     dscbcaps.dwSize = sizeof( DSCBCAPS );
5926     result = buffer->GetCaps( &dscbcaps );
5927     if ( FAILED( result ) ) {
5928       input->Release();
5929       buffer->Release();
5930       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsDevices[ device ].name << ")!";
5931       errorText_ = errorStream_.str();
5932       return FAILURE;
5933     }
5934
5935     dsBufferSize = dscbcaps.dwBufferBytes;
5936
5937     // NOTE: We could have a problem here if this is a duplex stream
5938     // and the play and capture hardware buffer sizes are different
5939     // (I'm actually not sure if that is a problem or not).
5940     // Currently, we are not verifying that.
5941
5942     // Lock the capture buffer
5943     LPVOID audioPtr;
5944     DWORD dataLen;
5945     result = buffer->Lock( 0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0 );
5946     if ( FAILED( result ) ) {
5947       input->Release();
5948       buffer->Release();
5949       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") locking input buffer (" << dsDevices[ device ].name << ")!";
5950       errorText_ = errorStream_.str();
5951       return FAILURE;
5952     }
5953
5954     // Zero the buffer
5955     ZeroMemory( audioPtr, dataLen );
5956
5957     // Unlock the buffer
5958     result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );
5959     if ( FAILED( result ) ) {
5960       input->Release();
5961       buffer->Release();
5962       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking input buffer (" << dsDevices[ device ].name << ")!";
5963       errorText_ = errorStream_.str();
5964       return FAILURE;
5965     }
5966
5967     ohandle = (void *) input;
5968     bhandle = (void *) buffer;
5969   }
5970
5971   // Set various stream parameters
5972   DsHandle *handle = 0;
5973   stream_.nDeviceChannels[mode] = channels + firstChannel;
5974   stream_.nUserChannels[mode] = channels;
5975   stream_.bufferSize = *bufferSize;
5976   stream_.channelOffset[mode] = firstChannel;
5977   stream_.deviceInterleaved[mode] = true;
5978   if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;
5979   else stream_.userInterleaved = true;
5980
5981   // Set flag for buffer conversion
5982   stream_.doConvertBuffer[mode] = false;
5983   if (stream_.nUserChannels[mode] != stream_.nDeviceChannels[mode])
5984     stream_.doConvertBuffer[mode] = true;
5985   if (stream_.userFormat != stream_.deviceFormat[mode])
5986     stream_.doConvertBuffer[mode] = true;
5987   if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
5988        stream_.nUserChannels[mode] > 1 )
5989     stream_.doConvertBuffer[mode] = true;
5990
5991   // Allocate necessary internal buffers
5992   long bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
5993   stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
5994   if ( stream_.userBuffer[mode] == NULL ) {
5995     errorText_ = "RtApiDs::probeDeviceOpen: error allocating user buffer memory.";
5996     goto error;
5997   }
5998
5999   if ( stream_.doConvertBuffer[mode] ) {
6000
6001     bool makeBuffer = true;
6002     bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
6003     if ( mode == INPUT ) {
6004       if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
6005         unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
6006         if ( bufferBytes <= (long) bytesOut ) makeBuffer = false;
6007       }
6008     }
6009
6010     if ( makeBuffer ) {
6011       bufferBytes *= *bufferSize;
6012       if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
6013       stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
6014       if ( stream_.deviceBuffer == NULL ) {
6015         errorText_ = "RtApiDs::probeDeviceOpen: error allocating device buffer memory.";
6016         goto error;
6017       }
6018     }
6019   }
6020
6021   // Allocate our DsHandle structures for the stream.
6022   if ( stream_.apiHandle == 0 ) {
6023     try {
6024       handle = new DsHandle;
6025     }
6026     catch ( std::bad_alloc& ) {
6027       errorText_ = "RtApiDs::probeDeviceOpen: error allocating AsioHandle memory.";
6028       goto error;
6029     }
6030
6031     // Create a manual-reset event.
6032     handle->condition = CreateEvent( NULL,   // no security
6033                                      TRUE,   // manual-reset
6034                                      FALSE,  // non-signaled initially
6035                                      NULL ); // unnamed
6036     stream_.apiHandle = (void *) handle;
6037   }
6038   else
6039     handle = (DsHandle *) stream_.apiHandle;
6040   handle->id[mode] = ohandle;
6041   handle->buffer[mode] = bhandle;
6042   handle->dsBufferSize[mode] = dsBufferSize;
6043   handle->dsPointerLeadTime[mode] = dsPointerLeadTime;
6044
6045   stream_.device[mode] = device;
6046   stream_.state = STREAM_STOPPED;
6047   if ( stream_.mode == OUTPUT && mode == INPUT )
6048     // We had already set up an output stream.
6049     stream_.mode = DUPLEX;
6050   else
6051     stream_.mode = mode;
6052   stream_.nBuffers = nBuffers;
6053   stream_.sampleRate = sampleRate;
6054
6055   // Setup the buffer conversion information structure.
6056   if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );
6057
6058   // Setup the callback thread.
6059   if ( stream_.callbackInfo.isRunning == false ) {
6060     unsigned threadId;
6061     stream_.callbackInfo.isRunning = true;
6062     stream_.callbackInfo.object = (void *) this;
6063     stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &callbackHandler,
6064                                                   &stream_.callbackInfo, 0, &threadId );
6065     if ( stream_.callbackInfo.thread == 0 ) {
6066       errorText_ = "RtApiDs::probeDeviceOpen: error creating callback thread!";
6067       goto error;
6068     }
6069
6070     // Boost DS thread priority
6071     SetThreadPriority( (HANDLE) stream_.callbackInfo.thread, THREAD_PRIORITY_HIGHEST );
6072   }
6073   return SUCCESS;
6074
6075  error:
6076   if ( handle ) {
6077     if ( handle->buffer[0] ) { // the object pointer can be NULL and valid
6078       LPDIRECTSOUND object = (LPDIRECTSOUND) handle->id[0];
6079       LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
6080       if ( buffer ) buffer->Release();
6081       object->Release();
6082     }
6083     if ( handle->buffer[1] ) {
6084       LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handle->id[1];
6085       LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
6086       if ( buffer ) buffer->Release();
6087       object->Release();
6088     }
6089     CloseHandle( handle->condition );
6090     delete handle;
6091     stream_.apiHandle = 0;
6092   }
6093
6094   for ( int i=0; i<2; i++ ) {
6095     if ( stream_.userBuffer[i] ) {
6096       free( stream_.userBuffer[i] );
6097       stream_.userBuffer[i] = 0;
6098     }
6099   }
6100
6101   if ( stream_.deviceBuffer ) {
6102     free( stream_.deviceBuffer );
6103     stream_.deviceBuffer = 0;
6104   }
6105
6106   stream_.state = STREAM_CLOSED;
6107   return FAILURE;
6108 }
6109
6110 void RtApiDs :: closeStream()
6111 {
6112   if ( stream_.state == STREAM_CLOSED ) {
6113     errorText_ = "RtApiDs::closeStream(): no open stream to close!";
6114     error( RtAudioError::WARNING );
6115     return;
6116   }
6117
6118   // Stop the callback thread.
6119   stream_.callbackInfo.isRunning = false;
6120   WaitForSingleObject( (HANDLE) stream_.callbackInfo.thread, INFINITE );
6121   CloseHandle( (HANDLE) stream_.callbackInfo.thread );
6122
6123   DsHandle *handle = (DsHandle *) stream_.apiHandle;
6124   if ( handle ) {
6125     if ( handle->buffer[0] ) { // the object pointer can be NULL and valid
6126       LPDIRECTSOUND object = (LPDIRECTSOUND) handle->id[0];
6127       LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
6128       if ( buffer ) {
6129         buffer->Stop();
6130         buffer->Release();
6131       }
6132       object->Release();
6133     }
6134     if ( handle->buffer[1] ) {
6135       LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handle->id[1];
6136       LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
6137       if ( buffer ) {
6138         buffer->Stop();
6139         buffer->Release();
6140       }
6141       object->Release();
6142     }
6143     CloseHandle( handle->condition );
6144     delete handle;
6145     stream_.apiHandle = 0;
6146   }
6147
6148   for ( int i=0; i<2; i++ ) {
6149     if ( stream_.userBuffer[i] ) {
6150       free( stream_.userBuffer[i] );
6151       stream_.userBuffer[i] = 0;
6152     }
6153   }
6154
6155   if ( stream_.deviceBuffer ) {
6156     free( stream_.deviceBuffer );
6157     stream_.deviceBuffer = 0;
6158   }
6159
6160   stream_.mode = UNINITIALIZED;
6161   stream_.state = STREAM_CLOSED;
6162 }
6163
6164 void RtApiDs :: startStream()
6165 {
6166   verifyStream();
6167   if ( stream_.state == STREAM_RUNNING ) {
6168     errorText_ = "RtApiDs::startStream(): the stream is already running!";
6169     error( RtAudioError::WARNING );
6170     return;
6171   }
6172
6173   DsHandle *handle = (DsHandle *) stream_.apiHandle;
6174
6175   // Increase scheduler frequency on lesser windows (a side-effect of
6176   // increasing timer accuracy).  On greater windows (Win2K or later),
6177   // this is already in effect.
6178   timeBeginPeriod( 1 ); 
6179
6180   buffersRolling = false;
6181   duplexPrerollBytes = 0;
6182
6183   if ( stream_.mode == DUPLEX ) {
6184     // 0.5 seconds of silence in DUPLEX mode while the devices spin up and synchronize.
6185     duplexPrerollBytes = (int) ( 0.5 * stream_.sampleRate * formatBytes( stream_.deviceFormat[1] ) * stream_.nDeviceChannels[1] );
6186   }
6187
6188   HRESULT result = 0;
6189   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
6190
6191     LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
6192     result = buffer->Play( 0, 0, DSBPLAY_LOOPING );
6193     if ( FAILED( result ) ) {
6194       errorStream_ << "RtApiDs::startStream: error (" << getErrorString( result ) << ") starting output buffer!";
6195       errorText_ = errorStream_.str();
6196       goto unlock;
6197     }
6198   }
6199
6200   if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
6201
6202     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
6203     result = buffer->Start( DSCBSTART_LOOPING );
6204     if ( FAILED( result ) ) {
6205       errorStream_ << "RtApiDs::startStream: error (" << getErrorString( result ) << ") starting input buffer!";
6206       errorText_ = errorStream_.str();
6207       goto unlock;
6208     }
6209   }
6210
6211   handle->drainCounter = 0;
6212   handle->internalDrain = false;
6213   ResetEvent( handle->condition );
6214   stream_.state = STREAM_RUNNING;
6215
6216  unlock:
6217   if ( FAILED( result ) ) error( RtAudioError::SYSTEM_ERROR );
6218 }
6219
6220 void RtApiDs :: stopStream()
6221 {
6222   verifyStream();
6223   if ( stream_.state == STREAM_STOPPED ) {
6224     errorText_ = "RtApiDs::stopStream(): the stream is already stopped!";
6225     error( RtAudioError::WARNING );
6226     return;
6227   }
6228
6229   HRESULT result = 0;
6230   LPVOID audioPtr;
6231   DWORD dataLen;
6232   DsHandle *handle = (DsHandle *) stream_.apiHandle;
6233   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
6234     if ( handle->drainCounter == 0 ) {
6235       handle->drainCounter = 2;
6236       WaitForSingleObject( handle->condition, INFINITE );  // block until signaled
6237     }
6238
6239     stream_.state = STREAM_STOPPED;
6240
6241     MUTEX_LOCK( &stream_.mutex );
6242
6243     // Stop the buffer and clear memory
6244     LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
6245     result = buffer->Stop();
6246     if ( FAILED( result ) ) {
6247       errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") stopping output buffer!";
6248       errorText_ = errorStream_.str();
6249       goto unlock;
6250     }
6251
6252     // Lock the buffer and clear it so that if we start to play again,
6253     // we won't have old data playing.
6254     result = buffer->Lock( 0, handle->dsBufferSize[0], &audioPtr, &dataLen, NULL, NULL, 0 );
6255     if ( FAILED( result ) ) {
6256       errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") locking output buffer!";
6257       errorText_ = errorStream_.str();
6258       goto unlock;
6259     }
6260
6261     // Zero the DS buffer
6262     ZeroMemory( audioPtr, dataLen );
6263
6264     // Unlock the DS buffer
6265     result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );
6266     if ( FAILED( result ) ) {
6267       errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") unlocking output buffer!";
6268       errorText_ = errorStream_.str();
6269       goto unlock;
6270     }
6271
6272     // If we start playing again, we must begin at beginning of buffer.
6273     handle->bufferPointer[0] = 0;
6274   }
6275
6276   if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
6277     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
6278     audioPtr = NULL;
6279     dataLen = 0;
6280
6281     stream_.state = STREAM_STOPPED;
6282
6283     if ( stream_.mode != DUPLEX )
6284       MUTEX_LOCK( &stream_.mutex );
6285
6286     result = buffer->Stop();
6287     if ( FAILED( result ) ) {
6288       errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") stopping input buffer!";
6289       errorText_ = errorStream_.str();
6290       goto unlock;
6291     }
6292
6293     // Lock the buffer and clear it so that if we start to play again,
6294     // we won't have old data playing.
6295     result = buffer->Lock( 0, handle->dsBufferSize[1], &audioPtr, &dataLen, NULL, NULL, 0 );
6296     if ( FAILED( result ) ) {
6297       errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") locking input buffer!";
6298       errorText_ = errorStream_.str();
6299       goto unlock;
6300     }
6301
6302     // Zero the DS buffer
6303     ZeroMemory( audioPtr, dataLen );
6304
6305     // Unlock the DS buffer
6306     result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );
6307     if ( FAILED( result ) ) {
6308       errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") unlocking input buffer!";
6309       errorText_ = errorStream_.str();
6310       goto unlock;
6311     }
6312
6313     // If we start recording again, we must begin at beginning of buffer.
6314     handle->bufferPointer[1] = 0;
6315   }
6316
6317  unlock:
6318   timeEndPeriod( 1 ); // revert to normal scheduler frequency on lesser windows.
6319   MUTEX_UNLOCK( &stream_.mutex );
6320
6321   if ( FAILED( result ) ) error( RtAudioError::SYSTEM_ERROR );
6322 }
6323
6324 void RtApiDs :: abortStream()
6325 {
6326   verifyStream();
6327   if ( stream_.state == STREAM_STOPPED ) {
6328     errorText_ = "RtApiDs::abortStream(): the stream is already stopped!";
6329     error( RtAudioError::WARNING );
6330     return;
6331   }
6332
6333   DsHandle *handle = (DsHandle *) stream_.apiHandle;
6334   handle->drainCounter = 2;
6335
6336   stopStream();
6337 }
6338
6339 void RtApiDs :: callbackEvent()
6340 {
6341   if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) {
6342     Sleep( 50 ); // sleep 50 milliseconds
6343     return;
6344   }
6345
6346   if ( stream_.state == STREAM_CLOSED ) {
6347     errorText_ = "RtApiDs::callbackEvent(): the stream is closed ... this shouldn't happen!";
6348     error( RtAudioError::WARNING );
6349     return;
6350   }
6351
6352   CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
6353   DsHandle *handle = (DsHandle *) stream_.apiHandle;
6354
6355   // Check if we were draining the stream and signal is finished.
6356   if ( handle->drainCounter > stream_.nBuffers + 2 ) {
6357
6358     stream_.state = STREAM_STOPPING;
6359     if ( handle->internalDrain == false )
6360       SetEvent( handle->condition );
6361     else
6362       stopStream();
6363     return;
6364   }
6365
6366   // Invoke user callback to get fresh output data UNLESS we are
6367   // draining stream.
6368   if ( handle->drainCounter == 0 ) {
6369     RtAudioCallback callback = (RtAudioCallback) info->callback;
6370     double streamTime = getStreamTime();
6371     RtAudioStreamStatus status = 0;
6372     if ( stream_.mode != INPUT && handle->xrun[0] == true ) {
6373       status |= RTAUDIO_OUTPUT_UNDERFLOW;
6374       handle->xrun[0] = false;
6375     }
6376     if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {
6377       status |= RTAUDIO_INPUT_OVERFLOW;
6378       handle->xrun[1] = false;
6379     }
6380     int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],
6381                                   stream_.bufferSize, streamTime, status, info->userData );
6382     if ( cbReturnValue == 2 ) {
6383       stream_.state = STREAM_STOPPING;
6384       handle->drainCounter = 2;
6385       abortStream();
6386       return;
6387     }
6388     else if ( cbReturnValue == 1 ) {
6389       handle->drainCounter = 1;
6390       handle->internalDrain = true;
6391     }
6392   }
6393
6394   HRESULT result;
6395   DWORD currentWritePointer, safeWritePointer;
6396   DWORD currentReadPointer, safeReadPointer;
6397   UINT nextWritePointer;
6398
6399   LPVOID buffer1 = NULL;
6400   LPVOID buffer2 = NULL;
6401   DWORD bufferSize1 = 0;
6402   DWORD bufferSize2 = 0;
6403
6404   char *buffer;
6405   long bufferBytes;
6406
6407   MUTEX_LOCK( &stream_.mutex );
6408   if ( stream_.state == STREAM_STOPPED ) {
6409     MUTEX_UNLOCK( &stream_.mutex );
6410     return;
6411   }
6412
6413   if ( buffersRolling == false ) {
6414     if ( stream_.mode == DUPLEX ) {
6415       //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );
6416
6417       // It takes a while for the devices to get rolling. As a result,
6418       // there's no guarantee that the capture and write device pointers
6419       // will move in lockstep.  Wait here for both devices to start
6420       // rolling, and then set our buffer pointers accordingly.
6421       // e.g. Crystal Drivers: the capture buffer starts up 5700 to 9600
6422       // bytes later than the write buffer.
6423
6424       // Stub: a serious risk of having a pre-emptive scheduling round
6425       // take place between the two GetCurrentPosition calls... but I'm
6426       // really not sure how to solve the problem.  Temporarily boost to
6427       // Realtime priority, maybe; but I'm not sure what priority the
6428       // DirectSound service threads run at. We *should* be roughly
6429       // within a ms or so of correct.
6430
6431       LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
6432       LPDIRECTSOUNDCAPTUREBUFFER dsCaptureBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
6433
6434       DWORD startSafeWritePointer, startSafeReadPointer;
6435
6436       result = dsWriteBuffer->GetCurrentPosition( NULL, &startSafeWritePointer );
6437       if ( FAILED( result ) ) {
6438         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
6439         errorText_ = errorStream_.str();
6440         MUTEX_UNLOCK( &stream_.mutex );
6441         error( RtAudioError::SYSTEM_ERROR );
6442         return;
6443       }
6444       result = dsCaptureBuffer->GetCurrentPosition( NULL, &startSafeReadPointer );
6445       if ( FAILED( result ) ) {
6446         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
6447         errorText_ = errorStream_.str();
6448         MUTEX_UNLOCK( &stream_.mutex );
6449         error( RtAudioError::SYSTEM_ERROR );
6450         return;
6451       }
6452       while ( true ) {
6453         result = dsWriteBuffer->GetCurrentPosition( NULL, &safeWritePointer );
6454         if ( FAILED( result ) ) {
6455           errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
6456           errorText_ = errorStream_.str();
6457           MUTEX_UNLOCK( &stream_.mutex );
6458           error( RtAudioError::SYSTEM_ERROR );
6459           return;
6460         }
6461         result = dsCaptureBuffer->GetCurrentPosition( NULL, &safeReadPointer );
6462         if ( FAILED( result ) ) {
6463           errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
6464           errorText_ = errorStream_.str();
6465           MUTEX_UNLOCK( &stream_.mutex );
6466           error( RtAudioError::SYSTEM_ERROR );
6467           return;
6468         }
6469         if ( safeWritePointer != startSafeWritePointer && safeReadPointer != startSafeReadPointer ) break;
6470         Sleep( 1 );
6471       }
6472
6473       //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );
6474
6475       handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0];
6476       if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0];
6477       handle->bufferPointer[1] = safeReadPointer;
6478     }
6479     else if ( stream_.mode == OUTPUT ) {
6480
6481       // Set the proper nextWritePosition after initial startup.
6482       LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
6483       result = dsWriteBuffer->GetCurrentPosition( &currentWritePointer, &safeWritePointer );
6484       if ( FAILED( result ) ) {
6485         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
6486         errorText_ = errorStream_.str();
6487         MUTEX_UNLOCK( &stream_.mutex );
6488         error( RtAudioError::SYSTEM_ERROR );
6489         return;
6490       }
6491       handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0];
6492       if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0];
6493     }
6494
6495     buffersRolling = true;
6496   }
6497
6498   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
6499     
6500     LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
6501
6502     if ( handle->drainCounter > 1 ) { // write zeros to the output stream
6503       bufferBytes = stream_.bufferSize * stream_.nUserChannels[0];
6504       bufferBytes *= formatBytes( stream_.userFormat );
6505       memset( stream_.userBuffer[0], 0, bufferBytes );
6506     }
6507
6508     // Setup parameters and do buffer conversion if necessary.
6509     if ( stream_.doConvertBuffer[0] ) {
6510       buffer = stream_.deviceBuffer;
6511       convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] );
6512       bufferBytes = stream_.bufferSize * stream_.nDeviceChannels[0];
6513       bufferBytes *= formatBytes( stream_.deviceFormat[0] );
6514     }
6515     else {
6516       buffer = stream_.userBuffer[0];
6517       bufferBytes = stream_.bufferSize * stream_.nUserChannels[0];
6518       bufferBytes *= formatBytes( stream_.userFormat );
6519     }
6520
6521     // No byte swapping necessary in DirectSound implementation.
6522
6523     // Ahhh ... windoze.  16-bit data is signed but 8-bit data is
6524     // unsigned.  So, we need to convert our signed 8-bit data here to
6525     // unsigned.
6526     if ( stream_.deviceFormat[0] == RTAUDIO_SINT8 )
6527       for ( int i=0; i<bufferBytes; i++ ) buffer[i] = (unsigned char) ( buffer[i] + 128 );
6528
6529     DWORD dsBufferSize = handle->dsBufferSize[0];
6530     nextWritePointer = handle->bufferPointer[0];
6531
6532     DWORD endWrite, leadPointer;
6533     while ( true ) {
6534       // Find out where the read and "safe write" pointers are.
6535       result = dsBuffer->GetCurrentPosition( &currentWritePointer, &safeWritePointer );
6536       if ( FAILED( result ) ) {
6537         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
6538         errorText_ = errorStream_.str();
6539         MUTEX_UNLOCK( &stream_.mutex );
6540         error( RtAudioError::SYSTEM_ERROR );
6541         return;
6542       }
6543
6544       // We will copy our output buffer into the region between
6545       // safeWritePointer and leadPointer.  If leadPointer is not
6546       // beyond the next endWrite position, wait until it is.
6547       leadPointer = safeWritePointer + handle->dsPointerLeadTime[0];
6548       //std::cout << "safeWritePointer = " << safeWritePointer << ", leadPointer = " << leadPointer << ", nextWritePointer = " << nextWritePointer << std::endl;
6549       if ( leadPointer > dsBufferSize ) leadPointer -= dsBufferSize;
6550       if ( leadPointer < nextWritePointer ) leadPointer += dsBufferSize; // unwrap offset
6551       endWrite = nextWritePointer + bufferBytes;
6552
6553       // Check whether the entire write region is behind the play pointer.
6554       if ( leadPointer >= endWrite ) break;
6555
6556       // If we are here, then we must wait until the leadPointer advances
6557       // beyond the end of our next write region. We use the
6558       // Sleep() function to suspend operation until that happens.
6559       double millis = ( endWrite - leadPointer ) * 1000.0;
6560       millis /= ( formatBytes( stream_.deviceFormat[0]) * stream_.nDeviceChannels[0] * stream_.sampleRate);
6561       if ( millis < 1.0 ) millis = 1.0;
6562       Sleep( (DWORD) millis );
6563     }
6564
6565     if ( dsPointerBetween( nextWritePointer, safeWritePointer, currentWritePointer, dsBufferSize )
6566          || dsPointerBetween( endWrite, safeWritePointer, currentWritePointer, dsBufferSize ) ) { 
6567       // We've strayed into the forbidden zone ... resync the read pointer.
6568       handle->xrun[0] = true;
6569       nextWritePointer = safeWritePointer + handle->dsPointerLeadTime[0] - bufferBytes;
6570       if ( nextWritePointer >= dsBufferSize ) nextWritePointer -= dsBufferSize;
6571       handle->bufferPointer[0] = nextWritePointer;
6572       endWrite = nextWritePointer + bufferBytes;
6573     }
6574
6575     // Lock free space in the buffer
6576     result = dsBuffer->Lock( nextWritePointer, bufferBytes, &buffer1,
6577                              &bufferSize1, &buffer2, &bufferSize2, 0 );
6578     if ( FAILED( result ) ) {
6579       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking buffer during playback!";
6580       errorText_ = errorStream_.str();
6581       MUTEX_UNLOCK( &stream_.mutex );
6582       error( RtAudioError::SYSTEM_ERROR );
6583       return;
6584     }
6585
6586     // Copy our buffer into the DS buffer
6587     CopyMemory( buffer1, buffer, bufferSize1 );
6588     if ( buffer2 != NULL ) CopyMemory( buffer2, buffer+bufferSize1, bufferSize2 );
6589
6590     // Update our buffer offset and unlock sound buffer
6591     dsBuffer->Unlock( buffer1, bufferSize1, buffer2, bufferSize2 );
6592     if ( FAILED( result ) ) {
6593       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!";
6594       errorText_ = errorStream_.str();
6595       MUTEX_UNLOCK( &stream_.mutex );
6596       error( RtAudioError::SYSTEM_ERROR );
6597       return;
6598     }
6599     nextWritePointer = ( nextWritePointer + bufferSize1 + bufferSize2 ) % dsBufferSize;
6600     handle->bufferPointer[0] = nextWritePointer;
6601   }
6602
6603   // Don't bother draining input
6604   if ( handle->drainCounter ) {
6605     handle->drainCounter++;
6606     goto unlock;
6607   }
6608
6609   if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
6610
6611     // Setup parameters.
6612     if ( stream_.doConvertBuffer[1] ) {
6613       buffer = stream_.deviceBuffer;
6614       bufferBytes = stream_.bufferSize * stream_.nDeviceChannels[1];
6615       bufferBytes *= formatBytes( stream_.deviceFormat[1] );
6616     }
6617     else {
6618       buffer = stream_.userBuffer[1];
6619       bufferBytes = stream_.bufferSize * stream_.nUserChannels[1];
6620       bufferBytes *= formatBytes( stream_.userFormat );
6621     }
6622
6623     LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
6624     long nextReadPointer = handle->bufferPointer[1];
6625     DWORD dsBufferSize = handle->dsBufferSize[1];
6626
6627     // Find out where the write and "safe read" pointers are.
6628     result = dsBuffer->GetCurrentPosition( &currentReadPointer, &safeReadPointer );
6629     if ( FAILED( result ) ) {
6630       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
6631       errorText_ = errorStream_.str();
6632       MUTEX_UNLOCK( &stream_.mutex );
6633       error( RtAudioError::SYSTEM_ERROR );
6634       return;
6635     }
6636
6637     if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset
6638     DWORD endRead = nextReadPointer + bufferBytes;
6639
6640     // Handling depends on whether we are INPUT or DUPLEX. 
6641     // If we're in INPUT mode then waiting is a good thing. If we're in DUPLEX mode,
6642     // then a wait here will drag the write pointers into the forbidden zone.
6643     // 
6644     // In DUPLEX mode, rather than wait, we will back off the read pointer until 
6645     // it's in a safe position. This causes dropouts, but it seems to be the only 
6646     // practical way to sync up the read and write pointers reliably, given the 
6647     // the very complex relationship between phase and increment of the read and write 
6648     // pointers.
6649     //
6650     // In order to minimize audible dropouts in DUPLEX mode, we will
6651     // provide a pre-roll period of 0.5 seconds in which we return
6652     // zeros from the read buffer while the pointers sync up.
6653
6654     if ( stream_.mode == DUPLEX ) {
6655       if ( safeReadPointer < endRead ) {
6656         if ( duplexPrerollBytes <= 0 ) {
6657           // Pre-roll time over. Be more agressive.
6658           int adjustment = endRead-safeReadPointer;
6659
6660           handle->xrun[1] = true;
6661           // Two cases:
6662           //   - large adjustments: we've probably run out of CPU cycles, so just resync exactly,
6663           //     and perform fine adjustments later.
6664           //   - small adjustments: back off by twice as much.
6665           if ( adjustment >= 2*bufferBytes )
6666             nextReadPointer = safeReadPointer-2*bufferBytes;
6667           else
6668             nextReadPointer = safeReadPointer-bufferBytes-adjustment;
6669
6670           if ( nextReadPointer < 0 ) nextReadPointer += dsBufferSize;
6671
6672         }
6673         else {
6674           // In pre=roll time. Just do it.
6675           nextReadPointer = safeReadPointer - bufferBytes;
6676           while ( nextReadPointer < 0 ) nextReadPointer += dsBufferSize;
6677         }
6678         endRead = nextReadPointer + bufferBytes;
6679       }
6680     }
6681     else { // mode == INPUT
6682       while ( safeReadPointer < endRead && stream_.callbackInfo.isRunning ) {
6683         // See comments for playback.
6684         double millis = (endRead - safeReadPointer) * 1000.0;
6685         millis /= ( formatBytes(stream_.deviceFormat[1]) * stream_.nDeviceChannels[1] * stream_.sampleRate);
6686         if ( millis < 1.0 ) millis = 1.0;
6687         Sleep( (DWORD) millis );
6688
6689         // Wake up and find out where we are now.
6690         result = dsBuffer->GetCurrentPosition( &currentReadPointer, &safeReadPointer );
6691         if ( FAILED( result ) ) {
6692           errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
6693           errorText_ = errorStream_.str();
6694           MUTEX_UNLOCK( &stream_.mutex );
6695           error( RtAudioError::SYSTEM_ERROR );
6696           return;
6697         }
6698       
6699         if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset
6700       }
6701     }
6702
6703     // Lock free space in the buffer
6704     result = dsBuffer->Lock( nextReadPointer, bufferBytes, &buffer1,
6705                              &bufferSize1, &buffer2, &bufferSize2, 0 );
6706     if ( FAILED( result ) ) {
6707       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking capture buffer!";
6708       errorText_ = errorStream_.str();
6709       MUTEX_UNLOCK( &stream_.mutex );
6710       error( RtAudioError::SYSTEM_ERROR );
6711       return;
6712     }
6713
6714     if ( duplexPrerollBytes <= 0 ) {
6715       // Copy our buffer into the DS buffer
6716       CopyMemory( buffer, buffer1, bufferSize1 );
6717       if ( buffer2 != NULL ) CopyMemory( buffer+bufferSize1, buffer2, bufferSize2 );
6718     }
6719     else {
6720       memset( buffer, 0, bufferSize1 );
6721       if ( buffer2 != NULL ) memset( buffer + bufferSize1, 0, bufferSize2 );
6722       duplexPrerollBytes -= bufferSize1 + bufferSize2;
6723     }
6724
6725     // Update our buffer offset and unlock sound buffer
6726     nextReadPointer = ( nextReadPointer + bufferSize1 + bufferSize2 ) % dsBufferSize;
6727     dsBuffer->Unlock( buffer1, bufferSize1, buffer2, bufferSize2 );
6728     if ( FAILED( result ) ) {
6729       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking capture buffer!";
6730       errorText_ = errorStream_.str();
6731       MUTEX_UNLOCK( &stream_.mutex );
6732       error( RtAudioError::SYSTEM_ERROR );
6733       return;
6734     }
6735     handle->bufferPointer[1] = nextReadPointer;
6736
6737     // No byte swapping necessary in DirectSound implementation.
6738
6739     // If necessary, convert 8-bit data from unsigned to signed.
6740     if ( stream_.deviceFormat[1] == RTAUDIO_SINT8 )
6741       for ( int j=0; j<bufferBytes; j++ ) buffer[j] = (signed char) ( buffer[j] - 128 );
6742
6743     // Do buffer conversion if necessary.
6744     if ( stream_.doConvertBuffer[1] )
6745       convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
6746   }
6747
6748  unlock:
6749   MUTEX_UNLOCK( &stream_.mutex );
6750   RtApi::tickStreamTime();
6751 }
6752
6753 // Definitions for utility functions and callbacks
6754 // specific to the DirectSound implementation.
6755
6756 static unsigned __stdcall callbackHandler( void *ptr )
6757 {
6758   CallbackInfo *info = (CallbackInfo *) ptr;
6759   RtApiDs *object = (RtApiDs *) info->object;
6760   bool* isRunning = &info->isRunning;
6761
6762   while ( *isRunning == true ) {
6763     object->callbackEvent();
6764   }
6765
6766   _endthreadex( 0 );
6767   return 0;
6768 }
6769
6770 static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
6771                                           LPCTSTR description,
6772                                           LPCTSTR /*module*/,
6773                                           LPVOID lpContext )
6774 {
6775   struct DsProbeData& probeInfo = *(struct DsProbeData*) lpContext;
6776   std::vector<struct DsDevice>& dsDevices = *probeInfo.dsDevices;
6777
6778   HRESULT hr;
6779   bool validDevice = false;
6780   if ( probeInfo.isInput == true ) {
6781     DSCCAPS caps;
6782     LPDIRECTSOUNDCAPTURE object;
6783
6784     hr = DirectSoundCaptureCreate(  lpguid, &object,   NULL );
6785     if ( hr != DS_OK ) return TRUE;
6786
6787     caps.dwSize = sizeof(caps);
6788     hr = object->GetCaps( &caps );
6789     if ( hr == DS_OK ) {
6790       if ( caps.dwChannels > 0 && caps.dwFormats > 0 )
6791         validDevice = true;
6792     }
6793     object->Release();
6794   }
6795   else {
6796     DSCAPS caps;
6797     LPDIRECTSOUND object;
6798     hr = DirectSoundCreate(  lpguid, &object,   NULL );
6799     if ( hr != DS_OK ) return TRUE;
6800
6801     caps.dwSize = sizeof(caps);
6802     hr = object->GetCaps( &caps );
6803     if ( hr == DS_OK ) {
6804       if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO )
6805         validDevice = true;
6806     }
6807     object->Release();
6808   }
6809
6810   // If good device, then save its name and guid.
6811   std::string name = convertCharPointerToStdString( description );
6812   //if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" )
6813   if ( lpguid == NULL )
6814     name = "Default Device";
6815   if ( validDevice ) {
6816     for ( unsigned int i=0; i<dsDevices.size(); i++ ) {
6817       if ( dsDevices[i].name == name ) {
6818         dsDevices[i].found = true;
6819         if ( probeInfo.isInput ) {
6820           dsDevices[i].id[1] = lpguid;
6821           dsDevices[i].validId[1] = true;
6822         }
6823         else {
6824           dsDevices[i].id[0] = lpguid;
6825           dsDevices[i].validId[0] = true;
6826         }
6827         return TRUE;
6828       }
6829     }
6830
6831     DsDevice device;
6832     device.name = name;
6833     device.found = true;
6834     if ( probeInfo.isInput ) {
6835       device.id[1] = lpguid;
6836       device.validId[1] = true;
6837     }
6838     else {
6839       device.id[0] = lpguid;
6840       device.validId[0] = true;
6841     }
6842     dsDevices.push_back( device );
6843   }
6844
6845   return TRUE;
6846 }
6847
6848 static const char* getErrorString( int code )
6849 {
6850   switch ( code ) {
6851
6852   case DSERR_ALLOCATED:
6853     return "Already allocated";
6854
6855   case DSERR_CONTROLUNAVAIL:
6856     return "Control unavailable";
6857
6858   case DSERR_INVALIDPARAM:
6859     return "Invalid parameter";
6860
6861   case DSERR_INVALIDCALL:
6862     return "Invalid call";
6863
6864   case DSERR_GENERIC:
6865     return "Generic error";
6866
6867   case DSERR_PRIOLEVELNEEDED:
6868     return "Priority level needed";
6869
6870   case DSERR_OUTOFMEMORY:
6871     return "Out of memory";
6872
6873   case DSERR_BADFORMAT:
6874     return "The sample rate or the channel format is not supported";
6875
6876   case DSERR_UNSUPPORTED:
6877     return "Not supported";
6878
6879   case DSERR_NODRIVER:
6880     return "No driver";
6881
6882   case DSERR_ALREADYINITIALIZED:
6883     return "Already initialized";
6884
6885   case DSERR_NOAGGREGATION:
6886     return "No aggregation";
6887
6888   case DSERR_BUFFERLOST:
6889     return "Buffer lost";
6890
6891   case DSERR_OTHERAPPHASPRIO:
6892     return "Another application already has priority";
6893
6894   case DSERR_UNINITIALIZED:
6895     return "Uninitialized";
6896
6897   default:
6898     return "DirectSound unknown error";
6899   }
6900 }
6901 //******************** End of __WINDOWS_DS__ *********************//
6902 #endif
6903
6904
6905 #if defined(__LINUX_ALSA__)
6906
6907 #include <alsa/asoundlib.h>
6908 #include <unistd.h>
6909
6910   // A structure to hold various information related to the ALSA API
6911   // implementation.
6912 struct AlsaHandle {
6913   snd_pcm_t *handles[2];
6914   bool synchronized;
6915   bool xrun[2];
6916   pthread_cond_t runnable_cv;
6917   bool runnable;
6918
6919   AlsaHandle()
6920     :synchronized(false), runnable(false) { xrun[0] = false; xrun[1] = false; }
6921 };
6922
6923 static void *alsaCallbackHandler( void * ptr );
6924
6925 RtApiAlsa :: RtApiAlsa()
6926 {
6927   // Nothing to do here.
6928 }
6929
6930 RtApiAlsa :: ~RtApiAlsa()
6931 {
6932   if ( stream_.state != STREAM_CLOSED ) closeStream();
6933 }
6934
6935 unsigned int RtApiAlsa :: getDeviceCount( void )
6936 {
6937   unsigned nDevices = 0;
6938   int result, subdevice, card;
6939   char name[64];
6940   snd_ctl_t *handle;
6941
6942   // Count cards and devices
6943   card = -1;
6944   snd_card_next( &card );
6945   while ( card >= 0 ) {
6946     sprintf( name, "hw:%d", card );
6947     result = snd_ctl_open( &handle, name, 0 );
6948     if ( result < 0 ) {
6949       errorStream_ << "RtApiAlsa::getDeviceCount: control open, card = " << card << ", " << snd_strerror( result ) << ".";
6950       errorText_ = errorStream_.str();
6951       error( RtAudioError::WARNING );
6952       goto nextcard;
6953     }
6954     subdevice = -1;
6955     while( 1 ) {
6956       result = snd_ctl_pcm_next_device( handle, &subdevice );
6957       if ( result < 0 ) {
6958         errorStream_ << "RtApiAlsa::getDeviceCount: control next device, card = " << card << ", " << snd_strerror( result ) << ".";
6959         errorText_ = errorStream_.str();
6960         error( RtAudioError::WARNING );
6961         break;
6962       }
6963       if ( subdevice < 0 )
6964         break;
6965       nDevices++;
6966     }
6967   nextcard:
6968     snd_ctl_close( handle );
6969     snd_card_next( &card );
6970   }
6971
6972   result = snd_ctl_open( &handle, "default", 0 );
6973   if (result == 0) {
6974     nDevices++;
6975     snd_ctl_close( handle );
6976   }
6977
6978   return nDevices;
6979 }
6980
6981 RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
6982 {
6983   RtAudio::DeviceInfo info;
6984   info.probed = false;
6985
6986   unsigned nDevices = 0;
6987   int result, subdevice, card;
6988   char name[64];
6989   snd_ctl_t *chandle;
6990
6991   // Count cards and devices
6992   card = -1;
6993   subdevice = -1;
6994   snd_card_next( &card );
6995   while ( card >= 0 ) {
6996     sprintf( name, "hw:%d", card );
6997     result = snd_ctl_open( &chandle, name, SND_CTL_NONBLOCK );
6998     if ( result < 0 ) {
6999       errorStream_ << "RtApiAlsa::getDeviceInfo: control open, card = " << card << ", " << snd_strerror( result ) << ".";
7000       errorText_ = errorStream_.str();
7001       error( RtAudioError::WARNING );
7002       goto nextcard;
7003     }
7004     subdevice = -1;
7005     while( 1 ) {
7006       result = snd_ctl_pcm_next_device( chandle, &subdevice );
7007       if ( result < 0 ) {
7008         errorStream_ << "RtApiAlsa::getDeviceInfo: control next device, card = " << card << ", " << snd_strerror( result ) << ".";
7009         errorText_ = errorStream_.str();
7010         error( RtAudioError::WARNING );
7011         break;
7012       }
7013       if ( subdevice < 0 ) break;
7014       if ( nDevices == device ) {
7015         sprintf( name, "hw:%d,%d", card, subdevice );
7016         goto foundDevice;
7017       }
7018       nDevices++;
7019     }
7020   nextcard:
7021     snd_ctl_close( chandle );
7022     snd_card_next( &card );
7023   }
7024
7025   result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK );
7026   if ( result == 0 ) {
7027     if ( nDevices == device ) {
7028       strcpy( name, "default" );
7029       goto foundDevice;
7030     }
7031     nDevices++;
7032   }
7033
7034   if ( nDevices == 0 ) {
7035     errorText_ = "RtApiAlsa::getDeviceInfo: no devices found!";
7036     error( RtAudioError::INVALID_USE );
7037     return info;
7038   }
7039
7040   if ( device >= nDevices ) {
7041     errorText_ = "RtApiAlsa::getDeviceInfo: device ID is invalid!";
7042     error( RtAudioError::INVALID_USE );
7043     return info;
7044   }
7045
7046  foundDevice:
7047
7048   // If a stream is already open, we cannot probe the stream devices.
7049   // Thus, use the saved results.
7050   if ( stream_.state != STREAM_CLOSED &&
7051        ( stream_.device[0] == device || stream_.device[1] == device ) ) {
7052     snd_ctl_close( chandle );
7053     if ( device >= devices_.size() ) {
7054       errorText_ = "RtApiAlsa::getDeviceInfo: device ID was not present before stream was opened.";
7055       error( RtAudioError::WARNING );
7056       return info;
7057     }
7058     return devices_[ device ];
7059   }
7060
7061   int openMode = SND_PCM_ASYNC;
7062   snd_pcm_stream_t stream;
7063   snd_pcm_info_t *pcminfo;
7064   snd_pcm_info_alloca( &pcminfo );
7065   snd_pcm_t *phandle;
7066   snd_pcm_hw_params_t *params;
7067   snd_pcm_hw_params_alloca( &params );
7068
7069   // First try for playback unless default device (which has subdev -1)
7070   stream = SND_PCM_STREAM_PLAYBACK;
7071   snd_pcm_info_set_stream( pcminfo, stream );
7072   if ( subdevice != -1 ) {
7073     snd_pcm_info_set_device( pcminfo, subdevice );
7074     snd_pcm_info_set_subdevice( pcminfo, 0 );
7075
7076     result = snd_ctl_pcm_info( chandle, pcminfo );
7077     if ( result < 0 ) {
7078       // Device probably doesn't support playback.
7079       goto captureProbe;
7080     }
7081   }
7082
7083   result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK );
7084   if ( result < 0 ) {
7085     errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";
7086     errorText_ = errorStream_.str();
7087     error( RtAudioError::WARNING );
7088     goto captureProbe;
7089   }
7090
7091   // The device is open ... fill the parameter structure.
7092   result = snd_pcm_hw_params_any( phandle, params );
7093   if ( result < 0 ) {
7094     snd_pcm_close( phandle );
7095     errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";
7096     errorText_ = errorStream_.str();
7097     error( RtAudioError::WARNING );
7098     goto captureProbe;
7099   }
7100
7101   // Get output channel information.
7102   unsigned int value;
7103   result = snd_pcm_hw_params_get_channels_max( params, &value );
7104   if ( result < 0 ) {
7105     snd_pcm_close( phandle );
7106     errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") output channels, " << snd_strerror( result ) << ".";
7107     errorText_ = errorStream_.str();
7108     error( RtAudioError::WARNING );
7109     goto captureProbe;
7110   }
7111   info.outputChannels = value;
7112   snd_pcm_close( phandle );
7113
7114  captureProbe:
7115   stream = SND_PCM_STREAM_CAPTURE;
7116   snd_pcm_info_set_stream( pcminfo, stream );
7117
7118   // Now try for capture unless default device (with subdev = -1)
7119   if ( subdevice != -1 ) {
7120     result = snd_ctl_pcm_info( chandle, pcminfo );
7121     snd_ctl_close( chandle );
7122     if ( result < 0 ) {
7123       // Device probably doesn't support capture.
7124       if ( info.outputChannels == 0 ) return info;
7125       goto probeParameters;
7126     }
7127   }
7128   else
7129     snd_ctl_close( chandle );
7130
7131   result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK);
7132   if ( result < 0 ) {
7133     errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";
7134     errorText_ = errorStream_.str();
7135     error( RtAudioError::WARNING );
7136     if ( info.outputChannels == 0 ) return info;
7137     goto probeParameters;
7138   }
7139
7140   // The device is open ... fill the parameter structure.
7141   result = snd_pcm_hw_params_any( phandle, params );
7142   if ( result < 0 ) {
7143     snd_pcm_close( phandle );
7144     errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";
7145     errorText_ = errorStream_.str();
7146     error( RtAudioError::WARNING );
7147     if ( info.outputChannels == 0 ) return info;
7148     goto probeParameters;
7149   }
7150
7151   result = snd_pcm_hw_params_get_channels_max( params, &value );
7152   if ( result < 0 ) {
7153     snd_pcm_close( phandle );
7154     errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") input channels, " << snd_strerror( result ) << ".";
7155     errorText_ = errorStream_.str();
7156     error( RtAudioError::WARNING );
7157     if ( info.outputChannels == 0 ) return info;
7158     goto probeParameters;
7159   }
7160   info.inputChannels = value;
7161   snd_pcm_close( phandle );
7162
7163   // If device opens for both playback and capture, we determine the channels.
7164   if ( info.outputChannels > 0 && info.inputChannels > 0 )
7165     info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
7166
7167   // ALSA doesn't provide default devices so we'll use the first available one.
7168   if ( device == 0 && info.outputChannels > 0 )
7169     info.isDefaultOutput = true;
7170   if ( device == 0 && info.inputChannels > 0 )
7171     info.isDefaultInput = true;
7172
7173  probeParameters:
7174   // At this point, we just need to figure out the supported data
7175   // formats and sample rates.  We'll proceed by opening the device in
7176   // the direction with the maximum number of channels, or playback if
7177   // they are equal.  This might limit our sample rate options, but so
7178   // be it.
7179
7180   if ( info.outputChannels >= info.inputChannels )
7181     stream = SND_PCM_STREAM_PLAYBACK;
7182   else
7183     stream = SND_PCM_STREAM_CAPTURE;
7184   snd_pcm_info_set_stream( pcminfo, stream );
7185
7186   result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK);
7187   if ( result < 0 ) {
7188     errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";
7189     errorText_ = errorStream_.str();
7190     error( RtAudioError::WARNING );
7191     return info;
7192   }
7193
7194   // The device is open ... fill the parameter structure.
7195   result = snd_pcm_hw_params_any( phandle, params );
7196   if ( result < 0 ) {
7197     snd_pcm_close( phandle );
7198     errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";
7199     errorText_ = errorStream_.str();
7200     error( RtAudioError::WARNING );
7201     return info;
7202   }
7203
7204   // Test our discrete set of sample rate values.
7205   info.sampleRates.clear();
7206   for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {
7207     if ( snd_pcm_hw_params_test_rate( phandle, params, SAMPLE_RATES[i], 0 ) == 0 ) {
7208       info.sampleRates.push_back( SAMPLE_RATES[i] );
7209
7210       if ( !info.preferredSampleRate || ( SAMPLE_RATES[i] <= 48000 && SAMPLE_RATES[i] > info.preferredSampleRate ) )
7211         info.preferredSampleRate = SAMPLE_RATES[i];
7212     }
7213   }
7214   if ( info.sampleRates.size() == 0 ) {
7215     snd_pcm_close( phandle );
7216     errorStream_ << "RtApiAlsa::getDeviceInfo: no supported sample rates found for device (" << name << ").";
7217     errorText_ = errorStream_.str();
7218     error( RtAudioError::WARNING );
7219     return info;
7220   }
7221
7222   // Probe the supported data formats ... we don't care about endian-ness just yet
7223   snd_pcm_format_t format;
7224   info.nativeFormats = 0;
7225   format = SND_PCM_FORMAT_S8;
7226   if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )
7227     info.nativeFormats |= RTAUDIO_SINT8;
7228   format = SND_PCM_FORMAT_S16;
7229   if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )
7230     info.nativeFormats |= RTAUDIO_SINT16;
7231   format = SND_PCM_FORMAT_S24;
7232   if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )
7233     info.nativeFormats |= RTAUDIO_SINT24;
7234   format = SND_PCM_FORMAT_S32;
7235   if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )
7236     info.nativeFormats |= RTAUDIO_SINT32;
7237   format = SND_PCM_FORMAT_FLOAT;
7238   if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )
7239     info.nativeFormats |= RTAUDIO_FLOAT32;
7240   format = SND_PCM_FORMAT_FLOAT64;
7241   if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )
7242     info.nativeFormats |= RTAUDIO_FLOAT64;
7243
7244   // Check that we have at least one supported format
7245   if ( info.nativeFormats == 0 ) {
7246     snd_pcm_close( phandle );
7247     errorStream_ << "RtApiAlsa::getDeviceInfo: pcm device (" << name << ") data format not supported by RtAudio.";
7248     errorText_ = errorStream_.str();
7249     error( RtAudioError::WARNING );
7250     return info;
7251   }
7252
7253   // Get the device name
7254   char *cardname;
7255   result = snd_card_get_name( card, &cardname );
7256   if ( result >= 0 ) {
7257     sprintf( name, "hw:%s,%d", cardname, subdevice );
7258     free( cardname );
7259   }
7260   info.name = name;
7261
7262   // That's all ... close the device and return
7263   snd_pcm_close( phandle );
7264   info.probed = true;
7265   return info;
7266 }
7267
7268 void RtApiAlsa :: saveDeviceInfo( void )
7269 {
7270   devices_.clear();
7271
7272   unsigned int nDevices = getDeviceCount();
7273   devices_.resize( nDevices );
7274   for ( unsigned int i=0; i<nDevices; i++ )
7275     devices_[i] = getDeviceInfo( i );
7276 }
7277
7278 bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
7279                                    unsigned int firstChannel, unsigned int sampleRate,
7280                                    RtAudioFormat format, unsigned int *bufferSize,
7281                                    RtAudio::StreamOptions *options )
7282
7283 {
7284 #if defined(__RTAUDIO_DEBUG__)
7285   snd_output_t *out;
7286   snd_output_stdio_attach(&out, stderr, 0);
7287 #endif
7288
7289   // I'm not using the "plug" interface ... too much inconsistent behavior.
7290
7291   unsigned nDevices = 0;
7292   int result, subdevice, card;
7293   char name[64];
7294   snd_ctl_t *chandle;
7295
7296   if ( options && options->flags & RTAUDIO_ALSA_USE_DEFAULT )
7297     snprintf(name, sizeof(name), "%s", "default");
7298   else {
7299     // Count cards and devices
7300     card = -1;
7301     snd_card_next( &card );
7302     while ( card >= 0 ) {
7303       sprintf( name, "hw:%d", card );
7304       result = snd_ctl_open( &chandle, name, SND_CTL_NONBLOCK );
7305       if ( result < 0 ) {
7306         errorStream_ << "RtApiAlsa::probeDeviceOpen: control open, card = " << card << ", " << snd_strerror( result ) << ".";
7307         errorText_ = errorStream_.str();
7308         return FAILURE;
7309       }
7310       subdevice = -1;
7311       while( 1 ) {
7312         result = snd_ctl_pcm_next_device( chandle, &subdevice );
7313         if ( result < 0 ) break;
7314         if ( subdevice < 0 ) break;
7315         if ( nDevices == device ) {
7316           sprintf( name, "hw:%d,%d", card, subdevice );
7317           snd_ctl_close( chandle );
7318           goto foundDevice;
7319         }
7320         nDevices++;
7321       }
7322       snd_ctl_close( chandle );
7323       snd_card_next( &card );
7324     }
7325
7326     result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK );
7327     if ( result == 0 ) {
7328       if ( nDevices == device ) {
7329         strcpy( name, "default" );
7330         goto foundDevice;
7331       }
7332       nDevices++;
7333     }
7334
7335     if ( nDevices == 0 ) {
7336       // This should not happen because a check is made before this function is called.
7337       errorText_ = "RtApiAlsa::probeDeviceOpen: no devices found!";
7338       return FAILURE;
7339     }
7340
7341     if ( device >= nDevices ) {
7342       // This should not happen because a check is made before this function is called.
7343       errorText_ = "RtApiAlsa::probeDeviceOpen: device ID is invalid!";
7344       return FAILURE;
7345     }
7346   }
7347
7348  foundDevice:
7349
7350   // The getDeviceInfo() function will not work for a device that is
7351   // already open.  Thus, we'll probe the system before opening a
7352   // stream and save the results for use by getDeviceInfo().
7353   if ( mode == OUTPUT || ( mode == INPUT && stream_.mode != OUTPUT ) ) // only do once
7354     this->saveDeviceInfo();
7355
7356   snd_pcm_stream_t stream;
7357   if ( mode == OUTPUT )
7358     stream = SND_PCM_STREAM_PLAYBACK;
7359   else
7360     stream = SND_PCM_STREAM_CAPTURE;
7361
7362   snd_pcm_t *phandle;
7363   int openMode = SND_PCM_ASYNC;
7364   result = snd_pcm_open( &phandle, name, stream, openMode );
7365   if ( result < 0 ) {
7366     if ( mode == OUTPUT )
7367       errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device (" << name << ") won't open for output.";
7368     else
7369       errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device (" << name << ") won't open for input.";
7370     errorText_ = errorStream_.str();
7371     return FAILURE;
7372   }
7373
7374   // Fill the parameter structure.
7375   snd_pcm_hw_params_t *hw_params;
7376   snd_pcm_hw_params_alloca( &hw_params );
7377   result = snd_pcm_hw_params_any( phandle, hw_params );
7378   if ( result < 0 ) {
7379     snd_pcm_close( phandle );
7380     errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting pcm device (" << name << ") parameters, " << snd_strerror( result ) << ".";
7381     errorText_ = errorStream_.str();
7382     return FAILURE;
7383   }
7384
7385 #if defined(__RTAUDIO_DEBUG__)
7386   fprintf( stderr, "\nRtApiAlsa: dump hardware params just after device open:\n\n" );
7387   snd_pcm_hw_params_dump( hw_params, out );
7388 #endif
7389
7390   // Set access ... check user preference.
7391   if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) {
7392     stream_.userInterleaved = false;
7393     result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED );
7394     if ( result < 0 ) {
7395       result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED );
7396       stream_.deviceInterleaved[mode] =  true;
7397     }
7398     else
7399       stream_.deviceInterleaved[mode] = false;
7400   }
7401   else {
7402     stream_.userInterleaved = true;
7403     result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED );
7404     if ( result < 0 ) {
7405       result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED );
7406       stream_.deviceInterleaved[mode] =  false;
7407     }
7408     else
7409       stream_.deviceInterleaved[mode] =  true;
7410   }
7411
7412   if ( result < 0 ) {
7413     snd_pcm_close( phandle );
7414     errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting pcm device (" << name << ") access, " << snd_strerror( result ) << ".";
7415     errorText_ = errorStream_.str();
7416     return FAILURE;
7417   }
7418
7419   // Determine how to set the device format.
7420   stream_.userFormat = format;
7421   snd_pcm_format_t deviceFormat = SND_PCM_FORMAT_UNKNOWN;
7422
7423   if ( format == RTAUDIO_SINT8 )
7424     deviceFormat = SND_PCM_FORMAT_S8;
7425   else if ( format == RTAUDIO_SINT16 )
7426     deviceFormat = SND_PCM_FORMAT_S16;
7427   else if ( format == RTAUDIO_SINT24 )
7428     deviceFormat = SND_PCM_FORMAT_S24;
7429   else if ( format == RTAUDIO_SINT32 )
7430     deviceFormat = SND_PCM_FORMAT_S32;
7431   else if ( format == RTAUDIO_FLOAT32 )
7432     deviceFormat = SND_PCM_FORMAT_FLOAT;
7433   else if ( format == RTAUDIO_FLOAT64 )
7434     deviceFormat = SND_PCM_FORMAT_FLOAT64;
7435
7436   if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat) == 0) {
7437     stream_.deviceFormat[mode] = format;
7438     goto setFormat;
7439   }
7440
7441   // The user requested format is not natively supported by the device.
7442   deviceFormat = SND_PCM_FORMAT_FLOAT64;
7443   if ( snd_pcm_hw_params_test_format( phandle, hw_params, deviceFormat ) == 0 ) {
7444     stream_.deviceFormat[mode] = RTAUDIO_FLOAT64;
7445     goto setFormat;
7446   }
7447
7448   deviceFormat = SND_PCM_FORMAT_FLOAT;
7449   if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {
7450     stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
7451     goto setFormat;
7452   }
7453
7454   deviceFormat = SND_PCM_FORMAT_S32;
7455   if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {
7456     stream_.deviceFormat[mode] = RTAUDIO_SINT32;
7457     goto setFormat;
7458   }
7459
7460   deviceFormat = SND_PCM_FORMAT_S24;
7461   if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {
7462     stream_.deviceFormat[mode] = RTAUDIO_SINT24;
7463     goto setFormat;
7464   }
7465
7466   deviceFormat = SND_PCM_FORMAT_S16;
7467   if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {
7468     stream_.deviceFormat[mode] = RTAUDIO_SINT16;
7469     goto setFormat;
7470   }
7471
7472   deviceFormat = SND_PCM_FORMAT_S8;
7473   if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {
7474     stream_.deviceFormat[mode] = RTAUDIO_SINT8;
7475     goto setFormat;
7476   }
7477
7478   // If we get here, no supported format was found.
7479   snd_pcm_close( phandle );
7480   errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device " << device << " data format not supported by RtAudio.";
7481   errorText_ = errorStream_.str();
7482   return FAILURE;
7483
7484  setFormat:
7485   result = snd_pcm_hw_params_set_format( phandle, hw_params, deviceFormat );
7486   if ( result < 0 ) {
7487     snd_pcm_close( phandle );
7488     errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting pcm device (" << name << ") data format, " << snd_strerror( result ) << ".";
7489     errorText_ = errorStream_.str();
7490     return FAILURE;
7491   }
7492
7493   // Determine whether byte-swaping is necessary.
7494   stream_.doByteSwap[mode] = false;
7495   if ( deviceFormat != SND_PCM_FORMAT_S8 ) {
7496     result = snd_pcm_format_cpu_endian( deviceFormat );
7497     if ( result == 0 )
7498       stream_.doByteSwap[mode] = true;
7499     else if (result < 0) {
7500       snd_pcm_close( phandle );
7501       errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting pcm device (" << name << ") endian-ness, " << snd_strerror( result ) << ".";
7502       errorText_ = errorStream_.str();
7503       return FAILURE;
7504     }
7505   }
7506
7507   // Set the sample rate.
7508   result = snd_pcm_hw_params_set_rate_near( phandle, hw_params, (unsigned int*) &sampleRate, 0 );
7509   if ( result < 0 ) {
7510     snd_pcm_close( phandle );
7511     errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting sample rate on device (" << name << "), " << snd_strerror( result ) << ".";
7512     errorText_ = errorStream_.str();
7513     return FAILURE;
7514   }
7515
7516   // Determine the number of channels for this device.  We support a possible
7517   // minimum device channel number > than the value requested by the user.
7518   stream_.nUserChannels[mode] = channels;
7519   unsigned int value;
7520   result = snd_pcm_hw_params_get_channels_max( hw_params, &value );
7521   unsigned int deviceChannels = value;
7522   if ( result < 0 || deviceChannels < channels + firstChannel ) {
7523     snd_pcm_close( phandle );
7524     errorStream_ << "RtApiAlsa::probeDeviceOpen: requested channel parameters not supported by device (" << name << "), " << snd_strerror( result ) << ".";
7525     errorText_ = errorStream_.str();
7526     return FAILURE;
7527   }
7528
7529   result = snd_pcm_hw_params_get_channels_min( hw_params, &value );
7530   if ( result < 0 ) {
7531     snd_pcm_close( phandle );
7532     errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting minimum channels for device (" << name << "), " << snd_strerror( result ) << ".";
7533     errorText_ = errorStream_.str();
7534     return FAILURE;
7535   }
7536   deviceChannels = value;
7537   if ( deviceChannels < channels + firstChannel ) deviceChannels = channels + firstChannel;
7538   stream_.nDeviceChannels[mode] = deviceChannels;
7539
7540   // Set the device channels.
7541   result = snd_pcm_hw_params_set_channels( phandle, hw_params, deviceChannels );
7542   if ( result < 0 ) {
7543     snd_pcm_close( phandle );
7544     errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting channels for device (" << name << "), " << snd_strerror( result ) << ".";
7545     errorText_ = errorStream_.str();
7546     return FAILURE;
7547   }
7548
7549   // Set the buffer (or period) size.
7550   int dir = 0;
7551   snd_pcm_uframes_t periodSize = *bufferSize;
7552   result = snd_pcm_hw_params_set_period_size_near( phandle, hw_params, &periodSize, &dir );
7553   if ( result < 0 ) {
7554     snd_pcm_close( phandle );
7555     errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting period size for device (" << name << "), " << snd_strerror( result ) << ".";
7556     errorText_ = errorStream_.str();
7557     return FAILURE;
7558   }
7559   *bufferSize = periodSize;
7560
7561   // Set the buffer number, which in ALSA is referred to as the "period".
7562   unsigned int periods = 0;
7563   if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) periods = 2;
7564   if ( options && options->numberOfBuffers > 0 ) periods = options->numberOfBuffers;
7565   if ( periods < 2 ) periods = 4; // a fairly safe default value
7566   result = snd_pcm_hw_params_set_periods_near( phandle, hw_params, &periods, &dir );
7567   if ( result < 0 ) {
7568     snd_pcm_close( phandle );
7569     errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting periods for device (" << name << "), " << snd_strerror( result ) << ".";
7570     errorText_ = errorStream_.str();
7571     return FAILURE;
7572   }
7573
7574   // If attempting to setup a duplex stream, the bufferSize parameter
7575   // MUST be the same in both directions!
7576   if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) {
7577     snd_pcm_close( phandle );
7578     errorStream_ << "RtApiAlsa::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << name << ").";
7579     errorText_ = errorStream_.str();
7580     return FAILURE;
7581   }
7582
7583   stream_.bufferSize = *bufferSize;
7584
7585   // Install the hardware configuration
7586   result = snd_pcm_hw_params( phandle, hw_params );
7587   if ( result < 0 ) {
7588     snd_pcm_close( phandle );
7589     errorStream_ << "RtApiAlsa::probeDeviceOpen: error installing hardware configuration on device (" << name << "), " << snd_strerror( result ) << ".";
7590     errorText_ = errorStream_.str();
7591     return FAILURE;
7592   }
7593
7594 #if defined(__RTAUDIO_DEBUG__)
7595   fprintf(stderr, "\nRtApiAlsa: dump hardware params after installation:\n\n");
7596   snd_pcm_hw_params_dump( hw_params, out );
7597 #endif
7598
7599   // Set the software configuration to fill buffers with zeros and prevent device stopping on xruns.
7600   snd_pcm_sw_params_t *sw_params = NULL;
7601   snd_pcm_sw_params_alloca( &sw_params );
7602   snd_pcm_sw_params_current( phandle, sw_params );
7603   snd_pcm_sw_params_set_start_threshold( phandle, sw_params, *bufferSize );
7604   snd_pcm_sw_params_set_stop_threshold( phandle, sw_params, ULONG_MAX );
7605   snd_pcm_sw_params_set_silence_threshold( phandle, sw_params, 0 );
7606
7607   // The following two settings were suggested by Theo Veenker
7608   //snd_pcm_sw_params_set_avail_min( phandle, sw_params, *bufferSize );
7609   //snd_pcm_sw_params_set_xfer_align( phandle, sw_params, 1 );
7610
7611   // here are two options for a fix
7612   //snd_pcm_sw_params_set_silence_size( phandle, sw_params, ULONG_MAX );
7613   snd_pcm_uframes_t val;
7614   snd_pcm_sw_params_get_boundary( sw_params, &val );
7615   snd_pcm_sw_params_set_silence_size( phandle, sw_params, val );
7616
7617   result = snd_pcm_sw_params( phandle, sw_params );
7618   if ( result < 0 ) {
7619     snd_pcm_close( phandle );
7620     errorStream_ << "RtApiAlsa::probeDeviceOpen: error installing software configuration on device (" << name << "), " << snd_strerror( result ) << ".";
7621     errorText_ = errorStream_.str();
7622     return FAILURE;
7623   }
7624
7625 #if defined(__RTAUDIO_DEBUG__)
7626   fprintf(stderr, "\nRtApiAlsa: dump software params after installation:\n\n");
7627   snd_pcm_sw_params_dump( sw_params, out );
7628 #endif
7629
7630   // Set flags for buffer conversion
7631   stream_.doConvertBuffer[mode] = false;
7632   if ( stream_.userFormat != stream_.deviceFormat[mode] )
7633     stream_.doConvertBuffer[mode] = true;
7634   if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )
7635     stream_.doConvertBuffer[mode] = true;
7636   if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
7637        stream_.nUserChannels[mode] > 1 )
7638     stream_.doConvertBuffer[mode] = true;
7639
7640   // Allocate the ApiHandle if necessary and then save.
7641   AlsaHandle *apiInfo = 0;
7642   if ( stream_.apiHandle == 0 ) {
7643     try {
7644       apiInfo = (AlsaHandle *) new AlsaHandle;
7645     }
7646     catch ( std::bad_alloc& ) {
7647       errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating AlsaHandle memory.";
7648       goto error;
7649     }
7650
7651     if ( pthread_cond_init( &apiInfo->runnable_cv, NULL ) ) {
7652       errorText_ = "RtApiAlsa::probeDeviceOpen: error initializing pthread condition variable.";
7653       goto error;
7654     }
7655
7656     stream_.apiHandle = (void *) apiInfo;
7657     apiInfo->handles[0] = 0;
7658     apiInfo->handles[1] = 0;
7659   }
7660   else {
7661     apiInfo = (AlsaHandle *) stream_.apiHandle;
7662   }
7663   apiInfo->handles[mode] = phandle;
7664   phandle = 0;
7665
7666   // Allocate necessary internal buffers.
7667   unsigned long bufferBytes;
7668   bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
7669   stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
7670   if ( stream_.userBuffer[mode] == NULL ) {
7671     errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating user buffer memory.";
7672     goto error;
7673   }
7674
7675   if ( stream_.doConvertBuffer[mode] ) {
7676
7677     bool makeBuffer = true;
7678     bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
7679     if ( mode == INPUT ) {
7680       if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
7681         unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
7682         if ( bufferBytes <= bytesOut ) makeBuffer = false;
7683       }
7684     }
7685
7686     if ( makeBuffer ) {
7687       bufferBytes *= *bufferSize;
7688       if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
7689       stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
7690       if ( stream_.deviceBuffer == NULL ) {
7691         errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating device buffer memory.";
7692         goto error;
7693       }
7694     }
7695   }
7696
7697   stream_.sampleRate = sampleRate;
7698   stream_.nBuffers = periods;
7699   stream_.device[mode] = device;
7700   stream_.state = STREAM_STOPPED;
7701
7702   // Setup the buffer conversion information structure.
7703   if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );
7704
7705   // Setup thread if necessary.
7706   if ( stream_.mode == OUTPUT && mode == INPUT ) {
7707     // We had already set up an output stream.
7708     stream_.mode = DUPLEX;
7709     // Link the streams if possible.
7710     apiInfo->synchronized = false;
7711     if ( snd_pcm_link( apiInfo->handles[0], apiInfo->handles[1] ) == 0 )
7712       apiInfo->synchronized = true;
7713     else {
7714       errorText_ = "RtApiAlsa::probeDeviceOpen: unable to synchronize input and output devices.";
7715       error( RtAudioError::WARNING );
7716     }
7717   }
7718   else {
7719     stream_.mode = mode;
7720
7721     // Setup callback thread.
7722     stream_.callbackInfo.object = (void *) this;
7723
7724     // Set the thread attributes for joinable and realtime scheduling
7725     // priority (optional).  The higher priority will only take affect
7726     // if the program is run as root or suid. Note, under Linux
7727     // processes with CAP_SYS_NICE privilege, a user can change
7728     // scheduling policy and priority (thus need not be root). See
7729     // POSIX "capabilities".
7730     pthread_attr_t attr;
7731     pthread_attr_init( &attr );
7732     pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
7733
7734 #ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
7735     if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
7736       // We previously attempted to increase the audio callback priority
7737       // to SCHED_RR here via the attributes.  However, while no errors
7738       // were reported in doing so, it did not work.  So, now this is
7739       // done in the alsaCallbackHandler function.
7740       stream_.callbackInfo.doRealtime = true;
7741       int priority = options->priority;
7742       int min = sched_get_priority_min( SCHED_RR );
7743       int max = sched_get_priority_max( SCHED_RR );
7744       if ( priority < min ) priority = min;
7745       else if ( priority > max ) priority = max;
7746       stream_.callbackInfo.priority = priority;
7747     }
7748 #endif
7749
7750     stream_.callbackInfo.isRunning = true;
7751     result = pthread_create( &stream_.callbackInfo.thread, &attr, alsaCallbackHandler, &stream_.callbackInfo );
7752     pthread_attr_destroy( &attr );
7753     if ( result ) {
7754       stream_.callbackInfo.isRunning = false;
7755       errorText_ = "RtApiAlsa::error creating callback thread!";
7756       goto error;
7757     }
7758   }
7759
7760   return SUCCESS;
7761
7762  error:
7763   if ( apiInfo ) {
7764     pthread_cond_destroy( &apiInfo->runnable_cv );
7765     if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] );
7766     if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] );
7767     delete apiInfo;
7768     stream_.apiHandle = 0;
7769   }
7770
7771   if ( phandle) snd_pcm_close( phandle );
7772
7773   for ( int i=0; i<2; i++ ) {
7774     if ( stream_.userBuffer[i] ) {
7775       free( stream_.userBuffer[i] );
7776       stream_.userBuffer[i] = 0;
7777     }
7778   }
7779
7780   if ( stream_.deviceBuffer ) {
7781     free( stream_.deviceBuffer );
7782     stream_.deviceBuffer = 0;
7783   }
7784
7785   stream_.state = STREAM_CLOSED;
7786   return FAILURE;
7787 }
7788
7789 void RtApiAlsa :: closeStream()
7790 {
7791   if ( stream_.state == STREAM_CLOSED ) {
7792     errorText_ = "RtApiAlsa::closeStream(): no open stream to close!";
7793     error( RtAudioError::WARNING );
7794     return;
7795   }
7796
7797   AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
7798   stream_.callbackInfo.isRunning = false;
7799   MUTEX_LOCK( &stream_.mutex );
7800   if ( stream_.state == STREAM_STOPPED ) {
7801     apiInfo->runnable = true;
7802     pthread_cond_signal( &apiInfo->runnable_cv );
7803   }
7804   MUTEX_UNLOCK( &stream_.mutex );
7805   pthread_join( stream_.callbackInfo.thread, NULL );
7806
7807   if ( stream_.state == STREAM_RUNNING ) {
7808     stream_.state = STREAM_STOPPED;
7809     if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )
7810       snd_pcm_drop( apiInfo->handles[0] );
7811     if ( stream_.mode == INPUT || stream_.mode == DUPLEX )
7812       snd_pcm_drop( apiInfo->handles[1] );
7813   }
7814
7815   if ( apiInfo ) {
7816     pthread_cond_destroy( &apiInfo->runnable_cv );
7817     if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] );
7818     if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] );
7819     delete apiInfo;
7820     stream_.apiHandle = 0;
7821   }
7822
7823   for ( int i=0; i<2; i++ ) {
7824     if ( stream_.userBuffer[i] ) {
7825       free( stream_.userBuffer[i] );
7826       stream_.userBuffer[i] = 0;
7827     }
7828   }
7829
7830   if ( stream_.deviceBuffer ) {
7831     free( stream_.deviceBuffer );
7832     stream_.deviceBuffer = 0;
7833   }
7834
7835   stream_.mode = UNINITIALIZED;
7836   stream_.state = STREAM_CLOSED;
7837 }
7838
7839 void RtApiAlsa :: startStream()
7840 {
7841   // This method calls snd_pcm_prepare if the device isn't already in that state.
7842
7843   verifyStream();
7844   if ( stream_.state == STREAM_RUNNING ) {
7845     errorText_ = "RtApiAlsa::startStream(): the stream is already running!";
7846     error( RtAudioError::WARNING );
7847     return;
7848   }
7849
7850   MUTEX_LOCK( &stream_.mutex );
7851
7852   int result = 0;
7853   snd_pcm_state_t state;
7854   AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
7855   snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;
7856   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
7857     state = snd_pcm_state( handle[0] );
7858     if ( state != SND_PCM_STATE_PREPARED ) {
7859       result = snd_pcm_prepare( handle[0] );
7860       if ( result < 0 ) {
7861         errorStream_ << "RtApiAlsa::startStream: error preparing output pcm device, " << snd_strerror( result ) << ".";
7862         errorText_ = errorStream_.str();
7863         goto unlock;
7864       }
7865     }
7866   }
7867
7868   if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) {
7869     result = snd_pcm_drop(handle[1]); // fix to remove stale data received since device has been open
7870     state = snd_pcm_state( handle[1] );
7871     if ( state != SND_PCM_STATE_PREPARED ) {
7872       result = snd_pcm_prepare( handle[1] );
7873       if ( result < 0 ) {
7874         errorStream_ << "RtApiAlsa::startStream: error preparing input pcm device, " << snd_strerror( result ) << ".";
7875         errorText_ = errorStream_.str();
7876         goto unlock;
7877       }
7878     }
7879   }
7880
7881   stream_.state = STREAM_RUNNING;
7882
7883  unlock:
7884   apiInfo->runnable = true;
7885   pthread_cond_signal( &apiInfo->runnable_cv );
7886   MUTEX_UNLOCK( &stream_.mutex );
7887
7888   if ( result >= 0 ) return;
7889   error( RtAudioError::SYSTEM_ERROR );
7890 }
7891
7892 void RtApiAlsa :: stopStream()
7893 {
7894   verifyStream();
7895   if ( stream_.state == STREAM_STOPPED ) {
7896     errorText_ = "RtApiAlsa::stopStream(): the stream is already stopped!";
7897     error( RtAudioError::WARNING );
7898     return;
7899   }
7900
7901   stream_.state = STREAM_STOPPED;
7902   MUTEX_LOCK( &stream_.mutex );
7903
7904   int result = 0;
7905   AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
7906   snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;
7907   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
7908     if ( apiInfo->synchronized ) 
7909       result = snd_pcm_drop( handle[0] );
7910     else
7911       result = snd_pcm_drain( handle[0] );
7912     if ( result < 0 ) {
7913       errorStream_ << "RtApiAlsa::stopStream: error draining output pcm device, " << snd_strerror( result ) << ".";
7914       errorText_ = errorStream_.str();
7915       goto unlock;
7916     }
7917   }
7918
7919   if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) {
7920     result = snd_pcm_drop( handle[1] );
7921     if ( result < 0 ) {
7922       errorStream_ << "RtApiAlsa::stopStream: error stopping input pcm device, " << snd_strerror( result ) << ".";
7923       errorText_ = errorStream_.str();
7924       goto unlock;
7925     }
7926   }
7927
7928  unlock:
7929   apiInfo->runnable = false; // fixes high CPU usage when stopped
7930   MUTEX_UNLOCK( &stream_.mutex );
7931
7932   if ( result >= 0 ) return;
7933   error( RtAudioError::SYSTEM_ERROR );
7934 }
7935
7936 void RtApiAlsa :: abortStream()
7937 {
7938   verifyStream();
7939   if ( stream_.state == STREAM_STOPPED ) {
7940     errorText_ = "RtApiAlsa::abortStream(): the stream is already stopped!";
7941     error( RtAudioError::WARNING );
7942     return;
7943   }
7944
7945   stream_.state = STREAM_STOPPED;
7946   MUTEX_LOCK( &stream_.mutex );
7947
7948   int result = 0;
7949   AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
7950   snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;
7951   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
7952     result = snd_pcm_drop( handle[0] );
7953     if ( result < 0 ) {
7954       errorStream_ << "RtApiAlsa::abortStream: error aborting output pcm device, " << snd_strerror( result ) << ".";
7955       errorText_ = errorStream_.str();
7956       goto unlock;
7957     }
7958   }
7959
7960   if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) {
7961     result = snd_pcm_drop( handle[1] );
7962     if ( result < 0 ) {
7963       errorStream_ << "RtApiAlsa::abortStream: error aborting input pcm device, " << snd_strerror( result ) << ".";
7964       errorText_ = errorStream_.str();
7965       goto unlock;
7966     }
7967   }
7968
7969  unlock:
7970   apiInfo->runnable = false; // fixes high CPU usage when stopped
7971   MUTEX_UNLOCK( &stream_.mutex );
7972
7973   if ( result >= 0 ) return;
7974   error( RtAudioError::SYSTEM_ERROR );
7975 }
7976
7977 void RtApiAlsa :: callbackEvent()
7978 {
7979   AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
7980   if ( stream_.state == STREAM_STOPPED ) {
7981     MUTEX_LOCK( &stream_.mutex );
7982     while ( !apiInfo->runnable )
7983       pthread_cond_wait( &apiInfo->runnable_cv, &stream_.mutex );
7984
7985     if ( stream_.state != STREAM_RUNNING ) {
7986       MUTEX_UNLOCK( &stream_.mutex );
7987       return;
7988     }
7989     MUTEX_UNLOCK( &stream_.mutex );
7990   }
7991
7992   if ( stream_.state == STREAM_CLOSED ) {
7993     errorText_ = "RtApiAlsa::callbackEvent(): the stream is closed ... this shouldn't happen!";
7994     error( RtAudioError::WARNING );
7995     return;
7996   }
7997
7998   int doStopStream = 0;
7999   RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
8000   double streamTime = getStreamTime();
8001   RtAudioStreamStatus status = 0;
8002   if ( stream_.mode != INPUT && apiInfo->xrun[0] == true ) {
8003     status |= RTAUDIO_OUTPUT_UNDERFLOW;
8004     apiInfo->xrun[0] = false;
8005   }
8006   if ( stream_.mode != OUTPUT && apiInfo->xrun[1] == true ) {
8007     status |= RTAUDIO_INPUT_OVERFLOW;
8008     apiInfo->xrun[1] = false;
8009   }
8010   doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1],
8011                            stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData );
8012
8013   if ( doStopStream == 2 ) {
8014     abortStream();
8015     return;
8016   }
8017
8018   MUTEX_LOCK( &stream_.mutex );
8019
8020   // The state might change while waiting on a mutex.
8021   if ( stream_.state == STREAM_STOPPED ) goto unlock;
8022
8023   int result;
8024   char *buffer;
8025   int channels;
8026   snd_pcm_t **handle;
8027   snd_pcm_sframes_t frames;
8028   RtAudioFormat format;
8029   handle = (snd_pcm_t **) apiInfo->handles;
8030
8031   if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
8032
8033     // Setup parameters.
8034     if ( stream_.doConvertBuffer[1] ) {
8035       buffer = stream_.deviceBuffer;
8036       channels = stream_.nDeviceChannels[1];
8037       format = stream_.deviceFormat[1];
8038     }
8039     else {
8040       buffer = stream_.userBuffer[1];
8041       channels = stream_.nUserChannels[1];
8042       format = stream_.userFormat;
8043     }
8044
8045     // Read samples from device in interleaved/non-interleaved format.
8046     if ( stream_.deviceInterleaved[1] )
8047       result = snd_pcm_readi( handle[1], buffer, stream_.bufferSize );
8048     else {
8049       void *bufs[channels];
8050       size_t offset = stream_.bufferSize * formatBytes( format );
8051       for ( int i=0; i<channels; i++ )
8052         bufs[i] = (void *) (buffer + (i * offset));
8053       result = snd_pcm_readn( handle[1], bufs, stream_.bufferSize );
8054     }
8055
8056     if ( result < (int) stream_.bufferSize ) {
8057       // Either an error or overrun occured.
8058       if ( result == -EPIPE ) {
8059         snd_pcm_state_t state = snd_pcm_state( handle[1] );
8060         if ( state == SND_PCM_STATE_XRUN ) {
8061           apiInfo->xrun[1] = true;
8062           result = snd_pcm_prepare( handle[1] );
8063           if ( result < 0 ) {
8064             errorStream_ << "RtApiAlsa::callbackEvent: error preparing device after overrun, " << snd_strerror( result ) << ".";
8065             errorText_ = errorStream_.str();
8066           }
8067         }
8068         else {
8069           errorStream_ << "RtApiAlsa::callbackEvent: error, current state is " << snd_pcm_state_name( state ) << ", " << snd_strerror( result ) << ".";
8070           errorText_ = errorStream_.str();
8071         }
8072       }
8073       else {
8074         errorStream_ << "RtApiAlsa::callbackEvent: audio read error, " << snd_strerror( result ) << ".";
8075         errorText_ = errorStream_.str();
8076       }
8077       error( RtAudioError::WARNING );
8078       goto tryOutput;
8079     }
8080
8081     // Do byte swapping if necessary.
8082     if ( stream_.doByteSwap[1] )
8083       byteSwapBuffer( buffer, stream_.bufferSize * channels, format );
8084
8085     // Do buffer conversion if necessary.
8086     if ( stream_.doConvertBuffer[1] )
8087       convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
8088
8089     // Check stream latency
8090     result = snd_pcm_delay( handle[1], &frames );
8091     if ( result == 0 && frames > 0 ) stream_.latency[1] = frames;
8092   }
8093
8094  tryOutput:
8095
8096   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
8097
8098     // Setup parameters and do buffer conversion if necessary.
8099     if ( stream_.doConvertBuffer[0] ) {
8100       buffer = stream_.deviceBuffer;
8101       convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] );
8102       channels = stream_.nDeviceChannels[0];
8103       format = stream_.deviceFormat[0];
8104     }
8105     else {
8106       buffer = stream_.userBuffer[0];
8107       channels = stream_.nUserChannels[0];
8108       format = stream_.userFormat;
8109     }
8110
8111     // Do byte swapping if necessary.
8112     if ( stream_.doByteSwap[0] )
8113       byteSwapBuffer(buffer, stream_.bufferSize * channels, format);
8114
8115     // Write samples to device in interleaved/non-interleaved format.
8116     if ( stream_.deviceInterleaved[0] )
8117       result = snd_pcm_writei( handle[0], buffer, stream_.bufferSize );
8118     else {
8119       void *bufs[channels];
8120       size_t offset = stream_.bufferSize * formatBytes( format );
8121       for ( int i=0; i<channels; i++ )
8122         bufs[i] = (void *) (buffer + (i * offset));
8123       result = snd_pcm_writen( handle[0], bufs, stream_.bufferSize );
8124     }
8125
8126     if ( result < (int) stream_.bufferSize ) {
8127       // Either an error or underrun occured.
8128       if ( result == -EPIPE ) {
8129         snd_pcm_state_t state = snd_pcm_state( handle[0] );
8130         if ( state == SND_PCM_STATE_XRUN ) {
8131           apiInfo->xrun[0] = true;
8132           result = snd_pcm_prepare( handle[0] );
8133           if ( result < 0 ) {
8134             errorStream_ << "RtApiAlsa::callbackEvent: error preparing device after underrun, " << snd_strerror( result ) << ".";
8135             errorText_ = errorStream_.str();
8136           }
8137           else
8138             errorText_ =  "RtApiAlsa::callbackEvent: audio write error, underrun.";
8139         }
8140         else {
8141           errorStream_ << "RtApiAlsa::callbackEvent: error, current state is " << snd_pcm_state_name( state ) << ", " << snd_strerror( result ) << ".";
8142           errorText_ = errorStream_.str();
8143         }
8144       }
8145       else {
8146         errorStream_ << "RtApiAlsa::callbackEvent: audio write error, " << snd_strerror( result ) << ".";
8147         errorText_ = errorStream_.str();
8148       }
8149       error( RtAudioError::WARNING );
8150       goto unlock;
8151     }
8152
8153     // Check stream latency
8154     result = snd_pcm_delay( handle[0], &frames );
8155     if ( result == 0 && frames > 0 ) stream_.latency[0] = frames;
8156   }
8157
8158  unlock:
8159   MUTEX_UNLOCK( &stream_.mutex );
8160
8161   RtApi::tickStreamTime();
8162   if ( doStopStream == 1 ) this->stopStream();
8163 }
8164
8165 static void *alsaCallbackHandler( void *ptr )
8166 {
8167   CallbackInfo *info = (CallbackInfo *) ptr;
8168   RtApiAlsa *object = (RtApiAlsa *) info->object;
8169   bool *isRunning = &info->isRunning;
8170
8171 #ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
8172   if ( info->doRealtime ) {
8173     pthread_t tID = pthread_self();      // ID of this thread
8174     sched_param prio = { info->priority }; // scheduling priority of thread
8175     pthread_setschedparam( tID, SCHED_RR, &prio );
8176   }
8177 #endif
8178
8179   while ( *isRunning == true ) {
8180     pthread_testcancel();
8181     object->callbackEvent();
8182   }
8183
8184   pthread_exit( NULL );
8185 }
8186
8187 //******************** End of __LINUX_ALSA__ *********************//
8188 #endif
8189
8190 #if defined(__LINUX_PULSE__)
8191
8192 // Code written by Peter Meerwald, pmeerw@pmeerw.net
8193 // and Tristan Matthews.
8194
8195 #include <pulse/error.h>
8196 #include <pulse/simple.h>
8197 #include <cstdio>
8198
8199 static const unsigned int SUPPORTED_SAMPLERATES[] = { 8000, 16000, 22050, 32000,
8200                                                       44100, 48000, 96000, 0};
8201
8202 struct rtaudio_pa_format_mapping_t {
8203   RtAudioFormat rtaudio_format;
8204   pa_sample_format_t pa_format;
8205 };
8206
8207 static const rtaudio_pa_format_mapping_t supported_sampleformats[] = {
8208   {RTAUDIO_SINT16, PA_SAMPLE_S16LE},
8209   {RTAUDIO_SINT32, PA_SAMPLE_S32LE},
8210   {RTAUDIO_FLOAT32, PA_SAMPLE_FLOAT32LE},
8211   {0, PA_SAMPLE_INVALID}};
8212
8213 struct PulseAudioHandle {
8214   pa_simple *s_play;
8215   pa_simple *s_rec;
8216   pthread_t thread;
8217   pthread_cond_t runnable_cv;
8218   bool runnable;
8219   PulseAudioHandle() : s_play(0), s_rec(0), runnable(false) { }
8220 };
8221
8222 RtApiPulse::~RtApiPulse()
8223 {
8224   if ( stream_.state != STREAM_CLOSED )
8225     closeStream();
8226 }
8227
8228 unsigned int RtApiPulse::getDeviceCount( void )
8229 {
8230   return 1;
8231 }
8232
8233 RtAudio::DeviceInfo RtApiPulse::getDeviceInfo( unsigned int /*device*/ )
8234 {
8235   RtAudio::DeviceInfo info;
8236   info.probed = true;
8237   info.name = "PulseAudio";
8238   info.outputChannels = 2;
8239   info.inputChannels = 2;
8240   info.duplexChannels = 2;
8241   info.isDefaultOutput = true;
8242   info.isDefaultInput = true;
8243
8244   for ( const unsigned int *sr = SUPPORTED_SAMPLERATES; *sr; ++sr )
8245     info.sampleRates.push_back( *sr );
8246
8247   info.preferredSampleRate = 48000;
8248   info.nativeFormats = RTAUDIO_SINT16 | RTAUDIO_SINT32 | RTAUDIO_FLOAT32;
8249
8250   return info;
8251 }
8252
8253 static void *pulseaudio_callback( void * user )
8254 {
8255   CallbackInfo *cbi = static_cast<CallbackInfo *>( user );
8256   RtApiPulse *context = static_cast<RtApiPulse *>( cbi->object );
8257   volatile bool *isRunning = &cbi->isRunning;
8258
8259   while ( *isRunning ) {
8260     pthread_testcancel();
8261     context->callbackEvent();
8262   }
8263
8264   pthread_exit( NULL );
8265 }
8266
8267 void RtApiPulse::closeStream( void )
8268 {
8269   PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );
8270
8271   stream_.callbackInfo.isRunning = false;
8272   if ( pah ) {
8273     MUTEX_LOCK( &stream_.mutex );
8274     if ( stream_.state == STREAM_STOPPED ) {
8275       pah->runnable = true;
8276       pthread_cond_signal( &pah->runnable_cv );
8277     }
8278     MUTEX_UNLOCK( &stream_.mutex );
8279
8280     pthread_join( pah->thread, 0 );
8281     if ( pah->s_play ) {
8282       pa_simple_flush( pah->s_play, NULL );
8283       pa_simple_free( pah->s_play );
8284     }
8285     if ( pah->s_rec )
8286       pa_simple_free( pah->s_rec );
8287
8288     pthread_cond_destroy( &pah->runnable_cv );
8289     delete pah;
8290     stream_.apiHandle = 0;
8291   }
8292
8293   if ( stream_.userBuffer[0] ) {
8294     free( stream_.userBuffer[0] );
8295     stream_.userBuffer[0] = 0;
8296   }
8297   if ( stream_.userBuffer[1] ) {
8298     free( stream_.userBuffer[1] );
8299     stream_.userBuffer[1] = 0;
8300   }
8301
8302   stream_.state = STREAM_CLOSED;
8303   stream_.mode = UNINITIALIZED;
8304 }
8305
8306 void RtApiPulse::callbackEvent( void )
8307 {
8308   PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );
8309
8310   if ( stream_.state == STREAM_STOPPED ) {
8311     MUTEX_LOCK( &stream_.mutex );
8312     while ( !pah->runnable )
8313       pthread_cond_wait( &pah->runnable_cv, &stream_.mutex );
8314
8315     if ( stream_.state != STREAM_RUNNING ) {
8316       MUTEX_UNLOCK( &stream_.mutex );
8317       return;
8318     }
8319     MUTEX_UNLOCK( &stream_.mutex );
8320   }
8321
8322   if ( stream_.state == STREAM_CLOSED ) {
8323     errorText_ = "RtApiPulse::callbackEvent(): the stream is closed ... "
8324       "this shouldn't happen!";
8325     error( RtAudioError::WARNING );
8326     return;
8327   }
8328
8329   RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
8330   double streamTime = getStreamTime();
8331   RtAudioStreamStatus status = 0;
8332   int doStopStream = callback( stream_.userBuffer[OUTPUT], stream_.userBuffer[INPUT],
8333                                stream_.bufferSize, streamTime, status,
8334                                stream_.callbackInfo.userData );
8335
8336   if ( doStopStream == 2 ) {
8337     abortStream();
8338     return;
8339   }
8340
8341   MUTEX_LOCK( &stream_.mutex );
8342   void *pulse_in = stream_.doConvertBuffer[INPUT] ? stream_.deviceBuffer : stream_.userBuffer[INPUT];
8343   void *pulse_out = stream_.doConvertBuffer[OUTPUT] ? stream_.deviceBuffer : stream_.userBuffer[OUTPUT];
8344
8345   if ( stream_.state != STREAM_RUNNING )
8346     goto unlock;
8347
8348   int pa_error;
8349   size_t bytes;
8350   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
8351     if ( stream_.doConvertBuffer[OUTPUT] ) {
8352         convertBuffer( stream_.deviceBuffer,
8353                        stream_.userBuffer[OUTPUT],
8354                        stream_.convertInfo[OUTPUT] );
8355         bytes = stream_.nDeviceChannels[OUTPUT] * stream_.bufferSize *
8356                 formatBytes( stream_.deviceFormat[OUTPUT] );
8357     } else
8358         bytes = stream_.nUserChannels[OUTPUT] * stream_.bufferSize *
8359                 formatBytes( stream_.userFormat );
8360
8361     if ( pa_simple_write( pah->s_play, pulse_out, bytes, &pa_error ) < 0 ) {
8362       errorStream_ << "RtApiPulse::callbackEvent: audio write error, " <<
8363         pa_strerror( pa_error ) << ".";
8364       errorText_ = errorStream_.str();
8365       error( RtAudioError::WARNING );
8366     }
8367   }
8368
8369   if ( stream_.mode == INPUT || stream_.mode == DUPLEX) {
8370     if ( stream_.doConvertBuffer[INPUT] )
8371       bytes = stream_.nDeviceChannels[INPUT] * stream_.bufferSize *
8372         formatBytes( stream_.deviceFormat[INPUT] );
8373     else
8374       bytes = stream_.nUserChannels[INPUT] * stream_.bufferSize *
8375         formatBytes( stream_.userFormat );
8376             
8377     if ( pa_simple_read( pah->s_rec, pulse_in, bytes, &pa_error ) < 0 ) {
8378       errorStream_ << "RtApiPulse::callbackEvent: audio read error, " <<
8379         pa_strerror( pa_error ) << ".";
8380       errorText_ = errorStream_.str();
8381       error( RtAudioError::WARNING );
8382     }
8383     if ( stream_.doConvertBuffer[INPUT] ) {
8384       convertBuffer( stream_.userBuffer[INPUT],
8385                      stream_.deviceBuffer,
8386                      stream_.convertInfo[INPUT] );
8387     }
8388   }
8389
8390  unlock:
8391   MUTEX_UNLOCK( &stream_.mutex );
8392   RtApi::tickStreamTime();
8393
8394   if ( doStopStream == 1 )
8395     stopStream();
8396 }
8397
8398 void RtApiPulse::startStream( void )
8399 {
8400   PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );
8401
8402   if ( stream_.state == STREAM_CLOSED ) {
8403     errorText_ = "RtApiPulse::startStream(): the stream is not open!";
8404     error( RtAudioError::INVALID_USE );
8405     return;
8406   }
8407   if ( stream_.state == STREAM_RUNNING ) {
8408     errorText_ = "RtApiPulse::startStream(): the stream is already running!";
8409     error( RtAudioError::WARNING );
8410     return;
8411   }
8412
8413   MUTEX_LOCK( &stream_.mutex );
8414
8415   stream_.state = STREAM_RUNNING;
8416
8417   pah->runnable = true;
8418   pthread_cond_signal( &pah->runnable_cv );
8419   MUTEX_UNLOCK( &stream_.mutex );
8420 }
8421
8422 void RtApiPulse::stopStream( void )
8423 {
8424   PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );
8425
8426   if ( stream_.state == STREAM_CLOSED ) {
8427     errorText_ = "RtApiPulse::stopStream(): the stream is not open!";
8428     error( RtAudioError::INVALID_USE );
8429     return;
8430   }
8431   if ( stream_.state == STREAM_STOPPED ) {
8432     errorText_ = "RtApiPulse::stopStream(): the stream is already stopped!";
8433     error( RtAudioError::WARNING );
8434     return;
8435   }
8436
8437   stream_.state = STREAM_STOPPED;
8438   MUTEX_LOCK( &stream_.mutex );
8439
8440   if ( pah && pah->s_play ) {
8441     int pa_error;
8442     if ( pa_simple_drain( pah->s_play, &pa_error ) < 0 ) {
8443       errorStream_ << "RtApiPulse::stopStream: error draining output device, " <<
8444         pa_strerror( pa_error ) << ".";
8445       errorText_ = errorStream_.str();
8446       MUTEX_UNLOCK( &stream_.mutex );
8447       error( RtAudioError::SYSTEM_ERROR );
8448       return;
8449     }
8450   }
8451
8452   stream_.state = STREAM_STOPPED;
8453   MUTEX_UNLOCK( &stream_.mutex );
8454 }
8455
8456 void RtApiPulse::abortStream( void )
8457 {
8458   PulseAudioHandle *pah = static_cast<PulseAudioHandle*>( stream_.apiHandle );
8459
8460   if ( stream_.state == STREAM_CLOSED ) {
8461     errorText_ = "RtApiPulse::abortStream(): the stream is not open!";
8462     error( RtAudioError::INVALID_USE );
8463     return;
8464   }
8465   if ( stream_.state == STREAM_STOPPED ) {
8466     errorText_ = "RtApiPulse::abortStream(): the stream is already stopped!";
8467     error( RtAudioError::WARNING );
8468     return;
8469   }
8470
8471   stream_.state = STREAM_STOPPED;
8472   MUTEX_LOCK( &stream_.mutex );
8473
8474   if ( pah && pah->s_play ) {
8475     int pa_error;
8476     if ( pa_simple_flush( pah->s_play, &pa_error ) < 0 ) {
8477       errorStream_ << "RtApiPulse::abortStream: error flushing output device, " <<
8478         pa_strerror( pa_error ) << ".";
8479       errorText_ = errorStream_.str();
8480       MUTEX_UNLOCK( &stream_.mutex );
8481       error( RtAudioError::SYSTEM_ERROR );
8482       return;
8483     }
8484   }
8485
8486   stream_.state = STREAM_STOPPED;
8487   MUTEX_UNLOCK( &stream_.mutex );
8488 }
8489
8490 bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
8491                                   unsigned int channels, unsigned int firstChannel,
8492                                   unsigned int sampleRate, RtAudioFormat format,
8493                                   unsigned int *bufferSize, RtAudio::StreamOptions *options )
8494 {
8495   PulseAudioHandle *pah = 0;
8496   unsigned long bufferBytes = 0;
8497   pa_sample_spec ss;
8498
8499   if ( device != 0 ) return false;
8500   if ( mode != INPUT && mode != OUTPUT ) return false;
8501   if ( channels != 1 && channels != 2 ) {
8502     errorText_ = "RtApiPulse::probeDeviceOpen: unsupported number of channels.";
8503     return false;
8504   }
8505   ss.channels = channels;
8506
8507   if ( firstChannel != 0 ) return false;
8508
8509   bool sr_found = false;
8510   for ( const unsigned int *sr = SUPPORTED_SAMPLERATES; *sr; ++sr ) {
8511     if ( sampleRate == *sr ) {
8512       sr_found = true;
8513       stream_.sampleRate = sampleRate;
8514       ss.rate = sampleRate;
8515       break;
8516     }
8517   }
8518   if ( !sr_found ) {
8519     errorText_ = "RtApiPulse::probeDeviceOpen: unsupported sample rate.";
8520     return false;
8521   }
8522
8523   bool sf_found = 0;
8524   for ( const rtaudio_pa_format_mapping_t *sf = supported_sampleformats;
8525         sf->rtaudio_format && sf->pa_format != PA_SAMPLE_INVALID; ++sf ) {
8526     if ( format == sf->rtaudio_format ) {
8527       sf_found = true;
8528       stream_.userFormat = sf->rtaudio_format;
8529       stream_.deviceFormat[mode] = stream_.userFormat;
8530       ss.format = sf->pa_format;
8531       break;
8532     }
8533   }
8534   if ( !sf_found ) { // Use internal data format conversion.
8535     stream_.userFormat = format;
8536     stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
8537     ss.format = PA_SAMPLE_FLOAT32LE;
8538   }
8539
8540   // Set other stream parameters.
8541   if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;
8542   else stream_.userInterleaved = true;
8543   stream_.deviceInterleaved[mode] = true;
8544   stream_.nBuffers = 1;
8545   stream_.doByteSwap[mode] = false;
8546   stream_.nUserChannels[mode] = channels;
8547   stream_.nDeviceChannels[mode] = channels + firstChannel;
8548   stream_.channelOffset[mode] = 0;
8549   std::string streamName = "RtAudio";
8550
8551   // Set flags for buffer conversion.
8552   stream_.doConvertBuffer[mode] = false;
8553   if ( stream_.userFormat != stream_.deviceFormat[mode] )
8554     stream_.doConvertBuffer[mode] = true;
8555   if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )
8556     stream_.doConvertBuffer[mode] = true;
8557
8558   // Allocate necessary internal buffers.
8559   bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
8560   stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
8561   if ( stream_.userBuffer[mode] == NULL ) {
8562     errorText_ = "RtApiPulse::probeDeviceOpen: error allocating user buffer memory.";
8563     goto error;
8564   }
8565   stream_.bufferSize = *bufferSize;
8566
8567   if ( stream_.doConvertBuffer[mode] ) {
8568
8569     bool makeBuffer = true;
8570     bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
8571     if ( mode == INPUT ) {
8572       if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
8573         unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
8574         if ( bufferBytes <= bytesOut ) makeBuffer = false;
8575       }
8576     }
8577
8578     if ( makeBuffer ) {
8579       bufferBytes *= *bufferSize;
8580       if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
8581       stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
8582       if ( stream_.deviceBuffer == NULL ) {
8583         errorText_ = "RtApiPulse::probeDeviceOpen: error allocating device buffer memory.";
8584         goto error;
8585       }
8586     }
8587   }
8588
8589   stream_.device[mode] = device;
8590
8591   // Setup the buffer conversion information structure.
8592   if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );
8593
8594   if ( !stream_.apiHandle ) {
8595     PulseAudioHandle *pah = new PulseAudioHandle;
8596     if ( !pah ) {
8597       errorText_ = "RtApiPulse::probeDeviceOpen: error allocating memory for handle.";
8598       goto error;
8599     }
8600
8601     stream_.apiHandle = pah;
8602     if ( pthread_cond_init( &pah->runnable_cv, NULL ) != 0 ) {
8603       errorText_ = "RtApiPulse::probeDeviceOpen: error creating condition variable.";
8604       goto error;
8605     }
8606   }
8607   pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );
8608
8609   int error;
8610   if ( options && !options->streamName.empty() ) streamName = options->streamName;
8611   switch ( mode ) {
8612   case INPUT:
8613     pa_buffer_attr buffer_attr;
8614     buffer_attr.fragsize = bufferBytes;
8615     buffer_attr.maxlength = -1;
8616
8617     pah->s_rec = pa_simple_new( NULL, streamName.c_str(), PA_STREAM_RECORD, NULL, "Record", &ss, NULL, &buffer_attr, &error );
8618     if ( !pah->s_rec ) {
8619       errorText_ = "RtApiPulse::probeDeviceOpen: error connecting input to PulseAudio server.";
8620       goto error;
8621     }
8622     break;
8623   case OUTPUT:
8624     pah->s_play = pa_simple_new( NULL, streamName.c_str(), PA_STREAM_PLAYBACK, NULL, "Playback", &ss, NULL, NULL, &error );
8625     if ( !pah->s_play ) {
8626       errorText_ = "RtApiPulse::probeDeviceOpen: error connecting output to PulseAudio server.";
8627       goto error;
8628     }
8629     break;
8630   default:
8631     goto error;
8632   }
8633
8634   if ( stream_.mode == UNINITIALIZED )
8635     stream_.mode = mode;
8636   else if ( stream_.mode == mode )
8637     goto error;
8638   else
8639     stream_.mode = DUPLEX;
8640
8641   if ( !stream_.callbackInfo.isRunning ) {
8642     stream_.callbackInfo.object = this;
8643     stream_.callbackInfo.isRunning = true;
8644     if ( pthread_create( &pah->thread, NULL, pulseaudio_callback, (void *)&stream_.callbackInfo) != 0 ) {
8645       errorText_ = "RtApiPulse::probeDeviceOpen: error creating thread.";
8646       goto error;
8647     }
8648   }
8649
8650   stream_.state = STREAM_STOPPED;
8651   return true;
8652  
8653  error:
8654   if ( pah && stream_.callbackInfo.isRunning ) {
8655     pthread_cond_destroy( &pah->runnable_cv );
8656     delete pah;
8657     stream_.apiHandle = 0;
8658   }
8659
8660   for ( int i=0; i<2; i++ ) {
8661     if ( stream_.userBuffer[i] ) {
8662       free( stream_.userBuffer[i] );
8663       stream_.userBuffer[i] = 0;
8664     }
8665   }
8666
8667   if ( stream_.deviceBuffer ) {
8668     free( stream_.deviceBuffer );
8669     stream_.deviceBuffer = 0;
8670   }
8671
8672   return FAILURE;
8673 }
8674
8675 //******************** End of __LINUX_PULSE__ *********************//
8676 #endif
8677
8678 #if defined(__LINUX_OSS__)
8679
8680 #include <unistd.h>
8681 #include <sys/ioctl.h>
8682 #include <unistd.h>
8683 #include <fcntl.h>
8684 #include <sys/soundcard.h>
8685 #include <errno.h>
8686 #include <math.h>
8687
8688 static void *ossCallbackHandler(void * ptr);
8689
8690 // A structure to hold various information related to the OSS API
8691 // implementation.
8692 struct OssHandle {
8693   int id[2];    // device ids
8694   bool xrun[2];
8695   bool triggered;
8696   pthread_cond_t runnable;
8697
8698   OssHandle()
8699     :triggered(false) { id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }
8700 };
8701
8702 RtApiOss :: RtApiOss()
8703 {
8704   // Nothing to do here.
8705 }
8706
8707 RtApiOss :: ~RtApiOss()
8708 {
8709   if ( stream_.state != STREAM_CLOSED ) closeStream();
8710 }
8711
8712 unsigned int RtApiOss :: getDeviceCount( void )
8713 {
8714   int mixerfd = open( "/dev/mixer", O_RDWR, 0 );
8715   if ( mixerfd == -1 ) {
8716     errorText_ = "RtApiOss::getDeviceCount: error opening '/dev/mixer'.";
8717     error( RtAudioError::WARNING );
8718     return 0;
8719   }
8720
8721   oss_sysinfo sysinfo;
8722   if ( ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo ) == -1 ) {
8723     close( mixerfd );
8724     errorText_ = "RtApiOss::getDeviceCount: error getting sysinfo, OSS version >= 4.0 is required.";
8725     error( RtAudioError::WARNING );
8726     return 0;
8727   }
8728
8729   close( mixerfd );
8730   return sysinfo.numaudios;
8731 }
8732
8733 RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
8734 {
8735   RtAudio::DeviceInfo info;
8736   info.probed = false;
8737
8738   int mixerfd = open( "/dev/mixer", O_RDWR, 0 );
8739   if ( mixerfd == -1 ) {
8740     errorText_ = "RtApiOss::getDeviceInfo: error opening '/dev/mixer'.";
8741     error( RtAudioError::WARNING );
8742     return info;
8743   }
8744
8745   oss_sysinfo sysinfo;
8746   int result = ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo );
8747   if ( result == -1 ) {
8748     close( mixerfd );
8749     errorText_ = "RtApiOss::getDeviceInfo: error getting sysinfo, OSS version >= 4.0 is required.";
8750     error( RtAudioError::WARNING );
8751     return info;
8752   }
8753
8754   unsigned nDevices = sysinfo.numaudios;
8755   if ( nDevices == 0 ) {
8756     close( mixerfd );
8757     errorText_ = "RtApiOss::getDeviceInfo: no devices found!";
8758     error( RtAudioError::INVALID_USE );
8759     return info;
8760   }
8761
8762   if ( device >= nDevices ) {
8763     close( mixerfd );
8764     errorText_ = "RtApiOss::getDeviceInfo: device ID is invalid!";
8765     error( RtAudioError::INVALID_USE );
8766     return info;
8767   }
8768
8769   oss_audioinfo ainfo;
8770   ainfo.dev = device;
8771   result = ioctl( mixerfd, SNDCTL_AUDIOINFO, &ainfo );
8772   close( mixerfd );
8773   if ( result == -1 ) {
8774     errorStream_ << "RtApiOss::getDeviceInfo: error getting device (" << ainfo.name << ") info.";
8775     errorText_ = errorStream_.str();
8776     error( RtAudioError::WARNING );
8777     return info;
8778   }
8779
8780   // Probe channels
8781   if ( ainfo.caps & PCM_CAP_OUTPUT ) info.outputChannels = ainfo.max_channels;
8782   if ( ainfo.caps & PCM_CAP_INPUT ) info.inputChannels = ainfo.max_channels;
8783   if ( ainfo.caps & PCM_CAP_DUPLEX ) {
8784     if ( info.outputChannels > 0 && info.inputChannels > 0 && ainfo.caps & PCM_CAP_DUPLEX )
8785       info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
8786   }
8787
8788   // Probe data formats ... do for input
8789   unsigned long mask = ainfo.iformats;
8790   if ( mask & AFMT_S16_LE || mask & AFMT_S16_BE )
8791     info.nativeFormats |= RTAUDIO_SINT16;
8792   if ( mask & AFMT_S8 )
8793     info.nativeFormats |= RTAUDIO_SINT8;
8794   if ( mask & AFMT_S32_LE || mask & AFMT_S32_BE )
8795     info.nativeFormats |= RTAUDIO_SINT32;
8796 #ifdef AFMT_FLOAT
8797   if ( mask & AFMT_FLOAT )
8798     info.nativeFormats |= RTAUDIO_FLOAT32;
8799 #endif
8800   if ( mask & AFMT_S24_LE || mask & AFMT_S24_BE )
8801     info.nativeFormats |= RTAUDIO_SINT24;
8802
8803   // Check that we have at least one supported format
8804   if ( info.nativeFormats == 0 ) {
8805     errorStream_ << "RtApiOss::getDeviceInfo: device (" << ainfo.name << ") data format not supported by RtAudio.";
8806     errorText_ = errorStream_.str();
8807     error( RtAudioError::WARNING );
8808     return info;
8809   }
8810
8811   // Probe the supported sample rates.
8812   info.sampleRates.clear();
8813   if ( ainfo.nrates ) {
8814     for ( unsigned int i=0; i<ainfo.nrates; i++ ) {
8815       for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
8816         if ( ainfo.rates[i] == SAMPLE_RATES[k] ) {
8817           info.sampleRates.push_back( SAMPLE_RATES[k] );
8818
8819           if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )
8820             info.preferredSampleRate = SAMPLE_RATES[k];
8821
8822           break;
8823         }
8824       }
8825     }
8826   }
8827   else {
8828     // Check min and max rate values;
8829     for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
8830       if ( ainfo.min_rate <= (int) SAMPLE_RATES[k] && ainfo.max_rate >= (int) SAMPLE_RATES[k] ) {
8831         info.sampleRates.push_back( SAMPLE_RATES[k] );
8832
8833         if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )
8834           info.preferredSampleRate = SAMPLE_RATES[k];
8835       }
8836     }
8837   }
8838
8839   if ( info.sampleRates.size() == 0 ) {
8840     errorStream_ << "RtApiOss::getDeviceInfo: no supported sample rates found for device (" << ainfo.name << ").";
8841     errorText_ = errorStream_.str();
8842     error( RtAudioError::WARNING );
8843   }
8844   else {
8845     info.probed = true;
8846     info.name = ainfo.name;
8847   }
8848
8849   return info;
8850 }
8851
8852
8853 bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
8854                                   unsigned int firstChannel, unsigned int sampleRate,
8855                                   RtAudioFormat format, unsigned int *bufferSize,
8856                                   RtAudio::StreamOptions *options )
8857 {
8858   int mixerfd = open( "/dev/mixer", O_RDWR, 0 );
8859   if ( mixerfd == -1 ) {
8860     errorText_ = "RtApiOss::probeDeviceOpen: error opening '/dev/mixer'.";
8861     return FAILURE;
8862   }
8863
8864   oss_sysinfo sysinfo;
8865   int result = ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo );
8866   if ( result == -1 ) {
8867     close( mixerfd );
8868     errorText_ = "RtApiOss::probeDeviceOpen: error getting sysinfo, OSS version >= 4.0 is required.";
8869     return FAILURE;
8870   }
8871
8872   unsigned nDevices = sysinfo.numaudios;
8873   if ( nDevices == 0 ) {
8874     // This should not happen because a check is made before this function is called.
8875     close( mixerfd );
8876     errorText_ = "RtApiOss::probeDeviceOpen: no devices found!";
8877     return FAILURE;
8878   }
8879
8880   if ( device >= nDevices ) {
8881     // This should not happen because a check is made before this function is called.
8882     close( mixerfd );
8883     errorText_ = "RtApiOss::probeDeviceOpen: device ID is invalid!";
8884     return FAILURE;
8885   }
8886
8887   oss_audioinfo ainfo;
8888   ainfo.dev = device;
8889   result = ioctl( mixerfd, SNDCTL_AUDIOINFO, &ainfo );
8890   close( mixerfd );
8891   if ( result == -1 ) {
8892     errorStream_ << "RtApiOss::getDeviceInfo: error getting device (" << ainfo.name << ") info.";
8893     errorText_ = errorStream_.str();
8894     return FAILURE;
8895   }
8896
8897   // Check if device supports input or output
8898   if ( ( mode == OUTPUT && !( ainfo.caps & PCM_CAP_OUTPUT ) ) ||
8899        ( mode == INPUT && !( ainfo.caps & PCM_CAP_INPUT ) ) ) {
8900     if ( mode == OUTPUT )
8901       errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support output.";
8902     else
8903       errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support input.";
8904     errorText_ = errorStream_.str();
8905     return FAILURE;
8906   }
8907
8908   int flags = 0;
8909   OssHandle *handle = (OssHandle *) stream_.apiHandle;
8910   if ( mode == OUTPUT )
8911     flags |= O_WRONLY;
8912   else { // mode == INPUT
8913     if (stream_.mode == OUTPUT && stream_.device[0] == device) {
8914       // We just set the same device for playback ... close and reopen for duplex (OSS only).
8915       close( handle->id[0] );
8916       handle->id[0] = 0;
8917       if ( !( ainfo.caps & PCM_CAP_DUPLEX ) ) {
8918         errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support duplex mode.";
8919         errorText_ = errorStream_.str();
8920         return FAILURE;
8921       }
8922       // Check that the number previously set channels is the same.
8923       if ( stream_.nUserChannels[0] != channels ) {
8924         errorStream_ << "RtApiOss::probeDeviceOpen: input/output channels must be equal for OSS duplex device (" << ainfo.name << ").";
8925         errorText_ = errorStream_.str();
8926         return FAILURE;
8927       }
8928       flags |= O_RDWR;
8929     }
8930     else
8931       flags |= O_RDONLY;
8932   }
8933
8934   // Set exclusive access if specified.
8935   if ( options && options->flags & RTAUDIO_HOG_DEVICE ) flags |= O_EXCL;
8936
8937   // Try to open the device.
8938   int fd;
8939   fd = open( ainfo.devnode, flags, 0 );
8940   if ( fd == -1 ) {
8941     if ( errno == EBUSY )
8942       errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") is busy.";
8943     else
8944       errorStream_ << "RtApiOss::probeDeviceOpen: error opening device (" << ainfo.name << ").";
8945     errorText_ = errorStream_.str();
8946     return FAILURE;
8947   }
8948
8949   // For duplex operation, specifically set this mode (this doesn't seem to work).
8950   /*
8951     if ( flags | O_RDWR ) {
8952     result = ioctl( fd, SNDCTL_DSP_SETDUPLEX, NULL );
8953     if ( result == -1) {
8954     errorStream_ << "RtApiOss::probeDeviceOpen: error setting duplex mode for device (" << ainfo.name << ").";
8955     errorText_ = errorStream_.str();
8956     return FAILURE;
8957     }
8958     }
8959   */
8960
8961   // Check the device channel support.
8962   stream_.nUserChannels[mode] = channels;
8963   if ( ainfo.max_channels < (int)(channels + firstChannel) ) {
8964     close( fd );
8965     errorStream_ << "RtApiOss::probeDeviceOpen: the device (" << ainfo.name << ") does not support requested channel parameters.";
8966     errorText_ = errorStream_.str();
8967     return FAILURE;
8968   }
8969
8970   // Set the number of channels.
8971   int deviceChannels = channels + firstChannel;
8972   result = ioctl( fd, SNDCTL_DSP_CHANNELS, &deviceChannels );
8973   if ( result == -1 || deviceChannels < (int)(channels + firstChannel) ) {
8974     close( fd );
8975     errorStream_ << "RtApiOss::probeDeviceOpen: error setting channel parameters on device (" << ainfo.name << ").";
8976     errorText_ = errorStream_.str();
8977     return FAILURE;
8978   }
8979   stream_.nDeviceChannels[mode] = deviceChannels;
8980
8981   // Get the data format mask
8982   int mask;
8983   result = ioctl( fd, SNDCTL_DSP_GETFMTS, &mask );
8984   if ( result == -1 ) {
8985     close( fd );
8986     errorStream_ << "RtApiOss::probeDeviceOpen: error getting device (" << ainfo.name << ") data formats.";
8987     errorText_ = errorStream_.str();
8988     return FAILURE;
8989   }
8990
8991   // Determine how to set the device format.
8992   stream_.userFormat = format;
8993   int deviceFormat = -1;
8994   stream_.doByteSwap[mode] = false;
8995   if ( format == RTAUDIO_SINT8 ) {
8996     if ( mask & AFMT_S8 ) {
8997       deviceFormat = AFMT_S8;
8998       stream_.deviceFormat[mode] = RTAUDIO_SINT8;
8999     }
9000   }
9001   else if ( format == RTAUDIO_SINT16 ) {
9002     if ( mask & AFMT_S16_NE ) {
9003       deviceFormat = AFMT_S16_NE;
9004       stream_.deviceFormat[mode] = RTAUDIO_SINT16;
9005     }
9006     else if ( mask & AFMT_S16_OE ) {
9007       deviceFormat = AFMT_S16_OE;
9008       stream_.deviceFormat[mode] = RTAUDIO_SINT16;
9009       stream_.doByteSwap[mode] = true;
9010     }
9011   }
9012   else if ( format == RTAUDIO_SINT24 ) {
9013     if ( mask & AFMT_S24_NE ) {
9014       deviceFormat = AFMT_S24_NE;
9015       stream_.deviceFormat[mode] = RTAUDIO_SINT24;
9016     }
9017     else if ( mask & AFMT_S24_OE ) {
9018       deviceFormat = AFMT_S24_OE;
9019       stream_.deviceFormat[mode] = RTAUDIO_SINT24;
9020       stream_.doByteSwap[mode] = true;
9021     }
9022   }
9023   else if ( format == RTAUDIO_SINT32 ) {
9024     if ( mask & AFMT_S32_NE ) {
9025       deviceFormat = AFMT_S32_NE;
9026       stream_.deviceFormat[mode] = RTAUDIO_SINT32;
9027     }
9028     else if ( mask & AFMT_S32_OE ) {
9029       deviceFormat = AFMT_S32_OE;
9030       stream_.deviceFormat[mode] = RTAUDIO_SINT32;
9031       stream_.doByteSwap[mode] = true;
9032     }
9033   }
9034
9035   if ( deviceFormat == -1 ) {
9036     // The user requested format is not natively supported by the device.
9037     if ( mask & AFMT_S16_NE ) {
9038       deviceFormat = AFMT_S16_NE;
9039       stream_.deviceFormat[mode] = RTAUDIO_SINT16;
9040     }
9041     else if ( mask & AFMT_S32_NE ) {
9042       deviceFormat = AFMT_S32_NE;
9043       stream_.deviceFormat[mode] = RTAUDIO_SINT32;
9044     }
9045     else if ( mask & AFMT_S24_NE ) {
9046       deviceFormat = AFMT_S24_NE;
9047       stream_.deviceFormat[mode] = RTAUDIO_SINT24;
9048     }
9049     else if ( mask & AFMT_S16_OE ) {
9050       deviceFormat = AFMT_S16_OE;
9051       stream_.deviceFormat[mode] = RTAUDIO_SINT16;
9052       stream_.doByteSwap[mode] = true;
9053     }
9054     else if ( mask & AFMT_S32_OE ) {
9055       deviceFormat = AFMT_S32_OE;
9056       stream_.deviceFormat[mode] = RTAUDIO_SINT32;
9057       stream_.doByteSwap[mode] = true;
9058     }
9059     else if ( mask & AFMT_S24_OE ) {
9060       deviceFormat = AFMT_S24_OE;
9061       stream_.deviceFormat[mode] = RTAUDIO_SINT24;
9062       stream_.doByteSwap[mode] = true;
9063     }
9064     else if ( mask & AFMT_S8) {
9065       deviceFormat = AFMT_S8;
9066       stream_.deviceFormat[mode] = RTAUDIO_SINT8;
9067     }
9068   }
9069
9070   if ( stream_.deviceFormat[mode] == 0 ) {
9071     // This really shouldn't happen ...
9072     close( fd );
9073     errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") data format not supported by RtAudio.";
9074     errorText_ = errorStream_.str();
9075     return FAILURE;
9076   }
9077
9078   // Set the data format.
9079   int temp = deviceFormat;
9080   result = ioctl( fd, SNDCTL_DSP_SETFMT, &deviceFormat );
9081   if ( result == -1 || deviceFormat != temp ) {
9082     close( fd );
9083     errorStream_ << "RtApiOss::probeDeviceOpen: error setting data format on device (" << ainfo.name << ").";
9084     errorText_ = errorStream_.str();
9085     return FAILURE;
9086   }
9087
9088   // Attempt to set the buffer size.  According to OSS, the minimum
9089   // number of buffers is two.  The supposed minimum buffer size is 16
9090   // bytes, so that will be our lower bound.  The argument to this
9091   // call is in the form 0xMMMMSSSS (hex), where the buffer size (in
9092   // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM.
9093   // We'll check the actual value used near the end of the setup
9094   // procedure.
9095   int ossBufferBytes = *bufferSize * formatBytes( stream_.deviceFormat[mode] ) * deviceChannels;
9096   if ( ossBufferBytes < 16 ) ossBufferBytes = 16;
9097   int buffers = 0;
9098   if ( options ) buffers = options->numberOfBuffers;
9099   if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) buffers = 2;
9100   if ( buffers < 2 ) buffers = 3;
9101   temp = ((int) buffers << 16) + (int)( log10( (double)ossBufferBytes ) / log10( 2.0 ) );
9102   result = ioctl( fd, SNDCTL_DSP_SETFRAGMENT, &temp );
9103   if ( result == -1 ) {
9104     close( fd );
9105     errorStream_ << "RtApiOss::probeDeviceOpen: error setting buffer size on device (" << ainfo.name << ").";
9106     errorText_ = errorStream_.str();
9107     return FAILURE;
9108   }
9109   stream_.nBuffers = buffers;
9110
9111   // Save buffer size (in sample frames).
9112   *bufferSize = ossBufferBytes / ( formatBytes(stream_.deviceFormat[mode]) * deviceChannels );
9113   stream_.bufferSize = *bufferSize;
9114
9115   // Set the sample rate.
9116   int srate = sampleRate;
9117   result = ioctl( fd, SNDCTL_DSP_SPEED, &srate );
9118   if ( result == -1 ) {
9119     close( fd );
9120     errorStream_ << "RtApiOss::probeDeviceOpen: error setting sample rate (" << sampleRate << ") on device (" << ainfo.name << ").";
9121     errorText_ = errorStream_.str();
9122     return FAILURE;
9123   }
9124
9125   // Verify the sample rate setup worked.
9126   if ( abs( srate - (int)sampleRate ) > 100 ) {
9127     close( fd );
9128     errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support sample rate (" << sampleRate << ").";
9129     errorText_ = errorStream_.str();
9130     return FAILURE;
9131   }
9132   stream_.sampleRate = sampleRate;
9133
9134   if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] == device) {
9135     // We're doing duplex setup here.
9136     stream_.deviceFormat[0] = stream_.deviceFormat[1];
9137     stream_.nDeviceChannels[0] = deviceChannels;
9138   }
9139
9140   // Set interleaving parameters.
9141   stream_.userInterleaved = true;
9142   stream_.deviceInterleaved[mode] =  true;
9143   if ( options && options->flags & RTAUDIO_NONINTERLEAVED )
9144     stream_.userInterleaved = false;
9145
9146   // Set flags for buffer conversion
9147   stream_.doConvertBuffer[mode] = false;
9148   if ( stream_.userFormat != stream_.deviceFormat[mode] )
9149     stream_.doConvertBuffer[mode] = true;
9150   if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )
9151     stream_.doConvertBuffer[mode] = true;
9152   if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
9153        stream_.nUserChannels[mode] > 1 )
9154     stream_.doConvertBuffer[mode] = true;
9155
9156   // Allocate the stream handles if necessary and then save.
9157   if ( stream_.apiHandle == 0 ) {
9158     try {
9159       handle = new OssHandle;
9160     }
9161     catch ( std::bad_alloc& ) {
9162       errorText_ = "RtApiOss::probeDeviceOpen: error allocating OssHandle memory.";
9163       goto error;
9164     }
9165
9166     if ( pthread_cond_init( &handle->runnable, NULL ) ) {
9167       errorText_ = "RtApiOss::probeDeviceOpen: error initializing pthread condition variable.";
9168       goto error;
9169     }
9170
9171     stream_.apiHandle = (void *) handle;
9172   }
9173   else {
9174     handle = (OssHandle *) stream_.apiHandle;
9175   }
9176   handle->id[mode] = fd;
9177
9178   // Allocate necessary internal buffers.
9179   unsigned long bufferBytes;
9180   bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
9181   stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
9182   if ( stream_.userBuffer[mode] == NULL ) {
9183     errorText_ = "RtApiOss::probeDeviceOpen: error allocating user buffer memory.";
9184     goto error;
9185   }
9186
9187   if ( stream_.doConvertBuffer[mode] ) {
9188
9189     bool makeBuffer = true;
9190     bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
9191     if ( mode == INPUT ) {
9192       if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
9193         unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
9194         if ( bufferBytes <= bytesOut ) makeBuffer = false;
9195       }
9196     }
9197
9198     if ( makeBuffer ) {
9199       bufferBytes *= *bufferSize;
9200       if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
9201       stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
9202       if ( stream_.deviceBuffer == NULL ) {
9203         errorText_ = "RtApiOss::probeDeviceOpen: error allocating device buffer memory.";
9204         goto error;
9205       }
9206     }
9207   }
9208
9209   stream_.device[mode] = device;
9210   stream_.state = STREAM_STOPPED;
9211
9212   // Setup the buffer conversion information structure.
9213   if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );
9214
9215   // Setup thread if necessary.
9216   if ( stream_.mode == OUTPUT && mode == INPUT ) {
9217     // We had already set up an output stream.
9218     stream_.mode = DUPLEX;
9219     if ( stream_.device[0] == device ) handle->id[0] = fd;
9220   }
9221   else {
9222     stream_.mode = mode;
9223
9224     // Setup callback thread.
9225     stream_.callbackInfo.object = (void *) this;
9226
9227     // Set the thread attributes for joinable and realtime scheduling
9228     // priority.  The higher priority will only take affect if the
9229     // program is run as root or suid.
9230     pthread_attr_t attr;
9231     pthread_attr_init( &attr );
9232     pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
9233 #ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
9234     if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
9235       struct sched_param param;
9236       int priority = options->priority;
9237       int min = sched_get_priority_min( SCHED_RR );
9238       int max = sched_get_priority_max( SCHED_RR );
9239       if ( priority < min ) priority = min;
9240       else if ( priority > max ) priority = max;
9241       param.sched_priority = priority;
9242       pthread_attr_setschedparam( &attr, &param );
9243       pthread_attr_setschedpolicy( &attr, SCHED_RR );
9244     }
9245     else
9246       pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
9247 #else
9248     pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
9249 #endif
9250
9251     stream_.callbackInfo.isRunning = true;
9252     result = pthread_create( &stream_.callbackInfo.thread, &attr, ossCallbackHandler, &stream_.callbackInfo );
9253     pthread_attr_destroy( &attr );
9254     if ( result ) {
9255       stream_.callbackInfo.isRunning = false;
9256       errorText_ = "RtApiOss::error creating callback thread!";
9257       goto error;
9258     }
9259   }
9260
9261   return SUCCESS;
9262
9263  error:
9264   if ( handle ) {
9265     pthread_cond_destroy( &handle->runnable );
9266     if ( handle->id[0] ) close( handle->id[0] );
9267     if ( handle->id[1] ) close( handle->id[1] );
9268     delete handle;
9269     stream_.apiHandle = 0;
9270   }
9271
9272   for ( int i=0; i<2; i++ ) {
9273     if ( stream_.userBuffer[i] ) {
9274       free( stream_.userBuffer[i] );
9275       stream_.userBuffer[i] = 0;
9276     }
9277   }
9278
9279   if ( stream_.deviceBuffer ) {
9280     free( stream_.deviceBuffer );
9281     stream_.deviceBuffer = 0;
9282   }
9283
9284   return FAILURE;
9285 }
9286
9287 void RtApiOss :: closeStream()
9288 {
9289   if ( stream_.state == STREAM_CLOSED ) {
9290     errorText_ = "RtApiOss::closeStream(): no open stream to close!";
9291     error( RtAudioError::WARNING );
9292     return;
9293   }
9294
9295   OssHandle *handle = (OssHandle *) stream_.apiHandle;
9296   stream_.callbackInfo.isRunning = false;
9297   MUTEX_LOCK( &stream_.mutex );
9298   if ( stream_.state == STREAM_STOPPED )
9299     pthread_cond_signal( &handle->runnable );
9300   MUTEX_UNLOCK( &stream_.mutex );
9301   pthread_join( stream_.callbackInfo.thread, NULL );
9302
9303   if ( stream_.state == STREAM_RUNNING ) {
9304     if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )
9305       ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 );
9306     else
9307       ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 );
9308     stream_.state = STREAM_STOPPED;
9309   }
9310
9311   if ( handle ) {
9312     pthread_cond_destroy( &handle->runnable );
9313     if ( handle->id[0] ) close( handle->id[0] );
9314     if ( handle->id[1] ) close( handle->id[1] );
9315     delete handle;
9316     stream_.apiHandle = 0;
9317   }
9318
9319   for ( int i=0; i<2; i++ ) {
9320     if ( stream_.userBuffer[i] ) {
9321       free( stream_.userBuffer[i] );
9322       stream_.userBuffer[i] = 0;
9323     }
9324   }
9325
9326   if ( stream_.deviceBuffer ) {
9327     free( stream_.deviceBuffer );
9328     stream_.deviceBuffer = 0;
9329   }
9330
9331   stream_.mode = UNINITIALIZED;
9332   stream_.state = STREAM_CLOSED;
9333 }
9334
9335 void RtApiOss :: startStream()
9336 {
9337   verifyStream();
9338   if ( stream_.state == STREAM_RUNNING ) {
9339     errorText_ = "RtApiOss::startStream(): the stream is already running!";
9340     error( RtAudioError::WARNING );
9341     return;
9342   }
9343
9344   MUTEX_LOCK( &stream_.mutex );
9345
9346   stream_.state = STREAM_RUNNING;
9347
9348   // No need to do anything else here ... OSS automatically starts
9349   // when fed samples.
9350
9351   MUTEX_UNLOCK( &stream_.mutex );
9352
9353   OssHandle *handle = (OssHandle *) stream_.apiHandle;
9354   pthread_cond_signal( &handle->runnable );
9355 }
9356
9357 void RtApiOss :: stopStream()
9358 {
9359   verifyStream();
9360   if ( stream_.state == STREAM_STOPPED ) {
9361     errorText_ = "RtApiOss::stopStream(): the stream is already stopped!";
9362     error( RtAudioError::WARNING );
9363     return;
9364   }
9365
9366   MUTEX_LOCK( &stream_.mutex );
9367
9368   // The state might change while waiting on a mutex.
9369   if ( stream_.state == STREAM_STOPPED ) {
9370     MUTEX_UNLOCK( &stream_.mutex );
9371     return;
9372   }
9373
9374   int result = 0;
9375   OssHandle *handle = (OssHandle *) stream_.apiHandle;
9376   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
9377
9378     // Flush the output with zeros a few times.
9379     char *buffer;
9380     int samples;
9381     RtAudioFormat format;
9382
9383     if ( stream_.doConvertBuffer[0] ) {
9384       buffer = stream_.deviceBuffer;
9385       samples = stream_.bufferSize * stream_.nDeviceChannels[0];
9386       format = stream_.deviceFormat[0];
9387     }
9388     else {
9389       buffer = stream_.userBuffer[0];
9390       samples = stream_.bufferSize * stream_.nUserChannels[0];
9391       format = stream_.userFormat;
9392     }
9393
9394     memset( buffer, 0, samples * formatBytes(format) );
9395     for ( unsigned int i=0; i<stream_.nBuffers+1; i++ ) {
9396       result = write( handle->id[0], buffer, samples * formatBytes(format) );
9397       if ( result == -1 ) {
9398         errorText_ = "RtApiOss::stopStream: audio write error.";
9399         error( RtAudioError::WARNING );
9400       }
9401     }
9402
9403     result = ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 );
9404     if ( result == -1 ) {
9405       errorStream_ << "RtApiOss::stopStream: system error stopping callback procedure on device (" << stream_.device[0] << ").";
9406       errorText_ = errorStream_.str();
9407       goto unlock;
9408     }
9409     handle->triggered = false;
9410   }
9411
9412   if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && handle->id[0] != handle->id[1] ) ) {
9413     result = ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 );
9414     if ( result == -1 ) {
9415       errorStream_ << "RtApiOss::stopStream: system error stopping input callback procedure on device (" << stream_.device[0] << ").";
9416       errorText_ = errorStream_.str();
9417       goto unlock;
9418     }
9419   }
9420
9421  unlock:
9422   stream_.state = STREAM_STOPPED;
9423   MUTEX_UNLOCK( &stream_.mutex );
9424
9425   if ( result != -1 ) return;
9426   error( RtAudioError::SYSTEM_ERROR );
9427 }
9428
9429 void RtApiOss :: abortStream()
9430 {
9431   verifyStream();
9432   if ( stream_.state == STREAM_STOPPED ) {
9433     errorText_ = "RtApiOss::abortStream(): the stream is already stopped!";
9434     error( RtAudioError::WARNING );
9435     return;
9436   }
9437
9438   MUTEX_LOCK( &stream_.mutex );
9439
9440   // The state might change while waiting on a mutex.
9441   if ( stream_.state == STREAM_STOPPED ) {
9442     MUTEX_UNLOCK( &stream_.mutex );
9443     return;
9444   }
9445
9446   int result = 0;
9447   OssHandle *handle = (OssHandle *) stream_.apiHandle;
9448   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
9449     result = ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 );
9450     if ( result == -1 ) {
9451       errorStream_ << "RtApiOss::abortStream: system error stopping callback procedure on device (" << stream_.device[0] << ").";
9452       errorText_ = errorStream_.str();
9453       goto unlock;
9454     }
9455     handle->triggered = false;
9456   }
9457
9458   if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && handle->id[0] != handle->id[1] ) ) {
9459     result = ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 );
9460     if ( result == -1 ) {
9461       errorStream_ << "RtApiOss::abortStream: system error stopping input callback procedure on device (" << stream_.device[0] << ").";
9462       errorText_ = errorStream_.str();
9463       goto unlock;
9464     }
9465   }
9466
9467  unlock:
9468   stream_.state = STREAM_STOPPED;
9469   MUTEX_UNLOCK( &stream_.mutex );
9470
9471   if ( result != -1 ) return;
9472   error( RtAudioError::SYSTEM_ERROR );
9473 }
9474
9475 void RtApiOss :: callbackEvent()
9476 {
9477   OssHandle *handle = (OssHandle *) stream_.apiHandle;
9478   if ( stream_.state == STREAM_STOPPED ) {
9479     MUTEX_LOCK( &stream_.mutex );
9480     pthread_cond_wait( &handle->runnable, &stream_.mutex );
9481     if ( stream_.state != STREAM_RUNNING ) {
9482       MUTEX_UNLOCK( &stream_.mutex );
9483       return;
9484     }
9485     MUTEX_UNLOCK( &stream_.mutex );
9486   }
9487
9488   if ( stream_.state == STREAM_CLOSED ) {
9489     errorText_ = "RtApiOss::callbackEvent(): the stream is closed ... this shouldn't happen!";
9490     error( RtAudioError::WARNING );
9491     return;
9492   }
9493
9494   // Invoke user callback to get fresh output data.
9495   int doStopStream = 0;
9496   RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
9497   double streamTime = getStreamTime();
9498   RtAudioStreamStatus status = 0;
9499   if ( stream_.mode != INPUT && handle->xrun[0] == true ) {
9500     status |= RTAUDIO_OUTPUT_UNDERFLOW;
9501     handle->xrun[0] = false;
9502   }
9503   if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {
9504     status |= RTAUDIO_INPUT_OVERFLOW;
9505     handle->xrun[1] = false;
9506   }
9507   doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1],
9508                            stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData );
9509   if ( doStopStream == 2 ) {
9510     this->abortStream();
9511     return;
9512   }
9513
9514   MUTEX_LOCK( &stream_.mutex );
9515
9516   // The state might change while waiting on a mutex.
9517   if ( stream_.state == STREAM_STOPPED ) goto unlock;
9518
9519   int result;
9520   char *buffer;
9521   int samples;
9522   RtAudioFormat format;
9523
9524   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
9525
9526     // Setup parameters and do buffer conversion if necessary.
9527     if ( stream_.doConvertBuffer[0] ) {
9528       buffer = stream_.deviceBuffer;
9529       convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] );
9530       samples = stream_.bufferSize * stream_.nDeviceChannels[0];
9531       format = stream_.deviceFormat[0];
9532     }
9533     else {
9534       buffer = stream_.userBuffer[0];
9535       samples = stream_.bufferSize * stream_.nUserChannels[0];
9536       format = stream_.userFormat;
9537     }
9538
9539     // Do byte swapping if necessary.
9540     if ( stream_.doByteSwap[0] )
9541       byteSwapBuffer( buffer, samples, format );
9542
9543     if ( stream_.mode == DUPLEX && handle->triggered == false ) {
9544       int trig = 0;
9545       ioctl( handle->id[0], SNDCTL_DSP_SETTRIGGER, &trig );
9546       result = write( handle->id[0], buffer, samples * formatBytes(format) );
9547       trig = PCM_ENABLE_INPUT|PCM_ENABLE_OUTPUT;
9548       ioctl( handle->id[0], SNDCTL_DSP_SETTRIGGER, &trig );
9549       handle->triggered = true;
9550     }
9551     else
9552       // Write samples to device.
9553       result = write( handle->id[0], buffer, samples * formatBytes(format) );
9554
9555     if ( result == -1 ) {
9556       // We'll assume this is an underrun, though there isn't a
9557       // specific means for determining that.
9558       handle->xrun[0] = true;
9559       errorText_ = "RtApiOss::callbackEvent: audio write error.";
9560       error( RtAudioError::WARNING );
9561       // Continue on to input section.
9562     }
9563   }
9564
9565   if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
9566
9567     // Setup parameters.
9568     if ( stream_.doConvertBuffer[1] ) {
9569       buffer = stream_.deviceBuffer;
9570       samples = stream_.bufferSize * stream_.nDeviceChannels[1];
9571       format = stream_.deviceFormat[1];
9572     }
9573     else {
9574       buffer = stream_.userBuffer[1];
9575       samples = stream_.bufferSize * stream_.nUserChannels[1];
9576       format = stream_.userFormat;
9577     }
9578
9579     // Read samples from device.
9580     result = read( handle->id[1], buffer, samples * formatBytes(format) );
9581
9582     if ( result == -1 ) {
9583       // We'll assume this is an overrun, though there isn't a
9584       // specific means for determining that.
9585       handle->xrun[1] = true;
9586       errorText_ = "RtApiOss::callbackEvent: audio read error.";
9587       error( RtAudioError::WARNING );
9588       goto unlock;
9589     }
9590
9591     // Do byte swapping if necessary.
9592     if ( stream_.doByteSwap[1] )
9593       byteSwapBuffer( buffer, samples, format );
9594
9595     // Do buffer conversion if necessary.
9596     if ( stream_.doConvertBuffer[1] )
9597       convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
9598   }
9599
9600  unlock:
9601   MUTEX_UNLOCK( &stream_.mutex );
9602
9603   RtApi::tickStreamTime();
9604   if ( doStopStream == 1 ) this->stopStream();
9605 }
9606
9607 static void *ossCallbackHandler( void *ptr )
9608 {
9609   CallbackInfo *info = (CallbackInfo *) ptr;
9610   RtApiOss *object = (RtApiOss *) info->object;
9611   bool *isRunning = &info->isRunning;
9612
9613   while ( *isRunning == true ) {
9614     pthread_testcancel();
9615     object->callbackEvent();
9616   }
9617
9618   pthread_exit( NULL );
9619 }
9620
9621 //******************** End of __LINUX_OSS__ *********************//
9622 #endif
9623
9624
9625 // *************************************************** //
9626 //
9627 // Protected common (OS-independent) RtAudio methods.
9628 //
9629 // *************************************************** //
9630
9631 // This method can be modified to control the behavior of error
9632 // message printing.
9633 void RtApi :: error( RtAudioError::Type type )
9634 {
9635   errorStream_.str(""); // clear the ostringstream
9636
9637   RtAudioErrorCallback errorCallback = (RtAudioErrorCallback) stream_.callbackInfo.errorCallback;
9638   if ( errorCallback ) {
9639     // abortStream() can generate new error messages. Ignore them. Just keep original one.
9640
9641     if ( firstErrorOccurred_ )
9642       return;
9643
9644     firstErrorOccurred_ = true;
9645     const std::string errorMessage = errorText_;
9646
9647     if ( type != RtAudioError::WARNING && stream_.state != STREAM_STOPPED) {
9648       stream_.callbackInfo.isRunning = false; // exit from the thread
9649       abortStream();
9650     }
9651
9652     errorCallback( type, errorMessage );
9653     firstErrorOccurred_ = false;
9654     return;
9655   }
9656
9657   if ( type == RtAudioError::WARNING && showWarnings_ == true )
9658     std::cerr << '\n' << errorText_ << "\n\n";
9659   else if ( type != RtAudioError::WARNING )
9660     throw( RtAudioError( errorText_, type ) );
9661 }
9662
9663 void RtApi :: verifyStream()
9664 {
9665   if ( stream_.state == STREAM_CLOSED ) {
9666     errorText_ = "RtApi:: a stream is not open!";
9667     error( RtAudioError::INVALID_USE );
9668   }
9669 }
9670
9671 void RtApi :: clearStreamInfo()
9672 {
9673   stream_.mode = UNINITIALIZED;
9674   stream_.state = STREAM_CLOSED;
9675   stream_.sampleRate = 0;
9676   stream_.bufferSize = 0;
9677   stream_.nBuffers = 0;
9678   stream_.userFormat = 0;
9679   stream_.userInterleaved = true;
9680   stream_.streamTime = 0.0;
9681   stream_.apiHandle = 0;
9682   stream_.deviceBuffer = 0;
9683   stream_.callbackInfo.callback = 0;
9684   stream_.callbackInfo.userData = 0;
9685   stream_.callbackInfo.isRunning = false;
9686   stream_.callbackInfo.errorCallback = 0;
9687   for ( int i=0; i<2; i++ ) {
9688     stream_.device[i] = 11111;
9689     stream_.doConvertBuffer[i] = false;
9690     stream_.deviceInterleaved[i] = true;
9691     stream_.doByteSwap[i] = false;
9692     stream_.nUserChannels[i] = 0;
9693     stream_.nDeviceChannels[i] = 0;
9694     stream_.channelOffset[i] = 0;
9695     stream_.deviceFormat[i] = 0;
9696     stream_.latency[i] = 0;
9697     stream_.userBuffer[i] = 0;
9698     stream_.convertInfo[i].channels = 0;
9699     stream_.convertInfo[i].inJump = 0;
9700     stream_.convertInfo[i].outJump = 0;
9701     stream_.convertInfo[i].inFormat = 0;
9702     stream_.convertInfo[i].outFormat = 0;
9703     stream_.convertInfo[i].inOffset.clear();
9704     stream_.convertInfo[i].outOffset.clear();
9705   }
9706 }
9707
9708 unsigned int RtApi :: formatBytes( RtAudioFormat format )
9709 {
9710   if ( format == RTAUDIO_SINT16 )
9711     return 2;
9712   else if ( format == RTAUDIO_SINT32 || format == RTAUDIO_FLOAT32 )
9713     return 4;
9714   else if ( format == RTAUDIO_FLOAT64 )
9715     return 8;
9716   else if ( format == RTAUDIO_SINT24 )
9717     return 3;
9718   else if ( format == RTAUDIO_SINT8 )
9719     return 1;
9720
9721   errorText_ = "RtApi::formatBytes: undefined format.";
9722   error( RtAudioError::WARNING );
9723
9724   return 0;
9725 }
9726
9727 void RtApi :: setConvertInfo( StreamMode mode, unsigned int firstChannel )
9728 {
9729   if ( mode == INPUT ) { // convert device to user buffer
9730     stream_.convertInfo[mode].inJump = stream_.nDeviceChannels[1];
9731     stream_.convertInfo[mode].outJump = stream_.nUserChannels[1];
9732     stream_.convertInfo[mode].inFormat = stream_.deviceFormat[1];
9733     stream_.convertInfo[mode].outFormat = stream_.userFormat;
9734   }
9735   else { // convert user to device buffer
9736     stream_.convertInfo[mode].inJump = stream_.nUserChannels[0];
9737     stream_.convertInfo[mode].outJump = stream_.nDeviceChannels[0];
9738     stream_.convertInfo[mode].inFormat = stream_.userFormat;
9739     stream_.convertInfo[mode].outFormat = stream_.deviceFormat[0];
9740   }
9741
9742   if ( stream_.convertInfo[mode].inJump < stream_.convertInfo[mode].outJump )
9743     stream_.convertInfo[mode].channels = stream_.convertInfo[mode].inJump;
9744   else
9745     stream_.convertInfo[mode].channels = stream_.convertInfo[mode].outJump;
9746
9747   // Set up the interleave/deinterleave offsets.
9748   if ( stream_.deviceInterleaved[mode] != stream_.userInterleaved ) {
9749     if ( ( mode == OUTPUT && stream_.deviceInterleaved[mode] ) ||
9750          ( mode == INPUT && stream_.userInterleaved ) ) {
9751       for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {
9752         stream_.convertInfo[mode].inOffset.push_back( k * stream_.bufferSize );
9753         stream_.convertInfo[mode].outOffset.push_back( k );
9754         stream_.convertInfo[mode].inJump = 1;
9755       }
9756     }
9757     else {
9758       for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {
9759         stream_.convertInfo[mode].inOffset.push_back( k );
9760         stream_.convertInfo[mode].outOffset.push_back( k * stream_.bufferSize );
9761         stream_.convertInfo[mode].outJump = 1;
9762       }
9763     }
9764   }
9765   else { // no (de)interleaving
9766     if ( stream_.userInterleaved ) {
9767       for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {
9768         stream_.convertInfo[mode].inOffset.push_back( k );
9769         stream_.convertInfo[mode].outOffset.push_back( k );
9770       }
9771     }
9772     else {
9773       for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {
9774         stream_.convertInfo[mode].inOffset.push_back( k * stream_.bufferSize );
9775         stream_.convertInfo[mode].outOffset.push_back( k * stream_.bufferSize );
9776         stream_.convertInfo[mode].inJump = 1;
9777         stream_.convertInfo[mode].outJump = 1;
9778       }
9779     }
9780   }
9781
9782   // Add channel offset.
9783   if ( firstChannel > 0 ) {
9784     if ( stream_.deviceInterleaved[mode] ) {
9785       if ( mode == OUTPUT ) {
9786         for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )
9787           stream_.convertInfo[mode].outOffset[k] += firstChannel;
9788       }
9789       else {
9790         for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )
9791           stream_.convertInfo[mode].inOffset[k] += firstChannel;
9792       }
9793     }
9794     else {
9795       if ( mode == OUTPUT ) {
9796         for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )
9797           stream_.convertInfo[mode].outOffset[k] += ( firstChannel * stream_.bufferSize );
9798       }
9799       else {
9800         for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )
9801           stream_.convertInfo[mode].inOffset[k] += ( firstChannel  * stream_.bufferSize );
9802       }
9803     }
9804   }
9805 }
9806
9807 void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info )
9808 {
9809   // This function does format conversion, input/output channel compensation, and
9810   // data interleaving/deinterleaving.  24-bit integers are assumed to occupy
9811   // the lower three bytes of a 32-bit integer.
9812
9813   // Clear our device buffer when in/out duplex device channels are different
9814   if ( outBuffer == stream_.deviceBuffer && stream_.mode == DUPLEX &&
9815        ( stream_.nDeviceChannels[0] < stream_.nDeviceChannels[1] ) )
9816     memset( outBuffer, 0, stream_.bufferSize * info.outJump * formatBytes( info.outFormat ) );
9817
9818   int j;
9819   if (info.outFormat == RTAUDIO_FLOAT64) {
9820     Float64 scale;
9821     Float64 *out = (Float64 *)outBuffer;
9822
9823     if (info.inFormat == RTAUDIO_SINT8) {
9824       signed char *in = (signed char *)inBuffer;
9825       scale = 1.0 / 127.5;
9826       for (unsigned int i=0; i<stream_.bufferSize; i++) {
9827         for (j=0; j<info.channels; j++) {
9828           out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
9829           out[info.outOffset[j]] += 0.5;
9830           out[info.outOffset[j]] *= scale;
9831         }
9832         in += info.inJump;
9833         out += info.outJump;
9834       }
9835     }
9836     else if (info.inFormat == RTAUDIO_SINT16) {
9837       Int16 *in = (Int16 *)inBuffer;
9838       scale = 1.0 / 32767.5;
9839       for (unsigned int i=0; i<stream_.bufferSize; i++) {
9840         for (j=0; j<info.channels; j++) {
9841           out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
9842           out[info.outOffset[j]] += 0.5;
9843           out[info.outOffset[j]] *= scale;
9844         }
9845         in += info.inJump;
9846         out += info.outJump;
9847       }
9848     }
9849     else if (info.inFormat == RTAUDIO_SINT24) {
9850       Int24 *in = (Int24 *)inBuffer;
9851       scale = 1.0 / 8388607.5;
9852       for (unsigned int i=0; i<stream_.bufferSize; i++) {
9853         for (j=0; j<info.channels; j++) {
9854           out[info.outOffset[j]] = (Float64) (in[info.inOffset[j]].asInt());
9855           out[info.outOffset[j]] += 0.5;
9856           out[info.outOffset[j]] *= scale;
9857         }
9858         in += info.inJump;
9859         out += info.outJump;
9860       }
9861     }
9862     else if (info.inFormat == RTAUDIO_SINT32) {
9863       Int32 *in = (Int32 *)inBuffer;
9864       scale = 1.0 / 2147483647.5;
9865       for (unsigned int i=0; i<stream_.bufferSize; i++) {
9866         for (j=0; j<info.channels; j++) {
9867           out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
9868           out[info.outOffset[j]] += 0.5;
9869           out[info.outOffset[j]] *= scale;
9870         }
9871         in += info.inJump;
9872         out += info.outJump;
9873       }
9874     }
9875     else if (info.inFormat == RTAUDIO_FLOAT32) {
9876       Float32 *in = (Float32 *)inBuffer;
9877       for (unsigned int i=0; i<stream_.bufferSize; i++) {
9878         for (j=0; j<info.channels; j++) {
9879           out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
9880         }
9881         in += info.inJump;
9882         out += info.outJump;
9883       }
9884     }
9885     else if (info.inFormat == RTAUDIO_FLOAT64) {
9886       // Channel compensation and/or (de)interleaving only.
9887       Float64 *in = (Float64 *)inBuffer;
9888       for (unsigned int i=0; i<stream_.bufferSize; i++) {
9889         for (j=0; j<info.channels; j++) {
9890           out[info.outOffset[j]] = in[info.inOffset[j]];
9891         }
9892         in += info.inJump;
9893         out += info.outJump;
9894       }
9895     }
9896   }
9897   else if (info.outFormat == RTAUDIO_FLOAT32) {
9898     Float32 scale;
9899     Float32 *out = (Float32 *)outBuffer;
9900
9901     if (info.inFormat == RTAUDIO_SINT8) {
9902       signed char *in = (signed char *)inBuffer;
9903       scale = (Float32) ( 1.0 / 127.5 );
9904       for (unsigned int i=0; i<stream_.bufferSize; i++) {
9905         for (j=0; j<info.channels; j++) {
9906           out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
9907           out[info.outOffset[j]] += 0.5;
9908           out[info.outOffset[j]] *= scale;
9909         }
9910         in += info.inJump;
9911         out += info.outJump;
9912       }
9913     }
9914     else if (info.inFormat == RTAUDIO_SINT16) {
9915       Int16 *in = (Int16 *)inBuffer;
9916       scale = (Float32) ( 1.0 / 32767.5 );
9917       for (unsigned int i=0; i<stream_.bufferSize; i++) {
9918         for (j=0; j<info.channels; j++) {
9919           out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
9920           out[info.outOffset[j]] += 0.5;
9921           out[info.outOffset[j]] *= scale;
9922         }
9923         in += info.inJump;
9924         out += info.outJump;
9925       }
9926     }
9927     else if (info.inFormat == RTAUDIO_SINT24) {
9928       Int24 *in = (Int24 *)inBuffer;
9929       scale = (Float32) ( 1.0 / 8388607.5 );
9930       for (unsigned int i=0; i<stream_.bufferSize; i++) {
9931         for (j=0; j<info.channels; j++) {
9932           out[info.outOffset[j]] = (Float32) (in[info.inOffset[j]].asInt());
9933           out[info.outOffset[j]] += 0.5;
9934           out[info.outOffset[j]] *= scale;
9935         }
9936         in += info.inJump;
9937         out += info.outJump;
9938       }
9939     }
9940     else if (info.inFormat == RTAUDIO_SINT32) {
9941       Int32 *in = (Int32 *)inBuffer;
9942       scale = (Float32) ( 1.0 / 2147483647.5 );
9943       for (unsigned int i=0; i<stream_.bufferSize; i++) {
9944         for (j=0; j<info.channels; j++) {
9945           out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
9946           out[info.outOffset[j]] += 0.5;
9947           out[info.outOffset[j]] *= scale;
9948         }
9949         in += info.inJump;
9950         out += info.outJump;
9951       }
9952     }
9953     else if (info.inFormat == RTAUDIO_FLOAT32) {
9954       // Channel compensation and/or (de)interleaving only.
9955       Float32 *in = (Float32 *)inBuffer;
9956       for (unsigned int i=0; i<stream_.bufferSize; i++) {
9957         for (j=0; j<info.channels; j++) {
9958           out[info.outOffset[j]] = in[info.inOffset[j]];
9959         }
9960         in += info.inJump;
9961         out += info.outJump;
9962       }
9963     }
9964     else if (info.inFormat == RTAUDIO_FLOAT64) {
9965       Float64 *in = (Float64 *)inBuffer;
9966       for (unsigned int i=0; i<stream_.bufferSize; i++) {
9967         for (j=0; j<info.channels; j++) {
9968           out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
9969         }
9970         in += info.inJump;
9971         out += info.outJump;
9972       }
9973     }
9974   }
9975   else if (info.outFormat == RTAUDIO_SINT32) {
9976     Int32 *out = (Int32 *)outBuffer;
9977     if (info.inFormat == RTAUDIO_SINT8) {
9978       signed char *in = (signed char *)inBuffer;
9979       for (unsigned int i=0; i<stream_.bufferSize; i++) {
9980         for (j=0; j<info.channels; j++) {
9981           out[info.outOffset[j]] = (Int32) in[info.inOffset[j]];
9982           out[info.outOffset[j]] <<= 24;
9983         }
9984         in += info.inJump;
9985         out += info.outJump;
9986       }
9987     }
9988     else if (info.inFormat == RTAUDIO_SINT16) {
9989       Int16 *in = (Int16 *)inBuffer;
9990       for (unsigned int i=0; i<stream_.bufferSize; i++) {
9991         for (j=0; j<info.channels; j++) {
9992           out[info.outOffset[j]] = (Int32) in[info.inOffset[j]];
9993           out[info.outOffset[j]] <<= 16;
9994         }
9995         in += info.inJump;
9996         out += info.outJump;
9997       }
9998     }
9999     else if (info.inFormat == RTAUDIO_SINT24) {
10000       Int24 *in = (Int24 *)inBuffer;
10001       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10002         for (j=0; j<info.channels; j++) {
10003           out[info.outOffset[j]] = (Int32) in[info.inOffset[j]].asInt();
10004           out[info.outOffset[j]] <<= 8;
10005         }
10006         in += info.inJump;
10007         out += info.outJump;
10008       }
10009     }
10010     else if (info.inFormat == RTAUDIO_SINT32) {
10011       // Channel compensation and/or (de)interleaving only.
10012       Int32 *in = (Int32 *)inBuffer;
10013       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10014         for (j=0; j<info.channels; j++) {
10015           out[info.outOffset[j]] = in[info.inOffset[j]];
10016         }
10017         in += info.inJump;
10018         out += info.outJump;
10019       }
10020     }
10021     else if (info.inFormat == RTAUDIO_FLOAT32) {
10022       Float32 *in = (Float32 *)inBuffer;
10023       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10024         for (j=0; j<info.channels; j++) {
10025           out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.5 - 0.5);
10026         }
10027         in += info.inJump;
10028         out += info.outJump;
10029       }
10030     }
10031     else if (info.inFormat == RTAUDIO_FLOAT64) {
10032       Float64 *in = (Float64 *)inBuffer;
10033       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10034         for (j=0; j<info.channels; j++) {
10035           out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.5 - 0.5);
10036         }
10037         in += info.inJump;
10038         out += info.outJump;
10039       }
10040     }
10041   }
10042   else if (info.outFormat == RTAUDIO_SINT24) {
10043     Int24 *out = (Int24 *)outBuffer;
10044     if (info.inFormat == RTAUDIO_SINT8) {
10045       signed char *in = (signed char *)inBuffer;
10046       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10047         for (j=0; j<info.channels; j++) {
10048           out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] << 16);
10049           //out[info.outOffset[j]] <<= 16;
10050         }
10051         in += info.inJump;
10052         out += info.outJump;
10053       }
10054     }
10055     else if (info.inFormat == RTAUDIO_SINT16) {
10056       Int16 *in = (Int16 *)inBuffer;
10057       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10058         for (j=0; j<info.channels; j++) {
10059           out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] << 8);
10060           //out[info.outOffset[j]] <<= 8;
10061         }
10062         in += info.inJump;
10063         out += info.outJump;
10064       }
10065     }
10066     else if (info.inFormat == RTAUDIO_SINT24) {
10067       // Channel compensation and/or (de)interleaving only.
10068       Int24 *in = (Int24 *)inBuffer;
10069       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10070         for (j=0; j<info.channels; j++) {
10071           out[info.outOffset[j]] = in[info.inOffset[j]];
10072         }
10073         in += info.inJump;
10074         out += info.outJump;
10075       }
10076     }
10077     else if (info.inFormat == RTAUDIO_SINT32) {
10078       Int32 *in = (Int32 *)inBuffer;
10079       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10080         for (j=0; j<info.channels; j++) {
10081           out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] >> 8);
10082           //out[info.outOffset[j]] >>= 8;
10083         }
10084         in += info.inJump;
10085         out += info.outJump;
10086       }
10087     }
10088     else if (info.inFormat == RTAUDIO_FLOAT32) {
10089       Float32 *in = (Float32 *)inBuffer;
10090       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10091         for (j=0; j<info.channels; j++) {
10092           out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388607.5 - 0.5);
10093         }
10094         in += info.inJump;
10095         out += info.outJump;
10096       }
10097     }
10098     else if (info.inFormat == RTAUDIO_FLOAT64) {
10099       Float64 *in = (Float64 *)inBuffer;
10100       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10101         for (j=0; j<info.channels; j++) {
10102           out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388607.5 - 0.5);
10103         }
10104         in += info.inJump;
10105         out += info.outJump;
10106       }
10107     }
10108   }
10109   else if (info.outFormat == RTAUDIO_SINT16) {
10110     Int16 *out = (Int16 *)outBuffer;
10111     if (info.inFormat == RTAUDIO_SINT8) {
10112       signed char *in = (signed char *)inBuffer;
10113       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10114         for (j=0; j<info.channels; j++) {
10115           out[info.outOffset[j]] = (Int16) in[info.inOffset[j]];
10116           out[info.outOffset[j]] <<= 8;
10117         }
10118         in += info.inJump;
10119         out += info.outJump;
10120       }
10121     }
10122     else if (info.inFormat == RTAUDIO_SINT16) {
10123       // Channel compensation and/or (de)interleaving only.
10124       Int16 *in = (Int16 *)inBuffer;
10125       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10126         for (j=0; j<info.channels; j++) {
10127           out[info.outOffset[j]] = in[info.inOffset[j]];
10128         }
10129         in += info.inJump;
10130         out += info.outJump;
10131       }
10132     }
10133     else if (info.inFormat == RTAUDIO_SINT24) {
10134       Int24 *in = (Int24 *)inBuffer;
10135       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10136         for (j=0; j<info.channels; j++) {
10137           out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]].asInt() >> 8);
10138         }
10139         in += info.inJump;
10140         out += info.outJump;
10141       }
10142     }
10143     else if (info.inFormat == RTAUDIO_SINT32) {
10144       Int32 *in = (Int32 *)inBuffer;
10145       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10146         for (j=0; j<info.channels; j++) {
10147           out[info.outOffset[j]] = (Int16) ((in[info.inOffset[j]] >> 16) & 0x0000ffff);
10148         }
10149         in += info.inJump;
10150         out += info.outJump;
10151       }
10152     }
10153     else if (info.inFormat == RTAUDIO_FLOAT32) {
10154       Float32 *in = (Float32 *)inBuffer;
10155       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10156         for (j=0; j<info.channels; j++) {
10157           out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.5 - 0.5);
10158         }
10159         in += info.inJump;
10160         out += info.outJump;
10161       }
10162     }
10163     else if (info.inFormat == RTAUDIO_FLOAT64) {
10164       Float64 *in = (Float64 *)inBuffer;
10165       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10166         for (j=0; j<info.channels; j++) {
10167           out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.5 - 0.5);
10168         }
10169         in += info.inJump;
10170         out += info.outJump;
10171       }
10172     }
10173   }
10174   else if (info.outFormat == RTAUDIO_SINT8) {
10175     signed char *out = (signed char *)outBuffer;
10176     if (info.inFormat == RTAUDIO_SINT8) {
10177       // Channel compensation and/or (de)interleaving only.
10178       signed char *in = (signed char *)inBuffer;
10179       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10180         for (j=0; j<info.channels; j++) {
10181           out[info.outOffset[j]] = in[info.inOffset[j]];
10182         }
10183         in += info.inJump;
10184         out += info.outJump;
10185       }
10186     }
10187     if (info.inFormat == RTAUDIO_SINT16) {
10188       Int16 *in = (Int16 *)inBuffer;
10189       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10190         for (j=0; j<info.channels; j++) {
10191           out[info.outOffset[j]] = (signed char) ((in[info.inOffset[j]] >> 8) & 0x00ff);
10192         }
10193         in += info.inJump;
10194         out += info.outJump;
10195       }
10196     }
10197     else if (info.inFormat == RTAUDIO_SINT24) {
10198       Int24 *in = (Int24 *)inBuffer;
10199       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10200         for (j=0; j<info.channels; j++) {
10201           out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]].asInt() >> 16);
10202         }
10203         in += info.inJump;
10204         out += info.outJump;
10205       }
10206     }
10207     else if (info.inFormat == RTAUDIO_SINT32) {
10208       Int32 *in = (Int32 *)inBuffer;
10209       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10210         for (j=0; j<info.channels; j++) {
10211           out[info.outOffset[j]] = (signed char) ((in[info.inOffset[j]] >> 24) & 0x000000ff);
10212         }
10213         in += info.inJump;
10214         out += info.outJump;
10215       }
10216     }
10217     else if (info.inFormat == RTAUDIO_FLOAT32) {
10218       Float32 *in = (Float32 *)inBuffer;
10219       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10220         for (j=0; j<info.channels; j++) {
10221           out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.5 - 0.5);
10222         }
10223         in += info.inJump;
10224         out += info.outJump;
10225       }
10226     }
10227     else if (info.inFormat == RTAUDIO_FLOAT64) {
10228       Float64 *in = (Float64 *)inBuffer;
10229       for (unsigned int i=0; i<stream_.bufferSize; i++) {
10230         for (j=0; j<info.channels; j++) {
10231           out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.5 - 0.5);
10232         }
10233         in += info.inJump;
10234         out += info.outJump;
10235       }
10236     }
10237   }
10238 }
10239
10240 //static inline uint16_t bswap_16(uint16_t x) { return (x>>8) | (x<<8); }
10241 //static inline uint32_t bswap_32(uint32_t x) { return (bswap_16(x&0xffff)<<16) | (bswap_16(x>>16)); }
10242 //static inline uint64_t bswap_64(uint64_t x) { return (((unsigned long long)bswap_32(x&0xffffffffull))<<32) | (bswap_32(x>>32)); }
10243
10244 void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat format )
10245 {
10246   char val;
10247   char *ptr;
10248
10249   ptr = buffer;
10250   if ( format == RTAUDIO_SINT16 ) {
10251     for ( unsigned int i=0; i<samples; i++ ) {
10252       // Swap 1st and 2nd bytes.
10253       val = *(ptr);
10254       *(ptr) = *(ptr+1);
10255       *(ptr+1) = val;
10256
10257       // Increment 2 bytes.
10258       ptr += 2;
10259     }
10260   }
10261   else if ( format == RTAUDIO_SINT32 ||
10262             format == RTAUDIO_FLOAT32 ) {
10263     for ( unsigned int i=0; i<samples; i++ ) {
10264       // Swap 1st and 4th bytes.
10265       val = *(ptr);
10266       *(ptr) = *(ptr+3);
10267       *(ptr+3) = val;
10268
10269       // Swap 2nd and 3rd bytes.
10270       ptr += 1;
10271       val = *(ptr);
10272       *(ptr) = *(ptr+1);
10273       *(ptr+1) = val;
10274
10275       // Increment 3 more bytes.
10276       ptr += 3;
10277     }
10278   }
10279   else if ( format == RTAUDIO_SINT24 ) {
10280     for ( unsigned int i=0; i<samples; i++ ) {
10281       // Swap 1st and 3rd bytes.
10282       val = *(ptr);
10283       *(ptr) = *(ptr+2);
10284       *(ptr+2) = val;
10285
10286       // Increment 2 more bytes.
10287       ptr += 2;
10288     }
10289   }
10290   else if ( format == RTAUDIO_FLOAT64 ) {
10291     for ( unsigned int i=0; i<samples; i++ ) {
10292       // Swap 1st and 8th bytes
10293       val = *(ptr);
10294       *(ptr) = *(ptr+7);
10295       *(ptr+7) = val;
10296
10297       // Swap 2nd and 7th bytes
10298       ptr += 1;
10299       val = *(ptr);
10300       *(ptr) = *(ptr+5);
10301       *(ptr+5) = val;
10302
10303       // Swap 3rd and 6th bytes
10304       ptr += 1;
10305       val = *(ptr);
10306       *(ptr) = *(ptr+3);
10307       *(ptr+3) = val;
10308
10309       // Swap 4th and 5th bytes
10310       ptr += 1;
10311       val = *(ptr);
10312       *(ptr) = *(ptr+1);
10313       *(ptr+1) = val;
10314
10315       // Increment 5 more bytes.
10316       ptr += 5;
10317     }
10318   }
10319 }
10320
10321   // Indentation settings for Vim and Emacs
10322   //
10323   // Local Variables:
10324   // c-basic-offset: 2
10325   // indent-tabs-mode: nil
10326   // End:
10327   //
10328   // vim: et sts=2 sw=2
10329