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