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