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