f7c918de7b8dbea0f11f12d0ac1b293344cd3cbf
[rtaudio-cdist.git] / RtAudio.cpp
1 /************************************************************************/
2 /*! \class RtAudio
3     \brief Realtime audio i/o C++ classes.
4
5     RtAudio provides a common API (Application Programming Interface)
6     for realtime audio input/output across Linux (native ALSA, Jack,
7     and OSS), SGI, Macintosh OS X (CoreAudio), and Windows
8     (DirectSound and ASIO) operating systems.
9
10     RtAudio WWW site: http://music.mcgill.ca/~gary/rtaudio/
11
12     RtAudio: realtime audio i/o C++ classes
13     Copyright (c) 2001-2005 Gary P. Scavone
14
15     Permission is hereby granted, free of charge, to any person
16     obtaining a copy of this software and associated documentation files
17     (the "Software"), to deal in the Software without restriction,
18     including without limitation the rights to use, copy, modify, merge,
19     publish, distribute, sublicense, and/or sell copies of the Software,
20     and to permit persons to whom the Software is furnished to do so,
21     subject to the following conditions:
22
23     The above copyright notice and this permission notice shall be
24     included in all copies or substantial portions of the Software.
25
26     Any person wishing to distribute modifications to the Software is
27     requested to send the modifications to the original developer so that
28     they can be incorporated into the canonical version.
29
30     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
33     IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
34     ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
35     CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
36     WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 */
38 /************************************************************************/
39
40 // RtAudio: Version 3.0.3 (18 November 2005)
41
42 #include "RtAudio.h"
43 #include <iostream>
44 #include <stdio.h>
45
46 // Static variable definitions.
47 const unsigned int RtApi::MAX_SAMPLE_RATES = 14;
48 const unsigned int RtApi::SAMPLE_RATES[] = {
49   4000, 5512, 8000, 9600, 11025, 16000, 22050,
50   32000, 44100, 48000, 88200, 96000, 176400, 192000
51 };
52
53 #if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__)
54   #define MUTEX_INITIALIZE(A) InitializeCriticalSection(A)
55   #define MUTEX_DESTROY(A)    DeleteCriticalSection(A);
56   #define MUTEX_LOCK(A)      EnterCriticalSection(A)
57   #define MUTEX_UNLOCK(A)     LeaveCriticalSection(A)
58 #else // pthread API
59   #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL)
60   #define MUTEX_DESTROY(A)    pthread_mutex_destroy(A);
61   #define MUTEX_LOCK(A)       pthread_mutex_lock(A)
62   #define MUTEX_UNLOCK(A)     pthread_mutex_unlock(A)
63 #endif
64
65 // *************************************************** //
66 //
67 // Public common (OS-independent) methods.
68 //
69 // *************************************************** //
70
71 RtAudio :: RtAudio( RtAudioApi api )
72 {
73   initialize( api );
74 }
75
76 RtAudio :: RtAudio( int outputDevice, int outputChannels,
77                     int inputDevice, int inputChannels,
78                     RtAudioFormat format, int sampleRate,
79                     int *bufferSize, int numberOfBuffers, RtAudioApi api )
80 {
81   initialize( api );
82
83   try {
84     rtapi_->openStream( outputDevice, outputChannels,
85                         inputDevice, inputChannels,
86                         format, sampleRate,
87                         bufferSize, numberOfBuffers );
88   }
89   catch (RtError &exception) {
90     // Deallocate the RtApi instance.
91     delete rtapi_;
92     throw exception;
93   }
94 }
95
96 RtAudio :: RtAudio( int outputDevice, int outputChannels,
97                     int inputDevice, int inputChannels,
98                     RtAudioFormat format, int sampleRate,
99                     int *bufferSize, int *numberOfBuffers, RtAudioApi api )
100 {
101   initialize( api );
102
103   try {
104     rtapi_->openStream( outputDevice, outputChannels,
105                         inputDevice, inputChannels,
106                         format, sampleRate,
107                         bufferSize, numberOfBuffers );
108   }
109   catch (RtError &exception) {
110     // Deallocate the RtApi instance.
111     delete rtapi_;
112     throw exception;
113   }
114 }
115
116 RtAudio :: ~RtAudio()
117 {
118   delete rtapi_;
119 }
120
121 void RtAudio :: openStream( int outputDevice, int outputChannels,
122                             int inputDevice, int inputChannels,
123                             RtAudioFormat format, int sampleRate,
124                             int *bufferSize, int numberOfBuffers )
125 {
126   rtapi_->openStream( outputDevice, outputChannels, inputDevice,
127                       inputChannels, format, sampleRate,
128                       bufferSize, numberOfBuffers );
129 }
130
131 void RtAudio :: openStream( int outputDevice, int outputChannels,
132                             int inputDevice, int inputChannels,
133                             RtAudioFormat format, int sampleRate,
134                             int *bufferSize, int *numberOfBuffers )
135 {
136   rtapi_->openStream( outputDevice, outputChannels, inputDevice,
137                       inputChannels, format, sampleRate,
138                       bufferSize, *numberOfBuffers );
139 }
140
141 void RtAudio::initialize( RtAudioApi api )
142 {
143   rtapi_ = 0;
144
145   // First look for a compiled match to a specified API value. If one
146   // of these constructors throws an error, it will be passed up the
147   // inheritance chain.
148 #if defined(__LINUX_JACK__)
149   if ( api == LINUX_JACK )
150     rtapi_ = new RtApiJack();
151 #endif
152 #if defined(__LINUX_ALSA__)
153   if ( api == LINUX_ALSA )
154     rtapi_ = new RtApiAlsa();
155 #endif
156 #if defined(__LINUX_OSS__)
157   if ( api == LINUX_OSS )
158     rtapi_ = new RtApiOss();
159 #endif
160 #if defined(__WINDOWS_ASIO__)
161   if ( api == WINDOWS_ASIO )
162     rtapi_ = new RtApiAsio();
163 #endif
164 #if defined(__WINDOWS_DS__)
165   if ( api == WINDOWS_DS )
166     rtapi_ = new RtApiDs();
167 #endif
168 #if defined(__IRIX_AL__)
169   if ( api == IRIX_AL )
170     rtapi_ = new RtApiAl();
171 #endif
172 #if defined(__MACOSX_CORE__)
173   if ( api == MACOSX_CORE )
174     rtapi_ = new RtApiCore();
175 #endif
176
177   if ( rtapi_ ) return;
178   if ( api > 0 ) {
179     // No compiled support for specified API value.
180     throw RtError( "RtAudio: no compiled support for specified API argument!", RtError::INVALID_PARAMETER );
181   }
182
183   // No specified API ... search for "best" option.
184   try {
185 #if defined(__LINUX_JACK__)
186     rtapi_ = new RtApiJack();
187 #elif defined(__WINDOWS_ASIO__)
188     rtapi_ = new RtApiAsio();
189 #elif defined(__IRIX_AL__)
190     rtapi_ = new RtApiAl();
191 #elif defined(__MACOSX_CORE__)
192     rtapi_ = new RtApiCore();
193 #else
194     ;
195 #endif
196   }
197   catch (RtError &) {
198 #if defined(__RTAUDIO_DEBUG__)
199     fprintf(stderr, "\nRtAudio: no devices found for first api option (JACK, ASIO, Al, or CoreAudio).\n\n");
200 #endif
201     rtapi_ = 0;
202   }
203
204   if ( rtapi_ ) return;
205
206 // Try second API support
207   if ( rtapi_ == 0 ) {
208     try {
209 #if defined(__LINUX_ALSA__)
210       rtapi_ = new RtApiAlsa();
211 #elif defined(__WINDOWS_DS__)
212       rtapi_ = new RtApiDs();
213 #else
214       ;
215 #endif
216     }
217     catch (RtError &) {
218 #if defined(__RTAUDIO_DEBUG__)
219       fprintf(stderr, "\nRtAudio: no devices found for second api option (Alsa or DirectSound).\n\n");
220 #endif
221       rtapi_ = 0;
222     }
223   }
224
225   if ( rtapi_ ) return;
226
227   // Try third API support
228   if ( rtapi_ == 0 ) {
229 #if defined(__LINUX_OSS__)
230     try {
231       rtapi_ = new RtApiOss();
232     }
233     catch (RtError &error) {
234       rtapi_ = 0;
235     }
236 #else
237     ;
238 #endif
239   }
240
241   if ( rtapi_ == 0 ) {
242     // No devices found.
243     throw RtError( "RtAudio: no devices found for compiled audio APIs!", RtError::NO_DEVICES_FOUND );
244   }
245 }
246
247 RtApi :: RtApi()
248 {
249   stream_.mode = UNINITIALIZED;
250   stream_.state = STREAM_STOPPED;
251   stream_.apiHandle = 0;
252   MUTEX_INITIALIZE(&stream_.mutex);
253 }
254
255 RtApi :: ~RtApi()
256 {
257   MUTEX_DESTROY(&stream_.mutex);
258 }
259
260 void RtApi :: openStream( int outputDevice, int outputChannels,
261                          int inputDevice, int inputChannels,
262                          RtAudioFormat format, int sampleRate,
263                          int *bufferSize, int *numberOfBuffers )
264 {
265   this->openStream( outputDevice, outputChannels, inputDevice,
266                     inputChannels, format, sampleRate,
267                     bufferSize, *numberOfBuffers );
268   *numberOfBuffers = stream_.nBuffers;
269 }
270
271 void RtApi :: openStream( int outputDevice, int outputChannels,
272                          int inputDevice, int inputChannels,
273                          RtAudioFormat format, int sampleRate,
274                          int *bufferSize, int numberOfBuffers )
275 {
276   if ( stream_.mode != UNINITIALIZED ) {
277     sprintf(message_, "RtApi: only one open stream allowed per class instance.");
278     error(RtError::INVALID_STREAM);
279   }
280
281   if (outputChannels < 1 && inputChannels < 1) {
282     sprintf(message_,"RtApi: one or both 'channel' parameters must be greater than zero.");
283     error(RtError::INVALID_PARAMETER);
284   }
285
286   if ( formatBytes(format) == 0 ) {
287     sprintf(message_,"RtApi: 'format' parameter value is undefined.");
288     error(RtError::INVALID_PARAMETER);
289   }
290
291   if ( outputChannels > 0 ) {
292     if (outputDevice > nDevices_ || outputDevice < 0) {
293       sprintf(message_,"RtApi: 'outputDevice' parameter value (%d) is invalid.", outputDevice);
294       error(RtError::INVALID_PARAMETER);
295     }
296   }
297
298   if ( inputChannels > 0 ) {
299     if (inputDevice > nDevices_ || inputDevice < 0) {
300       sprintf(message_,"RtApi: 'inputDevice' parameter value (%d) is invalid.", inputDevice);
301       error(RtError::INVALID_PARAMETER);
302     }
303   }
304
305   std::string errorMessages;
306   clearStreamInfo();
307   bool result = FAILURE;
308   int device, defaultDevice = 0;
309   StreamMode mode;
310   int channels;
311   if ( outputChannels > 0 ) {
312
313     mode = OUTPUT;
314     channels = outputChannels;
315
316     if ( outputDevice == 0 ) { // Try default device first.
317       defaultDevice = getDefaultOutputDevice();
318       device = defaultDevice;
319     }
320     else
321       device = outputDevice - 1;
322
323     for ( int i=-1; i<nDevices_; i++ ) {
324       if ( i >= 0 ) { 
325         if ( i == defaultDevice ) continue;
326         device = i;
327       }
328       if ( devices_[device].probed == false ) {
329         // If the device wasn't successfully probed before, try it
330         // (again) now.
331         clearDeviceInfo(&devices_[device]);
332         probeDeviceInfo(&devices_[device]);
333       }
334       if ( devices_[device].probed )
335         result = probeDeviceOpen(device, mode, channels, sampleRate,
336                                  format, bufferSize, numberOfBuffers);
337       if ( result == SUCCESS ) break;
338       errorMessages.append( "    " );
339       errorMessages.append( message_ );
340       errorMessages.append( "\n" );
341       if ( outputDevice > 0 ) break;
342       clearStreamInfo();
343     }
344   }
345
346   if ( inputChannels > 0 && ( result == SUCCESS || outputChannels <= 0 ) ) {
347
348     mode = INPUT;
349     channels = inputChannels;
350
351     if ( inputDevice == 0 ) { // Try default device first.
352       defaultDevice = getDefaultInputDevice();
353       device = defaultDevice;
354     }
355     else
356       device = inputDevice - 1;
357
358     for ( int i=-1; i<nDevices_; i++ ) {
359       if (i >= 0 ) { 
360         if ( i == defaultDevice ) continue;
361         device = i;
362       }
363       if ( devices_[device].probed == false ) {
364         // If the device wasn't successfully probed before, try it
365         // (again) now.
366         clearDeviceInfo(&devices_[device]);
367         probeDeviceInfo(&devices_[device]);
368       }
369       if ( devices_[device].probed )
370         result = probeDeviceOpen( device, mode, channels, sampleRate,
371                                   format, bufferSize, numberOfBuffers );
372       if ( result == SUCCESS ) break;
373       errorMessages.append( "    " );
374       errorMessages.append( message_ );
375       errorMessages.append( "\n" );
376       if ( inputDevice > 0 ) break;
377     }
378   }
379
380   if ( result == SUCCESS )
381     return;
382
383   // If we get here, all attempted probes failed.  Close any opened
384   // devices and clear the stream structure.
385   if ( stream_.mode != UNINITIALIZED ) closeStream();
386   clearStreamInfo();
387   if ( ( outputDevice == 0 && outputChannels > 0 )
388        || ( inputDevice == 0 && inputChannels > 0 ) )
389     sprintf(message_,"RtApi: no devices found for given stream parameters: \n%s",
390             errorMessages.c_str());
391   else
392     sprintf(message_,"RtApi: unable to open specified device(s) with given stream parameters: \n%s",
393             errorMessages.c_str());
394   error(RtError::INVALID_PARAMETER);
395
396   return;
397 }
398
399 int RtApi :: getDeviceCount(void)
400 {
401   return devices_.size();
402 }
403
404 RtApi::StreamState RtApi :: getStreamState( void ) const
405 {
406   return stream_.state;
407 }
408
409 RtAudioDeviceInfo RtApi :: getDeviceInfo( int device )
410 {
411   if (device > (int) devices_.size() || device < 1) {
412     sprintf(message_, "RtApi: invalid device specifier (%d)!", device);
413     error(RtError::INVALID_DEVICE);
414   }
415
416   RtAudioDeviceInfo info;
417   int deviceIndex = device - 1;
418
419   // If the device wasn't successfully probed before, try it now (or again).
420   if (devices_[deviceIndex].probed == false) {
421     clearDeviceInfo(&devices_[deviceIndex]);
422     probeDeviceInfo(&devices_[deviceIndex]);
423   }
424
425   info.name.append( devices_[deviceIndex].name );
426   info.probed = devices_[deviceIndex].probed;
427   if ( info.probed == true ) {
428     info.outputChannels = devices_[deviceIndex].maxOutputChannels;
429     info.inputChannels = devices_[deviceIndex].maxInputChannels;
430     info.duplexChannels = devices_[deviceIndex].maxDuplexChannels;
431     for (unsigned int i=0; i<devices_[deviceIndex].sampleRates.size(); i++)
432       info.sampleRates.push_back( devices_[deviceIndex].sampleRates[i] );
433     info.nativeFormats = devices_[deviceIndex].nativeFormats;
434     if ( (deviceIndex == getDefaultOutputDevice()) ||
435          (deviceIndex == getDefaultInputDevice()) )
436       info.isDefault = true;
437   }
438
439   return info;
440 }
441
442 char * const RtApi :: getStreamBuffer(void)
443 {
444   verifyStream();
445   return stream_.userBuffer;
446 }
447
448 int RtApi :: getDefaultInputDevice(void)
449 {
450   // Should be implemented in subclasses if appropriate.
451   return 0;
452 }
453
454 int RtApi :: getDefaultOutputDevice(void)
455 {
456   // Should be implemented in subclasses if appropriate.
457   return 0;
458 }
459
460 void RtApi :: closeStream(void)
461 {
462   // MUST be implemented in subclasses!
463 }
464
465 void RtApi :: probeDeviceInfo( RtApiDevice *info )
466 {
467   // MUST be implemented in subclasses!
468 }
469
470 bool RtApi :: probeDeviceOpen( int device, StreamMode mode, int channels, 
471                                int sampleRate, RtAudioFormat format,
472                                int *bufferSize, int numberOfBuffers )
473 {
474   // MUST be implemented in subclasses!
475   return FAILURE;
476 }
477
478
479 // *************************************************** //
480 //
481 // OS/API-specific methods.
482 //
483 // *************************************************** //
484
485 #if defined(__LINUX_OSS__)
486
487 #include <unistd.h>
488 #include <sys/stat.h>
489 #include <sys/types.h>
490 #include <sys/ioctl.h>
491 #include <unistd.h>
492 #include <fcntl.h>
493 #include <sys/soundcard.h>
494 #include <errno.h>
495 #include <math.h>
496
497 #define DAC_NAME "/dev/dsp"
498 #define MAX_DEVICES 16
499 #define MAX_CHANNELS 16
500
501 extern "C" void *ossCallbackHandler(void * ptr);
502
503 RtApiOss :: RtApiOss()
504 {
505   this->initialize();
506
507   if (nDevices_ <= 0) {
508     sprintf(message_, "RtApiOss: no Linux OSS audio devices found!");
509     error(RtError::NO_DEVICES_FOUND);
510  }
511 }
512
513 RtApiOss :: ~RtApiOss()
514 {
515   if ( stream_.mode != UNINITIALIZED )
516     closeStream();
517 }
518
519 void RtApiOss :: initialize(void)
520 {
521   // Count cards and devices
522   nDevices_ = 0;
523
524   // We check /dev/dsp before probing devices.  /dev/dsp is supposed to
525   // be a link to the "default" audio device, of the form /dev/dsp0,
526   // /dev/dsp1, etc...  However, I've seen many cases where /dev/dsp was a
527   // real device, so we need to check for that.  Also, sometimes the
528   // link is to /dev/dspx and other times just dspx.  I'm not sure how
529   // the latter works, but it does.
530   char device_name[16];
531   struct stat dspstat;
532   int dsplink = -1;
533   int i = 0;
534   if (lstat(DAC_NAME, &dspstat) == 0) {
535     if (S_ISLNK(dspstat.st_mode)) {
536       i = readlink(DAC_NAME, device_name, sizeof(device_name));
537       if (i > 0) {
538         device_name[i] = '\0';
539         if (i > 8) { // check for "/dev/dspx"
540           if (!strncmp(DAC_NAME, device_name, 8))
541             dsplink = atoi(&device_name[8]);
542         }
543         else if (i > 3) { // check for "dspx"
544           if (!strncmp("dsp", device_name, 3))
545             dsplink = atoi(&device_name[3]);
546         }
547       }
548       else {
549         sprintf(message_, "RtApiOss: cannot read value of symbolic link %s.", DAC_NAME);
550         error(RtError::SYSTEM_ERROR);
551       }
552     }
553   }
554   else {
555     sprintf(message_, "RtApiOss: cannot stat %s.", DAC_NAME);
556     error(RtError::SYSTEM_ERROR);
557   }
558
559   // The OSS API doesn't provide a routine for determining the number
560   // of devices.  Thus, we'll just pursue a brute force method.  The
561   // idea is to start with /dev/dsp(0) and continue with higher device
562   // numbers until we reach MAX_DSP_DEVICES.  This should tell us how
563   // many devices we have ... it is not a fullproof scheme, but hopefully
564   // it will work most of the time.
565   int fd = 0;
566   RtApiDevice device;
567   for (i=-1; i<MAX_DEVICES; i++) {
568
569     // Probe /dev/dsp first, since it is supposed to be the default device.
570     if (i == -1)
571       sprintf(device_name, "%s", DAC_NAME);
572     else if (i == dsplink)
573       continue; // We've aready probed this device via /dev/dsp link ... try next device.
574     else
575       sprintf(device_name, "%s%d", DAC_NAME, i);
576
577     // First try to open the device for playback, then record mode.
578     fd = open(device_name, O_WRONLY | O_NONBLOCK);
579     if (fd == -1) {
580       // Open device for playback failed ... either busy or doesn't exist.
581       if (errno != EBUSY && errno != EAGAIN) {
582         // Try to open for capture
583         fd = open(device_name, O_RDONLY | O_NONBLOCK);
584         if (fd == -1) {
585           // Open device for record failed.
586           if (errno != EBUSY && errno != EAGAIN)
587             continue;
588           else {
589             sprintf(message_, "RtApiOss: OSS record device (%s) is busy.", device_name);
590             error(RtError::WARNING);
591             // still count it for now
592           }
593         }
594       }
595       else {
596         sprintf(message_, "RtApiOss: OSS playback device (%s) is busy.", device_name);
597         error(RtError::WARNING);
598         // still count it for now
599       }
600     }
601
602     if (fd >= 0) close(fd);
603     device.name.erase();
604     device.name.append( (const char *)device_name, strlen(device_name)+1);
605     devices_.push_back(device);
606     nDevices_++;
607   }
608 }
609
610 void RtApiOss :: probeDeviceInfo(RtApiDevice *info)
611 {
612   int i, fd, channels, mask;
613
614   // The OSS API doesn't provide a means for probing the capabilities
615   // of devices.  Thus, we'll just pursue a brute force method.
616
617   // First try for playback
618   fd = open(info->name.c_str(), O_WRONLY | O_NONBLOCK);
619   if (fd == -1) {
620     // Open device failed ... either busy or doesn't exist
621     if (errno == EBUSY || errno == EAGAIN)
622       sprintf(message_, "RtApiOss: OSS playback device (%s) is busy and cannot be probed.",
623               info->name.c_str());
624     else
625       sprintf(message_, "RtApiOss: OSS playback device (%s) open error.", info->name.c_str());
626     error(RtError::DEBUG_WARNING);
627     goto capture_probe;
628   }
629
630   // We have an open device ... see how many channels it can handle
631   for (i=MAX_CHANNELS; i>0; i--) {
632     channels = i;
633     if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
634       // This would normally indicate some sort of hardware error, but under ALSA's
635       // OSS emulation, it sometimes indicates an invalid channel value.  Further,
636       // the returned channel value is not changed. So, we'll ignore the possible
637       // hardware error.
638       continue; // try next channel number
639     }
640     // Check to see whether the device supports the requested number of channels
641     if (channels != i ) continue; // try next channel number
642     // If here, we found the largest working channel value
643     break;
644   }
645   info->maxOutputChannels = i;
646
647   // Now find the minimum number of channels it can handle
648   for (i=1; i<=info->maxOutputChannels; i++) {
649     channels = i;
650     if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
651       continue; // try next channel number
652     // If here, we found the smallest working channel value
653     break;
654   }
655   info->minOutputChannels = i;
656   close(fd);
657
658  capture_probe:
659   // Now try for capture
660   fd = open(info->name.c_str(), O_RDONLY | O_NONBLOCK);
661   if (fd == -1) {
662     // Open device for capture failed ... either busy or doesn't exist
663     if (errno == EBUSY || errno == EAGAIN)
664       sprintf(message_, "RtApiOss: OSS capture device (%s) is busy and cannot be probed.",
665               info->name.c_str());
666     else
667       sprintf(message_, "RtApiOss: OSS capture device (%s) open error.", info->name.c_str());
668     error(RtError::DEBUG_WARNING);
669     if (info->maxOutputChannels == 0)
670       // didn't open for playback either ... device invalid
671       return;
672     goto probe_parameters;
673   }
674
675   // We have the device open for capture ... see how many channels it can handle
676   for (i=MAX_CHANNELS; i>0; i--) {
677     channels = i;
678     if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
679       continue; // as above
680     }
681     // If here, we found a working channel value
682     break;
683   }
684   info->maxInputChannels = i;
685
686   // Now find the minimum number of channels it can handle
687   for (i=1; i<=info->maxInputChannels; i++) {
688     channels = i;
689     if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
690       continue; // try next channel number
691     // If here, we found the smallest working channel value
692     break;
693   }
694   info->minInputChannels = i;
695   close(fd);
696
697   if (info->maxOutputChannels == 0 && info->maxInputChannels == 0) {
698     sprintf(message_, "RtApiOss: device (%s) reports zero channels for input and output.",
699             info->name.c_str());
700     error(RtError::DEBUG_WARNING);
701     return;
702   }
703
704   // If device opens for both playback and capture, we determine the channels.
705   if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
706     goto probe_parameters;
707
708   fd = open(info->name.c_str(), O_RDWR | O_NONBLOCK);
709   if (fd == -1)
710     goto probe_parameters;
711
712   ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
713   ioctl(fd, SNDCTL_DSP_GETCAPS, &mask);
714   if (mask & DSP_CAP_DUPLEX) {
715     info->hasDuplexSupport = true;
716     // We have the device open for duplex ... see how many channels it can handle
717     for (i=MAX_CHANNELS; i>0; i--) {
718       channels = i;
719       if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
720         continue; // as above
721       // If here, we found a working channel value
722       break;
723     }
724     info->maxDuplexChannels = i;
725
726     // Now find the minimum number of channels it can handle
727     for (i=1; i<=info->maxDuplexChannels; i++) {
728       channels = i;
729       if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
730         continue; // try next channel number
731       // If here, we found the smallest working channel value
732       break;
733     }
734     info->minDuplexChannels = i;
735   }
736   close(fd);
737
738  probe_parameters:
739   // At this point, we need to figure out the supported data formats
740   // and sample rates.  We'll proceed by openning the device in the
741   // direction with the maximum number of channels, or playback if
742   // they are equal.  This might limit our sample rate options, but so
743   // be it.
744
745   if (info->maxOutputChannels >= info->maxInputChannels) {
746     fd = open(info->name.c_str(), O_WRONLY | O_NONBLOCK);
747     channels = info->maxOutputChannels;
748   }
749   else {
750     fd = open(info->name.c_str(), O_RDONLY | O_NONBLOCK);
751     channels = info->maxInputChannels;
752   }
753
754   if (fd == -1) {
755     // We've got some sort of conflict ... abort
756     sprintf(message_, "RtApiOss: device (%s) won't reopen during probe.",
757             info->name.c_str());
758     error(RtError::DEBUG_WARNING);
759     return;
760   }
761
762   // We have an open device ... set to maximum channels.
763   i = channels;
764   if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
765     // We've got some sort of conflict ... abort
766     close(fd);
767     sprintf(message_, "RtApiOss: device (%s) won't revert to previous channel setting.",
768             info->name.c_str());
769     error(RtError::DEBUG_WARNING);
770     return;
771   }
772
773   if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
774     close(fd);
775     sprintf(message_, "RtApiOss: device (%s) can't get supported audio formats.",
776             info->name.c_str());
777     error(RtError::DEBUG_WARNING);
778     return;
779   }
780
781   // Probe the supported data formats ... we don't care about endian-ness just yet.
782   int format;
783   info->nativeFormats = 0;
784 #if defined (AFMT_S32_BE)
785   // This format does not seem to be in the 2.4 kernel version of OSS soundcard.h
786   if (mask & AFMT_S32_BE) {
787     format = AFMT_S32_BE;
788     info->nativeFormats |= RTAUDIO_SINT32;
789   }
790 #endif
791 #if defined (AFMT_S32_LE)
792   /* This format is not in the 2.4.4 kernel version of OSS soundcard.h */
793   if (mask & AFMT_S32_LE) {
794     format = AFMT_S32_LE;
795     info->nativeFormats |= RTAUDIO_SINT32;
796   }
797 #endif
798   if (mask & AFMT_S8) {
799     format = AFMT_S8;
800     info->nativeFormats |= RTAUDIO_SINT8;
801   }
802   if (mask & AFMT_S16_BE) {
803     format = AFMT_S16_BE;
804     info->nativeFormats |= RTAUDIO_SINT16;
805   }
806   if (mask & AFMT_S16_LE) {
807     format = AFMT_S16_LE;
808     info->nativeFormats |= RTAUDIO_SINT16;
809   }
810
811   // Check that we have at least one supported format
812   if (info->nativeFormats == 0) {
813     close(fd);
814     sprintf(message_, "RtApiOss: device (%s) data format not supported by RtAudio.",
815             info->name.c_str());
816     error(RtError::DEBUG_WARNING);
817     return;
818   }
819
820   // Set the format
821   i = format;
822   if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1 || format != i) {
823     close(fd);
824     sprintf(message_, "RtApiOss: device (%s) error setting data format.",
825             info->name.c_str());
826     error(RtError::DEBUG_WARNING);
827     return;
828   }
829
830   // Probe the supported sample rates.
831   info->sampleRates.clear();
832   for (unsigned int k=0; k<MAX_SAMPLE_RATES; k++) {
833     int speed = SAMPLE_RATES[k];
834     if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) != -1 && speed == (int)SAMPLE_RATES[k])
835       info->sampleRates.push_back(speed);
836   }
837
838   if (info->sampleRates.size() == 0) {
839     close(fd);
840     sprintf(message_, "RtApiOss: no supported sample rates found for device (%s).",
841             info->name.c_str());
842     error(RtError::DEBUG_WARNING);
843     return;
844   }
845
846   // That's all ... close the device and return
847   close(fd);
848   info->probed = true;
849   return;
850 }
851
852 bool RtApiOss :: probeDeviceOpen(int device, StreamMode mode, int channels, 
853                                 int sampleRate, RtAudioFormat format,
854                                 int *bufferSize, int numberOfBuffers)
855 {
856   int buffers, buffer_bytes, device_channels, device_format;
857   int srate, temp, fd;
858   int *handle = (int *) stream_.apiHandle;
859
860   const char *name = devices_[device].name.c_str();
861
862   if (mode == OUTPUT)
863     fd = open(name, O_WRONLY | O_NONBLOCK);
864   else { // mode == INPUT
865     if (stream_.mode == OUTPUT && stream_.device[0] == device) {
866       // We just set the same device for playback ... close and reopen for duplex (OSS only).
867       close(handle[0]);
868       handle[0] = 0;
869       // First check that the number previously set channels is the same.
870       if (stream_.nUserChannels[0] != channels) {
871         sprintf(message_, "RtApiOss: input/output channels must be equal for OSS duplex device (%s).", name);
872         goto error;
873       }
874       fd = open(name, O_RDWR | O_NONBLOCK);
875     }
876     else
877       fd = open(name, O_RDONLY | O_NONBLOCK);
878   }
879
880   if (fd == -1) {
881     if (errno == EBUSY || errno == EAGAIN)
882       sprintf(message_, "RtApiOss: device (%s) is busy and cannot be opened.",
883               name);
884     else
885       sprintf(message_, "RtApiOss: device (%s) cannot be opened.", name);
886     goto error;
887   }
888
889   // Now reopen in blocking mode.
890   close(fd);
891   if (mode == OUTPUT)
892     fd = open(name, O_WRONLY | O_SYNC);
893   else { // mode == INPUT
894     if (stream_.mode == OUTPUT && stream_.device[0] == device)
895       fd = open(name, O_RDWR | O_SYNC);
896     else
897       fd = open(name, O_RDONLY | O_SYNC);
898   }
899
900   if (fd == -1) {
901     sprintf(message_, "RtApiOss: device (%s) cannot be opened.", name);
902     goto error;
903   }
904
905   // Get the sample format mask
906   int mask;
907   if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
908     close(fd);
909     sprintf(message_, "RtApiOss: device (%s) can't get supported audio formats.",
910             name);
911     goto error;
912   }
913
914   // Determine how to set the device format.
915   stream_.userFormat = format;
916   device_format = -1;
917   stream_.doByteSwap[mode] = false;
918   if (format == RTAUDIO_SINT8) {
919     if (mask & AFMT_S8) {
920       device_format = AFMT_S8;
921       stream_.deviceFormat[mode] = RTAUDIO_SINT8;
922     }
923   }
924   else if (format == RTAUDIO_SINT16) {
925     if (mask & AFMT_S16_NE) {
926       device_format = AFMT_S16_NE;
927       stream_.deviceFormat[mode] = RTAUDIO_SINT16;
928     }
929 #if BYTE_ORDER == LITTLE_ENDIAN
930     else if (mask & AFMT_S16_BE) {
931       device_format = AFMT_S16_BE;
932       stream_.deviceFormat[mode] = RTAUDIO_SINT16;
933       stream_.doByteSwap[mode] = true;
934     }
935 #else
936     else if (mask & AFMT_S16_LE) {
937       device_format = AFMT_S16_LE;
938       stream_.deviceFormat[mode] = RTAUDIO_SINT16;
939       stream_.doByteSwap[mode] = true;
940     }
941 #endif
942   }
943 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
944   else if (format == RTAUDIO_SINT32) {
945     if (mask & AFMT_S32_NE) {
946       device_format = AFMT_S32_NE;
947       stream_.deviceFormat[mode] = RTAUDIO_SINT32;
948     }
949 #if BYTE_ORDER == LITTLE_ENDIAN
950     else if (mask & AFMT_S32_BE) {
951       device_format = AFMT_S32_BE;
952       stream_.deviceFormat[mode] = RTAUDIO_SINT32;
953       stream_.doByteSwap[mode] = true;
954     }
955 #else
956     else if (mask & AFMT_S32_LE) {
957       device_format = AFMT_S32_LE;
958       stream_.deviceFormat[mode] = RTAUDIO_SINT32;
959       stream_.doByteSwap[mode] = true;
960     }
961 #endif
962   }
963 #endif
964
965   if (device_format == -1) {
966     // The user requested format is not natively supported by the device.
967     if (mask & AFMT_S16_NE) {
968       device_format = AFMT_S16_NE;
969       stream_.deviceFormat[mode] = RTAUDIO_SINT16;
970     }
971 #if BYTE_ORDER == LITTLE_ENDIAN
972     else if (mask & AFMT_S16_BE) {
973       device_format = AFMT_S16_BE;
974       stream_.deviceFormat[mode] = RTAUDIO_SINT16;
975       stream_.doByteSwap[mode] = true;
976     }
977 #else
978     else if (mask & AFMT_S16_LE) {
979       device_format = AFMT_S16_LE;
980       stream_.deviceFormat[mode] = RTAUDIO_SINT16;
981       stream_.doByteSwap[mode] = true;
982     }
983 #endif
984 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
985     else if (mask & AFMT_S32_NE) {
986       device_format = AFMT_S32_NE;
987       stream_.deviceFormat[mode] = RTAUDIO_SINT32;
988     }
989 #if BYTE_ORDER == LITTLE_ENDIAN
990     else if (mask & AFMT_S32_BE) {
991       device_format = AFMT_S32_BE;
992       stream_.deviceFormat[mode] = RTAUDIO_SINT32;
993       stream_.doByteSwap[mode] = true;
994     }
995 #else
996     else if (mask & AFMT_S32_LE) {
997       device_format = AFMT_S32_LE;
998       stream_.deviceFormat[mode] = RTAUDIO_SINT32;
999       stream_.doByteSwap[mode] = true;
1000     }
1001 #endif
1002 #endif
1003     else if (mask & AFMT_S8) {
1004       device_format = AFMT_S8;
1005       stream_.deviceFormat[mode] = RTAUDIO_SINT8;
1006     }
1007   }
1008
1009   if (stream_.deviceFormat[mode] == 0) {
1010     // This really shouldn't happen ...
1011     close(fd);
1012     sprintf(message_, "RtApiOss: device (%s) data format not supported by RtAudio.",
1013             name);
1014     goto error;
1015   }
1016
1017   // Determine the number of channels for this device.  Note that the
1018   // channel value requested by the user might be < min_X_Channels.
1019   stream_.nUserChannels[mode] = channels;
1020   device_channels = channels;
1021   if (mode == OUTPUT) {
1022     if (channels < devices_[device].minOutputChannels)
1023       device_channels = devices_[device].minOutputChannels;
1024   }
1025   else { // mode == INPUT
1026     if (stream_.mode == OUTPUT && stream_.device[0] == device) {
1027       // We're doing duplex setup here.
1028       if (channels < devices_[device].minDuplexChannels)
1029         device_channels = devices_[device].minDuplexChannels;
1030     }
1031     else {
1032       if (channels < devices_[device].minInputChannels)
1033         device_channels = devices_[device].minInputChannels;
1034     }
1035   }
1036   stream_.nDeviceChannels[mode] = device_channels;
1037
1038   // Attempt to set the buffer size.  According to OSS, the minimum
1039   // number of buffers is two.  The supposed minimum buffer size is 16
1040   // bytes, so that will be our lower bound.  The argument to this
1041   // call is in the form 0xMMMMSSSS (hex), where the buffer size (in
1042   // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM.
1043   // We'll check the actual value used near the end of the setup
1044   // procedure.
1045   buffer_bytes = *bufferSize * formatBytes(stream_.deviceFormat[mode]) * device_channels;
1046   if (buffer_bytes < 16) buffer_bytes = 16;
1047   buffers = numberOfBuffers;
1048   if (buffers < 2) buffers = 2;
1049   temp = ((int) buffers << 16) + (int)(log10((double)buffer_bytes)/log10(2.0));
1050   if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &temp)) {
1051     close(fd);
1052     sprintf(message_, "RtApiOss: error setting fragment size for device (%s).",
1053             name);
1054     goto error;
1055   }
1056   stream_.nBuffers = buffers;
1057
1058   // Set the data format.
1059   temp = device_format;
1060   if (ioctl(fd, SNDCTL_DSP_SETFMT, &device_format) == -1 || device_format != temp) {
1061     close(fd);
1062     sprintf(message_, "RtApiOss: error setting data format for device (%s).",
1063             name);
1064     goto error;
1065   }
1066
1067   // Set the number of channels.
1068   temp = device_channels;
1069   if (ioctl(fd, SNDCTL_DSP_CHANNELS, &device_channels) == -1 || device_channels != temp) {
1070     close(fd);
1071     sprintf(message_, "RtApiOss: error setting %d channels on device (%s).",
1072             temp, name);
1073     goto error;
1074   }
1075
1076   // Set the sample rate.
1077   srate = sampleRate;
1078   temp = srate;
1079   if (ioctl(fd, SNDCTL_DSP_SPEED, &srate) == -1) {
1080     close(fd);
1081     sprintf(message_, "RtApiOss: error setting sample rate = %d on device (%s).",
1082             temp, name);
1083     goto error;
1084   }
1085
1086   // Verify the sample rate setup worked.
1087   if (abs(srate - temp) > 100) {
1088     close(fd);
1089     sprintf(message_, "RtApiOss: error ... audio device (%s) doesn't support sample rate of %d.",
1090             name, temp);
1091     goto error;
1092   }
1093   stream_.sampleRate = sampleRate;
1094
1095   if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &buffer_bytes) == -1) {
1096     close(fd);
1097     sprintf(message_, "RtApiOss: error getting buffer size for device (%s).",
1098             name);
1099     goto error;
1100   }
1101
1102   // Save buffer size (in sample frames).
1103   *bufferSize = buffer_bytes / (formatBytes(stream_.deviceFormat[mode]) * device_channels);
1104   stream_.bufferSize = *bufferSize;
1105
1106   if (mode == INPUT && stream_.mode == OUTPUT &&
1107       stream_.device[0] == device) {
1108     // We're doing duplex setup here.
1109     stream_.deviceFormat[0] = stream_.deviceFormat[1];
1110     stream_.nDeviceChannels[0] = device_channels;
1111   }
1112
1113   // Allocate the stream handles if necessary and then save.
1114   if ( stream_.apiHandle == 0 ) {
1115     handle = (int *) calloc(2, sizeof(int));
1116     stream_.apiHandle = (void *) handle;
1117     handle[0] = 0;
1118     handle[1] = 0;
1119   }
1120   else {
1121     handle = (int *) stream_.apiHandle;
1122   }
1123   handle[mode] = fd;
1124
1125   // Set flags for buffer conversion
1126   stream_.doConvertBuffer[mode] = false;
1127   if (stream_.userFormat != stream_.deviceFormat[mode])
1128     stream_.doConvertBuffer[mode] = true;
1129   if (stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode])
1130     stream_.doConvertBuffer[mode] = true;
1131
1132   // Allocate necessary internal buffers
1133   if ( stream_.nUserChannels[0] != stream_.nUserChannels[1] ) {
1134
1135     long buffer_bytes;
1136     if (stream_.nUserChannels[0] >= stream_.nUserChannels[1])
1137       buffer_bytes = stream_.nUserChannels[0];
1138     else
1139       buffer_bytes = stream_.nUserChannels[1];
1140
1141     buffer_bytes *= *bufferSize * formatBytes(stream_.userFormat);
1142     if (stream_.userBuffer) free(stream_.userBuffer);
1143     stream_.userBuffer = (char *) calloc(buffer_bytes, 1);
1144     if (stream_.userBuffer == NULL) {
1145       close(fd);
1146       sprintf(message_, "RtApiOss: error allocating user buffer memory (%s).",
1147               name);
1148       goto error;
1149     }
1150   }
1151
1152   if ( stream_.doConvertBuffer[mode] ) {
1153
1154     long buffer_bytes;
1155     bool makeBuffer = true;
1156     if ( mode == OUTPUT )
1157       buffer_bytes = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
1158     else { // mode == INPUT
1159       buffer_bytes = stream_.nDeviceChannels[1] * formatBytes(stream_.deviceFormat[1]);
1160       if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
1161         long bytes_out = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
1162         if ( buffer_bytes < bytes_out ) makeBuffer = false;
1163       }
1164     }
1165
1166     if ( makeBuffer ) {
1167       buffer_bytes *= *bufferSize;
1168       if (stream_.deviceBuffer) free(stream_.deviceBuffer);
1169       stream_.deviceBuffer = (char *) calloc(buffer_bytes, 1);
1170       if (stream_.deviceBuffer == NULL) {
1171         close(fd);
1172         sprintf(message_, "RtApiOss: error allocating device buffer memory (%s).",
1173                 name);
1174         goto error;
1175       }
1176     }
1177   }
1178
1179   stream_.device[mode] = device;
1180   stream_.state = STREAM_STOPPED;
1181
1182   if ( stream_.mode == OUTPUT && mode == INPUT ) {
1183     stream_.mode = DUPLEX;
1184     if (stream_.device[0] == device)
1185       handle[0] = fd;
1186   }
1187   else
1188     stream_.mode = mode;
1189
1190   // Setup the buffer conversion information structure.
1191   if ( stream_.doConvertBuffer[mode] ) {
1192     if (mode == INPUT) { // convert device to user buffer
1193       stream_.convertInfo[mode].inJump = stream_.nDeviceChannels[1];
1194       stream_.convertInfo[mode].outJump = stream_.nUserChannels[1];
1195       stream_.convertInfo[mode].inFormat = stream_.deviceFormat[1];
1196       stream_.convertInfo[mode].outFormat = stream_.userFormat;
1197     }
1198     else { // convert user to device buffer
1199       stream_.convertInfo[mode].inJump = stream_.nUserChannels[0];
1200       stream_.convertInfo[mode].outJump = stream_.nDeviceChannels[0];
1201       stream_.convertInfo[mode].inFormat = stream_.userFormat;
1202       stream_.convertInfo[mode].outFormat = stream_.deviceFormat[0];
1203     }
1204
1205     if ( stream_.convertInfo[mode].inJump < stream_.convertInfo[mode].outJump )
1206       stream_.convertInfo[mode].channels = stream_.convertInfo[mode].inJump;
1207     else
1208       stream_.convertInfo[mode].channels = stream_.convertInfo[mode].outJump;
1209
1210     // Set up the interleave/deinterleave offsets.
1211     if ( mode == INPUT && stream_.deInterleave[1] ) {
1212       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
1213         stream_.convertInfo[mode].inOffset.push_back( k * stream_.bufferSize );
1214         stream_.convertInfo[mode].outOffset.push_back( k );
1215         stream_.convertInfo[mode].inJump = 1;
1216       }
1217     }
1218     else if (mode == OUTPUT && stream_.deInterleave[0]) {
1219       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
1220         stream_.convertInfo[mode].inOffset.push_back( k );
1221         stream_.convertInfo[mode].outOffset.push_back( k * stream_.bufferSize );
1222         stream_.convertInfo[mode].outJump = 1;
1223       }
1224     }
1225     else {
1226       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
1227         stream_.convertInfo[mode].inOffset.push_back( k );
1228         stream_.convertInfo[mode].outOffset.push_back( k );
1229       }
1230     }
1231   }
1232
1233   return SUCCESS;
1234
1235  error:
1236   if (handle) {
1237     if (handle[0])
1238       close(handle[0]);
1239     free(handle);
1240     stream_.apiHandle = 0;
1241   }
1242
1243   if (stream_.userBuffer) {
1244     free(stream_.userBuffer);
1245     stream_.userBuffer = 0;
1246   }
1247
1248   error(RtError::DEBUG_WARNING);
1249   return FAILURE;
1250 }
1251
1252 void RtApiOss :: closeStream()
1253 {
1254   // We don't want an exception to be thrown here because this
1255   // function is called by our class destructor.  So, do our own
1256   // stream check.
1257   if ( stream_.mode == UNINITIALIZED ) {
1258     sprintf(message_, "RtApiOss::closeStream(): no open stream to close!");
1259     error(RtError::WARNING);
1260     return;
1261   }
1262
1263   int *handle = (int *) stream_.apiHandle;
1264   if (stream_.state == STREAM_RUNNING) {
1265     if (stream_.mode == OUTPUT || stream_.mode == DUPLEX)
1266       ioctl(handle[0], SNDCTL_DSP_RESET, 0);
1267     else
1268       ioctl(handle[1], SNDCTL_DSP_RESET, 0);
1269     stream_.state = STREAM_STOPPED;
1270   }
1271
1272   if (stream_.callbackInfo.usingCallback) {
1273     stream_.callbackInfo.usingCallback = false;
1274     pthread_join(stream_.callbackInfo.thread, NULL);
1275   }
1276
1277   if (handle) {
1278     if (handle[0]) close(handle[0]);
1279     if (handle[1]) close(handle[1]);
1280     free(handle);
1281     stream_.apiHandle = 0;
1282   }
1283
1284   if (stream_.userBuffer) {
1285     free(stream_.userBuffer);
1286     stream_.userBuffer = 0;
1287   }
1288
1289   if (stream_.deviceBuffer) {
1290     free(stream_.deviceBuffer);
1291     stream_.deviceBuffer = 0;
1292   }
1293
1294   stream_.mode = UNINITIALIZED;
1295 }
1296
1297 void RtApiOss :: startStream()
1298 {
1299   verifyStream();
1300   if (stream_.state == STREAM_RUNNING) return;
1301
1302   MUTEX_LOCK(&stream_.mutex);
1303
1304   stream_.state = STREAM_RUNNING;
1305
1306   // No need to do anything else here ... OSS automatically starts
1307   // when fed samples.
1308
1309   MUTEX_UNLOCK(&stream_.mutex);
1310 }
1311
1312 void RtApiOss :: stopStream()
1313 {
1314   verifyStream();
1315   if (stream_.state == STREAM_STOPPED) return;
1316
1317   // Change the state before the lock to improve shutdown response
1318   // when using a callback.
1319   stream_.state = STREAM_STOPPED;
1320   MUTEX_LOCK(&stream_.mutex);
1321
1322   int err;
1323   int *handle = (int *) stream_.apiHandle;
1324   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
1325     err = ioctl(handle[0], SNDCTL_DSP_POST, 0);
1326     //err = ioctl(handle[0], SNDCTL_DSP_SYNC, 0);
1327     if (err < -1) {
1328       sprintf(message_, "RtApiOss: error stopping device (%s).",
1329               devices_[stream_.device[0]].name.c_str());
1330       error(RtError::DRIVER_ERROR);
1331     }
1332   }
1333   else {
1334     err = ioctl(handle[1], SNDCTL_DSP_POST, 0);
1335     //err = ioctl(handle[1], SNDCTL_DSP_SYNC, 0);
1336     if (err < -1) {
1337       sprintf(message_, "RtApiOss: error stopping device (%s).",
1338               devices_[stream_.device[1]].name.c_str());
1339       error(RtError::DRIVER_ERROR);
1340     }
1341   }
1342
1343   MUTEX_UNLOCK(&stream_.mutex);
1344 }
1345
1346 void RtApiOss :: abortStream()
1347 {
1348   stopStream();
1349 }
1350
1351 int RtApiOss :: streamWillBlock()
1352 {
1353   verifyStream();
1354   if (stream_.state == STREAM_STOPPED) return 0;
1355
1356   MUTEX_LOCK(&stream_.mutex);
1357
1358   int bytes = 0, channels = 0, frames = 0;
1359   audio_buf_info info;
1360   int *handle = (int *) stream_.apiHandle;
1361   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
1362     ioctl(handle[0], SNDCTL_DSP_GETOSPACE, &info);
1363     bytes = info.bytes;
1364     channels = stream_.nDeviceChannels[0];
1365   }
1366
1367   if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
1368     ioctl(handle[1], SNDCTL_DSP_GETISPACE, &info);
1369     if (stream_.mode == DUPLEX ) {
1370       bytes = (bytes < info.bytes) ? bytes : info.bytes;
1371       channels = stream_.nDeviceChannels[0];
1372     }
1373     else {
1374       bytes = info.bytes;
1375       channels = stream_.nDeviceChannels[1];
1376     }
1377   }
1378
1379   frames = (int) (bytes / (channels * formatBytes(stream_.deviceFormat[0])));
1380   frames -= stream_.bufferSize;
1381   if (frames < 0) frames = 0;
1382
1383   MUTEX_UNLOCK(&stream_.mutex);
1384   return frames;
1385 }
1386
1387 void RtApiOss :: tickStream()
1388 {
1389   verifyStream();
1390
1391   int stopStream = 0;
1392   if (stream_.state == STREAM_STOPPED) {
1393     if (stream_.callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
1394     return;
1395   }
1396   else if (stream_.callbackInfo.usingCallback) {
1397     RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
1398     stopStream = callback(stream_.userBuffer, stream_.bufferSize, stream_.callbackInfo.userData);
1399   }
1400
1401   MUTEX_LOCK(&stream_.mutex);
1402
1403   // The state might change while waiting on a mutex.
1404   if (stream_.state == STREAM_STOPPED)
1405     goto unlock;
1406
1407   int result, *handle;
1408   char *buffer;
1409   int samples;
1410   RtAudioFormat format;
1411   handle = (int *) stream_.apiHandle;
1412   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
1413
1414     // Setup parameters and do buffer conversion if necessary.
1415     if (stream_.doConvertBuffer[0]) {
1416       buffer = stream_.deviceBuffer;
1417       convertBuffer( buffer, stream_.userBuffer, stream_.convertInfo[0] );
1418       samples = stream_.bufferSize * stream_.nDeviceChannels[0];
1419       format = stream_.deviceFormat[0];
1420     }
1421     else {
1422       buffer = stream_.userBuffer;
1423       samples = stream_.bufferSize * stream_.nUserChannels[0];
1424       format = stream_.userFormat;
1425     }
1426
1427     // Do byte swapping if necessary.
1428     if (stream_.doByteSwap[0])
1429       byteSwapBuffer(buffer, samples, format);
1430
1431     // Write samples to device.
1432     result = write(handle[0], buffer, samples * formatBytes(format));
1433
1434     if (result == -1) {
1435       // This could be an underrun, but the basic OSS API doesn't provide a means for determining that.
1436       sprintf(message_, "RtApiOss: audio write error for device (%s).",
1437               devices_[stream_.device[0]].name.c_str());
1438       error(RtError::DRIVER_ERROR);
1439     }
1440   }
1441
1442   if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
1443
1444     // Setup parameters.
1445     if (stream_.doConvertBuffer[1]) {
1446       buffer = stream_.deviceBuffer;
1447       samples = stream_.bufferSize * stream_.nDeviceChannels[1];
1448       format = stream_.deviceFormat[1];
1449     }
1450     else {
1451       buffer = stream_.userBuffer;
1452       samples = stream_.bufferSize * stream_.nUserChannels[1];
1453       format = stream_.userFormat;
1454     }
1455
1456     // Read samples from device.
1457     result = read(handle[1], buffer, samples * formatBytes(format));
1458
1459     if (result == -1) {
1460       // This could be an overrun, but the basic OSS API doesn't provide a means for determining that.
1461       sprintf(message_, "RtApiOss: audio read error for device (%s).",
1462               devices_[stream_.device[1]].name.c_str());
1463       error(RtError::DRIVER_ERROR);
1464     }
1465
1466     // Do byte swapping if necessary.
1467     if (stream_.doByteSwap[1])
1468       byteSwapBuffer(buffer, samples, format);
1469
1470     // Do buffer conversion if necessary.
1471     if (stream_.doConvertBuffer[1])
1472       convertBuffer( stream_.userBuffer, stream_.deviceBuffer, stream_.convertInfo[1] );
1473   }
1474
1475  unlock:
1476   MUTEX_UNLOCK(&stream_.mutex);
1477
1478   if (stream_.callbackInfo.usingCallback && stopStream)
1479     this->stopStream();
1480 }
1481
1482 void RtApiOss :: setStreamCallback(RtAudioCallback callback, void *userData)
1483 {
1484   verifyStream();
1485
1486   CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
1487   if ( info->usingCallback ) {
1488     sprintf(message_, "RtApiOss: A callback is already set for this stream!");
1489     error(RtError::WARNING);
1490     return;
1491   }
1492
1493   info->callback = (void *) callback;
1494   info->userData = userData;
1495   info->usingCallback = true;
1496   info->object = (void *) this;
1497
1498   // Set the thread attributes for joinable and realtime scheduling
1499   // priority.  The higher priority will only take affect if the
1500   // program is run as root or suid.
1501   pthread_attr_t attr;
1502   pthread_attr_init(&attr);
1503   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1504   pthread_attr_setschedpolicy(&attr, SCHED_RR);
1505
1506   int err = pthread_create(&(info->thread), &attr, ossCallbackHandler, &stream_.callbackInfo);
1507   pthread_attr_destroy(&attr);
1508   if (err) {
1509     info->usingCallback = false;
1510     sprintf(message_, "RtApiOss: error starting callback thread!");
1511     error(RtError::THREAD_ERROR);
1512   }
1513 }
1514
1515 void RtApiOss :: cancelStreamCallback()
1516 {
1517   verifyStream();
1518
1519   if (stream_.callbackInfo.usingCallback) {
1520
1521     if (stream_.state == STREAM_RUNNING)
1522       stopStream();
1523
1524     MUTEX_LOCK(&stream_.mutex);
1525
1526     stream_.callbackInfo.usingCallback = false;
1527     pthread_join(stream_.callbackInfo.thread, NULL);
1528     stream_.callbackInfo.thread = 0;
1529     stream_.callbackInfo.callback = NULL;
1530     stream_.callbackInfo.userData = NULL;
1531
1532     MUTEX_UNLOCK(&stream_.mutex);
1533   }
1534 }
1535
1536 extern "C" void *ossCallbackHandler(void *ptr)
1537 {
1538   CallbackInfo *info = (CallbackInfo *) ptr;
1539   RtApiOss *object = (RtApiOss *) info->object;
1540   bool *usingCallback = &info->usingCallback;
1541
1542   while ( *usingCallback ) {
1543     pthread_testcancel();
1544     try {
1545       object->tickStream();
1546     }
1547     catch (RtError &exception) {
1548       fprintf(stderr, "\nRtApiOss: callback thread error (%s) ... closing thread.\n\n",
1549               exception.getMessageString());
1550       break;
1551     }
1552   }
1553
1554   return 0;
1555 }
1556
1557 //******************** End of __LINUX_OSS__ *********************//
1558 #endif
1559
1560 #if defined(__MACOSX_CORE__)
1561
1562
1563 // The OS X CoreAudio API is designed to use a separate callback
1564 // procedure for each of its audio devices.  A single RtAudio duplex
1565 // stream using two different devices is supported here, though it
1566 // cannot be guaranteed to always behave correctly because we cannot
1567 // synchronize these two callbacks.  This same functionality can be
1568 // achieved with better synchrony by opening two separate streams for
1569 // the devices and using RtAudio blocking calls (i.e. tickStream()).
1570 //
1571 // A property listener is installed for over/underrun information.
1572 // However, no functionality is currently provided to allow property
1573 // listeners to trigger user handlers because it is unclear what could
1574 // be done if a critical stream parameter (buffer size, sample rate,
1575 // device disconnect) notification arrived.  The listeners entail
1576 // quite a bit of extra code and most likely, a user program wouldn't
1577 // be prepared for the result anyway.
1578
1579 // A structure to hold various information related to the CoreAudio API
1580 // implementation.
1581 struct CoreHandle {
1582   UInt32 index[2];
1583   bool stopStream;
1584   bool xrun;
1585   char *deviceBuffer;
1586   pthread_cond_t condition;
1587
1588   CoreHandle()
1589     :stopStream(false), xrun(false), deviceBuffer(0) {}
1590 };
1591
1592 RtApiCore :: RtApiCore()
1593 {
1594   this->initialize();
1595
1596   if (nDevices_ <= 0) {
1597     sprintf(message_, "RtApiCore: no Macintosh OS-X Core Audio devices found!");
1598     error(RtError::NO_DEVICES_FOUND);
1599  }
1600 }
1601
1602 RtApiCore :: ~RtApiCore()
1603 {
1604   // The subclass destructor gets called before the base class
1605   // destructor, so close an existing stream before deallocating
1606   // apiDeviceId memory.
1607   if ( stream_.mode != UNINITIALIZED ) closeStream();
1608
1609   // Free our allocated apiDeviceId memory.
1610   AudioDeviceID *id;
1611   for ( unsigned int i=0; i<devices_.size(); i++ ) {
1612     id = (AudioDeviceID *) devices_[i].apiDeviceId;
1613     if (id) free(id);
1614   }
1615 }
1616
1617 void RtApiCore :: initialize(void)
1618 {
1619   OSStatus err = noErr;
1620   UInt32 dataSize;
1621   AudioDeviceID *deviceList = NULL;
1622   nDevices_ = 0;
1623
1624   // Find out how many audio devices there are, if any.
1625   err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &dataSize, NULL);
1626   if (err != noErr) {
1627     sprintf(message_, "RtApiCore: OS-X error getting device info!");
1628     error(RtError::SYSTEM_ERROR);
1629   }
1630
1631   nDevices_ = dataSize / sizeof(AudioDeviceID);
1632   if (nDevices_ == 0) return;
1633
1634   // Make space for the devices we are about to get.
1635   deviceList = (AudioDeviceID   *) malloc( dataSize );
1636   if (deviceList == NULL) {
1637     sprintf(message_, "RtApiCore: memory allocation error during initialization!");
1638     error(RtError::MEMORY_ERROR);
1639   }
1640
1641   // Get the array of AudioDeviceIDs.
1642   err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &dataSize, (void *) deviceList);
1643   if (err != noErr) {
1644     free(deviceList);
1645     sprintf(message_, "RtApiCore: OS-X error getting device properties!");
1646     error(RtError::SYSTEM_ERROR);
1647   }
1648
1649   // Create list of device structures and write device identifiers.
1650   RtApiDevice device;
1651   AudioDeviceID *id;
1652   for (int i=0; i<nDevices_; i++) {
1653     devices_.push_back(device);
1654     id = (AudioDeviceID *) malloc( sizeof(AudioDeviceID) );
1655     *id = deviceList[i];
1656     devices_[i].apiDeviceId = (void *) id;
1657   }
1658
1659   free(deviceList);
1660 }
1661
1662 int RtApiCore :: getDefaultInputDevice(void)
1663 {
1664   AudioDeviceID id, *deviceId;
1665   UInt32 dataSize = sizeof( AudioDeviceID );
1666
1667   OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultInputDevice,
1668                                               &dataSize, &id );
1669
1670   if (result != noErr) {
1671     sprintf( message_, "RtApiCore: OS-X error getting default input device." );
1672     error(RtError::WARNING);
1673     return 0;
1674   }
1675
1676   for ( int i=0; i<nDevices_; i++ ) {
1677     deviceId = (AudioDeviceID *) devices_[i].apiDeviceId;
1678     if ( id == *deviceId ) return i;
1679   }
1680
1681   return 0;
1682 }
1683
1684 int RtApiCore :: getDefaultOutputDevice(void)
1685 {
1686   AudioDeviceID id, *deviceId;
1687   UInt32 dataSize = sizeof( AudioDeviceID );
1688
1689   OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice,
1690                                               &dataSize, &id );
1691
1692   if (result != noErr) {
1693     sprintf( message_, "RtApiCore: OS-X error getting default output device." );
1694     error(RtError::WARNING);
1695     return 0;
1696   }
1697
1698   for ( int i=0; i<nDevices_; i++ ) {
1699     deviceId = (AudioDeviceID *) devices_[i].apiDeviceId;
1700     if ( id == *deviceId ) return i;
1701   }
1702
1703   return 0;
1704 }
1705
1706 static bool deviceSupportsFormat( AudioDeviceID id, bool isInput,
1707                                   AudioStreamBasicDescription   *desc, bool isDuplex )
1708 {
1709   OSStatus result = noErr;
1710   UInt32 dataSize = sizeof( AudioStreamBasicDescription );
1711
1712   result = AudioDeviceGetProperty( id, 0, isInput,
1713                                    kAudioDevicePropertyStreamFormatSupported,
1714                                    &dataSize, desc );
1715
1716   if (result == kAudioHardwareNoError) {
1717     if ( isDuplex ) {
1718       result = AudioDeviceGetProperty( id, 0, true,
1719                                        kAudioDevicePropertyStreamFormatSupported,
1720                                        &dataSize, desc );
1721
1722
1723       if (result != kAudioHardwareNoError)
1724         return false;
1725     }
1726     return true;
1727   }
1728
1729   return false;
1730 }
1731
1732 void RtApiCore :: probeDeviceInfo( RtApiDevice *info )
1733 {
1734   OSStatus err = noErr;
1735
1736   // Get the device manufacturer and name.
1737   char  name[256];
1738   char  fullname[512];
1739   UInt32 dataSize = 256;
1740   AudioDeviceID *id = (AudioDeviceID *) info->apiDeviceId;
1741   err = AudioDeviceGetProperty( *id, 0, false,
1742                                 kAudioDevicePropertyDeviceManufacturer,
1743                                 &dataSize, name );
1744   if (err != noErr) {
1745     sprintf( message_, "RtApiCore: OS-X error getting device manufacturer." );
1746     error(RtError::DEBUG_WARNING);
1747     return;
1748   }
1749   strncpy(fullname, name, 256);
1750   strcat(fullname, ": " );
1751
1752   dataSize = 256;
1753   err = AudioDeviceGetProperty( *id, 0, false,
1754                                 kAudioDevicePropertyDeviceName,
1755                                 &dataSize, name );
1756   if (err != noErr) {
1757     sprintf( message_, "RtApiCore: OS-X error getting device name." );
1758     error(RtError::DEBUG_WARNING);
1759     return;
1760   }
1761   strncat(fullname, name, 254);
1762   info->name.erase();
1763   info->name.append( (const char *)fullname, strlen(fullname)+1);
1764
1765   // Get output channel information.
1766   unsigned int i, minChannels = 0, maxChannels = 0, nStreams = 0;
1767   AudioBufferList       *bufferList = nil;
1768   err = AudioDeviceGetPropertyInfo( *id, 0, false,
1769                                     kAudioDevicePropertyStreamConfiguration,
1770                                     &dataSize, NULL );
1771   if (err == noErr && dataSize > 0) {
1772     bufferList = (AudioBufferList *) malloc( dataSize );
1773     if (bufferList == NULL) {
1774       sprintf(message_, "RtApiCore: memory allocation error!");
1775       error(RtError::DEBUG_WARNING);
1776       return;
1777     }
1778
1779     err = AudioDeviceGetProperty( *id, 0, false,
1780                                   kAudioDevicePropertyStreamConfiguration,
1781                                   &dataSize, bufferList );
1782     if (err == noErr) {
1783       maxChannels = 0;
1784       minChannels = 1000;
1785       nStreams = bufferList->mNumberBuffers;
1786       for ( i=0; i<nStreams; i++ ) {
1787         maxChannels += bufferList->mBuffers[i].mNumberChannels;
1788         if ( bufferList->mBuffers[i].mNumberChannels < minChannels )
1789           minChannels = bufferList->mBuffers[i].mNumberChannels;
1790       }
1791     }
1792   }
1793   free (bufferList);
1794
1795   if (err != noErr || dataSize <= 0) {
1796     sprintf( message_, "RtApiCore: OS-X error getting output channels for device (%s).",
1797              info->name.c_str() );
1798     error(RtError::DEBUG_WARNING);
1799     return;
1800   }
1801
1802   if ( nStreams ) {
1803     if ( maxChannels > 0 )
1804       info->maxOutputChannels = maxChannels;
1805     if ( minChannels > 0 )
1806       info->minOutputChannels = minChannels;
1807   }
1808
1809   // Get input channel information.
1810   bufferList = nil;
1811   err = AudioDeviceGetPropertyInfo( *id, 0, true,
1812                                     kAudioDevicePropertyStreamConfiguration,
1813                                     &dataSize, NULL );
1814   if (err == noErr && dataSize > 0) {
1815     bufferList = (AudioBufferList *) malloc( dataSize );
1816     if (bufferList == NULL) {
1817       sprintf(message_, "RtApiCore: memory allocation error!");
1818       error(RtError::DEBUG_WARNING);
1819       return;
1820     }
1821     err = AudioDeviceGetProperty( *id, 0, true,
1822                                   kAudioDevicePropertyStreamConfiguration,
1823                                   &dataSize, bufferList );
1824     if (err == noErr) {
1825       maxChannels = 0;
1826       minChannels = 1000;
1827       nStreams = bufferList->mNumberBuffers;
1828       for ( i=0; i<nStreams; i++ ) {
1829         if ( bufferList->mBuffers[i].mNumberChannels < minChannels )
1830           minChannels = bufferList->mBuffers[i].mNumberChannels;
1831         maxChannels += bufferList->mBuffers[i].mNumberChannels;
1832       }
1833     }
1834   }
1835   free (bufferList);
1836
1837   if (err != noErr || dataSize <= 0) {
1838     sprintf( message_, "RtApiCore: OS-X error getting input channels for device (%s).",
1839              info->name.c_str() );
1840     error(RtError::DEBUG_WARNING);
1841     return;
1842   }
1843
1844   if ( nStreams ) {
1845     if ( maxChannels > 0 )
1846       info->maxInputChannels = maxChannels;
1847     if ( minChannels > 0 )
1848       info->minInputChannels = minChannels;
1849   }
1850
1851   // If device opens for both playback and capture, we determine the channels.
1852   if (info->maxOutputChannels > 0 && info->maxInputChannels > 0) {
1853     info->hasDuplexSupport = true;
1854     info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
1855       info->maxInputChannels : info->maxOutputChannels;
1856     info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
1857       info->minInputChannels : info->minOutputChannels;
1858   }
1859
1860   // Probe the device sample rate and data format parameters.  The
1861   // core audio query mechanism is performed on a "stream"
1862   // description, which can have a variable number of channels and
1863   // apply to input or output only.
1864
1865   // Create a stream description structure.
1866   AudioStreamBasicDescription   description;
1867   dataSize = sizeof( AudioStreamBasicDescription );
1868   memset(&description, 0, sizeof(AudioStreamBasicDescription));
1869   bool isInput = false;
1870   if ( info->maxOutputChannels == 0 ) isInput = true;
1871   bool isDuplex = false;
1872   if ( info->maxDuplexChannels > 0 ) isDuplex = true;
1873
1874   // Determine the supported sample rates.
1875   info->sampleRates.clear();
1876   for (unsigned int k=0; k<MAX_SAMPLE_RATES; k++) {
1877     description.mSampleRate = (double) SAMPLE_RATES[k];
1878     if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
1879       info->sampleRates.push_back( SAMPLE_RATES[k] );
1880   }
1881
1882   if (info->sampleRates.size() == 0) {
1883     sprintf( message_, "RtApiCore: No supported sample rates found for OS-X device (%s).",
1884              info->name.c_str() );
1885     error(RtError::DEBUG_WARNING);
1886     return;
1887   }
1888
1889   // Determine the supported data formats.
1890   info->nativeFormats = 0;
1891   description.mFormatID = kAudioFormatLinearPCM;
1892   description.mBitsPerChannel = 8;
1893   description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian;
1894   if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
1895     info->nativeFormats |= RTAUDIO_SINT8;
1896   else {
1897     description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
1898     if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
1899       info->nativeFormats |= RTAUDIO_SINT8;
1900   }
1901
1902   description.mBitsPerChannel = 16;
1903   description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
1904   if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
1905     info->nativeFormats |= RTAUDIO_SINT16;
1906   else {
1907     description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
1908     if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
1909       info->nativeFormats |= RTAUDIO_SINT16;
1910   }
1911
1912   description.mBitsPerChannel = 32;
1913   description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
1914   if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
1915     info->nativeFormats |= RTAUDIO_SINT32;
1916   else {
1917     description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
1918     if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
1919       info->nativeFormats |= RTAUDIO_SINT32;
1920   }
1921
1922   description.mBitsPerChannel = 24;
1923   description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsAlignedHigh | kLinearPCMFormatFlagIsBigEndian;
1924   if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
1925     info->nativeFormats |= RTAUDIO_SINT24;
1926   else {
1927     description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
1928     if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
1929       info->nativeFormats |= RTAUDIO_SINT24;
1930   }
1931
1932   description.mBitsPerChannel = 32;
1933   description.mFormatFlags = kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian;
1934   if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
1935     info->nativeFormats |= RTAUDIO_FLOAT32;
1936   else {
1937     description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
1938     if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
1939       info->nativeFormats |= RTAUDIO_FLOAT32;
1940   }
1941
1942   description.mBitsPerChannel = 64;
1943   description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
1944   if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
1945     info->nativeFormats |= RTAUDIO_FLOAT64;
1946   else {
1947     description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
1948     if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) )
1949       info->nativeFormats |= RTAUDIO_FLOAT64;
1950   }
1951
1952   // Check that we have at least one supported format.
1953   if (info->nativeFormats == 0) {
1954     sprintf(message_, "RtApiCore: OS-X device (%s) data format not supported by RtAudio.",
1955             info->name.c_str());
1956     error(RtError::DEBUG_WARNING);
1957     return;
1958   }
1959
1960   info->probed = true;
1961 }
1962
1963 OSStatus callbackHandler( AudioDeviceID inDevice,
1964                           const AudioTimeStamp* inNow,
1965                           const AudioBufferList* inInputData,
1966                           const AudioTimeStamp* inInputTime,
1967                           AudioBufferList* outOutputData,
1968                           const AudioTimeStamp* inOutputTime, 
1969                           void* infoPointer )
1970 {
1971   CallbackInfo *info = (CallbackInfo *) infoPointer;
1972
1973   RtApiCore *object = (RtApiCore *) info->object;
1974   try {
1975     object->callbackEvent( inDevice, (void *)inInputData, (void *)outOutputData );
1976   }
1977   catch (RtError &exception) {
1978     fprintf(stderr, "\nRtApiCore: callback handler error (%s)!\n\n", exception.getMessageString());
1979     return kAudioHardwareUnspecifiedError;
1980   }
1981
1982   return kAudioHardwareNoError;
1983 }
1984
1985 OSStatus deviceListener( AudioDeviceID inDevice,
1986                          UInt32 channel,
1987                          Boolean isInput,
1988                          AudioDevicePropertyID propertyID,
1989                          void* handlePointer )
1990 {
1991   CoreHandle *handle = (CoreHandle *) handlePointer;
1992   if ( propertyID == kAudioDeviceProcessorOverload ) {
1993     if ( isInput )
1994       fprintf(stderr, "\nRtApiCore: OS-X audio input overrun detected!\n");
1995     else
1996       fprintf(stderr, "\nRtApiCore: OS-X audio output underrun detected!\n");
1997     handle->xrun = true;
1998   }
1999
2000   return kAudioHardwareNoError;
2001 }
2002
2003 bool RtApiCore :: probeDeviceOpen( int device, StreamMode mode, int channels, 
2004                                    int sampleRate, RtAudioFormat format,
2005                                    int *bufferSize, int numberOfBuffers )
2006 {
2007   // Setup for stream mode.
2008   bool isInput = false;
2009   AudioDeviceID id = *((AudioDeviceID *) devices_[device].apiDeviceId);
2010   if ( mode == INPUT ) isInput = true;
2011
2012   // Search for a stream which contains the desired number of channels.
2013   OSStatus err = noErr;
2014   UInt32 dataSize;
2015   unsigned int deviceChannels, nStreams = 0;
2016   UInt32 iChannel = 0, iStream = 0;
2017   AudioBufferList       *bufferList = nil;
2018   err = AudioDeviceGetPropertyInfo( id, 0, isInput,
2019                                     kAudioDevicePropertyStreamConfiguration,
2020                                     &dataSize, NULL );
2021
2022   if (err == noErr && dataSize > 0) {
2023     bufferList = (AudioBufferList *) malloc( dataSize );
2024     if (bufferList == NULL) {
2025       sprintf(message_, "RtApiCore: memory allocation error in probeDeviceOpen()!");
2026       error(RtError::DEBUG_WARNING);
2027       return FAILURE;
2028     }
2029     err = AudioDeviceGetProperty( id, 0, isInput,
2030                                   kAudioDevicePropertyStreamConfiguration,
2031                                   &dataSize, bufferList );
2032
2033     if (err == noErr) {
2034       stream_.deInterleave[mode] = false;
2035       nStreams = bufferList->mNumberBuffers;
2036       for ( iStream=0; iStream<nStreams; iStream++ ) {
2037         if ( bufferList->mBuffers[iStream].mNumberChannels >= (unsigned int) channels ) break;
2038         iChannel += bufferList->mBuffers[iStream].mNumberChannels;
2039       }
2040       // If we didn't find a single stream above, see if we can meet
2041       // the channel specification in mono mode (i.e. using separate
2042       // non-interleaved buffers).  This can only work if there are N
2043       // consecutive one-channel streams, where N is the number of
2044       // desired channels.
2045       iChannel = 0;
2046       if ( iStream >= nStreams && nStreams >= (unsigned int) channels ) {
2047         int counter = 0;
2048         for ( iStream=0; iStream<nStreams; iStream++ ) {
2049           if ( bufferList->mBuffers[iStream].mNumberChannels == 1 )
2050             counter++;
2051           else
2052             counter = 0;
2053           if ( counter == channels ) {
2054             iStream -= channels - 1;
2055             iChannel -= channels - 1;
2056             stream_.deInterleave[mode] = true;
2057             break;
2058           }
2059           iChannel += bufferList->mBuffers[iStream].mNumberChannels;
2060         }
2061       }
2062     }
2063   }
2064   if (err != noErr || dataSize <= 0) {
2065     if ( bufferList ) free( bufferList );
2066     sprintf( message_, "RtApiCore: OS-X error getting channels for device (%s).",
2067              devices_[device].name.c_str() );
2068     error(RtError::DEBUG_WARNING);
2069     return FAILURE;
2070   }
2071
2072   if (iStream >= nStreams) {
2073     free (bufferList);
2074     sprintf( message_, "RtApiCore: unable to find OS-X audio stream on device (%s) for requested channels (%d).",
2075              devices_[device].name.c_str(), channels );
2076     error(RtError::DEBUG_WARNING);
2077     return FAILURE;
2078   }
2079
2080   // This is ok even for mono mode ... it gets updated later.
2081   deviceChannels = bufferList->mBuffers[iStream].mNumberChannels;
2082   free (bufferList);
2083
2084   // Determine the buffer size.
2085   AudioValueRange       bufferRange;
2086   dataSize = sizeof(AudioValueRange);
2087   err = AudioDeviceGetProperty( id, 0, isInput,
2088                                 kAudioDevicePropertyBufferSizeRange,
2089                                 &dataSize, &bufferRange);
2090   if (err != noErr) {
2091     sprintf( message_, "RtApiCore: OS-X error getting buffer size range for device (%s).",
2092              devices_[device].name.c_str() );
2093     error(RtError::DEBUG_WARNING);
2094     return FAILURE;
2095   }
2096
2097   long bufferBytes = *bufferSize * deviceChannels * formatBytes(RTAUDIO_FLOAT32);
2098   if (bufferRange.mMinimum > bufferBytes) bufferBytes = (int) bufferRange.mMinimum;
2099   else if (bufferRange.mMaximum < bufferBytes) bufferBytes = (int) bufferRange.mMaximum;
2100
2101   // Set the buffer size.  For mono mode, I'm assuming we only need to
2102   // make this setting for the first channel.
2103   UInt32 theSize = (UInt32) bufferBytes;
2104   dataSize = sizeof( UInt32);
2105   err = AudioDeviceSetProperty(id, NULL, 0, isInput,
2106                                kAudioDevicePropertyBufferSize,
2107                                dataSize, &theSize);
2108   if (err != noErr) {
2109     sprintf( message_, "RtApiCore: OS-X error setting the buffer size for device (%s).",
2110              devices_[device].name.c_str() );
2111     error(RtError::DEBUG_WARNING);
2112     return FAILURE;
2113   }
2114
2115   // If attempting to setup a duplex stream, the bufferSize parameter
2116   // MUST be the same in both directions!
2117   *bufferSize = bufferBytes / ( deviceChannels * formatBytes(RTAUDIO_FLOAT32) );
2118   if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) {
2119     sprintf( message_, "RtApiCore: OS-X error setting buffer size for duplex stream on device (%s).",
2120              devices_[device].name.c_str() );
2121     error(RtError::DEBUG_WARNING);
2122     return FAILURE;
2123   }
2124
2125   stream_.bufferSize = *bufferSize;
2126   stream_.nBuffers = 1;
2127
2128   // Set the stream format description.  Do for each channel in mono mode.
2129   AudioStreamBasicDescription   description;
2130   dataSize = sizeof( AudioStreamBasicDescription );
2131   if ( stream_.deInterleave[mode] ) nStreams = channels;
2132   else nStreams = 1;
2133   for ( unsigned int i=0; i<nStreams; i++, iChannel++ ) {
2134
2135     err = AudioDeviceGetProperty( id, iChannel, isInput,
2136                                   kAudioDevicePropertyStreamFormat,
2137                                   &dataSize, &description );
2138     if (err != noErr) {
2139       sprintf( message_, "RtApiCore: OS-X error getting stream format for device (%s).",
2140                devices_[device].name.c_str() );
2141       error(RtError::DEBUG_WARNING);
2142       return FAILURE;
2143     }
2144
2145     // Set the sample rate and data format id.
2146     description.mSampleRate = (double) sampleRate;
2147     description.mFormatID = kAudioFormatLinearPCM;
2148     err = AudioDeviceSetProperty( id, NULL, iChannel, isInput,
2149                                   kAudioDevicePropertyStreamFormat,
2150                                   dataSize, &description );
2151     if (err != noErr) {
2152       sprintf( message_, "RtApiCore: OS-X error setting sample rate or data format for device (%s).",
2153                devices_[device].name.c_str() );
2154       error(RtError::DEBUG_WARNING);
2155       return FAILURE;
2156     }
2157   }
2158
2159   // Check whether we need byte-swapping (assuming OS-X host is big-endian).
2160   iChannel -= nStreams;
2161   err = AudioDeviceGetProperty( id, iChannel, isInput,
2162                                 kAudioDevicePropertyStreamFormat,
2163                                 &dataSize, &description );
2164   if (err != noErr) {
2165     sprintf( message_, "RtApiCore: OS-X error getting stream format for device (%s).", devices_[device].name.c_str() );
2166     error(RtError::DEBUG_WARNING);
2167     return FAILURE;
2168   }
2169
2170   stream_.doByteSwap[mode] = false;
2171   if ( !description.mFormatFlags & kLinearPCMFormatFlagIsBigEndian )
2172     stream_.doByteSwap[mode] = true;
2173
2174   // From the CoreAudio documentation, PCM data must be supplied as
2175   // 32-bit floats.
2176   stream_.userFormat = format;
2177   stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
2178
2179   if ( stream_.deInterleave[mode] ) // mono mode
2180     stream_.nDeviceChannels[mode] = channels;
2181   else
2182     stream_.nDeviceChannels[mode] = description.mChannelsPerFrame;
2183   stream_.nUserChannels[mode] = channels;
2184
2185   // Set flags for buffer conversion.
2186   stream_.doConvertBuffer[mode] = false;
2187   if (stream_.userFormat != stream_.deviceFormat[mode])
2188     stream_.doConvertBuffer[mode] = true;
2189   if (stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode])
2190     stream_.doConvertBuffer[mode] = true;
2191   if (stream_.nUserChannels[mode] > 1 && stream_.deInterleave[mode])
2192     stream_.doConvertBuffer[mode] = true;
2193
2194   // Allocate our CoreHandle structure for the stream.
2195   CoreHandle *handle;
2196   if ( stream_.apiHandle == 0 ) {
2197     handle = (CoreHandle *) calloc(1, sizeof(CoreHandle));
2198     if ( handle == NULL ) {
2199       sprintf(message_, "RtApiCore: OS-X error allocating coreHandle memory (%s).",
2200               devices_[device].name.c_str());
2201       goto error;
2202     }
2203     handle->index[0] = 0;
2204     handle->index[1] = 0;
2205     if ( pthread_cond_init(&handle->condition, NULL) ) {
2206       sprintf(message_, "RtApiCore: error initializing pthread condition variable (%s).",
2207               devices_[device].name.c_str());
2208       goto error;
2209     }
2210     stream_.apiHandle = (void *) handle;
2211   }
2212   else
2213     handle = (CoreHandle *) stream_.apiHandle;
2214   handle->index[mode] = iStream;
2215
2216   // Allocate necessary internal buffers.
2217   if ( stream_.nUserChannels[0] != stream_.nUserChannels[1] ) {
2218
2219     long buffer_bytes;
2220     if (stream_.nUserChannels[0] >= stream_.nUserChannels[1])
2221       buffer_bytes = stream_.nUserChannels[0];
2222     else
2223       buffer_bytes = stream_.nUserChannels[1];
2224
2225     buffer_bytes *= *bufferSize * formatBytes(stream_.userFormat);
2226     if (stream_.userBuffer) free(stream_.userBuffer);
2227     stream_.userBuffer = (char *) calloc(buffer_bytes, 1);
2228     if (stream_.userBuffer == NULL) {
2229       sprintf(message_, "RtApiCore: OS-X error allocating user buffer memory (%s).",
2230               devices_[device].name.c_str());
2231       goto error;
2232     }
2233   }
2234
2235   if ( stream_.deInterleave[mode] ) {
2236
2237     long buffer_bytes;
2238     bool makeBuffer = true;
2239     if ( mode == OUTPUT )
2240       buffer_bytes = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
2241     else { // mode == INPUT
2242       buffer_bytes = stream_.nDeviceChannels[1] * formatBytes(stream_.deviceFormat[1]);
2243       if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
2244         long bytes_out = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
2245         if ( buffer_bytes < bytes_out ) makeBuffer = false;
2246       }
2247     }
2248
2249     if ( makeBuffer ) {
2250       buffer_bytes *= *bufferSize;
2251       if (stream_.deviceBuffer) free(stream_.deviceBuffer);
2252       stream_.deviceBuffer = (char *) calloc(buffer_bytes, 1);
2253       if (stream_.deviceBuffer == NULL) {
2254         sprintf(message_, "RtApiCore: error allocating device buffer memory (%s).",
2255                 devices_[device].name.c_str());
2256         goto error;
2257       }
2258
2259       // If not de-interleaving, we point stream_.deviceBuffer to the
2260       // OS X supplied device buffer before doing any necessary data
2261       // conversions.  This presents a problem if we have a duplex
2262       // stream using one device which needs de-interleaving and
2263       // another device which doesn't.  So, save a pointer to our own
2264       // device buffer in the CallbackInfo structure.
2265       handle->deviceBuffer = stream_.deviceBuffer;
2266     }
2267   }
2268
2269   stream_.sampleRate = sampleRate;
2270   stream_.device[mode] = device;
2271   stream_.state = STREAM_STOPPED;
2272   stream_.callbackInfo.object = (void *) this;
2273
2274   // Setup the buffer conversion information structure.
2275   if ( stream_.doConvertBuffer[mode] ) {
2276     if (mode == INPUT) { // convert device to user buffer
2277       stream_.convertInfo[mode].inJump = stream_.nDeviceChannels[1];
2278       stream_.convertInfo[mode].outJump = stream_.nUserChannels[1];
2279       stream_.convertInfo[mode].inFormat = stream_.deviceFormat[1];
2280       stream_.convertInfo[mode].outFormat = stream_.userFormat;
2281     }
2282     else { // convert user to device buffer
2283       stream_.convertInfo[mode].inJump = stream_.nUserChannels[0];
2284       stream_.convertInfo[mode].outJump = stream_.nDeviceChannels[0];
2285       stream_.convertInfo[mode].inFormat = stream_.userFormat;
2286       stream_.convertInfo[mode].outFormat = stream_.deviceFormat[0];
2287     }
2288
2289     if ( stream_.convertInfo[mode].inJump < stream_.convertInfo[mode].outJump )
2290       stream_.convertInfo[mode].channels = stream_.convertInfo[mode].inJump;
2291     else
2292       stream_.convertInfo[mode].channels = stream_.convertInfo[mode].outJump;
2293
2294     // Set up the interleave/deinterleave offsets.
2295     if ( mode == INPUT && stream_.deInterleave[1] ) {
2296       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
2297         stream_.convertInfo[mode].inOffset.push_back( k * stream_.bufferSize );
2298         stream_.convertInfo[mode].outOffset.push_back( k );
2299         stream_.convertInfo[mode].inJump = 1;
2300       }
2301     }
2302     else if (mode == OUTPUT && stream_.deInterleave[0]) {
2303       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
2304         stream_.convertInfo[mode].inOffset.push_back( k );
2305         stream_.convertInfo[mode].outOffset.push_back( k * stream_.bufferSize );
2306         stream_.convertInfo[mode].outJump = 1;
2307       }
2308     }
2309     else {
2310       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
2311         stream_.convertInfo[mode].inOffset.push_back( k );
2312         stream_.convertInfo[mode].outOffset.push_back( k );
2313       }
2314     }
2315   }
2316
2317   if ( stream_.mode == OUTPUT && mode == INPUT && stream_.device[0] == device )
2318     // Only one callback procedure per device.
2319     stream_.mode = DUPLEX;
2320   else {
2321     err = AudioDeviceAddIOProc( id, callbackHandler, (void *) &stream_.callbackInfo );
2322     if (err != noErr) {
2323       sprintf( message_, "RtApiCore: OS-X error setting callback for device (%s).", devices_[device].name.c_str() );
2324       error(RtError::DEBUG_WARNING);
2325       return FAILURE;
2326     }
2327     if ( stream_.mode == OUTPUT && mode == INPUT )
2328       stream_.mode = DUPLEX;
2329     else
2330       stream_.mode = mode;
2331   }
2332
2333   // Setup the device property listener for over/underload.
2334   err = AudioDeviceAddPropertyListener( id, iChannel, isInput,
2335                                         kAudioDeviceProcessorOverload,
2336                                         deviceListener, (void *) handle );
2337
2338   return SUCCESS;
2339
2340  error:
2341   if ( handle ) {
2342     pthread_cond_destroy(&handle->condition);
2343     free(handle);
2344     stream_.apiHandle = 0;
2345   }
2346
2347   if (stream_.userBuffer) {
2348     free(stream_.userBuffer);
2349     stream_.userBuffer = 0;
2350   }
2351
2352   error(RtError::DEBUG_WARNING);
2353   return FAILURE;
2354 }
2355
2356 void RtApiCore :: closeStream()
2357 {
2358   // We don't want an exception to be thrown here because this
2359   // function is called by our class destructor.  So, do our own
2360   // stream check.
2361   if ( stream_.mode == UNINITIALIZED ) {
2362     sprintf(message_, "RtApiCore::closeStream(): no open stream to close!");
2363     error(RtError::WARNING);
2364     return;
2365   }
2366
2367   AudioDeviceID id = *( (AudioDeviceID *) devices_[stream_.device[0]].apiDeviceId );
2368   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
2369     if (stream_.state == STREAM_RUNNING)
2370       AudioDeviceStop( id, callbackHandler );
2371     AudioDeviceRemoveIOProc( id, callbackHandler );
2372   }
2373
2374   id = *( (AudioDeviceID *) devices_[stream_.device[1]].apiDeviceId );
2375   if (stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1]) ) {
2376     if (stream_.state == STREAM_RUNNING)
2377       AudioDeviceStop( id, callbackHandler );
2378     AudioDeviceRemoveIOProc( id, callbackHandler );
2379   }
2380
2381   if (stream_.userBuffer) {
2382     free(stream_.userBuffer);
2383     stream_.userBuffer = 0;
2384   }
2385
2386   if ( stream_.deInterleave[0] || stream_.deInterleave[1] ) {
2387     free(stream_.deviceBuffer);
2388     stream_.deviceBuffer = 0;
2389   }
2390
2391   CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
2392
2393   // Destroy pthread condition variable and free the CoreHandle structure.
2394   if ( handle ) {
2395     pthread_cond_destroy(&handle->condition);
2396     free( handle );
2397     stream_.apiHandle = 0;
2398   }
2399
2400   stream_.mode = UNINITIALIZED;
2401 }
2402
2403 void RtApiCore :: startStream()
2404 {
2405   verifyStream();
2406   if (stream_.state == STREAM_RUNNING) return;
2407
2408   MUTEX_LOCK(&stream_.mutex);
2409
2410   OSStatus err;
2411   AudioDeviceID id;
2412   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
2413
2414     id = *( (AudioDeviceID *) devices_[stream_.device[0]].apiDeviceId );
2415     err = AudioDeviceStart(id, callbackHandler);
2416     if (err != noErr) {
2417       sprintf(message_, "RtApiCore: OS-X error starting callback procedure on device (%s).",
2418               devices_[stream_.device[0]].name.c_str());
2419       MUTEX_UNLOCK(&stream_.mutex);
2420       error(RtError::DRIVER_ERROR);
2421     }
2422   }
2423
2424   if (stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1]) ) {
2425
2426     id = *( (AudioDeviceID *) devices_[stream_.device[1]].apiDeviceId );
2427     err = AudioDeviceStart(id, callbackHandler);
2428     if (err != noErr) {
2429       sprintf(message_, "RtApiCore: OS-X error starting input callback procedure on device (%s).",
2430               devices_[stream_.device[0]].name.c_str());
2431       MUTEX_UNLOCK(&stream_.mutex);
2432       error(RtError::DRIVER_ERROR);
2433     }
2434   }
2435
2436   CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
2437   handle->stopStream = false;
2438   stream_.state = STREAM_RUNNING;
2439
2440   MUTEX_UNLOCK(&stream_.mutex);
2441 }
2442
2443 void RtApiCore :: stopStream()
2444 {
2445   verifyStream();
2446   if (stream_.state == STREAM_STOPPED) return;
2447
2448   // Change the state before the lock to improve shutdown response
2449   // when using a callback.
2450   stream_.state = STREAM_STOPPED;
2451   MUTEX_LOCK(&stream_.mutex);
2452
2453   OSStatus err;
2454   AudioDeviceID id;
2455   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
2456
2457     id = *( (AudioDeviceID *) devices_[stream_.device[0]].apiDeviceId );
2458     err = AudioDeviceStop(id, callbackHandler);
2459     if (err != noErr) {
2460       sprintf(message_, "RtApiCore: OS-X error stopping callback procedure on device (%s).",
2461               devices_[stream_.device[0]].name.c_str());
2462       MUTEX_UNLOCK(&stream_.mutex);
2463       error(RtError::DRIVER_ERROR);
2464     }
2465   }
2466
2467   if (stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1]) ) {
2468
2469     id = *( (AudioDeviceID *) devices_[stream_.device[1]].apiDeviceId );
2470     err = AudioDeviceStop(id, callbackHandler);
2471     if (err != noErr) {
2472       sprintf(message_, "RtApiCore: OS-X error stopping input callback procedure on device (%s).",
2473               devices_[stream_.device[0]].name.c_str());
2474       MUTEX_UNLOCK(&stream_.mutex);
2475       error(RtError::DRIVER_ERROR);
2476     }
2477   }
2478
2479   MUTEX_UNLOCK(&stream_.mutex);
2480 }
2481
2482 void RtApiCore :: abortStream()
2483 {
2484   stopStream();
2485 }
2486
2487 void RtApiCore :: tickStream()
2488 {
2489   verifyStream();
2490
2491   if (stream_.state == STREAM_STOPPED) return;
2492
2493   if (stream_.callbackInfo.usingCallback) {
2494     sprintf(message_, "RtApiCore: tickStream() should not be used when a callback function is set!");
2495     error(RtError::WARNING);
2496     return;
2497   }
2498
2499   CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
2500
2501   MUTEX_LOCK(&stream_.mutex);
2502
2503   pthread_cond_wait(&handle->condition, &stream_.mutex);
2504
2505   MUTEX_UNLOCK(&stream_.mutex);
2506 }
2507
2508 void RtApiCore :: callbackEvent( AudioDeviceID deviceId, void *inData, void *outData )
2509 {
2510   verifyStream();
2511
2512   if (stream_.state == STREAM_STOPPED) return;
2513
2514   CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
2515   CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
2516   AudioBufferList *inBufferList = (AudioBufferList *) inData;
2517   AudioBufferList *outBufferList = (AudioBufferList *) outData;
2518
2519   if ( info->usingCallback && handle->stopStream ) {
2520     // Check if the stream should be stopped (via the previous user
2521     // callback return value).  We stop the stream here, rather than
2522     // after the function call, so that output data can first be
2523     // processed.
2524     this->stopStream();
2525     return;
2526   }
2527
2528   MUTEX_LOCK(&stream_.mutex);
2529
2530   // Invoke user callback first, to get fresh output data.  Don't
2531   // invoke the user callback if duplex mode AND the input/output devices
2532   // are different AND this function is called for the input device.
2533   AudioDeviceID id = *( (AudioDeviceID *) devices_[stream_.device[0]].apiDeviceId );
2534   if ( info->usingCallback && (stream_.mode != DUPLEX || deviceId == id ) ) {
2535     RtAudioCallback callback = (RtAudioCallback) info->callback;
2536     handle->stopStream = callback(stream_.userBuffer, stream_.bufferSize, info->userData);
2537     if ( handle->xrun == true ) {
2538       handle->xrun = false;
2539       MUTEX_UNLOCK(&stream_.mutex);
2540       return;
2541     }
2542   }
2543
2544   if ( stream_.mode == OUTPUT || ( stream_.mode == DUPLEX && deviceId == id ) ) {
2545
2546     if (stream_.doConvertBuffer[0]) {
2547
2548       if ( !stream_.deInterleave[0] )
2549         stream_.deviceBuffer = (char *) outBufferList->mBuffers[handle->index[0]].mData;
2550       else
2551         stream_.deviceBuffer = handle->deviceBuffer;
2552
2553       convertBuffer( stream_.deviceBuffer, stream_.userBuffer, stream_.convertInfo[0] );
2554       if ( stream_.doByteSwap[0] )
2555         byteSwapBuffer(stream_.deviceBuffer,
2556                        stream_.bufferSize * stream_.nDeviceChannels[0],
2557                        stream_.deviceFormat[0]);
2558
2559       if ( stream_.deInterleave[0] ) {
2560         int bufferBytes = outBufferList->mBuffers[handle->index[0]].mDataByteSize;
2561         for ( int i=0; i<stream_.nDeviceChannels[0]; i++ ) {
2562           memcpy(outBufferList->mBuffers[handle->index[0]+i].mData,
2563                  &stream_.deviceBuffer[i*bufferBytes], bufferBytes );
2564         }
2565       }
2566
2567     }
2568     else {
2569       if (stream_.doByteSwap[0])
2570         byteSwapBuffer(stream_.userBuffer,
2571                        stream_.bufferSize * stream_.nUserChannels[0],
2572                        stream_.userFormat);
2573
2574       memcpy(outBufferList->mBuffers[handle->index[0]].mData,
2575              stream_.userBuffer,
2576              outBufferList->mBuffers[handle->index[0]].mDataByteSize );
2577     }
2578   }
2579
2580   id = *( (AudioDeviceID *) devices_[stream_.device[1]].apiDeviceId );
2581   if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && deviceId == id ) ) {
2582
2583     if (stream_.doConvertBuffer[1]) {
2584
2585       if ( stream_.deInterleave[1] ) {
2586         stream_.deviceBuffer = (char *) handle->deviceBuffer;
2587         int bufferBytes = inBufferList->mBuffers[handle->index[1]].mDataByteSize;
2588         for ( int i=0; i<stream_.nDeviceChannels[1]; i++ ) {
2589           memcpy(&stream_.deviceBuffer[i*bufferBytes],
2590                  inBufferList->mBuffers[handle->index[1]+i].mData, bufferBytes );
2591         }
2592       }
2593       else
2594         stream_.deviceBuffer = (char *) inBufferList->mBuffers[handle->index[1]].mData;
2595
2596       if ( stream_.doByteSwap[1] )
2597         byteSwapBuffer(stream_.deviceBuffer,
2598                        stream_.bufferSize * stream_.nDeviceChannels[1],
2599                        stream_.deviceFormat[1]);
2600       convertBuffer( stream_.userBuffer, stream_.deviceBuffer, stream_.convertInfo[1] );
2601
2602     }
2603     else {
2604       memcpy(stream_.userBuffer,
2605              inBufferList->mBuffers[handle->index[1]].mData,
2606              inBufferList->mBuffers[handle->index[1]].mDataByteSize );
2607
2608       if (stream_.doByteSwap[1])
2609         byteSwapBuffer(stream_.userBuffer,
2610                        stream_.bufferSize * stream_.nUserChannels[1],
2611                        stream_.userFormat);
2612     }
2613   }
2614
2615   if ( !info->usingCallback && (stream_.mode != DUPLEX || deviceId == id ) )
2616     pthread_cond_signal(&handle->condition);
2617
2618   MUTEX_UNLOCK(&stream_.mutex);
2619 }
2620
2621 void RtApiCore :: setStreamCallback(RtAudioCallback callback, void *userData)
2622 {
2623   verifyStream();
2624
2625   if ( stream_.callbackInfo.usingCallback ) {
2626     sprintf(message_, "RtApiCore: A callback is already set for this stream!");
2627     error(RtError::WARNING);
2628     return;
2629   }
2630
2631   stream_.callbackInfo.callback = (void *) callback;
2632   stream_.callbackInfo.userData = userData;
2633   stream_.callbackInfo.usingCallback = true;
2634 }
2635
2636 void RtApiCore :: cancelStreamCallback()
2637 {
2638   verifyStream();
2639
2640   if (stream_.callbackInfo.usingCallback) {
2641
2642     if (stream_.state == STREAM_RUNNING)
2643       stopStream();
2644
2645     MUTEX_LOCK(&stream_.mutex);
2646
2647     stream_.callbackInfo.usingCallback = false;
2648     stream_.callbackInfo.userData = NULL;
2649     stream_.state = STREAM_STOPPED;
2650     stream_.callbackInfo.callback = NULL;
2651
2652     MUTEX_UNLOCK(&stream_.mutex);
2653   }
2654 }
2655
2656
2657 //******************** End of __MACOSX_CORE__ *********************//
2658 #endif
2659
2660 #if defined(__LINUX_JACK__)
2661
2662 // JACK is a low-latency audio server, written primarily for the
2663 // GNU/Linux operating system. It can connect a number of different
2664 // applications to an audio device, as well as allowing them to share
2665 // audio between themselves.
2666 //
2667 // The JACK server must be running before RtApiJack can be instantiated.
2668 // RtAudio will report just a single "device", which is the JACK audio
2669 // server.  The JACK server is typically started in a terminal as follows:
2670 //
2671 // .jackd -d alsa -d hw:0
2672 //
2673 // or through an interface program such as qjackctl.  Many of the
2674 // parameters normally set for a stream are fixed by the JACK server
2675 // and can be specified when the JACK server is started.  In
2676 // particular,
2677 //
2678 // .jackd -d alsa -d hw:0 -r 44100 -p 512 -n 4
2679 //
2680 // specifies a sample rate of 44100 Hz, a buffer size of 512 sample
2681 // frames, and number of buffers = 4.  Once the server is running, it
2682 // is not possible to override these values.  If the values are not
2683 // specified in the command-line, the JACK server uses default values.
2684
2685 #include <jack/jack.h>
2686 #include <unistd.h>
2687
2688 // A structure to hold various information related to the Jack API
2689 // implementation.
2690 struct JackHandle {
2691   jack_client_t *client;
2692   jack_port_t **ports[2];
2693   bool clientOpen;
2694   bool stopStream;
2695   pthread_cond_t condition;
2696
2697   JackHandle()
2698     :client(0), clientOpen(false), stopStream(false) {}
2699 };
2700
2701 std::string jackmsg;
2702
2703 static void jackerror (const char *desc)
2704 {
2705   jackmsg.erase();
2706   jackmsg.append( desc, strlen(desc)+1 );
2707 }
2708
2709 RtApiJack :: RtApiJack()
2710 {
2711   this->initialize();
2712
2713   if (nDevices_ <= 0) {
2714     sprintf(message_, "RtApiJack: no Linux Jack server found or connection error (jack: %s)!",
2715             jackmsg.c_str());
2716     error(RtError::NO_DEVICES_FOUND);
2717   }
2718 }
2719
2720 RtApiJack :: ~RtApiJack()
2721 {
2722   if ( stream_.mode != UNINITIALIZED ) closeStream();
2723 }
2724
2725 void RtApiJack :: initialize(void)
2726 {
2727   nDevices_ = 0;
2728
2729   // Tell the jack server to call jackerror() when it experiences an
2730   // error.  This function saves the error message for subsequent
2731   // reporting via the normal RtAudio error function.
2732         jack_set_error_function( jackerror );
2733
2734   // Look for jack server and try to become a client.
2735   jack_client_t *client;
2736   if ( (client = jack_client_new( "RtApiJack" )) == 0)
2737     return;
2738
2739   /*
2740     RtApiDevice device;
2741     // Determine the name of the device.
2742     device.name = "Jack Server";
2743     devices_.push_back(device);
2744     nDevices_++;
2745   */
2746   const char **ports;
2747   std::string port, prevPort;
2748   unsigned int nChannels = 0;
2749   ports = jack_get_ports( client, NULL, NULL, 0 );
2750   if ( ports ) {
2751     port = (char *) ports[ nChannels ];
2752     unsigned int colonPos = 0;
2753     do {
2754       port = (char *) ports[ nChannels ];
2755       if ( (colonPos = port.find(":")) != std::string::npos ) {
2756         port = port.substr( 0, colonPos+1 );
2757         if ( port != prevPort ) {
2758           RtApiDevice device;
2759           device.name = port;
2760           devices_.push_back( device );
2761           nDevices_++;
2762           prevPort = port;
2763         }
2764       }
2765     } while ( ports[++nChannels] );
2766     free( ports );
2767   }
2768
2769   jack_client_close(client);
2770 }
2771
2772 void RtApiJack :: probeDeviceInfo(RtApiDevice *info)
2773 {
2774   // Look for jack server and try to become a client.
2775   jack_client_t *client;
2776   if ( (client = jack_client_new( "RtApiJack_Probe" )) == 0) {
2777     sprintf(message_, "RtApiJack: error connecting to Linux Jack server in probeDeviceInfo() (jack: %s)!",
2778             jackmsg.c_str());
2779     error(RtError::WARNING);
2780     return;
2781   }
2782
2783   // Get the current jack server sample rate.
2784   info->sampleRates.clear();
2785   info->sampleRates.push_back( jack_get_sample_rate(client) );
2786
2787   // Count the available ports as device channels.  Jack "input ports"
2788   // equal RtAudio output channels.
2789   const char **ports;
2790   char *port;
2791   unsigned int nChannels = 0;
2792   ports = jack_get_ports( client, info->name.c_str(), NULL, JackPortIsInput );
2793   if ( ports ) {
2794     port = (char *) ports[nChannels];
2795     while ( port )
2796       port = (char *) ports[++nChannels];
2797     free( ports );
2798     info->maxOutputChannels = nChannels;
2799     info->minOutputChannels = 1;
2800   }
2801
2802   // Jack "output ports" equal RtAudio input channels.
2803   nChannels = 0;
2804   ports = jack_get_ports( client, info->name.c_str(), NULL, JackPortIsOutput );
2805   if ( ports ) {
2806     port = (char *) ports[nChannels];
2807     while ( port )
2808       port = (char *) ports[++nChannels];
2809     free( ports );
2810     info->maxInputChannels = nChannels;
2811     info->minInputChannels = 1;
2812   }
2813
2814   if (info->maxOutputChannels == 0 && info->maxInputChannels == 0) {
2815     jack_client_close(client);
2816     sprintf(message_, "RtApiJack: error determining jack input/output channels!");
2817     error(RtError::DEBUG_WARNING);
2818     return;
2819   }
2820
2821   if (info->maxOutputChannels > 0 && info->maxInputChannels > 0) {
2822     info->hasDuplexSupport = true;
2823     info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
2824       info->maxInputChannels : info->maxOutputChannels;
2825     info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
2826       info->minInputChannels : info->minOutputChannels;
2827   }
2828
2829   // Get the jack data format type.  There isn't much documentation
2830   // regarding supported data formats in jack.  I'm assuming here that
2831   // the default type will always be a floating-point type, of length
2832   // equal to either 4 or 8 bytes.
2833   int sample_size = sizeof( jack_default_audio_sample_t );
2834   if ( sample_size == 4 )
2835     info->nativeFormats = RTAUDIO_FLOAT32;
2836   else if ( sample_size == 8 )
2837     info->nativeFormats = RTAUDIO_FLOAT64;
2838
2839   // Check that we have a supported format
2840   if (info->nativeFormats == 0) {
2841     jack_client_close(client);
2842     sprintf(message_, "RtApiJack: error determining jack server data format!");
2843     error(RtError::DEBUG_WARNING);
2844     return;
2845   }
2846
2847   jack_client_close(client);
2848   info->probed = true;
2849 }
2850
2851 int jackCallbackHandler(jack_nframes_t nframes, void *infoPointer)
2852 {
2853   CallbackInfo *info = (CallbackInfo *) infoPointer;
2854   RtApiJack *object = (RtApiJack *) info->object;
2855   try {
2856     object->callbackEvent( (unsigned long) nframes );
2857   }
2858   catch (RtError &exception) {
2859     fprintf(stderr, "\nRtApiJack: callback handler error (%s)!\n\n", exception.getMessageString());
2860     return 0;
2861   }
2862
2863   return 0;
2864 }
2865
2866 void jackShutdown(void *infoPointer)
2867 {
2868   CallbackInfo *info = (CallbackInfo *) infoPointer;
2869   JackHandle *handle = (JackHandle *) info->apiInfo;
2870   handle->clientOpen = false;
2871   RtApiJack *object = (RtApiJack *) info->object;
2872
2873   // Check current stream state.  If stopped, then we'll assume this
2874   // was called as a result of a call to RtApiJack::stopStream (the
2875   // deactivation of a client handle causes this function to be called).
2876   // If not, we'll assume the Jack server is shutting down or some
2877   // other problem occurred and we should close the stream.
2878   if ( object->getStreamState() == RtApi::STREAM_STOPPED ) return;
2879
2880   try {
2881     object->closeStream();
2882   }
2883   catch (RtError &exception) {
2884     fprintf(stderr, "\nRtApiJack: jackShutdown error (%s)!\n\n", exception.getMessageString());
2885     return;
2886   }
2887
2888   fprintf(stderr, "\nRtApiJack: the Jack server is shutting down this client ... stream stopped and closed!!!\n\n");
2889 }
2890
2891 int jackXrun( void * )
2892 {
2893   fprintf(stderr, "\nRtApiJack: audio overrun/underrun reported!\n");
2894   return 0;
2895 }
2896
2897 bool RtApiJack :: probeDeviceOpen(int device, StreamMode mode, int channels, 
2898                                 int sampleRate, RtAudioFormat format,
2899                                 int *bufferSize, int numberOfBuffers)
2900 {
2901   // Compare the jack server channels to the requested number of channels.
2902   if ( (mode == OUTPUT && devices_[device].maxOutputChannels < channels ) || 
2903        (mode == INPUT && devices_[device].maxInputChannels < channels ) ) {
2904     sprintf(message_, "RtApiJack: the Jack server does not support requested channels!");
2905     error(RtError::DEBUG_WARNING);
2906     return FAILURE;
2907   }
2908
2909   JackHandle *handle = (JackHandle *) stream_.apiHandle;
2910
2911   // Look for jack server and try to become a client (only do once per stream).
2912   char label[32];
2913   jack_client_t *client = 0;
2914   if ( mode == OUTPUT || (mode == INPUT && stream_.mode != OUTPUT) ) {
2915     snprintf(label, 32, "RtApiJack");
2916     if ( (client = jack_client_new( (const char *) label )) == 0) {
2917       sprintf(message_, "RtApiJack: cannot connect to Linux Jack server in probeDeviceOpen() (jack: %s)!",
2918               jackmsg.c_str());
2919       error(RtError::DEBUG_WARNING);
2920       return FAILURE;
2921     }
2922   }
2923   else {
2924     // The handle must have been created on an earlier pass.
2925     client = handle->client;
2926   }
2927
2928   // First, check the jack server sample rate.
2929   int jack_rate;
2930   jack_rate = (int) jack_get_sample_rate(client);
2931   if ( sampleRate != jack_rate ) {
2932     jack_client_close(client);
2933     sprintf( message_, "RtApiJack: the requested sample rate (%d) is different than the JACK server rate (%d).",
2934              sampleRate, jack_rate );
2935     error(RtError::DEBUG_WARNING);
2936     return FAILURE;
2937   }
2938   stream_.sampleRate = jack_rate;
2939
2940   // The jack server seems to support just a single floating-point
2941   // data type.  Since we already checked it before, just use what we
2942   // found then.
2943   stream_.deviceFormat[mode] = devices_[device].nativeFormats;
2944   stream_.userFormat = format;
2945
2946   // Jack always uses non-interleaved buffers.  We'll need to
2947   // de-interleave if we have more than one channel.
2948   stream_.deInterleave[mode] = false;
2949   if ( channels > 1 )
2950     stream_.deInterleave[mode] = true;
2951
2952   // Jack always provides host byte-ordered data.
2953   stream_.doByteSwap[mode] = false;
2954
2955   // Get the buffer size.  The buffer size and number of buffers
2956   // (periods) is set when the jack server is started.
2957   stream_.bufferSize = (int) jack_get_buffer_size(client);
2958   *bufferSize = stream_.bufferSize;
2959
2960   stream_.nDeviceChannels[mode] = channels;
2961   stream_.nUserChannels[mode] = channels;
2962
2963   stream_.doConvertBuffer[mode] = false;
2964   if (stream_.userFormat != stream_.deviceFormat[mode])
2965     stream_.doConvertBuffer[mode] = true;
2966   if (stream_.deInterleave[mode])
2967     stream_.doConvertBuffer[mode] = true;
2968
2969   // Allocate our JackHandle structure for the stream.
2970   if ( handle == 0 ) {
2971     handle = (JackHandle *) calloc(1, sizeof(JackHandle));
2972     if ( handle == NULL ) {
2973       sprintf(message_, "RtApiJack: error allocating JackHandle memory (%s).",
2974               devices_[device].name.c_str());
2975       goto error;
2976     }
2977     handle->ports[0] = 0;
2978     handle->ports[1] = 0;
2979     if ( pthread_cond_init(&handle->condition, NULL) ) {
2980       sprintf(message_, "RtApiJack: error initializing pthread condition variable!");
2981       goto error;
2982     }
2983     stream_.apiHandle = (void *) handle;
2984     handle->client = client;
2985     handle->clientOpen = true;
2986   }
2987
2988   // Allocate necessary internal buffers.
2989   if ( stream_.nUserChannels[0] != stream_.nUserChannels[1] ) {
2990
2991     long buffer_bytes;
2992     if (stream_.nUserChannels[0] >= stream_.nUserChannels[1])
2993       buffer_bytes = stream_.nUserChannels[0];
2994     else
2995       buffer_bytes = stream_.nUserChannels[1];
2996
2997     buffer_bytes *= *bufferSize * formatBytes(stream_.userFormat);
2998     if (stream_.userBuffer) free(stream_.userBuffer);
2999     stream_.userBuffer = (char *) calloc(buffer_bytes, 1);
3000     if (stream_.userBuffer == NULL) {
3001       sprintf(message_, "RtApiJack: error allocating user buffer memory (%s).",
3002               devices_[device].name.c_str());
3003       goto error;
3004     }
3005   }
3006
3007   if ( stream_.doConvertBuffer[mode] ) {
3008
3009     long buffer_bytes;
3010     bool makeBuffer = true;
3011     if ( mode == OUTPUT )
3012       buffer_bytes = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
3013     else { // mode == INPUT
3014       buffer_bytes = stream_.nDeviceChannels[1] * formatBytes(stream_.deviceFormat[1]);
3015       if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
3016         long bytes_out = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
3017         if ( buffer_bytes < bytes_out ) makeBuffer = false;
3018       }
3019     }
3020
3021     if ( makeBuffer ) {
3022       buffer_bytes *= *bufferSize;
3023       if (stream_.deviceBuffer) free(stream_.deviceBuffer);
3024       stream_.deviceBuffer = (char *) calloc(buffer_bytes, 1);
3025       if (stream_.deviceBuffer == NULL) {
3026         sprintf(message_, "RtApiJack: error allocating device buffer memory (%s).",
3027                 devices_[device].name.c_str());
3028         goto error;
3029       }
3030     }
3031   }
3032
3033   // Allocate memory for the Jack ports (channels) identifiers.
3034   handle->ports[mode] = (jack_port_t **) malloc (sizeof (jack_port_t *) * channels);
3035   if ( handle->ports[mode] == NULL )  {
3036     sprintf(message_, "RtApiJack: error allocating port handle memory (%s).",
3037             devices_[device].name.c_str());
3038     goto error;
3039   }
3040
3041   stream_.device[mode] = device;
3042   stream_.state = STREAM_STOPPED;
3043   stream_.callbackInfo.usingCallback = false;
3044   stream_.callbackInfo.object = (void *) this;
3045   stream_.callbackInfo.apiInfo = (void *) handle;
3046
3047   if ( stream_.mode == OUTPUT && mode == INPUT )
3048     // We had already set up the stream for output.
3049     stream_.mode = DUPLEX;
3050   else {
3051     stream_.mode = mode;
3052     jack_set_process_callback( handle->client, jackCallbackHandler, (void *) &stream_.callbackInfo );
3053     jack_set_xrun_callback( handle->client, jackXrun, NULL );
3054     jack_on_shutdown( handle->client, jackShutdown, (void *) &stream_.callbackInfo );
3055   }
3056
3057   // Setup the buffer conversion information structure.
3058   if ( stream_.doConvertBuffer[mode] ) {
3059     if (mode == INPUT) { // convert device to user buffer
3060       stream_.convertInfo[mode].inJump = stream_.nDeviceChannels[1];
3061       stream_.convertInfo[mode].outJump = stream_.nUserChannels[1];
3062       stream_.convertInfo[mode].inFormat = stream_.deviceFormat[1];
3063       stream_.convertInfo[mode].outFormat = stream_.userFormat;
3064     }
3065     else { // convert user to device buffer
3066       stream_.convertInfo[mode].inJump = stream_.nUserChannels[0];
3067       stream_.convertInfo[mode].outJump = stream_.nDeviceChannels[0];
3068       stream_.convertInfo[mode].inFormat = stream_.userFormat;
3069       stream_.convertInfo[mode].outFormat = stream_.deviceFormat[0];
3070     }
3071
3072     if ( stream_.convertInfo[mode].inJump < stream_.convertInfo[mode].outJump )
3073       stream_.convertInfo[mode].channels = stream_.convertInfo[mode].inJump;
3074     else
3075       stream_.convertInfo[mode].channels = stream_.convertInfo[mode].outJump;
3076
3077     // Set up the interleave/deinterleave offsets.
3078     if ( mode == INPUT && stream_.deInterleave[1] ) {
3079       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
3080         stream_.convertInfo[mode].inOffset.push_back( k * stream_.bufferSize );
3081         stream_.convertInfo[mode].outOffset.push_back( k );
3082         stream_.convertInfo[mode].inJump = 1;
3083       }
3084     }
3085     else if (mode == OUTPUT && stream_.deInterleave[0]) {
3086       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
3087         stream_.convertInfo[mode].inOffset.push_back( k );
3088         stream_.convertInfo[mode].outOffset.push_back( k * stream_.bufferSize );
3089         stream_.convertInfo[mode].outJump = 1;
3090       }
3091     }
3092     else {
3093       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
3094         stream_.convertInfo[mode].inOffset.push_back( k );
3095         stream_.convertInfo[mode].outOffset.push_back( k );
3096       }
3097     }
3098   }
3099
3100   return SUCCESS;
3101
3102  error:
3103   if ( handle ) {
3104     pthread_cond_destroy(&handle->condition);
3105     if ( handle->clientOpen == true )
3106       jack_client_close(handle->client);
3107
3108     if ( handle->ports[0] ) free(handle->ports[0]);
3109     if ( handle->ports[1] ) free(handle->ports[1]);
3110
3111     free( handle );
3112     stream_.apiHandle = 0;
3113   }
3114
3115   if (stream_.userBuffer) {
3116     free(stream_.userBuffer);
3117     stream_.userBuffer = 0;
3118   }
3119
3120   error(RtError::DEBUG_WARNING);
3121   return FAILURE;
3122 }
3123
3124 void RtApiJack :: closeStream()
3125 {
3126   // We don't want an exception to be thrown here because this
3127   // function is called by our class destructor.  So, do our own
3128   // stream check.
3129   if ( stream_.mode == UNINITIALIZED ) {
3130     sprintf(message_, "RtApiJack::closeStream(): no open stream to close!");
3131     error(RtError::WARNING);
3132     return;
3133   }
3134
3135   JackHandle *handle = (JackHandle *) stream_.apiHandle;
3136   if ( handle && handle->clientOpen == true ) {
3137     if (stream_.state == STREAM_RUNNING)
3138       jack_deactivate(handle->client);
3139
3140     jack_client_close(handle->client);
3141   }
3142
3143   if ( handle ) {
3144     if ( handle->ports[0] ) free(handle->ports[0]);
3145     if ( handle->ports[1] ) free(handle->ports[1]);
3146     pthread_cond_destroy(&handle->condition);
3147     free( handle );
3148     stream_.apiHandle = 0;
3149   }
3150
3151   if (stream_.userBuffer) {
3152     free(stream_.userBuffer);
3153     stream_.userBuffer = 0;
3154   }
3155
3156   if (stream_.deviceBuffer) {
3157     free(stream_.deviceBuffer);
3158     stream_.deviceBuffer = 0;
3159   }
3160
3161   stream_.mode = UNINITIALIZED;
3162 }
3163
3164
3165 void RtApiJack :: startStream()
3166 {
3167   verifyStream();
3168   if (stream_.state == STREAM_RUNNING) return;
3169
3170   MUTEX_LOCK(&stream_.mutex);
3171
3172   char label[64];
3173   JackHandle *handle = (JackHandle *) stream_.apiHandle;
3174   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
3175     for ( int i=0; i<stream_.nUserChannels[0]; i++ ) {
3176       snprintf(label, 64, "outport %d", i);
3177       handle->ports[0][i] = jack_port_register(handle->client, (const char *)label,
3178                                                JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
3179     }
3180   }
3181
3182   if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
3183     for ( int i=0; i<stream_.nUserChannels[1]; i++ ) {
3184       snprintf(label, 64, "inport %d", i);
3185       handle->ports[1][i] = jack_port_register(handle->client, (const char *)label,
3186                                                JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
3187     }
3188   }
3189
3190   if (jack_activate(handle->client)) {
3191     sprintf(message_, "RtApiJack: unable to activate JACK client!");
3192     error(RtError::SYSTEM_ERROR);
3193   }
3194
3195   const char **ports;
3196   int result;
3197   // Get the list of available ports.
3198   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
3199     ports = jack_get_ports(handle->client, devices_[stream_.device[0]].name.c_str(), NULL, JackPortIsInput);
3200     if ( ports == NULL) {
3201       sprintf(message_, "RtApiJack: error determining available jack input ports!");
3202       error(RtError::SYSTEM_ERROR);
3203     }
3204
3205     // Now make the port connections.  Since RtAudio wasn't designed to
3206     // allow the user to select particular channels of a device, we'll
3207     // just open the first "nChannels" ports.
3208     for ( int i=0; i<stream_.nUserChannels[0]; i++ ) {
3209       result = 1;
3210       if ( ports[i] )
3211         result = jack_connect( handle->client, jack_port_name(handle->ports[0][i]), ports[i] );
3212       if ( result ) {
3213         free(ports);
3214         sprintf(message_, "RtApiJack: error connecting output ports!");
3215         error(RtError::SYSTEM_ERROR);
3216       }
3217     }
3218     free(ports);
3219   }
3220
3221   if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
3222     ports = jack_get_ports( handle->client, devices_[stream_.device[1]].name.c_str(), NULL, JackPortIsOutput );
3223     if ( ports == NULL) {
3224       sprintf(message_, "RtApiJack: error determining available jack output ports!");
3225       error(RtError::SYSTEM_ERROR);
3226     }
3227
3228     // Now make the port connections.  See note above.
3229     for ( int i=0; i<stream_.nUserChannels[1]; i++ ) {
3230       result = 1;
3231       if ( ports[i] )
3232         result = jack_connect( handle->client, ports[i], jack_port_name(handle->ports[1][i]) );
3233       if ( result ) {
3234         free(ports);
3235         sprintf(message_, "RtApiJack: error connecting input ports!");
3236         error(RtError::SYSTEM_ERROR);
3237       }
3238     }
3239     free(ports);
3240   }
3241
3242   handle->stopStream = false;
3243   stream_.state = STREAM_RUNNING;
3244
3245   MUTEX_UNLOCK(&stream_.mutex);
3246 }
3247
3248 void RtApiJack :: stopStream()
3249 {
3250   verifyStream();
3251   if (stream_.state == STREAM_STOPPED) return;
3252
3253   // Change the state before the lock to improve shutdown response
3254   // when using a callback.
3255   stream_.state = STREAM_STOPPED;
3256   MUTEX_LOCK(&stream_.mutex);
3257
3258   JackHandle *handle = (JackHandle *) stream_.apiHandle;
3259   jack_deactivate(handle->client);
3260
3261   MUTEX_UNLOCK(&stream_.mutex);
3262 }
3263
3264 void RtApiJack :: abortStream()
3265 {
3266   stopStream();
3267 }
3268
3269 void RtApiJack :: tickStream()
3270 {
3271   verifyStream();
3272
3273   if (stream_.state == STREAM_STOPPED) return;
3274
3275   if (stream_.callbackInfo.usingCallback) {
3276     sprintf(message_, "RtApiJack: tickStream() should not be used when a callback function is set!");
3277     error(RtError::WARNING);
3278     return;
3279   }
3280
3281   JackHandle *handle = (JackHandle *) stream_.apiHandle;
3282
3283   MUTEX_LOCK(&stream_.mutex);
3284
3285   pthread_cond_wait(&handle->condition, &stream_.mutex);
3286
3287   MUTEX_UNLOCK(&stream_.mutex);
3288 }
3289
3290 void RtApiJack :: callbackEvent( unsigned long nframes )
3291 {
3292   verifyStream();
3293
3294   if (stream_.state == STREAM_STOPPED) return;
3295
3296   CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
3297   JackHandle *handle = (JackHandle *) stream_.apiHandle;
3298   if ( info->usingCallback && handle->stopStream ) {
3299     // Check if the stream should be stopped (via the previous user
3300     // callback return value).  We stop the stream here, rather than
3301     // after the function call, so that output data can first be
3302     // processed.
3303     this->stopStream();
3304     return;
3305   }
3306
3307   MUTEX_LOCK(&stream_.mutex);
3308
3309   // Invoke user callback first, to get fresh output data.
3310   if ( info->usingCallback ) {
3311     RtAudioCallback callback = (RtAudioCallback) info->callback;
3312     handle->stopStream = callback(stream_.userBuffer, stream_.bufferSize, info->userData);
3313   }
3314
3315   jack_default_audio_sample_t *jackbuffer;
3316   long bufferBytes = nframes * sizeof(jack_default_audio_sample_t);
3317   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
3318
3319     if (stream_.doConvertBuffer[0]) {
3320       convertBuffer( stream_.deviceBuffer, stream_.userBuffer, stream_.convertInfo[0] );
3321
3322       for ( int i=0; i<stream_.nDeviceChannels[0]; i++ ) {
3323         jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(handle->ports[0][i],
3324                                                                           (jack_nframes_t) nframes);
3325         memcpy(jackbuffer, &stream_.deviceBuffer[i*bufferBytes], bufferBytes );
3326       }
3327     }
3328     else { // single channel only
3329       jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(handle->ports[0][0],
3330                                                                         (jack_nframes_t) nframes);
3331       memcpy(jackbuffer, stream_.userBuffer, bufferBytes );
3332     }
3333   }
3334
3335   if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
3336
3337     if (stream_.doConvertBuffer[1]) {
3338     for ( int i=0; i<stream_.nDeviceChannels[1]; i++ ) {
3339       jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(handle->ports[1][i],
3340                                                                         (jack_nframes_t) nframes);
3341       memcpy(&stream_.deviceBuffer[i*bufferBytes], jackbuffer, bufferBytes );
3342     }
3343     convertBuffer( stream_.userBuffer, stream_.deviceBuffer, stream_.convertInfo[1] );
3344     }
3345     else { // single channel only
3346       jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(handle->ports[1][0],
3347                                                                         (jack_nframes_t) nframes);
3348       memcpy(stream_.userBuffer, jackbuffer, bufferBytes );
3349     }
3350   }
3351
3352   if ( !info->usingCallback )
3353     pthread_cond_signal(&handle->condition);
3354
3355   MUTEX_UNLOCK(&stream_.mutex);
3356 }
3357
3358 void RtApiJack :: setStreamCallback(RtAudioCallback callback, void *userData)
3359 {
3360   verifyStream();
3361
3362   if ( stream_.callbackInfo.usingCallback ) {
3363     sprintf(message_, "RtApiJack: A callback is already set for this stream!");
3364     error(RtError::WARNING);
3365     return;
3366   }
3367
3368   stream_.callbackInfo.callback = (void *) callback;
3369   stream_.callbackInfo.userData = userData;
3370   stream_.callbackInfo.usingCallback = true;
3371 }
3372
3373 void RtApiJack :: cancelStreamCallback()
3374 {
3375   verifyStream();
3376
3377   if (stream_.callbackInfo.usingCallback) {
3378
3379     if (stream_.state == STREAM_RUNNING)
3380       stopStream();
3381
3382     MUTEX_LOCK(&stream_.mutex);
3383
3384     stream_.callbackInfo.usingCallback = false;
3385     stream_.callbackInfo.userData = NULL;
3386     stream_.state = STREAM_STOPPED;
3387     stream_.callbackInfo.callback = NULL;
3388
3389     MUTEX_UNLOCK(&stream_.mutex);
3390   }
3391 }
3392
3393 #endif
3394
3395 #if defined(__LINUX_ALSA__)
3396
3397 #include <alsa/asoundlib.h>
3398 #include <unistd.h>
3399 #include <ctype.h>
3400
3401 // A structure to hold various information related to the ALSA API
3402 // implementation.
3403 struct AlsaHandle {
3404   snd_pcm_t *handles[2];
3405   bool synchronized;
3406   char *tempBuffer;
3407
3408   AlsaHandle()
3409     :synchronized(false), tempBuffer(0) {}
3410 };
3411
3412 extern "C" void *alsaCallbackHandler(void * ptr);
3413
3414 RtApiAlsa :: RtApiAlsa()
3415 {
3416   this->initialize();
3417
3418   if (nDevices_ <= 0) {
3419     sprintf(message_, "RtApiAlsa: no Linux ALSA audio devices found!");
3420     error(RtError::NO_DEVICES_FOUND);
3421   }
3422 }
3423
3424 RtApiAlsa :: ~RtApiAlsa()
3425 {
3426   if ( stream_.mode != UNINITIALIZED )
3427     closeStream();
3428 }
3429
3430 void RtApiAlsa :: initialize(void)
3431 {
3432   int card, subdevice, result;
3433   char name[64];
3434   const char *cardId;
3435   snd_ctl_t *handle;
3436   snd_ctl_card_info_t *info;
3437   snd_ctl_card_info_alloca(&info);
3438   RtApiDevice device;
3439
3440   // Count cards and devices
3441   nDevices_ = 0;
3442   card = -1;
3443   snd_card_next(&card);
3444   while ( card >= 0 ) {
3445     sprintf(name, "hw:%d", card);
3446     result = snd_ctl_open(&handle, name, 0);
3447     if (result < 0) {
3448       sprintf(message_, "RtApiAlsa: control open (%i): %s.", card, snd_strerror(result));
3449       error(RtError::DEBUG_WARNING);
3450       goto next_card;
3451                 }
3452     result = snd_ctl_card_info(handle, info);
3453                 if (result < 0) {
3454       sprintf(message_, "RtApiAlsa: control hardware info (%i): %s.", card, snd_strerror(result));
3455       error(RtError::DEBUG_WARNING);
3456       goto next_card;
3457                 }
3458     cardId = snd_ctl_card_info_get_id(info);
3459                 subdevice = -1;
3460                 while (1) {
3461       result = snd_ctl_pcm_next_device(handle, &subdevice);
3462                         if (result < 0) {
3463         sprintf(message_, "RtApiAlsa: control next device (%i): %s.", card, snd_strerror(result));
3464         error(RtError::DEBUG_WARNING);
3465         break;
3466       }
3467                         if (subdevice < 0)
3468         break;
3469       sprintf( name, "hw:%d,%d", card, subdevice );
3470       // If a cardId exists and it contains at least one non-numeric
3471       // character, use it to identify the device.  This avoids a bug
3472       // in ALSA such that a numeric string is interpreted as a device
3473       // number.
3474       for ( unsigned int i=0; i<strlen(cardId); i++ ) {
3475         if ( !isdigit( cardId[i] ) ) {
3476           sprintf( name, "hw:%s,%d", cardId, subdevice );
3477           break;
3478         }
3479       }
3480       device.name.erase();
3481       device.name.append( (const char *)name, strlen(name)+1 );
3482       devices_.push_back(device);
3483       nDevices_++;
3484     }
3485   next_card:
3486     snd_ctl_close(handle);
3487     snd_card_next(&card);
3488   }
3489 }
3490
3491 void RtApiAlsa :: probeDeviceInfo(RtApiDevice *info)
3492 {
3493   int err;
3494   int open_mode = SND_PCM_ASYNC;
3495   snd_pcm_t *handle;
3496   snd_ctl_t *chandle;
3497   snd_pcm_stream_t stream;
3498         snd_pcm_info_t *pcminfo;
3499         snd_pcm_info_alloca(&pcminfo);
3500   snd_pcm_hw_params_t *params;
3501   snd_pcm_hw_params_alloca(&params);
3502   char name[64];
3503   char *card;
3504
3505   // Open the control interface for this card.
3506   strncpy( name, info->name.c_str(), 64 );
3507   card = strtok(name, ",");
3508   err = snd_ctl_open(&chandle, card, SND_CTL_NONBLOCK);
3509   if (err < 0) {
3510     sprintf(message_, "RtApiAlsa: control open (%s): %s.", card, snd_strerror(err));
3511     error(RtError::DEBUG_WARNING);
3512     return;
3513   }
3514   unsigned int dev = (unsigned int) atoi( strtok(NULL, ",") );
3515
3516   // First try for playback
3517   stream = SND_PCM_STREAM_PLAYBACK;
3518   snd_pcm_info_set_device(pcminfo, dev);
3519   snd_pcm_info_set_subdevice(pcminfo, 0);
3520   snd_pcm_info_set_stream(pcminfo, stream);
3521
3522   if ((err = snd_ctl_pcm_info(chandle, pcminfo)) < 0) {
3523     if (err == -ENOENT) {
3524       sprintf(message_, "RtApiAlsa: pcm device (%s) doesn't handle output!", info->name.c_str());
3525       error(RtError::DEBUG_WARNING);
3526     }
3527     else {
3528       sprintf(message_, "RtApiAlsa: snd_ctl_pcm_info error for device (%s) output: %s",
3529               info->name.c_str(), snd_strerror(err));
3530       error(RtError::DEBUG_WARNING);
3531     }
3532     goto capture_probe;
3533   }
3534
3535   err = snd_pcm_open(&handle, info->name.c_str(), stream, open_mode | SND_PCM_NONBLOCK );
3536   if (err < 0) {
3537     if ( err == EBUSY )
3538       sprintf(message_, "RtApiAlsa: pcm playback device (%s) is busy: %s.",
3539               info->name.c_str(), snd_strerror(err));
3540     else
3541       sprintf(message_, "RtApiAlsa: pcm playback open (%s) error: %s.",
3542               info->name.c_str(), snd_strerror(err));
3543     error(RtError::DEBUG_WARNING);
3544     goto capture_probe;
3545   }
3546
3547   // We have an open device ... allocate the parameter structure.
3548   err = snd_pcm_hw_params_any(handle, params);
3549   if (err < 0) {
3550     snd_pcm_close(handle);
3551     sprintf(message_, "RtApiAlsa: hardware probe error (%s): %s.",
3552             info->name.c_str(), snd_strerror(err));
3553     error(RtError::DEBUG_WARNING);
3554     goto capture_probe;
3555   }
3556
3557   // Get output channel information.
3558   unsigned int value;
3559   err = snd_pcm_hw_params_get_channels_min(params, &value);
3560   if (err < 0) {
3561     snd_pcm_close(handle);
3562     sprintf(message_, "RtApiAlsa: hardware minimum channel probe error (%s): %s.",
3563             info->name.c_str(), snd_strerror(err));
3564     error(RtError::DEBUG_WARNING);
3565     goto capture_probe;
3566   }
3567   info->minOutputChannels = value;
3568
3569   err = snd_pcm_hw_params_get_channels_max(params, &value);
3570   if (err < 0) {
3571     snd_pcm_close(handle);
3572     sprintf(message_, "RtApiAlsa: hardware maximum channel probe error (%s): %s.",
3573             info->name.c_str(), snd_strerror(err));
3574     error(RtError::DEBUG_WARNING);
3575     goto capture_probe;
3576   }
3577   info->maxOutputChannels = value;
3578
3579   snd_pcm_close(handle);
3580
3581  capture_probe:
3582   // Now try for capture
3583   stream = SND_PCM_STREAM_CAPTURE;
3584   snd_pcm_info_set_stream(pcminfo, stream);
3585
3586   err = snd_ctl_pcm_info(chandle, pcminfo);
3587   snd_ctl_close(chandle);
3588   if ( err < 0 ) {
3589     if (err == -ENOENT) {
3590       sprintf(message_, "RtApiAlsa: pcm device (%s) doesn't handle input!", info->name.c_str());
3591       error(RtError::DEBUG_WARNING);
3592     }
3593     else {
3594       sprintf(message_, "RtApiAlsa: snd_ctl_pcm_info error for device (%s) input: %s",
3595               info->name.c_str(), snd_strerror(err));
3596       error(RtError::DEBUG_WARNING);
3597     }
3598     if (info->maxOutputChannels == 0)
3599       // didn't open for playback either ... device invalid
3600       return;
3601     goto probe_parameters;
3602   }
3603
3604   err = snd_pcm_open(&handle, info->name.c_str(), stream, open_mode | SND_PCM_NONBLOCK);
3605   if (err < 0) {
3606     if ( err == EBUSY )
3607       sprintf(message_, "RtApiAlsa: pcm capture device (%s) is busy: %s.",
3608               info->name.c_str(), snd_strerror(err));
3609     else
3610       sprintf(message_, "RtApiAlsa: pcm capture open (%s) error: %s.",
3611               info->name.c_str(), snd_strerror(err));
3612     error(RtError::DEBUG_WARNING);
3613     if (info->maxOutputChannels == 0)
3614       // didn't open for playback either ... device invalid
3615       return;
3616     goto probe_parameters;
3617   }
3618
3619   // We have an open capture device ... allocate the parameter structure.
3620   err = snd_pcm_hw_params_any(handle, params);
3621   if (err < 0) {
3622     snd_pcm_close(handle);
3623     sprintf(message_, "RtApiAlsa: hardware probe error (%s): %s.",
3624             info->name.c_str(), snd_strerror(err));
3625     error(RtError::DEBUG_WARNING);
3626     if (info->maxOutputChannels > 0)
3627       goto probe_parameters;
3628     else
3629       return;
3630   }
3631
3632   // Get input channel information.
3633   err = snd_pcm_hw_params_get_channels_min(params, &value);
3634   if (err < 0) {
3635     snd_pcm_close(handle);
3636     sprintf(message_, "RtApiAlsa: hardware minimum in channel probe error (%s): %s.",
3637             info->name.c_str(), snd_strerror(err));
3638     error(RtError::DEBUG_WARNING);
3639     if (info->maxOutputChannels > 0)
3640       goto probe_parameters;
3641     else
3642       return;
3643   }
3644   info->minInputChannels = value;
3645
3646   err = snd_pcm_hw_params_get_channels_max(params, &value);
3647   if (err < 0) {
3648     snd_pcm_close(handle);
3649     sprintf(message_, "RtApiAlsa: hardware maximum in channel probe error (%s): %s.",
3650             info->name.c_str(), snd_strerror(err));
3651     error(RtError::DEBUG_WARNING);
3652     if (info->maxOutputChannels > 0)
3653       goto probe_parameters;
3654     else
3655       return;
3656   }
3657   info->maxInputChannels = value;
3658
3659   snd_pcm_close(handle);
3660
3661   // If device opens for both playback and capture, we determine the channels.
3662   if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
3663     goto probe_parameters;
3664
3665   info->hasDuplexSupport = true;
3666   info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
3667     info->maxInputChannels : info->maxOutputChannels;
3668   info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
3669     info->minInputChannels : info->minOutputChannels;
3670
3671  probe_parameters:
3672   // At this point, we just need to figure out the supported data
3673   // formats and sample rates.  We'll proceed by opening the device in
3674   // the direction with the maximum number of channels, or playback if
3675   // they are equal.  This might limit our sample rate options, but so
3676   // be it.
3677
3678   if (info->maxOutputChannels >= info->maxInputChannels)
3679     stream = SND_PCM_STREAM_PLAYBACK;
3680   else
3681     stream = SND_PCM_STREAM_CAPTURE;
3682
3683   err = snd_pcm_open(&handle, info->name.c_str(), stream, open_mode);
3684   if (err < 0) {
3685     sprintf(message_, "RtApiAlsa: pcm (%s) won't reopen during probe: %s.",
3686             info->name.c_str(), snd_strerror(err));
3687     error(RtError::DEBUG_WARNING);
3688     return;
3689   }
3690
3691   // We have an open device ... allocate the parameter structure.
3692   err = snd_pcm_hw_params_any(handle, params);
3693   if (err < 0) {
3694     snd_pcm_close(handle);
3695     sprintf(message_, "RtApiAlsa: hardware reopen probe error (%s): %s.",
3696             info->name.c_str(), snd_strerror(err));
3697     error(RtError::DEBUG_WARNING);
3698     return;
3699   }
3700
3701   // Test our discrete set of sample rate values.
3702   int dir = 0;
3703   info->sampleRates.clear();
3704   for (unsigned int i=0; i<MAX_SAMPLE_RATES; i++) {
3705     if (snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0)
3706       info->sampleRates.push_back(SAMPLE_RATES[i]);
3707   }
3708   if (info->sampleRates.size() == 0) {
3709     snd_pcm_close(handle);
3710     sprintf(message_, "RtApiAlsa: no supported sample rates found for device (%s).",
3711             info->name.c_str());
3712     error(RtError::DEBUG_WARNING);
3713     return;
3714   }
3715
3716   // Probe the supported data formats ... we don't care about endian-ness just yet
3717   snd_pcm_format_t format;
3718   info->nativeFormats = 0;
3719   format = SND_PCM_FORMAT_S8;
3720   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
3721     info->nativeFormats |= RTAUDIO_SINT8;
3722   format = SND_PCM_FORMAT_S16;
3723   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
3724     info->nativeFormats |= RTAUDIO_SINT16;
3725   format = SND_PCM_FORMAT_S24;
3726   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
3727     info->nativeFormats |= RTAUDIO_SINT24;
3728   format = SND_PCM_FORMAT_S32;
3729   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
3730     info->nativeFormats |= RTAUDIO_SINT32;
3731   format = SND_PCM_FORMAT_FLOAT;
3732   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
3733     info->nativeFormats |= RTAUDIO_FLOAT32;
3734   format = SND_PCM_FORMAT_FLOAT64;
3735   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
3736     info->nativeFormats |= RTAUDIO_FLOAT64;
3737
3738   // Check that we have at least one supported format
3739   if (info->nativeFormats == 0) {
3740     snd_pcm_close(handle);
3741     sprintf(message_, "RtApiAlsa: pcm device (%s) data format not supported by RtAudio.",
3742             info->name.c_str());
3743     error(RtError::DEBUG_WARNING);
3744     return;
3745   }
3746
3747   // That's all ... close the device and return
3748   snd_pcm_close(handle);
3749   info->probed = true;
3750   return;
3751 }
3752
3753 bool RtApiAlsa :: probeDeviceOpen( int device, StreamMode mode, int channels, 
3754                                    int sampleRate, RtAudioFormat format,
3755                                    int *bufferSize, int numberOfBuffers )
3756 {
3757 #if defined(__RTAUDIO_DEBUG__)
3758   snd_output_t *out;
3759   snd_output_stdio_attach(&out, stderr, 0);
3760 #endif
3761
3762   // I'm not using the "plug" interface ... too much inconsistent behavior.
3763   const char *name = devices_[device].name.c_str();
3764
3765   snd_pcm_stream_t alsa_stream;
3766   if (mode == OUTPUT)
3767     alsa_stream = SND_PCM_STREAM_PLAYBACK;
3768   else
3769     alsa_stream = SND_PCM_STREAM_CAPTURE;
3770
3771   int err;
3772   snd_pcm_t *handle;
3773   int alsa_open_mode = SND_PCM_ASYNC;
3774   err = snd_pcm_open(&handle, name, alsa_stream, alsa_open_mode);
3775   if (err < 0) {
3776     sprintf(message_,"RtApiAlsa: pcm device (%s) won't open: %s.",
3777             name, snd_strerror(err));
3778     error(RtError::DEBUG_WARNING);
3779     return FAILURE;
3780   }
3781
3782   // Fill the parameter structure.
3783   snd_pcm_hw_params_t *hw_params;
3784   snd_pcm_hw_params_alloca(&hw_params);
3785   err = snd_pcm_hw_params_any(handle, hw_params);
3786   if (err < 0) {
3787     snd_pcm_close(handle);
3788     sprintf(message_, "RtApiAlsa: error getting parameter handle (%s): %s.",
3789             name, snd_strerror(err));
3790     error(RtError::DEBUG_WARNING);
3791     return FAILURE;
3792   }
3793
3794 #if defined(__RTAUDIO_DEBUG__)
3795   fprintf(stderr, "\nRtApiAlsa: dump hardware params just after device open:\n\n");
3796   snd_pcm_hw_params_dump(hw_params, out);
3797 #endif
3798
3799   // Set access ... try interleaved access first, then non-interleaved
3800   if ( !snd_pcm_hw_params_test_access( handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) ) {
3801     err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
3802   }
3803   else if ( !snd_pcm_hw_params_test_access( handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED) ) {
3804                 err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED);
3805     stream_.deInterleave[mode] = true;
3806   }
3807   else {
3808     snd_pcm_close(handle);
3809     sprintf(message_, "RtApiAlsa: device (%s) access not supported by RtAudio.", name);
3810     error(RtError::DEBUG_WARNING);
3811     return FAILURE;
3812   }
3813
3814   if (err < 0) {
3815     snd_pcm_close(handle);
3816     sprintf(message_, "RtApiAlsa: error setting access ( (%s): %s.", name, snd_strerror(err));
3817     error(RtError::DEBUG_WARNING);
3818     return FAILURE;
3819   }
3820
3821   // Determine how to set the device format.
3822   stream_.userFormat = format;
3823   snd_pcm_format_t device_format = SND_PCM_FORMAT_UNKNOWN;
3824
3825   if (format == RTAUDIO_SINT8)
3826     device_format = SND_PCM_FORMAT_S8;
3827   else if (format == RTAUDIO_SINT16)
3828     device_format = SND_PCM_FORMAT_S16;
3829   else if (format == RTAUDIO_SINT24)
3830     device_format = SND_PCM_FORMAT_S24;
3831   else if (format == RTAUDIO_SINT32)
3832     device_format = SND_PCM_FORMAT_S32;
3833   else if (format == RTAUDIO_FLOAT32)
3834     device_format = SND_PCM_FORMAT_FLOAT;
3835   else if (format == RTAUDIO_FLOAT64)
3836     device_format = SND_PCM_FORMAT_FLOAT64;
3837
3838   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
3839     stream_.deviceFormat[mode] = format;
3840     goto set_format;
3841   }
3842
3843   // The user requested format is not natively supported by the device.
3844   device_format = SND_PCM_FORMAT_FLOAT64;
3845   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
3846     stream_.deviceFormat[mode] = RTAUDIO_FLOAT64;
3847     goto set_format;
3848   }
3849
3850   device_format = SND_PCM_FORMAT_FLOAT;
3851   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
3852     stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
3853     goto set_format;
3854   }
3855
3856   device_format = SND_PCM_FORMAT_S32;
3857   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
3858     stream_.deviceFormat[mode] = RTAUDIO_SINT32;
3859     goto set_format;
3860   }
3861
3862   device_format = SND_PCM_FORMAT_S24;
3863   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
3864     stream_.deviceFormat[mode] = RTAUDIO_SINT24;
3865     goto set_format;
3866   }
3867
3868   device_format = SND_PCM_FORMAT_S16;
3869   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
3870     stream_.deviceFormat[mode] = RTAUDIO_SINT16;
3871     goto set_format;
3872   }
3873
3874   device_format = SND_PCM_FORMAT_S8;
3875   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
3876     stream_.deviceFormat[mode] = RTAUDIO_SINT8;
3877     goto set_format;
3878   }
3879
3880   // If we get here, no supported format was found.
3881   sprintf(message_,"RtApiAlsa: pcm device (%s) data format not supported by RtAudio.", name);
3882   snd_pcm_close(handle);
3883   error(RtError::DEBUG_WARNING);
3884   return FAILURE;
3885
3886  set_format:
3887   err = snd_pcm_hw_params_set_format(handle, hw_params, device_format);
3888   if (err < 0) {
3889     snd_pcm_close(handle);
3890     sprintf(message_, "RtApiAlsa: error setting format (%s): %s.",
3891             name, snd_strerror(err));
3892     error(RtError::DEBUG_WARNING);
3893     return FAILURE;
3894   }
3895
3896   // Determine whether byte-swaping is necessary.
3897   stream_.doByteSwap[mode] = false;
3898   if (device_format != SND_PCM_FORMAT_S8) {
3899     err = snd_pcm_format_cpu_endian(device_format);
3900     if (err == 0)
3901       stream_.doByteSwap[mode] = true;
3902     else if (err < 0) {
3903       snd_pcm_close(handle);
3904       sprintf(message_, "RtApiAlsa: error getting format endian-ness (%s): %s.",
3905               name, snd_strerror(err));
3906       error(RtError::DEBUG_WARNING);
3907       return FAILURE;
3908     }
3909   }
3910
3911   // Set the sample rate.
3912   err = snd_pcm_hw_params_set_rate(handle, hw_params, (unsigned int)sampleRate, 0);
3913   if (err < 0) {
3914     snd_pcm_close(handle);
3915     sprintf(message_, "RtApiAlsa: error setting sample rate (%d) on device (%s): %s.",
3916             sampleRate, name, snd_strerror(err));
3917     error(RtError::DEBUG_WARNING);
3918     return FAILURE;
3919   }
3920
3921   // Determine the number of channels for this device.  We support a possible
3922   // minimum device channel number > than the value requested by the user.
3923   stream_.nUserChannels[mode] = channels;
3924   unsigned int value;
3925   err = snd_pcm_hw_params_get_channels_max(hw_params, &value);
3926   int device_channels = value;
3927   if (err < 0 || device_channels < channels) {
3928     snd_pcm_close(handle);
3929     sprintf(message_, "RtApiAlsa: channels (%d) not supported by device (%s).",
3930             channels, name);
3931     error(RtError::DEBUG_WARNING);
3932     return FAILURE;
3933   }
3934
3935   err = snd_pcm_hw_params_get_channels_min(hw_params, &value);
3936   if (err < 0 ) {
3937     snd_pcm_close(handle);
3938     sprintf(message_, "RtApiAlsa: error getting min channels count on device (%s).", name);
3939     error(RtError::DEBUG_WARNING);
3940     return FAILURE;
3941   }
3942   device_channels = value;
3943   if (device_channels < channels) device_channels = channels;
3944   stream_.nDeviceChannels[mode] = device_channels;
3945
3946   // Set the device channels.
3947   err = snd_pcm_hw_params_set_channels(handle, hw_params, device_channels);
3948   if (err < 0) {
3949     snd_pcm_close(handle);
3950     sprintf(message_, "RtApiAlsa: error setting channels (%d) on device (%s): %s.",
3951             device_channels, name, snd_strerror(err));
3952     error(RtError::DEBUG_WARNING);
3953     return FAILURE;
3954   }
3955
3956   // Set the buffer number, which in ALSA is referred to as the "period".
3957   int dir;
3958   unsigned int periods = numberOfBuffers;
3959   // Even though the hardware might allow 1 buffer, it won't work reliably.
3960   if (periods < 2) periods = 2;
3961   err = snd_pcm_hw_params_set_periods_near(handle, hw_params, &periods, &dir);
3962   if (err < 0) {
3963     snd_pcm_close(handle);
3964     sprintf(message_, "RtApiAlsa: error setting periods (%s): %s.",
3965             name, snd_strerror(err));
3966     error(RtError::DEBUG_WARNING);
3967     return FAILURE;
3968   }
3969
3970   // Set the buffer (or period) size.
3971   snd_pcm_uframes_t period_size = *bufferSize;
3972   err = snd_pcm_hw_params_set_period_size_near(handle, hw_params, &period_size, &dir);
3973   if (err < 0) {
3974     snd_pcm_close(handle);
3975     sprintf(message_, "RtApiAlsa: error setting period size (%s): %s.",
3976             name, snd_strerror(err));
3977     error(RtError::DEBUG_WARNING);
3978     return FAILURE;
3979   }
3980   *bufferSize = period_size;
3981
3982   // If attempting to setup a duplex stream, the bufferSize parameter
3983   // MUST be the same in both directions!
3984   if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) {
3985     sprintf( message_, "RtApiAlsa: error setting buffer size for duplex stream on device (%s).",
3986              name );
3987     error(RtError::DEBUG_WARNING);
3988     return FAILURE;
3989   }
3990
3991   stream_.bufferSize = *bufferSize;
3992
3993   // Install the hardware configuration
3994   err = snd_pcm_hw_params(handle, hw_params);
3995   if (err < 0) {
3996     snd_pcm_close(handle);
3997     sprintf(message_, "RtApiAlsa: error installing hardware configuration (%s): %s.",
3998             name, snd_strerror(err));
3999     error(RtError::DEBUG_WARNING);
4000     return FAILURE;
4001   }
4002
4003 #if defined(__RTAUDIO_DEBUG__)
4004   fprintf(stderr, "\nRtApiAlsa: dump hardware params after installation:\n\n");
4005   snd_pcm_hw_params_dump(hw_params, out);
4006 #endif
4007
4008   // Set the software configuration to fill buffers with zeros and prevent device stopping on xruns.
4009   snd_pcm_sw_params_t *sw_params = NULL;
4010   snd_pcm_sw_params_alloca( &sw_params );
4011   snd_pcm_sw_params_current( handle, sw_params );
4012   snd_pcm_sw_params_set_start_threshold( handle, sw_params, *bufferSize );
4013   snd_pcm_sw_params_set_stop_threshold( handle, sw_params, 0x7fffffff );
4014   snd_pcm_sw_params_set_silence_threshold( handle, sw_params, 0 );
4015   snd_pcm_sw_params_set_silence_size( handle, sw_params, INT_MAX );
4016   err = snd_pcm_sw_params( handle, sw_params );
4017   if (err < 0) {
4018     snd_pcm_close(handle);
4019     sprintf(message_, "RtAudio: ALSA error installing software configuration (%s): %s.",
4020             name, snd_strerror(err));
4021     error(RtError::DEBUG_WARNING);
4022     return FAILURE;
4023   }
4024
4025 #if defined(__RTAUDIO_DEBUG__)
4026   fprintf(stderr, "\nRtApiAlsa: dump software params after installation:\n\n");
4027   snd_pcm_sw_params_dump(sw_params, out);
4028 #endif
4029
4030   // Allocate the ApiHandle if necessary and then save.
4031   AlsaHandle *apiInfo = 0;
4032   if ( stream_.apiHandle == 0 ) {
4033     apiInfo = (AlsaHandle *) new AlsaHandle;
4034     stream_.apiHandle = (void *) apiInfo;
4035     apiInfo->handles[0] = 0;
4036     apiInfo->handles[1] = 0;
4037   }
4038   else {
4039     apiInfo = (AlsaHandle *) stream_.apiHandle;
4040   }
4041   apiInfo->handles[mode] = handle;
4042
4043   // Set flags for buffer conversion
4044   stream_.doConvertBuffer[mode] = false;
4045   if (stream_.userFormat != stream_.deviceFormat[mode])
4046     stream_.doConvertBuffer[mode] = true;
4047   if (stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode])
4048     stream_.doConvertBuffer[mode] = true;
4049   if (stream_.nUserChannels[mode] > 1 && stream_.deInterleave[mode])
4050     stream_.doConvertBuffer[mode] = true;
4051
4052   // Allocate necessary internal buffers
4053   if ( stream_.nUserChannels[0] != stream_.nUserChannels[1] ) {
4054
4055     long buffer_bytes;
4056     if (stream_.nUserChannels[0] >= stream_.nUserChannels[1])
4057       buffer_bytes = stream_.nUserChannels[0];
4058     else
4059       buffer_bytes = stream_.nUserChannels[1];
4060
4061     buffer_bytes *= *bufferSize * formatBytes(stream_.userFormat);
4062     if (stream_.userBuffer) free(stream_.userBuffer);
4063     if (apiInfo->tempBuffer) free(apiInfo->tempBuffer);
4064     stream_.userBuffer = (char *) calloc(buffer_bytes, 1);
4065     apiInfo->tempBuffer = (char *) calloc(buffer_bytes, 1);
4066     if ( stream_.userBuffer == NULL || apiInfo->tempBuffer == NULL ) {
4067       sprintf(message_, "RtApiAlsa: error allocating user buffer memory (%s).",
4068               devices_[device].name.c_str());
4069       goto error;
4070     }
4071   }
4072
4073   if ( stream_.doConvertBuffer[mode] ) {
4074
4075     long buffer_bytes;
4076     bool makeBuffer = true;
4077     if ( mode == OUTPUT )
4078       buffer_bytes = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
4079     else { // mode == INPUT
4080       buffer_bytes = stream_.nDeviceChannels[1] * formatBytes(stream_.deviceFormat[1]);
4081       if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
4082         long bytes_out = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
4083         if ( buffer_bytes < bytes_out ) makeBuffer = false;
4084       }
4085     }
4086
4087     if ( makeBuffer ) {
4088       buffer_bytes *= *bufferSize;
4089       if (stream_.deviceBuffer) free(stream_.deviceBuffer);
4090       stream_.deviceBuffer = (char *) calloc(buffer_bytes, 1);
4091       if (stream_.deviceBuffer == NULL) {
4092         sprintf(message_, "RtApiAlsa: error allocating device buffer memory (%s).",
4093                 devices_[device].name.c_str());
4094         goto error;
4095       }
4096     }
4097   }
4098
4099   stream_.device[mode] = device;
4100   stream_.state = STREAM_STOPPED;
4101   if ( stream_.mode == OUTPUT && mode == INPUT ) {
4102     // We had already set up an output stream.
4103     stream_.mode = DUPLEX;
4104     // Link the streams if possible.
4105     apiInfo->synchronized = false;
4106     if (snd_pcm_link( apiInfo->handles[0], apiInfo->handles[1] ) == 0)
4107       apiInfo->synchronized = true;
4108     else {
4109       sprintf(message_, "RtApiAlsa: unable to synchronize input and output streams (%s).",
4110               devices_[device].name.c_str());
4111       error(RtError::DEBUG_WARNING);
4112     }
4113   }
4114   else
4115     stream_.mode = mode;
4116   stream_.nBuffers = periods;
4117   stream_.sampleRate = sampleRate;
4118
4119   // Setup the buffer conversion information structure.
4120   if ( stream_.doConvertBuffer[mode] ) {
4121     if (mode == INPUT) { // convert device to user buffer
4122       stream_.convertInfo[mode].inJump = stream_.nDeviceChannels[1];
4123       stream_.convertInfo[mode].outJump = stream_.nUserChannels[1];
4124       stream_.convertInfo[mode].inFormat = stream_.deviceFormat[1];
4125       stream_.convertInfo[mode].outFormat = stream_.userFormat;
4126     }
4127     else { // convert user to device buffer
4128       stream_.convertInfo[mode].inJump = stream_.nUserChannels[0];
4129       stream_.convertInfo[mode].outJump = stream_.nDeviceChannels[0];
4130       stream_.convertInfo[mode].inFormat = stream_.userFormat;
4131       stream_.convertInfo[mode].outFormat = stream_.deviceFormat[0];
4132     }
4133
4134     if ( stream_.convertInfo[mode].inJump < stream_.convertInfo[mode].outJump )
4135       stream_.convertInfo[mode].channels = stream_.convertInfo[mode].inJump;
4136     else
4137       stream_.convertInfo[mode].channels = stream_.convertInfo[mode].outJump;
4138
4139     // Set up the interleave/deinterleave offsets.
4140     if ( mode == INPUT && stream_.deInterleave[1] ) {
4141       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
4142         stream_.convertInfo[mode].inOffset.push_back( k * stream_.bufferSize );
4143         stream_.convertInfo[mode].outOffset.push_back( k );
4144         stream_.convertInfo[mode].inJump = 1;
4145       }
4146     }
4147     else if (mode == OUTPUT && stream_.deInterleave[0]) {
4148       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
4149         stream_.convertInfo[mode].inOffset.push_back( k );
4150         stream_.convertInfo[mode].outOffset.push_back( k * stream_.bufferSize );
4151         stream_.convertInfo[mode].outJump = 1;
4152       }
4153     }
4154     else {
4155       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
4156         stream_.convertInfo[mode].inOffset.push_back( k );
4157         stream_.convertInfo[mode].outOffset.push_back( k );
4158       }
4159     }
4160   }
4161
4162   return SUCCESS;
4163
4164  error:
4165   if (apiInfo) {
4166     if (apiInfo->handles[0])
4167       snd_pcm_close(apiInfo->handles[0]);
4168     if (apiInfo->handles[1])
4169       snd_pcm_close(apiInfo->handles[1]);
4170     if ( apiInfo->tempBuffer ) free(apiInfo->tempBuffer);
4171     delete apiInfo;
4172     stream_.apiHandle = 0;
4173   }
4174
4175   if (stream_.userBuffer) {
4176     free(stream_.userBuffer);
4177     stream_.userBuffer = 0;
4178   }
4179
4180   error(RtError::DEBUG_WARNING);
4181   return FAILURE;
4182 }
4183
4184 void RtApiAlsa :: closeStream()
4185 {
4186   // We don't want an exception to be thrown here because this
4187   // function is called by our class destructor.  So, do our own
4188   // stream check.
4189   if ( stream_.mode == UNINITIALIZED ) {
4190     sprintf(message_, "RtApiAlsa::closeStream(): no open stream to close!");
4191     error(RtError::WARNING);
4192     return;
4193   }
4194
4195   AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
4196   if (stream_.state == STREAM_RUNNING) {
4197     if (stream_.mode == OUTPUT || stream_.mode == DUPLEX)
4198       snd_pcm_drop(apiInfo->handles[0]);
4199     if (stream_.mode == INPUT || stream_.mode == DUPLEX)
4200       snd_pcm_drop(apiInfo->handles[1]);
4201     stream_.state = STREAM_STOPPED;
4202   }
4203
4204   if (stream_.callbackInfo.usingCallback) {
4205     stream_.callbackInfo.usingCallback = false;
4206     pthread_join(stream_.callbackInfo.thread, NULL);
4207   }
4208
4209   if (apiInfo) {
4210     if (apiInfo->handles[0]) snd_pcm_close(apiInfo->handles[0]);
4211     if (apiInfo->handles[1]) snd_pcm_close(apiInfo->handles[1]);
4212     free(apiInfo->tempBuffer);
4213     delete apiInfo;
4214     stream_.apiHandle = 0;
4215   }
4216
4217   if (stream_.userBuffer) {
4218     free(stream_.userBuffer);
4219     stream_.userBuffer = 0;
4220   }
4221
4222   if (stream_.deviceBuffer) {
4223     free(stream_.deviceBuffer);
4224     stream_.deviceBuffer = 0;
4225   }
4226
4227   stream_.mode = UNINITIALIZED;
4228 }
4229
4230 // Pump a bunch of zeros into the output buffer.  This is needed only when we
4231 // are doing duplex operations.
4232 bool RtApiAlsa :: primeOutputBuffer()
4233 {
4234   int err;
4235   char *buffer;
4236   int channels;
4237   snd_pcm_t **handle;
4238   RtAudioFormat format;
4239   AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
4240   handle = (snd_pcm_t **) apiInfo->handles;
4241   
4242   if (stream_.mode == DUPLEX) {
4243
4244     // Setup parameters and do buffer conversion if necessary.
4245     if ( stream_.doConvertBuffer[0] ) {
4246       convertBuffer( stream_.deviceBuffer, apiInfo->tempBuffer, stream_.convertInfo[0] );
4247       channels = stream_.nDeviceChannels[0];
4248       format = stream_.deviceFormat[0];
4249     }
4250     else {
4251       channels = stream_.nUserChannels[0];
4252       format = stream_.userFormat;
4253     }
4254
4255     buffer = new char[stream_.bufferSize * formatBytes(format) * channels];
4256     bzero(buffer, stream_.bufferSize * formatBytes(format) * channels);
4257     
4258     for (int i=0; i<stream_.nBuffers; i++) {
4259       // Write samples to device in interleaved/non-interleaved format.
4260       if (stream_.deInterleave[0]) {
4261         void *bufs[channels];
4262         size_t offset = stream_.bufferSize * formatBytes(format);
4263         for (int i=0; i<channels; i++)
4264           bufs[i] = (void *) (buffer + (i * offset));
4265         err = snd_pcm_writen(handle[0], bufs, stream_.bufferSize);
4266       }
4267       else
4268         err = snd_pcm_writei(handle[0], buffer, stream_.bufferSize);
4269   
4270       if (err < stream_.bufferSize) {
4271         // Either an error or underrun occured.
4272         if (err == -EPIPE) {
4273           snd_pcm_state_t state = snd_pcm_state(handle[0]);
4274           if (state == SND_PCM_STATE_XRUN) {
4275             sprintf(message_, "RtApiAlsa: underrun detected while priming output buffer.");
4276             return false;
4277           }
4278           else {
4279             sprintf(message_, "RtApiAlsa: primeOutputBuffer() error, current state is %s.",
4280                     snd_pcm_state_name(state));
4281             return false;
4282           }
4283         }
4284         else {
4285           sprintf(message_, "RtApiAlsa: audio write error for device (%s): %s.",
4286                   devices_[stream_.device[0]].name.c_str(), snd_strerror(err));
4287           return false;
4288         }
4289       }
4290     }
4291   }
4292
4293   return true;
4294 }
4295
4296 void RtApiAlsa :: startStream()
4297 {
4298   // This method calls snd_pcm_prepare if the device isn't already in that state.
4299
4300   verifyStream();
4301   if (stream_.state == STREAM_RUNNING) return;
4302
4303   MUTEX_LOCK(&stream_.mutex);
4304
4305   int err;
4306   snd_pcm_state_t state;
4307   AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
4308   snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;
4309   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
4310     state = snd_pcm_state(handle[0]);
4311     if (state != SND_PCM_STATE_PREPARED) {
4312       err = snd_pcm_prepare(handle[0]);
4313       if (err < 0) {
4314         sprintf(message_, "RtApiAlsa: error preparing pcm device (%s): %s.",
4315                 devices_[stream_.device[0]].name.c_str(), snd_strerror(err));
4316         MUTEX_UNLOCK(&stream_.mutex);
4317         error(RtError::DRIVER_ERROR);
4318       }
4319       // Reprime output buffer if needed
4320       if ( (stream_.mode == DUPLEX) && ( !primeOutputBuffer() ) ) {
4321         MUTEX_UNLOCK(&stream_.mutex);
4322         error(RtError::DRIVER_ERROR);
4323       }
4324     }
4325   }
4326
4327   if ( (stream_.mode == INPUT || stream_.mode == DUPLEX) && !apiInfo->synchronized ) {
4328     state = snd_pcm_state(handle[1]);
4329     if (state != SND_PCM_STATE_PREPARED) {
4330       err = snd_pcm_prepare(handle[1]);
4331       if (err < 0) {
4332         sprintf(message_, "RtApiAlsa: error preparing pcm device (%s): %s.",
4333                 devices_[stream_.device[1]].name.c_str(), snd_strerror(err));
4334         MUTEX_UNLOCK(&stream_.mutex);
4335         error(RtError::DRIVER_ERROR);
4336       }
4337     }
4338   }
4339
4340   if ( (stream_.mode == DUPLEX) && ( !primeOutputBuffer() ) ) {
4341     MUTEX_UNLOCK(&stream_.mutex);
4342     error(RtError::DRIVER_ERROR);
4343   }
4344   stream_.state = STREAM_RUNNING;
4345
4346   MUTEX_UNLOCK(&stream_.mutex);
4347 }
4348
4349 void RtApiAlsa :: stopStream()
4350 {
4351   verifyStream();
4352   if (stream_.state == STREAM_STOPPED) return;
4353
4354   // Change the state before the lock to improve shutdown response
4355   // when using a callback.
4356   stream_.state = STREAM_STOPPED;
4357   MUTEX_LOCK(&stream_.mutex);
4358
4359   int err;
4360   AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
4361   snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;
4362   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
4363     err = snd_pcm_drain(handle[0]);
4364     if (err < 0) {
4365       sprintf(message_, "RtApiAlsa: error draining pcm device (%s): %s.",
4366               devices_[stream_.device[0]].name.c_str(), snd_strerror(err));
4367       MUTEX_UNLOCK(&stream_.mutex);
4368       error(RtError::DRIVER_ERROR);
4369     }
4370   }
4371
4372   if ( (stream_.mode == INPUT || stream_.mode == DUPLEX) && !apiInfo->synchronized ) {
4373     err = snd_pcm_drain(handle[1]);
4374     if (err < 0) {
4375       sprintf(message_, "RtApiAlsa: error draining pcm device (%s): %s.",
4376               devices_[stream_.device[1]].name.c_str(), snd_strerror(err));
4377       MUTEX_UNLOCK(&stream_.mutex);
4378       error(RtError::DRIVER_ERROR);
4379     }
4380   }
4381
4382   MUTEX_UNLOCK(&stream_.mutex);
4383 }
4384
4385 void RtApiAlsa :: abortStream()
4386 {
4387   verifyStream();
4388   if (stream_.state == STREAM_STOPPED) return;
4389
4390   // Change the state before the lock to improve shutdown response
4391   // when using a callback.
4392   stream_.state = STREAM_STOPPED;
4393   MUTEX_LOCK(&stream_.mutex);
4394
4395   int err;
4396   AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
4397   snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;
4398   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
4399     err = snd_pcm_drop(handle[0]);
4400     if (err < 0) {
4401       sprintf(message_, "RtApiAlsa: error draining pcm device (%s): %s.",
4402               devices_[stream_.device[0]].name.c_str(), snd_strerror(err));
4403       MUTEX_UNLOCK(&stream_.mutex);
4404       error(RtError::DRIVER_ERROR);
4405     }
4406   }
4407
4408   if ( (stream_.mode == INPUT || stream_.mode == DUPLEX) && !apiInfo->synchronized ) {
4409     err = snd_pcm_drop(handle[1]);
4410     if (err < 0) {
4411       sprintf(message_, "RtApiAlsa: error draining pcm device (%s): %s.",
4412               devices_[stream_.device[1]].name.c_str(), snd_strerror(err));
4413       MUTEX_UNLOCK(&stream_.mutex);
4414       error(RtError::DRIVER_ERROR);
4415     }
4416   }
4417
4418   MUTEX_UNLOCK(&stream_.mutex);
4419 }
4420
4421 int RtApiAlsa :: streamWillBlock()
4422 {
4423   verifyStream();
4424   if (stream_.state == STREAM_STOPPED) return 0;
4425
4426   MUTEX_LOCK(&stream_.mutex);
4427
4428   int err = 0, frames = 0;
4429   AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
4430   snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;
4431   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
4432     err = snd_pcm_avail_update(handle[0]);
4433     if (err < 0) {
4434       sprintf(message_, "RtApiAlsa: error getting available frames for device (%s): %s.",
4435               devices_[stream_.device[0]].name.c_str(), snd_strerror(err));
4436       MUTEX_UNLOCK(&stream_.mutex);
4437       error(RtError::DRIVER_ERROR);
4438     }
4439   }
4440
4441   frames = err;
4442
4443   if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
4444     err = snd_pcm_avail_update(handle[1]);
4445     if (err < 0) {
4446       sprintf(message_, "RtApiAlsa: error getting available frames for device (%s): %s.",
4447               devices_[stream_.device[1]].name.c_str(), snd_strerror(err));
4448       MUTEX_UNLOCK(&stream_.mutex);
4449       error(RtError::DRIVER_ERROR);
4450     }
4451     if (frames > err) frames = err;
4452   }
4453
4454   frames = stream_.bufferSize - frames;
4455   if (frames < 0) frames = 0;
4456
4457   MUTEX_UNLOCK(&stream_.mutex);
4458   return frames;
4459 }
4460
4461 void RtApiAlsa :: tickStream()
4462 {
4463   verifyStream();
4464
4465   int stopStream = 0;
4466   if (stream_.state == STREAM_STOPPED) {
4467     if (stream_.callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
4468     return;
4469   }
4470   else if (stream_.callbackInfo.usingCallback) {
4471     RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
4472     stopStream = callback(stream_.userBuffer, stream_.bufferSize, stream_.callbackInfo.userData);
4473   }
4474
4475   MUTEX_LOCK(&stream_.mutex);
4476
4477   // The state might change while waiting on a mutex.
4478   if (stream_.state == STREAM_STOPPED)
4479     goto unlock;
4480
4481   int err;
4482   char *buffer;
4483   int channels;
4484   AlsaHandle *apiInfo;
4485   snd_pcm_t **handle;
4486   RtAudioFormat format;
4487   apiInfo = (AlsaHandle *) stream_.apiHandle;
4488   handle = (snd_pcm_t **) apiInfo->handles;
4489
4490   if ( stream_.mode == DUPLEX ) {
4491     // In duplex mode, we need to make the snd_pcm_read call before
4492     // the snd_pcm_write call in order to avoid under/over runs.  So,
4493     // copy the userData to our temporary buffer.
4494     int bufferBytes;
4495     bufferBytes = stream_.bufferSize * stream_.nUserChannels[0] * formatBytes(stream_.userFormat);
4496     memcpy( apiInfo->tempBuffer, stream_.userBuffer, bufferBytes );
4497   }
4498
4499   if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
4500
4501     // Setup parameters.
4502     if (stream_.doConvertBuffer[1]) {
4503       buffer = stream_.deviceBuffer;
4504       channels = stream_.nDeviceChannels[1];
4505       format = stream_.deviceFormat[1];
4506     }
4507     else {
4508       buffer = stream_.userBuffer;
4509       channels = stream_.nUserChannels[1];
4510       format = stream_.userFormat;
4511     }
4512
4513     // Read samples from device in interleaved/non-interleaved format.
4514     if (stream_.deInterleave[1]) {
4515       void *bufs[channels];
4516       size_t offset = stream_.bufferSize * formatBytes(format);
4517       for (int i=0; i<channels; i++)
4518         bufs[i] = (void *) (buffer + (i * offset));
4519       err = snd_pcm_readn(handle[1], bufs, stream_.bufferSize);
4520     }
4521     else
4522       err = snd_pcm_readi(handle[1], buffer, stream_.bufferSize);
4523
4524     if (err < stream_.bufferSize) {
4525       // Either an error or underrun occured.
4526       if (err == -EPIPE) {
4527         snd_pcm_state_t state = snd_pcm_state(handle[1]);
4528         if (state == SND_PCM_STATE_XRUN) {
4529           sprintf(message_, "RtApiAlsa: overrun detected.");
4530           error(RtError::WARNING);
4531           err = snd_pcm_prepare(handle[1]);
4532           if (err < 0) {
4533             sprintf(message_, "RtApiAlsa: error preparing handle after overrun: %s.",
4534                     snd_strerror(err));
4535             MUTEX_UNLOCK(&stream_.mutex);
4536             error(RtError::DRIVER_ERROR);
4537           }
4538           // Reprime output buffer if needed.
4539           if ( (stream_.mode == DUPLEX) && ( !primeOutputBuffer() ) ) {
4540             MUTEX_UNLOCK(&stream_.mutex);
4541             error(RtError::DRIVER_ERROR);
4542           }
4543         }
4544         else {
4545           sprintf(message_, "RtApiAlsa: tickStream() error, current state is %s.",
4546                   snd_pcm_state_name(state));
4547           MUTEX_UNLOCK(&stream_.mutex);
4548           error(RtError::DRIVER_ERROR);
4549         }
4550         goto unlock;
4551       }
4552       else {
4553         sprintf(message_, "RtApiAlsa: audio read error for device (%s): %s.",
4554                 devices_[stream_.device[1]].name.c_str(), snd_strerror(err));
4555         MUTEX_UNLOCK(&stream_.mutex);
4556         error(RtError::DRIVER_ERROR);
4557       }
4558     }
4559
4560     // Do byte swapping if necessary.
4561     if (stream_.doByteSwap[1])
4562       byteSwapBuffer(buffer, stream_.bufferSize * channels, format);
4563
4564     // Do buffer conversion if necessary.
4565     if (stream_.doConvertBuffer[1])
4566       convertBuffer( stream_.userBuffer, stream_.deviceBuffer, stream_.convertInfo[1] );
4567   }
4568
4569   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
4570
4571     // Setup parameters and do buffer conversion if necessary.
4572     if (stream_.doConvertBuffer[0]) {
4573       buffer = stream_.deviceBuffer;
4574       if ( stream_.mode == DUPLEX )
4575         convertBuffer( buffer, apiInfo->tempBuffer, stream_.convertInfo[0] );
4576       else
4577         convertBuffer( buffer, stream_.userBuffer, stream_.convertInfo[0] );
4578       channels = stream_.nDeviceChannels[0];
4579       format = stream_.deviceFormat[0];
4580     }
4581     else {
4582       if ( stream_.mode == DUPLEX )
4583         buffer = apiInfo->tempBuffer;
4584       else
4585         buffer = stream_.userBuffer;
4586       channels = stream_.nUserChannels[0];
4587       format = stream_.userFormat;
4588     }
4589
4590     // Do byte swapping if necessary.
4591     if (stream_.doByteSwap[0])
4592       byteSwapBuffer(buffer, stream_.bufferSize * channels, format);
4593
4594     // Write samples to device in interleaved/non-interleaved format.
4595     if (stream_.deInterleave[0]) {
4596       void *bufs[channels];
4597       size_t offset = stream_.bufferSize * formatBytes(format);
4598       for (int i=0; i<channels; i++)
4599         bufs[i] = (void *) (buffer + (i * offset));
4600       err = snd_pcm_writen(handle[0], bufs, stream_.bufferSize);
4601     }
4602     else
4603       err = snd_pcm_writei(handle[0], buffer, stream_.bufferSize);
4604
4605     if (err < stream_.bufferSize) {
4606       // Either an error or underrun occured.
4607       if (err == -EPIPE) {
4608         snd_pcm_state_t state = snd_pcm_state(handle[0]);
4609         if (state == SND_PCM_STATE_XRUN) {
4610           sprintf(message_, "RtApiAlsa: underrun detected.");
4611           error(RtError::WARNING);
4612           err = snd_pcm_prepare(handle[0]);
4613           if (err < 0) {
4614             sprintf(message_, "RtApiAlsa: error preparing handle after underrun: %s.",
4615                     snd_strerror(err));
4616             MUTEX_UNLOCK(&stream_.mutex);
4617             error(RtError::DRIVER_ERROR);
4618           }
4619         }
4620         else {
4621           sprintf(message_, "RtApiAlsa: tickStream() error, current state is %s.",
4622                   snd_pcm_state_name(state));
4623           MUTEX_UNLOCK(&stream_.mutex);
4624           error(RtError::DRIVER_ERROR);
4625         }
4626         goto unlock;
4627       }
4628       else {
4629         sprintf(message_, "RtApiAlsa: audio write error for device (%s): %s.",
4630                 devices_[stream_.device[0]].name.c_str(), snd_strerror(err));
4631         MUTEX_UNLOCK(&stream_.mutex);
4632         error(RtError::DRIVER_ERROR);
4633       }
4634     }
4635   }
4636
4637  unlock:
4638   MUTEX_UNLOCK(&stream_.mutex);
4639
4640   if (stream_.callbackInfo.usingCallback && stopStream)
4641     this->stopStream();
4642 }
4643
4644 void RtApiAlsa :: setStreamCallback(RtAudioCallback callback, void *userData)
4645 {
4646   verifyStream();
4647
4648   CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
4649   if ( info->usingCallback ) {
4650     sprintf(message_, "RtApiAlsa: A callback is already set for this stream!");
4651     error(RtError::WARNING);
4652     return;
4653   }
4654
4655   info->callback = (void *) callback;
4656   info->userData = userData;
4657   info->usingCallback = true;
4658   info->object = (void *) this;
4659
4660   // Set the thread attributes for joinable and realtime scheduling
4661   // priority.  The higher priority will only take affect if the
4662   // program is run as root or suid.
4663   pthread_attr_t attr;
4664   pthread_attr_init(&attr);
4665   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
4666   pthread_attr_setschedpolicy(&attr, SCHED_RR);
4667
4668   int err = pthread_create(&info->thread, &attr, alsaCallbackHandler, &stream_.callbackInfo);
4669   pthread_attr_destroy(&attr);
4670   if (err) {
4671     info->usingCallback = false;
4672     sprintf(message_, "RtApiAlsa: error starting callback thread!");
4673     error(RtError::THREAD_ERROR);
4674   }
4675 }
4676
4677 void RtApiAlsa :: cancelStreamCallback()
4678 {
4679   verifyStream();
4680
4681   if (stream_.callbackInfo.usingCallback) {
4682
4683     if (stream_.state == STREAM_RUNNING)
4684       stopStream();
4685
4686     MUTEX_LOCK(&stream_.mutex);
4687
4688     stream_.callbackInfo.usingCallback = false;
4689     pthread_join(stream_.callbackInfo.thread, NULL);
4690     stream_.callbackInfo.thread = 0;
4691     stream_.callbackInfo.callback = NULL;
4692     stream_.callbackInfo.userData = NULL;
4693
4694     MUTEX_UNLOCK(&stream_.mutex);
4695   }
4696 }
4697
4698 extern "C" void *alsaCallbackHandler(void *ptr)
4699 {
4700   CallbackInfo *info = (CallbackInfo *) ptr;
4701   RtApiAlsa *object = (RtApiAlsa *) info->object;
4702   bool *usingCallback = &info->usingCallback;
4703
4704   while ( *usingCallback ) {
4705     try {
4706       object->tickStream();
4707     }
4708     catch (RtError &exception) {
4709       fprintf(stderr, "\nRtApiAlsa: callback thread error (%s) ... closing thread.\n\n",
4710               exception.getMessageString());
4711       break;
4712     }
4713   }
4714
4715   pthread_exit(NULL);
4716 }
4717
4718 //******************** End of __LINUX_ALSA__ *********************//
4719 #endif
4720
4721 #if defined(__WINDOWS_ASIO__) // ASIO API on Windows
4722
4723 // The ASIO API is designed around a callback scheme, so this
4724 // implementation is similar to that used for OS-X CoreAudio and Linux
4725 // Jack.  The primary constraint with ASIO is that it only allows
4726 // access to a single driver at a time.  Thus, it is not possible to
4727 // have more than one simultaneous RtAudio stream.
4728 //
4729 // This implementation also requires a number of external ASIO files
4730 // and a few global variables.  The ASIO callback scheme does not
4731 // allow for the passing of user data, so we must create a global
4732 // pointer to our callbackInfo structure.
4733 //
4734 // On unix systems, we make use of a pthread condition variable.
4735 // Since there is no equivalent in Windows, I hacked something based
4736 // on information found in
4737 // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html.
4738
4739 #include "asio/asiosys.h"
4740 #include "asio/asio.h"
4741 #include "asio/iasiothiscallresolver.h"
4742 #include "asio/asiodrivers.h"
4743 #include <math.h>
4744
4745 AsioDrivers drivers;
4746 ASIOCallbacks asioCallbacks;
4747 ASIODriverInfo driverInfo;
4748 CallbackInfo *asioCallbackInfo;
4749
4750 struct AsioHandle {
4751   bool stopStream;
4752   ASIOBufferInfo *bufferInfos;
4753   HANDLE condition;
4754
4755   AsioHandle()
4756     :stopStream(false), bufferInfos(0) {}
4757 };
4758
4759 static const char* GetAsioErrorString( ASIOError result )
4760 {
4761   struct Messages 
4762   {
4763     ASIOError value;
4764     const char*message;
4765   };
4766   static Messages m[] = 
4767   {
4768     {   ASE_NotPresent,    "Hardware input or output is not present or available." },
4769     {   ASE_HWMalfunction,  "Hardware is malfunctioning." },
4770     {   ASE_InvalidParameter, "Invalid input parameter." },
4771     {   ASE_InvalidMode,      "Invalid mode." },
4772     {   ASE_SPNotAdvancing,     "Sample position not advancing." },
4773     {   ASE_NoClock,            "Sample clock or rate cannot be determined or is not present." },
4774     {   ASE_NoMemory,           "Not enough memory to complete the request." }
4775   };
4776
4777   for (unsigned int i = 0; i < sizeof(m)/sizeof(m[0]); ++i)
4778     if (m[i].value == result) return m[i].message;
4779
4780   return "Unknown error.";
4781 }
4782
4783 RtApiAsio :: RtApiAsio()
4784 {
4785   this->coInitialized = false;
4786   this->initialize();
4787
4788   if (nDevices_ <= 0) {
4789     sprintf(message_, "RtApiAsio: no Windows ASIO audio drivers found!");
4790     error(RtError::NO_DEVICES_FOUND);
4791   }
4792 }
4793
4794 RtApiAsio :: ~RtApiAsio()
4795 {
4796   if ( stream_.mode != UNINITIALIZED ) closeStream();
4797
4798   if ( coInitialized )
4799     CoUninitialize();
4800 }
4801
4802 void RtApiAsio :: initialize(void)
4803 {
4804
4805   // ASIO cannot run on a multi-threaded appartment. You can call CoInitialize beforehand, but it must be 
4806   // for appartment threading (in which case, CoInitilialize will return S_FALSE here).
4807   coInitialized = false;
4808   HRESULT hr = CoInitialize(NULL); 
4809   if ( FAILED(hr) ) {
4810     sprintf(message_,"RtApiAsio: ASIO requires a single-threaded appartment. Call CoInitializeEx(0,COINIT_APARTMENTTHREADED)");
4811   }
4812   coInitialized = true;
4813
4814   nDevices_ = drivers.asioGetNumDev();
4815   if (nDevices_ <= 0) return;
4816
4817   // Create device structures and write device driver names to each.
4818   RtApiDevice device;
4819   char name[128];
4820   for (int i=0; i<nDevices_; i++) {
4821     if ( drivers.asioGetDriverName( i, name, 128 ) == 0 ) {
4822       device.name.erase();
4823       device.name.append( (const char *)name, strlen(name)+1);
4824       devices_.push_back(device);
4825     }
4826     else {
4827       sprintf(message_, "RtApiAsio: error getting driver name for device index %d!", i);
4828       error(RtError::WARNING);
4829     }
4830   }
4831
4832   nDevices_ = (int) devices_.size();
4833
4834   drivers.removeCurrentDriver();
4835   driverInfo.asioVersion = 2;
4836   // See note in DirectSound implementation about GetDesktopWindow().
4837   driverInfo.sysRef = GetForegroundWindow();
4838 }
4839
4840 void RtApiAsio :: probeDeviceInfo(RtApiDevice *info)
4841 {
4842   // Don't probe if a stream is already open.
4843   if ( stream_.mode != UNINITIALIZED ) {
4844     sprintf(message_, "RtApiAsio: unable to probe driver while a stream is open.");
4845     error(RtError::DEBUG_WARNING);
4846     return;
4847   }
4848
4849   if ( !drivers.loadDriver( (char *)info->name.c_str() ) ) {
4850     sprintf(message_, "RtApiAsio: error loading driver (%s).", info->name.c_str());
4851     error(RtError::DEBUG_WARNING);
4852     return;
4853   }
4854
4855   ASIOError result = ASIOInit( &driverInfo );
4856   if ( result != ASE_OK ) {
4857     sprintf(message_, "RtApiAsio: error (%s) initializing driver (%s).", 
4858       GetAsioErrorString(result), info->name.c_str());
4859     error(RtError::DEBUG_WARNING);
4860     return;
4861   }
4862
4863   // Determine the device channel information.
4864   long inputChannels, outputChannels;
4865   result = ASIOGetChannels( &inputChannels, &outputChannels );
4866   if ( result != ASE_OK ) {
4867     drivers.removeCurrentDriver();
4868     sprintf(message_, "RtApiAsio: error (%s) getting input/output channel count (%s).", 
4869       GetAsioErrorString(result), 
4870       info->name.c_str());
4871     error(RtError::DEBUG_WARNING);
4872     return;
4873   }
4874
4875   info->maxOutputChannels = outputChannels;
4876   if ( outputChannels > 0 ) info->minOutputChannels = 1;
4877
4878   info->maxInputChannels = inputChannels;
4879   if ( inputChannels > 0 ) info->minInputChannels = 1;
4880
4881   // If device opens for both playback and capture, we determine the channels.
4882   if (info->maxOutputChannels > 0 && info->maxInputChannels > 0) {
4883     info->hasDuplexSupport = true;
4884     info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
4885       info->maxInputChannels : info->maxOutputChannels;
4886     info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
4887       info->minInputChannels : info->minOutputChannels;
4888   }
4889
4890   // Determine the supported sample rates.
4891   info->sampleRates.clear();
4892   for (unsigned int i=0; i<MAX_SAMPLE_RATES; i++) {
4893     result = ASIOCanSampleRate( (ASIOSampleRate) SAMPLE_RATES[i] );
4894     if ( result == ASE_OK )
4895       info->sampleRates.push_back( SAMPLE_RATES[i] );
4896   }
4897
4898   if (info->sampleRates.size() == 0) {
4899     drivers.removeCurrentDriver();
4900     sprintf( message_, "RtApiAsio: No supported sample rates found for driver (%s).", info->name.c_str() );
4901     error(RtError::DEBUG_WARNING);
4902     return;
4903   }
4904
4905   // Determine supported data types ... just check first channel and assume rest are the same.
4906   ASIOChannelInfo channelInfo;
4907   channelInfo.channel = 0;
4908   channelInfo.isInput = true;
4909   if ( info->maxInputChannels <= 0 ) channelInfo.isInput = false;
4910   result = ASIOGetChannelInfo( &channelInfo );
4911   if ( result != ASE_OK ) {
4912     drivers.removeCurrentDriver();
4913     sprintf(message_, "RtApiAsio: error (%s) getting driver (%s) channel information.", 
4914       GetAsioErrorString(result), 
4915       info->name.c_str());
4916     error(RtError::DEBUG_WARNING);
4917     return;
4918   }
4919
4920   if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB )
4921     info->nativeFormats |= RTAUDIO_SINT16;
4922   else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB )
4923     info->nativeFormats |= RTAUDIO_SINT32;
4924   else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB )
4925     info->nativeFormats |= RTAUDIO_FLOAT32;
4926   else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB )
4927     info->nativeFormats |= RTAUDIO_FLOAT64;
4928
4929         // Check that we have at least one supported format.
4930   if (info->nativeFormats == 0) {
4931     drivers.removeCurrentDriver();
4932     sprintf(message_, "RtApiAsio: driver (%s) data format not supported by RtAudio.",
4933             info->name.c_str());
4934     error(RtError::DEBUG_WARNING);
4935     return;
4936   }
4937
4938   info->probed = true;
4939   drivers.removeCurrentDriver();
4940 }
4941
4942 void bufferSwitch(long index, ASIOBool processNow)
4943 {
4944   RtApiAsio *object = (RtApiAsio *) asioCallbackInfo->object;
4945   try {
4946     object->callbackEvent( index );
4947   }
4948   catch (RtError &exception) {
4949     fprintf(stderr, "\nRtApiAsio: callback handler error (%s)!\n\n", exception.getMessageString());
4950     return;
4951   }
4952
4953   return;
4954 }
4955
4956 void sampleRateChanged(ASIOSampleRate sRate)
4957 {
4958   // The ASIO documentation says that this usually only happens during
4959   // external sync.  Audio processing is not stopped by the driver,
4960   // actual sample rate might not have even changed, maybe only the
4961   // sample rate status of an AES/EBU or S/PDIF digital input at the
4962   // audio device.
4963
4964   RtAudio *object = (RtAudio *) asioCallbackInfo->object;
4965   try {
4966     object->stopStream();
4967   }
4968   catch (RtError &exception) {
4969     fprintf(stderr, "\nRtApiAsio: sampleRateChanged() error (%s)!\n\n", exception.getMessageString());
4970     return;
4971   }
4972
4973   fprintf(stderr, "\nRtApiAsio: driver reports sample rate changed to %d ... stream stopped!!!", (int) sRate);
4974 }
4975
4976 long asioMessages(long selector, long value, void* message, double* opt)
4977 {
4978   long ret = 0;
4979   switch(selector) {
4980   case kAsioSelectorSupported:
4981     if(value == kAsioResetRequest
4982        || value == kAsioEngineVersion
4983        || value == kAsioResyncRequest
4984        || value == kAsioLatenciesChanged
4985        // The following three were added for ASIO 2.0, you don't
4986        // necessarily have to support them.
4987        || value == kAsioSupportsTimeInfo
4988        || value == kAsioSupportsTimeCode
4989        || value == kAsioSupportsInputMonitor)
4990       ret = 1L;
4991     break;
4992   case kAsioResetRequest:
4993     // Defer the task and perform the reset of the driver during the
4994     // next "safe" situation.  You cannot reset the driver right now,
4995     // as this code is called from the driver.  Reset the driver is
4996     // done by completely destruct is. I.e. ASIOStop(),
4997     // ASIODisposeBuffers(), Destruction Afterwards you initialize the
4998     // driver again.
4999     fprintf(stderr, "\nRtApiAsio: driver reset requested!!!");
5000     ret = 1L;
5001     break;
5002   case kAsioResyncRequest:
5003     // This informs the application that the driver encountered some
5004     // non-fatal data loss.  It is used for synchronization purposes
5005     // of different media.  Added mainly to work around the Win16Mutex
5006     // problems in Windows 95/98 with the Windows Multimedia system,
5007     // which could lose data because the Mutex was held too long by
5008     // another thread.  However a driver can issue it in other
5009     // situations, too.
5010     fprintf(stderr, "\nRtApiAsio: driver resync requested!!!");
5011     ret = 1L;
5012     break;
5013   case kAsioLatenciesChanged:
5014     // This will inform the host application that the drivers were
5015     // latencies changed.  Beware, it this does not mean that the
5016     // buffer sizes have changed!  You might need to update internal
5017     // delay data.
5018     fprintf(stderr, "\nRtApiAsio: driver latency may have changed!!!");
5019     ret = 1L;
5020     break;
5021   case kAsioEngineVersion:
5022     // Return the supported ASIO version of the host application.  If
5023     // a host application does not implement this selector, ASIO 1.0
5024     // is assumed by the driver.
5025     ret = 2L;
5026     break;
5027   case kAsioSupportsTimeInfo:
5028     // Informs the driver whether the
5029     // asioCallbacks.bufferSwitchTimeInfo() callback is supported.
5030     // For compatibility with ASIO 1.0 drivers the host application
5031     // should always support the "old" bufferSwitch method, too.
5032     ret = 0;
5033     break;
5034   case kAsioSupportsTimeCode:
5035     // Informs the driver wether application is interested in time
5036     // code info.  If an application does not need to know about time
5037     // code, the driver has less work to do.
5038     ret = 0;
5039     break;
5040   }
5041   return ret;
5042 }
5043
5044 bool RtApiAsio :: probeDeviceOpen(int device, StreamMode mode, int channels, 
5045                                   int sampleRate, RtAudioFormat format,
5046                                   int *bufferSize, int numberOfBuffers)
5047 {
5048   // For ASIO, a duplex stream MUST use the same driver.
5049   if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] != device ) {
5050     sprintf(message_, "RtApiAsio: duplex stream must use the same device for input and output.");
5051     error(RtError::WARNING);
5052     return FAILURE;
5053   }
5054
5055   // Only load the driver once for duplex stream.
5056   ASIOError result;
5057   if ( mode != INPUT || stream_.mode != OUTPUT ) {
5058     if ( !drivers.loadDriver( (char *)devices_[device].name.c_str() ) ) {
5059       sprintf(message_, "RtApiAsio: error loading driver (%s).", 
5060         devices_[device].name.c_str());
5061       error(RtError::DEBUG_WARNING);
5062       return FAILURE;
5063     }
5064
5065     result = ASIOInit( &driverInfo );
5066     if ( result != ASE_OK ) {
5067       sprintf(message_, "RtApiAsio: error (%s) initializing driver (%s).", 
5068         GetAsioErrorString(result), devices_[device].name.c_str());
5069       error(RtError::DEBUG_WARNING);
5070       return FAILURE;
5071     }
5072   }
5073
5074   // Check the device channel count.
5075   long inputChannels, outputChannels;
5076   result = ASIOGetChannels( &inputChannels, &outputChannels );
5077   if ( result != ASE_OK ) {
5078     drivers.removeCurrentDriver();
5079     sprintf(message_, "RtApiAsio: error (%s) getting input/output channel count (%s).",
5080       GetAsioErrorString(result), 
5081       devices_[device].name.c_str());
5082     error(RtError::DEBUG_WARNING);
5083     return FAILURE;
5084   }
5085
5086   if ( ( mode == OUTPUT && channels > outputChannels) ||
5087        ( mode == INPUT && channels > inputChannels) ) {
5088     drivers.removeCurrentDriver();
5089     sprintf(message_, "RtApiAsio: driver (%s) does not support requested channel count (%d).",
5090             devices_[device].name.c_str(), channels);
5091     error(RtError::DEBUG_WARNING);
5092     return FAILURE;
5093   }
5094   stream_.nDeviceChannels[mode] = channels;
5095   stream_.nUserChannels[mode] = channels;
5096
5097   // Verify the sample rate is supported.
5098   result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate );
5099   if ( result != ASE_OK ) {
5100     drivers.removeCurrentDriver();
5101     sprintf(message_, "RtApiAsio: driver (%s) does not support requested sample rate (%d).",
5102             devices_[device].name.c_str(), sampleRate);
5103     error(RtError::DEBUG_WARNING);
5104     return FAILURE;
5105   }
5106
5107   // Set the sample rate.
5108   result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );
5109   if ( result != ASE_OK ) {
5110     drivers.removeCurrentDriver();
5111     sprintf(message_, "RtApiAsio: driver (%s) error setting sample rate (%d).",
5112             devices_[device].name.c_str(), sampleRate);
5113     error(RtError::DEBUG_WARNING);
5114     return FAILURE;
5115   }
5116
5117   // Determine the driver data type.
5118   ASIOChannelInfo channelInfo;
5119   channelInfo.channel = 0;
5120   if ( mode == OUTPUT ) channelInfo.isInput = false;
5121   else channelInfo.isInput = true;
5122   result = ASIOGetChannelInfo( &channelInfo );
5123   if ( result != ASE_OK ) {
5124     drivers.removeCurrentDriver();
5125     sprintf(message_, "RtApiAsio: driver (%s) error getting data format.",
5126             devices_[device].name.c_str());
5127     error(RtError::DEBUG_WARNING);
5128     return FAILURE;
5129   }
5130
5131   // Assuming WINDOWS host is always little-endian.
5132   stream_.doByteSwap[mode] = false;
5133   stream_.userFormat = format;
5134   stream_.deviceFormat[mode] = 0;
5135   if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB ) {
5136     stream_.deviceFormat[mode] = RTAUDIO_SINT16;
5137     if ( channelInfo.type == ASIOSTInt16MSB ) stream_.doByteSwap[mode] = true;
5138   }
5139   else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB ) {
5140     stream_.deviceFormat[mode] = RTAUDIO_SINT32;
5141     if ( channelInfo.type == ASIOSTInt32MSB ) stream_.doByteSwap[mode] = true;
5142   }
5143   else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB ) {
5144     stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
5145     if ( channelInfo.type == ASIOSTFloat32MSB ) stream_.doByteSwap[mode] = true;
5146   }
5147   else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB ) {
5148     stream_.deviceFormat[mode] = RTAUDIO_FLOAT64;
5149     if ( channelInfo.type == ASIOSTFloat64MSB ) stream_.doByteSwap[mode] = true;
5150   }
5151
5152   if ( stream_.deviceFormat[mode] == 0 ) {
5153     drivers.removeCurrentDriver();
5154     sprintf(message_, "RtApiAsio: driver (%s) data format not supported by RtAudio.",
5155             devices_[device].name.c_str());
5156     error(RtError::DEBUG_WARNING);
5157     return FAILURE;
5158   }
5159
5160   // Set the buffer size.  For a duplex stream, this will end up
5161   // setting the buffer size based on the input constraints, which
5162   // should be ok.
5163   long minSize, maxSize, preferSize, granularity;
5164   result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity );
5165   if ( result != ASE_OK ) {
5166     drivers.removeCurrentDriver();
5167     sprintf(message_, "RtApiAsio: error (%s) on driver (%s) error getting buffer size.",
5168         GetAsioErrorString(result), 
5169         devices_[device].name.c_str());
5170     error(RtError::DEBUG_WARNING);
5171     return FAILURE;
5172   }
5173
5174   if ( *bufferSize < minSize ) *bufferSize = minSize;
5175   else if ( *bufferSize > maxSize ) *bufferSize = maxSize;
5176   else if ( granularity == -1 ) {
5177     // Make sure bufferSize is a power of two.
5178     double power = log10( (double) *bufferSize ) / log10( 2.0 );
5179     *bufferSize = (int) pow( 2.0, floor(power+0.5) );
5180     if ( *bufferSize < minSize ) *bufferSize = minSize;
5181     else if ( *bufferSize > maxSize ) *bufferSize = maxSize;
5182     else *bufferSize = preferSize;
5183   } else if (granularity != 0)
5184   {
5185     // to an even multiple of granularity, rounding up.
5186     *bufferSize = (*bufferSize + granularity-1)/granularity*granularity;
5187   }
5188
5189
5190
5191   if ( mode == INPUT && stream_.mode == OUTPUT && stream_.bufferSize != *bufferSize )
5192     std::cerr << "Possible input/output buffersize discrepancy!" << std::endl;
5193
5194   stream_.bufferSize = *bufferSize;
5195   stream_.nBuffers = 2;
5196
5197   // ASIO always uses deinterleaved channels.
5198   stream_.deInterleave[mode] = true;
5199
5200   // Allocate, if necessary, our AsioHandle structure for the stream.
5201   AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
5202   if ( handle == 0 ) {
5203     handle = (AsioHandle *) calloc(1, sizeof(AsioHandle));
5204     if ( handle == NULL ) {
5205       drivers.removeCurrentDriver();
5206       sprintf(message_, "RtApiAsio: error allocating AsioHandle memory (%s).",
5207               devices_[device].name.c_str());
5208       error(RtError::DEBUG_WARNING);
5209       return FAILURE;
5210     }
5211     handle->bufferInfos = 0;
5212     // Create a manual-reset event.
5213     handle->condition = CreateEvent( NULL,  // no security
5214                                      TRUE,  // manual-reset
5215                                      FALSE, // non-signaled initially
5216                                      NULL ); // unnamed
5217     stream_.apiHandle = (void *) handle;
5218   }
5219
5220   // Create the ASIO internal buffers.  Since RtAudio sets up input
5221   // and output separately, we'll have to dispose of previously
5222   // created output buffers for a duplex stream.
5223   if ( mode == INPUT && stream_.mode == OUTPUT ) {
5224     ASIODisposeBuffers();
5225     if ( handle->bufferInfos ) free( handle->bufferInfos );
5226   }
5227
5228   // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure.
5229   int i, nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];
5230   handle->bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) );
5231   if (handle->bufferInfos == NULL) {
5232     sprintf(message_, "RtApiAsio: error allocating bufferInfo memory (%s).",
5233             devices_[device].name.c_str());
5234     goto error;
5235   }
5236   ASIOBufferInfo *infos;
5237   infos = handle->bufferInfos;
5238   for ( i=0; i<stream_.nDeviceChannels[0]; i++, infos++ ) {
5239     infos->isInput = ASIOFalse;
5240     infos->channelNum = i;
5241     infos->buffers[0] = infos->buffers[1] = 0;
5242   }
5243   for ( i=0; i<stream_.nDeviceChannels[1]; i++, infos++ ) {
5244     infos->isInput = ASIOTrue;
5245     infos->channelNum = i;
5246     infos->buffers[0] = infos->buffers[1] = 0;
5247   }
5248
5249   // Set up the ASIO callback structure and create the ASIO data buffers.
5250   asioCallbacks.bufferSwitch = &bufferSwitch;
5251   asioCallbacks.sampleRateDidChange = &sampleRateChanged;
5252   asioCallbacks.asioMessage = &asioMessages;
5253   asioCallbacks.bufferSwitchTimeInfo = NULL;
5254   result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks);
5255   if ( result != ASE_OK ) {
5256     sprintf(message_, "RtApiAsio: eror (%s) on driver (%s) error creating buffers.",
5257       GetAsioErrorString(result), 
5258       devices_[device].name.c_str());
5259     goto error;
5260   }
5261
5262   // Set flags for buffer conversion.
5263   stream_.doConvertBuffer[mode] = false;
5264   if (stream_.userFormat != stream_.deviceFormat[mode])
5265     stream_.doConvertBuffer[mode] = true;
5266   if (stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode])
5267     stream_.doConvertBuffer[mode] = true;
5268   if (stream_.nUserChannels[mode] > 1 && stream_.deInterleave[mode])
5269     stream_.doConvertBuffer[mode] = true;
5270
5271   // Allocate necessary internal buffers
5272   if ( stream_.nUserChannels[0] != stream_.nUserChannels[1] ) {
5273
5274     long buffer_bytes;
5275     if (stream_.nUserChannels[0] >= stream_.nUserChannels[1])
5276       buffer_bytes = stream_.nUserChannels[0];
5277     else
5278       buffer_bytes = stream_.nUserChannels[1];
5279
5280     buffer_bytes *= *bufferSize * formatBytes(stream_.userFormat);
5281     if (stream_.userBuffer) free(stream_.userBuffer);
5282     stream_.userBuffer = (char *) calloc(buffer_bytes, 1);
5283     if (stream_.userBuffer == NULL) {
5284       sprintf(message_, "RtApiAsio: error (%s) allocating user buffer memory (%s).",
5285         GetAsioErrorString(result), 
5286         devices_[device].name.c_str());
5287       goto error;
5288     }
5289   }
5290
5291   if ( stream_.doConvertBuffer[mode] ) {
5292
5293     long buffer_bytes;
5294     bool makeBuffer = true;
5295     if ( mode == OUTPUT )
5296       buffer_bytes = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
5297     else { // mode == INPUT
5298       buffer_bytes = stream_.nDeviceChannels[1] * formatBytes(stream_.deviceFormat[1]);
5299       if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
5300         long bytes_out = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
5301         if ( buffer_bytes < bytes_out ) makeBuffer = false;
5302       }
5303     }
5304
5305     if ( makeBuffer ) {
5306       buffer_bytes *= *bufferSize;
5307       if (stream_.deviceBuffer) free(stream_.deviceBuffer);
5308       stream_.deviceBuffer = (char *) calloc(buffer_bytes, 1);
5309       if (stream_.deviceBuffer == NULL) {
5310         sprintf(message_, "RtApiAsio: error (%s) allocating device buffer memory (%s).",
5311           GetAsioErrorString(result), 
5312                 devices_[device].name.c_str());
5313         goto error;
5314       }
5315     }
5316   }
5317
5318   stream_.device[mode] = device;
5319   stream_.state = STREAM_STOPPED;
5320   if ( stream_.mode == OUTPUT && mode == INPUT )
5321     // We had already set up an output stream.
5322     stream_.mode = DUPLEX;
5323   else
5324     stream_.mode = mode;
5325   stream_.sampleRate = sampleRate;
5326   asioCallbackInfo = &stream_.callbackInfo;
5327   stream_.callbackInfo.object = (void *) this;
5328
5329   // Setup the buffer conversion information structure.
5330   if ( stream_.doConvertBuffer[mode] ) {
5331     if (mode == INPUT) { // convert device to user buffer
5332       stream_.convertInfo[mode].inJump = stream_.nDeviceChannels[1];
5333       stream_.convertInfo[mode].outJump = stream_.nUserChannels[1];
5334       stream_.convertInfo[mode].inFormat = stream_.deviceFormat[1];
5335       stream_.convertInfo[mode].outFormat = stream_.userFormat;
5336     }
5337     else { // convert user to device buffer
5338       stream_.convertInfo[mode].inJump = stream_.nUserChannels[0];
5339       stream_.convertInfo[mode].outJump = stream_.nDeviceChannels[0];
5340       stream_.convertInfo[mode].inFormat = stream_.userFormat;
5341       stream_.convertInfo[mode].outFormat = stream_.deviceFormat[0];
5342     }
5343
5344     if ( stream_.convertInfo[mode].inJump < stream_.convertInfo[mode].outJump )
5345       stream_.convertInfo[mode].channels = stream_.convertInfo[mode].inJump;
5346     else
5347       stream_.convertInfo[mode].channels = stream_.convertInfo[mode].outJump;
5348
5349     // Set up the interleave/deinterleave offsets.
5350     if ( mode == INPUT && stream_.deInterleave[1] ) {
5351       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
5352         stream_.convertInfo[mode].inOffset.push_back( k * stream_.bufferSize );
5353         stream_.convertInfo[mode].outOffset.push_back( k );
5354         stream_.convertInfo[mode].inJump = 1;
5355       }
5356     }
5357     else if (mode == OUTPUT && stream_.deInterleave[0]) {
5358       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
5359         stream_.convertInfo[mode].inOffset.push_back( k );
5360         stream_.convertInfo[mode].outOffset.push_back( k * stream_.bufferSize );
5361         stream_.convertInfo[mode].outJump = 1;
5362       }
5363     }
5364     else {
5365       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
5366         stream_.convertInfo[mode].inOffset.push_back( k );
5367         stream_.convertInfo[mode].outOffset.push_back( k );
5368       }
5369     }
5370   }
5371
5372   return SUCCESS;
5373
5374  error:
5375   ASIODisposeBuffers();
5376   drivers.removeCurrentDriver();
5377
5378   if ( handle ) {
5379     CloseHandle( handle->condition );
5380     if ( handle->bufferInfos )
5381       free( handle->bufferInfos );
5382     free( handle );
5383     stream_.apiHandle = 0;
5384   }
5385
5386   if (stream_.userBuffer) {
5387     free(stream_.userBuffer);
5388     stream_.userBuffer = 0;
5389   }
5390
5391   error(RtError::DEBUG_WARNING);
5392   return FAILURE;
5393 }
5394
5395 void RtApiAsio :: closeStream()
5396 {
5397   // We don't want an exception to be thrown here because this
5398   // function is called by our class destructor.  So, do our own
5399   // streamId check.
5400   if ( stream_.mode == UNINITIALIZED ) {
5401     sprintf(message_, "RtApiAsio::closeStream(): no open stream to close!");
5402     error(RtError::WARNING);
5403     return;
5404   }
5405
5406   if (stream_.state == STREAM_RUNNING)
5407     ASIOStop();
5408
5409   ASIODisposeBuffers();
5410   drivers.removeCurrentDriver();
5411
5412   AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
5413   if ( handle ) {
5414     CloseHandle( handle->condition );
5415     if ( handle->bufferInfos )
5416       free( handle->bufferInfos );
5417     free( handle );
5418     stream_.apiHandle = 0;
5419   }
5420
5421   if (stream_.userBuffer) {
5422     free(stream_.userBuffer);
5423     stream_.userBuffer = 0;
5424   }
5425
5426   if (stream_.deviceBuffer) {
5427     free(stream_.deviceBuffer);
5428     stream_.deviceBuffer = 0;
5429   }
5430
5431   stream_.mode = UNINITIALIZED;
5432 }
5433
5434 void RtApiAsio :: setStreamCallback(RtAudioCallback callback, void *userData)
5435 {
5436   verifyStream();
5437
5438   if ( stream_.callbackInfo.usingCallback ) {
5439     sprintf(message_, "RtApiAsio: A callback is already set for this stream!");
5440     error(RtError::WARNING);
5441     return;
5442   }
5443
5444   stream_.callbackInfo.callback = (void *) callback;
5445   stream_.callbackInfo.userData = userData;
5446   stream_.callbackInfo.usingCallback = true;
5447 }
5448
5449 void RtApiAsio :: cancelStreamCallback()
5450 {
5451   verifyStream();
5452
5453   if (stream_.callbackInfo.usingCallback) {
5454
5455     if (stream_.state == STREAM_RUNNING)
5456       stopStream();
5457
5458     MUTEX_LOCK(&stream_.mutex);
5459
5460     stream_.callbackInfo.usingCallback = false;
5461     stream_.callbackInfo.userData = NULL;
5462     stream_.state = STREAM_STOPPED;
5463     stream_.callbackInfo.callback = NULL;
5464
5465     MUTEX_UNLOCK(&stream_.mutex);
5466   }
5467 }
5468
5469 void RtApiAsio :: startStream()
5470 {
5471   verifyStream();
5472   if (stream_.state == STREAM_RUNNING) return;
5473
5474   MUTEX_LOCK(&stream_.mutex);
5475
5476   ASIOError result = ASIOStart();
5477   if ( result != ASE_OK ) {
5478     sprintf(message_, "RtApiAsio: error starting device (%s).",
5479               devices_[stream_.device[0]].name.c_str());
5480     MUTEX_UNLOCK(&stream_.mutex);
5481     error(RtError::DRIVER_ERROR);
5482   }
5483   AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
5484   handle->stopStream = false;
5485   stream_.state = STREAM_RUNNING;
5486
5487   MUTEX_UNLOCK(&stream_.mutex);
5488 }
5489
5490 void RtApiAsio :: stopStream()
5491 {
5492   verifyStream();
5493   if (stream_.state == STREAM_STOPPED) return;
5494
5495   // Change the state before the lock to improve shutdown response
5496   // when using a callback.
5497   stream_.state = STREAM_STOPPED;
5498   MUTEX_LOCK(&stream_.mutex);
5499
5500   ASIOError result = ASIOStop();
5501   if ( result != ASE_OK ) {
5502     sprintf(message_, "RtApiAsio: error stopping device (%s).",
5503               devices_[stream_.device[0]].name.c_str());
5504     MUTEX_UNLOCK(&stream_.mutex);
5505     error(RtError::DRIVER_ERROR);
5506   }
5507
5508   MUTEX_UNLOCK(&stream_.mutex);
5509 }
5510
5511 void RtApiAsio :: abortStream()
5512 {
5513   stopStream();
5514 }
5515
5516 void RtApiAsio :: tickStream()
5517 {
5518   verifyStream();
5519
5520   if (stream_.state == STREAM_STOPPED)
5521     return;
5522
5523   if (stream_.callbackInfo.usingCallback) {
5524     sprintf(message_, "RtApiAsio: tickStream() should not be used when a callback function is set!");
5525     error(RtError::WARNING);
5526     return;
5527   }
5528
5529   AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
5530
5531   MUTEX_LOCK(&stream_.mutex);
5532
5533   // Release the stream_mutex here and wait for the event
5534   // to become signaled by the callback process.
5535   MUTEX_UNLOCK(&stream_.mutex);
5536   WaitForMultipleObjects(1, &handle->condition, FALSE, INFINITE);
5537   ResetEvent( handle->condition );
5538 }
5539
5540 void RtApiAsio :: callbackEvent(long bufferIndex)
5541 {
5542   verifyStream();
5543
5544   if (stream_.state == STREAM_STOPPED) return;
5545
5546   CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
5547   AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
5548   if ( info->usingCallback && handle->stopStream ) {
5549     // Check if the stream should be stopped (via the previous user
5550     // callback return value).  We stop the stream here, rather than
5551     // after the function call, so that output data can first be
5552     // processed.
5553     this->stopStream();
5554     return;
5555   }
5556
5557   MUTEX_LOCK(&stream_.mutex);
5558
5559   // Invoke user callback first, to get fresh output data.
5560   if ( info->usingCallback ) {
5561     RtAudioCallback callback = (RtAudioCallback) info->callback;
5562     if ( callback(stream_.userBuffer, stream_.bufferSize, info->userData) )
5563       handle->stopStream = true;
5564   }
5565
5566   int bufferBytes, j;
5567   int nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];
5568   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
5569
5570     bufferBytes = stream_.bufferSize * formatBytes(stream_.deviceFormat[0]);
5571     if (stream_.doConvertBuffer[0]) {
5572
5573       convertBuffer( stream_.deviceBuffer, stream_.userBuffer, stream_.convertInfo[0] );
5574       if ( stream_.doByteSwap[0] )
5575         byteSwapBuffer(stream_.deviceBuffer,
5576                        stream_.bufferSize * stream_.nDeviceChannels[0],
5577                        stream_.deviceFormat[0]);
5578
5579       // Always de-interleave ASIO output data.
5580       j = 0;
5581       for ( int i=0; i<nChannels; i++ ) {
5582         if ( handle->bufferInfos[i].isInput != ASIOTrue )
5583           memcpy(handle->bufferInfos[i].buffers[bufferIndex],
5584                  &stream_.deviceBuffer[j++*bufferBytes], bufferBytes );
5585       }
5586     }
5587     else { // single channel only
5588
5589       if (stream_.doByteSwap[0])
5590         byteSwapBuffer(stream_.userBuffer,
5591                        stream_.bufferSize * stream_.nUserChannels[0],
5592                        stream_.userFormat);
5593
5594       for ( int i=0; i<nChannels; i++ ) {
5595         if ( handle->bufferInfos[i].isInput != ASIOTrue ) {
5596           memcpy(handle->bufferInfos[i].buffers[bufferIndex], stream_.userBuffer, bufferBytes );
5597           break;
5598         }
5599       }
5600     }
5601   }
5602
5603   if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
5604
5605     bufferBytes = stream_.bufferSize * formatBytes(stream_.deviceFormat[1]);
5606     if (stream_.doConvertBuffer[1]) {
5607
5608       // Always interleave ASIO input data.
5609       j = 0;
5610       for ( int i=0; i<nChannels; i++ ) {
5611         if ( handle->bufferInfos[i].isInput == ASIOTrue )
5612           memcpy(&stream_.deviceBuffer[j++*bufferBytes],
5613                  handle->bufferInfos[i].buffers[bufferIndex],
5614                  bufferBytes );
5615       }
5616
5617       if ( stream_.doByteSwap[1] )
5618         byteSwapBuffer(stream_.deviceBuffer,
5619                        stream_.bufferSize * stream_.nDeviceChannels[1],
5620                        stream_.deviceFormat[1]);
5621       convertBuffer( stream_.userBuffer, stream_.deviceBuffer, stream_.convertInfo[1] );
5622
5623     }
5624     else { // single channel only
5625       for ( int i=0; i<nChannels; i++ ) {
5626         if ( handle->bufferInfos[i].isInput == ASIOTrue ) {
5627           memcpy(stream_.userBuffer,
5628                  handle->bufferInfos[i].buffers[bufferIndex],
5629                  bufferBytes );
5630           break;
5631         }
5632       }
5633
5634       if (stream_.doByteSwap[1])
5635         byteSwapBuffer(stream_.userBuffer,
5636                        stream_.bufferSize * stream_.nUserChannels[1],
5637                        stream_.userFormat);
5638     }
5639   }
5640
5641   if ( !info->usingCallback )
5642     SetEvent( handle->condition );
5643
5644   // The following call was suggested by Malte Clasen.  While the API
5645   // documentation indicates it should not be required, some device
5646   // drivers apparently do not function correctly without it.
5647   ASIOOutputReady();
5648
5649   MUTEX_UNLOCK(&stream_.mutex);
5650 }
5651
5652 //******************** End of __WINDOWS_ASIO__ *********************//
5653 #endif
5654
5655 #if defined(__WINDOWS_DS__) // Windows DirectSound API
5656
5657
5658 #include <dsound.h>
5659 #include <assert.h>
5660
5661 #define MINIMUM_DEVICE_BUFFER_SIZE 32768
5662
5663
5664 #ifdef _MSC_VER // if Microsoft Visual C++
5665 #pragma comment(lib,"winmm.lib") // then, auto-link winmm.lib. Otherwise, it has to be added manually.
5666 #endif
5667
5668
5669 static inline DWORD dsPointerDifference(DWORD laterPointer,DWORD earlierPointer,DWORD bufferSize)
5670 {
5671   if (laterPointer > earlierPointer)
5672     return laterPointer-earlierPointer;
5673   else
5674     return laterPointer-earlierPointer+bufferSize;
5675 }
5676
5677 static inline DWORD dsPointerBetween(DWORD pointer, DWORD laterPointer,DWORD earlierPointer, DWORD bufferSize)
5678 {
5679   if (pointer > bufferSize) pointer -= bufferSize;
5680
5681   if (laterPointer < earlierPointer)
5682     laterPointer += bufferSize;
5683
5684   if (pointer < earlierPointer)
5685     pointer += bufferSize;
5686
5687   return pointer >= earlierPointer && pointer < laterPointer;
5688 }
5689
5690 #undef GENERATE_DEBUG_LOG // Define this to generate a debug timing log file in c:/rtaudiolog.txt"
5691 #ifdef GENERATE_DEBUG_LOG
5692
5693 #include "mmsystem.h"
5694 #include "fstream"
5695
5696 struct TTickRecord
5697 {
5698   DWORD currentReadPointer, safeReadPointer;
5699   DWORD currentWritePointer, safeWritePointer;
5700   DWORD readTime, writeTime;
5701   DWORD nextWritePointer, nextReadPointer;
5702 };
5703
5704 int currentDebugLogEntry = 0;
5705 std::vector<TTickRecord> debugLog(2000);
5706
5707
5708 #endif
5709
5710 // A structure to hold various information related to the DirectSound
5711 // API implementation.
5712 struct DsHandle {
5713   void *object;
5714   void *buffer;
5715   UINT bufferPointer;  
5716   DWORD dsBufferSize;
5717   DWORD dsPointerLeadTime; // the number of bytes ahead of the safe pointer to lead by.
5718 };
5719
5720
5721 RtApiDs::RtDsStatistics RtApiDs::statistics;
5722
5723 // Provides a backdoor hook to monitor for DirectSound read overruns and write underruns.
5724 RtApiDs::RtDsStatistics RtApiDs::getDsStatistics()
5725 {
5726   RtDsStatistics s = statistics;
5727   // update the calculated fields.
5728   
5729
5730   if (s.inputFrameSize != 0)
5731     s.latency += s.readDeviceSafeLeadBytes*1.0/s.inputFrameSize / s.sampleRate;
5732
5733   if (s.outputFrameSize != 0)
5734     s.latency += (s.writeDeviceSafeLeadBytes+ s.writeDeviceBufferLeadBytes)*1.0/s.outputFrameSize / s.sampleRate;
5735
5736   return s;
5737 }
5738
5739 // Declarations for utility functions, callbacks, and structures
5740 // specific to the DirectSound implementation.
5741 static bool CALLBACK deviceCountCallback(LPGUID lpguid,
5742                                          LPCTSTR description,
5743                                          LPCTSTR module,
5744                                          LPVOID lpContext);
5745
5746 static bool CALLBACK deviceInfoCallback(LPGUID lpguid,
5747                                         LPCTSTR description,
5748                                         LPCTSTR module,
5749                                         LPVOID lpContext);
5750
5751 static bool CALLBACK defaultDeviceCallback(LPGUID lpguid,
5752                                            LPCTSTR description,
5753                                            LPCTSTR module,
5754                                            LPVOID lpContext);
5755
5756 static bool CALLBACK deviceIdCallback(LPGUID lpguid,
5757                                       LPCTSTR description,
5758                                       LPCTSTR module,
5759                                       LPVOID lpContext);
5760
5761 static char* getErrorString(int code);
5762
5763 extern "C" unsigned __stdcall callbackHandler(void *ptr);
5764
5765 struct enum_info {
5766   std::string name;
5767   LPGUID id;
5768   bool isInput;
5769   bool isValid;
5770 };
5771
5772 RtApiDs :: RtApiDs()
5773 {
5774   // Dsound will run both-threaded. If CoInitialize fails, then just
5775   // accept whatever the mainline chose for a threading model.
5776   coInitialized = false;
5777   HRESULT hr = CoInitialize(NULL);
5778   if ( !FAILED(hr) )
5779     coInitialized = true;
5780
5781   this->initialize();
5782
5783   if (nDevices_ <= 0) {
5784     sprintf(message_, "RtApiDs: no Windows DirectSound audio devices found!");
5785     error(RtError::NO_DEVICES_FOUND);
5786  }
5787 }
5788
5789 RtApiDs :: ~RtApiDs()
5790 {
5791   if (coInitialized)
5792     CoUninitialize(); // balanced call.
5793
5794   if ( stream_.mode != UNINITIALIZED ) closeStream();
5795 }
5796
5797 int RtApiDs :: getDefaultInputDevice(void)
5798 {
5799   enum_info info;
5800
5801   // Enumerate through devices to find the default output.
5802   HRESULT result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)defaultDeviceCallback, &info);
5803   if ( FAILED(result) ) {
5804     sprintf(message_, "RtApiDs: Error performing default input device enumeration: %s.",
5805             getErrorString(result));
5806     error(RtError::WARNING);
5807     return 0;
5808   }
5809
5810   for ( int i=0; i<nDevices_; i++ ) {
5811     if ( info.name == devices_[i].name ) return i;
5812   }
5813
5814   return 0;
5815 }
5816
5817 int RtApiDs :: getDefaultOutputDevice(void)
5818 {
5819   enum_info info;
5820   info.name[0] = '\0';
5821
5822   // Enumerate through devices to find the default output.
5823   HRESULT result = DirectSoundEnumerate((LPDSENUMCALLBACK)defaultDeviceCallback, &info);
5824   if ( FAILED(result) ) {
5825     sprintf(message_, "RtApiDs: Error performing default output device enumeration: %s.",
5826             getErrorString(result));
5827     error(RtError::WARNING);
5828     return 0;
5829   }
5830
5831   for ( int i=0; i<nDevices_; i++ )
5832     if ( info.name == devices_[i].name ) return i;
5833
5834   return 0;
5835 }
5836
5837 void RtApiDs :: initialize(void)
5838 {
5839   int i, ins = 0, outs = 0, count = 0;
5840   HRESULT result;
5841   nDevices_ = 0;
5842
5843   // Count DirectSound devices.
5844   result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &outs);
5845   if ( FAILED(result) ) {
5846     sprintf(message_, "RtApiDs: Unable to enumerate through sound playback devices: %s.",
5847             getErrorString(result));
5848     error(RtError::DRIVER_ERROR);
5849   }
5850
5851   // Count DirectSoundCapture devices.
5852   result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &ins);
5853   if ( FAILED(result) ) {
5854     sprintf(message_, "RtApiDs: Unable to enumerate through sound capture devices: %s.",
5855             getErrorString(result));
5856     error(RtError::DRIVER_ERROR);
5857   }
5858
5859   count = ins + outs;
5860   if (count == 0) return;
5861
5862   std::vector<enum_info> info(count);
5863   for (i=0; i<count; i++) {
5864     if (i < outs) info[i].isInput = false;
5865     else info[i].isInput = true;
5866   }
5867
5868   // Get playback device info and check capabilities.
5869   result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]);
5870   if ( FAILED(result) ) {
5871     sprintf(message_, "RtApiDs: Unable to enumerate through sound playback devices: %s.",
5872             getErrorString(result));
5873     error(RtError::DRIVER_ERROR);
5874   }
5875
5876   // Get capture device info and check capabilities.
5877   result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]);
5878   if ( FAILED(result) ) {
5879     sprintf(message_, "RtApiDs: Unable to enumerate through sound capture devices: %s.",
5880             getErrorString(result));
5881     error(RtError::DRIVER_ERROR);
5882   }
5883
5884   // Create device structures for valid devices and write device names
5885   // to each.  Devices are considered invalid if they cannot be
5886   // opened, they report < 1 supported channels, or they report no
5887   // supported data (capture only).
5888   RtApiDevice device;
5889   for (i=0; i<count; i++) {
5890     if ( info[i].isValid ) {
5891       device.name.erase();
5892       device.name = info[i].name;
5893       devices_.push_back(device);
5894     }
5895   }
5896
5897   nDevices_ = devices_.size();
5898   return;
5899 }
5900
5901 void RtApiDs :: probeDeviceInfo(RtApiDevice *info)
5902 {
5903   enum_info dsinfo;
5904   dsinfo.name = info->name;
5905   dsinfo.isValid = false;
5906
5907   // Enumerate through input devices to find the id (if it exists).
5908   HRESULT result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
5909   if ( FAILED(result) ) {
5910     sprintf(message_, "RtApiDs: Error performing input device id enumeration: %s.",
5911             getErrorString(result));
5912     error(RtError::DEBUG_WARNING);
5913     return;
5914   }
5915
5916   // Do capture probe first.
5917   if ( dsinfo.isValid == false )
5918     goto playback_probe;
5919
5920   LPDIRECTSOUNDCAPTURE  input;
5921   result = DirectSoundCaptureCreate( dsinfo.id, &input, NULL );
5922   if ( FAILED(result) ) {
5923     sprintf(message_, "RtApiDs: Could not create capture object (%s): %s.",
5924             info->name.c_str(), getErrorString(result));
5925     error(RtError::DEBUG_WARNING);
5926     goto playback_probe;
5927   }
5928
5929   DSCCAPS in_caps;
5930   in_caps.dwSize = sizeof(in_caps);
5931   result = input->GetCaps( &in_caps );
5932   if ( FAILED(result) ) {
5933     input->Release();
5934     sprintf(message_, "RtApiDs: Could not get capture capabilities (%s): %s.",
5935             info->name.c_str(), getErrorString(result));
5936     error(RtError::DEBUG_WARNING);
5937     goto playback_probe;
5938   }
5939
5940   // Get input channel information.
5941   info->minInputChannels = 1;
5942   info->maxInputChannels = in_caps.dwChannels;
5943
5944   // Get sample rate and format information.
5945   info->sampleRates.clear();
5946   if( in_caps.dwChannels == 2 ) {
5947     if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->nativeFormats |= RTAUDIO_SINT16;
5948     if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->nativeFormats |= RTAUDIO_SINT16;
5949     if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->nativeFormats |= RTAUDIO_SINT16;
5950     if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->nativeFormats |= RTAUDIO_SINT8;
5951     if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->nativeFormats |= RTAUDIO_SINT8;
5952     if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->nativeFormats |= RTAUDIO_SINT8;
5953
5954     if ( info->nativeFormats & RTAUDIO_SINT16 ) {
5955       if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->sampleRates.push_back( 11025 );
5956       if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->sampleRates.push_back( 22050 );
5957       if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->sampleRates.push_back( 44100 );
5958     }
5959     else if ( info->nativeFormats & RTAUDIO_SINT8 ) {
5960       if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->sampleRates.push_back( 11025 );
5961       if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->sampleRates.push_back( 22050 );
5962       if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->sampleRates.push_back( 44100 );
5963     }
5964   }
5965   else if ( in_caps.dwChannels == 1 ) {
5966     if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->nativeFormats |= RTAUDIO_SINT16;
5967     if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->nativeFormats |= RTAUDIO_SINT16;
5968     if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->nativeFormats |= RTAUDIO_SINT16;
5969     if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->nativeFormats |= RTAUDIO_SINT8;
5970     if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->nativeFormats |= RTAUDIO_SINT8;
5971     if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->nativeFormats |= RTAUDIO_SINT8;
5972
5973     if ( info->nativeFormats & RTAUDIO_SINT16 ) {
5974       if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->sampleRates.push_back( 11025 );
5975       if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->sampleRates.push_back( 22050 );
5976       if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->sampleRates.push_back( 44100 );
5977     }
5978     else if ( info->nativeFormats & RTAUDIO_SINT8 ) {
5979       if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->sampleRates.push_back( 11025 );
5980       if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->sampleRates.push_back( 22050 );
5981       if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->sampleRates.push_back( 44100 );
5982     }
5983   }
5984   else info->minInputChannels = 0; // technically, this would be an error
5985
5986   input->Release();
5987
5988  playback_probe:
5989
5990   dsinfo.isValid = false;
5991
5992   // Enumerate through output devices to find the id (if it exists).
5993   result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
5994   if ( FAILED(result) ) {
5995     sprintf(message_, "RtApiDs: Error performing output device id enumeration: %s.",
5996             getErrorString(result));
5997     error(RtError::DEBUG_WARNING);
5998     return;
5999   }
6000
6001   // Now do playback probe.
6002   if ( dsinfo.isValid == false )
6003     goto check_parameters;
6004
6005   LPDIRECTSOUND  output;
6006   DSCAPS out_caps;
6007   result = DirectSoundCreate( dsinfo.id, &output, NULL );
6008   if ( FAILED(result) ) {
6009     sprintf(message_, "RtApiDs: Could not create playback object (%s): %s.",
6010             info->name.c_str(), getErrorString(result));
6011     error(RtError::DEBUG_WARNING);
6012     goto check_parameters;
6013   }
6014
6015   out_caps.dwSize = sizeof(out_caps);
6016   result = output->GetCaps( &out_caps );
6017   if ( FAILED(result) ) {
6018     output->Release();
6019     sprintf(message_, "RtApiDs: Could not get playback capabilities (%s): %s.",
6020             info->name.c_str(), getErrorString(result));
6021     error(RtError::DEBUG_WARNING);
6022     goto check_parameters;
6023   }
6024
6025   // Get output channel information.
6026   info->minOutputChannels = 1;
6027   info->maxOutputChannels = ( out_caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
6028
6029   // Get sample rate information.  Use capture device rate information
6030   // if it exists.
6031   if ( info->sampleRates.size() == 0 ) {
6032     info->sampleRates.push_back( (int) out_caps.dwMinSecondarySampleRate );
6033     if ( out_caps.dwMaxSecondarySampleRate > out_caps.dwMinSecondarySampleRate )
6034       info->sampleRates.push_back( (int) out_caps.dwMaxSecondarySampleRate );
6035   }
6036   else {
6037     // Check input rates against output rate range.  If there's an
6038     // inconsistency (such as a duplex-capable device which reports a
6039     // single output rate of 48000 Hz), we'll go with the output
6040     // rate(s) since the DirectSoundCapture API is stupid and broken.
6041     // Note that the probed sample rate values are NOT used when
6042     // opening the device.  Thanks to Tue Andersen for reporting this.
6043     if ( info->sampleRates.back() < (int) out_caps.dwMinSecondarySampleRate ) {
6044       info->sampleRates.clear();
6045       info->sampleRates.push_back( (int) out_caps.dwMinSecondarySampleRate );
6046       if ( out_caps.dwMaxSecondarySampleRate > out_caps.dwMinSecondarySampleRate )
6047         info->sampleRates.push_back( (int) out_caps.dwMaxSecondarySampleRate );
6048     }
6049     else {
6050       for ( int i=info->sampleRates.size()-1; i>=0; i-- ) {
6051         if ( (unsigned int) info->sampleRates[i] > out_caps.dwMaxSecondarySampleRate )
6052           info->sampleRates.erase( info->sampleRates.begin() + i );
6053       }
6054       while ( info->sampleRates.size() > 0 &&
6055               ((unsigned int) info->sampleRates[0] < out_caps.dwMinSecondarySampleRate) ) {
6056         info->sampleRates.erase( info->sampleRates.begin() );
6057       }
6058     }
6059   }
6060
6061   // Get format information.
6062   if ( out_caps.dwFlags & DSCAPS_PRIMARY16BIT ) info->nativeFormats |= RTAUDIO_SINT16;
6063   if ( out_caps.dwFlags & DSCAPS_PRIMARY8BIT ) info->nativeFormats |= RTAUDIO_SINT8;
6064
6065   output->Release();
6066
6067  check_parameters:
6068   if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 ) {
6069     sprintf(message_, "RtApiDs: no reported input or output channels for device (%s).",
6070             info->name.c_str());
6071     error(RtError::DEBUG_WARNING);
6072     return;
6073   }
6074   if ( info->sampleRates.size() == 0 || info->nativeFormats == 0 ) {
6075     sprintf(message_, "RtApiDs: no reported sample rates or data formats for device (%s).",
6076             info->name.c_str());
6077     error(RtError::DEBUG_WARNING);
6078     return;
6079   }
6080
6081   // Determine duplex status.
6082   if (info->maxInputChannels < info->maxOutputChannels)
6083     info->maxDuplexChannels = info->maxInputChannels;
6084   else
6085     info->maxDuplexChannels = info->maxOutputChannels;
6086   if (info->minInputChannels < info->minOutputChannels)
6087     info->minDuplexChannels = info->minInputChannels;
6088   else
6089     info->minDuplexChannels = info->minOutputChannels;
6090
6091   if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true;
6092   else info->hasDuplexSupport = false;
6093
6094   info->probed = true;
6095
6096   return;
6097 }
6098
6099 bool RtApiDs :: probeDeviceOpen( int device, StreamMode mode, int channels, 
6100                                  int sampleRate, RtAudioFormat format,
6101                                  int *bufferSize, int numberOfBuffers)
6102 {
6103   HRESULT result;
6104   HWND hWnd = GetForegroundWindow();
6105
6106   // According to a note in PortAudio, using GetDesktopWindow()
6107   // instead of GetForegroundWindow() is supposed to avoid problems
6108   // that occur when the application's window is not the foreground
6109   // window.  Also, if the application window closes before the
6110   // DirectSound buffer, DirectSound can crash.  However, for console
6111   // applications, no sound was produced when using GetDesktopWindow().
6112   long buffer_size;
6113   LPVOID audioPtr;
6114   DWORD dataLen;
6115   int nBuffers;
6116
6117   // Check the numberOfBuffers parameter and limit the lowest value to
6118   // two.  This is a judgement call and a value of two is probably too
6119   // low for capture, but it should work for playback.
6120   if (numberOfBuffers < 2)
6121     nBuffers = 2;
6122   else
6123     nBuffers = numberOfBuffers;
6124
6125   // Define the wave format structure (16-bit PCM, srate, channels)
6126   WAVEFORMATEX waveFormat;
6127   ZeroMemory(&waveFormat, sizeof(WAVEFORMATEX));
6128   waveFormat.wFormatTag = WAVE_FORMAT_PCM;
6129   waveFormat.nChannels = channels;
6130   waveFormat.nSamplesPerSec = (unsigned long) sampleRate;
6131
6132   // Determine the data format.
6133   if ( devices_[device].nativeFormats ) { // 8-bit and/or 16-bit support
6134     if ( format == RTAUDIO_SINT8 ) {
6135       if ( devices_[device].nativeFormats & RTAUDIO_SINT8 )
6136         waveFormat.wBitsPerSample = 8;
6137       else
6138         waveFormat.wBitsPerSample = 16;
6139     }
6140     else {
6141       if ( devices_[device].nativeFormats & RTAUDIO_SINT16 )
6142         waveFormat.wBitsPerSample = 16;
6143       else
6144         waveFormat.wBitsPerSample = 8;
6145     }
6146   }
6147   else {
6148     sprintf(message_, "RtApiDs: no reported data formats for device (%s).",
6149             devices_[device].name.c_str());
6150     error(RtError::DEBUG_WARNING);
6151     return FAILURE;
6152   }
6153
6154   waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
6155   waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
6156
6157   // Determine the device buffer size. By default, 32k, but we will
6158   // grow it to make allowances for very large software buffer sizes.
6159   DWORD dsBufferSize = 0;
6160   DWORD dsPointerLeadTime = 0;
6161
6162   buffer_size = MINIMUM_DEVICE_BUFFER_SIZE; // sound cards will always *knock wood* support this
6163
6164   enum_info dsinfo;
6165   void *ohandle = 0, *bhandle = 0;
6166   //  strncpy( dsinfo.name, devices_[device].name.c_str(), 64 );
6167   dsinfo.name = devices_[device].name;
6168   dsinfo.isValid = false;
6169   if ( mode == OUTPUT ) {
6170
6171     dsPointerLeadTime = numberOfBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels;
6172
6173     // If the user wants an even bigger buffer, increase the device buffer size accordingly.
6174     while ( dsPointerLeadTime * 2U > (DWORD)buffer_size )
6175       buffer_size *= 2;
6176
6177     if ( devices_[device].maxOutputChannels < channels ) {
6178       sprintf(message_, "RtApiDs: requested channels (%d) > than supported (%d) by device (%s).",
6179               channels, devices_[device].maxOutputChannels, devices_[device].name.c_str());
6180       error(RtError::DEBUG_WARNING);
6181       return FAILURE;
6182     }
6183
6184     // Enumerate through output devices to find the id (if it exists).
6185     result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
6186     if ( FAILED(result) ) {
6187       sprintf(message_, "RtApiDs: Error performing output device id enumeration: %s.",
6188               getErrorString(result));
6189       error(RtError::DEBUG_WARNING);
6190       return FAILURE;
6191     }
6192
6193     if ( dsinfo.isValid == false ) {
6194       sprintf(message_, "RtApiDs: output device (%s) id not found!", devices_[device].name.c_str());
6195       error(RtError::DEBUG_WARNING);
6196       return FAILURE;
6197     }
6198
6199     LPGUID id = dsinfo.id;
6200     LPDIRECTSOUND  object;
6201     LPDIRECTSOUNDBUFFER buffer;
6202     DSBUFFERDESC bufferDescription;
6203     
6204     result = DirectSoundCreate( id, &object, NULL );
6205     if ( FAILED(result) ) {
6206       sprintf(message_, "RtApiDs: Could not create playback object (%s): %s.",
6207               devices_[device].name.c_str(), getErrorString(result));
6208       error(RtError::DEBUG_WARNING);
6209       return FAILURE;
6210     }
6211
6212     // Set cooperative level to DSSCL_EXCLUSIVE
6213     result = object->SetCooperativeLevel(hWnd, DSSCL_EXCLUSIVE);
6214     if ( FAILED(result) ) {
6215       object->Release();
6216       sprintf(message_, "RtApiDs: Unable to set cooperative level (%s): %s.",
6217               devices_[device].name.c_str(), getErrorString(result));
6218       error(RtError::DEBUG_WARNING);
6219       return FAILURE;
6220     }
6221
6222     // Even though we will write to the secondary buffer, we need to
6223     // access the primary buffer to set the correct output format
6224     // (since the default is 8-bit, 22 kHz!).  Setup the DS primary
6225     // buffer description.
6226     ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
6227     bufferDescription.dwSize = sizeof(DSBUFFERDESC);
6228     bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
6229     // Obtain the primary buffer
6230     result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
6231     if ( FAILED(result) ) {
6232       object->Release();
6233       sprintf(message_, "RtApiDs: Unable to access primary buffer (%s): %s.",
6234               devices_[device].name.c_str(), getErrorString(result));
6235       error(RtError::DEBUG_WARNING);
6236       return FAILURE;
6237     }
6238
6239     // Set the primary DS buffer sound format.
6240     result = buffer->SetFormat(&waveFormat);
6241     if ( FAILED(result) ) {
6242       object->Release();
6243       sprintf(message_, "RtApiDs: Unable to set primary buffer format (%s): %s.",
6244               devices_[device].name.c_str(), getErrorString(result));
6245       error(RtError::DEBUG_WARNING);
6246       return FAILURE;
6247     }
6248
6249     // Setup the secondary DS buffer description.
6250     dsBufferSize = (DWORD)buffer_size;
6251     ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
6252     bufferDescription.dwSize = sizeof(DSBUFFERDESC);
6253     bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
6254                                   DSBCAPS_GETCURRENTPOSITION2 |
6255                                   DSBCAPS_LOCHARDWARE );  // Force hardware mixing
6256     bufferDescription.dwBufferBytes = buffer_size;
6257     bufferDescription.lpwfxFormat = &waveFormat;
6258
6259     // Try to create the secondary DS buffer.  If that doesn't work,
6260     // try to use software mixing.  Otherwise, there's a problem.
6261     result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
6262     if ( FAILED(result) ) {
6263       bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
6264                                     DSBCAPS_GETCURRENTPOSITION2 |
6265                                     DSBCAPS_LOCSOFTWARE );  // Force software mixing
6266       result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
6267       if ( FAILED(result) ) {
6268         object->Release();
6269         sprintf(message_, "RtApiDs: Unable to create secondary DS buffer (%s): %s.",
6270                 devices_[device].name.c_str(), getErrorString(result));
6271         error(RtError::DEBUG_WARNING);
6272         return FAILURE;
6273       }
6274     }
6275
6276     // Get the buffer size ... might be different from what we specified.
6277     DSBCAPS dsbcaps;
6278     dsbcaps.dwSize = sizeof(DSBCAPS);
6279     buffer->GetCaps(&dsbcaps);
6280     buffer_size = dsbcaps.dwBufferBytes;
6281
6282     // Lock the DS buffer
6283     result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0);
6284     if ( FAILED(result) ) {
6285       object->Release();
6286       buffer->Release();
6287       sprintf(message_, "RtApiDs: Unable to lock buffer (%s): %s.",
6288               devices_[device].name.c_str(), getErrorString(result));
6289       error(RtError::DEBUG_WARNING);
6290       return FAILURE;
6291     }
6292
6293     // Zero the DS buffer
6294     ZeroMemory(audioPtr, dataLen);
6295
6296     // Unlock the DS buffer
6297     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
6298     if ( FAILED(result) ) {
6299       object->Release();
6300       buffer->Release();
6301       sprintf(message_, "RtApiDs: Unable to unlock buffer(%s): %s.",
6302               devices_[device].name.c_str(), getErrorString(result));
6303       error(RtError::DEBUG_WARNING);
6304       return FAILURE;
6305     }
6306
6307     ohandle = (void *) object;
6308     bhandle = (void *) buffer;
6309     stream_.nDeviceChannels[0] = channels;
6310   }
6311
6312   if ( mode == INPUT ) {
6313
6314     if ( devices_[device].maxInputChannels < channels ) {
6315       sprintf(message_, "RtAudioDS: device (%s) does not support %d channels.", devices_[device].name.c_str(), channels);
6316       error(RtError::DEBUG_WARNING);
6317       return FAILURE;
6318     }
6319
6320     // Enumerate through input devices to find the id (if it exists).
6321     result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
6322     if ( FAILED(result) ) {
6323       sprintf(message_, "RtApiDs: Error performing input device id enumeration: %s.",
6324               getErrorString(result));
6325       error(RtError::DEBUG_WARNING);
6326       return FAILURE;
6327     }
6328
6329     if ( dsinfo.isValid == false ) {
6330       sprintf(message_, "RtAudioDS: input device (%s) id not found!", devices_[device].name.c_str());
6331       error(RtError::DEBUG_WARNING);
6332       return FAILURE;
6333     }
6334
6335     LPGUID id = dsinfo.id;
6336     LPDIRECTSOUNDCAPTURE  object;
6337     LPDIRECTSOUNDCAPTUREBUFFER buffer;
6338     DSCBUFFERDESC bufferDescription;
6339
6340     result = DirectSoundCaptureCreate( id, &object, NULL );
6341     if ( FAILED(result) ) {
6342       sprintf(message_, "RtApiDs: Could not create capture object (%s): %s.",
6343               devices_[device].name.c_str(), getErrorString(result));
6344       error(RtError::DEBUG_WARNING);
6345       return FAILURE;
6346     }
6347
6348     // Setup the secondary DS buffer description.
6349     dsBufferSize = buffer_size;
6350     ZeroMemory(&bufferDescription, sizeof(DSCBUFFERDESC));
6351     bufferDescription.dwSize = sizeof(DSCBUFFERDESC);
6352     bufferDescription.dwFlags = 0;
6353     bufferDescription.dwReserved = 0;
6354     bufferDescription.dwBufferBytes = buffer_size;
6355     bufferDescription.lpwfxFormat = &waveFormat;
6356
6357     // Create the capture buffer.
6358     result = object->CreateCaptureBuffer(&bufferDescription, &buffer, NULL);
6359     if ( FAILED(result) ) {
6360       object->Release();
6361       sprintf(message_, "RtApiDs: Unable to create capture buffer (%s): %s.",
6362               devices_[device].name.c_str(), getErrorString(result));
6363       error(RtError::DEBUG_WARNING);
6364       return FAILURE;
6365     }
6366
6367     // Lock the capture buffer
6368     result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0);
6369     if ( FAILED(result) ) {
6370       object->Release();
6371       buffer->Release();
6372       sprintf(message_, "RtApiDs: Unable to lock capture buffer (%s): %s.",
6373               devices_[device].name.c_str(), getErrorString(result));
6374       error(RtError::DEBUG_WARNING);
6375       return FAILURE;
6376     }
6377
6378     // Zero the buffer
6379     ZeroMemory(audioPtr, dataLen);
6380
6381     // Unlock the buffer
6382     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
6383     if ( FAILED(result) ) {
6384       object->Release();
6385       buffer->Release();
6386       sprintf(message_, "RtApiDs: Unable to unlock capture buffer (%s): %s.",
6387               devices_[device].name.c_str(), getErrorString(result));
6388       error(RtError::DEBUG_WARNING);
6389       return FAILURE;
6390     }
6391
6392     ohandle = (void *) object;
6393     bhandle = (void *) buffer;
6394     stream_.nDeviceChannels[1] = channels;
6395   }
6396
6397   stream_.userFormat = format;
6398   if ( waveFormat.wBitsPerSample == 8 )
6399     stream_.deviceFormat[mode] = RTAUDIO_SINT8;
6400   else
6401     stream_.deviceFormat[mode] = RTAUDIO_SINT16;
6402   stream_.nUserChannels[mode] = channels;
6403
6404   stream_.bufferSize = *bufferSize;
6405
6406   // Set flags for buffer conversion
6407   stream_.doConvertBuffer[mode] = false;
6408   if (stream_.userFormat != stream_.deviceFormat[mode])
6409     stream_.doConvertBuffer[mode] = true;
6410   if (stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode])
6411     stream_.doConvertBuffer[mode] = true;
6412
6413   // Allocate necessary internal buffers
6414   if ( stream_.nUserChannels[0] != stream_.nUserChannels[1] ) {
6415
6416     long buffer_bytes;
6417     if (stream_.nUserChannels[0] >= stream_.nUserChannels[1])
6418       buffer_bytes = stream_.nUserChannels[0];
6419     else
6420       buffer_bytes = stream_.nUserChannels[1];
6421
6422     buffer_bytes *= *bufferSize * formatBytes(stream_.userFormat);
6423     if (stream_.userBuffer) free(stream_.userBuffer);
6424     stream_.userBuffer = (char *) calloc(buffer_bytes, 1);
6425     if (stream_.userBuffer == NULL) {
6426       sprintf(message_, "RtApiDs: error allocating user buffer memory (%s).",
6427               devices_[device].name.c_str());
6428       goto error;
6429     }
6430   }
6431
6432   if ( stream_.doConvertBuffer[mode] ) {
6433
6434     long buffer_bytes;
6435     bool makeBuffer = true;
6436     if ( mode == OUTPUT )
6437       buffer_bytes = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
6438     else { // mode == INPUT
6439       buffer_bytes = stream_.nDeviceChannels[1] * formatBytes(stream_.deviceFormat[1]);
6440       if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
6441         long bytes_out = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
6442         if ( buffer_bytes < bytes_out ) makeBuffer = false;
6443       }
6444     }
6445
6446     if ( makeBuffer ) {
6447       buffer_bytes *= *bufferSize;
6448       if (stream_.deviceBuffer) free(stream_.deviceBuffer);
6449       stream_.deviceBuffer = (char *) calloc(buffer_bytes, 1);
6450       if (stream_.deviceBuffer == NULL) {
6451         sprintf(message_, "RtApiDs: error allocating device buffer memory (%s).",
6452                 devices_[device].name.c_str());
6453         goto error;
6454       }
6455     }
6456   }
6457
6458   // Allocate our DsHandle structures for the stream.
6459   DsHandle *handles;
6460   if ( stream_.apiHandle == 0 ) {
6461     handles = (DsHandle *) calloc(2, sizeof(DsHandle));
6462     if ( handles == NULL ) {
6463       sprintf(message_, "RtApiDs: Error allocating DsHandle memory (%s).",
6464               devices_[device].name.c_str());
6465       goto error;
6466     }
6467     handles[0].object = 0;
6468     handles[1].object = 0;
6469     stream_.apiHandle = (void *) handles;
6470   }
6471   else
6472     handles = (DsHandle *) stream_.apiHandle;
6473   handles[mode].object = ohandle;
6474   handles[mode].buffer = bhandle;
6475   handles[mode].dsBufferSize = dsBufferSize;
6476   handles[mode].dsPointerLeadTime = dsPointerLeadTime;
6477
6478   stream_.device[mode] = device;
6479   stream_.state = STREAM_STOPPED;
6480   if ( stream_.mode == OUTPUT && mode == INPUT )
6481     // We had already set up an output stream.
6482     stream_.mode = DUPLEX;
6483   else
6484     stream_.mode = mode;
6485   stream_.nBuffers = nBuffers;
6486   stream_.sampleRate = sampleRate;
6487
6488   // Setup the buffer conversion information structure.
6489   if ( stream_.doConvertBuffer[mode] ) {
6490     if (mode == INPUT) { // convert device to user buffer
6491       stream_.convertInfo[mode].inJump = stream_.nDeviceChannels[1];
6492       stream_.convertInfo[mode].outJump = stream_.nUserChannels[1];
6493       stream_.convertInfo[mode].inFormat = stream_.deviceFormat[1];
6494       stream_.convertInfo[mode].outFormat = stream_.userFormat;
6495     }
6496     else { // convert user to device buffer
6497       stream_.convertInfo[mode].inJump = stream_.nUserChannels[0];
6498       stream_.convertInfo[mode].outJump = stream_.nDeviceChannels[0];
6499       stream_.convertInfo[mode].inFormat = stream_.userFormat;
6500       stream_.convertInfo[mode].outFormat = stream_.deviceFormat[0];
6501     }
6502
6503     if ( stream_.convertInfo[mode].inJump < stream_.convertInfo[mode].outJump )
6504       stream_.convertInfo[mode].channels = stream_.convertInfo[mode].inJump;
6505     else
6506       stream_.convertInfo[mode].channels = stream_.convertInfo[mode].outJump;
6507
6508     // Set up the interleave/deinterleave offsets.
6509     if ( mode == INPUT && stream_.deInterleave[1] ) {
6510       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
6511         stream_.convertInfo[mode].inOffset.push_back( k * stream_.bufferSize );
6512         stream_.convertInfo[mode].outOffset.push_back( k );
6513         stream_.convertInfo[mode].inJump = 1;
6514       }
6515     }
6516     else if (mode == OUTPUT && stream_.deInterleave[0]) {
6517       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
6518         stream_.convertInfo[mode].inOffset.push_back( k );
6519         stream_.convertInfo[mode].outOffset.push_back( k * stream_.bufferSize );
6520         stream_.convertInfo[mode].outJump = 1;
6521       }
6522     }
6523     else {
6524       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
6525         stream_.convertInfo[mode].inOffset.push_back( k );
6526         stream_.convertInfo[mode].outOffset.push_back( k );
6527       }
6528     }
6529   }
6530
6531   return SUCCESS;
6532
6533  error:
6534   if (handles) {
6535     if (handles[0].object) {
6536       LPDIRECTSOUND object = (LPDIRECTSOUND) handles[0].object;
6537       LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handles[0].buffer;
6538       if (buffer) buffer->Release();
6539       object->Release();
6540     }
6541     if (handles[1].object) {
6542       LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handles[1].object;
6543       LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handles[1].buffer;
6544       if (buffer) buffer->Release();
6545       object->Release();
6546     }
6547     free(handles);
6548     stream_.apiHandle = 0;
6549   }
6550
6551   if (stream_.userBuffer) {
6552     free(stream_.userBuffer);
6553     stream_.userBuffer = 0;
6554   }
6555
6556   error(RtError::DEBUG_WARNING);
6557   return FAILURE;
6558 }
6559
6560 void RtApiDs :: setStreamCallback(RtAudioCallback callback, void *userData)
6561 {
6562   verifyStream();
6563
6564   CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
6565   if ( info->usingCallback ) {
6566     sprintf(message_, "RtApiDs: A callback is already set for this stream!");
6567     error(RtError::WARNING);
6568     return;
6569   }
6570
6571   info->callback = (void *) callback;
6572   info->userData = userData;
6573   info->usingCallback = true;
6574   info->object = (void *) this;
6575
6576   unsigned thread_id;
6577   info->thread = _beginthreadex(NULL, 0, &callbackHandler,
6578                                 &stream_.callbackInfo, 0, &thread_id);
6579   if (info->thread == 0) {
6580     info->usingCallback = false;
6581     sprintf(message_, "RtApiDs: error starting callback thread!");
6582     error(RtError::THREAD_ERROR);
6583   }
6584
6585   // When spawning multiple threads in quick succession, it appears to be
6586   // necessary to wait a bit for each to initialize ... another windoism!
6587   Sleep(1);
6588 }
6589
6590 void RtApiDs :: cancelStreamCallback()
6591 {
6592   verifyStream();
6593
6594   if (stream_.callbackInfo.usingCallback) {
6595
6596     if (stream_.state == STREAM_RUNNING)
6597       stopStream();
6598
6599     MUTEX_LOCK(&stream_.mutex);
6600
6601     stream_.callbackInfo.usingCallback = false;
6602     WaitForSingleObject( (HANDLE)stream_.callbackInfo.thread, INFINITE );
6603     CloseHandle( (HANDLE)stream_.callbackInfo.thread );
6604     stream_.callbackInfo.thread = 0;
6605     stream_.callbackInfo.callback = NULL;
6606     stream_.callbackInfo.userData = NULL;
6607
6608     MUTEX_UNLOCK(&stream_.mutex);
6609   }
6610 }
6611
6612 void RtApiDs :: closeStream()
6613 {
6614   // We don't want an exception to be thrown here because this
6615   // function is called by our class destructor.  So, do our own
6616   // streamId check.
6617   if ( stream_.mode == UNINITIALIZED ) {
6618     sprintf(message_, "RtApiDs::closeStream(): no open stream to close!");
6619     error(RtError::WARNING);
6620     return;
6621   }
6622
6623   if (stream_.callbackInfo.usingCallback) {
6624     stream_.callbackInfo.usingCallback = false;
6625     WaitForSingleObject( (HANDLE)stream_.callbackInfo.thread, INFINITE );
6626     CloseHandle( (HANDLE)stream_.callbackInfo.thread );
6627   }
6628
6629   DsHandle *handles = (DsHandle *) stream_.apiHandle;
6630   if (handles) {
6631     if (handles[0].object) {
6632       LPDIRECTSOUND object = (LPDIRECTSOUND) handles[0].object;
6633       LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handles[0].buffer;
6634       if (buffer) {
6635         buffer->Stop();
6636         buffer->Release();
6637       }
6638       object->Release();
6639     }
6640
6641     if (handles[1].object) {
6642       LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handles[1].object;
6643       LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handles[1].buffer;
6644       if (buffer) {
6645         buffer->Stop();
6646         buffer->Release();
6647       }
6648       object->Release();
6649     }
6650     free(handles);
6651     stream_.apiHandle = 0;
6652   }
6653     
6654   if (stream_.userBuffer) {
6655     free(stream_.userBuffer);
6656     stream_.userBuffer = 0;
6657   }
6658
6659   if (stream_.deviceBuffer) {
6660     free(stream_.deviceBuffer);
6661     stream_.deviceBuffer = 0;
6662   }
6663
6664   stream_.mode = UNINITIALIZED;
6665 }
6666
6667 void RtApiDs :: startStream()
6668 {
6669   verifyStream();
6670   if (stream_.state == STREAM_RUNNING) return;
6671
6672   // Increase scheduler frequency on lesser windows (a side-effect of
6673   // increasing timer accuracy).  On greater windows (Win2K or later),
6674   // this is already in effect.
6675
6676   MUTEX_LOCK(&stream_.mutex);
6677   
6678   DsHandle *handles = (DsHandle *) stream_.apiHandle;
6679
6680   timeBeginPeriod(1); 
6681
6682   memset(&statistics,0,sizeof(statistics));
6683   statistics.sampleRate = stream_.sampleRate;
6684   statistics.writeDeviceBufferLeadBytes = handles[0].dsPointerLeadTime ;
6685
6686   buffersRolling = false;
6687   duplexPrerollBytes = 0;
6688
6689   if (stream_.mode == DUPLEX) {
6690     // 0.5 seconds of silence in DUPLEX mode while the devices spin up and synchronize.
6691     duplexPrerollBytes = (int)(0.5*stream_.sampleRate*formatBytes( stream_.deviceFormat[1])*stream_.nDeviceChannels[1]);
6692   }
6693
6694 #ifdef GENERATE_DEBUG_LOG
6695   currentDebugLogEntry = 0;
6696 #endif  
6697
6698   HRESULT result;
6699   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
6700       statistics.outputFrameSize = formatBytes( stream_.deviceFormat[0])
6701                                   *stream_.nDeviceChannels[0];
6702
6703     LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handles[0].buffer;
6704     result = buffer->Play( 0, 0, DSBPLAY_LOOPING );
6705     if ( FAILED(result) ) {
6706       sprintf(message_, "RtApiDs: Unable to start buffer (%s): %s.",
6707               devices_[stream_.device[0]].name.c_str(), getErrorString(result));
6708       error(RtError::DRIVER_ERROR);
6709     }
6710   }
6711
6712   if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
6713     statistics.inputFrameSize = formatBytes( stream_.deviceFormat[1])
6714                                   *stream_.nDeviceChannels[1];
6715
6716     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handles[1].buffer;
6717     result = buffer->Start(DSCBSTART_LOOPING );
6718     if ( FAILED(result) ) {
6719       sprintf(message_, "RtApiDs: Unable to start capture buffer (%s): %s.",
6720               devices_[stream_.device[1]].name.c_str(), getErrorString(result));
6721       error(RtError::DRIVER_ERROR);
6722     }
6723   }
6724   stream_.state = STREAM_RUNNING;
6725
6726   MUTEX_UNLOCK(&stream_.mutex);
6727 }
6728
6729 void RtApiDs :: stopStream()
6730 {
6731   verifyStream();
6732   if (stream_.state == STREAM_STOPPED) return;
6733
6734   // Change the state before the lock to improve shutdown response
6735   // when using a callback.
6736   stream_.state = STREAM_STOPPED;
6737   MUTEX_LOCK(&stream_.mutex);
6738
6739   timeEndPeriod(1); // revert to normal scheduler frequency on lesser windows.
6740
6741 #ifdef GENERATE_DEBUG_LOG
6742   // Write the timing log to a .TSV file for analysis in Excel.
6743   unlink("c:/rtaudiolog.txt");
6744   std::ofstream os("c:/rtaudiolog.txt");
6745   os << "writeTime\treadDelay\tnextWritePointer\tnextReadPointer\tcurrentWritePointer\tsafeWritePointer\tcurrentReadPointer\tsafeReadPointer" << std::endl;
6746   for (int i = 0; i < currentDebugLogEntry ; ++i) {
6747     TTickRecord &r = debugLog[i];
6748     os << r.writeTime-debugLog[0].writeTime << "\t" << (r.readTime-r.writeTime) << "\t"
6749        << r.nextWritePointer % BUFFER_SIZE << "\t" << r.nextReadPointer % BUFFER_SIZE 
6750        << "\t" << r.currentWritePointer % BUFFER_SIZE << "\t" << r.safeWritePointer % BUFFER_SIZE 
6751        << "\t" << r.currentReadPointer % BUFFER_SIZE << "\t" << r.safeReadPointer % BUFFER_SIZE << std::endl;
6752   }
6753 #endif
6754
6755   // There is no specific DirectSound API call to "drain" a buffer
6756   // before stopping.  We can hack this for playback by writing
6757   // buffers of zeroes over the entire buffer.  For capture, the
6758   // concept is less clear so we'll repeat what we do in the
6759   // abortStream() case.
6760   HRESULT result;
6761   DWORD dsBufferSize;
6762   LPVOID buffer1 = NULL;
6763   LPVOID buffer2 = NULL;
6764   DWORD bufferSize1 = 0;
6765   DWORD bufferSize2 = 0;
6766   DsHandle *handles = (DsHandle *) stream_.apiHandle;
6767   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
6768
6769     DWORD currentPos, safePos;
6770     long buffer_bytes = stream_.bufferSize * stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
6771
6772     LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) handles[0].buffer;
6773     DWORD nextWritePos = handles[0].bufferPointer;
6774     dsBufferSize = handles[0].dsBufferSize;
6775     DWORD dsBytesWritten = 0;
6776
6777     // Write zeroes for at least dsBufferSize bytes. 
6778     while ( dsBytesWritten < dsBufferSize ) {
6779
6780       // Find out where the read and "safe write" pointers are.
6781       result = dsBuffer->GetCurrentPosition( &currentPos, &safePos );
6782       if ( FAILED(result) ) {
6783         sprintf(message_, "RtApiDs: Unable to get current position (%s): %s.",
6784                 devices_[stream_.device[0]].name.c_str(), getErrorString(result));
6785         error(RtError::DRIVER_ERROR);
6786       }
6787
6788       // Chase nextWritePosition.
6789       if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
6790       DWORD endWrite = nextWritePos + buffer_bytes;
6791
6792       // Check whether the entire write region is behind the play pointer.
6793       while ( currentPos < endWrite ) {
6794         double millis = (endWrite - currentPos) * 900.0;
6795         millis /= ( formatBytes(stream_.deviceFormat[0]) * stream_.nDeviceChannels[0] *stream_.sampleRate);
6796         if ( millis < 1.0 ) millis = 1.0;
6797         Sleep( (DWORD) millis );
6798
6799         // Wake up, find out where we are now
6800         result = dsBuffer->GetCurrentPosition( &currentPos, &safePos );
6801         if ( FAILED(result) ) {
6802           sprintf(message_, "RtApiDs: Unable to get current position (%s): %s.",
6803                   devices_[stream_.device[0]].name.c_str(), getErrorString(result));
6804           error(RtError::DRIVER_ERROR);
6805         }
6806
6807         if ( currentPos < (DWORD)nextWritePos ) currentPos += dsBufferSize; // unwrap offset
6808       }
6809
6810       // Lock free space in the buffer
6811       result = dsBuffer->Lock( nextWritePos, buffer_bytes, &buffer1,
6812                                &bufferSize1, &buffer2, &bufferSize2, 0);
6813       if ( FAILED(result) ) {
6814         sprintf(message_, "RtApiDs: Unable to lock buffer during playback (%s): %s.",
6815                 devices_[stream_.device[0]].name.c_str(), getErrorString(result));
6816         error(RtError::DRIVER_ERROR);
6817       }
6818
6819       // Zero the free space
6820       ZeroMemory( buffer1, bufferSize1 );
6821       if (buffer2 != NULL) ZeroMemory( buffer2, bufferSize2 );
6822
6823       // Update our buffer offset and unlock sound buffer
6824       dsBuffer->Unlock( buffer1, bufferSize1, buffer2, bufferSize2 );
6825       if ( FAILED(result) ) {
6826         sprintf(message_, "RtApiDs: Unable to unlock buffer during playback (%s): %s.",
6827                 devices_[stream_.device[0]].name.c_str(), getErrorString(result));
6828         error(RtError::DRIVER_ERROR);
6829       }
6830       nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize;
6831       handles[0].bufferPointer = nextWritePos;
6832       dsBytesWritten += buffer_bytes;
6833     }
6834
6835     // OK, now stop the buffer.
6836     result = dsBuffer->Stop();
6837     if ( FAILED(result) ) {
6838       sprintf(message_, "RtApiDs: Unable to stop buffer (%s): %s",
6839               devices_[stream_.device[0]].name.c_str(), getErrorString(result));
6840       error(RtError::DRIVER_ERROR);
6841     }
6842
6843     // If we play again, start at the beginning of the buffer.
6844     handles[0].bufferPointer = 0;
6845   }
6846
6847   if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
6848
6849     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handles[1].buffer;
6850     buffer1 = NULL;
6851     bufferSize1 = 0;
6852
6853     result = buffer->Stop();
6854     if ( FAILED(result) ) {
6855       sprintf(message_, "RtApiDs: Unable to stop capture buffer (%s): %s",
6856               devices_[stream_.device[1]].name.c_str(), getErrorString(result));
6857       error(RtError::DRIVER_ERROR);
6858     }
6859
6860     dsBufferSize = handles[1].dsBufferSize;
6861
6862     // Lock the buffer and clear it so that if we start to play again,
6863     // we won't have old data playing.
6864     result = buffer->Lock(0, dsBufferSize, &buffer1, &bufferSize1, NULL, NULL, 0);
6865     if ( FAILED(result) ) {
6866       sprintf(message_, "RtApiDs: Unable to lock capture buffer (%s): %s.",
6867               devices_[stream_.device[1]].name.c_str(), getErrorString(result));
6868       error(RtError::DRIVER_ERROR);
6869     }
6870
6871     // Zero the DS buffer
6872     ZeroMemory(buffer1, bufferSize1);
6873
6874     // Unlock the DS buffer
6875     result = buffer->Unlock(buffer1, bufferSize1, NULL, 0);
6876     if ( FAILED(result) ) {
6877       sprintf(message_, "RtApiDs: Unable to unlock capture buffer (%s): %s.",
6878               devices_[stream_.device[1]].name.c_str(), getErrorString(result));
6879       error(RtError::DRIVER_ERROR);
6880     }
6881
6882     // If we start recording again, we must begin at beginning of buffer.
6883     handles[1].bufferPointer = 0;
6884   }
6885
6886   MUTEX_UNLOCK(&stream_.mutex);
6887 }
6888
6889 void RtApiDs :: abortStream()
6890 {
6891   verifyStream();
6892   if (stream_.state == STREAM_STOPPED) return;
6893
6894   // Change the state before the lock to improve shutdown response
6895   // when using a callback.
6896   stream_.state = STREAM_STOPPED;
6897   MUTEX_LOCK(&stream_.mutex);
6898
6899   timeEndPeriod(1); // revert to normal scheduler frequency on lesser windows.
6900
6901   HRESULT result;
6902   long dsBufferSize;
6903   LPVOID audioPtr;
6904   DWORD dataLen;
6905   DsHandle *handles = (DsHandle *) stream_.apiHandle;
6906   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
6907  
6908     LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handles[0].buffer;
6909     result = buffer->Stop();
6910     if ( FAILED(result) ) {
6911       sprintf(message_, "RtApiDs: Unable to stop buffer (%s): %s",
6912               devices_[stream_.device[0]].name.c_str(), getErrorString(result));
6913       error(RtError::DRIVER_ERROR);
6914     }
6915
6916     dsBufferSize = handles[0].dsBufferSize;
6917
6918     // Lock the buffer and clear it so that if we start to play again,
6919     // we won't have old data playing.
6920     result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0);
6921     if ( FAILED(result) ) {
6922       sprintf(message_, "RtApiDs: Unable to lock buffer (%s): %s.",
6923               devices_[stream_.device[0]].name.c_str(), getErrorString(result));
6924       error(RtError::DRIVER_ERROR);
6925     }
6926
6927     // Zero the DS buffer
6928     ZeroMemory(audioPtr, dataLen);
6929
6930     // Unlock the DS buffer
6931     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
6932     if ( FAILED(result) ) {
6933       sprintf(message_, "RtApiDs: Unable to unlock buffer (%s): %s.",
6934               devices_[stream_.device[0]].name.c_str(), getErrorString(result));
6935       error(RtError::DRIVER_ERROR);
6936     }
6937
6938     // If we start playing again, we must begin at beginning of buffer.
6939     handles[0].bufferPointer = 0;
6940   }
6941
6942   if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
6943     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handles[1].buffer;
6944     audioPtr = NULL;
6945     dataLen = 0;
6946
6947     result = buffer->Stop();
6948     if ( FAILED(result) ) {
6949       sprintf(message_, "RtApiDs: Unable to stop capture buffer (%s): %s",
6950               devices_[stream_.device[1]].name.c_str(), getErrorString(result));
6951       error(RtError::DRIVER_ERROR);
6952     }
6953
6954     dsBufferSize = handles[1].dsBufferSize;
6955
6956     // Lock the buffer and clear it so that if we start to play again,
6957     // we won't have old data playing.
6958     result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0);
6959     if ( FAILED(result) ) {
6960       sprintf(message_, "RtApiDs: Unable to lock capture buffer (%s): %s.",
6961               devices_[stream_.device[1]].name.c_str(), getErrorString(result));
6962       error(RtError::DRIVER_ERROR);
6963     }
6964
6965     // Zero the DS buffer
6966     ZeroMemory(audioPtr, dataLen);
6967
6968     // Unlock the DS buffer
6969     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
6970     if ( FAILED(result) ) {
6971       sprintf(message_, "RtApiDs: Unable to unlock capture buffer (%s): %s.",
6972               devices_[stream_.device[1]].name.c_str(), getErrorString(result));
6973       error(RtError::DRIVER_ERROR);
6974     }
6975
6976     // If we start recording again, we must begin at beginning of buffer.
6977     handles[1].bufferPointer = 0;
6978   }
6979
6980   MUTEX_UNLOCK(&stream_.mutex);
6981 }
6982
6983 int RtApiDs :: streamWillBlock()
6984 {
6985   verifyStream();
6986   if (stream_.state == STREAM_STOPPED) return 0;
6987
6988   MUTEX_LOCK(&stream_.mutex);
6989
6990   int channels;
6991   int frames = 0;
6992   HRESULT result;
6993   DWORD currentPos, safePos;
6994   channels = 1;
6995   DsHandle *handles = (DsHandle *) stream_.apiHandle;
6996   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
6997
6998     LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) handles[0].buffer;
6999     UINT nextWritePos = handles[0].bufferPointer;
7000     channels = stream_.nDeviceChannels[0];
7001     DWORD dsBufferSize = handles[0].dsBufferSize;
7002
7003     // Find out where the read and "safe write" pointers are.
7004     result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
7005     if ( FAILED(result) ) {
7006       sprintf(message_, "RtApiDs: Unable to get current position (%s): %s.",
7007               devices_[stream_.device[0]].name.c_str(), getErrorString(result));
7008       error(RtError::DRIVER_ERROR);
7009     }
7010
7011     DWORD leadPos = safePos + handles[0].dsPointerLeadTime;
7012     if (leadPos > dsBufferSize) {
7013       leadPos -= dsBufferSize;
7014     }
7015     if ( leadPos < nextWritePos ) leadPos += dsBufferSize; // unwrap offset
7016
7017     frames = (leadPos - nextWritePos);
7018     frames /= channels * formatBytes(stream_.deviceFormat[0]);
7019   }
7020
7021   if (stream_.mode == INPUT ) {
7022       // note that we don't block on DUPLEX input anymore. We run lockstep with the write pointer instead.
7023
7024     LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handles[1].buffer;
7025     UINT nextReadPos = handles[1].bufferPointer;
7026     channels = stream_.nDeviceChannels[1];
7027     DWORD dsBufferSize = handles[1].dsBufferSize;
7028
7029     // Find out where the write and "safe read" pointers are.
7030     result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
7031     if ( FAILED(result) ) {
7032       sprintf(message_, "RtApiDs: Unable to get current capture position (%s): %s.",
7033               devices_[stream_.device[1]].name.c_str(), getErrorString(result));
7034       error(RtError::DRIVER_ERROR);
7035     }
7036
7037     if ( safePos < (DWORD)nextReadPos ) safePos += dsBufferSize; // unwrap offset
7038
7039     frames = (int)(safePos - nextReadPos);
7040     frames /= channels * formatBytes(stream_.deviceFormat[1]);
7041   }
7042
7043   frames = stream_.bufferSize - frames;
7044   if (frames < 0) frames = 0;
7045
7046   MUTEX_UNLOCK(&stream_.mutex);
7047   return frames;
7048 }
7049
7050 void RtApiDs :: tickStream()
7051 {
7052   verifyStream();
7053
7054   int stopStream = 0;
7055   if (stream_.state == STREAM_STOPPED) {
7056     if (stream_.callbackInfo.usingCallback) Sleep(50); // sleep 50 milliseconds
7057     return;
7058   }
7059   else if (stream_.callbackInfo.usingCallback) {
7060     RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
7061     stopStream = callback(stream_.userBuffer, stream_.bufferSize, stream_.callbackInfo.userData);
7062   }
7063
7064   MUTEX_LOCK(&stream_.mutex);
7065
7066   // The state might change while waiting on a mutex.
7067   if (stream_.state == STREAM_STOPPED) {
7068     MUTEX_UNLOCK(&stream_.mutex);
7069     return;
7070   }
7071
7072   HRESULT result;
7073   DWORD currentWritePos, safeWritePos;
7074   DWORD currentReadPos, safeReadPos;
7075   DWORD leadPos;
7076   UINT nextWritePos;
7077
7078 #ifdef GENERATE_DEBUG_LOG
7079   DWORD writeTime, readTime;
7080 #endif
7081
7082   LPVOID buffer1 = NULL;
7083   LPVOID buffer2 = NULL;
7084   DWORD bufferSize1 = 0;
7085   DWORD bufferSize2 = 0;
7086
7087   char *buffer;
7088   long buffer_bytes;
7089   DsHandle *handles = (DsHandle *) stream_.apiHandle;
7090
7091   if (stream_.mode == DUPLEX && !buffersRolling) {
7092     assert(handles[0].dsBufferSize == handles[1].dsBufferSize);
7093
7094     // It takes a while for the devices to get rolling. As a result,
7095     // there's no guarantee that the capture and write device pointers
7096     // will move in lockstep.  Wait here for both devices to start
7097     // rolling, and then set our buffer pointers accordingly.
7098     // e.g. Crystal Drivers: the capture buffer starts up 5700 to 9600
7099     // bytes later than the write buffer.
7100
7101     // Stub: a serious risk of having a pre-emptive scheduling round
7102     // take place between the two GetCurrentPosition calls... but I'm
7103     // really not sure how to solve the problem.  Temporarily boost to
7104     // Realtime priority, maybe; but I'm not sure what priority the
7105     // directsound service threads run at. We *should* be roughly
7106     // within a ms or so of correct.
7107
7108     LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handles[0].buffer;
7109     LPDIRECTSOUNDCAPTUREBUFFER dsCaptureBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handles[1].buffer;
7110
7111     DWORD initialWritePos, initialSafeWritePos;
7112     DWORD initialReadPos, initialSafeReadPos;;
7113
7114     result = dsWriteBuffer->GetCurrentPosition(&initialWritePos, &initialSafeWritePos);
7115     if ( FAILED(result) ) {
7116       sprintf(message_, "RtApiDs: Unable to get current position (%s): %s.",
7117               devices_[stream_.device[0]].name.c_str(), getErrorString(result));
7118       error(RtError::DRIVER_ERROR);
7119     }
7120     result = dsCaptureBuffer->GetCurrentPosition(&initialReadPos, &initialSafeReadPos);
7121     if ( FAILED(result) ) {
7122       sprintf(message_, "RtApiDs: Unable to get current capture position (%s): %s.",
7123               devices_[stream_.device[1]].name.c_str(), getErrorString(result));
7124       error(RtError::DRIVER_ERROR);
7125     }
7126     while (true) {
7127       result = dsWriteBuffer->GetCurrentPosition(&currentWritePos, &safeWritePos);
7128       if ( FAILED(result) ) {
7129         sprintf(message_, "RtApiDs: Unable to get current position (%s): %s.",
7130                 devices_[stream_.device[0]].name.c_str(), getErrorString(result));
7131         error(RtError::DRIVER_ERROR);
7132       }
7133       result = dsCaptureBuffer->GetCurrentPosition(&currentReadPos, &safeReadPos);
7134       if ( FAILED(result) ) {
7135         sprintf(message_, "RtApiDs: Unable to get current capture position (%s): %s.",
7136                 devices_[stream_.device[1]].name.c_str(), getErrorString(result));
7137         error(RtError::DRIVER_ERROR);
7138       }
7139       if (safeWritePos != initialSafeWritePos && safeReadPos != initialSafeReadPos) {
7140         break;
7141       }
7142       Sleep(1);
7143     }
7144
7145     assert( handles[0].dsBufferSize == handles[1].dsBufferSize );
7146
7147     buffersRolling = true;
7148     handles[0].bufferPointer = (safeWritePos + handles[0].dsPointerLeadTime);
7149     handles[1].bufferPointer = safeReadPos;
7150
7151   }
7152
7153   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
7154     
7155     LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) handles[0].buffer;
7156
7157     // Setup parameters and do buffer conversion if necessary.
7158     if (stream_.doConvertBuffer[0]) {
7159       buffer = stream_.deviceBuffer;
7160       convertBuffer( buffer, stream_.userBuffer, stream_.convertInfo[0] );
7161       buffer_bytes = stream_.bufferSize * stream_.nDeviceChannels[0];
7162       buffer_bytes *= formatBytes(stream_.deviceFormat[0]);
7163     }
7164     else {
7165       buffer = stream_.userBuffer;
7166       buffer_bytes = stream_.bufferSize * stream_.nUserChannels[0];
7167       buffer_bytes *= formatBytes(stream_.userFormat);
7168     }
7169
7170     // No byte swapping necessary in DirectSound implementation.
7171
7172     // Ahhh ... windoze.  16-bit data is signed but 8-bit data is
7173     // unsigned.  So, we need to convert our signed 8-bit data here to
7174     // unsigned.
7175     if ( stream_.deviceFormat[0] == RTAUDIO_SINT8 )
7176       for ( int i=0; i<buffer_bytes; i++ ) buffer[i] = (unsigned char) (buffer[i] + 128);
7177
7178     DWORD dsBufferSize = handles[0].dsBufferSize;
7179           nextWritePos = handles[0].bufferPointer;
7180
7181     DWORD endWrite;
7182     while ( true ) {
7183       // Find out where the read and "safe write" pointers are.
7184       result = dsBuffer->GetCurrentPosition(&currentWritePos, &safeWritePos);
7185       if ( FAILED(result) ) {
7186         sprintf(message_, "RtApiDs: Unable to get current position (%s): %s.",
7187                 devices_[stream_.device[0]].name.c_str(), getErrorString(result));
7188         error(RtError::DRIVER_ERROR);
7189       }
7190
7191       leadPos = safeWritePos + handles[0].dsPointerLeadTime;
7192       if ( leadPos > dsBufferSize ) leadPos -= dsBufferSize;
7193       if ( leadPos < nextWritePos ) leadPos += dsBufferSize; // unwrap offset
7194       endWrite = nextWritePos + buffer_bytes;
7195
7196       // Check whether the entire write region is behind the play pointer.
7197       if ( leadPos >= endWrite ) break;
7198
7199       // If we are here, then we must wait until the play pointer gets
7200       // beyond the write region.  The approach here is to use the
7201       // Sleep() function to suspend operation until safePos catches
7202       // up. Calculate number of milliseconds to wait as:
7203       //   time = distance * (milliseconds/second) * fudgefactor /
7204       //          ((bytes/sample) * (samples/second))
7205       // A "fudgefactor" less than 1 is used because it was found
7206       // that sleeping too long was MUCH worse than sleeping for
7207       // several shorter periods.
7208       double millis = (endWrite - leadPos) * 900.0;
7209       millis /= ( formatBytes(stream_.deviceFormat[0]) *stream_.nDeviceChannels[0]* stream_.sampleRate);
7210       if ( millis < 1.0 ) millis = 1.0;
7211       if ( millis > 50.0 ) {
7212         static int nOverruns = 0;
7213         ++nOverruns;
7214       }
7215       Sleep( (DWORD) millis );
7216     }
7217
7218 #ifdef GENERATE_DEBUG_LOG
7219     writeTime = timeGetTime();
7220 #endif
7221
7222     if (statistics.writeDeviceSafeLeadBytes < dsPointerDifference(safeWritePos,currentWritePos,handles[0].dsBufferSize)) {
7223       statistics.writeDeviceSafeLeadBytes = dsPointerDifference(safeWritePos,currentWritePos,handles[0].dsBufferSize);
7224     }
7225
7226     if ( dsPointerBetween( nextWritePos, safeWritePos, currentWritePos, dsBufferSize )
7227          || dsPointerBetween( endWrite, safeWritePos, currentWritePos, dsBufferSize ) ) { 
7228       // We've strayed into the forbidden zone ... resync the read pointer.
7229       ++statistics.numberOfWriteUnderruns;
7230       nextWritePos = safeWritePos + handles[0].dsPointerLeadTime-buffer_bytes+dsBufferSize;
7231       while (nextWritePos >= dsBufferSize) nextWritePos-= dsBufferSize;
7232       handles[0].bufferPointer = nextWritePos;
7233       endWrite = nextWritePos + buffer_bytes;
7234     }
7235     
7236     // Lock free space in the buffer
7237     result = dsBuffer->Lock( nextWritePos, buffer_bytes, &buffer1,
7238                              &bufferSize1, &buffer2, &bufferSize2, 0 );
7239     if ( FAILED(result) ) {
7240       sprintf(message_, "RtApiDs: Unable to lock buffer during playback (%s): %s.",
7241               devices_[stream_.device[0]].name.c_str(), getErrorString(result));
7242       error(RtError::DRIVER_ERROR);
7243     }
7244
7245     // Copy our buffer into the DS buffer
7246     CopyMemory(buffer1, buffer, bufferSize1);
7247     if (buffer2 != NULL) CopyMemory(buffer2, buffer+bufferSize1, bufferSize2);
7248
7249     // Update our buffer offset and unlock sound buffer
7250     dsBuffer->Unlock( buffer1, bufferSize1, buffer2, bufferSize2 );
7251     if ( FAILED(result) ) {
7252       sprintf(message_, "RtApiDs: Unable to unlock buffer during playback (%s): %s.",
7253               devices_[stream_.device[0]].name.c_str(), getErrorString(result));
7254       error(RtError::DRIVER_ERROR);
7255     }
7256     nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize;
7257     handles[0].bufferPointer = nextWritePos;
7258   }
7259
7260   if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
7261
7262     // Setup parameters.
7263     if (stream_.doConvertBuffer[1]) {
7264       buffer = stream_.deviceBuffer;
7265       buffer_bytes = stream_.bufferSize * stream_.nDeviceChannels[1];
7266       buffer_bytes *= formatBytes(stream_.deviceFormat[1]);
7267     }
7268     else {
7269       buffer = stream_.userBuffer;
7270       buffer_bytes = stream_.bufferSize * stream_.nUserChannels[1];
7271       buffer_bytes *= formatBytes(stream_.userFormat);
7272     }
7273     LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handles[1].buffer;
7274     long nextReadPos = handles[1].bufferPointer;
7275     DWORD dsBufferSize = handles[1].dsBufferSize;
7276
7277     // Find out where the write and "safe read" pointers are.
7278     result = dsBuffer->GetCurrentPosition(&currentReadPos, &safeReadPos);
7279     if ( FAILED(result) ) {
7280       sprintf(message_, "RtApiDs: Unable to get current capture position (%s): %s.",
7281               devices_[stream_.device[1]].name.c_str(), getErrorString(result));
7282       error(RtError::DRIVER_ERROR);
7283     }
7284
7285     if ( safeReadPos < (DWORD)nextReadPos ) safeReadPos += dsBufferSize; // unwrap offset
7286     DWORD endRead = nextReadPos + buffer_bytes;
7287
7288     // Handling depends on whether we are INPUT or DUPLEX. 
7289     // If we're in INPUT mode then waiting is a good thing. If we're in DUPLEX mode,
7290     // then a wait here will drag the write pointers into the forbidden zone.
7291     // 
7292     // In DUPLEX mode, rather than wait, we will back off the read pointer until 
7293     // it's in a safe position. This causes dropouts, but it seems to be the only 
7294     // practical way to sync up the read and write pointers reliably, given the 
7295     // the very complex relationship between phase and increment of the read and write 
7296     // pointers.
7297     //
7298     // In order to minimize audible dropouts in DUPLEX mode, we will
7299     // provide a pre-roll period of 0.5 seconds in which we return
7300     // zeros from the read buffer while the pointers sync up.
7301
7302     if (stream_.mode == DUPLEX)
7303     {
7304       if (safeReadPos < endRead) 
7305       {
7306         if (duplexPrerollBytes <= 0)
7307         {
7308           // pre-roll time over. Be more agressive.
7309           int adjustment = endRead-safeReadPos;
7310
7311           ++statistics.numberOfReadOverruns;
7312           // Two cases:
7313           // large adjustments: we've probably run out of CPU cycles, so just resync exactly,
7314           //     and perform fine adjustments later.
7315           // small adjustments: back off by twice as much.
7316           if (adjustment >= 2*buffer_bytes)  
7317           {
7318             nextReadPos = safeReadPos-2*buffer_bytes;
7319           } else 
7320           {
7321             nextReadPos = safeReadPos-buffer_bytes-adjustment;
7322           }
7323           statistics.readDeviceSafeLeadBytes =  currentReadPos-nextReadPos;
7324           if (statistics.readDeviceSafeLeadBytes  < 0) statistics.readDeviceSafeLeadBytes += dsBufferSize;
7325
7326           if (nextReadPos < 0) nextReadPos += dsBufferSize;
7327
7328         } else {
7329           // in pre=roll time. Just do it.
7330           nextReadPos = safeReadPos-buffer_bytes;
7331           while (nextReadPos < 0) nextReadPos += dsBufferSize;
7332         }
7333         endRead = nextReadPos + buffer_bytes;
7334       }
7335     } else {
7336       while ( safeReadPos < endRead ) {
7337         // See comments for playback.
7338         double millis = (endRead - safeReadPos) * 900.0;
7339         millis /= ( formatBytes(stream_.deviceFormat[1]) * stream_.nDeviceChannels[1] * stream_.sampleRate);
7340         if ( millis < 1.0 ) millis = 1.0;
7341         Sleep( (DWORD) millis );
7342
7343         // Wake up, find out where we are now
7344         result = dsBuffer->GetCurrentPosition( &currentReadPos, &safeReadPos );
7345         if ( FAILED(result) ) {
7346           sprintf(message_, "RtApiDs: Unable to get current capture position (%s): %s.",
7347                   devices_[stream_.device[1]].name.c_str(), getErrorString(result));
7348           error(RtError::DRIVER_ERROR);
7349         }
7350       
7351         if ( safeReadPos < (DWORD)nextReadPos ) safeReadPos += dsBufferSize; // unwrap offset
7352       }
7353     }
7354 #ifdef GENERATE_DEBUG_LOG
7355     readTime = timeGetTime();
7356 #endif
7357     if (statistics.readDeviceSafeLeadBytes < dsPointerDifference(currentReadPos,nextReadPos ,dsBufferSize))
7358     {
7359       statistics.readDeviceSafeLeadBytes = dsPointerDifference(currentReadPos,nextReadPos ,dsBufferSize);
7360     }
7361
7362     // Lock free space in the buffer
7363     result = dsBuffer->Lock (nextReadPos, buffer_bytes, &buffer1,
7364                              &bufferSize1, &buffer2, &bufferSize2, 0);
7365     if ( FAILED(result) ) {
7366       sprintf(message_, "RtApiDs: Unable to lock buffer during capture (%s): %s.",
7367               devices_[stream_.device[1]].name.c_str(), getErrorString(result));
7368       error(RtError::DRIVER_ERROR);
7369     }
7370
7371     if (duplexPrerollBytes <= 0)
7372     {
7373       // Copy our buffer into the DS buffer
7374       CopyMemory(buffer, buffer1, bufferSize1);
7375       if (buffer2 != NULL) CopyMemory(buffer+bufferSize1, buffer2, bufferSize2);
7376     } else {
7377       memset(buffer,0,bufferSize1);
7378       if (buffer2 != NULL) memset(buffer+bufferSize1,0,bufferSize2);
7379       duplexPrerollBytes -= bufferSize1 + bufferSize2;
7380     }
7381
7382     // Update our buffer offset and unlock sound buffer
7383     nextReadPos = (nextReadPos + bufferSize1 + bufferSize2) % dsBufferSize;
7384     dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
7385     if ( FAILED(result) ) {
7386       sprintf(message_, "RtApiDs: Unable to unlock buffer during capture (%s): %s.",
7387               devices_[stream_.device[1]].name.c_str(), getErrorString(result));
7388       error(RtError::DRIVER_ERROR);
7389     }
7390     handles[1].bufferPointer = nextReadPos;
7391
7392
7393     // No byte swapping necessary in DirectSound implementation.
7394
7395     // If necessary, convert 8-bit data from unsigned to signed.
7396     if ( stream_.deviceFormat[1] == RTAUDIO_SINT8 )
7397       for ( int j=0; j<buffer_bytes; j++ ) buffer[j] = (signed char) (buffer[j] - 128);
7398
7399     // Do buffer conversion if necessary.
7400     if (stream_.doConvertBuffer[1])
7401       convertBuffer( stream_.userBuffer, stream_.deviceBuffer, stream_.convertInfo[1] );
7402   }
7403 #ifdef GENERATE_DEBUG_LOG
7404   if (currentDebugLogEntry < debugLog.size())
7405   {
7406     TTickRecord &r = debugLog[currentDebugLogEntry++];
7407     r.currentReadPointer = currentReadPos;
7408     r.safeReadPointer = safeReadPos;
7409     r.currentWritePointer = currentWritePos;
7410     r.safeWritePointer = safeWritePos;
7411     r.readTime = readTime;
7412     r.writeTime = writeTime;
7413     r.nextReadPointer = handles[1].bufferPointer;
7414     r.nextWritePointer = handles[0].bufferPointer;
7415   }
7416 #endif
7417
7418
7419   MUTEX_UNLOCK(&stream_.mutex);
7420
7421   if (stream_.callbackInfo.usingCallback && stopStream)
7422     this->stopStream();
7423 }
7424 // Definitions for utility functions and callbacks
7425 // specific to the DirectSound implementation.
7426
7427 extern "C" unsigned __stdcall callbackHandler(void *ptr)
7428 {
7429   CallbackInfo *info = (CallbackInfo *) ptr;
7430   RtApiDs *object = (RtApiDs *) info->object;
7431   bool *usingCallback = &info->usingCallback;
7432
7433   while ( *usingCallback ) {
7434     try {
7435       object->tickStream();
7436     }
7437     catch (RtError &exception) {
7438       fprintf(stderr, "\nRtApiDs: callback thread error (%s) ... closing thread.\n\n",
7439               exception.getMessageString());
7440       break;
7441     }
7442   }
7443
7444   _endthreadex( 0 );
7445   return 0;
7446 }
7447
7448 static bool CALLBACK deviceCountCallback(LPGUID lpguid,
7449                                          LPCTSTR description,
7450                                          LPCTSTR module,
7451                                          LPVOID lpContext)
7452 {
7453   int *pointer = ((int *) lpContext);
7454   (*pointer)++;
7455
7456   return true;
7457 }
7458
7459 #include "tchar.h"
7460
7461 std::string convertTChar( LPCTSTR name )
7462 {
7463   std::string s;
7464
7465 #if defined( UNICODE ) || defined( _UNICODE )
7466   // Yes, this conversion doesn't make sense for two-byte characters
7467   // but RtAudio is currently written to return an std::string of
7468   // one-byte chars for the device name.
7469   for ( unsigned int i=0; i<wcslen( name ); i++ )
7470     s.push_back( name[i] );
7471 #else
7472   s.append( std::string( name ) );
7473 #endif
7474
7475   return s;
7476 }
7477
7478 static bool CALLBACK deviceInfoCallback(LPGUID lpguid,
7479                                         LPCTSTR description,
7480                                         LPCTSTR module,
7481                                         LPVOID lpContext)
7482 {
7483   enum_info *info = ((enum_info *) lpContext);
7484   while ( !info->name.empty() ) info++;
7485
7486   info->name = convertTChar( description );
7487   info->id = lpguid;
7488
7489   HRESULT hr;
7490   info->isValid = false;
7491   if (info->isInput == true) {
7492     DSCCAPS caps;
7493     LPDIRECTSOUNDCAPTURE object;
7494
7495     hr = DirectSoundCaptureCreate(  lpguid, &object,   NULL );
7496     if( hr != DS_OK ) return true;
7497
7498     caps.dwSize = sizeof(caps);
7499     hr = object->GetCaps( &caps );
7500     if( hr == DS_OK ) {
7501       if (caps.dwChannels > 0 && caps.dwFormats > 0)
7502         info->isValid = true;
7503     }
7504     object->Release();
7505   }
7506   else {
7507     DSCAPS caps;
7508     LPDIRECTSOUND object;
7509     hr = DirectSoundCreate(  lpguid, &object,   NULL );
7510     if( hr != DS_OK ) return true;
7511
7512     caps.dwSize = sizeof(caps);
7513     hr = object->GetCaps( &caps );
7514     if( hr == DS_OK ) {
7515       if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO )
7516         info->isValid = true;
7517     }
7518     object->Release();
7519   }
7520
7521   return true;
7522 }
7523
7524 static bool CALLBACK defaultDeviceCallback(LPGUID lpguid,
7525                                            LPCTSTR description,
7526                                            LPCTSTR module,
7527                                            LPVOID lpContext)
7528 {
7529   enum_info *info = ((enum_info *) lpContext);
7530
7531   if ( lpguid == NULL ) {
7532     info->name = convertTChar( description );
7533     return false;
7534   }
7535
7536   return true;
7537 }
7538
7539 static bool CALLBACK deviceIdCallback(LPGUID lpguid,
7540                                       LPCTSTR description,
7541                                       LPCTSTR module,
7542                                       LPVOID lpContext)
7543 {
7544   enum_info *info = ((enum_info *) lpContext);
7545
7546   std::string s = convertTChar( description );
7547   if ( info->name == s ) {
7548     info->id = lpguid;
7549     info->isValid = true;
7550     return false;
7551   }
7552
7553   return true;
7554 }
7555
7556 static char* getErrorString(int code)
7557 {
7558         switch (code) {
7559
7560   case DSERR_ALLOCATED:
7561     return "Already allocated.";
7562
7563   case DSERR_CONTROLUNAVAIL:
7564     return "Control unavailable.";
7565
7566   case DSERR_INVALIDPARAM:
7567     return "Invalid parameter.";
7568
7569   case DSERR_INVALIDCALL:
7570     return "Invalid call.";
7571
7572   case DSERR_GENERIC:
7573     return "Generic error.";
7574
7575   case DSERR_PRIOLEVELNEEDED:
7576     return "Priority level needed";
7577
7578   case DSERR_OUTOFMEMORY:
7579     return "Out of memory";
7580
7581   case DSERR_BADFORMAT:
7582     return "The sample rate or the channel format is not supported.";
7583
7584   case DSERR_UNSUPPORTED:
7585     return "Not supported.";
7586
7587   case DSERR_NODRIVER:
7588     return "No driver.";
7589
7590   case DSERR_ALREADYINITIALIZED:
7591     return "Already initialized.";
7592
7593   case DSERR_NOAGGREGATION:
7594     return "No aggregation.";
7595
7596   case DSERR_BUFFERLOST:
7597     return "Buffer lost.";
7598
7599   case DSERR_OTHERAPPHASPRIO:
7600     return "Another application already has priority.";
7601
7602   case DSERR_UNINITIALIZED:
7603     return "Uninitialized.";
7604
7605   default:
7606     return "DirectSound unknown error";
7607         }
7608 }
7609
7610 //******************** End of __WINDOWS_DS__ *********************//
7611 #endif
7612
7613 #if defined(__IRIX_AL__) // SGI's AL API for IRIX
7614
7615 #include <dmedia/audio.h>
7616 #include <unistd.h>
7617 #include <errno.h>
7618
7619 extern "C" void *callbackHandler(void * ptr);
7620
7621 RtApiAl :: RtApiAl()
7622 {
7623   this->initialize();
7624
7625   if (nDevices_ <= 0) {
7626     sprintf(message_, "RtApiAl: no Irix AL audio devices found!");
7627     error(RtError::NO_DEVICES_FOUND);
7628  }
7629 }
7630
7631 RtApiAl :: ~RtApiAl()
7632 {
7633   // The subclass destructor gets called before the base class
7634   // destructor, so close any existing streams before deallocating
7635   // apiDeviceId memory.
7636   if ( stream_.mode != UNINITIALIZED ) closeStream();
7637
7638   // Free our allocated apiDeviceId memory.
7639   long *id;
7640   for ( unsigned int i=0; i<devices_.size(); i++ ) {
7641     id = (long *) devices_[i].apiDeviceId;
7642     if (id) free(id);
7643   }
7644 }
7645
7646 void RtApiAl :: initialize(void)
7647 {
7648   // Count cards and devices
7649   nDevices_ = 0;
7650
7651   // Determine the total number of input and output devices.
7652   nDevices_ = alQueryValues(AL_SYSTEM, AL_DEVICES, 0, 0, 0, 0);
7653   if (nDevices_ < 0) {
7654     sprintf(message_, "RtApiAl: error counting devices: %s.",
7655             alGetErrorString(oserror()));
7656     error(RtError::DRIVER_ERROR);
7657   }
7658
7659   if (nDevices_ <= 0) return;
7660
7661   ALvalue *vls = (ALvalue *) new ALvalue[nDevices_];
7662
7663   // Create our list of devices and write their ascii identifiers and resource ids.
7664   char name[64];
7665   int outs, ins, i;
7666   ALpv pvs[1];
7667   pvs[0].param = AL_NAME;
7668   pvs[0].value.ptr = name;
7669   pvs[0].sizeIn = 64;
7670   RtApiDevice device;
7671   long *id;
7672
7673   outs = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, vls, nDevices_, 0, 0);
7674   if (outs < 0) {
7675     delete [] vls;
7676     sprintf(message_, "RtApiAl: error getting output devices: %s.",
7677             alGetErrorString(oserror()));
7678     error(RtError::DRIVER_ERROR);
7679   }
7680
7681   for (i=0; i<outs; i++) {
7682     if (alGetParams(vls[i].i, pvs, 1) < 0) {
7683       delete [] vls;
7684       sprintf(message_, "RtApiAl: error querying output devices: %s.",
7685               alGetErrorString(oserror()));
7686       error(RtError::DRIVER_ERROR);
7687     }
7688     device.name.erase();
7689     device.name.append( (const char *)name, strlen(name)+1);
7690     devices_.push_back(device);
7691     id = (long *) calloc(2, sizeof(long));
7692     id[0] = vls[i].i;
7693     devices_[i].apiDeviceId = (void *) id;
7694   }
7695
7696   ins = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &vls[outs], nDevices_-outs, 0, 0);
7697   if (ins < 0) {
7698     delete [] vls;
7699     sprintf(message_, "RtApiAl: error getting input devices: %s.",
7700             alGetErrorString(oserror()));
7701     error(RtError::DRIVER_ERROR);
7702   }
7703
7704   for (i=outs; i<ins+outs; i++) {
7705     if (alGetParams(vls[i].i, pvs, 1) < 0) {
7706       delete [] vls;
7707       sprintf(message_, "RtApiAl: error querying input devices: %s.",
7708               alGetErrorString(oserror()));
7709       error(RtError::DRIVER_ERROR);
7710     }
7711     device.name.erase();
7712     device.name.append( (const char *)name, strlen(name)+1);
7713     devices_.push_back(device);
7714     id = (long *) calloc(2, sizeof(long));
7715     id[1] = vls[i].i;
7716     devices_[i].apiDeviceId = (void *) id;
7717   }
7718
7719   delete [] vls;
7720 }
7721
7722 int RtApiAl :: getDefaultInputDevice(void)
7723 {
7724   ALvalue value;
7725   long *id;
7726   int result = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &value, 1, 0, 0);
7727   if (result < 0) {
7728     sprintf(message_, "RtApiAl: error getting default input device id: %s.",
7729             alGetErrorString(oserror()));
7730     error(RtError::WARNING);
7731   }
7732   else {
7733     for ( unsigned int i=0; i<devices_.size(); i++ ) {
7734       id = (long *) devices_[i].apiDeviceId;
7735       if ( id[1] == value.i ) return i;
7736     }
7737   }
7738
7739   return 0;
7740 }
7741
7742 int RtApiAl :: getDefaultOutputDevice(void)
7743 {
7744   ALvalue value;
7745   long *id;
7746   int result = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, &value, 1, 0, 0);
7747   if (result < 0) {
7748     sprintf(message_, "RtApiAl: error getting default output device id: %s.",
7749             alGetErrorString(oserror()));
7750     error(RtError::WARNING);
7751   }
7752   else {
7753     for ( unsigned int i=0; i<devices_.size(); i++ ) {
7754       id = (long *) devices_[i].apiDeviceId;
7755       if ( id[0] == value.i ) return i;
7756     }
7757   }
7758
7759   return 0;
7760 }
7761
7762 void RtApiAl :: probeDeviceInfo(RtApiDevice *info)
7763 {
7764   int result;
7765   long resource;
7766   ALvalue value;
7767   ALparamInfo pinfo;
7768
7769   // Get output resource ID if it exists.
7770   long *id = (long *) info->apiDeviceId;
7771   resource = id[0];
7772   if (resource > 0) {
7773
7774     // Probe output device parameters.
7775     result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0);
7776     if (result < 0) {
7777       sprintf(message_, "RtApiAl: error getting device (%s) channels: %s.",
7778               info->name.c_str(), alGetErrorString(oserror()));
7779       error(RtError::DEBUG_WARNING);
7780     }
7781     else {
7782       info->maxOutputChannels = value.i;
7783       info->minOutputChannels = 1;
7784     }
7785
7786     result = alGetParamInfo(resource, AL_RATE, &pinfo);
7787     if (result < 0) {
7788       sprintf(message_, "RtApiAl: error getting device (%s) rates: %s.",
7789               info->name.c_str(), alGetErrorString(oserror()));
7790       error(RtError::DEBUG_WARNING);
7791     }
7792     else {
7793       info->sampleRates.clear();
7794       for (unsigned int k=0; k<MAX_SAMPLE_RATES; k++) {
7795         if ( SAMPLE_RATES[k] >= pinfo.min.i && SAMPLE_RATES[k] <= pinfo.max.i )
7796           info->sampleRates.push_back( SAMPLE_RATES[k] );
7797       }
7798     }
7799
7800     // The AL library supports all our formats, except 24-bit and 32-bit ints.
7801     info->nativeFormats = (RtAudioFormat) 51;
7802   }
7803
7804   // Now get input resource ID if it exists.
7805   resource = id[1];
7806   if (resource > 0) {
7807
7808     // Probe input device parameters.
7809     result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0);
7810     if (result < 0) {
7811       sprintf(message_, "RtApiAl: error getting device (%s) channels: %s.",
7812               info->name.c_str(), alGetErrorString(oserror()));
7813       error(RtError::DEBUG_WARNING);
7814     }
7815     else {
7816       info->maxInputChannels = value.i;
7817       info->minInputChannels = 1;
7818     }
7819
7820     result = alGetParamInfo(resource, AL_RATE, &pinfo);
7821     if (result < 0) {
7822       sprintf(message_, "RtApiAl: error getting device (%s) rates: %s.",
7823               info->name.c_str(), alGetErrorString(oserror()));
7824       error(RtError::DEBUG_WARNING);
7825     }
7826     else {
7827       // In the case of the default device, these values will
7828       // overwrite the rates determined for the output device.  Since
7829       // the input device is most likely to be more limited than the
7830       // output device, this is ok.
7831       info->sampleRates.clear();
7832       for (unsigned int k=0; k<MAX_SAMPLE_RATES; k++) {
7833         if ( SAMPLE_RATES[k] >= pinfo.min.i && SAMPLE_RATES[k] <= pinfo.max.i )
7834           info->sampleRates.push_back( SAMPLE_RATES[k] );
7835       }
7836     }
7837
7838     // The AL library supports all our formats, except 24-bit and 32-bit ints.
7839     info->nativeFormats = (RtAudioFormat) 51;
7840   }
7841
7842   if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 )
7843     return;
7844   if ( info->sampleRates.size() == 0 )
7845     return;
7846
7847   // Determine duplex status.
7848   if (info->maxInputChannels < info->maxOutputChannels)
7849     info->maxDuplexChannels = info->maxInputChannels;
7850   else
7851     info->maxDuplexChannels = info->maxOutputChannels;
7852   if (info->minInputChannels < info->minOutputChannels)
7853     info->minDuplexChannels = info->minInputChannels;
7854   else
7855     info->minDuplexChannels = info->minOutputChannels;
7856
7857   if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true;
7858   else info->hasDuplexSupport = false;
7859
7860   info->probed = true;
7861
7862   return;
7863 }
7864
7865 bool RtApiAl :: probeDeviceOpen(int device, StreamMode mode, int channels, 
7866                                 int sampleRate, RtAudioFormat format,
7867                                 int *bufferSize, int numberOfBuffers)
7868 {
7869   int result, nBuffers;
7870   long resource;
7871   ALconfig al_config;
7872   ALport port;
7873   ALpv pvs[2];
7874   long *id = (long *) devices_[device].apiDeviceId;
7875
7876   // Get a new ALconfig structure.
7877   al_config = alNewConfig();
7878   if ( !al_config ) {
7879     sprintf(message_,"RtApiAl: can't get AL config: %s.",
7880             alGetErrorString(oserror()));
7881     error(RtError::DEBUG_WARNING);
7882     return FAILURE;
7883   }
7884
7885   // Set the channels.
7886   result = alSetChannels(al_config, channels);
7887   if ( result < 0 ) {
7888     alFreeConfig(al_config);
7889     sprintf(message_,"RtApiAl: can't set %d channels in AL config: %s.",
7890             channels, alGetErrorString(oserror()));
7891     error(RtError::DEBUG_WARNING);
7892     return FAILURE;
7893   }
7894
7895   // Attempt to set the queue size.  The al API doesn't provide a
7896   // means for querying the minimum/maximum buffer size of a device,
7897   // so if the specified size doesn't work, take whatever the
7898   // al_config structure returns.
7899   if ( numberOfBuffers < 1 )
7900     nBuffers = 1;
7901   else
7902     nBuffers = numberOfBuffers;
7903   long buffer_size = *bufferSize * nBuffers;
7904   result = alSetQueueSize(al_config, buffer_size); // in sample frames
7905   if ( result < 0 ) {
7906     // Get the buffer size specified by the al_config and try that.
7907     buffer_size = alGetQueueSize(al_config);
7908     result = alSetQueueSize(al_config, buffer_size);
7909     if ( result < 0 ) {
7910       alFreeConfig(al_config);
7911       sprintf(message_,"RtApiAl: can't set buffer size (%ld) in AL config: %s.",
7912               buffer_size, alGetErrorString(oserror()));
7913       error(RtError::DEBUG_WARNING);
7914       return FAILURE;
7915     }
7916     *bufferSize = buffer_size / nBuffers;
7917   }
7918
7919   // Set the data format.
7920   stream_.userFormat = format;
7921   stream_.deviceFormat[mode] = format;
7922   if (format == RTAUDIO_SINT8) {
7923     result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP);
7924     result = alSetWidth(al_config, AL_SAMPLE_8);
7925   }
7926   else if (format == RTAUDIO_SINT16) {
7927     result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP);
7928     result = alSetWidth(al_config, AL_SAMPLE_16);
7929   }
7930   else if (format == RTAUDIO_SINT24) {
7931     // Our 24-bit format assumes the upper 3 bytes of a 4 byte word.
7932     // The AL library uses the lower 3 bytes, so we'll need to do our
7933     // own conversion.
7934     result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
7935     stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
7936   }
7937   else if (format == RTAUDIO_SINT32) {
7938     // The AL library doesn't seem to support the 32-bit integer
7939     // format, so we'll need to do our own conversion.
7940     result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
7941     stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
7942   }
7943   else if (format == RTAUDIO_FLOAT32)
7944     result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
7945   else if (format == RTAUDIO_FLOAT64)
7946     result = alSetSampFmt(al_config, AL_SAMPFMT_DOUBLE);
7947
7948   if ( result == -1 ) {
7949     alFreeConfig(al_config);
7950     sprintf(message_,"RtApiAl: error setting sample format in AL config: %s.",
7951             alGetErrorString(oserror()));
7952     error(RtError::DEBUG_WARNING);
7953     return FAILURE;
7954   }
7955
7956   if (mode == OUTPUT) {
7957
7958     // Set our device.
7959     if (device == 0)
7960       resource = AL_DEFAULT_OUTPUT;
7961     else
7962       resource = id[0];
7963     result = alSetDevice(al_config, resource);
7964     if ( result == -1 ) {
7965       alFreeConfig(al_config);
7966       sprintf(message_,"RtApiAl: error setting device (%s) in AL config: %s.",
7967               devices_[device].name.c_str(), alGetErrorString(oserror()));
7968       error(RtError::DEBUG_WARNING);
7969       return FAILURE;
7970     }
7971
7972     // Open the port.
7973     port = alOpenPort("RtApiAl Output Port", "w", al_config);
7974     if( !port ) {
7975       alFreeConfig(al_config);
7976       sprintf(message_,"RtApiAl: error opening output port: %s.",
7977               alGetErrorString(oserror()));
7978       error(RtError::DEBUG_WARNING);
7979       return FAILURE;
7980     }
7981
7982     // Set the sample rate
7983     pvs[0].param = AL_MASTER_CLOCK;
7984     pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
7985     pvs[1].param = AL_RATE;
7986     pvs[1].value.ll = alDoubleToFixed((double)sampleRate);
7987     result = alSetParams(resource, pvs, 2);
7988     if ( result < 0 ) {
7989       alClosePort(port);
7990       alFreeConfig(al_config);
7991       sprintf(message_,"RtApiAl: error setting sample rate (%d) for device (%s): %s.",
7992               sampleRate, devices_[device].name.c_str(), alGetErrorString(oserror()));
7993       error(RtError::DEBUG_WARNING);
7994       return FAILURE;
7995     }
7996   }
7997   else { // mode == INPUT
7998
7999     // Set our device.
8000     if (device == 0)
8001       resource = AL_DEFAULT_INPUT;
8002     else
8003       resource = id[1];
8004     result = alSetDevice(al_config, resource);
8005     if ( result == -1 ) {
8006       alFreeConfig(al_config);
8007       sprintf(message_,"RtApiAl: error setting device (%s) in AL config: %s.",
8008               devices_[device].name.c_str(), alGetErrorString(oserror()));
8009       error(RtError::DEBUG_WARNING);
8010       return FAILURE;
8011     }
8012
8013     // Open the port.
8014     port = alOpenPort("RtApiAl Input Port", "r", al_config);
8015     if( !port ) {
8016       alFreeConfig(al_config);
8017       sprintf(message_,"RtApiAl: error opening input port: %s.",
8018               alGetErrorString(oserror()));
8019       error(RtError::DEBUG_WARNING);
8020       return FAILURE;
8021     }
8022
8023     // Set the sample rate
8024     pvs[0].param = AL_MASTER_CLOCK;
8025     pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
8026     pvs[1].param = AL_RATE;
8027     pvs[1].value.ll = alDoubleToFixed((double)sampleRate);
8028     result = alSetParams(resource, pvs, 2);
8029     if ( result < 0 ) {
8030       alClosePort(port);
8031       alFreeConfig(al_config);
8032       sprintf(message_,"RtApiAl: error setting sample rate (%d) for device (%s): %s.",
8033               sampleRate, devices_[device].name.c_str(), alGetErrorString(oserror()));
8034       error(RtError::DEBUG_WARNING);
8035       return FAILURE;
8036     }
8037   }
8038
8039   alFreeConfig(al_config);
8040
8041   stream_.nUserChannels[mode] = channels;
8042   stream_.nDeviceChannels[mode] = channels;
8043
8044   // Save stream handle.
8045   ALport *handle = (ALport *) stream_.apiHandle;
8046   if ( handle == 0 ) {
8047     handle = (ALport *) calloc(2, sizeof(ALport));
8048     if ( handle == NULL ) {
8049       sprintf(message_, "RtApiAl: Irix Al error allocating handle memory (%s).",
8050               devices_[device].name.c_str());
8051       goto error;
8052     }
8053     stream_.apiHandle = (void *) handle;
8054     handle[0] = 0;
8055     handle[1] = 0;
8056   }
8057   handle[mode] = port;
8058
8059   // Set flags for buffer conversion
8060   stream_.doConvertBuffer[mode] = false;
8061   if (stream_.userFormat != stream_.deviceFormat[mode])
8062     stream_.doConvertBuffer[mode] = true;
8063
8064   // Allocate necessary internal buffers
8065   if ( stream_.nUserChannels[0] != stream_.nUserChannels[1] ) {
8066
8067     long buffer_bytes;
8068     if (stream_.nUserChannels[0] >= stream_.nUserChannels[1])
8069       buffer_bytes = stream_.nUserChannels[0];
8070     else
8071       buffer_bytes = stream_.nUserChannels[1];
8072
8073     buffer_bytes *= *bufferSize * formatBytes(stream_.userFormat);
8074     if (stream_.userBuffer) free(stream_.userBuffer);
8075     stream_.userBuffer = (char *) calloc(buffer_bytes, 1);
8076     if (stream_.userBuffer == NULL) {
8077       sprintf(message_, "RtApiAl: error allocating user buffer memory (%s).",
8078               devices_[device].name.c_str());
8079       goto error;
8080     }
8081   }
8082
8083   if ( stream_.doConvertBuffer[mode] ) {
8084
8085     long buffer_bytes;
8086     bool makeBuffer = true;
8087     if ( mode == OUTPUT )
8088       buffer_bytes = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
8089     else { // mode == INPUT
8090       buffer_bytes = stream_.nDeviceChannels[1] * formatBytes(stream_.deviceFormat[1]);
8091       if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
8092         long bytes_out = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
8093         if ( buffer_bytes < bytes_out ) makeBuffer = false;
8094       }
8095     }
8096
8097     if ( makeBuffer ) {
8098       buffer_bytes *= *bufferSize;
8099       if (stream_.deviceBuffer) free(stream_.deviceBuffer);
8100       stream_.deviceBuffer = (char *) calloc(buffer_bytes, 1);
8101       if (stream_.deviceBuffer == NULL) {
8102         sprintf(message_, "RtApiAl: error allocating device buffer memory (%s).",
8103                 devices_[device].name.c_str());
8104         goto error;
8105       }
8106     }
8107   }
8108
8109   stream_.device[mode] = device;
8110   stream_.state = STREAM_STOPPED;
8111   if ( stream_.mode == OUTPUT && mode == INPUT )
8112     // We had already set up an output stream.
8113     stream_.mode = DUPLEX;
8114   else
8115     stream_.mode = mode;
8116   stream_.nBuffers = nBuffers;
8117   stream_.bufferSize = *bufferSize;
8118   stream_.sampleRate = sampleRate;
8119
8120   // Setup the buffer conversion information structure.
8121   if ( stream_.doConvertBuffer[mode] ) {
8122     if (mode == INPUT) { // convert device to user buffer
8123       stream_.convertInfo[mode].inJump = stream_.nDeviceChannels[1];
8124       stream_.convertInfo[mode].outJump = stream_.nUserChannels[1];
8125       stream_.convertInfo[mode].inFormat = stream_.deviceFormat[1];
8126       stream_.convertInfo[mode].outFormat = stream_.userFormat;
8127     }
8128     else { // convert user to device buffer
8129       stream_.convertInfo[mode].inJump = stream_.nUserChannels[0];
8130       stream_.convertInfo[mode].outJump = stream_.nDeviceChannels[0];
8131       stream_.convertInfo[mode].inFormat = stream_.userFormat;
8132       stream_.convertInfo[mode].outFormat = stream_.deviceFormat[0];
8133     }
8134
8135     if ( stream_.convertInfo[mode].inJump < stream_.convertInfo[mode].outJump )
8136       stream_.convertInfo[mode].channels = stream_.convertInfo[mode].inJump;
8137     else
8138       stream_.convertInfo[mode].channels = stream_.convertInfo[mode].outJump;
8139
8140     // Set up the interleave/deinterleave offsets.
8141     if ( mode == INPUT && stream_.deInterleave[1] ) {
8142       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
8143         stream_.convertInfo[mode].inOffset.push_back( k * stream_.bufferSize );
8144         stream_.convertInfo[mode].outOffset.push_back( k );
8145         stream_.convertInfo[mode].inJump = 1;
8146       }
8147     }
8148     else if (mode == OUTPUT && stream_.deInterleave[0]) {
8149       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
8150         stream_.convertInfo[mode].inOffset.push_back( k );
8151         stream_.convertInfo[mode].outOffset.push_back( k * stream_.bufferSize );
8152         stream_.convertInfo[mode].outJump = 1;
8153       }
8154     }
8155     else {
8156       for (int k=0; k<stream_.convertInfo[mode].channels; k++) {
8157         stream_.convertInfo[mode].inOffset.push_back( k );
8158         stream_.convertInfo[mode].outOffset.push_back( k );
8159       }
8160     }
8161   }
8162
8163   return SUCCESS;
8164
8165  error:
8166   if (handle) {
8167     if (handle[0])
8168       alClosePort(handle[0]);
8169     if (handle[1])
8170       alClosePort(handle[1]);
8171     free(handle);
8172     stream_.apiHandle = 0;
8173   }
8174
8175   if (stream_.userBuffer) {
8176     free(stream_.userBuffer);
8177     stream_.userBuffer = 0;
8178   }
8179
8180   error(RtError::DEBUG_WARNING);
8181   return FAILURE;
8182 }
8183
8184 void RtApiAl :: closeStream()
8185 {
8186   // We don't want an exception to be thrown here because this
8187   // function is called by our class destructor.  So, do our own
8188   // streamId check.
8189   if ( stream_.mode == UNINITIALIZED ) {
8190     sprintf(message_, "RtApiAl::closeStream(): no open stream to close!");
8191     error(RtError::WARNING);
8192     return;
8193   }
8194
8195   ALport *handle = (ALport *) stream_.apiHandle;
8196   if (stream_.state == STREAM_RUNNING) {
8197     int buffer_size = stream_.bufferSize * stream_.nBuffers;
8198     if (stream_.mode == OUTPUT || stream_.mode == DUPLEX)
8199       alDiscardFrames(handle[0], buffer_size);
8200     if (stream_.mode == INPUT || stream_.mode == DUPLEX)
8201       alDiscardFrames(handle[1], buffer_size);
8202     stream_.state = STREAM_STOPPED;
8203   }
8204
8205   if (stream_.callbackInfo.usingCallback) {
8206     stream_.callbackInfo.usingCallback = false;
8207     pthread_join(stream_.callbackInfo.thread, NULL);
8208   }
8209
8210   if (handle) {
8211     if (handle[0]) alClosePort(handle[0]);
8212     if (handle[1]) alClosePort(handle[1]);
8213     free(handle);
8214     stream_.apiHandle = 0;
8215   }
8216
8217   if (stream_.userBuffer) {
8218     free(stream_.userBuffer);
8219     stream_.userBuffer = 0;
8220   }
8221
8222   if (stream_.deviceBuffer) {
8223     free(stream_.deviceBuffer);
8224     stream_.deviceBuffer = 0;
8225   }
8226
8227   stream_.mode = UNINITIALIZED;
8228 }
8229
8230 void RtApiAl :: startStream()
8231 {
8232   verifyStream();
8233   if (stream_.state == STREAM_RUNNING) return;
8234
8235   MUTEX_LOCK(&stream_.mutex);
8236
8237   // The AL port is ready as soon as it is opened.
8238   stream_.state = STREAM_RUNNING;
8239
8240   MUTEX_UNLOCK(&stream_.mutex);
8241 }
8242
8243 void RtApiAl :: stopStream()
8244 {
8245   verifyStream();
8246   if (stream_.state == STREAM_STOPPED) return;
8247
8248   // Change the state before the lock to improve shutdown response
8249   // when using a callback.
8250   stream_.state = STREAM_STOPPED;
8251   MUTEX_LOCK(&stream_.mutex);
8252
8253   int result, buffer_size = stream_.bufferSize * stream_.nBuffers;
8254   ALport *handle = (ALport *) stream_.apiHandle;
8255
8256   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX)
8257     alZeroFrames(handle[0], buffer_size);
8258
8259   if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
8260     result = alDiscardFrames(handle[1], buffer_size);
8261     if (result == -1) {
8262       sprintf(message_, "RtApiAl: error draining stream device (%s): %s.",
8263               devices_[stream_.device[1]].name.c_str(), alGetErrorString(oserror()));
8264       error(RtError::DRIVER_ERROR);
8265     }
8266   }
8267
8268   MUTEX_UNLOCK(&stream_.mutex);
8269 }
8270
8271 void RtApiAl :: abortStream()
8272 {
8273   verifyStream();
8274   if (stream_.state == STREAM_STOPPED) return;
8275
8276   // Change the state before the lock to improve shutdown response
8277   // when using a callback.
8278   stream_.state = STREAM_STOPPED;
8279   MUTEX_LOCK(&stream_.mutex);
8280
8281   ALport *handle = (ALport *) stream_.apiHandle;
8282   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
8283
8284     int buffer_size = stream_.bufferSize * stream_.nBuffers;
8285     int result = alDiscardFrames(handle[0], buffer_size);
8286     if (result == -1) {
8287       sprintf(message_, "RtApiAl: error aborting stream device (%s): %s.",
8288               devices_[stream_.device[0]].name.c_str(), alGetErrorString(oserror()));
8289       error(RtError::DRIVER_ERROR);
8290     }
8291   }
8292
8293   // There is no clear action to take on the input stream, since the
8294   // port will continue to run in any event.
8295
8296   MUTEX_UNLOCK(&stream_.mutex);
8297 }
8298
8299 int RtApiAl :: streamWillBlock()
8300 {
8301   verifyStream();
8302
8303   if (stream_.state == STREAM_STOPPED) return 0;
8304
8305   MUTEX_LOCK(&stream_.mutex);
8306
8307   int frames = 0;
8308   int err = 0;
8309   ALport *handle = (ALport *) stream_.apiHandle;
8310   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
8311     err = alGetFillable(handle[0]);
8312     if (err < 0) {
8313       sprintf(message_, "RtApiAl: error getting available frames for stream (%s): %s.",
8314               devices_[stream_.device[0]].name.c_str(), alGetErrorString(oserror()));
8315       error(RtError::DRIVER_ERROR);
8316     }
8317   }
8318
8319   frames = err;
8320
8321   if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
8322     err = alGetFilled(handle[1]);
8323     if (err < 0) {
8324       sprintf(message_, "RtApiAl: error getting available frames for stream (%s): %s.",
8325               devices_[stream_.device[1]].name.c_str(), alGetErrorString(oserror()));
8326       error(RtError::DRIVER_ERROR);
8327     }
8328     if (frames > err) frames = err;
8329   }
8330
8331   frames = stream_.bufferSize - frames;
8332   if (frames < 0) frames = 0;
8333
8334   MUTEX_UNLOCK(&stream_.mutex);
8335   return frames;
8336 }
8337
8338 void RtApiAl :: tickStream()
8339 {
8340   verifyStream();
8341
8342   int stopStream = 0;
8343   if (stream_.state == STREAM_STOPPED) {
8344     if (stream_.callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
8345     return;
8346   }
8347   else if (stream_.callbackInfo.usingCallback) {
8348     RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
8349     stopStream = callback(stream_.userBuffer, stream_.bufferSize, stream_.callbackInfo.userData);
8350   }
8351
8352   MUTEX_LOCK(&stream_.mutex);
8353
8354   // The state might change while waiting on a mutex.
8355   if (stream_.state == STREAM_STOPPED)
8356     goto unlock;
8357
8358   char *buffer;
8359   int channels;
8360   RtAudioFormat format;
8361   ALport *handle = (ALport *) stream_.apiHandle;
8362   if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) {
8363
8364     // Setup parameters and do buffer conversion if necessary.
8365     if (stream_.doConvertBuffer[0]) {
8366       buffer = stream_.deviceBuffer;
8367       convertBuffer( buffer, stream_.userBuffer, stream_.convertInfo[0] );
8368       channels = stream_.nDeviceChannels[0];
8369       format = stream_.deviceFormat[0];
8370     }
8371     else {
8372       buffer = stream_.userBuffer;
8373       channels = stream_.nUserChannels[0];
8374       format = stream_.userFormat;
8375     }
8376
8377     // Do byte swapping if necessary.
8378     if (stream_.doByteSwap[0])
8379       byteSwapBuffer(buffer, stream_.bufferSize * channels, format);
8380
8381     // Write interleaved samples to device.
8382     alWriteFrames(handle[0], buffer, stream_.bufferSize);
8383   }
8384
8385   if (stream_.mode == INPUT || stream_.mode == DUPLEX) {
8386
8387     // Setup parameters.
8388     if (stream_.doConvertBuffer[1]) {
8389       buffer = stream_.deviceBuffer;
8390       channels = stream_.nDeviceChannels[1];
8391       format = stream_.deviceFormat[1];
8392     }
8393     else {
8394       buffer = stream_.userBuffer;
8395       channels = stream_.nUserChannels[1];
8396       format = stream_.userFormat;
8397     }
8398
8399     // Read interleaved samples from device.
8400     alReadFrames(handle[1], buffer, stream_.bufferSize);
8401
8402     // Do byte swapping if necessary.
8403     if (stream_.doByteSwap[1])
8404       byteSwapBuffer(buffer, stream_.bufferSize * channels, format);
8405
8406     // Do buffer conversion if necessary.
8407     if (stream_.doConvertBuffer[1])
8408       convertBuffer( stream_.userBuffer, stream_.deviceBuffer, stream_.convertInfo[1] );
8409   }
8410
8411  unlock:
8412   MUTEX_UNLOCK(&stream_.mutex);
8413
8414   if (stream_.callbackInfo.usingCallback && stopStream)
8415     this->stopStream();
8416 }
8417
8418 void RtApiAl :: setStreamCallback(RtAudioCallback callback, void *userData)
8419 {
8420   verifyStream();
8421
8422   CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
8423   if ( info->usingCallback ) {
8424     sprintf(message_, "RtApiAl: A callback is already set for this stream!");
8425     error(RtError::WARNING);
8426     return;
8427   }
8428
8429   info->callback = (void *) callback;
8430   info->userData = userData;
8431   info->usingCallback = true;
8432   info->object = (void *) this;
8433
8434   // Set the thread attributes for joinable and realtime scheduling
8435   // priority.  The higher priority will only take affect if the
8436   // program is run as root or suid.
8437   pthread_attr_t attr;
8438   pthread_attr_init(&attr);
8439   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
8440   pthread_attr_setschedpolicy(&attr, SCHED_RR);
8441
8442   int err = pthread_create(&info->thread, &attr, callbackHandler, &stream_.callbackInfo);
8443   pthread_attr_destroy(&attr);
8444   if (err) {
8445     info->usingCallback = false;
8446     sprintf(message_, "RtApiAl: error starting callback thread!");
8447     error(RtError::THREAD_ERROR);
8448   }
8449 }
8450
8451 void RtApiAl :: cancelStreamCallback()
8452 {
8453   verifyStream();
8454
8455   if (stream_.callbackInfo.usingCallback) {
8456
8457     if (stream_.state == STREAM_RUNNING)
8458       stopStream();
8459
8460     MUTEX_LOCK(&stream_.mutex);
8461
8462     stream_.callbackInfo.usingCallback = false;
8463     pthread_join(stream_.callbackInfo.thread, NULL);
8464     stream_.callbackInfo.thread = 0;
8465     stream_.callbackInfo.callback = NULL;
8466     stream_.callbackInfo.userData = NULL;
8467
8468     MUTEX_UNLOCK(&stream_.mutex);
8469   }
8470 }
8471
8472 extern "C" void *callbackHandler(void *ptr)
8473 {
8474   CallbackInfo *info = (CallbackInfo *) ptr;
8475   RtApiAl *object = (RtApiAl *) info->object;
8476   bool *usingCallback = &info->usingCallback;
8477
8478   while ( *usingCallback ) {
8479     try {
8480       object->tickStream();
8481     }
8482     catch (RtError &exception) {
8483       fprintf(stderr, "\nRtApiAl: callback thread error (%s) ... closing thread.\n\n",
8484               exception.getMessageString());
8485       break;
8486     }
8487   }
8488
8489   return 0;
8490 }
8491
8492 //******************** End of __IRIX_AL__ *********************//
8493 #endif
8494
8495
8496 // *************************************************** //
8497 //
8498 // Protected common (OS-independent) RtAudio methods.
8499 //
8500 // *************************************************** //
8501
8502 // This method can be modified to control the behavior of error
8503 // message reporting and throwing.
8504 void RtApi :: error(RtError::Type type)
8505 {
8506   if (type == RtError::WARNING) {
8507     fprintf(stderr, "\n%s\n\n", message_);
8508   }
8509   else if (type == RtError::DEBUG_WARNING) {
8510 #if defined(__RTAUDIO_DEBUG__)
8511     fprintf(stderr, "\n%s\n\n", message_);
8512 #endif
8513   }
8514   else {
8515 #if defined(__RTAUDIO_DEBUG__)
8516     fprintf(stderr, "\n%s\n\n", message_);
8517 #endif
8518     throw RtError(std::string(message_), type);
8519   }
8520 }
8521
8522 void RtApi :: verifyStream()
8523 {
8524   if ( stream_.mode == UNINITIALIZED ) {
8525     sprintf(message_, "RtAudio: stream is not open!");
8526     error(RtError::INVALID_STREAM);
8527   }
8528 }
8529
8530 void RtApi :: clearDeviceInfo(RtApiDevice *info)
8531 {
8532   // Don't clear the name or DEVICE_ID fields here ... they are
8533   // typically set prior to a call of this function.
8534   info->probed = false;
8535   info->maxOutputChannels = 0;
8536   info->maxInputChannels = 0;
8537   info->maxDuplexChannels = 0;
8538   info->minOutputChannels = 0;
8539   info->minInputChannels = 0;
8540   info->minDuplexChannels = 0;
8541   info->hasDuplexSupport = false;
8542   info->sampleRates.clear();
8543   info->nativeFormats = 0;
8544 }
8545
8546 void RtApi :: clearStreamInfo()
8547 {
8548   stream_.mode = UNINITIALIZED;
8549   stream_.state = STREAM_STOPPED;
8550   stream_.sampleRate = 0;
8551   stream_.bufferSize = 0;
8552   stream_.nBuffers = 0;
8553   stream_.userFormat = 0;
8554   for ( int i=0; i<2; i++ ) {
8555     stream_.device[i] = 0;
8556     stream_.doConvertBuffer[i] = false;
8557     stream_.deInterleave[i] = false;
8558     stream_.doByteSwap[i] = false;
8559     stream_.nUserChannels[i] = 0;
8560     stream_.nDeviceChannels[i] = 0;
8561     stream_.deviceFormat[i] = 0;
8562   }
8563 }
8564
8565 int RtApi :: formatBytes(RtAudioFormat format)
8566 {
8567   if (format == RTAUDIO_SINT16)
8568     return 2;
8569   else if (format == RTAUDIO_SINT24 || format == RTAUDIO_SINT32 ||
8570            format == RTAUDIO_FLOAT32)
8571     return 4;
8572   else if (format == RTAUDIO_FLOAT64)
8573     return 8;
8574   else if (format == RTAUDIO_SINT8)
8575     return 1;
8576
8577   sprintf(message_,"RtApi: undefined format in formatBytes().");
8578   error(RtError::WARNING);
8579
8580   return 0;
8581 }
8582
8583 void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info )
8584 {
8585   // This function does format conversion, input/output channel compensation, and
8586   // data interleaving/deinterleaving.  24-bit integers are assumed to occupy
8587   // the upper three bytes of a 32-bit integer.
8588
8589   // Clear our device buffer when in/out duplex device channels are different
8590   if ( outBuffer == stream_.deviceBuffer && stream_.mode == DUPLEX &&
8591        stream_.nDeviceChannels[0] != stream_.nDeviceChannels[1] )
8592     memset( outBuffer, 0, stream_.bufferSize * info.outJump * formatBytes( info.outFormat ) );
8593
8594   int j;
8595   if (info.outFormat == RTAUDIO_FLOAT64) {
8596     Float64 scale;
8597     Float64 *out = (Float64 *)outBuffer;
8598
8599     if (info.inFormat == RTAUDIO_SINT8) {
8600       signed char *in = (signed char *)inBuffer;
8601       scale = 1.0 / 128.0;
8602       for (int i=0; i<stream_.bufferSize; i++) {
8603         for (j=0; j<info.channels; j++) {
8604           out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
8605           out[info.outOffset[j]] *= scale;
8606         }
8607         in += info.inJump;
8608         out += info.outJump;
8609       }
8610     }
8611     else if (info.inFormat == RTAUDIO_SINT16) {
8612       Int16 *in = (Int16 *)inBuffer;
8613       scale = 1.0 / 32768.0;
8614       for (int i=0; i<stream_.bufferSize; i++) {
8615         for (j=0; j<info.channels; j++) {
8616           out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
8617           out[info.outOffset[j]] *= scale;
8618         }
8619         in += info.inJump;
8620         out += info.outJump;
8621       }
8622     }
8623     else if (info.inFormat == RTAUDIO_SINT24) {
8624       Int32 *in = (Int32 *)inBuffer;
8625       scale = 1.0 / 2147483648.0;
8626       for (int i=0; i<stream_.bufferSize; i++) {
8627         for (j=0; j<info.channels; j++) {
8628           out[info.outOffset[j]] = (Float64) (in[info.inOffset[j]] & 0xffffff00);
8629           out[info.outOffset[j]] *= scale;
8630         }
8631         in += info.inJump;
8632         out += info.outJump;
8633       }
8634     }
8635     else if (info.inFormat == RTAUDIO_SINT32) {
8636       Int32 *in = (Int32 *)inBuffer;
8637       scale = 1.0 / 2147483648.0;
8638       for (int i=0; i<stream_.bufferSize; i++) {
8639         for (j=0; j<info.channels; j++) {
8640           out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
8641           out[info.outOffset[j]] *= scale;
8642         }
8643         in += info.inJump;
8644         out += info.outJump;
8645       }
8646     }
8647     else if (info.inFormat == RTAUDIO_FLOAT32) {
8648       Float32 *in = (Float32 *)inBuffer;
8649       for (int i=0; i<stream_.bufferSize; i++) {
8650         for (j=0; j<info.channels; j++) {
8651           out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
8652         }
8653         in += info.inJump;
8654         out += info.outJump;
8655       }
8656     }
8657     else if (info.inFormat == RTAUDIO_FLOAT64) {
8658       // Channel compensation and/or (de)interleaving only.
8659       Float64 *in = (Float64 *)inBuffer;
8660       for (int i=0; i<stream_.bufferSize; i++) {
8661         for (j=0; j<info.channels; j++) {
8662           out[info.outOffset[j]] = in[info.inOffset[j]];
8663         }
8664         in += info.inJump;
8665         out += info.outJump;
8666       }
8667     }
8668   }
8669   else if (info.outFormat == RTAUDIO_FLOAT32) {
8670     Float32 scale;
8671     Float32 *out = (Float32 *)outBuffer;
8672
8673     if (info.inFormat == RTAUDIO_SINT8) {
8674       signed char *in = (signed char *)inBuffer;
8675       scale = 1.0 / 128.0;
8676       for (int i=0; i<stream_.bufferSize; i++) {
8677         for (j=0; j<info.channels; j++) {
8678           out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
8679           out[info.outOffset[j]] *= scale;
8680         }
8681         in += info.inJump;
8682         out += info.outJump;
8683       }
8684     }
8685     else if (info.inFormat == RTAUDIO_SINT16) {
8686       Int16 *in = (Int16 *)inBuffer;
8687       scale = 1.0 / 32768.0;
8688       for (int i=0; i<stream_.bufferSize; i++) {
8689         for (j=0; j<info.channels; j++) {
8690           out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
8691           out[info.outOffset[j]] *= scale;
8692         }
8693         in += info.inJump;
8694         out += info.outJump;
8695       }
8696     }
8697     else if (info.inFormat == RTAUDIO_SINT24) {
8698       Int32 *in = (Int32 *)inBuffer;
8699       scale = 1.0 / 2147483648.0;
8700       for (int i=0; i<stream_.bufferSize; i++) {
8701         for (j=0; j<info.channels; j++) {
8702           out[info.outOffset[j]] = (Float32) (in[info.inOffset[j]] & 0xffffff00);
8703           out[info.outOffset[j]] *= scale;
8704         }
8705         in += info.inJump;
8706         out += info.outJump;
8707       }
8708     }
8709     else if (info.inFormat == RTAUDIO_SINT32) {
8710       Int32 *in = (Int32 *)inBuffer;
8711       scale = 1.0 / 2147483648.0;
8712       for (int i=0; i<stream_.bufferSize; i++) {
8713         for (j=0; j<info.channels; j++) {
8714           out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
8715           out[info.outOffset[j]] *= scale;
8716         }
8717         in += info.inJump;
8718         out += info.outJump;
8719       }
8720     }
8721     else if (info.inFormat == RTAUDIO_FLOAT32) {
8722       // Channel compensation and/or (de)interleaving only.
8723       Float32 *in = (Float32 *)inBuffer;
8724       for (int i=0; i<stream_.bufferSize; i++) {
8725         for (j=0; j<info.channels; j++) {
8726           out[info.outOffset[j]] = in[info.inOffset[j]];
8727         }
8728         in += info.inJump;
8729         out += info.outJump;
8730       }
8731     }
8732     else if (info.inFormat == RTAUDIO_FLOAT64) {
8733       Float64 *in = (Float64 *)inBuffer;
8734       for (int i=0; i<stream_.bufferSize; i++) {
8735         for (j=0; j<info.channels; j++) {
8736           out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
8737         }
8738         in += info.inJump;
8739         out += info.outJump;
8740       }
8741     }
8742   }
8743   else if (info.outFormat == RTAUDIO_SINT32) {
8744     Int32 *out = (Int32 *)outBuffer;
8745     if (info.inFormat == RTAUDIO_SINT8) {
8746       signed char *in = (signed char *)inBuffer;
8747       for (int i=0; i<stream_.bufferSize; i++) {
8748         for (j=0; j<info.channels; j++) {
8749           out[info.outOffset[j]] = (Int32) in[info.inOffset[j]];
8750           out[info.outOffset[j]] <<= 24;
8751         }
8752         in += info.inJump;
8753         out += info.outJump;
8754       }
8755     }
8756     else if (info.inFormat == RTAUDIO_SINT16) {
8757       Int16 *in = (Int16 *)inBuffer;
8758       for (int i=0; i<stream_.bufferSize; i++) {
8759         for (j=0; j<info.channels; j++) {
8760           out[info.outOffset[j]] = (Int32) in[info.inOffset[j]];
8761           out[info.outOffset[j]] <<= 16;
8762         }
8763         in += info.inJump;
8764         out += info.outJump;
8765       }
8766     }
8767     else if (info.inFormat == RTAUDIO_SINT24) {
8768       Int32 *in = (Int32 *)inBuffer;
8769       for (int i=0; i<stream_.bufferSize; i++) {
8770         for (j=0; j<info.channels; j++) {
8771           out[info.outOffset[j]] = (Int32) in[info.inOffset[j]];
8772         }
8773         in += info.inJump;
8774         out += info.outJump;
8775       }
8776     }
8777     else if (info.inFormat == RTAUDIO_SINT32) {
8778       // Channel compensation and/or (de)interleaving only.
8779       Int32 *in = (Int32 *)inBuffer;
8780       for (int i=0; i<stream_.bufferSize; i++) {
8781         for (j=0; j<info.channels; j++) {
8782           out[info.outOffset[j]] = in[info.inOffset[j]];
8783         }
8784         in += info.inJump;
8785         out += info.outJump;
8786       }
8787     }
8788     else if (info.inFormat == RTAUDIO_FLOAT32) {
8789       Float32 *in = (Float32 *)inBuffer;
8790       for (int i=0; i<stream_.bufferSize; i++) {
8791         for (j=0; j<info.channels; j++) {
8792           out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.0);
8793         }
8794         in += info.inJump;
8795         out += info.outJump;
8796       }
8797     }
8798     else if (info.inFormat == RTAUDIO_FLOAT64) {
8799       Float64 *in = (Float64 *)inBuffer;
8800       for (int i=0; i<stream_.bufferSize; i++) {
8801         for (j=0; j<info.channels; j++) {
8802           out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.0);
8803         }
8804         in += info.inJump;
8805         out += info.outJump;
8806       }
8807     }
8808   }
8809   else if (info.outFormat == RTAUDIO_SINT24) {
8810     Int32 *out = (Int32 *)outBuffer;
8811     if (info.inFormat == RTAUDIO_SINT8) {
8812       signed char *in = (signed char *)inBuffer;
8813       for (int i=0; i<stream_.bufferSize; i++) {
8814         for (j=0; j<info.channels; j++) {
8815           out[info.outOffset[j]] = (Int32) in[info.inOffset[j]];
8816           out[info.outOffset[j]] <<= 24;
8817         }
8818         in += info.inJump;
8819         out += info.outJump;
8820       }
8821     }
8822     else if (info.inFormat == RTAUDIO_SINT16) {
8823       Int16 *in = (Int16 *)inBuffer;
8824       for (int i=0; i<stream_.bufferSize; i++) {
8825         for (j=0; j<info.channels; j++) {
8826           out[info.outOffset[j]] = (Int32) in[info.inOffset[j]];
8827           out[info.outOffset[j]] <<= 16;
8828         }
8829         in += info.inJump;
8830         out += info.outJump;
8831       }
8832     }
8833     else if (info.inFormat == RTAUDIO_SINT24) {
8834       // Channel compensation and/or (de)interleaving only.
8835       Int32 *in = (Int32 *)inBuffer;
8836       for (int i=0; i<stream_.bufferSize; i++) {
8837         for (j=0; j<info.channels; j++) {
8838           out[info.outOffset[j]] = in[info.inOffset[j]];
8839         }
8840         in += info.inJump;
8841         out += info.outJump;
8842       }
8843     }
8844     else if (info.inFormat == RTAUDIO_SINT32) {
8845       Int32 *in = (Int32 *)inBuffer;
8846       for (int i=0; i<stream_.bufferSize; i++) {
8847         for (j=0; j<info.channels; j++) {
8848           out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] & 0xffffff00);
8849         }
8850         in += info.inJump;
8851         out += info.outJump;
8852       }
8853     }
8854     else if (info.inFormat == RTAUDIO_FLOAT32) {
8855       Float32 *in = (Float32 *)inBuffer;
8856       for (int i=0; i<stream_.bufferSize; i++) {
8857         for (j=0; j<info.channels; j++) {
8858           out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.0);
8859         }
8860         in += info.inJump;
8861         out += info.outJump;
8862       }
8863     }
8864     else if (info.inFormat == RTAUDIO_FLOAT64) {
8865       Float64 *in = (Float64 *)inBuffer;
8866       for (int i=0; i<stream_.bufferSize; i++) {
8867         for (j=0; j<info.channels; j++) {
8868           out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.0);
8869         }
8870         in += info.inJump;
8871         out += info.outJump;
8872       }
8873     }
8874   }
8875   else if (info.outFormat == RTAUDIO_SINT16) {
8876     Int16 *out = (Int16 *)outBuffer;
8877     if (info.inFormat == RTAUDIO_SINT8) {
8878       signed char *in = (signed char *)inBuffer;
8879       for (int i=0; i<stream_.bufferSize; i++) {
8880         for (j=0; j<info.channels; j++) {
8881           out[info.outOffset[j]] = (Int16) in[info.inOffset[j]];
8882           out[info.outOffset[j]] <<= 8;
8883         }
8884         in += info.inJump;
8885         out += info.outJump;
8886       }
8887     }
8888     else if (info.inFormat == RTAUDIO_SINT16) {
8889       // Channel compensation and/or (de)interleaving only.
8890       Int16 *in = (Int16 *)inBuffer;
8891       for (int i=0; i<stream_.bufferSize; i++) {
8892         for (j=0; j<info.channels; j++) {
8893           out[info.outOffset[j]] = in[info.inOffset[j]];
8894         }
8895         in += info.inJump;
8896         out += info.outJump;
8897       }
8898     }
8899     else if (info.inFormat == RTAUDIO_SINT24) {
8900       Int32 *in = (Int32 *)inBuffer;
8901       for (int i=0; i<stream_.bufferSize; i++) {
8902         for (j=0; j<info.channels; j++) {
8903           out[info.outOffset[j]] = (Int16) ((in[info.inOffset[j]] >> 16) & 0x0000ffff);
8904         }
8905         in += info.inJump;
8906         out += info.outJump;
8907       }
8908     }
8909     else if (info.inFormat == RTAUDIO_SINT32) {
8910       Int32 *in = (Int32 *)inBuffer;
8911       for (int i=0; i<stream_.bufferSize; i++) {
8912         for (j=0; j<info.channels; j++) {
8913           out[info.outOffset[j]] = (Int16) ((in[info.inOffset[j]] >> 16) & 0x0000ffff);
8914         }
8915         in += info.inJump;
8916         out += info.outJump;
8917       }
8918     }
8919     else if (info.inFormat == RTAUDIO_FLOAT32) {
8920       Float32 *in = (Float32 *)inBuffer;
8921       for (int i=0; i<stream_.bufferSize; i++) {
8922         for (j=0; j<info.channels; j++) {
8923           out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.0);
8924         }
8925         in += info.inJump;
8926         out += info.outJump;
8927       }
8928     }
8929     else if (info.inFormat == RTAUDIO_FLOAT64) {
8930       Float64 *in = (Float64 *)inBuffer;
8931       for (int i=0; i<stream_.bufferSize; i++) {
8932         for (j=0; j<info.channels; j++) {
8933           out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.0);
8934         }
8935         in += info.inJump;
8936         out += info.outJump;
8937       }
8938     }
8939   }
8940   else if (info.outFormat == RTAUDIO_SINT8) {
8941     signed char *out = (signed char *)outBuffer;
8942     if (info.inFormat == RTAUDIO_SINT8) {
8943       // Channel compensation and/or (de)interleaving only.
8944       signed char *in = (signed char *)inBuffer;
8945       for (int i=0; i<stream_.bufferSize; i++) {
8946         for (j=0; j<info.channels; j++) {
8947           out[info.outOffset[j]] = in[info.inOffset[j]];
8948         }
8949         in += info.inJump;
8950         out += info.outJump;
8951       }
8952     }
8953     if (info.inFormat == RTAUDIO_SINT16) {
8954       Int16 *in = (Int16 *)inBuffer;
8955       for (int i=0; i<stream_.bufferSize; i++) {
8956         for (j=0; j<info.channels; j++) {
8957           out[info.outOffset[j]] = (signed char) ((in[info.inOffset[j]] >> 8) & 0x00ff);
8958         }
8959         in += info.inJump;
8960         out += info.outJump;
8961       }
8962     }
8963     else if (info.inFormat == RTAUDIO_SINT24) {
8964       Int32 *in = (Int32 *)inBuffer;
8965       for (int i=0; i<stream_.bufferSize; i++) {
8966         for (j=0; j<info.channels; j++) {
8967           out[info.outOffset[j]] = (signed char) ((in[info.inOffset[j]] >> 24) & 0x000000ff);
8968         }
8969         in += info.inJump;
8970         out += info.outJump;
8971       }
8972     }
8973     else if (info.inFormat == RTAUDIO_SINT32) {
8974       Int32 *in = (Int32 *)inBuffer;
8975       for (int i=0; i<stream_.bufferSize; i++) {
8976         for (j=0; j<info.channels; j++) {
8977           out[info.outOffset[j]] = (signed char) ((in[info.inOffset[j]] >> 24) & 0x000000ff);
8978         }
8979         in += info.inJump;
8980         out += info.outJump;
8981       }
8982     }
8983     else if (info.inFormat == RTAUDIO_FLOAT32) {
8984       Float32 *in = (Float32 *)inBuffer;
8985       for (int i=0; i<stream_.bufferSize; i++) {
8986         for (j=0; j<info.channels; j++) {
8987           out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.0);
8988         }
8989         in += info.inJump;
8990         out += info.outJump;
8991       }
8992     }
8993     else if (info.inFormat == RTAUDIO_FLOAT64) {
8994       Float64 *in = (Float64 *)inBuffer;
8995       for (int i=0; i<stream_.bufferSize; i++) {
8996         for (j=0; j<info.channels; j++) {
8997           out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.0);
8998         }
8999         in += info.inJump;
9000         out += info.outJump;
9001       }
9002     }
9003   }
9004 }
9005
9006 void RtApi :: byteSwapBuffer( char *buffer, int samples, RtAudioFormat format )
9007 {
9008   register char val;
9009   register char *ptr;
9010
9011   ptr = buffer;
9012   if (format == RTAUDIO_SINT16) {
9013     for (int i=0; i<samples; i++) {
9014       // Swap 1st and 2nd bytes.
9015       val = *(ptr);
9016       *(ptr) = *(ptr+1);
9017       *(ptr+1) = val;
9018
9019       // Increment 2 bytes.
9020       ptr += 2;
9021     }
9022   }
9023   else if (format == RTAUDIO_SINT24 ||
9024            format == RTAUDIO_SINT32 ||
9025            format == RTAUDIO_FLOAT32) {
9026     for (int i=0; i<samples; i++) {
9027       // Swap 1st and 4th bytes.
9028       val = *(ptr);
9029       *(ptr) = *(ptr+3);
9030       *(ptr+3) = val;
9031
9032       // Swap 2nd and 3rd bytes.
9033       ptr += 1;
9034       val = *(ptr);
9035       *(ptr) = *(ptr+1);
9036       *(ptr+1) = val;
9037
9038       // Increment 4 bytes.
9039       ptr += 4;
9040     }
9041   }
9042   else if (format == RTAUDIO_FLOAT64) {
9043     for (int i=0; i<samples; i++) {
9044       // Swap 1st and 8th bytes
9045       val = *(ptr);
9046       *(ptr) = *(ptr+7);
9047       *(ptr+7) = val;
9048
9049       // Swap 2nd and 7th bytes
9050       ptr += 1;
9051       val = *(ptr);
9052       *(ptr) = *(ptr+5);
9053       *(ptr+5) = val;
9054
9055       // Swap 3rd and 6th bytes
9056       ptr += 1;
9057       val = *(ptr);
9058       *(ptr) = *(ptr+3);
9059       *(ptr+3) = val;
9060
9061       // Swap 4th and 5th bytes
9062       ptr += 1;
9063       val = *(ptr);
9064       *(ptr) = *(ptr+1);
9065       *(ptr+1) = val;
9066
9067       // Increment 8 bytes.
9068       ptr += 8;
9069     }
9070   }
9071 }