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