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