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