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