1d235161e79dd26970fa9d671af31801d9918034
[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   // for cmath functions
3887   using namespace std;
3888
3889   outSampleCount = ( unsigned int ) roundf( inSampleCount * sampleRatio );
3890
3891   // if inSampleRate is a multiple of outSampleRate (or vice versa) there's no need to interpolate
3892   if ( floor( sampleRatio ) == sampleRatio || floor( sampleRatioInv ) == sampleRatioInv )
3893   {
3894     // frame-by-frame, copy each relative input sample into it's corresponding output sample
3895     for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )
3896     {
3897       unsigned int inSample = ( unsigned int ) inSampleFraction;
3898
3899       switch ( format )
3900       {
3901         case RTAUDIO_SINT8:
3902           memcpy( &( ( char* ) outBuffer )[ outSample * channelCount ], &( ( char* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( char ) );
3903           break;
3904         case RTAUDIO_SINT16:
3905           memcpy( &( ( short* ) outBuffer )[ outSample * channelCount ], &( ( short* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( short ) );
3906           break;
3907         case RTAUDIO_SINT24:
3908           memcpy( &( ( S24* ) outBuffer )[ outSample * channelCount ], &( ( S24* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( S24 ) );
3909           break;
3910         case RTAUDIO_SINT32:
3911           memcpy( &( ( int* ) outBuffer )[ outSample * channelCount ], &( ( int* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( int ) );
3912           break;
3913         case RTAUDIO_FLOAT32:
3914           memcpy( &( ( float* ) outBuffer )[ outSample * channelCount ], &( ( float* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( float ) );
3915           break;
3916         case RTAUDIO_FLOAT64:
3917           memcpy( &( ( double* ) outBuffer )[ outSample * channelCount ], &( ( double* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( double ) );
3918           break;
3919       }
3920
3921       // jump to next in sample
3922       inSampleFraction += sampleStep;
3923     }
3924   }
3925   else // else interpolate
3926   {
3927     // frame-by-frame, copy each relative input sample into it's corresponding output sample
3928     for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )
3929     {
3930       unsigned int inSample = ( unsigned int ) inSampleFraction;
3931       float inSampleDec = inSampleFraction - inSample;
3932       unsigned int frameInSample = inSample * channelCount;
3933       unsigned int frameOutSample = outSample * channelCount;
3934
3935       switch ( format )
3936       {
3937         case RTAUDIO_SINT8:
3938         {
3939           for ( unsigned int channel = 0; channel < channelCount; channel++ )
3940           {
3941             char fromSample = ( ( char* ) inBuffer )[ frameInSample + channel ];
3942             char toSample = ( ( char* ) inBuffer )[ frameInSample + channelCount + channel ];
3943             char sampleDiff = ( char ) ( ( toSample - fromSample ) * inSampleDec );
3944             ( ( char* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
3945           }
3946           break;
3947         }
3948         case RTAUDIO_SINT16:
3949         {
3950           for ( unsigned int channel = 0; channel < channelCount; channel++ )
3951           {
3952             short fromSample = ( ( short* ) inBuffer )[ frameInSample + channel ];
3953             short toSample = ( ( short* ) inBuffer )[ frameInSample + channelCount + channel ];
3954             short sampleDiff = ( short ) ( ( toSample - fromSample ) * inSampleDec );
3955             ( ( short* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
3956           }
3957           break;
3958         }
3959         case RTAUDIO_SINT24:
3960         {
3961           for ( unsigned int channel = 0; channel < channelCount; channel++ )
3962           {
3963             int fromSample = ( ( S24* ) inBuffer )[ frameInSample + channel ].asInt();
3964             int toSample = ( ( S24* ) inBuffer )[ frameInSample + channelCount + channel ].asInt();
3965             int sampleDiff = ( int ) ( ( toSample - fromSample ) * inSampleDec );
3966             ( ( S24* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
3967           }
3968           break;
3969         }
3970         case RTAUDIO_SINT32:
3971         {
3972           for ( unsigned int channel = 0; channel < channelCount; channel++ )
3973           {
3974             int fromSample = ( ( int* ) inBuffer )[ frameInSample + channel ];
3975             int toSample = ( ( int* ) inBuffer )[ frameInSample + channelCount + channel ];
3976             int sampleDiff = ( int ) ( ( toSample - fromSample ) * inSampleDec );
3977             ( ( int* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
3978           }
3979           break;
3980         }
3981         case RTAUDIO_FLOAT32:
3982         {
3983           for ( unsigned int channel = 0; channel < channelCount; channel++ )
3984           {
3985             float fromSample = ( ( float* ) inBuffer )[ frameInSample + channel ];
3986             float toSample = ( ( float* ) inBuffer )[ frameInSample + channelCount + channel ];
3987             float sampleDiff = ( toSample - fromSample ) * inSampleDec;
3988             ( ( float* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
3989           }
3990           break;
3991         }
3992         case RTAUDIO_FLOAT64:
3993         {
3994           for ( unsigned int channel = 0; channel < channelCount; channel++ )
3995           {
3996             double fromSample = ( ( double* ) inBuffer )[ frameInSample + channel ];
3997             double toSample = ( ( double* ) inBuffer )[ frameInSample + channelCount + channel ];
3998             double sampleDiff = ( toSample - fromSample ) * inSampleDec;
3999             ( ( double* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
4000           }
4001           break;
4002         }
4003       }
4004
4005       // jump to next in sample
4006       inSampleFraction += sampleStep;
4007     }
4008   }
4009 }
4010
4011 //-----------------------------------------------------------------------------
4012
4013 // A structure to hold various information related to the WASAPI implementation.
4014 struct WasapiHandle
4015 {
4016   IAudioClient* captureAudioClient;
4017   IAudioClient* renderAudioClient;
4018   IAudioCaptureClient* captureClient;
4019   IAudioRenderClient* renderClient;
4020   HANDLE captureEvent;
4021   HANDLE renderEvent;
4022
4023   WasapiHandle()
4024   : captureAudioClient( NULL ),
4025     renderAudioClient( NULL ),
4026     captureClient( NULL ),
4027     renderClient( NULL ),
4028     captureEvent( NULL ),
4029     renderEvent( NULL ) {}
4030 };
4031
4032 //=============================================================================
4033
4034 RtApiWasapi::RtApiWasapi()
4035   : coInitialized_( false ), deviceEnumerator_( NULL )
4036 {
4037   // WASAPI can run either apartment or multi-threaded
4038   HRESULT hr = CoInitialize( NULL );
4039   if ( !FAILED( hr ) )
4040     coInitialized_ = true;
4041
4042   // Instantiate device enumerator
4043   hr = CoCreateInstance( __uuidof( MMDeviceEnumerator ), NULL,
4044                          CLSCTX_ALL, __uuidof( IMMDeviceEnumerator ),
4045                          ( void** ) &deviceEnumerator_ );
4046
4047   if ( FAILED( hr ) ) {
4048     errorText_ = "RtApiWasapi::RtApiWasapi: Unable to instantiate device enumerator";
4049     error( RtAudioError::DRIVER_ERROR );
4050   }
4051 }
4052
4053 //-----------------------------------------------------------------------------
4054
4055 RtApiWasapi::~RtApiWasapi()
4056 {
4057   if ( stream_.state != STREAM_CLOSED )
4058     closeStream();
4059
4060   SAFE_RELEASE( deviceEnumerator_ );
4061
4062   // If this object previously called CoInitialize()
4063   if ( coInitialized_ )
4064     CoUninitialize();
4065 }
4066
4067 //=============================================================================
4068
4069 unsigned int RtApiWasapi::getDeviceCount( void )
4070 {
4071   unsigned int captureDeviceCount = 0;
4072   unsigned int renderDeviceCount = 0;
4073
4074   IMMDeviceCollection* captureDevices = NULL;
4075   IMMDeviceCollection* renderDevices = NULL;
4076
4077   // Count capture devices
4078   errorText_.clear();
4079   HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
4080   if ( FAILED( hr ) ) {
4081     errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device collection.";
4082     goto Exit;
4083   }
4084
4085   hr = captureDevices->GetCount( &captureDeviceCount );
4086   if ( FAILED( hr ) ) {
4087     errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device count.";
4088     goto Exit;
4089   }
4090
4091   // Count render devices
4092   hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );
4093   if ( FAILED( hr ) ) {
4094     errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device collection.";
4095     goto Exit;
4096   }
4097
4098   hr = renderDevices->GetCount( &renderDeviceCount );
4099   if ( FAILED( hr ) ) {
4100     errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device count.";
4101     goto Exit;
4102   }
4103
4104 Exit:
4105   // release all references
4106   SAFE_RELEASE( captureDevices );
4107   SAFE_RELEASE( renderDevices );
4108
4109   if ( errorText_.empty() )
4110     return captureDeviceCount + renderDeviceCount;
4111
4112   error( RtAudioError::DRIVER_ERROR );
4113   return 0;
4114 }
4115
4116 //-----------------------------------------------------------------------------
4117
4118 RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device )
4119 {
4120   RtAudio::DeviceInfo info;
4121   unsigned int captureDeviceCount = 0;
4122   unsigned int renderDeviceCount = 0;
4123   std::string defaultDeviceName;
4124   bool isCaptureDevice = false;
4125
4126   PROPVARIANT deviceNameProp;
4127   PROPVARIANT defaultDeviceNameProp;
4128
4129   IMMDeviceCollection* captureDevices = NULL;
4130   IMMDeviceCollection* renderDevices = NULL;
4131   IMMDevice* devicePtr = NULL;
4132   IMMDevice* defaultDevicePtr = NULL;
4133   IAudioClient* audioClient = NULL;
4134   IPropertyStore* devicePropStore = NULL;
4135   IPropertyStore* defaultDevicePropStore = NULL;
4136
4137   WAVEFORMATEX* deviceFormat = NULL;
4138   WAVEFORMATEX* closestMatchFormat = NULL;
4139
4140   // probed
4141   info.probed = false;
4142
4143   // Count capture devices
4144   errorText_.clear();
4145   RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;
4146   HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
4147   if ( FAILED( hr ) ) {
4148     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device collection.";
4149     goto Exit;
4150   }
4151
4152   hr = captureDevices->GetCount( &captureDeviceCount );
4153   if ( FAILED( hr ) ) {
4154     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device count.";
4155     goto Exit;
4156   }
4157
4158   // Count render devices
4159   hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );
4160   if ( FAILED( hr ) ) {
4161     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device collection.";
4162     goto Exit;
4163   }
4164
4165   hr = renderDevices->GetCount( &renderDeviceCount );
4166   if ( FAILED( hr ) ) {
4167     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device count.";
4168     goto Exit;
4169   }
4170
4171   // validate device index
4172   if ( device >= captureDeviceCount + renderDeviceCount ) {
4173     errorText_ = "RtApiWasapi::getDeviceInfo: Invalid device index.";
4174     errorType = RtAudioError::INVALID_USE;
4175     goto Exit;
4176   }
4177
4178   // determine whether index falls within capture or render devices
4179   if ( device >= renderDeviceCount ) {
4180     hr = captureDevices->Item( device - renderDeviceCount, &devicePtr );
4181     if ( FAILED( hr ) ) {
4182       errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device handle.";
4183       goto Exit;
4184     }
4185     isCaptureDevice = true;
4186   }
4187   else {
4188     hr = renderDevices->Item( device, &devicePtr );
4189     if ( FAILED( hr ) ) {
4190       errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device handle.";
4191       goto Exit;
4192     }
4193     isCaptureDevice = false;
4194   }
4195
4196   // get default device name
4197   if ( isCaptureDevice ) {
4198     hr = deviceEnumerator_->GetDefaultAudioEndpoint( eCapture, eConsole, &defaultDevicePtr );
4199     if ( FAILED( hr ) ) {
4200       errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default capture device handle.";
4201       goto Exit;
4202     }
4203   }
4204   else {
4205     hr = deviceEnumerator_->GetDefaultAudioEndpoint( eRender, eConsole, &defaultDevicePtr );
4206     if ( FAILED( hr ) ) {
4207       errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default render device handle.";
4208       goto Exit;
4209     }
4210   }
4211
4212   hr = defaultDevicePtr->OpenPropertyStore( STGM_READ, &defaultDevicePropStore );
4213   if ( FAILED( hr ) ) {
4214     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open default device property store.";
4215     goto Exit;
4216   }
4217   PropVariantInit( &defaultDeviceNameProp );
4218
4219   hr = defaultDevicePropStore->GetValue( PKEY_Device_FriendlyName, &defaultDeviceNameProp );
4220   if ( FAILED( hr ) ) {
4221     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default device property: PKEY_Device_FriendlyName.";
4222     goto Exit;
4223   }
4224
4225   defaultDeviceName = convertCharPointerToStdString(defaultDeviceNameProp.pwszVal);
4226
4227   // name
4228   hr = devicePtr->OpenPropertyStore( STGM_READ, &devicePropStore );
4229   if ( FAILED( hr ) ) {
4230     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open device property store.";
4231     goto Exit;
4232   }
4233
4234   PropVariantInit( &deviceNameProp );
4235
4236   hr = devicePropStore->GetValue( PKEY_Device_FriendlyName, &deviceNameProp );
4237   if ( FAILED( hr ) ) {
4238     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device property: PKEY_Device_FriendlyName.";
4239     goto Exit;
4240   }
4241
4242   info.name =convertCharPointerToStdString(deviceNameProp.pwszVal);
4243
4244   // is default
4245   if ( isCaptureDevice ) {
4246     info.isDefaultInput = info.name == defaultDeviceName;
4247     info.isDefaultOutput = false;
4248   }
4249   else {
4250     info.isDefaultInput = false;
4251     info.isDefaultOutput = info.name == defaultDeviceName;
4252   }
4253
4254   // channel count
4255   hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL, NULL, ( void** ) &audioClient );
4256   if ( FAILED( hr ) ) {
4257     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device audio client.";
4258     goto Exit;
4259   }
4260
4261   hr = audioClient->GetMixFormat( &deviceFormat );
4262   if ( FAILED( hr ) ) {
4263     errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device mix format.";
4264     goto Exit;
4265   }
4266
4267   if ( isCaptureDevice ) {
4268     info.inputChannels = deviceFormat->nChannels;
4269     info.outputChannels = 0;
4270     info.duplexChannels = 0;
4271   }
4272   else {
4273     info.inputChannels = 0;
4274     info.outputChannels = deviceFormat->nChannels;
4275     info.duplexChannels = 0;
4276   }
4277
4278   // sample rates
4279   info.sampleRates.clear();
4280
4281   // allow support for all sample rates as we have a built-in sample rate converter
4282   for ( unsigned int i = 0; i < MAX_SAMPLE_RATES; i++ ) {
4283     info.sampleRates.push_back( SAMPLE_RATES[i] );
4284   }
4285   info.preferredSampleRate = deviceFormat->nSamplesPerSec;
4286
4287   // native format
4288   info.nativeFormats = 0;
4289
4290   if ( deviceFormat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
4291        ( deviceFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
4292          ( ( WAVEFORMATEXTENSIBLE* ) deviceFormat )->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT ) )
4293   {
4294     if ( deviceFormat->wBitsPerSample == 32 ) {
4295       info.nativeFormats |= RTAUDIO_FLOAT32;
4296     }
4297     else if ( deviceFormat->wBitsPerSample == 64 ) {
4298       info.nativeFormats |= RTAUDIO_FLOAT64;
4299     }
4300   }
4301   else if ( deviceFormat->wFormatTag == WAVE_FORMAT_PCM ||
4302            ( deviceFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
4303              ( ( WAVEFORMATEXTENSIBLE* ) deviceFormat )->SubFormat == KSDATAFORMAT_SUBTYPE_PCM ) )
4304   {
4305     if ( deviceFormat->wBitsPerSample == 8 ) {
4306       info.nativeFormats |= RTAUDIO_SINT8;
4307     }
4308     else if ( deviceFormat->wBitsPerSample == 16 ) {
4309       info.nativeFormats |= RTAUDIO_SINT16;
4310     }
4311     else if ( deviceFormat->wBitsPerSample == 24 ) {
4312       info.nativeFormats |= RTAUDIO_SINT24;
4313     }
4314     else if ( deviceFormat->wBitsPerSample == 32 ) {
4315       info.nativeFormats |= RTAUDIO_SINT32;
4316     }
4317   }
4318
4319   // probed
4320   info.probed = true;
4321
4322 Exit:
4323   // release all references
4324   PropVariantClear( &deviceNameProp );
4325   PropVariantClear( &defaultDeviceNameProp );
4326
4327   SAFE_RELEASE( captureDevices );
4328   SAFE_RELEASE( renderDevices );
4329   SAFE_RELEASE( devicePtr );
4330   SAFE_RELEASE( defaultDevicePtr );
4331   SAFE_RELEASE( audioClient );
4332   SAFE_RELEASE( devicePropStore );
4333   SAFE_RELEASE( defaultDevicePropStore );
4334
4335   CoTaskMemFree( deviceFormat );
4336   CoTaskMemFree( closestMatchFormat );
4337
4338   if ( !errorText_.empty() )
4339     error( errorType );
4340   return info;
4341 }
4342
4343 //-----------------------------------------------------------------------------
4344
4345 unsigned int RtApiWasapi::getDefaultOutputDevice( void )
4346 {
4347   for ( unsigned int i = 0; i < getDeviceCount(); i++ ) {
4348     if ( getDeviceInfo( i ).isDefaultOutput ) {
4349       return i;
4350     }
4351   }
4352
4353   return 0;
4354 }
4355
4356 //-----------------------------------------------------------------------------
4357
4358 unsigned int RtApiWasapi::getDefaultInputDevice( void )
4359 {
4360   for ( unsigned int i = 0; i < getDeviceCount(); i++ ) {
4361     if ( getDeviceInfo( i ).isDefaultInput ) {
4362       return i;
4363     }
4364   }
4365
4366   return 0;
4367 }
4368
4369 //-----------------------------------------------------------------------------
4370
4371 void RtApiWasapi::closeStream( void )
4372 {
4373   if ( stream_.state == STREAM_CLOSED ) {
4374     errorText_ = "RtApiWasapi::closeStream: No open stream to close.";
4375     error( RtAudioError::WARNING );
4376     return;
4377   }
4378
4379   if ( stream_.state != STREAM_STOPPED )
4380     stopStream();
4381
4382   // clean up stream memory
4383   SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient )
4384   SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient )
4385
4386   SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->captureClient )
4387   SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->renderClient )
4388
4389   if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent )
4390     CloseHandle( ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent );
4391
4392   if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent )
4393     CloseHandle( ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent );
4394
4395   delete ( WasapiHandle* ) stream_.apiHandle;
4396   stream_.apiHandle = NULL;
4397
4398   for ( int i = 0; i < 2; i++ ) {
4399     if ( stream_.userBuffer[i] ) {
4400       free( stream_.userBuffer[i] );
4401       stream_.userBuffer[i] = 0;
4402     }
4403   }
4404
4405   if ( stream_.deviceBuffer ) {
4406     free( stream_.deviceBuffer );
4407     stream_.deviceBuffer = 0;
4408   }
4409
4410   // update stream state
4411   stream_.state = STREAM_CLOSED;
4412 }
4413
4414 //-----------------------------------------------------------------------------
4415
4416 void RtApiWasapi::startStream( void )
4417 {
4418   verifyStream();
4419
4420   if ( stream_.state == STREAM_RUNNING ) {
4421     errorText_ = "RtApiWasapi::startStream: The stream is already running.";
4422     error( RtAudioError::WARNING );
4423     return;
4424   }
4425
4426   // update stream state
4427   stream_.state = STREAM_RUNNING;
4428
4429   // create WASAPI stream thread
4430   stream_.callbackInfo.thread = ( ThreadHandle ) CreateThread( NULL, 0, runWasapiThread, this, CREATE_SUSPENDED, NULL );
4431
4432   if ( !stream_.callbackInfo.thread ) {
4433     errorText_ = "RtApiWasapi::startStream: Unable to instantiate callback thread.";
4434     error( RtAudioError::THREAD_ERROR );
4435   }
4436   else {
4437     SetThreadPriority( ( void* ) stream_.callbackInfo.thread, stream_.callbackInfo.priority );
4438     ResumeThread( ( void* ) stream_.callbackInfo.thread );
4439   }
4440 }
4441
4442 //-----------------------------------------------------------------------------
4443
4444 void RtApiWasapi::stopStream( void )
4445 {
4446   verifyStream();
4447
4448   if ( stream_.state == STREAM_STOPPED ) {
4449     errorText_ = "RtApiWasapi::stopStream: The stream is already stopped.";
4450     error( RtAudioError::WARNING );
4451     return;
4452   }
4453
4454   // inform stream thread by setting stream state to STREAM_STOPPING
4455   stream_.state = STREAM_STOPPING;
4456
4457   // wait until stream thread is stopped
4458   while( stream_.state != STREAM_STOPPED ) {
4459     Sleep( 1 );
4460   }
4461
4462   // Wait for the last buffer to play before stopping.
4463   Sleep( 1000 * stream_.bufferSize / stream_.sampleRate );
4464
4465   // stop capture client if applicable
4466   if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) {
4467     HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop();
4468     if ( FAILED( hr ) ) {
4469       errorText_ = "RtApiWasapi::stopStream: Unable to stop capture stream.";
4470       error( RtAudioError::DRIVER_ERROR );
4471       return;
4472     }
4473   }
4474
4475   // stop render client if applicable
4476   if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) {
4477     HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop();
4478     if ( FAILED( hr ) ) {
4479       errorText_ = "RtApiWasapi::stopStream: Unable to stop render stream.";
4480       error( RtAudioError::DRIVER_ERROR );
4481       return;
4482     }
4483   }
4484
4485   // close thread handle
4486   if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) {
4487     errorText_ = "RtApiWasapi::stopStream: Unable to close callback thread.";
4488     error( RtAudioError::THREAD_ERROR );
4489     return;
4490   }
4491
4492   stream_.callbackInfo.thread = (ThreadHandle) NULL;
4493 }
4494
4495 //-----------------------------------------------------------------------------
4496
4497 void RtApiWasapi::abortStream( void )
4498 {
4499   verifyStream();
4500
4501   if ( stream_.state == STREAM_STOPPED ) {
4502     errorText_ = "RtApiWasapi::abortStream: The stream is already stopped.";
4503     error( RtAudioError::WARNING );
4504     return;
4505   }
4506
4507   // inform stream thread by setting stream state to STREAM_STOPPING
4508   stream_.state = STREAM_STOPPING;
4509
4510   // wait until stream thread is stopped
4511   while ( stream_.state != STREAM_STOPPED ) {
4512     Sleep( 1 );
4513   }
4514
4515   // stop capture client if applicable
4516   if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) {
4517     HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop();
4518     if ( FAILED( hr ) ) {
4519       errorText_ = "RtApiWasapi::abortStream: Unable to stop capture stream.";
4520       error( RtAudioError::DRIVER_ERROR );
4521       return;
4522     }
4523   }
4524
4525   // stop render client if applicable
4526   if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) {
4527     HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop();
4528     if ( FAILED( hr ) ) {
4529       errorText_ = "RtApiWasapi::abortStream: Unable to stop render stream.";
4530       error( RtAudioError::DRIVER_ERROR );
4531       return;
4532     }
4533   }
4534
4535   // close thread handle
4536   if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) {
4537     errorText_ = "RtApiWasapi::abortStream: Unable to close callback thread.";
4538     error( RtAudioError::THREAD_ERROR );
4539     return;
4540   }
4541
4542   stream_.callbackInfo.thread = (ThreadHandle) NULL;
4543 }
4544
4545 //-----------------------------------------------------------------------------
4546
4547 bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
4548                                    unsigned int firstChannel, unsigned int sampleRate,
4549                                    RtAudioFormat format, unsigned int* bufferSize,
4550                                    RtAudio::StreamOptions* options )
4551 {
4552   bool methodResult = FAILURE;
4553   unsigned int captureDeviceCount = 0;
4554   unsigned int renderDeviceCount = 0;
4555
4556   IMMDeviceCollection* captureDevices = NULL;
4557   IMMDeviceCollection* renderDevices = NULL;
4558   IMMDevice* devicePtr = NULL;
4559   WAVEFORMATEX* deviceFormat = NULL;
4560   unsigned int bufferBytes;
4561   stream_.state = STREAM_STOPPED;
4562
4563   // create API Handle if not already created
4564   if ( !stream_.apiHandle )
4565     stream_.apiHandle = ( void* ) new WasapiHandle();
4566
4567   // Count capture devices
4568   errorText_.clear();
4569   RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;
4570   HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
4571   if ( FAILED( hr ) ) {
4572     errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device collection.";
4573     goto Exit;
4574   }
4575
4576   hr = captureDevices->GetCount( &captureDeviceCount );
4577   if ( FAILED( hr ) ) {
4578     errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device count.";
4579     goto Exit;
4580   }
4581
4582   // Count render devices
4583   hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );
4584   if ( FAILED( hr ) ) {
4585     errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device collection.";
4586     goto Exit;
4587   }
4588
4589   hr = renderDevices->GetCount( &renderDeviceCount );
4590   if ( FAILED( hr ) ) {
4591     errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device count.";
4592     goto Exit;
4593   }
4594
4595   // validate device index
4596   if ( device >= captureDeviceCount + renderDeviceCount ) {
4597     errorType = RtAudioError::INVALID_USE;
4598     errorText_ = "RtApiWasapi::probeDeviceOpen: Invalid device index.";
4599     goto Exit;
4600   }
4601
4602   // determine whether index falls within capture or render devices
4603   if ( device >= renderDeviceCount ) {
4604     if ( mode != INPUT ) {
4605       errorType = RtAudioError::INVALID_USE;
4606       errorText_ = "RtApiWasapi::probeDeviceOpen: Capture device selected as output device.";
4607       goto Exit;
4608     }
4609
4610     // retrieve captureAudioClient from devicePtr
4611     IAudioClient*& captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient;
4612
4613     hr = captureDevices->Item( device - renderDeviceCount, &devicePtr );
4614     if ( FAILED( hr ) ) {
4615       errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device handle.";
4616       goto Exit;
4617     }
4618
4619     hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,
4620                               NULL, ( void** ) &captureAudioClient );
4621     if ( FAILED( hr ) ) {
4622       errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";
4623       goto Exit;
4624     }
4625
4626     hr = captureAudioClient->GetMixFormat( &deviceFormat );
4627     if ( FAILED( hr ) ) {
4628       errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";
4629       goto Exit;
4630     }
4631
4632     stream_.nDeviceChannels[mode] = deviceFormat->nChannels;
4633     captureAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );
4634   }
4635   else {
4636     if ( mode != OUTPUT ) {
4637       errorType = RtAudioError::INVALID_USE;
4638       errorText_ = "RtApiWasapi::probeDeviceOpen: Render device selected as input device.";
4639       goto Exit;
4640     }
4641
4642     // retrieve renderAudioClient from devicePtr
4643     IAudioClient*& renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;
4644
4645     hr = renderDevices->Item( device, &devicePtr );
4646     if ( FAILED( hr ) ) {
4647       errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device handle.";
4648       goto Exit;
4649     }
4650
4651     hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,
4652                               NULL, ( void** ) &renderAudioClient );
4653     if ( FAILED( hr ) ) {
4654       errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";
4655       goto Exit;
4656     }
4657
4658     hr = renderAudioClient->GetMixFormat( &deviceFormat );
4659     if ( FAILED( hr ) ) {
4660       errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";
4661       goto Exit;
4662     }
4663
4664     stream_.nDeviceChannels[mode] = deviceFormat->nChannels;
4665     renderAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );
4666   }
4667
4668   // fill stream data
4669   if ( ( stream_.mode == OUTPUT && mode == INPUT ) ||
4670        ( stream_.mode == INPUT && mode == OUTPUT ) ) {
4671     stream_.mode = DUPLEX;
4672   }
4673   else {
4674     stream_.mode = mode;
4675   }
4676
4677   stream_.device[mode] = device;
4678   stream_.doByteSwap[mode] = false;
4679   stream_.sampleRate = sampleRate;
4680   stream_.bufferSize = *bufferSize;
4681   stream_.nBuffers = 1;
4682   stream_.nUserChannels[mode] = channels;
4683   stream_.channelOffset[mode] = firstChannel;
4684   stream_.userFormat = format;
4685   stream_.deviceFormat[mode] = getDeviceInfo( device ).nativeFormats;
4686
4687   if ( options && options->flags & RTAUDIO_NONINTERLEAVED )
4688     stream_.userInterleaved = false;
4689   else
4690     stream_.userInterleaved = true;
4691   stream_.deviceInterleaved[mode] = true;
4692
4693   // Set flags for buffer conversion.
4694   stream_.doConvertBuffer[mode] = false;
4695   if ( stream_.userFormat != stream_.deviceFormat[mode] ||
4696        stream_.nUserChannels != stream_.nDeviceChannels )
4697     stream_.doConvertBuffer[mode] = true;
4698   else if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
4699             stream_.nUserChannels[mode] > 1 )
4700     stream_.doConvertBuffer[mode] = true;
4701
4702   if ( stream_.doConvertBuffer[mode] )
4703     setConvertInfo( mode, 0 );
4704
4705   // Allocate necessary internal buffers
4706   bufferBytes = stream_.nUserChannels[mode] * stream_.bufferSize * formatBytes( stream_.userFormat );
4707
4708   stream_.userBuffer[mode] = ( char* ) calloc( bufferBytes, 1 );
4709   if ( !stream_.userBuffer[mode] ) {
4710     errorType = RtAudioError::MEMORY_ERROR;
4711     errorText_ = "RtApiWasapi::probeDeviceOpen: Error allocating user buffer memory.";
4712     goto Exit;
4713   }
4714
4715   if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME )
4716     stream_.callbackInfo.priority = 15;
4717   else
4718     stream_.callbackInfo.priority = 0;
4719
4720   ///! TODO: RTAUDIO_MINIMIZE_LATENCY // Provide stream buffers directly to callback
4721   ///! TODO: RTAUDIO_HOG_DEVICE       // Exclusive mode
4722
4723   methodResult = SUCCESS;
4724
4725 Exit:
4726   //clean up
4727   SAFE_RELEASE( captureDevices );
4728   SAFE_RELEASE( renderDevices );
4729   SAFE_RELEASE( devicePtr );
4730   CoTaskMemFree( deviceFormat );
4731
4732   // if method failed, close the stream
4733   if ( methodResult == FAILURE )
4734     closeStream();
4735
4736   if ( !errorText_.empty() )
4737     error( errorType );
4738   return methodResult;
4739 }
4740
4741 //=============================================================================
4742
4743 DWORD WINAPI RtApiWasapi::runWasapiThread( void* wasapiPtr )
4744 {
4745   if ( wasapiPtr )
4746     ( ( RtApiWasapi* ) wasapiPtr )->wasapiThread();
4747
4748   return 0;
4749 }
4750
4751 DWORD WINAPI RtApiWasapi::stopWasapiThread( void* wasapiPtr )
4752 {
4753   if ( wasapiPtr )
4754     ( ( RtApiWasapi* ) wasapiPtr )->stopStream();
4755
4756   return 0;
4757 }
4758
4759 DWORD WINAPI RtApiWasapi::abortWasapiThread( void* wasapiPtr )
4760 {
4761   if ( wasapiPtr )
4762     ( ( RtApiWasapi* ) wasapiPtr )->abortStream();
4763
4764   return 0;
4765 }
4766
4767 //-----------------------------------------------------------------------------
4768
4769 void RtApiWasapi::wasapiThread()
4770 {
4771   // as this is a new thread, we must CoInitialize it
4772   CoInitialize( NULL );
4773
4774   HRESULT hr;
4775
4776   IAudioClient* captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient;
4777   IAudioClient* renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;
4778   IAudioCaptureClient* captureClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureClient;
4779   IAudioRenderClient* renderClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderClient;
4780   HANDLE captureEvent = ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent;
4781   HANDLE renderEvent = ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent;
4782
4783   WAVEFORMATEX* captureFormat = NULL;
4784   WAVEFORMATEX* renderFormat = NULL;
4785   float captureSrRatio = 0.0f;
4786   float renderSrRatio = 0.0f;
4787   WasapiBuffer captureBuffer;
4788   WasapiBuffer renderBuffer;
4789
4790   // declare local stream variables
4791   RtAudioCallback callback = ( RtAudioCallback ) stream_.callbackInfo.callback;
4792   BYTE* streamBuffer = NULL;
4793   unsigned long captureFlags = 0;
4794   unsigned int bufferFrameCount = 0;
4795   unsigned int numFramesPadding = 0;
4796   unsigned int convBufferSize = 0;
4797   bool callbackPushed = false;
4798   bool callbackPulled = false;
4799   bool callbackStopped = false;
4800   int callbackResult = 0;
4801
4802   // convBuffer is used to store converted buffers between WASAPI and the user
4803   char* convBuffer = NULL;
4804   unsigned int convBuffSize = 0;
4805   unsigned int deviceBuffSize = 0;
4806
4807   errorText_.clear();
4808   RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;
4809
4810   // Attempt to assign "Pro Audio" characteristic to thread
4811   HMODULE AvrtDll = LoadLibrary( (LPCTSTR) "AVRT.dll" );
4812   if ( AvrtDll ) {
4813     DWORD taskIndex = 0;
4814     TAvSetMmThreadCharacteristicsPtr AvSetMmThreadCharacteristicsPtr = ( TAvSetMmThreadCharacteristicsPtr ) GetProcAddress( AvrtDll, "AvSetMmThreadCharacteristicsW" );
4815     AvSetMmThreadCharacteristicsPtr( L"Pro Audio", &taskIndex );
4816     FreeLibrary( AvrtDll );
4817   }
4818
4819   // start capture stream if applicable
4820   if ( captureAudioClient ) {
4821     hr = captureAudioClient->GetMixFormat( &captureFormat );
4822     if ( FAILED( hr ) ) {
4823       errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";
4824       goto Exit;
4825     }
4826
4827     captureSrRatio = ( ( float ) captureFormat->nSamplesPerSec / stream_.sampleRate );
4828
4829     // initialize capture stream according to desire buffer size
4830     float desiredBufferSize = stream_.bufferSize * captureSrRatio;
4831     REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) desiredBufferSize * 10000000 / captureFormat->nSamplesPerSec );
4832
4833     if ( !captureClient ) {
4834       hr = captureAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED,
4835                                            AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
4836                                            desiredBufferPeriod,
4837                                            desiredBufferPeriod,
4838                                            captureFormat,
4839                                            NULL );
4840       if ( FAILED( hr ) ) {
4841         errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize capture audio client.";
4842         goto Exit;
4843       }
4844
4845       hr = captureAudioClient->GetService( __uuidof( IAudioCaptureClient ),
4846                                            ( void** ) &captureClient );
4847       if ( FAILED( hr ) ) {
4848         errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture client handle.";
4849         goto Exit;
4850       }
4851
4852       // configure captureEvent to trigger on every available capture buffer
4853       captureEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
4854       if ( !captureEvent ) {
4855         errorType = RtAudioError::SYSTEM_ERROR;
4856         errorText_ = "RtApiWasapi::wasapiThread: Unable to create capture event.";
4857         goto Exit;
4858       }
4859
4860       hr = captureAudioClient->SetEventHandle( captureEvent );
4861       if ( FAILED( hr ) ) {
4862         errorText_ = "RtApiWasapi::wasapiThread: Unable to set capture event handle.";
4863         goto Exit;
4864       }
4865
4866       ( ( WasapiHandle* ) stream_.apiHandle )->captureClient = captureClient;
4867       ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent = captureEvent;
4868     }
4869
4870     unsigned int inBufferSize = 0;
4871     hr = captureAudioClient->GetBufferSize( &inBufferSize );
4872     if ( FAILED( hr ) ) {
4873       errorText_ = "RtApiWasapi::wasapiThread: Unable to get capture buffer size.";
4874       goto Exit;
4875     }
4876
4877     // scale outBufferSize according to stream->user sample rate ratio
4878     unsigned int outBufferSize = ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT];
4879     inBufferSize *= stream_.nDeviceChannels[INPUT];
4880
4881     // set captureBuffer size
4882     captureBuffer.setBufferSize( inBufferSize + outBufferSize, formatBytes( stream_.deviceFormat[INPUT] ) );
4883
4884     // reset the capture stream
4885     hr = captureAudioClient->Reset();
4886     if ( FAILED( hr ) ) {
4887       errorText_ = "RtApiWasapi::wasapiThread: Unable to reset capture stream.";
4888       goto Exit;
4889     }
4890
4891     // start the capture stream
4892     hr = captureAudioClient->Start();
4893     if ( FAILED( hr ) ) {
4894       errorText_ = "RtApiWasapi::wasapiThread: Unable to start capture stream.";
4895       goto Exit;
4896     }
4897   }
4898
4899   // start render stream if applicable
4900   if ( renderAudioClient ) {
4901     hr = renderAudioClient->GetMixFormat( &renderFormat );
4902     if ( FAILED( hr ) ) {
4903       errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";
4904       goto Exit;
4905     }
4906
4907     renderSrRatio = ( ( float ) renderFormat->nSamplesPerSec / stream_.sampleRate );
4908
4909     // initialize render stream according to desire buffer size
4910     float desiredBufferSize = stream_.bufferSize * renderSrRatio;
4911     REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) desiredBufferSize * 10000000 / renderFormat->nSamplesPerSec );
4912
4913     if ( !renderClient ) {
4914       hr = renderAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED,
4915                                           AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
4916                                           desiredBufferPeriod,
4917                                           desiredBufferPeriod,
4918                                           renderFormat,
4919                                           NULL );
4920       if ( FAILED( hr ) ) {
4921         errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize render audio client.";
4922         goto Exit;
4923       }
4924
4925       hr = renderAudioClient->GetService( __uuidof( IAudioRenderClient ),
4926                                           ( void** ) &renderClient );
4927       if ( FAILED( hr ) ) {
4928         errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render client handle.";
4929         goto Exit;
4930       }
4931
4932       // configure renderEvent to trigger on every available render buffer
4933       renderEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
4934       if ( !renderEvent ) {
4935         errorType = RtAudioError::SYSTEM_ERROR;
4936         errorText_ = "RtApiWasapi::wasapiThread: Unable to create render event.";
4937         goto Exit;
4938       }
4939
4940       hr = renderAudioClient->SetEventHandle( renderEvent );
4941       if ( FAILED( hr ) ) {
4942         errorText_ = "RtApiWasapi::wasapiThread: Unable to set render event handle.";
4943         goto Exit;
4944       }
4945
4946       ( ( WasapiHandle* ) stream_.apiHandle )->renderClient = renderClient;
4947       ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent = renderEvent;
4948     }
4949
4950     unsigned int outBufferSize = 0;
4951     hr = renderAudioClient->GetBufferSize( &outBufferSize );
4952     if ( FAILED( hr ) ) {
4953       errorText_ = "RtApiWasapi::wasapiThread: Unable to get render buffer size.";
4954       goto Exit;
4955     }
4956
4957     // scale inBufferSize according to user->stream sample rate ratio
4958     unsigned int inBufferSize = ( unsigned int ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT];
4959     outBufferSize *= stream_.nDeviceChannels[OUTPUT];
4960
4961     // set renderBuffer size
4962     renderBuffer.setBufferSize( inBufferSize + outBufferSize, formatBytes( stream_.deviceFormat[OUTPUT] ) );
4963
4964     // reset the render stream
4965     hr = renderAudioClient->Reset();
4966     if ( FAILED( hr ) ) {
4967       errorText_ = "RtApiWasapi::wasapiThread: Unable to reset render stream.";
4968       goto Exit;
4969     }
4970
4971     // start the render stream
4972     hr = renderAudioClient->Start();
4973     if ( FAILED( hr ) ) {
4974       errorText_ = "RtApiWasapi::wasapiThread: Unable to start render stream.";
4975       goto Exit;
4976     }
4977   }
4978
4979   if ( stream_.mode == INPUT ) {
4980     using namespace std; // for roundf
4981     convBuffSize = ( size_t ) roundf( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] );
4982     deviceBuffSize = stream_.bufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] );
4983   }
4984   else if ( stream_.mode == OUTPUT ) {
4985     convBuffSize = ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] );
4986     deviceBuffSize = stream_.bufferSize * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] );
4987   }
4988   else if ( stream_.mode == DUPLEX ) {
4989     convBuffSize = std::max( ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),
4990                              ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) );
4991     deviceBuffSize = std::max( stream_.bufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),
4992                                stream_.bufferSize * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) );
4993   }
4994
4995   convBuffer = ( char* ) malloc( convBuffSize );
4996   stream_.deviceBuffer = ( char* ) malloc( deviceBuffSize );
4997   if ( !convBuffer || !stream_.deviceBuffer ) {
4998     errorType = RtAudioError::MEMORY_ERROR;
4999     errorText_ = "RtApiWasapi::wasapiThread: Error allocating device buffer memory.";
5000     goto Exit;
5001   }
5002
5003   // stream process loop
5004   while ( stream_.state != STREAM_STOPPING ) {
5005     if ( !callbackPulled ) {
5006       // Callback Input
5007       // ==============
5008       // 1. Pull callback buffer from inputBuffer
5009       // 2. If 1. was successful: Convert callback buffer to user sample rate and channel count
5010       //                          Convert callback buffer to user format
5011
5012       if ( captureAudioClient ) {
5013         // Pull callback buffer from inputBuffer
5014         callbackPulled = captureBuffer.pullBuffer( convBuffer,
5015                                                    ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT],
5016                                                    stream_.deviceFormat[INPUT] );
5017
5018         if ( callbackPulled ) {
5019           // Convert callback buffer to user sample rate
5020           convertBufferWasapi( stream_.deviceBuffer,
5021                                convBuffer,
5022                                stream_.nDeviceChannels[INPUT],
5023                                captureFormat->nSamplesPerSec,
5024                                stream_.sampleRate,
5025                                ( unsigned int ) ( stream_.bufferSize * captureSrRatio ),
5026                                convBufferSize,
5027                                stream_.deviceFormat[INPUT] );
5028
5029           if ( stream_.doConvertBuffer[INPUT] ) {
5030             // Convert callback buffer to user format
5031             convertBuffer( stream_.userBuffer[INPUT],
5032                            stream_.deviceBuffer,
5033                            stream_.convertInfo[INPUT] );
5034           }
5035           else {
5036             // no further conversion, simple copy deviceBuffer to userBuffer
5037             memcpy( stream_.userBuffer[INPUT],
5038                     stream_.deviceBuffer,
5039                     stream_.bufferSize * stream_.nUserChannels[INPUT] * formatBytes( stream_.userFormat ) );
5040           }
5041         }
5042       }
5043       else {
5044         // if there is no capture stream, set callbackPulled flag
5045         callbackPulled = true;
5046       }
5047
5048       // Execute Callback
5049       // ================
5050       // 1. Execute user callback method
5051       // 2. Handle return value from callback
5052
5053       // if callback has not requested the stream to stop
5054       if ( callbackPulled && !callbackStopped ) {
5055         // Execute user callback method
5056         callbackResult = callback( stream_.userBuffer[OUTPUT],
5057                                    stream_.userBuffer[INPUT],
5058                                    stream_.bufferSize,
5059                                    getStreamTime(),
5060                                    captureFlags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY ? RTAUDIO_INPUT_OVERFLOW : 0,
5061                                    stream_.callbackInfo.userData );
5062
5063         // Handle return value from callback
5064         if ( callbackResult == 1 ) {
5065           // instantiate a thread to stop this thread
5066           HANDLE threadHandle = CreateThread( NULL, 0, stopWasapiThread, this, 0, NULL );
5067           if ( !threadHandle ) {
5068             errorType = RtAudioError::THREAD_ERROR;
5069             errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream stop thread.";
5070             goto Exit;
5071           }
5072           else if ( !CloseHandle( threadHandle ) ) {
5073             errorType = RtAudioError::THREAD_ERROR;
5074             errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream stop thread handle.";
5075             goto Exit;
5076           }
5077
5078           callbackStopped = true;
5079         }
5080         else if ( callbackResult == 2 ) {
5081           // instantiate a thread to stop this thread
5082           HANDLE threadHandle = CreateThread( NULL, 0, abortWasapiThread, this, 0, NULL );
5083           if ( !threadHandle ) {
5084             errorType = RtAudioError::THREAD_ERROR;
5085             errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream abort thread.";
5086             goto Exit;
5087           }
5088           else if ( !CloseHandle( threadHandle ) ) {
5089             errorType = RtAudioError::THREAD_ERROR;
5090             errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream abort thread handle.";
5091             goto Exit;
5092           }
5093
5094           callbackStopped = true;
5095         }
5096       }
5097     }
5098
5099     // Callback Output
5100     // ===============
5101     // 1. Convert callback buffer to stream format
5102     // 2. Convert callback buffer to stream sample rate and channel count
5103     // 3. Push callback buffer into outputBuffer
5104
5105     if ( renderAudioClient && callbackPulled ) {
5106       if ( stream_.doConvertBuffer[OUTPUT] ) {
5107         // Convert callback buffer to stream format
5108         convertBuffer( stream_.deviceBuffer,
5109                        stream_.userBuffer[OUTPUT],
5110                        stream_.convertInfo[OUTPUT] );
5111
5112       }
5113
5114       // Convert callback buffer to stream sample rate
5115       convertBufferWasapi( convBuffer,
5116                            stream_.deviceBuffer,
5117                            stream_.nDeviceChannels[OUTPUT],
5118                            stream_.sampleRate,
5119                            renderFormat->nSamplesPerSec,
5120                            stream_.bufferSize,
5121                            convBufferSize,
5122                            stream_.deviceFormat[OUTPUT] );
5123
5124       // Push callback buffer into outputBuffer
5125       callbackPushed = renderBuffer.pushBuffer( convBuffer,
5126                                                 convBufferSize * stream_.nDeviceChannels[OUTPUT],
5127                                                 stream_.deviceFormat[OUTPUT] );
5128     }
5129     else {
5130       // if there is no render stream, set callbackPushed flag
5131       callbackPushed = true;
5132     }
5133
5134     // Stream Capture
5135     // ==============
5136     // 1. Get capture buffer from stream
5137     // 2. Push capture buffer into inputBuffer
5138     // 3. If 2. was successful: Release capture buffer
5139
5140     if ( captureAudioClient ) {
5141       // if the callback input buffer was not pulled from captureBuffer, wait for next capture event
5142       if ( !callbackPulled ) {
5143         WaitForSingleObject( captureEvent, INFINITE );
5144       }
5145
5146       // Get capture buffer from stream
5147       hr = captureClient->GetBuffer( &streamBuffer,
5148                                      &bufferFrameCount,
5149                                      &captureFlags, NULL, NULL );
5150       if ( FAILED( hr ) ) {
5151         errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture buffer.";
5152         goto Exit;
5153       }
5154
5155       if ( bufferFrameCount != 0 ) {
5156         // Push capture buffer into inputBuffer
5157         if ( captureBuffer.pushBuffer( ( char* ) streamBuffer,
5158                                        bufferFrameCount * stream_.nDeviceChannels[INPUT],
5159                                        stream_.deviceFormat[INPUT] ) )
5160         {
5161           // Release capture buffer
5162           hr = captureClient->ReleaseBuffer( bufferFrameCount );
5163           if ( FAILED( hr ) ) {
5164             errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
5165             goto Exit;
5166           }
5167         }
5168         else
5169         {
5170           // Inform WASAPI that capture was unsuccessful
5171           hr = captureClient->ReleaseBuffer( 0 );
5172           if ( FAILED( hr ) ) {
5173             errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
5174             goto Exit;
5175           }
5176         }
5177       }
5178       else
5179       {
5180         // Inform WASAPI that capture was unsuccessful
5181         hr = captureClient->ReleaseBuffer( 0 );
5182         if ( FAILED( hr ) ) {
5183           errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
5184           goto Exit;
5185         }
5186       }
5187     }
5188
5189     // Stream Render
5190     // =============
5191     // 1. Get render buffer from stream
5192     // 2. Pull next buffer from outputBuffer
5193     // 3. If 2. was successful: Fill render buffer with next buffer
5194     //                          Release render buffer
5195
5196     if ( renderAudioClient ) {
5197       // if the callback output buffer was not pushed to renderBuffer, wait for next render event
5198       if ( callbackPulled && !callbackPushed ) {
5199         WaitForSingleObject( renderEvent, INFINITE );
5200       }
5201
5202       // Get render buffer from stream
5203       hr = renderAudioClient->GetBufferSize( &bufferFrameCount );
5204       if ( FAILED( hr ) ) {
5205         errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer size.";
5206         goto Exit;
5207       }
5208
5209       hr = renderAudioClient->GetCurrentPadding( &numFramesPadding );
5210       if ( FAILED( hr ) ) {
5211         errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer padding.";
5212         goto Exit;
5213       }
5214
5215       bufferFrameCount -= numFramesPadding;
5216
5217       if ( bufferFrameCount != 0 ) {
5218         hr = renderClient->GetBuffer( bufferFrameCount, &streamBuffer );
5219         if ( FAILED( hr ) ) {
5220           errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer.";
5221           goto Exit;
5222         }
5223
5224         // Pull next buffer from outputBuffer
5225         // Fill render buffer with next buffer
5226         if ( renderBuffer.pullBuffer( ( char* ) streamBuffer,
5227                                       bufferFrameCount * stream_.nDeviceChannels[OUTPUT],
5228                                       stream_.deviceFormat[OUTPUT] ) )
5229         {
5230           // Release render buffer
5231           hr = renderClient->ReleaseBuffer( bufferFrameCount, 0 );
5232           if ( FAILED( hr ) ) {
5233             errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
5234             goto Exit;
5235           }
5236         }
5237         else
5238         {
5239           // Inform WASAPI that render was unsuccessful
5240           hr = renderClient->ReleaseBuffer( 0, 0 );
5241           if ( FAILED( hr ) ) {
5242             errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
5243             goto Exit;
5244           }
5245         }
5246       }
5247       else
5248       {
5249         // Inform WASAPI that render was unsuccessful
5250         hr = renderClient->ReleaseBuffer( 0, 0 );
5251         if ( FAILED( hr ) ) {
5252           errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
5253           goto Exit;
5254         }
5255       }
5256     }
5257
5258     // if the callback buffer was pushed renderBuffer reset callbackPulled flag
5259     if ( callbackPushed ) {
5260       callbackPulled = false;
5261       // tick stream time
5262       RtApi::tickStreamTime();
5263     }
5264
5265   }
5266
5267 Exit:
5268   // clean up
5269   CoTaskMemFree( captureFormat );
5270   CoTaskMemFree( renderFormat );
5271
5272   free ( convBuffer );
5273
5274   CoUninitialize();
5275
5276   // update stream state
5277   stream_.state = STREAM_STOPPED;
5278
5279   if ( errorText_.empty() )
5280     return;
5281   else
5282     error( errorType );
5283 }
5284
5285 //******************** End of __WINDOWS_WASAPI__ *********************//
5286 #endif
5287
5288
5289 #if defined(__WINDOWS_DS__) // Windows DirectSound API
5290
5291 // Modified by Robin Davies, October 2005
5292 // - Improvements to DirectX pointer chasing. 
5293 // - Bug fix for non-power-of-two Asio granularity used by Edirol PCR-A30.
5294 // - Auto-call CoInitialize for DSOUND and ASIO platforms.
5295 // Various revisions for RtAudio 4.0 by Gary Scavone, April 2007
5296 // Changed device query structure for RtAudio 4.0.7, January 2010
5297
5298 #include <mmsystem.h>
5299 #include <mmreg.h>
5300 #include <dsound.h>
5301 #include <assert.h>
5302 #include <algorithm>
5303
5304 #if defined(__MINGW32__)
5305   // missing from latest mingw winapi
5306 #define WAVE_FORMAT_96M08 0x00010000 /* 96 kHz, Mono, 8-bit */
5307 #define WAVE_FORMAT_96S08 0x00020000 /* 96 kHz, Stereo, 8-bit */
5308 #define WAVE_FORMAT_96M16 0x00040000 /* 96 kHz, Mono, 16-bit */
5309 #define WAVE_FORMAT_96S16 0x00080000 /* 96 kHz, Stereo, 16-bit */
5310 #endif
5311
5312 #define MINIMUM_DEVICE_BUFFER_SIZE 32768
5313
5314 #ifdef _MSC_VER // if Microsoft Visual C++
5315 #pragma comment( lib, "winmm.lib" ) // then, auto-link winmm.lib. Otherwise, it has to be added manually.
5316 #endif
5317
5318 static inline DWORD dsPointerBetween( DWORD pointer, DWORD laterPointer, DWORD earlierPointer, DWORD bufferSize )
5319 {
5320   if ( pointer > bufferSize ) pointer -= bufferSize;
5321   if ( laterPointer < earlierPointer ) laterPointer += bufferSize;
5322   if ( pointer < earlierPointer ) pointer += bufferSize;
5323   return pointer >= earlierPointer && pointer < laterPointer;
5324 }
5325
5326 // A structure to hold various information related to the DirectSound
5327 // API implementation.
5328 struct DsHandle {
5329   unsigned int drainCounter; // Tracks callback counts when draining
5330   bool internalDrain;        // Indicates if stop is initiated from callback or not.
5331   void *id[2];
5332   void *buffer[2];
5333   bool xrun[2];
5334   UINT bufferPointer[2];  
5335   DWORD dsBufferSize[2];
5336   DWORD dsPointerLeadTime[2]; // the number of bytes ahead of the safe pointer to lead by.
5337   HANDLE condition;
5338
5339   DsHandle()
5340     :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; }
5341 };
5342
5343 // Declarations for utility functions, callbacks, and structures
5344 // specific to the DirectSound implementation.
5345 static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
5346                                           LPCTSTR description,
5347                                           LPCTSTR module,
5348                                           LPVOID lpContext );
5349
5350 static const char* getErrorString( int code );
5351
5352 static unsigned __stdcall callbackHandler( void *ptr );
5353
5354 struct DsDevice {
5355   LPGUID id[2];
5356   bool validId[2];
5357   bool found;
5358   std::string name;
5359
5360   DsDevice()
5361   : found(false) { validId[0] = false; validId[1] = false; }
5362 };
5363
5364 struct DsProbeData {
5365   bool isInput;
5366   std::vector<struct DsDevice>* dsDevices;
5367 };
5368
5369 RtApiDs :: RtApiDs()
5370 {
5371   // Dsound will run both-threaded. If CoInitialize fails, then just
5372   // accept whatever the mainline chose for a threading model.
5373   coInitialized_ = false;
5374   HRESULT hr = CoInitialize( NULL );
5375   if ( !FAILED( hr ) ) coInitialized_ = true;
5376 }
5377
5378 RtApiDs :: ~RtApiDs()
5379 {
5380   if ( stream_.state != STREAM_CLOSED ) closeStream();
5381   if ( coInitialized_ ) CoUninitialize(); // balanced call.
5382 }
5383
5384 // The DirectSound default output is always the first device.
5385 unsigned int RtApiDs :: getDefaultOutputDevice( void )
5386 {
5387   return 0;
5388 }
5389
5390 // The DirectSound default input is always the first input device,
5391 // which is the first capture device enumerated.
5392 unsigned int RtApiDs :: getDefaultInputDevice( void )
5393 {
5394   return 0;
5395 }
5396
5397 unsigned int RtApiDs :: getDeviceCount( void )
5398 {
5399   // Set query flag for previously found devices to false, so that we
5400   // can check for any devices that have disappeared.
5401   for ( unsigned int i=0; i<dsDevices.size(); i++ )
5402     dsDevices[i].found = false;
5403
5404   // Query DirectSound devices.
5405   struct DsProbeData probeInfo;
5406   probeInfo.isInput = false;
5407   probeInfo.dsDevices = &dsDevices;
5408   HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );
5409   if ( FAILED( result ) ) {
5410     errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating output devices!";
5411     errorText_ = errorStream_.str();
5412     error( RtAudioError::WARNING );
5413   }
5414
5415   // Query DirectSoundCapture devices.
5416   probeInfo.isInput = true;
5417   result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );
5418   if ( FAILED( result ) ) {
5419     errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating input devices!";
5420     errorText_ = errorStream_.str();
5421     error( RtAudioError::WARNING );
5422   }
5423
5424   // Clean out any devices that may have disappeared (code update submitted by Eli Zehngut).
5425   for ( unsigned int i=0; i<dsDevices.size(); ) {
5426     if ( dsDevices[i].found == false ) dsDevices.erase( dsDevices.begin() + i );
5427     else i++;
5428   }
5429
5430   return static_cast<unsigned int>(dsDevices.size());
5431 }
5432
5433 RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
5434 {
5435   RtAudio::DeviceInfo info;
5436   info.probed = false;
5437
5438   if ( dsDevices.size() == 0 ) {
5439     // Force a query of all devices
5440     getDeviceCount();
5441     if ( dsDevices.size() == 0 ) {
5442       errorText_ = "RtApiDs::getDeviceInfo: no devices found!";
5443       error( RtAudioError::INVALID_USE );
5444       return info;
5445     }
5446   }
5447
5448   if ( device >= dsDevices.size() ) {
5449     errorText_ = "RtApiDs::getDeviceInfo: device ID is invalid!";
5450     error( RtAudioError::INVALID_USE );
5451     return info;
5452   }
5453
5454   HRESULT result;
5455   if ( dsDevices[ device ].validId[0] == false ) goto probeInput;
5456
5457   LPDIRECTSOUND output;
5458   DSCAPS outCaps;
5459   result = DirectSoundCreate( dsDevices[ device ].id[0], &output, NULL );
5460   if ( FAILED( result ) ) {
5461     errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!";
5462     errorText_ = errorStream_.str();
5463     error( RtAudioError::WARNING );
5464     goto probeInput;
5465   }
5466
5467   outCaps.dwSize = sizeof( outCaps );
5468   result = output->GetCaps( &outCaps );
5469   if ( FAILED( result ) ) {
5470     output->Release();
5471     errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting capabilities!";
5472     errorText_ = errorStream_.str();
5473     error( RtAudioError::WARNING );
5474     goto probeInput;
5475   }
5476
5477   // Get output channel information.
5478   info.outputChannels = ( outCaps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
5479
5480   // Get sample rate information.
5481   info.sampleRates.clear();
5482   for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
5483     if ( SAMPLE_RATES[k] >= (unsigned int) outCaps.dwMinSecondarySampleRate &&
5484          SAMPLE_RATES[k] <= (unsigned int) outCaps.dwMaxSecondarySampleRate ) {
5485       info.sampleRates.push_back( SAMPLE_RATES[k] );
5486
5487       if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )
5488         info.preferredSampleRate = SAMPLE_RATES[k];
5489     }
5490   }
5491
5492   // Get format information.
5493   if ( outCaps.dwFlags & DSCAPS_PRIMARY16BIT ) info.nativeFormats |= RTAUDIO_SINT16;
5494   if ( outCaps.dwFlags & DSCAPS_PRIMARY8BIT ) info.nativeFormats |= RTAUDIO_SINT8;
5495
5496   output->Release();
5497
5498   if ( getDefaultOutputDevice() == device )
5499     info.isDefaultOutput = true;
5500
5501   if ( dsDevices[ device ].validId[1] == false ) {
5502     info.name = dsDevices[ device ].name;
5503     info.probed = true;
5504     return info;
5505   }
5506
5507  probeInput:
5508
5509   LPDIRECTSOUNDCAPTURE input;
5510   result = DirectSoundCaptureCreate( dsDevices[ device ].id[1], &input, NULL );
5511   if ( FAILED( result ) ) {
5512     errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!";
5513     errorText_ = errorStream_.str();
5514     error( RtAudioError::WARNING );
5515     return info;
5516   }
5517
5518   DSCCAPS inCaps;
5519   inCaps.dwSize = sizeof( inCaps );
5520   result = input->GetCaps( &inCaps );
5521   if ( FAILED( result ) ) {
5522     input->Release();
5523     errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting object capabilities (" << dsDevices[ device ].name << ")!";
5524     errorText_ = errorStream_.str();
5525     error( RtAudioError::WARNING );
5526     return info;
5527   }
5528
5529   // Get input channel information.
5530   info.inputChannels = inCaps.dwChannels;
5531
5532   // Get sample rate and format information.
5533   std::vector<unsigned int> rates;
5534   if ( inCaps.dwChannels >= 2 ) {
5535     if ( inCaps.dwFormats & WAVE_FORMAT_1S16 ) info.nativeFormats |= RTAUDIO_SINT16;
5536     if ( inCaps.dwFormats & WAVE_FORMAT_2S16 ) info.nativeFormats |= RTAUDIO_SINT16;
5537     if ( inCaps.dwFormats & WAVE_FORMAT_4S16 ) info.nativeFormats |= RTAUDIO_SINT16;
5538     if ( inCaps.dwFormats & WAVE_FORMAT_96S16 ) info.nativeFormats |= RTAUDIO_SINT16;
5539     if ( inCaps.dwFormats & WAVE_FORMAT_1S08 ) info.nativeFormats |= RTAUDIO_SINT8;
5540     if ( inCaps.dwFormats & WAVE_FORMAT_2S08 ) info.nativeFormats |= RTAUDIO_SINT8;
5541     if ( inCaps.dwFormats & WAVE_FORMAT_4S08 ) info.nativeFormats |= RTAUDIO_SINT8;
5542     if ( inCaps.dwFormats & WAVE_FORMAT_96S08 ) info.nativeFormats |= RTAUDIO_SINT8;
5543
5544     if ( info.nativeFormats & RTAUDIO_SINT16 ) {
5545       if ( inCaps.dwFormats & WAVE_FORMAT_1S16 ) rates.push_back( 11025 );
5546       if ( inCaps.dwFormats & WAVE_FORMAT_2S16 ) rates.push_back( 22050 );
5547       if ( inCaps.dwFormats & WAVE_FORMAT_4S16 ) rates.push_back( 44100 );
5548       if ( inCaps.dwFormats & WAVE_FORMAT_96S16 ) rates.push_back( 96000 );
5549     }
5550     else if ( info.nativeFormats & RTAUDIO_SINT8 ) {
5551       if ( inCaps.dwFormats & WAVE_FORMAT_1S08 ) rates.push_back( 11025 );
5552       if ( inCaps.dwFormats & WAVE_FORMAT_2S08 ) rates.push_back( 22050 );
5553       if ( inCaps.dwFormats & WAVE_FORMAT_4S08 ) rates.push_back( 44100 );
5554       if ( inCaps.dwFormats & WAVE_FORMAT_96S08 ) rates.push_back( 96000 );
5555     }
5556   }
5557   else if ( inCaps.dwChannels == 1 ) {
5558     if ( inCaps.dwFormats & WAVE_FORMAT_1M16 ) info.nativeFormats |= RTAUDIO_SINT16;
5559     if ( inCaps.dwFormats & WAVE_FORMAT_2M16 ) info.nativeFormats |= RTAUDIO_SINT16;
5560     if ( inCaps.dwFormats & WAVE_FORMAT_4M16 ) info.nativeFormats |= RTAUDIO_SINT16;
5561     if ( inCaps.dwFormats & WAVE_FORMAT_96M16 ) info.nativeFormats |= RTAUDIO_SINT16;
5562     if ( inCaps.dwFormats & WAVE_FORMAT_1M08 ) info.nativeFormats |= RTAUDIO_SINT8;
5563     if ( inCaps.dwFormats & WAVE_FORMAT_2M08 ) info.nativeFormats |= RTAUDIO_SINT8;
5564     if ( inCaps.dwFormats & WAVE_FORMAT_4M08 ) info.nativeFormats |= RTAUDIO_SINT8;
5565     if ( inCaps.dwFormats & WAVE_FORMAT_96M08 ) info.nativeFormats |= RTAUDIO_SINT8;
5566
5567     if ( info.nativeFormats & RTAUDIO_SINT16 ) {
5568       if ( inCaps.dwFormats & WAVE_FORMAT_1M16 ) rates.push_back( 11025 );
5569       if ( inCaps.dwFormats & WAVE_FORMAT_2M16 ) rates.push_back( 22050 );
5570       if ( inCaps.dwFormats & WAVE_FORMAT_4M16 ) rates.push_back( 44100 );
5571       if ( inCaps.dwFormats & WAVE_FORMAT_96M16 ) rates.push_back( 96000 );
5572     }
5573     else if ( info.nativeFormats & RTAUDIO_SINT8 ) {
5574       if ( inCaps.dwFormats & WAVE_FORMAT_1M08 ) rates.push_back( 11025 );
5575       if ( inCaps.dwFormats & WAVE_FORMAT_2M08 ) rates.push_back( 22050 );
5576       if ( inCaps.dwFormats & WAVE_FORMAT_4M08 ) rates.push_back( 44100 );
5577       if ( inCaps.dwFormats & WAVE_FORMAT_96M08 ) rates.push_back( 96000 );
5578     }
5579   }
5580   else info.inputChannels = 0; // technically, this would be an error
5581
5582   input->Release();
5583
5584   if ( info.inputChannels == 0 ) return info;
5585
5586   // Copy the supported rates to the info structure but avoid duplication.
5587   bool found;
5588   for ( unsigned int i=0; i<rates.size(); i++ ) {
5589     found = false;
5590     for ( unsigned int j=0; j<info.sampleRates.size(); j++ ) {
5591       if ( rates[i] == info.sampleRates[j] ) {
5592         found = true;
5593         break;
5594       }
5595     }
5596     if ( found == false ) info.sampleRates.push_back( rates[i] );
5597   }
5598   std::sort( info.sampleRates.begin(), info.sampleRates.end() );
5599
5600   // If device opens for both playback and capture, we determine the channels.
5601   if ( info.outputChannels > 0 && info.inputChannels > 0 )
5602     info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
5603
5604   if ( device == 0 ) info.isDefaultInput = true;
5605
5606   // Copy name and return.
5607   info.name = dsDevices[ device ].name;
5608   info.probed = true;
5609   return info;
5610 }
5611
5612 bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
5613                                  unsigned int firstChannel, unsigned int sampleRate,
5614                                  RtAudioFormat format, unsigned int *bufferSize,
5615                                  RtAudio::StreamOptions *options )
5616 {
5617   if ( channels + firstChannel > 2 ) {
5618     errorText_ = "RtApiDs::probeDeviceOpen: DirectSound does not support more than 2 channels per device.";
5619     return FAILURE;
5620   }
5621
5622   size_t nDevices = dsDevices.size();
5623   if ( nDevices == 0 ) {
5624     // This should not happen because a check is made before this function is called.
5625     errorText_ = "RtApiDs::probeDeviceOpen: no devices found!";
5626     return FAILURE;
5627   }
5628
5629   if ( device >= nDevices ) {
5630     // This should not happen because a check is made before this function is called.
5631     errorText_ = "RtApiDs::probeDeviceOpen: device ID is invalid!";
5632     return FAILURE;
5633   }
5634
5635   if ( mode == OUTPUT ) {
5636     if ( dsDevices[ device ].validId[0] == false ) {
5637       errorStream_ << "RtApiDs::probeDeviceOpen: device (" << device << ") does not support output!";
5638       errorText_ = errorStream_.str();
5639       return FAILURE;
5640     }
5641   }
5642   else { // mode == INPUT
5643     if ( dsDevices[ device ].validId[1] == false ) {
5644       errorStream_ << "RtApiDs::probeDeviceOpen: device (" << device << ") does not support input!";
5645       errorText_ = errorStream_.str();
5646       return FAILURE;
5647     }
5648   }
5649
5650   // According to a note in PortAudio, using GetDesktopWindow()
5651   // instead of GetForegroundWindow() is supposed to avoid problems
5652   // that occur when the application's window is not the foreground
5653   // window.  Also, if the application window closes before the
5654   // DirectSound buffer, DirectSound can crash.  In the past, I had
5655   // problems when using GetDesktopWindow() but it seems fine now
5656   // (January 2010).  I'll leave it commented here.
5657   // HWND hWnd = GetForegroundWindow();
5658   HWND hWnd = GetDesktopWindow();
5659
5660   // Check the numberOfBuffers parameter and limit the lowest value to
5661   // two.  This is a judgement call and a value of two is probably too
5662   // low for capture, but it should work for playback.
5663   int nBuffers = 0;
5664   if ( options ) nBuffers = options->numberOfBuffers;
5665   if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) nBuffers = 2;
5666   if ( nBuffers < 2 ) nBuffers = 3;
5667
5668   // Check the lower range of the user-specified buffer size and set
5669   // (arbitrarily) to a lower bound of 32.
5670   if ( *bufferSize < 32 ) *bufferSize = 32;
5671
5672   // Create the wave format structure.  The data format setting will
5673   // be determined later.
5674   WAVEFORMATEX waveFormat;
5675   ZeroMemory( &waveFormat, sizeof(WAVEFORMATEX) );
5676   waveFormat.wFormatTag = WAVE_FORMAT_PCM;
5677   waveFormat.nChannels = channels + firstChannel;
5678   waveFormat.nSamplesPerSec = (unsigned long) sampleRate;
5679
5680   // Determine the device buffer size. By default, we'll use the value
5681   // defined above (32K), but we will grow it to make allowances for
5682   // very large software buffer sizes.
5683   DWORD dsBufferSize = MINIMUM_DEVICE_BUFFER_SIZE;
5684   DWORD dsPointerLeadTime = 0;
5685
5686   void *ohandle = 0, *bhandle = 0;
5687   HRESULT result;
5688   if ( mode == OUTPUT ) {
5689
5690     LPDIRECTSOUND output;
5691     result = DirectSoundCreate( dsDevices[ device ].id[0], &output, NULL );
5692     if ( FAILED( result ) ) {
5693       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!";
5694       errorText_ = errorStream_.str();
5695       return FAILURE;
5696     }
5697
5698     DSCAPS outCaps;
5699     outCaps.dwSize = sizeof( outCaps );
5700     result = output->GetCaps( &outCaps );
5701     if ( FAILED( result ) ) {
5702       output->Release();
5703       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting capabilities (" << dsDevices[ device ].name << ")!";
5704       errorText_ = errorStream_.str();
5705       return FAILURE;
5706     }
5707
5708     // Check channel information.
5709     if ( channels + firstChannel == 2 && !( outCaps.dwFlags & DSCAPS_PRIMARYSTEREO ) ) {
5710       errorStream_ << "RtApiDs::getDeviceInfo: the output device (" << dsDevices[ device ].name << ") does not support stereo playback.";
5711       errorText_ = errorStream_.str();
5712       return FAILURE;
5713     }
5714
5715     // Check format information.  Use 16-bit format unless not
5716     // supported or user requests 8-bit.
5717     if ( outCaps.dwFlags & DSCAPS_PRIMARY16BIT &&
5718          !( format == RTAUDIO_SINT8 && outCaps.dwFlags & DSCAPS_PRIMARY8BIT ) ) {
5719       waveFormat.wBitsPerSample = 16;
5720       stream_.deviceFormat[mode] = RTAUDIO_SINT16;
5721     }
5722     else {
5723       waveFormat.wBitsPerSample = 8;
5724       stream_.deviceFormat[mode] = RTAUDIO_SINT8;
5725     }
5726     stream_.userFormat = format;
5727
5728     // Update wave format structure and buffer information.
5729     waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
5730     waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
5731     dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels;
5732
5733     // If the user wants an even bigger buffer, increase the device buffer size accordingly.
5734     while ( dsPointerLeadTime * 2U > dsBufferSize )
5735       dsBufferSize *= 2;
5736
5737     // Set cooperative level to DSSCL_EXCLUSIVE ... sound stops when window focus changes.
5738     // result = output->SetCooperativeLevel( hWnd, DSSCL_EXCLUSIVE );
5739     // Set cooperative level to DSSCL_PRIORITY ... sound remains when window focus changes.
5740     result = output->SetCooperativeLevel( hWnd, DSSCL_PRIORITY );
5741     if ( FAILED( result ) ) {
5742       output->Release();
5743       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting cooperative level (" << dsDevices[ device ].name << ")!";
5744       errorText_ = errorStream_.str();
5745       return FAILURE;
5746     }
5747
5748     // Even though we will write to the secondary buffer, we need to
5749     // access the primary buffer to set the correct output format
5750     // (since the default is 8-bit, 22 kHz!).  Setup the DS primary
5751     // buffer description.
5752     DSBUFFERDESC bufferDescription;
5753     ZeroMemory( &bufferDescription, sizeof( DSBUFFERDESC ) );
5754     bufferDescription.dwSize = sizeof( DSBUFFERDESC );
5755     bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
5756
5757     // Obtain the primary buffer
5758     LPDIRECTSOUNDBUFFER buffer;
5759     result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );
5760     if ( FAILED( result ) ) {
5761       output->Release();
5762       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") accessing primary buffer (" << dsDevices[ device ].name << ")!";
5763       errorText_ = errorStream_.str();
5764       return FAILURE;
5765     }
5766
5767     // Set the primary DS buffer sound format.
5768     result = buffer->SetFormat( &waveFormat );
5769     if ( FAILED( result ) ) {
5770       output->Release();
5771       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting primary buffer format (" << dsDevices[ device ].name << ")!";
5772       errorText_ = errorStream_.str();
5773       return FAILURE;
5774     }
5775
5776     // Setup the secondary DS buffer description.
5777     ZeroMemory( &bufferDescription, sizeof( DSBUFFERDESC ) );
5778     bufferDescription.dwSize = sizeof( DSBUFFERDESC );
5779     bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
5780                                   DSBCAPS_GLOBALFOCUS |
5781                                   DSBCAPS_GETCURRENTPOSITION2 |
5782                                   DSBCAPS_LOCHARDWARE );  // Force hardware mixing
5783     bufferDescription.dwBufferBytes = dsBufferSize;
5784     bufferDescription.lpwfxFormat = &waveFormat;
5785
5786     // Try to create the secondary DS buffer.  If that doesn't work,
5787     // try to use software mixing.  Otherwise, there's a problem.
5788     result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );
5789     if ( FAILED( result ) ) {
5790       bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
5791                                     DSBCAPS_GLOBALFOCUS |
5792                                     DSBCAPS_GETCURRENTPOSITION2 |
5793                                     DSBCAPS_LOCSOFTWARE );  // Force software mixing
5794       result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );
5795       if ( FAILED( result ) ) {
5796         output->Release();
5797         errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating secondary buffer (" << dsDevices[ device ].name << ")!";
5798         errorText_ = errorStream_.str();
5799         return FAILURE;
5800       }
5801     }
5802
5803     // Get the buffer size ... might be different from what we specified.
5804     DSBCAPS dsbcaps;
5805     dsbcaps.dwSize = sizeof( DSBCAPS );
5806     result = buffer->GetCaps( &dsbcaps );
5807     if ( FAILED( result ) ) {
5808       output->Release();
5809       buffer->Release();
5810       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsDevices[ device ].name << ")!";
5811       errorText_ = errorStream_.str();
5812       return FAILURE;
5813     }
5814
5815     dsBufferSize = dsbcaps.dwBufferBytes;
5816
5817     // Lock the DS buffer
5818     LPVOID audioPtr;
5819     DWORD dataLen;
5820     result = buffer->Lock( 0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0 );
5821     if ( FAILED( result ) ) {
5822       output->Release();
5823       buffer->Release();
5824       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") locking buffer (" << dsDevices[ device ].name << ")!";
5825       errorText_ = errorStream_.str();
5826       return FAILURE;
5827     }
5828
5829     // Zero the DS buffer
5830     ZeroMemory( audioPtr, dataLen );
5831
5832     // Unlock the DS buffer
5833     result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );
5834     if ( FAILED( result ) ) {
5835       output->Release();
5836       buffer->Release();
5837       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking buffer (" << dsDevices[ device ].name << ")!";
5838       errorText_ = errorStream_.str();
5839       return FAILURE;
5840     }
5841
5842     ohandle = (void *) output;
5843     bhandle = (void *) buffer;
5844   }
5845
5846   if ( mode == INPUT ) {
5847
5848     LPDIRECTSOUNDCAPTURE input;
5849     result = DirectSoundCaptureCreate( dsDevices[ device ].id[1], &input, NULL );
5850     if ( FAILED( result ) ) {
5851       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!";
5852       errorText_ = errorStream_.str();
5853       return FAILURE;
5854     }
5855
5856     DSCCAPS inCaps;
5857     inCaps.dwSize = sizeof( inCaps );
5858     result = input->GetCaps( &inCaps );
5859     if ( FAILED( result ) ) {
5860       input->Release();
5861       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting input capabilities (" << dsDevices[ device ].name << ")!";
5862       errorText_ = errorStream_.str();
5863       return FAILURE;
5864     }
5865
5866     // Check channel information.
5867     if ( inCaps.dwChannels < channels + firstChannel ) {
5868       errorText_ = "RtApiDs::getDeviceInfo: the input device does not support requested input channels.";
5869       return FAILURE;
5870     }
5871
5872     // Check format information.  Use 16-bit format unless user
5873     // requests 8-bit.
5874     DWORD deviceFormats;
5875     if ( channels + firstChannel == 2 ) {
5876       deviceFormats = WAVE_FORMAT_1S08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_96S08;
5877       if ( format == RTAUDIO_SINT8 && inCaps.dwFormats & deviceFormats ) {
5878         waveFormat.wBitsPerSample = 8;
5879         stream_.deviceFormat[mode] = RTAUDIO_SINT8;
5880       }
5881       else { // assume 16-bit is supported
5882         waveFormat.wBitsPerSample = 16;
5883         stream_.deviceFormat[mode] = RTAUDIO_SINT16;
5884       }
5885     }
5886     else { // channel == 1
5887       deviceFormats = WAVE_FORMAT_1M08 | WAVE_FORMAT_2M08 | WAVE_FORMAT_4M08 | WAVE_FORMAT_96M08;
5888       if ( format == RTAUDIO_SINT8 && inCaps.dwFormats & deviceFormats ) {
5889         waveFormat.wBitsPerSample = 8;
5890         stream_.deviceFormat[mode] = RTAUDIO_SINT8;
5891       }
5892       else { // assume 16-bit is supported
5893         waveFormat.wBitsPerSample = 16;
5894         stream_.deviceFormat[mode] = RTAUDIO_SINT16;
5895       }
5896     }
5897     stream_.userFormat = format;
5898
5899     // Update wave format structure and buffer information.
5900     waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
5901     waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
5902     dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels;
5903
5904     // If the user wants an even bigger buffer, increase the device buffer size accordingly.
5905     while ( dsPointerLeadTime * 2U > dsBufferSize )
5906       dsBufferSize *= 2;
5907
5908     // Setup the secondary DS buffer description.
5909     DSCBUFFERDESC bufferDescription;
5910     ZeroMemory( &bufferDescription, sizeof( DSCBUFFERDESC ) );
5911     bufferDescription.dwSize = sizeof( DSCBUFFERDESC );
5912     bufferDescription.dwFlags = 0;
5913     bufferDescription.dwReserved = 0;
5914     bufferDescription.dwBufferBytes = dsBufferSize;
5915     bufferDescription.lpwfxFormat = &waveFormat;
5916
5917     // Create the capture buffer.
5918     LPDIRECTSOUNDCAPTUREBUFFER buffer;
5919     result = input->CreateCaptureBuffer( &bufferDescription, &buffer, NULL );
5920     if ( FAILED( result ) ) {
5921       input->Release();
5922       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating input buffer (" << dsDevices[ device ].name << ")!";
5923       errorText_ = errorStream_.str();
5924       return FAILURE;
5925     }
5926
5927     // Get the buffer size ... might be different from what we specified.
5928     DSCBCAPS dscbcaps;
5929     dscbcaps.dwSize = sizeof( DSCBCAPS );
5930     result = buffer->GetCaps( &dscbcaps );
5931     if ( FAILED( result ) ) {
5932       input->Release();
5933       buffer->Release();
5934       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsDevices[ device ].name << ")!";
5935       errorText_ = errorStream_.str();
5936       return FAILURE;
5937     }
5938
5939     dsBufferSize = dscbcaps.dwBufferBytes;
5940
5941     // NOTE: We could have a problem here if this is a duplex stream
5942     // and the play and capture hardware buffer sizes are different
5943     // (I'm actually not sure if that is a problem or not).
5944     // Currently, we are not verifying that.
5945
5946     // Lock the capture buffer
5947     LPVOID audioPtr;
5948     DWORD dataLen;
5949     result = buffer->Lock( 0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0 );
5950     if ( FAILED( result ) ) {
5951       input->Release();
5952       buffer->Release();
5953       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") locking input buffer (" << dsDevices[ device ].name << ")!";
5954       errorText_ = errorStream_.str();
5955       return FAILURE;
5956     }
5957
5958     // Zero the buffer
5959     ZeroMemory( audioPtr, dataLen );
5960
5961     // Unlock the buffer
5962     result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );
5963     if ( FAILED( result ) ) {
5964       input->Release();
5965       buffer->Release();
5966       errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking input buffer (" << dsDevices[ device ].name << ")!";
5967       errorText_ = errorStream_.str();
5968       return FAILURE;
5969     }
5970
5971     ohandle = (void *) input;
5972     bhandle = (void *) buffer;
5973   }
5974
5975   // Set various stream parameters
5976   DsHandle *handle = 0;
5977   stream_.nDeviceChannels[mode] = channels + firstChannel;
5978   stream_.nUserChannels[mode] = channels;
5979   stream_.bufferSize = *bufferSize;
5980   stream_.channelOffset[mode] = firstChannel;
5981   stream_.deviceInterleaved[mode] = true;
5982   if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;
5983   else stream_.userInterleaved = true;
5984
5985   // Set flag for buffer conversion
5986   stream_.doConvertBuffer[mode] = false;
5987   if (stream_.nUserChannels[mode] != stream_.nDeviceChannels[mode])
5988     stream_.doConvertBuffer[mode] = true;
5989   if (stream_.userFormat != stream_.deviceFormat[mode])
5990     stream_.doConvertBuffer[mode] = true;
5991   if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
5992        stream_.nUserChannels[mode] > 1 )
5993     stream_.doConvertBuffer[mode] = true;
5994
5995   // Allocate necessary internal buffers
5996   long bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
5997   stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
5998   if ( stream_.userBuffer[mode] == NULL ) {
5999     errorText_ = "RtApiDs::probeDeviceOpen: error allocating user buffer memory.";
6000     goto error;
6001   }
6002
6003   if ( stream_.doConvertBuffer[mode] ) {
6004
6005     bool makeBuffer = true;
6006     bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
6007     if ( mode == INPUT ) {
6008       if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
6009         unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
6010         if ( bufferBytes <= (long) bytesOut ) makeBuffer = false;
6011       }
6012     }
6013
6014     if ( makeBuffer ) {
6015       bufferBytes *= *bufferSize;
6016       if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
6017       stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
6018       if ( stream_.deviceBuffer == NULL ) {
6019         errorText_ = "RtApiDs::probeDeviceOpen: error allocating device buffer memory.";
6020         goto error;
6021       }
6022     }
6023   }
6024
6025   // Allocate our DsHandle structures for the stream.
6026   if ( stream_.apiHandle == 0 ) {
6027     try {
6028       handle = new DsHandle;
6029     }
6030     catch ( std::bad_alloc& ) {
6031       errorText_ = "RtApiDs::probeDeviceOpen: error allocating AsioHandle memory.";
6032       goto error;
6033     }
6034
6035     // Create a manual-reset event.
6036     handle->condition = CreateEvent( NULL,   // no security
6037                                      TRUE,   // manual-reset
6038                                      FALSE,  // non-signaled initially
6039                                      NULL ); // unnamed
6040     stream_.apiHandle = (void *) handle;
6041   }
6042   else
6043     handle = (DsHandle *) stream_.apiHandle;
6044   handle->id[mode] = ohandle;
6045   handle->buffer[mode] = bhandle;
6046   handle->dsBufferSize[mode] = dsBufferSize;
6047   handle->dsPointerLeadTime[mode] = dsPointerLeadTime;
6048
6049   stream_.device[mode] = device;
6050   stream_.state = STREAM_STOPPED;
6051   if ( stream_.mode == OUTPUT && mode == INPUT )
6052     // We had already set up an output stream.
6053     stream_.mode = DUPLEX;
6054   else
6055     stream_.mode = mode;
6056   stream_.nBuffers = nBuffers;
6057   stream_.sampleRate = sampleRate;
6058
6059   // Setup the buffer conversion information structure.
6060   if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );
6061
6062   // Setup the callback thread.
6063   if ( stream_.callbackInfo.isRunning == false ) {
6064     unsigned threadId;
6065     stream_.callbackInfo.isRunning = true;
6066     stream_.callbackInfo.object = (void *) this;
6067     stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &callbackHandler,
6068                                                   &stream_.callbackInfo, 0, &threadId );
6069     if ( stream_.callbackInfo.thread == 0 ) {
6070       errorText_ = "RtApiDs::probeDeviceOpen: error creating callback thread!";
6071       goto error;
6072     }
6073
6074     // Boost DS thread priority
6075     SetThreadPriority( (HANDLE) stream_.callbackInfo.thread, THREAD_PRIORITY_HIGHEST );
6076   }
6077   return SUCCESS;
6078
6079  error:
6080   if ( handle ) {
6081     if ( handle->buffer[0] ) { // the object pointer can be NULL and valid
6082       LPDIRECTSOUND object = (LPDIRECTSOUND) handle->id[0];
6083       LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
6084       if ( buffer ) buffer->Release();
6085       object->Release();
6086     }
6087     if ( handle->buffer[1] ) {
6088       LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handle->id[1];
6089       LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
6090       if ( buffer ) buffer->Release();
6091       object->Release();
6092     }
6093     CloseHandle( handle->condition );
6094     delete handle;
6095     stream_.apiHandle = 0;
6096   }
6097
6098   for ( int i=0; i<2; i++ ) {
6099     if ( stream_.userBuffer[i] ) {
6100       free( stream_.userBuffer[i] );
6101       stream_.userBuffer[i] = 0;
6102     }
6103   }
6104
6105   if ( stream_.deviceBuffer ) {
6106     free( stream_.deviceBuffer );
6107     stream_.deviceBuffer = 0;
6108   }
6109
6110   stream_.state = STREAM_CLOSED;
6111   return FAILURE;
6112 }
6113
6114 void RtApiDs :: closeStream()
6115 {
6116   if ( stream_.state == STREAM_CLOSED ) {
6117     errorText_ = "RtApiDs::closeStream(): no open stream to close!";
6118     error( RtAudioError::WARNING );
6119     return;
6120   }
6121
6122   // Stop the callback thread.
6123   stream_.callbackInfo.isRunning = false;
6124   WaitForSingleObject( (HANDLE) stream_.callbackInfo.thread, INFINITE );
6125   CloseHandle( (HANDLE) stream_.callbackInfo.thread );
6126
6127   DsHandle *handle = (DsHandle *) stream_.apiHandle;
6128   if ( handle ) {
6129     if ( handle->buffer[0] ) { // the object pointer can be NULL and valid
6130       LPDIRECTSOUND object = (LPDIRECTSOUND) handle->id[0];
6131       LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
6132       if ( buffer ) {
6133         buffer->Stop();
6134         buffer->Release();
6135       }
6136       object->Release();
6137     }
6138     if ( handle->buffer[1] ) {
6139       LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handle->id[1];
6140       LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
6141       if ( buffer ) {
6142         buffer->Stop();
6143         buffer->Release();
6144       }
6145       object->Release();
6146     }
6147     CloseHandle( handle->condition );
6148     delete handle;
6149     stream_.apiHandle = 0;
6150   }
6151
6152   for ( int i=0; i<2; i++ ) {
6153     if ( stream_.userBuffer[i] ) {
6154       free( stream_.userBuffer[i] );
6155       stream_.userBuffer[i] = 0;
6156     }
6157   }
6158
6159   if ( stream_.deviceBuffer ) {
6160     free( stream_.deviceBuffer );
6161     stream_.deviceBuffer = 0;
6162   }
6163
6164   stream_.mode = UNINITIALIZED;
6165   stream_.state = STREAM_CLOSED;
6166 }
6167
6168 void RtApiDs :: startStream()
6169 {
6170   verifyStream();
6171   if ( stream_.state == STREAM_RUNNING ) {
6172     errorText_ = "RtApiDs::startStream(): the stream is already running!";
6173     error( RtAudioError::WARNING );
6174     return;
6175   }
6176
6177   DsHandle *handle = (DsHandle *) stream_.apiHandle;
6178
6179   // Increase scheduler frequency on lesser windows (a side-effect of
6180   // increasing timer accuracy).  On greater windows (Win2K or later),
6181   // this is already in effect.
6182   timeBeginPeriod( 1 ); 
6183
6184   buffersRolling = false;
6185   duplexPrerollBytes = 0;
6186
6187   if ( stream_.mode == DUPLEX ) {
6188     // 0.5 seconds of silence in DUPLEX mode while the devices spin up and synchronize.
6189     duplexPrerollBytes = (int) ( 0.5 * stream_.sampleRate * formatBytes( stream_.deviceFormat[1] ) * stream_.nDeviceChannels[1] );
6190   }
6191
6192   HRESULT result = 0;
6193   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
6194
6195     LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
6196     result = buffer->Play( 0, 0, DSBPLAY_LOOPING );
6197     if ( FAILED( result ) ) {
6198       errorStream_ << "RtApiDs::startStream: error (" << getErrorString( result ) << ") starting output buffer!";
6199       errorText_ = errorStream_.str();
6200       goto unlock;
6201     }
6202   }
6203
6204   if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
6205
6206     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
6207     result = buffer->Start( DSCBSTART_LOOPING );
6208     if ( FAILED( result ) ) {
6209       errorStream_ << "RtApiDs::startStream: error (" << getErrorString( result ) << ") starting input buffer!";
6210       errorText_ = errorStream_.str();
6211       goto unlock;
6212     }
6213   }
6214
6215   handle->drainCounter = 0;
6216   handle->internalDrain = false;
6217   ResetEvent( handle->condition );
6218   stream_.state = STREAM_RUNNING;
6219
6220  unlock:
6221   if ( FAILED( result ) ) error( RtAudioError::SYSTEM_ERROR );
6222 }
6223
6224 void RtApiDs :: stopStream()
6225 {
6226   verifyStream();
6227   if ( stream_.state == STREAM_STOPPED ) {
6228     errorText_ = "RtApiDs::stopStream(): the stream is already stopped!";
6229     error( RtAudioError::WARNING );
6230     return;
6231   }
6232
6233   HRESULT result = 0;
6234   LPVOID audioPtr;
6235   DWORD dataLen;
6236   DsHandle *handle = (DsHandle *) stream_.apiHandle;
6237   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
6238     if ( handle->drainCounter == 0 ) {
6239       handle->drainCounter = 2;
6240       WaitForSingleObject( handle->condition, INFINITE );  // block until signaled
6241     }
6242
6243     stream_.state = STREAM_STOPPED;
6244
6245     MUTEX_LOCK( &stream_.mutex );
6246
6247     // Stop the buffer and clear memory
6248     LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
6249     result = buffer->Stop();
6250     if ( FAILED( result ) ) {
6251       errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") stopping output buffer!";
6252       errorText_ = errorStream_.str();
6253       goto unlock;
6254     }
6255
6256     // Lock the buffer and clear it so that if we start to play again,
6257     // we won't have old data playing.
6258     result = buffer->Lock( 0, handle->dsBufferSize[0], &audioPtr, &dataLen, NULL, NULL, 0 );
6259     if ( FAILED( result ) ) {
6260       errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") locking output buffer!";
6261       errorText_ = errorStream_.str();
6262       goto unlock;
6263     }
6264
6265     // Zero the DS buffer
6266     ZeroMemory( audioPtr, dataLen );
6267
6268     // Unlock the DS buffer
6269     result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );
6270     if ( FAILED( result ) ) {
6271       errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") unlocking output buffer!";
6272       errorText_ = errorStream_.str();
6273       goto unlock;
6274     }
6275
6276     // If we start playing again, we must begin at beginning of buffer.
6277     handle->bufferPointer[0] = 0;
6278   }
6279
6280   if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
6281     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
6282     audioPtr = NULL;
6283     dataLen = 0;
6284
6285     stream_.state = STREAM_STOPPED;
6286
6287     if ( stream_.mode != DUPLEX )
6288       MUTEX_LOCK( &stream_.mutex );
6289
6290     result = buffer->Stop();
6291     if ( FAILED( result ) ) {
6292       errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") stopping input buffer!";
6293       errorText_ = errorStream_.str();
6294       goto unlock;
6295     }
6296
6297     // Lock the buffer and clear it so that if we start to play again,
6298     // we won't have old data playing.
6299     result = buffer->Lock( 0, handle->dsBufferSize[1], &audioPtr, &dataLen, NULL, NULL, 0 );
6300     if ( FAILED( result ) ) {
6301       errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") locking input buffer!";
6302       errorText_ = errorStream_.str();
6303       goto unlock;
6304     }
6305
6306     // Zero the DS buffer
6307     ZeroMemory( audioPtr, dataLen );
6308
6309     // Unlock the DS buffer
6310     result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );
6311     if ( FAILED( result ) ) {
6312       errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") unlocking input buffer!";
6313       errorText_ = errorStream_.str();
6314       goto unlock;
6315     }
6316
6317     // If we start recording again, we must begin at beginning of buffer.
6318     handle->bufferPointer[1] = 0;
6319   }
6320
6321  unlock:
6322   timeEndPeriod( 1 ); // revert to normal scheduler frequency on lesser windows.
6323   MUTEX_UNLOCK( &stream_.mutex );
6324
6325   if ( FAILED( result ) ) error( RtAudioError::SYSTEM_ERROR );
6326 }
6327
6328 void RtApiDs :: abortStream()
6329 {
6330   verifyStream();
6331   if ( stream_.state == STREAM_STOPPED ) {
6332     errorText_ = "RtApiDs::abortStream(): the stream is already stopped!";
6333     error( RtAudioError::WARNING );
6334     return;
6335   }
6336
6337   DsHandle *handle = (DsHandle *) stream_.apiHandle;
6338   handle->drainCounter = 2;
6339
6340   stopStream();
6341 }
6342
6343 void RtApiDs :: callbackEvent()
6344 {
6345   if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) {
6346     Sleep( 50 ); // sleep 50 milliseconds
6347     return;
6348   }
6349
6350   if ( stream_.state == STREAM_CLOSED ) {
6351     errorText_ = "RtApiDs::callbackEvent(): the stream is closed ... this shouldn't happen!";
6352     error( RtAudioError::WARNING );
6353     return;
6354   }
6355
6356   CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
6357   DsHandle *handle = (DsHandle *) stream_.apiHandle;
6358
6359   // Check if we were draining the stream and signal is finished.
6360   if ( handle->drainCounter > stream_.nBuffers + 2 ) {
6361
6362     stream_.state = STREAM_STOPPING;
6363     if ( handle->internalDrain == false )
6364       SetEvent( handle->condition );
6365     else
6366       stopStream();
6367     return;
6368   }
6369
6370   // Invoke user callback to get fresh output data UNLESS we are
6371   // draining stream.
6372   if ( handle->drainCounter == 0 ) {
6373     RtAudioCallback callback = (RtAudioCallback) info->callback;
6374     double streamTime = getStreamTime();
6375     RtAudioStreamStatus status = 0;
6376     if ( stream_.mode != INPUT && handle->xrun[0] == true ) {
6377       status |= RTAUDIO_OUTPUT_UNDERFLOW;
6378       handle->xrun[0] = false;
6379     }
6380     if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {
6381       status |= RTAUDIO_INPUT_OVERFLOW;
6382       handle->xrun[1] = false;
6383     }
6384     int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],
6385                                   stream_.bufferSize, streamTime, status, info->userData );
6386     if ( cbReturnValue == 2 ) {
6387       stream_.state = STREAM_STOPPING;
6388       handle->drainCounter = 2;
6389       abortStream();
6390       return;
6391     }
6392     else if ( cbReturnValue == 1 ) {
6393       handle->drainCounter = 1;
6394       handle->internalDrain = true;
6395     }
6396   }
6397
6398   HRESULT result;
6399   DWORD currentWritePointer, safeWritePointer;
6400   DWORD currentReadPointer, safeReadPointer;
6401   UINT nextWritePointer;
6402
6403   LPVOID buffer1 = NULL;
6404   LPVOID buffer2 = NULL;
6405   DWORD bufferSize1 = 0;
6406   DWORD bufferSize2 = 0;
6407
6408   char *buffer;
6409   long bufferBytes;
6410
6411   MUTEX_LOCK( &stream_.mutex );
6412   if ( stream_.state == STREAM_STOPPED ) {
6413     MUTEX_UNLOCK( &stream_.mutex );
6414     return;
6415   }
6416
6417   if ( buffersRolling == false ) {
6418     if ( stream_.mode == DUPLEX ) {
6419       //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );
6420
6421       // It takes a while for the devices to get rolling. As a result,
6422       // there's no guarantee that the capture and write device pointers
6423       // will move in lockstep.  Wait here for both devices to start
6424       // rolling, and then set our buffer pointers accordingly.
6425       // e.g. Crystal Drivers: the capture buffer starts up 5700 to 9600
6426       // bytes later than the write buffer.
6427
6428       // Stub: a serious risk of having a pre-emptive scheduling round
6429       // take place between the two GetCurrentPosition calls... but I'm
6430       // really not sure how to solve the problem.  Temporarily boost to
6431       // Realtime priority, maybe; but I'm not sure what priority the
6432       // DirectSound service threads run at. We *should* be roughly
6433       // within a ms or so of correct.
6434
6435       LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
6436       LPDIRECTSOUNDCAPTUREBUFFER dsCaptureBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
6437
6438       DWORD startSafeWritePointer, startSafeReadPointer;
6439
6440       result = dsWriteBuffer->GetCurrentPosition( NULL, &startSafeWritePointer );
6441       if ( FAILED( result ) ) {
6442         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
6443         errorText_ = errorStream_.str();
6444         MUTEX_UNLOCK( &stream_.mutex );
6445         error( RtAudioError::SYSTEM_ERROR );
6446         return;
6447       }
6448       result = dsCaptureBuffer->GetCurrentPosition( NULL, &startSafeReadPointer );
6449       if ( FAILED( result ) ) {
6450         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
6451         errorText_ = errorStream_.str();
6452         MUTEX_UNLOCK( &stream_.mutex );
6453         error( RtAudioError::SYSTEM_ERROR );
6454         return;
6455       }
6456       while ( true ) {
6457         result = dsWriteBuffer->GetCurrentPosition( NULL, &safeWritePointer );
6458         if ( FAILED( result ) ) {
6459           errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
6460           errorText_ = errorStream_.str();
6461           MUTEX_UNLOCK( &stream_.mutex );
6462           error( RtAudioError::SYSTEM_ERROR );
6463           return;
6464         }
6465         result = dsCaptureBuffer->GetCurrentPosition( NULL, &safeReadPointer );
6466         if ( FAILED( result ) ) {
6467           errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
6468           errorText_ = errorStream_.str();
6469           MUTEX_UNLOCK( &stream_.mutex );
6470           error( RtAudioError::SYSTEM_ERROR );
6471           return;
6472         }
6473         if ( safeWritePointer != startSafeWritePointer && safeReadPointer != startSafeReadPointer ) break;
6474         Sleep( 1 );
6475       }
6476
6477       //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );
6478
6479       handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0];
6480       if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0];
6481       handle->bufferPointer[1] = safeReadPointer;
6482     }
6483     else if ( stream_.mode == OUTPUT ) {
6484
6485       // Set the proper nextWritePosition after initial startup.
6486       LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
6487       result = dsWriteBuffer->GetCurrentPosition( &currentWritePointer, &safeWritePointer );
6488       if ( FAILED( result ) ) {
6489         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
6490         errorText_ = errorStream_.str();
6491         MUTEX_UNLOCK( &stream_.mutex );
6492         error( RtAudioError::SYSTEM_ERROR );
6493         return;
6494       }
6495       handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0];
6496       if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0];
6497     }
6498
6499     buffersRolling = true;
6500   }
6501
6502   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
6503     
6504     LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
6505
6506     if ( handle->drainCounter > 1 ) { // write zeros to the output stream
6507       bufferBytes = stream_.bufferSize * stream_.nUserChannels[0];
6508       bufferBytes *= formatBytes( stream_.userFormat );
6509       memset( stream_.userBuffer[0], 0, bufferBytes );
6510     }
6511
6512     // Setup parameters and do buffer conversion if necessary.
6513     if ( stream_.doConvertBuffer[0] ) {
6514       buffer = stream_.deviceBuffer;
6515       convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] );
6516       bufferBytes = stream_.bufferSize * stream_.nDeviceChannels[0];
6517       bufferBytes *= formatBytes( stream_.deviceFormat[0] );
6518     }
6519     else {
6520       buffer = stream_.userBuffer[0];
6521       bufferBytes = stream_.bufferSize * stream_.nUserChannels[0];
6522       bufferBytes *= formatBytes( stream_.userFormat );
6523     }
6524
6525     // No byte swapping necessary in DirectSound implementation.
6526
6527     // Ahhh ... windoze.  16-bit data is signed but 8-bit data is
6528     // unsigned.  So, we need to convert our signed 8-bit data here to
6529     // unsigned.
6530     if ( stream_.deviceFormat[0] == RTAUDIO_SINT8 )
6531       for ( int i=0; i<bufferBytes; i++ ) buffer[i] = (unsigned char) ( buffer[i] + 128 );
6532
6533     DWORD dsBufferSize = handle->dsBufferSize[0];
6534     nextWritePointer = handle->bufferPointer[0];
6535
6536     DWORD endWrite, leadPointer;
6537     while ( true ) {
6538       // Find out where the read and "safe write" pointers are.
6539       result = dsBuffer->GetCurrentPosition( &currentWritePointer, &safeWritePointer );
6540       if ( FAILED( result ) ) {
6541         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
6542         errorText_ = errorStream_.str();
6543         MUTEX_UNLOCK( &stream_.mutex );
6544         error( RtAudioError::SYSTEM_ERROR );
6545         return;
6546       }
6547
6548       // We will copy our output buffer into the region between
6549       // safeWritePointer and leadPointer.  If leadPointer is not
6550       // beyond the next endWrite position, wait until it is.
6551       leadPointer = safeWritePointer + handle->dsPointerLeadTime[0];
6552       //std::cout << "safeWritePointer = " << safeWritePointer << ", leadPointer = " << leadPointer << ", nextWritePointer = " << nextWritePointer << std::endl;
6553       if ( leadPointer > dsBufferSize ) leadPointer -= dsBufferSize;
6554       if ( leadPointer < nextWritePointer ) leadPointer += dsBufferSize; // unwrap offset
6555       endWrite = nextWritePointer + bufferBytes;
6556
6557       // Check whether the entire write region is behind the play pointer.
6558       if ( leadPointer >= endWrite ) break;
6559
6560       // If we are here, then we must wait until the leadPointer advances
6561       // beyond the end of our next write region. We use the
6562       // Sleep() function to suspend operation until that happens.
6563       double millis = ( endWrite - leadPointer ) * 1000.0;
6564       millis /= ( formatBytes( stream_.deviceFormat[0]) * stream_.nDeviceChannels[0] * stream_.sampleRate);
6565       if ( millis < 1.0 ) millis = 1.0;
6566       Sleep( (DWORD) millis );
6567     }
6568
6569     if ( dsPointerBetween( nextWritePointer, safeWritePointer, currentWritePointer, dsBufferSize )
6570          || dsPointerBetween( endWrite, safeWritePointer, currentWritePointer, dsBufferSize ) ) { 
6571       // We've strayed into the forbidden zone ... resync the read pointer.
6572       handle->xrun[0] = true;
6573       nextWritePointer = safeWritePointer + handle->dsPointerLeadTime[0] - bufferBytes;
6574       if ( nextWritePointer >= dsBufferSize ) nextWritePointer -= dsBufferSize;
6575       handle->bufferPointer[0] = nextWritePointer;
6576       endWrite = nextWritePointer + bufferBytes;
6577     }
6578
6579     // Lock free space in the buffer
6580     result = dsBuffer->Lock( nextWritePointer, bufferBytes, &buffer1,
6581                              &bufferSize1, &buffer2, &bufferSize2, 0 );
6582     if ( FAILED( result ) ) {
6583       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking buffer during playback!";
6584       errorText_ = errorStream_.str();
6585       MUTEX_UNLOCK( &stream_.mutex );
6586       error( RtAudioError::SYSTEM_ERROR );
6587       return;
6588     }
6589
6590     // Copy our buffer into the DS buffer
6591     CopyMemory( buffer1, buffer, bufferSize1 );
6592     if ( buffer2 != NULL ) CopyMemory( buffer2, buffer+bufferSize1, bufferSize2 );
6593
6594     // Update our buffer offset and unlock sound buffer
6595     dsBuffer->Unlock( buffer1, bufferSize1, buffer2, bufferSize2 );
6596     if ( FAILED( result ) ) {
6597       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!";
6598       errorText_ = errorStream_.str();
6599       MUTEX_UNLOCK( &stream_.mutex );
6600       error( RtAudioError::SYSTEM_ERROR );
6601       return;
6602     }
6603     nextWritePointer = ( nextWritePointer + bufferSize1 + bufferSize2 ) % dsBufferSize;
6604     handle->bufferPointer[0] = nextWritePointer;
6605   }
6606
6607   // Don't bother draining input
6608   if ( handle->drainCounter ) {
6609     handle->drainCounter++;
6610     goto unlock;
6611   }
6612
6613   if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
6614
6615     // Setup parameters.
6616     if ( stream_.doConvertBuffer[1] ) {
6617       buffer = stream_.deviceBuffer;
6618       bufferBytes = stream_.bufferSize * stream_.nDeviceChannels[1];
6619       bufferBytes *= formatBytes( stream_.deviceFormat[1] );
6620     }
6621     else {
6622       buffer = stream_.userBuffer[1];
6623       bufferBytes = stream_.bufferSize * stream_.nUserChannels[1];
6624       bufferBytes *= formatBytes( stream_.userFormat );
6625     }
6626
6627     LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
6628     long nextReadPointer = handle->bufferPointer[1];
6629     DWORD dsBufferSize = handle->dsBufferSize[1];
6630
6631     // Find out where the write and "safe read" pointers are.
6632     result = dsBuffer->GetCurrentPosition( &currentReadPointer, &safeReadPointer );
6633     if ( FAILED( result ) ) {
6634       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
6635       errorText_ = errorStream_.str();
6636       MUTEX_UNLOCK( &stream_.mutex );
6637       error( RtAudioError::SYSTEM_ERROR );
6638       return;
6639     }
6640
6641     if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset
6642     DWORD endRead = nextReadPointer + bufferBytes;
6643
6644     // Handling depends on whether we are INPUT or DUPLEX. 
6645     // If we're in INPUT mode then waiting is a good thing. If we're in DUPLEX mode,
6646     // then a wait here will drag the write pointers into the forbidden zone.
6647     // 
6648     // In DUPLEX mode, rather than wait, we will back off the read pointer until 
6649     // it's in a safe position. This causes dropouts, but it seems to be the only 
6650     // practical way to sync up the read and write pointers reliably, given the 
6651     // the very complex relationship between phase and increment of the read and write 
6652     // pointers.
6653     //
6654     // In order to minimize audible dropouts in DUPLEX mode, we will
6655     // provide a pre-roll period of 0.5 seconds in which we return
6656     // zeros from the read buffer while the pointers sync up.
6657
6658     if ( stream_.mode == DUPLEX ) {
6659       if ( safeReadPointer < endRead ) {
6660         if ( duplexPrerollBytes <= 0 ) {
6661           // Pre-roll time over. Be more agressive.
6662           int adjustment = endRead-safeReadPointer;
6663
6664           handle->xrun[1] = true;
6665           // Two cases:
6666           //   - large adjustments: we've probably run out of CPU cycles, so just resync exactly,
6667           //     and perform fine adjustments later.
6668           //   - small adjustments: back off by twice as much.
6669           if ( adjustment >= 2*bufferBytes )
6670             nextReadPointer = safeReadPointer-2*bufferBytes;
6671           else
6672             nextReadPointer = safeReadPointer-bufferBytes-adjustment;
6673
6674           if ( nextReadPointer < 0 ) nextReadPointer += dsBufferSize;
6675
6676         }
6677         else {
6678           // In pre=roll time. Just do it.
6679           nextReadPointer = safeReadPointer - bufferBytes;
6680           while ( nextReadPointer < 0 ) nextReadPointer += dsBufferSize;
6681         }
6682         endRead = nextReadPointer + bufferBytes;
6683       }
6684     }
6685     else { // mode == INPUT
6686       while ( safeReadPointer < endRead && stream_.callbackInfo.isRunning ) {
6687         // See comments for playback.
6688         double millis = (endRead - safeReadPointer) * 1000.0;
6689         millis /= ( formatBytes(stream_.deviceFormat[1]) * stream_.nDeviceChannels[1] * stream_.sampleRate);
6690         if ( millis < 1.0 ) millis = 1.0;
6691         Sleep( (DWORD) millis );
6692
6693         // Wake up and find out where we are now.
6694         result = dsBuffer->GetCurrentPosition( &currentReadPointer, &safeReadPointer );
6695         if ( FAILED( result ) ) {
6696           errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
6697           errorText_ = errorStream_.str();
6698           MUTEX_UNLOCK( &stream_.mutex );
6699           error( RtAudioError::SYSTEM_ERROR );
6700           return;
6701         }
6702       
6703         if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset
6704       }
6705     }
6706
6707     // Lock free space in the buffer
6708     result = dsBuffer->Lock( nextReadPointer, bufferBytes, &buffer1,
6709                              &bufferSize1, &buffer2, &bufferSize2, 0 );
6710     if ( FAILED( result ) ) {
6711       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking capture buffer!";
6712       errorText_ = errorStream_.str();
6713       MUTEX_UNLOCK( &stream_.mutex );
6714       error( RtAudioError::SYSTEM_ERROR );
6715       return;
6716     }
6717
6718     if ( duplexPrerollBytes <= 0 ) {
6719       // Copy our buffer into the DS buffer
6720       CopyMemory( buffer, buffer1, bufferSize1 );
6721       if ( buffer2 != NULL ) CopyMemory( buffer+bufferSize1, buffer2, bufferSize2 );
6722     }
6723     else {
6724       memset( buffer, 0, bufferSize1 );
6725       if ( buffer2 != NULL ) memset( buffer + bufferSize1, 0, bufferSize2 );
6726       duplexPrerollBytes -= bufferSize1 + bufferSize2;
6727     }
6728
6729     // Update our buffer offset and unlock sound buffer
6730     nextReadPointer = ( nextReadPointer + bufferSize1 + bufferSize2 ) % dsBufferSize;
6731     dsBuffer->Unlock( buffer1, bufferSize1, buffer2, bufferSize2 );
6732     if ( FAILED( result ) ) {
6733       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking capture buffer!";
6734       errorText_ = errorStream_.str();
6735       MUTEX_UNLOCK( &stream_.mutex );
6736       error( RtAudioError::SYSTEM_ERROR );
6737       return;
6738     }
6739     handle->bufferPointer[1] = nextReadPointer;
6740
6741     // No byte swapping necessary in DirectSound implementation.
6742
6743     // If necessary, convert 8-bit data from unsigned to signed.
6744     if ( stream_.deviceFormat[1] == RTAUDIO_SINT8 )
6745       for ( int j=0; j<bufferBytes; j++ ) buffer[j] = (signed char) ( buffer[j] - 128 );
6746
6747     // Do buffer conversion if necessary.
6748     if ( stream_.doConvertBuffer[1] )
6749       convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
6750   }
6751
6752  unlock:
6753   MUTEX_UNLOCK( &stream_.mutex );
6754   RtApi::tickStreamTime();
6755 }
6756
6757 // Definitions for utility functions and callbacks
6758 // specific to the DirectSound implementation.
6759
6760 static unsigned __stdcall callbackHandler( void *ptr )
6761 {
6762   CallbackInfo *info = (CallbackInfo *) ptr;
6763   RtApiDs *object = (RtApiDs *) info->object;
6764   bool* isRunning = &info->isRunning;
6765
6766   while ( *isRunning == true ) {
6767     object->callbackEvent();
6768   }
6769
6770   _endthreadex( 0 );
6771   return 0;
6772 }
6773
6774 static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
6775                                           LPCTSTR description,
6776                                           LPCTSTR /*module*/,
6777                                           LPVOID lpContext )
6778 {
6779   struct DsProbeData& probeInfo = *(struct DsProbeData*) lpContext;
6780   std::vector<struct DsDevice>& dsDevices = *probeInfo.dsDevices;
6781
6782   HRESULT hr;
6783   bool validDevice = false;
6784   if ( probeInfo.isInput == true ) {
6785     DSCCAPS caps;
6786     LPDIRECTSOUNDCAPTURE object;
6787
6788     hr = DirectSoundCaptureCreate(  lpguid, &object,   NULL );
6789     if ( hr != DS_OK ) return TRUE;
6790
6791     caps.dwSize = sizeof(caps);
6792     hr = object->GetCaps( &caps );
6793     if ( hr == DS_OK ) {
6794       if ( caps.dwChannels > 0 && caps.dwFormats > 0 )
6795         validDevice = true;
6796     }
6797     object->Release();
6798   }
6799   else {
6800     DSCAPS caps;
6801     LPDIRECTSOUND object;
6802     hr = DirectSoundCreate(  lpguid, &object,   NULL );
6803     if ( hr != DS_OK ) return TRUE;
6804
6805     caps.dwSize = sizeof(caps);
6806     hr = object->GetCaps( &caps );
6807     if ( hr == DS_OK ) {
6808       if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO )
6809         validDevice = true;
6810     }
6811     object->Release();
6812   }
6813
6814   // If good device, then save its name and guid.
6815   std::string name = convertCharPointerToStdString( description );
6816   //if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" )
6817   if ( lpguid == NULL )
6818     name = "Default Device";
6819   if ( validDevice ) {
6820     for ( unsigned int i=0; i<dsDevices.size(); i++ ) {
6821       if ( dsDevices[i].name == name ) {
6822         dsDevices[i].found = true;
6823         if ( probeInfo.isInput ) {
6824           dsDevices[i].id[1] = lpguid;
6825           dsDevices[i].validId[1] = true;
6826         }
6827         else {
6828           dsDevices[i].id[0] = lpguid;
6829           dsDevices[i].validId[0] = true;
6830         }
6831         return TRUE;
6832       }
6833     }
6834
6835     DsDevice device;
6836     device.name = name;
6837     device.found = true;
6838     if ( probeInfo.isInput ) {
6839       device.id[1] = lpguid;
6840       device.validId[1] = true;
6841     }
6842     else {
6843       device.id[0] = lpguid;
6844       device.validId[0] = true;
6845     }
6846     dsDevices.push_back( device );
6847   }
6848
6849   return TRUE;
6850 }
6851
6852 static const char* getErrorString( int code )
6853 {
6854   switch ( code ) {
6855
6856   case DSERR_ALLOCATED:
6857     return "Already allocated";
6858
6859   case DSERR_CONTROLUNAVAIL:
6860     return "Control unavailable";
6861
6862   case DSERR_INVALIDPARAM:
6863     return "Invalid parameter";
6864
6865   case DSERR_INVALIDCALL:
6866     return "Invalid call";
6867
6868   case DSERR_GENERIC:
6869     return "Generic error";
6870
6871   case DSERR_PRIOLEVELNEEDED:
6872     return "Priority level needed";
6873
6874   case DSERR_OUTOFMEMORY:
6875     return "Out of memory";
6876
6877   case DSERR_BADFORMAT:
6878     return "The sample rate or the channel format is not supported";
6879
6880   case DSERR_UNSUPPORTED:
6881     return "Not supported";
6882
6883   case DSERR_NODRIVER:
6884     return "No driver";
6885
6886   case DSERR_ALREADYINITIALIZED:
6887     return "Already initialized";
6888
6889   case DSERR_NOAGGREGATION:
6890     return "No aggregation";
6891
6892   case DSERR_BUFFERLOST:
6893     return "Buffer lost";
6894
6895   case DSERR_OTHERAPPHASPRIO:
6896     return "Another application already has priority";
6897
6898   case DSERR_UNINITIALIZED:
6899     return "Uninitialized";
6900
6901   default:
6902     return "DirectSound unknown error";
6903   }
6904 }
6905 //******************** End of __WINDOWS_DS__ *********************//
6906 #endif
6907
6908
6909 #if defined(__LINUX_ALSA__)
6910
6911 #include <alsa/asoundlib.h>
6912 #include <unistd.h>
6913
6914   // A structure to hold various information related to the ALSA API
6915   // implementation.
6916 struct AlsaHandle {
6917   snd_pcm_t *handles[2];
6918   bool synchronized;
6919   bool xrun[2];
6920   pthread_cond_t runnable_cv;
6921   bool runnable;
6922
6923   AlsaHandle()
6924     :synchronized(false), runnable(false) { xrun[0] = false; xrun[1] = false; }
6925 };
6926
6927 static void *alsaCallbackHandler( void * ptr );
6928
6929 RtApiAlsa :: RtApiAlsa()
6930 {
6931   // Nothing to do here.
6932 }
6933
6934 RtApiAlsa :: ~RtApiAlsa()
6935 {
6936   if ( stream_.state != STREAM_CLOSED ) closeStream();
6937 }
6938
6939 unsigned int RtApiAlsa :: getDeviceCount( void )
6940 {
6941   unsigned nDevices = 0;
6942   int result, subdevice, card;
6943   char name[64];
6944   snd_ctl_t *handle;
6945
6946   // Count cards and devices
6947   card = -1;
6948   snd_card_next( &card );
6949   while ( card >= 0 ) {
6950     sprintf( name, "hw:%d", card );
6951     result = snd_ctl_open( &handle, name, 0 );
6952     if ( result < 0 ) {
6953       errorStream_ << "RtApiAlsa::getDeviceCount: control open, card = " << card << ", " << snd_strerror( result ) << ".";
6954       errorText_ = errorStream_.str();
6955       error( RtAudioError::WARNING );
6956       goto nextcard;
6957     }
6958     subdevice = -1;
6959     while( 1 ) {
6960       result = snd_ctl_pcm_next_device( handle, &subdevice );
6961       if ( result < 0 ) {
6962         errorStream_ << "RtApiAlsa::getDeviceCount: control next device, card = " << card << ", " << snd_strerror( result ) << ".";
6963         errorText_ = errorStream_.str();
6964         error( RtAudioError::WARNING );
6965         break;
6966       }
6967       if ( subdevice < 0 )
6968         break;
6969       nDevices++;
6970     }
6971   nextcard:
6972     snd_ctl_close( handle );
6973     snd_card_next( &card );
6974   }
6975
6976   result = snd_ctl_open( &handle, "default", 0 );
6977   if (result == 0) {
6978     nDevices++;
6979     snd_ctl_close( handle );
6980   }
6981
6982   return nDevices;
6983 }
6984
6985 RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
6986 {
6987   RtAudio::DeviceInfo info;
6988   info.probed = false;
6989
6990   unsigned nDevices = 0;
6991   int result, subdevice, card;
6992   char name[64];
6993   snd_ctl_t *chandle;
6994
6995   // Count cards and devices
6996   card = -1;
6997   subdevice = -1;
6998   snd_card_next( &card );
6999   while ( card >= 0 ) {
7000     sprintf( name, "hw:%d", card );
7001     result = snd_ctl_open( &chandle, name, SND_CTL_NONBLOCK );
7002     if ( result < 0 ) {
7003       errorStream_ << "RtApiAlsa::getDeviceInfo: control open, card = " << card << ", " << snd_strerror( result ) << ".";
7004       errorText_ = errorStream_.str();
7005       error( RtAudioError::WARNING );
7006       goto nextcard;
7007     }
7008     subdevice = -1;
7009     while( 1 ) {
7010       result = snd_ctl_pcm_next_device( chandle, &subdevice );
7011       if ( result < 0 ) {
7012         errorStream_ << "RtApiAlsa::getDeviceInfo: control next device, card = " << card << ", " << snd_strerror( result ) << ".";
7013         errorText_ = errorStream_.str();
7014         error( RtAudioError::WARNING );
7015         break;
7016       }
7017       if ( subdevice < 0 ) break;
7018       if ( nDevices == device ) {
7019         sprintf( name, "hw:%d,%d", card, subdevice );
7020         goto foundDevice;
7021       }
7022       nDevices++;
7023     }
7024   nextcard:
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