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