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