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