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