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