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