Version 2.0
[rtaudio-cdist.git] / RtAudio.cpp
1 /******************************************/
2 /*
3   RtAudio - realtime sound I/O C++ class
4   Version 2.0 by Gary P. Scavone, 2001-2002.
5 */
6 /******************************************/
7
8 #include "RtAudio.h"
9 #include <vector>
10 #include <stdio.h>
11
12 // Static variable definitions.
13 const unsigned int RtAudio :: SAMPLE_RATES[] = {
14   4000, 5512, 8000, 9600, 11025, 16000, 22050,
15   32000, 44100, 48000, 88200, 96000, 176400, 192000
16 };
17 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT8 = 1;
18 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT16 = 2;
19 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT24 = 4;
20 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT32 = 8;
21 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT32 = 16;
22 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT64 = 32;
23
24 #if defined(__WINDOWS_DS_)
25   #define MUTEX_INITIALIZE(A) InitializeCriticalSection(A)
26   #define MUTEX_LOCK(A)       EnterCriticalSection(A)
27   #define MUTEX_UNLOCK(A)     LeaveCriticalSection(A)
28   typedef unsigned THREAD_RETURN;
29 #else // pthread API
30   #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL)
31   #define MUTEX_LOCK(A)       pthread_mutex_lock(A)
32   #define MUTEX_UNLOCK(A)     pthread_mutex_unlock(A)
33   typedef void * THREAD_RETURN;
34 #endif
35
36 // *************************************************** //
37 //
38 // Public common (OS-independent) methods.
39 //
40 // *************************************************** //
41
42 RtAudio :: RtAudio()
43 {
44   initialize();
45
46   if (nDevices <= 0) {
47     sprintf(message, "RtAudio: no audio devices found!");
48     error(RtAudioError::NO_DEVICES_FOUND);
49   }
50 }
51
52 RtAudio :: RtAudio(int *streamID,
53                    int outputDevice, int outputChannels,
54                    int inputDevice, int inputChannels,
55                    RTAUDIO_FORMAT format, int sampleRate,
56                    int *bufferSize, int numberOfBuffers)
57 {
58   initialize();
59
60   if (nDevices <= 0) {
61     sprintf(message, "RtAudio: no audio devices found!");
62     error(RtAudioError::NO_DEVICES_FOUND);
63   }
64
65   try {
66     *streamID = openStream(outputDevice, outputChannels, inputDevice, inputChannels,
67                            format, sampleRate, bufferSize, numberOfBuffers);
68   }
69   catch (RtAudioError &exception) {
70     // deallocate the RTAUDIO_DEVICE structures
71     if (devices) free(devices);
72     error(exception.getType());
73   }
74 }
75
76 RtAudio :: ~RtAudio()
77 {
78   // close any existing streams
79   while ( streams.size() )
80     closeStream( streams.begin()->first );
81
82   // deallocate the RTAUDIO_DEVICE structures
83   if (devices) free(devices);
84 }
85
86 int RtAudio :: openStream(int outputDevice, int outputChannels,
87                           int inputDevice, int inputChannels,
88                           RTAUDIO_FORMAT format, int sampleRate,
89                           int *bufferSize, int numberOfBuffers)
90 {
91   static int streamKey = 0; // Unique stream identifier ... OK for multiple instances.
92
93   if (outputChannels < 1 && inputChannels < 1) {
94     sprintf(message,"RtAudio: one or both 'channel' parameters must be greater than zero.");
95     error(RtAudioError::INVALID_PARAMETER);
96   }
97
98   if ( formatBytes(format) == 0 ) {
99     sprintf(message,"RtAudio: 'format' parameter value is undefined.");
100     error(RtAudioError::INVALID_PARAMETER);
101   }
102
103   if ( outputChannels > 0 ) {
104     if (outputDevice >= nDevices || outputDevice < 0) {
105       sprintf(message,"RtAudio: 'outputDevice' parameter value (%d) is invalid.", outputDevice);
106       error(RtAudioError::INVALID_PARAMETER);
107     }
108   }
109
110   if ( inputChannels > 0 ) {
111     if (inputDevice >= nDevices || inputDevice < 0) {
112       sprintf(message,"RtAudio: 'inputDevice' parameter value (%d) is invalid.", inputDevice);
113       error(RtAudioError::INVALID_PARAMETER);
114     }
115   }
116
117   // Allocate a new stream structure.
118   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) calloc(1, sizeof(RTAUDIO_STREAM));
119   if (stream == NULL) {
120     sprintf(message, "RtAudio: memory allocation error!");
121     error(RtAudioError::MEMORY_ERROR);
122   }
123   streams[++streamKey] = (void *) stream;
124   stream->mode = UNINITIALIZED;
125
126   bool result = SUCCESS;
127   int device;
128   STREAM_MODE mode;
129   int channels;
130   if ( outputChannels > 0 ) {
131
132     device = outputDevice;
133     mode = PLAYBACK;
134     channels = outputChannels;
135
136     if (device == 0) { // Try default device first.
137       for (int i=0; i<nDevices; i++) {
138         if (devices[i].probed == false) {
139           // If the device wasn't successfully probed before, try it
140           // again now.
141           clearDeviceInfo(&devices[i]);
142           probeDeviceInfo(&devices[i]);
143           if (devices[i].probed == false)
144             continue;
145         }
146         result = probeDeviceOpen(i, stream, mode, channels, sampleRate,
147                                  format, bufferSize, numberOfBuffers);
148         if (result == SUCCESS)
149           break;
150       }
151     }
152     else {
153       result = probeDeviceOpen(device, stream, mode, channels, sampleRate,
154                                format, bufferSize, numberOfBuffers);
155     }
156   }
157
158   if ( inputChannels > 0 && result == SUCCESS ) {
159
160     device = inputDevice;
161     mode = RECORD;
162     channels = inputChannels;
163
164     if (device == 0) { // Try default device first.
165       for (int i=0; i<nDevices; i++) {
166         if (devices[i].probed == false) {
167           // If the device wasn't successfully probed before, try it
168           // again now.
169           clearDeviceInfo(&devices[i]);
170           probeDeviceInfo(&devices[i]);
171           if (devices[i].probed == false)
172             continue;
173         }
174         result = probeDeviceOpen(i, stream, mode, channels, sampleRate,
175                                  format, bufferSize, numberOfBuffers);
176         if (result == SUCCESS)
177           break;
178       }
179     }
180     else {
181       result = probeDeviceOpen(device, stream, mode, channels, sampleRate,
182                                format, bufferSize, numberOfBuffers);
183     }
184   }
185
186   if ( result == SUCCESS ) {
187     MUTEX_INITIALIZE(&stream->mutex);
188     return streamKey;
189   }
190
191   // If we get here, all attempted probes failed.  Close any opened
192   // devices and delete the allocated stream.
193   closeStream(streamKey);
194   sprintf(message,"RtAudio: no devices found for given parameters.");
195   error(RtAudioError::INVALID_PARAMETER);
196
197   return -1;
198 }
199
200 int RtAudio :: getDeviceCount(void)
201 {
202   return nDevices;
203 }
204
205 void RtAudio :: getDeviceInfo(int device, RTAUDIO_DEVICE *info)
206 {
207   if (device >= nDevices || device < 0) {
208     sprintf(message, "RtAudio: invalid device specifier (%d)!", device);
209     error(RtAudioError::INVALID_DEVICE);
210   }
211
212   // If the device wasn't successfully probed before, try it again.
213   if (devices[device].probed == false) {
214     clearDeviceInfo(&devices[device]);
215     probeDeviceInfo(&devices[device]);
216   }
217
218   // Clear the info structure.
219   memset(info, 0, sizeof(RTAUDIO_DEVICE));
220
221   strncpy(info->name, devices[device].name, 128);
222   info->probed = devices[device].probed;
223   if ( info->probed == true ) {
224     info->maxOutputChannels = devices[device].maxOutputChannels;
225     info->maxInputChannels = devices[device].maxInputChannels;
226     info->maxDuplexChannels = devices[device].maxDuplexChannels;
227     info->minOutputChannels = devices[device].minOutputChannels;
228     info->minInputChannels = devices[device].minInputChannels;
229     info->minDuplexChannels = devices[device].minDuplexChannels;
230     info->hasDuplexSupport = devices[device].hasDuplexSupport;
231     info->nSampleRates = devices[device].nSampleRates;
232     if (info->nSampleRates == -1) {
233       info->sampleRates[0] = devices[device].sampleRates[0];
234       info->sampleRates[1] = devices[device].sampleRates[1];
235     }
236     else {
237       for (int i=0; i<info->nSampleRates; i++)
238         info->sampleRates[i] = devices[device].sampleRates[i];
239     }
240     info->nativeFormats = devices[device].nativeFormats;
241   }
242
243   return;
244 }
245
246 char * const RtAudio :: getStreamBuffer(int streamID)
247 {
248   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
249
250   return stream->userBuffer;
251 }
252
253 // This global structure is used to pass information to the thread
254 // function.  I tried other methods but had intermittent errors due to
255 // variable persistence during thread startup.
256 struct {
257   RtAudio *object;
258   int streamID;
259 } thread_info;
260
261 #if defined(__WINDOWS_DS_)
262   extern "C" unsigned __stdcall callbackHandler(void *ptr);
263 #else
264   extern "C" void *callbackHandler(void *ptr);
265 #endif
266
267 void RtAudio :: setStreamCallback(int streamID, RTAUDIO_CALLBACK callback, void *userData)
268 {
269   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
270
271   stream->callback = callback;
272   stream->userData = userData;
273   stream->usingCallback = true;
274   thread_info.object = this;
275   thread_info.streamID = streamID;
276
277   int err = 0;
278 #if defined(__WINDOWS_DS_)
279   unsigned thread_id;
280   stream->thread = _beginthreadex(NULL, 0, &callbackHandler,
281                                   &stream->usingCallback, 0, &thread_id);
282   if (stream->thread == 0) err = -1;
283   // When spawning multiple threads in quick succession, it appears to be
284   // necessary to wait a bit for each to initialize ... another windism!
285   Sleep(1);
286 #else
287   err = pthread_create(&stream->thread, NULL, callbackHandler, &stream->usingCallback);
288 #endif
289
290   if (err) {
291     stream->usingCallback = false;
292     sprintf(message, "RtAudio: error starting callback thread!");
293     error(RtAudioError::THREAD_ERROR);
294   }
295 }
296
297 // *************************************************** //
298 //
299 // OS/API-specific methods.
300 //
301 // *************************************************** //
302
303 #if defined(__LINUX_ALSA_)
304
305 void RtAudio :: initialize(void)
306 {
307   int card, err, device;
308   int devices_per_card[32] = {0};
309   char name[32];
310   snd_ctl_t *handle;
311   snd_ctl_card_info_t *info;
312   snd_ctl_card_info_alloca(&info);
313
314   // Count cards and devices
315   nDevices = 0;
316   card = -1;
317   snd_card_next(&card);
318   while (card >= 0) {
319     sprintf(name, "hw:%d", card);
320     err = snd_ctl_open(&handle, name, 0);
321     if (err < 0) {
322       sprintf(message, "RtAudio: ALSA control open (%i): %s.", card, snd_strerror(err));
323       error(RtAudioError::WARNING);
324       goto next_card;
325                 }
326     err = snd_ctl_card_info(handle, info);
327                 if (err < 0) {
328       sprintf(message, "RtAudio: ALSA control hardware info (%i): %s.", card, snd_strerror(err));
329       error(RtAudioError::WARNING);
330       goto next_card;
331                 }
332                 device = -1;
333                 while (1) {
334       err = snd_ctl_pcm_next_device(handle, &device);
335                         if (err < 0) {
336         sprintf(message, "RtAudio: ALSA control next device (%i): %s.", card, snd_strerror(err));
337         error(RtAudioError::WARNING);
338         break;
339       }
340                         if (device < 0)
341         break;
342       nDevices++;
343       devices_per_card[card]++;
344     }
345
346   next_card:
347     snd_ctl_close(handle);
348     snd_card_next(&card);
349   }
350
351   if (nDevices == 0) return;
352
353   //  Allocate the RTAUDIO_DEVICE structures.
354   devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
355   if (devices == NULL) {
356     sprintf(message, "RtAudio: memory allocation error!");
357     error(RtAudioError::MEMORY_ERROR);
358   }
359
360   // Write device ascii identifiers to device structures and then
361   // probe the device capabilities.
362   card = 0;
363   device = 0;
364   for (int i=0; i<nDevices; i++) {
365     if (devices_per_card[card])
366       sprintf(devices[i].name, "hw:%d,%d", card, device);
367     if (devices_per_card[card] <= device+1) {
368       card++;
369       device = 0;
370     }
371     else
372       device++;
373     probeDeviceInfo(&devices[i]);
374   }
375
376   return;
377 }
378
379 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
380 {
381   int err;
382   int open_mode = SND_PCM_ASYNC;
383   snd_pcm_t *handle;
384   snd_pcm_stream_t stream;
385
386   // First try for playback
387   stream = SND_PCM_STREAM_PLAYBACK;
388   err = snd_pcm_open(&handle, info->name, stream, open_mode);
389   if (err < 0) {
390     sprintf(message, "RtAudio: ALSA pcm playback open (%s): %s.",
391             info->name, snd_strerror(err));
392     error(RtAudioError::WARNING);
393     goto capture_probe;
394   }
395
396   snd_pcm_hw_params_t *params;
397   snd_pcm_hw_params_alloca(&params);
398
399   // We have an open device ... allocate the parameter structure.
400   err = snd_pcm_hw_params_any(handle, params);
401   if (err < 0) {
402     snd_pcm_close(handle);
403     sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.",
404             info->name, snd_strerror(err));
405     error(RtAudioError::WARNING);
406     goto capture_probe;
407   }
408
409   // Get output channel information.
410   info->minOutputChannels = snd_pcm_hw_params_get_channels_min(params);
411   info->maxOutputChannels = snd_pcm_hw_params_get_channels_max(params);
412
413   snd_pcm_close(handle);
414
415  capture_probe:
416   // Now try for capture
417   stream = SND_PCM_STREAM_CAPTURE;
418   err = snd_pcm_open(&handle, info->name, stream, open_mode);
419   if (err < 0) {
420     sprintf(message, "RtAudio: ALSA pcm capture open (%s): %s.",
421             info->name, snd_strerror(err));
422     error(RtAudioError::WARNING);
423     if (info->maxOutputChannels == 0)
424       // didn't open for playback either ... device invalid
425       return;
426     goto probe_parameters;
427   }
428
429   // We have an open capture device ... allocate the parameter structure.
430   err = snd_pcm_hw_params_any(handle, params);
431   if (err < 0) {
432     snd_pcm_close(handle);
433     sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.",
434             info->name, snd_strerror(err));
435     error(RtAudioError::WARNING);
436     if (info->maxOutputChannels > 0)
437       goto probe_parameters;
438     else
439       return;
440   }
441
442   // Get input channel information.
443   info->minInputChannels = snd_pcm_hw_params_get_channels_min(params);
444   info->maxInputChannels = snd_pcm_hw_params_get_channels_max(params);
445
446   // If device opens for both playback and capture, we determine the channels.
447   if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
448     goto probe_parameters;
449
450   info->hasDuplexSupport = true;
451   info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
452     info->maxInputChannels : info->maxOutputChannels;
453   info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
454     info->minInputChannels : info->minOutputChannels;
455
456   snd_pcm_close(handle);
457
458  probe_parameters:
459   // At this point, we just need to figure out the supported data formats and sample rates.
460   // We'll proceed by openning the device in the direction with the maximum number of channels,
461   // or playback if they are equal.  This might limit our sample rate options, but so be it.
462
463   if (info->maxOutputChannels >= info->maxInputChannels)
464     stream = SND_PCM_STREAM_PLAYBACK;
465   else
466     stream = SND_PCM_STREAM_CAPTURE;
467
468   err = snd_pcm_open(&handle, info->name, stream, open_mode);
469   if (err < 0) {
470     sprintf(message, "RtAudio: ALSA pcm (%s) won't reopen during probe: %s.",
471             info->name, snd_strerror(err));
472     error(RtAudioError::WARNING);
473     return;
474   }
475
476   // We have an open device ... allocate the parameter structure.
477   err = snd_pcm_hw_params_any(handle, params);
478   if (err < 0) {
479     snd_pcm_close(handle);
480     sprintf(message, "RtAudio: ALSA hardware reopen probe error (%s): %s.",
481             info->name, snd_strerror(err));
482     error(RtAudioError::WARNING);
483     return;
484   }
485
486   // Test a non-standard sample rate to see if continuous rate is supported.
487   int dir = 0;
488   if (snd_pcm_hw_params_test_rate(handle, params, 35500, dir) == 0) {
489     // It appears that continuous sample rate support is available.
490     info->nSampleRates = -1;
491     info->sampleRates[0] = snd_pcm_hw_params_get_rate_min(params, &dir);
492     info->sampleRates[1] = snd_pcm_hw_params_get_rate_max(params, &dir);
493   }
494   else {
495     // No continuous rate support ... test our discrete set of sample rate values.
496     info->nSampleRates = 0;
497     for (int i=0; i<MAX_SAMPLE_RATES; i++) {
498       if (snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0) {
499         info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
500         info->nSampleRates++;
501       }
502     }
503     if (info->nSampleRates == 0) {
504       snd_pcm_close(handle);
505       return;
506     }
507   }
508
509   // Probe the supported data formats ... we don't care about endian-ness just yet
510   snd_pcm_format_t format;
511   info->nativeFormats = 0;
512   format = SND_PCM_FORMAT_S8;
513   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
514     info->nativeFormats |= RTAUDIO_SINT8;
515   format = SND_PCM_FORMAT_S16;
516   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
517     info->nativeFormats |= RTAUDIO_SINT16;
518   format = SND_PCM_FORMAT_S24;
519   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
520     info->nativeFormats |= RTAUDIO_SINT24;
521   format = SND_PCM_FORMAT_S32;
522   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
523     info->nativeFormats |= RTAUDIO_SINT32;
524   format = SND_PCM_FORMAT_FLOAT;
525   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
526     info->nativeFormats |= RTAUDIO_FLOAT32;
527   format = SND_PCM_FORMAT_FLOAT64;
528   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
529     info->nativeFormats |= RTAUDIO_FLOAT64;
530
531   // Check that we have at least one supported format
532   if (info->nativeFormats == 0) {
533     snd_pcm_close(handle);
534     sprintf(message, "RtAudio: ALSA PCM device (%s) data format not supported by RtAudio.",
535             info->name);
536     error(RtAudioError::WARNING);
537     return;
538   }
539
540   // That's all ... close the device and return
541   snd_pcm_close(handle);
542   info->probed = true;
543   return;
544 }
545
546 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
547                                 STREAM_MODE mode, int channels, 
548                                 int sampleRate, RTAUDIO_FORMAT format,
549                                 int *bufferSize, int numberOfBuffers)
550 {
551 #if defined(RTAUDIO_DEBUG)
552   snd_output_t *out;
553   snd_output_stdio_attach(&out, stderr, 0);
554 #endif
555
556   // I'm not using the "plug" interface ... too much inconsistent behavior.
557   const char *name = devices[device].name;
558
559   snd_pcm_stream_t alsa_stream;
560   if (mode == PLAYBACK)
561     alsa_stream = SND_PCM_STREAM_PLAYBACK;
562   else
563     alsa_stream = SND_PCM_STREAM_CAPTURE;
564
565   int err;
566   snd_pcm_t *handle;
567   int alsa_open_mode = SND_PCM_ASYNC;
568   err = snd_pcm_open(&handle, name, alsa_stream, alsa_open_mode);
569   if (err < 0) {
570     sprintf(message,"RtAudio: ALSA pcm device (%s) won't open: %s.",
571             name, snd_strerror(err));
572     error(RtAudioError::WARNING);
573     return FAILURE;
574   }
575
576   // Fill the parameter structure.
577   snd_pcm_hw_params_t *hw_params;
578   snd_pcm_hw_params_alloca(&hw_params);
579   err = snd_pcm_hw_params_any(handle, hw_params);
580   if (err < 0) {
581     snd_pcm_close(handle);
582     sprintf(message, "RtAudio: ALSA error getting parameter handle (%s): %s.",
583             name, snd_strerror(err));
584     error(RtAudioError::WARNING);
585     return FAILURE;
586   }
587
588 #if defined(RTAUDIO_DEBUG)
589   fprintf(stderr, "\nRtAudio: ALSA dump hardware params just after device open:\n\n");
590   snd_pcm_hw_params_dump(hw_params, out);
591 #endif
592
593   // Set access ... try interleaved access first, then non-interleaved
594   err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
595   if (err < 0) {
596     // No interleave support ... try non-interleave.
597                 err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED);
598     if (err < 0) {
599       snd_pcm_close(handle);
600       sprintf(message, "RtAudio: ALSA error setting access ( (%s): %s.",
601               name, snd_strerror(err));
602       error(RtAudioError::WARNING);
603       return FAILURE;
604     }
605     stream->deInterleave[mode] = true;
606   }
607
608   // Determine how to set the device format.
609   stream->userFormat = format;
610   snd_pcm_format_t device_format;
611
612   if (format == RTAUDIO_SINT8)
613     device_format = SND_PCM_FORMAT_S8;
614   else if (format == RTAUDIO_SINT16)
615     device_format = SND_PCM_FORMAT_S16;
616   else if (format == RTAUDIO_SINT24)
617     device_format = SND_PCM_FORMAT_S24;
618   else if (format == RTAUDIO_SINT32)
619     device_format = SND_PCM_FORMAT_S32;
620   else if (format == RTAUDIO_FLOAT32)
621     device_format = SND_PCM_FORMAT_FLOAT;
622   else if (format == RTAUDIO_FLOAT64)
623     device_format = SND_PCM_FORMAT_FLOAT64;
624
625   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
626     stream->deviceFormat[mode] = format;
627     goto set_format;
628   }
629
630   // The user requested format is not natively supported by the device.
631   device_format = SND_PCM_FORMAT_FLOAT64;
632   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
633     stream->deviceFormat[mode] = RTAUDIO_FLOAT64;
634     goto set_format;
635   }
636
637   device_format = SND_PCM_FORMAT_FLOAT;
638   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
639     stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
640     goto set_format;
641   }
642
643   device_format = SND_PCM_FORMAT_S32;
644   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
645     stream->deviceFormat[mode] = RTAUDIO_SINT32;
646     goto set_format;
647   }
648
649   device_format = SND_PCM_FORMAT_S24;
650   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
651     stream->deviceFormat[mode] = RTAUDIO_SINT24;
652     goto set_format;
653   }
654
655   device_format = SND_PCM_FORMAT_S16;
656   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
657     stream->deviceFormat[mode] = RTAUDIO_SINT16;
658     goto set_format;
659   }
660
661   device_format = SND_PCM_FORMAT_S8;
662   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
663     stream->deviceFormat[mode] = RTAUDIO_SINT8;
664     goto set_format;
665   }
666
667   // If we get here, no supported format was found.
668   sprintf(message,"RtAudio: ALSA pcm device (%s) data format not supported by RtAudio.", name);
669   snd_pcm_close(handle);
670   error(RtAudioError::WARNING);
671   return FAILURE;
672
673  set_format:
674   err = snd_pcm_hw_params_set_format(handle, hw_params, device_format);
675   if (err < 0) {
676     snd_pcm_close(handle);
677     sprintf(message, "RtAudio: ALSA error setting format (%s): %s.",
678             name, snd_strerror(err));
679     error(RtAudioError::WARNING);
680     return FAILURE;
681   }
682
683   // Determine whether byte-swaping is necessary.
684   stream->doByteSwap[mode] = false;
685   if (device_format != SND_PCM_FORMAT_S8) {
686     err = snd_pcm_format_cpu_endian(device_format);
687     if (err == 0)
688       stream->doByteSwap[mode] = true;
689     else if (err < 0) {
690       snd_pcm_close(handle);
691       sprintf(message, "RtAudio: ALSA error getting format endian-ness (%s): %s.",
692               name, snd_strerror(err));
693       error(RtAudioError::WARNING);
694       return FAILURE;
695     }
696   }
697
698   // Determine the number of channels for this device.  We support a possible
699   // minimum device channel number > than the value requested by the user.
700   stream->nUserChannels[mode] = channels;
701   int device_channels = snd_pcm_hw_params_get_channels_max(hw_params);
702   if (device_channels < channels) {
703     snd_pcm_close(handle);
704     sprintf(message, "RtAudio: channels (%d) not supported by device (%s).",
705             channels, name);
706     error(RtAudioError::WARNING);
707     return FAILURE;
708   }
709
710   device_channels = snd_pcm_hw_params_get_channels_min(hw_params);
711   if (device_channels < channels) device_channels = channels;
712   stream->nDeviceChannels[mode] = device_channels;
713
714   // Set the device channels.
715   err = snd_pcm_hw_params_set_channels(handle, hw_params, device_channels);
716   if (err < 0) {
717     snd_pcm_close(handle);
718     sprintf(message, "RtAudio: ALSA error setting channels (%d) on device (%s): %s.",
719             device_channels, name, snd_strerror(err));
720     error(RtAudioError::WARNING);
721     return FAILURE;
722   }
723
724   // Set the sample rate.
725   err = snd_pcm_hw_params_set_rate(handle, hw_params, (unsigned int)sampleRate, 0);
726   if (err < 0) {
727     snd_pcm_close(handle);
728     sprintf(message, "RtAudio: ALSA error setting sample rate (%d) on device (%s): %s.",
729             sampleRate, name, snd_strerror(err));
730     error(RtAudioError::WARNING);
731     return FAILURE;
732   }
733
734   // Set the buffer number, which in ALSA is referred to as the "period".
735   int dir;
736   int periods = numberOfBuffers;
737   // Even though the hardware might allow 1 buffer, it won't work reliably.
738   if (periods < 2) periods = 2;
739   err = snd_pcm_hw_params_get_periods_min(hw_params, &dir);
740   if (err > periods) periods = err;
741
742   err = snd_pcm_hw_params_set_periods(handle, hw_params, periods, 0);
743   if (err < 0) {
744     snd_pcm_close(handle);
745     sprintf(message, "RtAudio: ALSA error setting periods (%s): %s.",
746             name, snd_strerror(err));
747     error(RtAudioError::WARNING);
748     return FAILURE;
749   }
750
751   // Set the buffer (or period) size.
752   err = snd_pcm_hw_params_get_period_size_min(hw_params, &dir);
753   if (err > *bufferSize) *bufferSize = err;
754
755   err = snd_pcm_hw_params_set_period_size(handle, hw_params, *bufferSize, 0);
756   if (err < 0) {
757     snd_pcm_close(handle);
758     sprintf(message, "RtAudio: ALSA error setting period size (%s): %s.",
759             name, snd_strerror(err));
760     error(RtAudioError::WARNING);
761     return FAILURE;
762   }
763
764   stream->bufferSize = *bufferSize;
765
766   // Install the hardware configuration
767   err = snd_pcm_hw_params(handle, hw_params);
768   if (err < 0) {
769     snd_pcm_close(handle);
770     sprintf(message, "RtAudio: ALSA error installing hardware configuration (%s): %s.",
771             name, snd_strerror(err));
772     error(RtAudioError::WARNING);
773     return FAILURE;
774   }
775
776 #if defined(RTAUDIO_DEBUG)
777   fprintf(stderr, "\nRtAudio: ALSA dump hardware params after installation:\n\n");
778   snd_pcm_hw_params_dump(hw_params, out);
779 #endif
780
781   /*
782   // Install the software configuration
783   snd_pcm_sw_params_t *sw_params = NULL;
784   snd_pcm_sw_params_alloca(&sw_params);
785   snd_pcm_sw_params_current(handle, sw_params);
786   err = snd_pcm_sw_params(handle, sw_params);
787   if (err < 0) {
788     snd_pcm_close(handle);
789     sprintf(message, "RtAudio: ALSA error installing software configuration (%s): %s.",
790             name, snd_strerror(err));
791     error(RtAudioError::WARNING);
792     return FAILURE;
793   }
794   */
795
796   // Set handle and flags for buffer conversion
797   stream->handle[mode] = handle;
798   stream->doConvertBuffer[mode] = false;
799   if (stream->userFormat != stream->deviceFormat[mode])
800     stream->doConvertBuffer[mode] = true;
801   if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
802     stream->doConvertBuffer[mode] = true;
803   if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode])
804     stream->doConvertBuffer[mode] = true;
805
806   // Allocate necessary internal buffers
807   if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
808
809     long buffer_bytes;
810     if (stream->nUserChannels[0] >= stream->nUserChannels[1])
811       buffer_bytes = stream->nUserChannels[0];
812     else
813       buffer_bytes = stream->nUserChannels[1];
814
815     buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
816     if (stream->userBuffer) free(stream->userBuffer);
817     stream->userBuffer = (char *) calloc(buffer_bytes, 1);
818     if (stream->userBuffer == NULL)
819       goto memory_error;
820   }
821
822   if ( stream->doConvertBuffer[mode] ) {
823
824     long buffer_bytes;
825     bool makeBuffer = true;
826     if ( mode == PLAYBACK )
827       buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
828     else { // mode == RECORD
829       buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
830       if ( stream->mode == PLAYBACK ) {
831         long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
832         if ( buffer_bytes > bytes_out )
833           buffer_bytes = (buffer_bytes > bytes_out) ? buffer_bytes : bytes_out;
834         else
835           makeBuffer = false;
836       }
837     }
838
839     if ( makeBuffer ) {
840       buffer_bytes *= *bufferSize;
841       if (stream->deviceBuffer) free(stream->deviceBuffer);
842       stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
843       if (stream->deviceBuffer == NULL)
844         goto memory_error;
845     }
846   }
847
848   stream->device[mode] = device;
849   stream->state = STREAM_STOPPED;
850   if ( stream->mode == PLAYBACK && mode == RECORD )
851     // We had already set up an output stream.
852     stream->mode = DUPLEX;
853   else
854     stream->mode = mode;
855   stream->nBuffers = periods;
856   stream->sampleRate = sampleRate;
857
858   return SUCCESS;
859
860  memory_error:
861   if (stream->handle[0]) {
862     snd_pcm_close(stream->handle[0]);
863     stream->handle[0] = 0;
864   }
865   if (stream->handle[1]) {
866     snd_pcm_close(stream->handle[1]);
867     stream->handle[1] = 0;
868   }
869   if (stream->userBuffer) {
870     free(stream->userBuffer);
871     stream->userBuffer = 0;
872   }
873   sprintf(message, "RtAudio: ALSA error allocating buffer memory (%s).", name);
874   error(RtAudioError::WARNING);
875   return FAILURE;
876 }
877
878 void RtAudio :: cancelStreamCallback(int streamID)
879 {
880   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
881
882   if (stream->usingCallback) {
883     stream->usingCallback = false;
884     pthread_cancel(stream->thread);
885     pthread_join(stream->thread, NULL);
886     stream->thread = 0;
887     stream->callback = NULL;
888     stream->userData = NULL;
889   }
890 }
891
892 void RtAudio :: closeStream(int streamID)
893 {
894   // We don't want an exception to be thrown here because this
895   // function is called by our class destructor.  So, do our own
896   // streamID check.
897   if ( streams.find( streamID ) == streams.end() ) {
898     sprintf(message, "RtAudio: invalid stream identifier!");
899     error(RtAudioError::WARNING);
900     return;
901   }
902
903   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamID];
904
905   if (stream->usingCallback) {
906     pthread_cancel(stream->thread);
907     pthread_join(stream->thread, NULL);
908   }
909
910   if (stream->state == STREAM_RUNNING) {
911     if (stream->mode == PLAYBACK || stream->mode == DUPLEX)
912       snd_pcm_drop(stream->handle[0]);
913     if (stream->mode == RECORD || stream->mode == DUPLEX)
914       snd_pcm_drop(stream->handle[1]);
915   }
916
917   pthread_mutex_destroy(&stream->mutex);
918
919   if (stream->handle[0])
920     snd_pcm_close(stream->handle[0]);
921
922   if (stream->handle[1])
923     snd_pcm_close(stream->handle[1]);
924
925   if (stream->userBuffer)
926     free(stream->userBuffer);
927
928   if (stream->deviceBuffer)
929     free(stream->deviceBuffer);
930
931   free(stream);
932   streams.erase(streamID);
933 }
934
935 void RtAudio :: startStream(int streamID)
936 {
937   // This method calls snd_pcm_prepare if the device isn't already in that state.
938
939   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
940
941   MUTEX_LOCK(&stream->mutex);
942
943   if (stream->state == STREAM_RUNNING)
944     goto unlock;
945
946   int err;
947   snd_pcm_state_t state;
948   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
949     state = snd_pcm_state(stream->handle[0]);
950     if (state != SND_PCM_STATE_PREPARED) {
951       err = snd_pcm_prepare(stream->handle[0]);
952       if (err < 0) {
953         sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.",
954                 devices[stream->device[0]].name, snd_strerror(err));
955         MUTEX_UNLOCK(&stream->mutex);
956         error(RtAudioError::DRIVER_ERROR);
957       }
958     }
959   }
960
961   if (stream->mode == RECORD || stream->mode == DUPLEX) {
962     state = snd_pcm_state(stream->handle[1]);
963     if (state != SND_PCM_STATE_PREPARED) {
964       err = snd_pcm_prepare(stream->handle[1]);
965       if (err < 0) {
966         sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.",
967                 devices[stream->device[1]].name, snd_strerror(err));
968         MUTEX_UNLOCK(&stream->mutex);
969         error(RtAudioError::DRIVER_ERROR);
970       }
971     }
972   }
973   stream->state = STREAM_RUNNING;
974
975  unlock:
976   MUTEX_UNLOCK(&stream->mutex);
977 }
978
979 void RtAudio :: stopStream(int streamID)
980 {
981   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
982
983   MUTEX_LOCK(&stream->mutex);
984
985   if (stream->state == STREAM_STOPPED)
986     goto unlock;
987
988   int err;
989   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
990     err = snd_pcm_drain(stream->handle[0]);
991     if (err < 0) {
992       sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
993               devices[stream->device[0]].name, snd_strerror(err));
994       MUTEX_UNLOCK(&stream->mutex);
995       error(RtAudioError::DRIVER_ERROR);
996     }
997   }
998
999   if (stream->mode == RECORD || stream->mode == DUPLEX) {
1000     err = snd_pcm_drain(stream->handle[1]);
1001     if (err < 0) {
1002       sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
1003               devices[stream->device[1]].name, snd_strerror(err));
1004       MUTEX_UNLOCK(&stream->mutex);
1005       error(RtAudioError::DRIVER_ERROR);
1006     }
1007   }
1008   stream->state = STREAM_STOPPED;
1009
1010  unlock:
1011   MUTEX_UNLOCK(&stream->mutex);
1012 }
1013
1014 void RtAudio :: abortStream(int streamID)
1015 {
1016   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
1017
1018   MUTEX_LOCK(&stream->mutex);
1019
1020   if (stream->state == STREAM_STOPPED)
1021     goto unlock;
1022
1023   int err;
1024   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
1025     err = snd_pcm_drop(stream->handle[0]);
1026     if (err < 0) {
1027       sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
1028               devices[stream->device[0]].name, snd_strerror(err));
1029       MUTEX_UNLOCK(&stream->mutex);
1030       error(RtAudioError::DRIVER_ERROR);
1031     }
1032   }
1033
1034   if (stream->mode == RECORD || stream->mode == DUPLEX) {
1035     err = snd_pcm_drop(stream->handle[1]);
1036     if (err < 0) {
1037       sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
1038               devices[stream->device[1]].name, snd_strerror(err));
1039       MUTEX_UNLOCK(&stream->mutex);
1040       error(RtAudioError::DRIVER_ERROR);
1041     }
1042   }
1043   stream->state = STREAM_STOPPED;
1044
1045  unlock:
1046   MUTEX_UNLOCK(&stream->mutex);
1047 }
1048
1049 int RtAudio :: streamWillBlock(int streamID)
1050 {
1051   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
1052
1053   MUTEX_LOCK(&stream->mutex);
1054
1055   int err = 0, frames = 0;
1056   if (stream->state == STREAM_STOPPED)
1057     goto unlock;
1058
1059   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
1060     err = snd_pcm_avail_update(stream->handle[0]);
1061     if (err < 0) {
1062       sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.",
1063               devices[stream->device[0]].name, snd_strerror(err));
1064       MUTEX_UNLOCK(&stream->mutex);
1065       error(RtAudioError::DRIVER_ERROR);
1066     }
1067   }
1068
1069   frames = err;
1070
1071   if (stream->mode == RECORD || stream->mode == DUPLEX) {
1072     err = snd_pcm_avail_update(stream->handle[1]);
1073     if (err < 0) {
1074       sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.",
1075               devices[stream->device[1]].name, snd_strerror(err));
1076       MUTEX_UNLOCK(&stream->mutex);
1077       error(RtAudioError::DRIVER_ERROR);
1078     }
1079     if (frames > err) frames = err;
1080   }
1081
1082   frames = stream->bufferSize - frames;
1083   if (frames < 0) frames = 0;
1084
1085  unlock:
1086   MUTEX_UNLOCK(&stream->mutex);
1087   return frames;
1088 }
1089
1090 void RtAudio :: tickStream(int streamID)
1091 {
1092   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
1093
1094   int stopStream = 0;
1095   if (stream->state == STREAM_STOPPED) {
1096     if (stream->usingCallback) usleep(50000); // sleep 50 milliseconds
1097     return;
1098   }
1099   else if (stream->usingCallback) {
1100     stopStream = stream->callback(stream->userBuffer, stream->bufferSize, stream->userData);
1101   }
1102
1103   MUTEX_LOCK(&stream->mutex);
1104
1105   // The state might change while waiting on a mutex.
1106   if (stream->state == STREAM_STOPPED)
1107     goto unlock;
1108
1109   int err;
1110   char *buffer;
1111   int channels;
1112   RTAUDIO_FORMAT format;
1113   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
1114
1115     // Setup parameters and do buffer conversion if necessary.
1116     if (stream->doConvertBuffer[0]) {
1117       convertStreamBuffer(stream, PLAYBACK);
1118       buffer = stream->deviceBuffer;
1119       channels = stream->nDeviceChannels[0];
1120       format = stream->deviceFormat[0];
1121     }
1122     else {
1123       buffer = stream->userBuffer;
1124       channels = stream->nUserChannels[0];
1125       format = stream->userFormat;
1126     }
1127
1128     // Do byte swapping if necessary.
1129     if (stream->doByteSwap[0])
1130       byteSwapBuffer(buffer, stream->bufferSize * channels, format);
1131
1132     // Write samples to device in interleaved/non-interleaved format.
1133     if (stream->deInterleave[0]) {
1134       void *bufs[channels];
1135       size_t offset = stream->bufferSize * formatBytes(format);
1136       for (int i=0; i<channels; i++)
1137         bufs[i] = (void *) (buffer + (i * offset));
1138       err = snd_pcm_writen(stream->handle[0], bufs, stream->bufferSize);
1139     }
1140     else
1141       err = snd_pcm_writei(stream->handle[0], buffer, stream->bufferSize);
1142
1143     if (err < stream->bufferSize) {
1144       // Either an error or underrun occured.
1145       if (err == -EPIPE) {
1146         snd_pcm_state_t state = snd_pcm_state(stream->handle[0]);
1147         if (state == SND_PCM_STATE_XRUN) {
1148           sprintf(message, "RtAudio: ALSA underrun detected.");
1149           error(RtAudioError::WARNING);
1150           err = snd_pcm_prepare(stream->handle[0]);
1151           if (err < 0) {
1152             sprintf(message, "RtAudio: ALSA error preparing handle after underrun: %s.",
1153                     snd_strerror(err));
1154             MUTEX_UNLOCK(&stream->mutex);
1155             error(RtAudioError::DRIVER_ERROR);
1156           }
1157         }
1158         else {
1159           sprintf(message, "RtAudio: ALSA error, current state is %s.",
1160                   snd_pcm_state_name(state));
1161           MUTEX_UNLOCK(&stream->mutex);
1162           error(RtAudioError::DRIVER_ERROR);
1163         }
1164         goto unlock;
1165       }
1166       else {
1167         sprintf(message, "RtAudio: ALSA audio write error for device (%s): %s.",
1168                 devices[stream->device[0]].name, snd_strerror(err));
1169         MUTEX_UNLOCK(&stream->mutex);
1170         error(RtAudioError::DRIVER_ERROR);
1171       }
1172     }
1173   }
1174
1175   if (stream->mode == RECORD || stream->mode == DUPLEX) {
1176
1177     // Setup parameters.
1178     if (stream->doConvertBuffer[1]) {
1179       buffer = stream->deviceBuffer;
1180       channels = stream->nDeviceChannels[1];
1181       format = stream->deviceFormat[1];
1182     }
1183     else {
1184       buffer = stream->userBuffer;
1185       channels = stream->nUserChannels[1];
1186       format = stream->userFormat;
1187     }
1188
1189     // Read samples from device in interleaved/non-interleaved format.
1190     if (stream->deInterleave[1]) {
1191       void *bufs[channels];
1192       size_t offset = stream->bufferSize * formatBytes(format);
1193       for (int i=0; i<channels; i++)
1194         bufs[i] = (void *) (buffer + (i * offset));
1195       err = snd_pcm_readn(stream->handle[1], bufs, stream->bufferSize);
1196     }
1197     else
1198       err = snd_pcm_readi(stream->handle[1], buffer, stream->bufferSize);
1199
1200     if (err < stream->bufferSize) {
1201       // Either an error or underrun occured.
1202       if (err == -EPIPE) {
1203         snd_pcm_state_t state = snd_pcm_state(stream->handle[1]);
1204         if (state == SND_PCM_STATE_XRUN) {
1205           sprintf(message, "RtAudio: ALSA overrun detected.");
1206           error(RtAudioError::WARNING);
1207           err = snd_pcm_prepare(stream->handle[1]);
1208           if (err < 0) {
1209             sprintf(message, "RtAudio: ALSA error preparing handle after overrun: %s.",
1210                     snd_strerror(err));
1211             MUTEX_UNLOCK(&stream->mutex);
1212             error(RtAudioError::DRIVER_ERROR);
1213           }
1214         }
1215         else {
1216           sprintf(message, "RtAudio: ALSA error, current state is %s.",
1217                   snd_pcm_state_name(state));
1218           MUTEX_UNLOCK(&stream->mutex);
1219           error(RtAudioError::DRIVER_ERROR);
1220         }
1221         goto unlock;
1222       }
1223       else {
1224         sprintf(message, "RtAudio: ALSA audio read error for device (%s): %s.",
1225                 devices[stream->device[1]].name, snd_strerror(err));
1226         MUTEX_UNLOCK(&stream->mutex);
1227         error(RtAudioError::DRIVER_ERROR);
1228       }
1229     }
1230
1231     // Do byte swapping if necessary.
1232     if (stream->doByteSwap[1])
1233       byteSwapBuffer(buffer, stream->bufferSize * channels, format);
1234
1235     // Do buffer conversion if necessary.
1236     if (stream->doConvertBuffer[1])
1237       convertStreamBuffer(stream, RECORD);
1238   }
1239
1240  unlock:
1241   MUTEX_UNLOCK(&stream->mutex);
1242
1243   if (stream->usingCallback && stopStream)
1244     this->stopStream(streamID);
1245 }
1246
1247 extern "C" void *callbackHandler(void *ptr)
1248 {
1249   RtAudio *object = thread_info.object;
1250   int stream = thread_info.streamID;
1251   bool *usingCallback = (bool *) ptr;
1252
1253   while ( *usingCallback ) {
1254     pthread_testcancel();
1255     try {
1256       object->tickStream(stream);
1257     }
1258     catch (RtAudioError &exception) {
1259       fprintf(stderr, "\nCallback thread error (%s) ... closing thread.\n\n",
1260               exception.getMessage());
1261       break;
1262     }
1263   }
1264
1265   return 0;
1266 }
1267
1268 //******************** End of __LINUX_ALSA_ *********************//
1269
1270 #elif defined(__LINUX_OSS_)
1271
1272 #include <sys/stat.h>
1273 #include <sys/types.h>
1274 #include <sys/ioctl.h>
1275 #include <unistd.h>
1276 #include <fcntl.h>
1277 #include <sys/soundcard.h>
1278 #include <errno.h>
1279 #include <math.h>
1280
1281 #define DAC_NAME "/dev/dsp"
1282 #define MAX_DEVICES 16
1283 #define MAX_CHANNELS 16
1284
1285 void RtAudio :: initialize(void)
1286 {
1287   // Count cards and devices
1288   nDevices = 0;
1289
1290   // We check /dev/dsp before probing devices.  /dev/dsp is supposed to
1291   // be a link to the "default" audio device, of the form /dev/dsp0,
1292   // /dev/dsp1, etc...  However, I've seen one case where /dev/dsp was a
1293   // real device, so we need to check for that.  Also, sometimes the
1294   // link is to /dev/dspx and other times just dspx.  I'm not sure how
1295   // the latter works, but it does.
1296   char device_name[16];
1297   struct stat dspstat;
1298   int dsplink = -1;
1299   int i = 0;
1300   if (lstat(DAC_NAME, &dspstat) == 0) {
1301     if (S_ISLNK(dspstat.st_mode)) {
1302       i = readlink(DAC_NAME, device_name, sizeof(device_name));
1303       if (i > 0) {
1304         device_name[i] = '\0';
1305         if (i > 8) { // check for "/dev/dspx"
1306           if (!strncmp(DAC_NAME, device_name, 8))
1307             dsplink = atoi(&device_name[8]);
1308         }
1309         else if (i > 3) { // check for "dspx"
1310           if (!strncmp("dsp", device_name, 3))
1311             dsplink = atoi(&device_name[3]);
1312         }
1313       }
1314       else {
1315         sprintf(message, "RtAudio: cannot read value of symbolic link %s.", DAC_NAME);
1316         error(RtAudioError::SYSTEM_ERROR);
1317       }
1318     }
1319   }
1320   else {
1321     sprintf(message, "RtAudio: cannot stat %s.", DAC_NAME);
1322     error(RtAudioError::SYSTEM_ERROR);
1323   }
1324
1325   // The OSS API doesn't provide a routine for determining the number
1326   // of devices.  Thus, we'll just pursue a brute force method.  The
1327   // idea is to start with /dev/dsp(0) and continue with higher device
1328   // numbers until we reach MAX_DSP_DEVICES.  This should tell us how
1329   // many devices we have ... it is not a fullproof scheme, but hopefully
1330   // it will work most of the time.
1331
1332   int fd = 0;
1333   char names[MAX_DEVICES][16];
1334   for (i=-1; i<MAX_DEVICES; i++) {
1335
1336     // Probe /dev/dsp first, since it is supposed to be the default device.
1337     if (i == -1)
1338       sprintf(device_name, "%s", DAC_NAME);
1339     else if (i == dsplink)
1340       continue; // We've aready probed this device via /dev/dsp link ... try next device.
1341     else
1342       sprintf(device_name, "%s%d", DAC_NAME, i);
1343
1344     // First try to open the device for playback, then record mode.
1345     fd = open(device_name, O_WRONLY | O_NONBLOCK);
1346     if (fd == -1) {
1347       // Open device for playback failed ... either busy or doesn't exist.
1348       if (errno != EBUSY && errno != EAGAIN) {
1349         // Try to open for capture
1350         fd = open(device_name, O_RDONLY | O_NONBLOCK);
1351         if (fd == -1) {
1352           // Open device for record failed.
1353           if (errno != EBUSY && errno != EAGAIN)
1354             continue;
1355           else {
1356             sprintf(message, "RtAudio: OSS record device (%s) is busy.", device_name);
1357             error(RtAudioError::WARNING);
1358             // still count it for now
1359           }
1360         }
1361       }
1362       else {
1363         sprintf(message, "RtAudio: OSS playback device (%s) is busy.", device_name);
1364         error(RtAudioError::WARNING);
1365         // still count it for now
1366       }
1367     }
1368
1369     if (fd >= 0) close(fd);
1370     strncpy(names[nDevices], device_name, 16);
1371     nDevices++;
1372   }
1373
1374   if (nDevices == 0) return;
1375
1376   //  Allocate the DEVICE_CONTROL structures.
1377   devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
1378   if (devices == NULL) {
1379     sprintf(message, "RtAudio: memory allocation error!");
1380     error(RtAudioError::MEMORY_ERROR);
1381   }
1382
1383   // Write device ascii identifiers to device control structure and then probe capabilities.
1384   for (i=0; i<nDevices; i++) {
1385     strncpy(devices[i].name, names[i], 16);
1386     probeDeviceInfo(&devices[i]);
1387   }
1388
1389   return;
1390 }
1391
1392 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
1393 {
1394   int i, fd, channels, mask;
1395
1396   // The OSS API doesn't provide a means for probing the capabilities
1397   // of devices.  Thus, we'll just pursue a brute force method.
1398
1399   // First try for playback
1400   fd = open(info->name, O_WRONLY | O_NONBLOCK);
1401   if (fd == -1) {
1402     // Open device failed ... either busy or doesn't exist
1403     if (errno == EBUSY || errno == EAGAIN)
1404       sprintf(message, "RtAudio: OSS playback device (%s) is busy and cannot be probed.",
1405               info->name);
1406     else
1407       sprintf(message, "RtAudio: OSS playback device (%s) open error.", info->name);
1408     error(RtAudioError::WARNING);
1409     goto capture_probe;
1410   }
1411
1412   // We have an open device ... see how many channels it can handle
1413   for (i=MAX_CHANNELS; i>0; i--) {
1414     channels = i;
1415     if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
1416       // This would normally indicate some sort of hardware error, but under ALSA's
1417       // OSS emulation, it sometimes indicates an invalid channel value.  Further,
1418       // the returned channel value is not changed. So, we'll ignore the possible
1419       // hardware error.
1420       continue; // try next channel number
1421     }
1422     // Check to see whether the device supports the requested number of channels
1423     if (channels != i ) continue; // try next channel number
1424     // If here, we found the largest working channel value
1425     break;
1426   }
1427   info->maxOutputChannels = channels;
1428
1429   // Now find the minimum number of channels it can handle
1430   for (i=1; i<=info->maxOutputChannels; i++) {
1431     channels = i;
1432     if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
1433       continue; // try next channel number
1434     // If here, we found the smallest working channel value
1435     break;
1436   }
1437   info->minOutputChannels = channels;
1438   close(fd);
1439
1440  capture_probe:
1441   // Now try for capture
1442   fd = open(info->name, O_RDONLY | O_NONBLOCK);
1443   if (fd == -1) {
1444     // Open device for capture failed ... either busy or doesn't exist
1445     if (errno == EBUSY || errno == EAGAIN)
1446       sprintf(message, "RtAudio: OSS capture device (%s) is busy and cannot be probed.",
1447               info->name);
1448     else
1449       sprintf(message, "RtAudio: OSS capture device (%s) open error.", info->name);
1450     error(RtAudioError::WARNING);
1451     if (info->maxOutputChannels == 0)
1452       // didn't open for playback either ... device invalid
1453       return;
1454     goto probe_parameters;
1455   }
1456
1457   // We have the device open for capture ... see how many channels it can handle
1458   for (i=MAX_CHANNELS; i>0; i--) {
1459     channels = i;
1460     if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
1461       continue; // as above
1462     }
1463     // If here, we found a working channel value
1464     break;
1465   }
1466   info->maxInputChannels = channels;
1467
1468   // Now find the minimum number of channels it can handle
1469   for (i=1; i<=info->maxInputChannels; i++) {
1470     channels = i;
1471     if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
1472       continue; // try next channel number
1473     // If here, we found the smallest working channel value
1474     break;
1475   }
1476   info->minInputChannels = channels;
1477   close(fd);
1478
1479   // If device opens for both playback and capture, we determine the channels.
1480   if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
1481     goto probe_parameters;
1482
1483   fd = open(info->name, O_RDWR | O_NONBLOCK);
1484   if (fd == -1)
1485     goto probe_parameters;
1486
1487   ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
1488   ioctl(fd, SNDCTL_DSP_GETCAPS, &mask);
1489   if (mask & DSP_CAP_DUPLEX) {
1490     info->hasDuplexSupport = true;
1491     // We have the device open for duplex ... see how many channels it can handle
1492     for (i=MAX_CHANNELS; i>0; i--) {
1493       channels = i;
1494       if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
1495         continue; // as above
1496       // If here, we found a working channel value
1497       break;
1498     }
1499     info->maxDuplexChannels = channels;
1500
1501     // Now find the minimum number of channels it can handle
1502     for (i=1; i<=info->maxDuplexChannels; i++) {
1503       channels = i;
1504       if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
1505         continue; // try next channel number
1506       // If here, we found the smallest working channel value
1507       break;
1508     }
1509     info->minDuplexChannels = channels;
1510   }
1511   close(fd);
1512
1513  probe_parameters:
1514   // At this point, we need to figure out the supported data formats
1515   // and sample rates.  We'll proceed by openning the device in the
1516   // direction with the maximum number of channels, or playback if
1517   // they are equal.  This might limit our sample rate options, but so
1518   // be it.
1519
1520   if (info->maxOutputChannels >= info->maxInputChannels) {
1521     fd = open(info->name, O_WRONLY | O_NONBLOCK);
1522     channels = info->maxOutputChannels;
1523   }
1524   else {
1525     fd = open(info->name, O_RDONLY | O_NONBLOCK);
1526     channels = info->maxInputChannels;
1527   }
1528
1529   if (fd == -1) {
1530     // We've got some sort of conflict ... abort
1531     sprintf(message, "RtAudio: OSS device (%s) won't reopen during probe.",
1532             info->name);
1533     error(RtAudioError::WARNING);
1534     return;
1535   }
1536
1537   // We have an open device ... set to maximum channels.
1538   i = channels;
1539   if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
1540     // We've got some sort of conflict ... abort
1541     close(fd);
1542     sprintf(message, "RtAudio: OSS device (%s) won't revert to previous channel setting.",
1543             info->name);
1544     error(RtAudioError::WARNING);
1545     return;
1546   }
1547
1548   if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
1549     close(fd);
1550     sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.",
1551             info->name);
1552     error(RtAudioError::WARNING);
1553     return;
1554   }
1555
1556   // Probe the supported data formats ... we don't care about endian-ness just yet.
1557   int format;
1558   info->nativeFormats = 0;
1559 #if defined (AFMT_S32_BE)
1560   // This format does not seem to be in the 2.4 kernel version of OSS soundcard.h
1561   if (mask & AFMT_S32_BE) {
1562     format = AFMT_S32_BE;
1563     info->nativeFormats |= RTAUDIO_SINT32;
1564   }
1565 #endif
1566 #if defined (AFMT_S32_LE)
1567   /* This format is not in the 2.4.4 kernel version of OSS soundcard.h */
1568   if (mask & AFMT_S32_LE) {
1569     format = AFMT_S32_LE;
1570     info->nativeFormats |= RTAUDIO_SINT32;
1571   }
1572 #endif
1573   if (mask & AFMT_S8) {
1574     format = AFMT_S8;
1575     info->nativeFormats |= RTAUDIO_SINT8;
1576   }
1577   if (mask & AFMT_S16_BE) {
1578     format = AFMT_S16_BE;
1579     info->nativeFormats |= RTAUDIO_SINT16;
1580   }
1581   if (mask & AFMT_S16_LE) {
1582     format = AFMT_S16_LE;
1583     info->nativeFormats |= RTAUDIO_SINT16;
1584   }
1585
1586   // Check that we have at least one supported format
1587   if (info->nativeFormats == 0) {
1588     close(fd);
1589     sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.",
1590             info->name);
1591     error(RtAudioError::WARNING);
1592     return;
1593   }
1594
1595   // Set the format
1596   i = format;
1597   if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1 || format != i) {
1598     close(fd);
1599     sprintf(message, "RtAudio: OSS device (%s) error setting data format.",
1600             info->name);
1601     error(RtAudioError::WARNING);
1602     return;
1603   }
1604
1605   // Probe the supported sample rates ... first get lower limit
1606   int speed = 1;
1607   if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) {
1608     // If we get here, we're probably using an ALSA driver with OSS-emulation,
1609     // which doesn't conform to the OSS specification.  In this case,
1610     // we'll probe our predefined list of sample rates for working values.
1611     info->nSampleRates = 0;
1612     for (i=0; i<MAX_SAMPLE_RATES; i++) {
1613       speed = SAMPLE_RATES[i];
1614       if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) != -1) {
1615         info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
1616         info->nSampleRates++;
1617       }
1618     }
1619     if (info->nSampleRates == 0) {
1620       close(fd);
1621       return;
1622     }
1623     goto finished;
1624   }
1625   info->sampleRates[0] = speed;
1626
1627   // Now get upper limit
1628   speed = 1000000;
1629   if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) {
1630     close(fd);
1631     sprintf(message, "RtAudio: OSS device (%s) error setting sample rate.",
1632             info->name);
1633     error(RtAudioError::WARNING);
1634     return;
1635   }
1636   info->sampleRates[1] = speed;
1637   info->nSampleRates = -1;
1638
1639  finished: // That's all ... close the device and return
1640   close(fd);
1641   info->probed = true;
1642   return;
1643 }
1644
1645 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
1646                                 STREAM_MODE mode, int channels, 
1647                                 int sampleRate, RTAUDIO_FORMAT format,
1648                                 int *bufferSize, int numberOfBuffers)
1649 {
1650   int buffers, buffer_bytes, device_channels, device_format;
1651   int srate, temp, fd;
1652
1653   const char *name = devices[device].name;
1654
1655   if (mode == PLAYBACK)
1656     fd = open(name, O_WRONLY | O_NONBLOCK);
1657   else { // mode == RECORD
1658     if (stream->mode == PLAYBACK && stream->device[0] == device) {
1659       // We just set the same device for playback ... close and reopen for duplex (OSS only).
1660       close(stream->handle[0]);
1661       stream->handle[0] = 0;
1662       // First check that the number previously set channels is the same.
1663       if (stream->nUserChannels[0] != channels) {
1664         sprintf(message, "RtAudio: input/output channels must be equal for OSS duplex device (%s).", name);
1665         goto error;
1666       }
1667       fd = open(name, O_RDWR | O_NONBLOCK);
1668     }
1669     else
1670       fd = open(name, O_RDONLY | O_NONBLOCK);
1671   }
1672
1673   if (fd == -1) {
1674     if (errno == EBUSY || errno == EAGAIN)
1675       sprintf(message, "RtAudio: OSS device (%s) is busy and cannot be opened.",
1676               name);
1677     else
1678       sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name);
1679     goto error;
1680   }
1681
1682   // Now reopen in blocking mode.
1683   close(fd);
1684   if (mode == PLAYBACK)
1685     fd = open(name, O_WRONLY | O_SYNC);
1686   else { // mode == RECORD
1687     if (stream->mode == PLAYBACK && stream->device[0] == device)
1688       fd = open(name, O_RDWR | O_SYNC);
1689     else
1690       fd = open(name, O_RDONLY | O_SYNC);
1691   }
1692
1693   if (fd == -1) {
1694     sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name);
1695     goto error;
1696   }
1697
1698   // Get the sample format mask
1699   int mask;
1700   if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
1701     close(fd);
1702     sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.",
1703             name);
1704     goto error;
1705   }
1706
1707   // Determine how to set the device format.
1708   stream->userFormat = format;
1709   device_format = -1;
1710   stream->doByteSwap[mode] = false;
1711   if (format == RTAUDIO_SINT8) {
1712     if (mask & AFMT_S8) {
1713       device_format = AFMT_S8;
1714       stream->deviceFormat[mode] = RTAUDIO_SINT8;
1715     }
1716   }
1717   else if (format == RTAUDIO_SINT16) {
1718     if (mask & AFMT_S16_NE) {
1719       device_format = AFMT_S16_NE;
1720       stream->deviceFormat[mode] = RTAUDIO_SINT16;
1721     }
1722 #if BYTE_ORDER == LITTLE_ENDIAN
1723     else if (mask & AFMT_S16_BE) {
1724       device_format = AFMT_S16_BE;
1725       stream->deviceFormat[mode] = RTAUDIO_SINT16;
1726       stream->doByteSwap[mode] = true;
1727     }
1728 #else
1729     else if (mask & AFMT_S16_LE) {
1730       device_format = AFMT_S16_LE;
1731       stream->deviceFormat[mode] = RTAUDIO_SINT16;
1732       stream->doByteSwap[mode] = true;
1733     }
1734 #endif
1735   }
1736 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
1737   else if (format == RTAUDIO_SINT32) {
1738     if (mask & AFMT_S32_NE) {
1739       device_format = AFMT_S32_NE;
1740       stream->deviceFormat[mode] = RTAUDIO_SINT32;
1741     }
1742 #if BYTE_ORDER == LITTLE_ENDIAN
1743     else if (mask & AFMT_S32_BE) {
1744       device_format = AFMT_S32_BE;
1745       stream->deviceFormat[mode] = RTAUDIO_SINT32;
1746       stream->doByteSwap[mode] = true;
1747     }
1748 #else
1749     else if (mask & AFMT_S32_LE) {
1750       device_format = AFMT_S32_LE;
1751       stream->deviceFormat[mode] = RTAUDIO_SINT32;
1752       stream->doByteSwap[mode] = true;
1753     }
1754 #endif
1755   }
1756 #endif
1757
1758   if (device_format == -1) {
1759     // The user requested format is not natively supported by the device.
1760     if (mask & AFMT_S16_NE) {
1761       device_format = AFMT_S16_NE;
1762       stream->deviceFormat[mode] = RTAUDIO_SINT16;
1763     }
1764 #if BYTE_ORDER == LITTLE_ENDIAN
1765     else if (mask & AFMT_S16_BE) {
1766       device_format = AFMT_S16_BE;
1767       stream->deviceFormat[mode] = RTAUDIO_SINT16;
1768       stream->doByteSwap[mode] = true;
1769     }
1770 #else
1771     else if (mask & AFMT_S16_LE) {
1772       device_format = AFMT_S16_LE;
1773       stream->deviceFormat[mode] = RTAUDIO_SINT16;
1774       stream->doByteSwap[mode] = true;
1775     }
1776 #endif
1777 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
1778     else if (mask & AFMT_S32_NE) {
1779       device_format = AFMT_S32_NE;
1780       stream->deviceFormat[mode] = RTAUDIO_SINT32;
1781     }
1782 #if BYTE_ORDER == LITTLE_ENDIAN
1783     else if (mask & AFMT_S32_BE) {
1784       device_format = AFMT_S32_BE;
1785       stream->deviceFormat[mode] = RTAUDIO_SINT32;
1786       stream->doByteSwap[mode] = true;
1787     }
1788 #else
1789     else if (mask & AFMT_S32_LE) {
1790       device_format = AFMT_S32_LE;
1791       stream->deviceFormat[mode] = RTAUDIO_SINT32;
1792       stream->doByteSwap[mode] = true;
1793     }
1794 #endif
1795 #endif
1796     else if (mask & AFMT_S8) {
1797       device_format = AFMT_S8;
1798       stream->deviceFormat[mode] = RTAUDIO_SINT8;
1799     }
1800   }
1801
1802   if (stream->deviceFormat[mode] == 0) {
1803     // This really shouldn't happen ...
1804     close(fd);
1805     sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.",
1806             name);
1807     goto error;
1808   }
1809
1810   // Determine the number of channels for this device.  Note that the
1811   // channel value requested by the user might be < min_X_Channels.
1812   stream->nUserChannels[mode] = channels;
1813   device_channels = channels;
1814   if (mode == PLAYBACK) {
1815     if (channels < devices[device].minOutputChannels)
1816       device_channels = devices[device].minOutputChannels;
1817   }
1818   else { // mode == RECORD
1819     if (stream->mode == PLAYBACK && stream->device[0] == device) {
1820       // We're doing duplex setup here.
1821       if (channels < devices[device].minDuplexChannels)
1822         device_channels = devices[device].minDuplexChannels;
1823     }
1824     else {
1825       if (channels < devices[device].minInputChannels)
1826         device_channels = devices[device].minInputChannels;
1827     }
1828   }
1829   stream->nDeviceChannels[mode] = device_channels;
1830
1831   // Attempt to set the buffer size.  According to OSS, the minimum
1832   // number of buffers is two.  The supposed minimum buffer size is 16
1833   // bytes, so that will be our lower bound.  The argument to this
1834   // call is in the form 0xMMMMSSSS (hex), where the buffer size (in
1835   // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM.
1836   // We'll check the actual value used near the end of the setup
1837   // procedure.
1838   buffer_bytes = *bufferSize * formatBytes(stream->deviceFormat[mode]) * device_channels;
1839   if (buffer_bytes < 16) buffer_bytes = 16;
1840   buffers = numberOfBuffers;
1841   if (buffers < 2) buffers = 2;
1842   temp = ((int) buffers << 16) + (int)(log10((double)buffer_bytes)/log10(2.0));
1843   if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &temp)) {
1844     close(fd);
1845     sprintf(message, "RtAudio: OSS error setting fragment size for device (%s).",
1846             name);
1847     goto error;
1848   }
1849   stream->nBuffers = buffers;
1850
1851   // Set the data format.
1852   temp = device_format;
1853   if (ioctl(fd, SNDCTL_DSP_SETFMT, &device_format) == -1 || device_format != temp) {
1854     close(fd);
1855     sprintf(message, "RtAudio: OSS error setting data format for device (%s).",
1856             name);
1857     goto error;
1858   }
1859
1860   // Set the number of channels.
1861   temp = device_channels;
1862   if (ioctl(fd, SNDCTL_DSP_CHANNELS, &device_channels) == -1 || device_channels != temp) {
1863     close(fd);
1864     sprintf(message, "RtAudio: OSS error setting %d channels on device (%s).",
1865             temp, name);
1866     goto error;
1867   }
1868
1869   // Set the sample rate.
1870   srate = sampleRate;
1871   temp = srate;
1872   if (ioctl(fd, SNDCTL_DSP_SPEED, &srate) == -1) {
1873     close(fd);
1874     sprintf(message, "RtAudio: OSS error setting sample rate = %d on device (%s).",
1875             temp, name);
1876     goto error;
1877   }
1878
1879   // Verify the sample rate setup worked.
1880   if (abs(srate - temp) > 100) {
1881     close(fd);
1882     sprintf(message, "RtAudio: OSS error ... audio device (%s) doesn't support sample rate of %d.",
1883             name, temp);
1884     goto error;
1885   }
1886   stream->sampleRate = sampleRate;
1887
1888   if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &buffer_bytes) == -1) {
1889     close(fd);
1890     sprintf(message, "RtAudio: OSS error getting buffer size for device (%s).",
1891             name);
1892     goto error;
1893   }
1894
1895   // Save buffer size (in sample frames).
1896   *bufferSize = buffer_bytes / (formatBytes(stream->deviceFormat[mode]) * device_channels);
1897   stream->bufferSize = *bufferSize;
1898
1899   if (mode == RECORD && stream->mode == PLAYBACK &&
1900       stream->device[0] == device) {
1901     // We're doing duplex setup here.
1902     stream->deviceFormat[0] = stream->deviceFormat[1];
1903     stream->nDeviceChannels[0] = device_channels;
1904   }
1905
1906   // Set flags for buffer conversion
1907   stream->doConvertBuffer[mode] = false;
1908   if (stream->userFormat != stream->deviceFormat[mode])
1909     stream->doConvertBuffer[mode] = true;
1910   if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
1911     stream->doConvertBuffer[mode] = true;
1912
1913   // Allocate necessary internal buffers
1914   if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
1915
1916     long buffer_bytes;
1917     if (stream->nUserChannels[0] >= stream->nUserChannels[1])
1918       buffer_bytes = stream->nUserChannels[0];
1919     else
1920       buffer_bytes = stream->nUserChannels[1];
1921
1922     buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
1923     if (stream->userBuffer) free(stream->userBuffer);
1924     stream->userBuffer = (char *) calloc(buffer_bytes, 1);
1925     if (stream->userBuffer == NULL) {
1926       close(fd);
1927       sprintf(message, "RtAudio: OSS error allocating user buffer memory (%s).",
1928               name);
1929       goto error;
1930     }
1931   }
1932
1933   if ( stream->doConvertBuffer[mode] ) {
1934
1935     long buffer_bytes;
1936     bool makeBuffer = true;
1937     if ( mode == PLAYBACK )
1938       buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1939     else { // mode == RECORD
1940       buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
1941       if ( stream->mode == PLAYBACK ) {
1942         long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1943         if ( buffer_bytes > bytes_out )
1944           buffer_bytes = (buffer_bytes > bytes_out) ? buffer_bytes : bytes_out;
1945         else
1946           makeBuffer = false;
1947       }
1948     }
1949
1950     if ( makeBuffer ) {
1951       buffer_bytes *= *bufferSize;
1952       if (stream->deviceBuffer) free(stream->deviceBuffer);
1953       stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
1954       if (stream->deviceBuffer == NULL) {
1955         close(fd);
1956         free(stream->userBuffer);
1957         sprintf(message, "RtAudio: OSS error allocating device buffer memory (%s).",
1958                 name);
1959         goto error;
1960       }
1961     }
1962   }
1963
1964   stream->device[mode] = device;
1965   stream->handle[mode] = fd;
1966   stream->state = STREAM_STOPPED;
1967   if ( stream->mode == PLAYBACK && mode == RECORD ) {
1968     stream->mode = DUPLEX;
1969     if (stream->device[0] == device)
1970       stream->handle[0] = fd;
1971   }
1972   else
1973     stream->mode = mode;
1974
1975   return SUCCESS;
1976
1977  error:
1978   if (stream->handle[0]) {
1979     close(stream->handle[0]);
1980     stream->handle[0] = 0;
1981   }
1982   error(RtAudioError::WARNING);
1983   return FAILURE;
1984 }
1985
1986 void RtAudio :: cancelStreamCallback(int streamID)
1987 {
1988   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
1989
1990   if (stream->usingCallback) {
1991     stream->usingCallback = false;
1992     pthread_cancel(stream->thread);
1993     pthread_join(stream->thread, NULL);
1994     stream->thread = 0;
1995     stream->callback = NULL;
1996     stream->userData = NULL;
1997   }
1998 }
1999
2000 void RtAudio :: closeStream(int streamID)
2001 {
2002   // We don't want an exception to be thrown here because this
2003   // function is called by our class destructor.  So, do our own
2004   // streamID check.
2005   if ( streams.find( streamID ) == streams.end() ) {
2006     sprintf(message, "RtAudio: invalid stream identifier!");
2007     error(RtAudioError::WARNING);
2008     return;
2009   }
2010
2011   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamID];
2012
2013   if (stream->usingCallback) {
2014     pthread_cancel(stream->thread);
2015     pthread_join(stream->thread, NULL);
2016   }
2017
2018   if (stream->state == STREAM_RUNNING) {
2019     if (stream->mode == PLAYBACK || stream->mode == DUPLEX)
2020       ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0);
2021     if (stream->mode == RECORD || stream->mode == DUPLEX)
2022       ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0);
2023   }
2024
2025   pthread_mutex_destroy(&stream->mutex);
2026
2027   if (stream->handle[0])
2028     close(stream->handle[0]);
2029
2030   if (stream->handle[1])
2031     close(stream->handle[1]);
2032
2033   if (stream->userBuffer)
2034     free(stream->userBuffer);
2035
2036   if (stream->deviceBuffer)
2037     free(stream->deviceBuffer);
2038
2039   free(stream);
2040   streams.erase(streamID);
2041 }
2042
2043 void RtAudio :: startStream(int streamID)
2044 {
2045   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
2046
2047   stream->state = STREAM_RUNNING;
2048
2049   // No need to do anything else here ... OSS automatically starts when fed samples.
2050 }
2051
2052 void RtAudio :: stopStream(int streamID)
2053 {
2054   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
2055
2056   MUTEX_LOCK(&stream->mutex);
2057
2058   if (stream->state == STREAM_STOPPED)
2059     goto unlock;
2060
2061   int err;
2062   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
2063     err = ioctl(stream->handle[0], SNDCTL_DSP_SYNC, 0);
2064     if (err < -1) {
2065       sprintf(message, "RtAudio: OSS error stopping device (%s).",
2066               devices[stream->device[0]].name);
2067       error(RtAudioError::DRIVER_ERROR);
2068     }
2069   }
2070   else {
2071     err = ioctl(stream->handle[1], SNDCTL_DSP_SYNC, 0);
2072     if (err < -1) {
2073       sprintf(message, "RtAudio: OSS error stopping device (%s).",
2074               devices[stream->device[1]].name);
2075       error(RtAudioError::DRIVER_ERROR);
2076     }
2077   }
2078   stream->state = STREAM_STOPPED;
2079
2080  unlock:
2081   MUTEX_UNLOCK(&stream->mutex);
2082 }
2083
2084 void RtAudio :: abortStream(int streamID)
2085 {
2086   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
2087
2088   MUTEX_LOCK(&stream->mutex);
2089
2090   if (stream->state == STREAM_STOPPED)
2091     goto unlock;
2092
2093   int err;
2094   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
2095     err = ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0);
2096     if (err < -1) {
2097       sprintf(message, "RtAudio: OSS error aborting device (%s).",
2098               devices[stream->device[0]].name);
2099       error(RtAudioError::DRIVER_ERROR);
2100     }
2101   }
2102   else {
2103     err = ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0);
2104     if (err < -1) {
2105       sprintf(message, "RtAudio: OSS error aborting device (%s).",
2106               devices[stream->device[1]].name);
2107       error(RtAudioError::DRIVER_ERROR);
2108     }
2109   }
2110   stream->state = STREAM_STOPPED;
2111
2112  unlock:
2113   MUTEX_UNLOCK(&stream->mutex);
2114 }
2115
2116 int RtAudio :: streamWillBlock(int streamID)
2117 {
2118   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
2119
2120   MUTEX_LOCK(&stream->mutex);
2121
2122   int bytes, channels = 0, frames = 0;
2123   if (stream->state == STREAM_STOPPED)
2124     goto unlock;
2125
2126   audio_buf_info info;
2127   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
2128     ioctl(stream->handle[0], SNDCTL_DSP_GETOSPACE, &info);
2129     bytes = info.bytes;
2130     channels = stream->nDeviceChannels[0];
2131   }
2132
2133   if (stream->mode == RECORD || stream->mode == DUPLEX) {
2134     ioctl(stream->handle[1], SNDCTL_DSP_GETISPACE, &info);
2135     if (stream->mode == DUPLEX ) {
2136       bytes = (bytes < info.bytes) ? bytes : info.bytes;
2137       channels = stream->nDeviceChannels[0];
2138     }
2139     else {
2140       bytes = info.bytes;
2141       channels = stream->nDeviceChannels[1];
2142     }
2143   }
2144
2145   frames = (int) (bytes / (channels * formatBytes(stream->deviceFormat[0])));
2146   frames -= stream->bufferSize;
2147   if (frames < 0) frames = 0;
2148
2149  unlock:
2150   MUTEX_UNLOCK(&stream->mutex);
2151   return frames;
2152 }
2153
2154 void RtAudio :: tickStream(int streamID)
2155 {
2156   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
2157
2158   int stopStream = 0;
2159   if (stream->state == STREAM_STOPPED) {
2160     if (stream->usingCallback) usleep(50000); // sleep 50 milliseconds
2161     return;
2162   }
2163   else if (stream->usingCallback) {
2164     stopStream = stream->callback(stream->userBuffer, stream->bufferSize, stream->userData);
2165   }
2166
2167   MUTEX_LOCK(&stream->mutex);
2168
2169   // The state might change while waiting on a mutex.
2170   if (stream->state == STREAM_STOPPED)
2171     goto unlock;
2172
2173   int result;
2174   char *buffer;
2175   int samples;
2176   RTAUDIO_FORMAT format;
2177   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
2178
2179     // Setup parameters and do buffer conversion if necessary.
2180     if (stream->doConvertBuffer[0]) {
2181       convertStreamBuffer(stream, PLAYBACK);
2182       buffer = stream->deviceBuffer;
2183       samples = stream->bufferSize * stream->nDeviceChannels[0];
2184       format = stream->deviceFormat[0];
2185     }
2186     else {
2187       buffer = stream->userBuffer;
2188       samples = stream->bufferSize * stream->nUserChannels[0];
2189       format = stream->userFormat;
2190     }
2191
2192     // Do byte swapping if necessary.
2193     if (stream->doByteSwap[0])
2194       byteSwapBuffer(buffer, samples, format);
2195
2196     // Write samples to device.
2197     result = write(stream->handle[0], buffer, samples * formatBytes(format));
2198
2199     if (result == -1) {
2200       // This could be an underrun, but the basic OSS API doesn't provide a means for determining that.
2201       sprintf(message, "RtAudio: OSS audio write error for device (%s).",
2202               devices[stream->device[0]].name);
2203       error(RtAudioError::DRIVER_ERROR);
2204     }
2205   }
2206
2207   if (stream->mode == RECORD || stream->mode == DUPLEX) {
2208
2209     // Setup parameters.
2210     if (stream->doConvertBuffer[1]) {
2211       buffer = stream->deviceBuffer;
2212       samples = stream->bufferSize * stream->nDeviceChannels[1];
2213       format = stream->deviceFormat[1];
2214     }
2215     else {
2216       buffer = stream->userBuffer;
2217       samples = stream->bufferSize * stream->nUserChannels[1];
2218       format = stream->userFormat;
2219     }
2220
2221     // Read samples from device.
2222     result = read(stream->handle[1], buffer, samples * formatBytes(format));
2223
2224     if (result == -1) {
2225       // This could be an overrun, but the basic OSS API doesn't provide a means for determining that.
2226       sprintf(message, "RtAudio: OSS audio read error for device (%s).",
2227               devices[stream->device[1]].name);
2228       error(RtAudioError::DRIVER_ERROR);
2229     }
2230
2231     // Do byte swapping if necessary.
2232     if (stream->doByteSwap[1])
2233       byteSwapBuffer(buffer, samples, format);
2234
2235     // Do buffer conversion if necessary.
2236     if (stream->doConvertBuffer[1])
2237       convertStreamBuffer(stream, RECORD);
2238   }
2239
2240  unlock:
2241   MUTEX_UNLOCK(&stream->mutex);
2242
2243   if (stream->usingCallback && stopStream)
2244     this->stopStream(streamID);
2245 }
2246
2247 extern "C" void *callbackHandler(void *ptr)
2248 {
2249   RtAudio *object = thread_info.object;
2250   int stream = thread_info.streamID;
2251   bool *usingCallback = (bool *) ptr;
2252
2253   while ( *usingCallback ) {
2254     pthread_testcancel();
2255     try {
2256       object->tickStream(stream);
2257     }
2258     catch (RtAudioError &exception) {
2259       fprintf(stderr, "\nCallback thread error (%s) ... closing thread.\n\n",
2260               exception.getMessage());
2261       break;
2262     }
2263   }
2264
2265   return 0;
2266 }
2267
2268 //******************** End of __LINUX_OSS_ *********************//
2269
2270 #elif defined(__WINDOWS_DS_) // Windows DirectSound API
2271
2272 #include <dsound.h>
2273
2274 // Declarations for utility functions, callbacks, and structures
2275 // specific to the DirectSound implementation.
2276 static bool CALLBACK deviceCountCallback(LPGUID lpguid,
2277                                          LPCSTR lpcstrDescription,
2278                                          LPCSTR lpcstrModule,
2279                                          LPVOID lpContext);
2280
2281 static bool CALLBACK deviceInfoCallback(LPGUID lpguid,
2282                                         LPCSTR lpcstrDescription,
2283                                         LPCSTR lpcstrModule,
2284                                         LPVOID lpContext);
2285
2286 static char* getErrorString(int code);
2287
2288 struct enum_info {
2289   char name[64];
2290   LPGUID id;
2291   bool isInput;
2292   bool isValid;
2293 };
2294
2295 // RtAudio methods for DirectSound implementation.
2296 void RtAudio :: initialize(void)
2297 {
2298   int i, ins = 0, outs = 0, count = 0;
2299   int index = 0;
2300   HRESULT result;
2301   nDevices = 0;
2302
2303   // Count DirectSound devices.
2304   result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &outs);
2305   if ( FAILED(result) ) {
2306     sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.",
2307             getErrorString(result));
2308     error(RtAudioError::DRIVER_ERROR);
2309   }
2310
2311   // Count DirectSoundCapture devices.
2312   result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &ins);
2313   if ( FAILED(result) ) {
2314     sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.",
2315             getErrorString(result));
2316     error(RtAudioError::DRIVER_ERROR);
2317   }
2318
2319   count = ins + outs;
2320   if (count == 0) return;
2321
2322   std::vector<enum_info> info(count);
2323   for (i=0; i<count; i++) {
2324     info[i].name[0] = '\0';
2325     if (i < outs) info[i].isInput = false;
2326     else info[i].isInput = true;
2327   }
2328
2329   // Get playback device info and check capabilities.
2330   result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]);
2331   if ( FAILED(result) ) {
2332     sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.",
2333             getErrorString(result));
2334     error(RtAudioError::DRIVER_ERROR);
2335   }
2336
2337   // Get capture device info and check capabilities.
2338   result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]);
2339   if ( FAILED(result) ) {
2340     sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.",
2341             getErrorString(result));
2342     error(RtAudioError::DRIVER_ERROR);
2343   }
2344
2345   // Parse the devices and check validity.  Devices are considered
2346   // invalid if they cannot be opened, they report no supported data
2347   // formats, or they report < 1 supported channels.
2348   for (i=0; i<count; i++) {
2349     if (info[i].isValid && info[i].id == NULL ) // default device
2350       nDevices++;
2351   }
2352
2353   // We group the default input and output devices together (as one
2354   // device) .
2355   if (nDevices > 0) {
2356     nDevices = 1;
2357     index = 1;
2358   }
2359
2360   // Non-default devices are listed separately.
2361   for (i=0; i<count; i++) {
2362     if (info[i].isValid && info[i].id != NULL )
2363       nDevices++;
2364   }
2365
2366   if (nDevices == 0) return;
2367
2368   //  Allocate the RTAUDIO_DEVICE structures.
2369   devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
2370   if (devices == NULL) {
2371     sprintf(message, "RtAudio: memory allocation error!");
2372     error(RtAudioError::MEMORY_ERROR);
2373   }
2374
2375   // Initialize the GUIDs to NULL for later validation.
2376   for (i=0; i<nDevices; i++) {
2377     devices[i].id[0] = NULL;
2378     devices[i].id[1] = NULL;
2379   }
2380
2381   // Rename the default device(s).
2382   if (index)
2383     strcpy(devices[0].name, "Default Input/Output Devices");
2384
2385   // Copy the names and GUIDs to our devices structures.
2386   for (i=0; i<count; i++) {
2387     if (info[i].isValid && info[i].id != NULL ) {
2388       strncpy(devices[index].name, info[i].name, 64);
2389       if (info[i].isInput)
2390         devices[index].id[1] = info[i].id;
2391       else
2392         devices[index].id[0] = info[i].id;
2393       index++;
2394     }
2395   }
2396
2397   for (i=0;i<nDevices; i++)
2398     probeDeviceInfo(&devices[i]);
2399
2400   return;
2401 }
2402
2403 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
2404 {
2405   HRESULT result;
2406
2407   // Get the device index so that we can check the device handle.
2408   int index;
2409   for (index=0; index<nDevices; index++)
2410     if ( info == &devices[index] ) break;
2411
2412   if ( index >= nDevices ) {
2413     sprintf(message, "RtAudio: device (%s) indexing error in DirectSound probeDeviceInfo().",
2414             info->name);
2415     error(RtAudioError::WARNING);
2416     return;
2417   }
2418
2419   // Do capture probe first.  If this is not the default device (index
2420   // = 0) _and_ GUID = NULL, then the capture handle is invalid.
2421   if ( index != 0 && info->id[1] == NULL )
2422     goto playback_probe;
2423
2424   LPDIRECTSOUNDCAPTURE  input;
2425   result = DirectSoundCaptureCreate( info->id[0], &input, NULL );
2426   if ( FAILED(result) ) {
2427     sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.",
2428             info->name, getErrorString(result));
2429     error(RtAudioError::WARNING);
2430     goto playback_probe;
2431   }
2432
2433   DSCCAPS in_caps;
2434   in_caps.dwSize = sizeof(in_caps);
2435   result = input->GetCaps( &in_caps );
2436   if ( FAILED(result) ) {
2437     input->Release();
2438     sprintf(message, "RtAudio: Could not get DirectSound capture capabilities (%s): %s.",
2439             info->name, getErrorString(result));
2440     error(RtAudioError::WARNING);
2441     goto playback_probe;
2442   }
2443
2444   // Get input channel information.
2445   info->minInputChannels = 1;
2446   info->maxInputChannels = in_caps.dwChannels;
2447
2448   // Get sample rate and format information.
2449   if( in_caps.dwChannels == 2 ) {
2450     if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->nativeFormats |= RTAUDIO_SINT16;
2451     if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->nativeFormats |= RTAUDIO_SINT16;
2452     if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->nativeFormats |= RTAUDIO_SINT16;
2453     if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->nativeFormats |= RTAUDIO_SINT8;
2454     if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->nativeFormats |= RTAUDIO_SINT8;
2455     if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->nativeFormats |= RTAUDIO_SINT8;
2456
2457     if ( info->nativeFormats & RTAUDIO_SINT16 ) {
2458       if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->sampleRates[info->nSampleRates++] = 11025;
2459       if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->sampleRates[info->nSampleRates++] = 22050;
2460       if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->sampleRates[info->nSampleRates++] = 44100;
2461     }
2462     else if ( info->nativeFormats & RTAUDIO_SINT8 ) {
2463       if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->sampleRates[info->nSampleRates++] = 11025;
2464       if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->sampleRates[info->nSampleRates++] = 22050;
2465       if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->sampleRates[info->nSampleRates++] = 44100;
2466     }
2467   }
2468   else if ( in_caps.dwChannels == 1 ) {
2469     if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->nativeFormats |= RTAUDIO_SINT16;
2470     if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->nativeFormats |= RTAUDIO_SINT16;
2471     if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->nativeFormats |= RTAUDIO_SINT16;
2472     if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->nativeFormats |= RTAUDIO_SINT8;
2473     if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->nativeFormats |= RTAUDIO_SINT8;
2474     if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->nativeFormats |= RTAUDIO_SINT8;
2475
2476     if ( info->nativeFormats & RTAUDIO_SINT16 ) {
2477       if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->sampleRates[info->nSampleRates++] = 11025;
2478       if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->sampleRates[info->nSampleRates++] = 22050;
2479       if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->sampleRates[info->nSampleRates++] = 44100;
2480     }
2481     else if ( info->nativeFormats & RTAUDIO_SINT8 ) {
2482       if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->sampleRates[info->nSampleRates++] = 11025;
2483       if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->sampleRates[info->nSampleRates++] = 22050;
2484       if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->sampleRates[info->nSampleRates++] = 44100;
2485     }
2486   }
2487   else info->minInputChannels = 0; // technically, this would be an error
2488
2489   input->Release();
2490
2491  playback_probe:
2492   LPDIRECTSOUND  output;
2493   DSCAPS out_caps;
2494
2495   // Now do playback probe.  If this is not the default device (index
2496   // = 0) _and_ GUID = NULL, then the playback handle is invalid.
2497   if ( index != 0 && info->id[0] == NULL )
2498     goto check_parameters;
2499
2500   result = DirectSoundCreate( info->id[0], &output, NULL );
2501   if ( FAILED(result) ) {
2502     sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.",
2503             info->name, getErrorString(result));
2504     error(RtAudioError::WARNING);
2505     goto check_parameters;
2506   }
2507
2508   out_caps.dwSize = sizeof(out_caps);
2509   result = output->GetCaps( &out_caps );
2510   if ( FAILED(result) ) {
2511     output->Release();
2512     sprintf(message, "RtAudio: Could not get DirectSound playback capabilities (%s): %s.",
2513             info->name, getErrorString(result));
2514     error(RtAudioError::WARNING);
2515     goto check_parameters;
2516   }
2517
2518   // Get output channel information.
2519   info->minOutputChannels = 1;
2520   info->maxOutputChannels = ( out_caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
2521
2522   // Get sample rate information.  Use capture device rate information
2523   // if it exists.
2524   if ( info->nSampleRates == 0 ) {
2525     info->sampleRates[0] = (int) out_caps.dwMinSecondarySampleRate;
2526     info->sampleRates[1] = (int) out_caps.dwMaxSecondarySampleRate;
2527     if ( out_caps.dwFlags & DSCAPS_CONTINUOUSRATE )
2528       info->nSampleRates = -1;
2529     else if ( out_caps.dwMinSecondarySampleRate == out_caps.dwMaxSecondarySampleRate ) {
2530       if ( out_caps.dwMinSecondarySampleRate == 0 ) {
2531         // This is a bogus driver report ... fake the range and cross
2532         // your fingers.
2533         info->sampleRates[0] = 11025;
2534                                 info->sampleRates[1] = 48000;
2535         info->nSampleRates = -1; /* continuous range */
2536         sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using defaults (%s).",
2537                 info->name);
2538         error(RtAudioError::WARNING);
2539       }
2540       else {
2541         info->nSampleRates = 1;
2542                         }
2543     }
2544     else if ( (out_caps.dwMinSecondarySampleRate < 1000.0) &&
2545               (out_caps.dwMaxSecondarySampleRate > 50000.0) ) {
2546       // This is a bogus driver report ... support for only two
2547       // distant rates.  We'll assume this is a range.
2548       info->nSampleRates = -1;
2549       sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using range (%s).",
2550               info->name);
2551       error(RtAudioError::WARNING);
2552     }
2553     else info->nSampleRates = 2;
2554   }
2555   else {
2556     // Check input rates against output rate range
2557     for ( int i=info->nSampleRates-1; i>=0; i-- ) {
2558       if ( info->sampleRates[i] <= out_caps.dwMaxSecondarySampleRate )
2559         break;
2560       info->nSampleRates--;
2561     }
2562     while ( info->sampleRates[0] < out_caps.dwMinSecondarySampleRate ) {
2563       info->nSampleRates--;
2564       for ( int i=0; i<info->nSampleRates; i++)
2565         info->sampleRates[i] = info->sampleRates[i+1];
2566       if ( info->nSampleRates <= 0 ) break;
2567     }
2568   }
2569
2570   // Get format information.
2571   if ( out_caps.dwFlags & DSCAPS_PRIMARY16BIT ) info->nativeFormats |= RTAUDIO_SINT16;
2572   if ( out_caps.dwFlags & DSCAPS_PRIMARY8BIT ) info->nativeFormats |= RTAUDIO_SINT8;
2573
2574   output->Release();
2575
2576  check_parameters:
2577   if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 )
2578     return;
2579   if ( info->nSampleRates == 0 || info->nativeFormats == 0 )
2580     return;
2581
2582   // Determine duplex status.
2583   if (info->maxInputChannels < info->maxOutputChannels)
2584     info->maxDuplexChannels = info->maxInputChannels;
2585   else
2586     info->maxDuplexChannels = info->maxOutputChannels;
2587   if (info->minInputChannels < info->minOutputChannels)
2588     info->minDuplexChannels = info->minInputChannels;
2589   else
2590     info->minDuplexChannels = info->minOutputChannels;
2591
2592   if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true;
2593   else info->hasDuplexSupport = false;
2594
2595   info->probed = true;
2596
2597   return;
2598 }
2599
2600 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
2601                                 STREAM_MODE mode, int channels, 
2602                                 int sampleRate, RTAUDIO_FORMAT format,
2603                                 int *bufferSize, int numberOfBuffers)
2604 {
2605   HRESULT result;
2606   HWND hWnd = GetForegroundWindow();
2607   // According to a note in PortAudio, using GetDesktopWindow()
2608   // instead of GetForegroundWindow() is supposed to avoid problems
2609   // that occur when the application's window is not the foreground
2610   // window.  Also, if the application window closes before the
2611   // DirectSound buffer, DirectSound can crash.  However, for console
2612   // applications, no sound was produced when using GetDesktopWindow().
2613   long buffer_size;
2614   LPVOID audioPtr;
2615   DWORD dataLen;
2616   int nBuffers;
2617
2618   // Check the numberOfBuffers parameter and limit the lowest value to
2619   // two.  This is a judgement call and a value of two is probably too
2620   // low for capture, but it should work for playback.
2621   if (numberOfBuffers < 2)
2622     nBuffers = 2;
2623   else
2624     nBuffers = numberOfBuffers;
2625
2626   // Define the wave format structure (16-bit PCM, srate, channels)
2627   WAVEFORMATEX waveFormat;
2628   ZeroMemory(&waveFormat, sizeof(WAVEFORMATEX));
2629   waveFormat.wFormatTag = WAVE_FORMAT_PCM;
2630   waveFormat.nChannels = channels;
2631   waveFormat.nSamplesPerSec = (unsigned long) sampleRate;
2632
2633   // Determine the data format.
2634   if ( devices[device].nativeFormats ) { // 8-bit and/or 16-bit support
2635     if ( format == RTAUDIO_SINT8 ) {
2636       if ( devices[device].nativeFormats & RTAUDIO_SINT8 )
2637         waveFormat.wBitsPerSample = 8;
2638       else
2639         waveFormat.wBitsPerSample = 16;
2640     }
2641     else {
2642       if ( devices[device].nativeFormats & RTAUDIO_SINT16 )
2643         waveFormat.wBitsPerSample = 16;
2644       else
2645         waveFormat.wBitsPerSample = 8;
2646     }
2647   }
2648   else {
2649     sprintf(message, "RtAudio: no reported data formats for DirectSound device (%s).",
2650             devices[device].name);
2651     error(RtAudioError::WARNING);
2652     return FAILURE;
2653   }
2654
2655   waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
2656   waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
2657
2658   if ( mode == PLAYBACK ) {
2659
2660     LPGUID id = devices[device].id[0];
2661     LPDIRECTSOUND  object;
2662     LPDIRECTSOUNDBUFFER buffer;
2663     DSBUFFERDESC bufferDescription;
2664     
2665     result = DirectSoundCreate( id, &object, NULL );
2666     if ( FAILED(result) ) {
2667       sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.",
2668               devices[device].name, getErrorString(result));
2669       error(RtAudioError::WARNING);
2670       return FAILURE;
2671     }
2672
2673     // Set cooperative level to DSSCL_EXCLUSIVE
2674     result = object->SetCooperativeLevel(hWnd, DSSCL_EXCLUSIVE);
2675     if ( FAILED(result) ) {
2676       object->Release();
2677       sprintf(message, "RtAudio: Unable to set DirectSound cooperative level (%s): %s.",
2678               devices[device].name, getErrorString(result));
2679       error(RtAudioError::WARNING);
2680       return FAILURE;
2681     }
2682
2683     // Even though we will write to the secondary buffer, we need to
2684     // access the primary buffer to set the correct output format.
2685     // The default is 8-bit, 22 kHz!
2686     // Setup the DS primary buffer description.
2687     ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
2688     bufferDescription.dwSize = sizeof(DSBUFFERDESC);
2689     bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
2690     // Obtain the primary buffer
2691     result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
2692     if ( FAILED(result) ) {
2693       object->Release();
2694       sprintf(message, "RtAudio: Unable to access DS primary buffer (%s): %s.",
2695               devices[device].name, getErrorString(result));
2696       error(RtAudioError::WARNING);
2697       return FAILURE;
2698     }
2699
2700     // Set the primary DS buffer sound format.
2701     result = buffer->SetFormat(&waveFormat);
2702     if ( FAILED(result) ) {
2703       object->Release();
2704       sprintf(message, "RtAudio: Unable to set DS primary buffer format (%s): %s.",
2705               devices[device].name, getErrorString(result));
2706       error(RtAudioError::WARNING);
2707       return FAILURE;
2708     }
2709
2710     // Setup the secondary DS buffer description.
2711     buffer_size = channels * *bufferSize * nBuffers * waveFormat.wBitsPerSample / 8;
2712     ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
2713     bufferDescription.dwSize = sizeof(DSBUFFERDESC);
2714     bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
2715                                   DSBCAPS_GETCURRENTPOSITION2 |
2716                                   DSBCAPS_LOCHARDWARE );  // Force hardware mixing
2717     bufferDescription.dwBufferBytes = buffer_size;
2718     bufferDescription.lpwfxFormat = &waveFormat;
2719
2720     // Try to create the secondary DS buffer.  If that doesn't work,
2721     // try to use software mixing.  Otherwise, there's a problem.
2722     result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
2723     if ( FAILED(result) ) {
2724       bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
2725                                     DSBCAPS_GETCURRENTPOSITION2 |
2726                                     DSBCAPS_LOCSOFTWARE );  // Force software mixing
2727       result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
2728       if ( FAILED(result) ) {
2729         object->Release();
2730         sprintf(message, "RtAudio: Unable to create secondary DS buffer (%s): %s.",
2731                 devices[device].name, getErrorString(result));
2732         error(RtAudioError::WARNING);
2733         return FAILURE;
2734       }
2735     }
2736
2737     // Get the buffer size ... might be different from what we specified.
2738     DSBCAPS dsbcaps;
2739     dsbcaps.dwSize = sizeof(DSBCAPS);
2740     buffer->GetCaps(&dsbcaps);
2741     buffer_size = dsbcaps.dwBufferBytes;
2742
2743     // Lock the DS buffer
2744     result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0);
2745     if ( FAILED(result) ) {
2746       object->Release();
2747       sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.",
2748               devices[device].name, getErrorString(result));
2749       error(RtAudioError::WARNING);
2750       return FAILURE;
2751     }
2752
2753     // Zero the DS buffer
2754     ZeroMemory(audioPtr, dataLen);
2755
2756     // Unlock the DS buffer
2757     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
2758     if ( FAILED(result) ) {
2759       object->Release();
2760       sprintf(message, "RtAudio: Unable to unlock DS buffer(%s): %s.",
2761               devices[device].name, getErrorString(result));
2762       error(RtAudioError::WARNING);
2763       return FAILURE;
2764     }
2765
2766     stream->handle[0].object = (void *) object;
2767     stream->handle[0].buffer = (void *) buffer;
2768     stream->nDeviceChannels[0] = channels;
2769   }
2770
2771   if ( mode == RECORD ) {
2772
2773     LPGUID id = devices[device].id[1];
2774     LPDIRECTSOUNDCAPTURE  object;
2775     LPDIRECTSOUNDCAPTUREBUFFER buffer;
2776     DSCBUFFERDESC bufferDescription;
2777
2778     result = DirectSoundCaptureCreate( id, &object, NULL );
2779     if ( FAILED(result) ) {
2780       sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.",
2781               devices[device].name, getErrorString(result));
2782       error(RtAudioError::WARNING);
2783       return FAILURE;
2784     }
2785
2786     // Setup the secondary DS buffer description.
2787     buffer_size = channels * *bufferSize * nBuffers * waveFormat.wBitsPerSample / 8;
2788     ZeroMemory(&bufferDescription, sizeof(DSCBUFFERDESC));
2789     bufferDescription.dwSize = sizeof(DSCBUFFERDESC);
2790     bufferDescription.dwFlags = 0;
2791     bufferDescription.dwReserved = 0;
2792     bufferDescription.dwBufferBytes = buffer_size;
2793     bufferDescription.lpwfxFormat = &waveFormat;
2794
2795     // Create the capture buffer.
2796     result = object->CreateCaptureBuffer(&bufferDescription, &buffer, NULL);
2797     if ( FAILED(result) ) {
2798       object->Release();
2799       sprintf(message, "RtAudio: Unable to create DS capture buffer (%s): %s.",
2800               devices[device].name, getErrorString(result));
2801       error(RtAudioError::WARNING);
2802       return FAILURE;
2803     }
2804
2805     // Lock the capture buffer
2806     result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0);
2807     if ( FAILED(result) ) {
2808       object->Release();
2809       sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
2810               devices[device].name, getErrorString(result));
2811       error(RtAudioError::WARNING);
2812       return FAILURE;
2813     }
2814
2815     // Zero the buffer
2816     ZeroMemory(audioPtr, dataLen);
2817
2818     // Unlock the buffer
2819     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
2820     if ( FAILED(result) ) {
2821       object->Release();
2822       sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
2823               devices[device].name, getErrorString(result));
2824       error(RtAudioError::WARNING);
2825       return FAILURE;
2826     }
2827
2828     stream->handle[1].object = (void *) object;
2829     stream->handle[1].buffer = (void *) buffer;
2830     stream->nDeviceChannels[1] = channels;
2831   }
2832
2833   stream->userFormat = format;
2834   if ( waveFormat.wBitsPerSample == 8 )
2835     stream->deviceFormat[mode] = RTAUDIO_SINT8;
2836   else
2837     stream->deviceFormat[mode] = RTAUDIO_SINT16;
2838   stream->nUserChannels[mode] = channels;
2839   *bufferSize = buffer_size / (channels * nBuffers * waveFormat.wBitsPerSample / 8);
2840   stream->bufferSize = *bufferSize;
2841
2842   // Set flags for buffer conversion
2843   stream->doConvertBuffer[mode] = false;
2844   if (stream->userFormat != stream->deviceFormat[mode])
2845     stream->doConvertBuffer[mode] = true;
2846   if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
2847     stream->doConvertBuffer[mode] = true;
2848
2849   // Allocate necessary internal buffers
2850   if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
2851
2852     long buffer_bytes;
2853     if (stream->nUserChannels[0] >= stream->nUserChannels[1])
2854       buffer_bytes = stream->nUserChannels[0];
2855     else
2856       buffer_bytes = stream->nUserChannels[1];
2857
2858     buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
2859     if (stream->userBuffer) free(stream->userBuffer);
2860     stream->userBuffer = (char *) calloc(buffer_bytes, 1);
2861     if (stream->userBuffer == NULL)
2862       goto memory_error;
2863   }
2864
2865   if ( stream->doConvertBuffer[mode] ) {
2866
2867     long buffer_bytes;
2868     bool makeBuffer = true;
2869     if ( mode == PLAYBACK )
2870       buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
2871     else { // mode == RECORD
2872       buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
2873       if ( stream->mode == PLAYBACK ) {
2874         long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
2875         if ( buffer_bytes > bytes_out )
2876           buffer_bytes = (buffer_bytes > bytes_out) ? buffer_bytes : bytes_out;
2877         else
2878           makeBuffer = false;
2879       }
2880     }
2881
2882     if ( makeBuffer ) {
2883       buffer_bytes *= *bufferSize;
2884       if (stream->deviceBuffer) free(stream->deviceBuffer);
2885       stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
2886       if (stream->deviceBuffer == NULL)
2887         goto memory_error;
2888     }
2889   }
2890
2891   stream->device[mode] = device;
2892   stream->state = STREAM_STOPPED;
2893   if ( stream->mode == PLAYBACK && mode == RECORD )
2894     // We had already set up an output stream.
2895     stream->mode = DUPLEX;
2896   else
2897     stream->mode = mode;
2898   stream->nBuffers = nBuffers;
2899   stream->sampleRate = sampleRate;
2900
2901   return SUCCESS;
2902
2903  memory_error:
2904   if (stream->handle[0].object) {
2905     LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object;
2906     LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
2907     if (buffer) {
2908       buffer->Release();
2909       stream->handle[0].buffer = NULL;
2910     }
2911     object->Release();
2912     stream->handle[0].object = NULL;
2913   }
2914   if (stream->handle[1].object) {
2915     LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object;
2916     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
2917     if (buffer) {
2918       buffer->Release();
2919       stream->handle[1].buffer = NULL;
2920     }
2921     object->Release();
2922     stream->handle[1].object = NULL;
2923   }
2924   if (stream->userBuffer) {
2925     free(stream->userBuffer);
2926     stream->userBuffer = 0;
2927   }
2928   sprintf(message, "RtAudio: error allocating buffer memory (%s).",
2929           devices[device].name);
2930   error(RtAudioError::WARNING);
2931   return FAILURE;
2932 }
2933
2934 void RtAudio :: cancelStreamCallback(int streamID)
2935 {
2936   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
2937
2938   if (stream->usingCallback) {
2939     stream->usingCallback = false;
2940     WaitForSingleObject( (HANDLE)stream->thread, INFINITE );
2941     CloseHandle( (HANDLE)stream->thread );
2942     stream->thread = 0;
2943     stream->callback = NULL;
2944     stream->userData = NULL;
2945   }
2946 }
2947
2948 void RtAudio :: closeStream(int streamID)
2949 {
2950   // We don't want an exception to be thrown here because this
2951   // function is called by our class destructor.  So, do our own
2952   // streamID check.
2953   if ( streams.find( streamID ) == streams.end() ) {
2954     sprintf(message, "RtAudio: invalid stream identifier!");
2955     error(RtAudioError::WARNING);
2956     return;
2957   }
2958
2959   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamID];
2960
2961   if (stream->usingCallback) {
2962     stream->usingCallback = false;
2963     WaitForSingleObject( (HANDLE)stream->thread, INFINITE );
2964     CloseHandle( (HANDLE)stream->thread );
2965   }
2966
2967   DeleteCriticalSection(&stream->mutex);
2968
2969   if (stream->handle[0].object) {
2970     LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object;
2971     LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
2972     if (buffer) {
2973       buffer->Stop();
2974       buffer->Release();
2975     }
2976     object->Release();
2977   }
2978
2979   if (stream->handle[1].object) {
2980     LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object;
2981     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
2982     if (buffer) {
2983       buffer->Stop();
2984       buffer->Release();
2985     }
2986     object->Release();
2987   }
2988
2989   if (stream->userBuffer)
2990     free(stream->userBuffer);
2991
2992   if (stream->deviceBuffer)
2993     free(stream->deviceBuffer);
2994
2995   free(stream);
2996   streams.erase(streamID);
2997 }
2998
2999 void RtAudio :: startStream(int streamID)
3000 {
3001   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
3002
3003   MUTEX_LOCK(&stream->mutex);
3004
3005   if (stream->state == STREAM_RUNNING)
3006     goto unlock;
3007
3008   HRESULT result;
3009   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
3010     LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
3011     result = buffer->Play(0, 0, DSBPLAY_LOOPING );
3012     if ( FAILED(result) ) {
3013       sprintf(message, "RtAudio: Unable to start DS buffer (%s): %s.",
3014               devices[stream->device[0]].name, getErrorString(result));
3015       error(RtAudioError::DRIVER_ERROR);
3016     }
3017   }
3018
3019   if (stream->mode == RECORD || stream->mode == DUPLEX) {
3020     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
3021     result = buffer->Start(DSCBSTART_LOOPING );
3022     if ( FAILED(result) ) {
3023       sprintf(message, "RtAudio: Unable to start DS capture buffer (%s): %s.",
3024               devices[stream->device[1]].name, getErrorString(result));
3025       error(RtAudioError::DRIVER_ERROR);
3026     }
3027   }
3028   stream->state = STREAM_RUNNING;
3029
3030  unlock:
3031   MUTEX_UNLOCK(&stream->mutex);
3032 }
3033
3034 void RtAudio :: stopStream(int streamID)
3035 {
3036   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
3037
3038   MUTEX_LOCK(&stream->mutex);
3039
3040   if (stream->state == STREAM_STOPPED) {
3041     MUTEX_UNLOCK(&stream->mutex);
3042     return;
3043   }
3044
3045   // There is no specific DirectSound API call to "drain" a buffer
3046   // before stopping.  We can hack this for playback by writing zeroes
3047   // for another bufferSize * nBuffers frames.  For capture, the
3048   // concept is less clear so we'll repeat what we do in the
3049   // abortStream() case.
3050   HRESULT result;
3051   DWORD dsBufferSize;
3052   LPVOID buffer1 = NULL;
3053   LPVOID buffer2 = NULL;
3054   DWORD bufferSize1 = 0;
3055   DWORD bufferSize2 = 0;
3056   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
3057
3058     DWORD currentPos, safePos;
3059     long buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0];
3060     buffer_bytes *= formatBytes(stream->deviceFormat[0]);
3061
3062     LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
3063     UINT nextWritePos = stream->handle[0].bufferPointer;
3064     dsBufferSize = buffer_bytes * stream->nBuffers;
3065
3066     // Write zeroes for nBuffer counts.
3067     for (int i=0; i<stream->nBuffers; i++) {
3068
3069       // Find out where the read and "safe write" pointers are.
3070       result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
3071       if ( FAILED(result) ) {
3072         sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
3073                 devices[stream->device[0]].name, getErrorString(result));
3074         error(RtAudioError::DRIVER_ERROR);
3075       }
3076
3077       if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
3078       DWORD endWrite = nextWritePos + buffer_bytes;
3079
3080       // Check whether the entire write region is behind the play pointer.
3081       while ( currentPos < endWrite ) {
3082         float millis = (endWrite - currentPos) * 900.0;
3083         millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate);
3084         if ( millis < 1.0 ) millis = 1.0;
3085         Sleep( (DWORD) millis );
3086
3087         // Wake up, find out where we are now
3088         result = dsBuffer->GetCurrentPosition( &currentPos, &safePos );
3089         if ( FAILED(result) ) {
3090           sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
3091                   devices[stream->device[0]].name, getErrorString(result));
3092           error(RtAudioError::DRIVER_ERROR);
3093         }
3094         if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
3095       }
3096
3097       // Lock free space in the buffer
3098       result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1,
3099                                &bufferSize1, &buffer2, &bufferSize2, 0);
3100       if ( FAILED(result) ) {
3101         sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.",
3102                 devices[stream->device[0]].name, getErrorString(result));
3103         error(RtAudioError::DRIVER_ERROR);
3104       }
3105
3106       // Zero the free space
3107       ZeroMemory(buffer1, bufferSize1);
3108       if (buffer2 != NULL) ZeroMemory(buffer2, bufferSize2);
3109
3110       // Update our buffer offset and unlock sound buffer
3111       dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
3112       if ( FAILED(result) ) {
3113         sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.",
3114                 devices[stream->device[0]].name, getErrorString(result));
3115         error(RtAudioError::DRIVER_ERROR);
3116       }
3117       nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize;
3118       stream->handle[0].bufferPointer = nextWritePos;
3119     }
3120
3121     // If we play again, start at the beginning of the buffer.
3122     stream->handle[0].bufferPointer = 0;
3123   }
3124
3125   if (stream->mode == RECORD || stream->mode == DUPLEX) {
3126     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
3127     buffer1 = NULL;
3128     bufferSize1 = 0;
3129
3130     result = buffer->Stop();
3131     if ( FAILED(result) ) {
3132       sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s",
3133               devices[stream->device[1]].name, getErrorString(result));
3134       error(RtAudioError::DRIVER_ERROR);
3135     }
3136
3137     dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1];
3138     dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
3139
3140     // Lock the buffer and clear it so that if we start to play again,
3141     // we won't have old data playing.
3142     result = buffer->Lock(0, dsBufferSize, &buffer1, &bufferSize1, NULL, NULL, 0);
3143     if ( FAILED(result) ) {
3144       sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
3145               devices[stream->device[1]].name, getErrorString(result));
3146       error(RtAudioError::DRIVER_ERROR);
3147     }
3148
3149     // Zero the DS buffer
3150     ZeroMemory(buffer1, bufferSize1);
3151
3152     // Unlock the DS buffer
3153     result = buffer->Unlock(buffer1, bufferSize1, NULL, 0);
3154     if ( FAILED(result) ) {
3155       sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
3156               devices[stream->device[1]].name, getErrorString(result));
3157       error(RtAudioError::DRIVER_ERROR);
3158     }
3159
3160     // If we start recording again, we must begin at beginning of buffer.
3161     stream->handle[1].bufferPointer = 0;
3162   }
3163   stream->state = STREAM_STOPPED;
3164
3165   MUTEX_UNLOCK(&stream->mutex);
3166 }
3167
3168 void RtAudio :: abortStream(int streamID)
3169 {
3170   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
3171
3172   MUTEX_LOCK(&stream->mutex);
3173
3174   if (stream->state == STREAM_STOPPED)
3175     goto unlock;
3176
3177   HRESULT result;
3178   long dsBufferSize;
3179   LPVOID audioPtr;
3180   DWORD dataLen;
3181   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
3182     LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
3183     result = buffer->Stop();
3184     if ( FAILED(result) ) {
3185       sprintf(message, "RtAudio: Unable to stop DS buffer (%s): %s",
3186               devices[stream->device[0]].name, getErrorString(result));
3187       error(RtAudioError::DRIVER_ERROR);
3188     }
3189
3190     dsBufferSize = stream->bufferSize * stream->nDeviceChannels[0];
3191     dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers;
3192
3193     // Lock the buffer and clear it so that if we start to play again,
3194     // we won't have old data playing.
3195     result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0);
3196     if ( FAILED(result) ) {
3197       sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.",
3198               devices[stream->device[0]].name, getErrorString(result));
3199       error(RtAudioError::DRIVER_ERROR);
3200     }
3201
3202     // Zero the DS buffer
3203     ZeroMemory(audioPtr, dataLen);
3204
3205     // Unlock the DS buffer
3206     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
3207     if ( FAILED(result) ) {
3208       sprintf(message, "RtAudio: Unable to unlock DS buffer (%s): %s.",
3209               devices[stream->device[0]].name, getErrorString(result));
3210       error(RtAudioError::DRIVER_ERROR);
3211     }
3212
3213     // If we start playing again, we must begin at beginning of buffer.
3214     stream->handle[0].bufferPointer = 0;
3215   }
3216
3217   if (stream->mode == RECORD || stream->mode == DUPLEX) {
3218     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
3219     audioPtr = NULL;
3220     dataLen = 0;
3221
3222     result = buffer->Stop();
3223     if ( FAILED(result) ) {
3224       sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s",
3225               devices[stream->device[1]].name, getErrorString(result));
3226       error(RtAudioError::DRIVER_ERROR);
3227     }
3228
3229     dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1];
3230     dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
3231
3232     // Lock the buffer and clear it so that if we start to play again,
3233     // we won't have old data playing.
3234     result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0);
3235     if ( FAILED(result) ) {
3236       sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
3237               devices[stream->device[1]].name, getErrorString(result));
3238       error(RtAudioError::DRIVER_ERROR);
3239     }
3240
3241     // Zero the DS buffer
3242     ZeroMemory(audioPtr, dataLen);
3243
3244     // Unlock the DS buffer
3245     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
3246     if ( FAILED(result) ) {
3247       sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
3248               devices[stream->device[1]].name, getErrorString(result));
3249       error(RtAudioError::DRIVER_ERROR);
3250     }
3251
3252     // If we start recording again, we must begin at beginning of buffer.
3253     stream->handle[1].bufferPointer = 0;
3254   }
3255   stream->state = STREAM_STOPPED;
3256
3257  unlock:
3258   MUTEX_UNLOCK(&stream->mutex);
3259 }
3260
3261 int RtAudio :: streamWillBlock(int streamID)
3262 {
3263   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
3264
3265   MUTEX_LOCK(&stream->mutex);
3266
3267   int frames = 0;
3268   int channels = 1;
3269   if (stream->state == STREAM_STOPPED)
3270     goto unlock;
3271
3272   HRESULT result;
3273   DWORD currentPos, safePos;
3274   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
3275
3276     LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
3277     UINT nextWritePos = stream->handle[0].bufferPointer;
3278     channels = stream->nDeviceChannels[0];
3279     DWORD dsBufferSize = stream->bufferSize * channels;
3280     dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers;
3281
3282     // Find out where the read and "safe write" pointers are.
3283     result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
3284     if ( FAILED(result) ) {
3285       sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
3286               devices[stream->device[0]].name, getErrorString(result));
3287       error(RtAudioError::DRIVER_ERROR);
3288     }
3289
3290     if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
3291     frames = currentPos - nextWritePos;
3292     frames /= channels * formatBytes(stream->deviceFormat[0]);
3293   }
3294
3295   if (stream->mode == RECORD || stream->mode == DUPLEX) {
3296
3297     LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
3298     UINT nextReadPos = stream->handle[1].bufferPointer;
3299     channels = stream->nDeviceChannels[1];
3300     DWORD dsBufferSize = stream->bufferSize * channels;
3301     dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
3302
3303     // Find out where the write and "safe read" pointers are.
3304     result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
3305     if ( FAILED(result) ) {
3306       sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
3307               devices[stream->device[1]].name, getErrorString(result));
3308       error(RtAudioError::DRIVER_ERROR);
3309     }
3310
3311     if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
3312
3313     if (stream->mode == DUPLEX ) {
3314       // Take largest value of the two.
3315       int temp = safePos - nextReadPos;
3316       temp /= channels * formatBytes(stream->deviceFormat[1]);
3317       frames = ( temp > frames ) ? temp : frames;
3318     }
3319     else {
3320       frames = safePos - nextReadPos;
3321       frames /= channels * formatBytes(stream->deviceFormat[1]);
3322     }
3323   }
3324
3325   frames = stream->bufferSize - frames;
3326   if (frames < 0) frames = 0;
3327
3328  unlock:
3329   MUTEX_UNLOCK(&stream->mutex);
3330   return frames;
3331 }
3332
3333 void RtAudio :: tickStream(int streamID)
3334 {
3335   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
3336
3337   int stopStream = 0;
3338   if (stream->state == STREAM_STOPPED) {
3339     if (stream->usingCallback) Sleep(50); // sleep 50 milliseconds
3340     return;
3341   }
3342   else if (stream->usingCallback) {
3343     stopStream = stream->callback(stream->userBuffer, stream->bufferSize, stream->userData);    
3344   }
3345
3346   MUTEX_LOCK(&stream->mutex);
3347
3348   // The state might change while waiting on a mutex.
3349   if (stream->state == STREAM_STOPPED)
3350     goto unlock;
3351
3352   HRESULT result;
3353   DWORD currentPos, safePos;
3354   LPVOID buffer1, buffer2;
3355   DWORD bufferSize1, bufferSize2;
3356   char *buffer;
3357   long buffer_bytes;
3358   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
3359
3360     // Setup parameters and do buffer conversion if necessary.
3361     if (stream->doConvertBuffer[0]) {
3362       convertStreamBuffer(stream, PLAYBACK);
3363       buffer = stream->deviceBuffer;
3364       buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0];
3365       buffer_bytes *= formatBytes(stream->deviceFormat[0]);
3366     }
3367     else {
3368       buffer = stream->userBuffer;
3369       buffer_bytes = stream->bufferSize * stream->nUserChannels[0];
3370       buffer_bytes *= formatBytes(stream->userFormat);
3371     }
3372
3373     // No byte swapping necessary in DirectSound implementation.
3374
3375     LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
3376     UINT nextWritePos = stream->handle[0].bufferPointer;
3377     DWORD dsBufferSize = buffer_bytes * stream->nBuffers;
3378
3379     // Find out where the read and "safe write" pointers are.
3380     result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
3381     if ( FAILED(result) ) {
3382       sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
3383               devices[stream->device[0]].name, getErrorString(result));
3384       error(RtAudioError::DRIVER_ERROR);
3385     }
3386
3387     if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
3388     DWORD endWrite = nextWritePos + buffer_bytes;
3389
3390     // Check whether the entire write region is behind the play pointer.
3391     while ( currentPos < endWrite ) {
3392       // If we are here, then we must wait until the play pointer gets
3393       // beyond the write region.  The approach here is to use the
3394       // Sleep() function to suspend operation until safePos catches
3395       // up. Calculate number of milliseconds to wait as:
3396       //   time = distance * (milliseconds/second) * fudgefactor /
3397       //          ((bytes/sample) * (samples/second))
3398       // A "fudgefactor" less than 1 is used because it was found
3399       // that sleeping too long was MUCH worse than sleeping for
3400       // several shorter periods.
3401       float millis = (endWrite - currentPos) * 900.0;
3402       millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate);
3403       if ( millis < 1.0 ) millis = 1.0;
3404       Sleep( (DWORD) millis );
3405
3406       // Wake up, find out where we are now
3407       result = dsBuffer->GetCurrentPosition( &currentPos, &safePos );
3408       if ( FAILED(result) ) {
3409         sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
3410               devices[stream->device[0]].name, getErrorString(result));
3411         error(RtAudioError::DRIVER_ERROR);
3412       }
3413       if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
3414     }
3415
3416     // Lock free space in the buffer
3417     result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1,
3418                              &bufferSize1, &buffer2, &bufferSize2, 0);
3419     if ( FAILED(result) ) {
3420       sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.",
3421               devices[stream->device[0]].name, getErrorString(result));
3422       error(RtAudioError::DRIVER_ERROR);
3423     }
3424
3425     // Copy our buffer into the DS buffer
3426     CopyMemory(buffer1, buffer, bufferSize1);
3427     if (buffer2 != NULL) CopyMemory(buffer2, buffer+bufferSize1, bufferSize2);
3428
3429     // Update our buffer offset and unlock sound buffer
3430     dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
3431     if ( FAILED(result) ) {
3432       sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.",
3433               devices[stream->device[0]].name, getErrorString(result));
3434       error(RtAudioError::DRIVER_ERROR);
3435     }
3436     nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize;
3437     stream->handle[0].bufferPointer = nextWritePos;
3438   }
3439
3440   if (stream->mode == RECORD || stream->mode == DUPLEX) {
3441
3442     // Setup parameters.
3443     if (stream->doConvertBuffer[1]) {
3444       buffer = stream->deviceBuffer;
3445       buffer_bytes = stream->bufferSize * stream->nDeviceChannels[1];
3446       buffer_bytes *= formatBytes(stream->deviceFormat[1]);
3447     }
3448     else {
3449       buffer = stream->userBuffer;
3450       buffer_bytes = stream->bufferSize * stream->nUserChannels[1];
3451       buffer_bytes *= formatBytes(stream->userFormat);
3452     }
3453
3454     LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
3455     UINT nextReadPos = stream->handle[1].bufferPointer;
3456     DWORD dsBufferSize = buffer_bytes * stream->nBuffers;
3457
3458     // Find out where the write and "safe read" pointers are.
3459     result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
3460     if ( FAILED(result) ) {
3461       sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
3462               devices[stream->device[1]].name, getErrorString(result));
3463       error(RtAudioError::DRIVER_ERROR);
3464     }
3465
3466     if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
3467     DWORD endRead = nextReadPos + buffer_bytes;
3468
3469     // Check whether the entire write region is behind the play pointer.
3470     while ( safePos < endRead ) {
3471       // See comments for playback.
3472       float millis = (endRead - safePos) * 900.0;
3473       millis /= ( formatBytes(stream->deviceFormat[1]) * stream->sampleRate);
3474       if ( millis < 1.0 ) millis = 1.0;
3475       Sleep( (DWORD) millis );
3476
3477       // Wake up, find out where we are now
3478       result = dsBuffer->GetCurrentPosition( &currentPos, &safePos );
3479       if ( FAILED(result) ) {
3480         sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
3481                 devices[stream->device[1]].name, getErrorString(result));
3482         error(RtAudioError::DRIVER_ERROR);
3483       }
3484       
3485       if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
3486     }
3487
3488     // Lock free space in the buffer
3489     result = dsBuffer->Lock (nextReadPos, buffer_bytes, &buffer1,
3490                              &bufferSize1, &buffer2, &bufferSize2, 0);
3491     if ( FAILED(result) ) {
3492       sprintf(message, "RtAudio: Unable to lock DS buffer during capture (%s): %s.",
3493               devices[stream->device[1]].name, getErrorString(result));
3494       error(RtAudioError::DRIVER_ERROR);
3495     }
3496
3497     // Copy our buffer into the DS buffer
3498     CopyMemory(buffer, buffer1, bufferSize1);
3499     if (buffer2 != NULL) CopyMemory(buffer+bufferSize1, buffer2, bufferSize2);
3500
3501     // Update our buffer offset and unlock sound buffer
3502     nextReadPos = (nextReadPos + bufferSize1 + bufferSize2) % dsBufferSize;
3503     dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
3504     if ( FAILED(result) ) {
3505       sprintf(message, "RtAudio: Unable to unlock DS buffer during capture (%s): %s.",
3506               devices[stream->device[1]].name, getErrorString(result));
3507       error(RtAudioError::DRIVER_ERROR);
3508     }
3509     stream->handle[1].bufferPointer = nextReadPos;
3510
3511     // No byte swapping necessary in DirectSound implementation.
3512
3513     // Do buffer conversion if necessary.
3514     if (stream->doConvertBuffer[1])
3515       convertStreamBuffer(stream, RECORD);
3516   }
3517
3518  unlock:
3519   MUTEX_UNLOCK(&stream->mutex);
3520
3521   if (stream->usingCallback && stopStream)
3522     this->stopStream(streamID);
3523 }
3524
3525 // Definitions for utility functions and callbacks
3526 // specific to the DirectSound implementation.
3527
3528 extern "C" unsigned __stdcall callbackHandler(void *ptr)
3529 {
3530   RtAudio *object = thread_info.object;
3531   int stream = thread_info.streamID;
3532   bool *usingCallback = (bool *) ptr;
3533
3534   while ( *usingCallback ) {
3535     try {
3536       object->tickStream(stream);
3537     }
3538     catch (RtAudioError &exception) {
3539       fprintf(stderr, "\nCallback thread error (%s) ... closing thread.\n\n",
3540               exception.getMessage());
3541       break;
3542     }
3543   }
3544
3545   _endthreadex( 0 );
3546   return 0;
3547 }
3548
3549 static bool CALLBACK deviceCountCallback(LPGUID lpguid,
3550                                          LPCSTR lpcstrDescription,
3551                                          LPCSTR lpcstrModule,
3552                                          LPVOID lpContext)
3553 {
3554   int *pointer = ((int *) lpContext);
3555   (*pointer)++;
3556
3557   return true;
3558 }
3559
3560 static bool CALLBACK deviceInfoCallback(LPGUID lpguid,
3561                                         LPCSTR lpcstrDescription,
3562                                         LPCSTR lpcstrModule,
3563                                         LPVOID lpContext)
3564 {
3565   enum_info *info = ((enum_info *) lpContext);
3566   while (strlen(info->name) > 0) info++;
3567
3568   strncpy(info->name, lpcstrDescription, 64);
3569   info->id = lpguid;
3570
3571         HRESULT    hr;
3572   info->isValid = false;
3573   if (info->isInput == true) {
3574     DSCCAPS               caps;
3575     LPDIRECTSOUNDCAPTURE  object;
3576
3577     hr = DirectSoundCaptureCreate(  lpguid, &object,   NULL );
3578     if( hr != DS_OK ) return true;
3579
3580     caps.dwSize = sizeof(caps);
3581     hr = object->GetCaps( &caps );
3582     if( hr == DS_OK ) {
3583       if (caps.dwChannels > 0 && caps.dwFormats > 0)
3584         info->isValid = true;
3585     }
3586     object->Release();
3587   }
3588   else {
3589     DSCAPS         caps;
3590     LPDIRECTSOUND  object;
3591     hr = DirectSoundCreate(  lpguid, &object,   NULL );
3592     if( hr != DS_OK ) return true;
3593
3594     caps.dwSize = sizeof(caps);
3595     hr = object->GetCaps( &caps );
3596     if( hr == DS_OK ) {
3597       if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO )
3598         info->isValid = true;
3599     }
3600     object->Release();
3601   }
3602
3603   return true;
3604 }
3605
3606 static char* getErrorString(int code)
3607 {
3608         switch (code) {
3609
3610   case DSERR_ALLOCATED:
3611     return "Direct Sound already allocated";
3612
3613   case DSERR_CONTROLUNAVAIL:
3614     return "Direct Sound control unavailable";
3615
3616   case DSERR_INVALIDPARAM:
3617     return "Direct Sound invalid parameter";
3618
3619   case DSERR_INVALIDCALL:
3620     return "Direct Sound invalid call";
3621
3622   case DSERR_GENERIC:
3623     return "Direct Sound generic error";
3624
3625   case DSERR_PRIOLEVELNEEDED:
3626     return "Direct Sound Priority level needed";
3627
3628   case DSERR_OUTOFMEMORY:
3629     return "Direct Sound out of memory";
3630
3631   case DSERR_BADFORMAT:
3632     return "Direct Sound bad format";
3633
3634   case DSERR_UNSUPPORTED:
3635     return "Direct Sound unsupported error";
3636
3637   case DSERR_NODRIVER:
3638     return "Direct Sound no driver error";
3639
3640   case DSERR_ALREADYINITIALIZED:
3641     return "Direct Sound already initialized";
3642
3643   case DSERR_NOAGGREGATION:
3644     return "Direct Sound no aggregation";
3645
3646   case DSERR_BUFFERLOST:
3647     return "Direct Sound buffer lost";
3648
3649   case DSERR_OTHERAPPHASPRIO:
3650     return "Direct Sound other app has priority";
3651
3652   case DSERR_UNINITIALIZED:
3653     return "Direct Sound uninitialized";
3654
3655   default:
3656     return "Direct Sound unknown error";
3657         }
3658 }
3659
3660 //******************** End of __WINDOWS_DS_ *********************//
3661
3662 #elif defined(__IRIX_AL_) // SGI's AL API for IRIX
3663
3664 #include <unistd.h>
3665 #include <errno.h>
3666
3667 void RtAudio :: initialize(void)
3668 {
3669
3670   // Count cards and devices
3671   nDevices = 0;
3672
3673   // Determine the total number of input and output devices.
3674   nDevices = alQueryValues(AL_SYSTEM, AL_DEVICES, 0, 0, 0, 0);
3675   if (nDevices < 0) {
3676     sprintf(message, "RtAudio: AL error counting devices: %s.",
3677             alGetErrorString(oserror()));
3678     error(RtAudioError::DRIVER_ERROR);
3679   }
3680
3681   if (nDevices <= 0) return;
3682
3683   ALvalue *vls = (ALvalue *) new ALvalue[nDevices];
3684
3685   // Add one for our default input/output devices.
3686   nDevices++;
3687
3688   //  Allocate the DEVICE_CONTROL structures.
3689   devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
3690   if (devices == NULL) {
3691     sprintf(message, "RtAudio: memory allocation error!");
3692     error(RtAudioError::MEMORY_ERROR);
3693   }
3694
3695   // Write device ascii identifiers to device info structure.
3696   char name[32];
3697   int outs, ins, i;
3698   ALpv pvs[1];
3699   pvs[0].param = AL_NAME;
3700   pvs[0].value.ptr = name;
3701   pvs[0].sizeIn = 32;
3702
3703   strcpy(devices[0].name, "Default Input/Output Devices");
3704
3705   outs = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, vls, nDevices-1, 0, 0);
3706   if (outs < 0) {
3707     sprintf(message, "RtAudio: AL error getting output devices: %s.",
3708             alGetErrorString(oserror()));
3709     error(RtAudioError::DRIVER_ERROR);
3710   }
3711
3712   for (i=0; i<outs; i++) {
3713     if (alGetParams(vls[i].i, pvs, 1) < 0) {
3714       sprintf(message, "RtAudio: AL error querying output devices: %s.",
3715               alGetErrorString(oserror()));
3716       error(RtAudioError::DRIVER_ERROR);
3717     }
3718     strncpy(devices[i+1].name, name, 32);
3719     devices[i+1].id[0] = vls[i].i;
3720   }
3721
3722   ins = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &vls[outs], nDevices-outs-1, 0, 0);
3723   if (ins < 0) {
3724     sprintf(message, "RtAudio: AL error getting input devices: %s.",
3725             alGetErrorString(oserror()));
3726     error(RtAudioError::DRIVER_ERROR);
3727   }
3728
3729   for (i=outs; i<ins+outs; i++) {
3730     if (alGetParams(vls[i].i, pvs, 1) < 0) {
3731       sprintf(message, "RtAudio: AL error querying input devices: %s.",
3732               alGetErrorString(oserror()));
3733       error(RtAudioError::DRIVER_ERROR);
3734     }
3735     strncpy(devices[i+1].name, name, 32);
3736     devices[i+1].id[1] = vls[i].i;
3737   }
3738
3739   delete [] vls;
3740
3741   return;
3742 }
3743
3744 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
3745 {
3746   int resource, result, i;
3747   ALvalue value;
3748   ALparamInfo pinfo;
3749
3750   // Get output resource ID if it exists.
3751   if ( !strncmp(info->name, "Default Input/Output Devices", 28) ) {
3752     result = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, &value, 1, 0, 0);
3753     if (result < 0) {
3754       sprintf(message, "RtAudio: AL error getting default output device id: %s.",
3755               alGetErrorString(oserror()));
3756       error(RtAudioError::WARNING);
3757     }
3758     else
3759       resource = value.i;
3760   }
3761   else
3762     resource = info->id[0];
3763
3764   if (resource > 0) {
3765
3766     // Probe output device parameters.
3767     result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0);
3768     if (result < 0) {
3769       sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.",
3770               info->name, alGetErrorString(oserror()));
3771       error(RtAudioError::WARNING);
3772     }
3773     else {
3774       info->maxOutputChannels = value.i;
3775       info->minOutputChannels = 1;
3776     }
3777
3778     result = alGetParamInfo(resource, AL_RATE, &pinfo);
3779     if (result < 0) {
3780       sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.",
3781               info->name, alGetErrorString(oserror()));
3782       error(RtAudioError::WARNING);
3783     }
3784     else {
3785       info->nSampleRates = 0;
3786       for (i=0; i<MAX_SAMPLE_RATES; i++) {
3787         if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) {
3788           info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
3789           info->nSampleRates++;
3790         }
3791       }
3792     }
3793
3794     // The AL library supports all our formats, except 24-bit and 32-bit ints.
3795     info->nativeFormats = (RTAUDIO_FORMAT) 51;
3796   }
3797
3798   // Now get input resource ID if it exists.
3799   if ( !strncmp(info->name, "Default Input/Output Devices", 28) ) {
3800     result = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &value, 1, 0, 0);
3801     if (result < 0) {
3802       sprintf(message, "RtAudio: AL error getting default input device id: %s.",
3803               alGetErrorString(oserror()));
3804       error(RtAudioError::WARNING);
3805     }
3806     else
3807       resource = value.i;
3808   }
3809   else
3810     resource = info->id[1];
3811
3812   if (resource > 0) {
3813
3814     // Probe input device parameters.
3815     result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0);
3816     if (result < 0) {
3817       sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.",
3818               info->name, alGetErrorString(oserror()));
3819       error(RtAudioError::WARNING);
3820     }
3821     else {
3822       info->maxInputChannels = value.i;
3823       info->minInputChannels = 1;
3824     }
3825
3826     result = alGetParamInfo(resource, AL_RATE, &pinfo);
3827     if (result < 0) {
3828       sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.",
3829               info->name, alGetErrorString(oserror()));
3830       error(RtAudioError::WARNING);
3831     }
3832     else {
3833       // In the case of the default device, these values will
3834       // overwrite the rates determined for the output device.  Since
3835       // the input device is most likely to be more limited than the
3836       // output device, this is ok.
3837       info->nSampleRates = 0;
3838       for (i=0; i<MAX_SAMPLE_RATES; i++) {
3839         if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) {
3840           info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
3841           info->nSampleRates++;
3842         }
3843       }
3844     }
3845
3846     // The AL library supports all our formats, except 24-bit and 32-bit ints.
3847     info->nativeFormats = (RTAUDIO_FORMAT) 51;
3848   }
3849
3850   if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 )
3851     return;
3852   if ( info->nSampleRates == 0 )
3853     return;
3854
3855   // Determine duplex status.
3856   if (info->maxInputChannels < info->maxOutputChannels)
3857     info->maxDuplexChannels = info->maxInputChannels;
3858   else
3859     info->maxDuplexChannels = info->maxOutputChannels;
3860   if (info->minInputChannels < info->minOutputChannels)
3861     info->minDuplexChannels = info->minInputChannels;
3862   else
3863     info->minDuplexChannels = info->minOutputChannels;
3864
3865   if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true;
3866   else info->hasDuplexSupport = false;
3867
3868   info->probed = true;
3869
3870   return;
3871 }
3872
3873 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
3874                                 STREAM_MODE mode, int channels, 
3875                                 int sampleRate, RTAUDIO_FORMAT format,
3876                                 int *bufferSize, int numberOfBuffers)
3877 {
3878   int result, resource, nBuffers;
3879   ALconfig al_config;
3880   ALport port;
3881   ALpv pvs[2];
3882
3883   // Get a new ALconfig structure.
3884   al_config = alNewConfig();
3885   if ( !al_config ) {
3886     sprintf(message,"RtAudio: can't get AL config: %s.",
3887             alGetErrorString(oserror()));
3888     error(RtAudioError::WARNING);
3889     return FAILURE;
3890   }
3891
3892   // Set the channels.
3893   result = alSetChannels(al_config, channels);
3894   if ( result < 0 ) {
3895     sprintf(message,"RtAudio: can't set %d channels in AL config: %s.",
3896             channels, alGetErrorString(oserror()));
3897     error(RtAudioError::WARNING);
3898     return FAILURE;
3899   }
3900
3901   // Set the queue (buffer) size.
3902   if ( numberOfBuffers < 1 )
3903     nBuffers = 1;
3904   else
3905     nBuffers = numberOfBuffers;
3906   long buffer_size = *bufferSize * nBuffers;
3907   result = alSetQueueSize(al_config, buffer_size); // in sample frames
3908   if ( result < 0 ) {
3909     sprintf(message,"RtAudio: can't set buffer size (%ld) in AL config: %s.",
3910             buffer_size, alGetErrorString(oserror()));
3911     error(RtAudioError::WARNING);
3912     return FAILURE;
3913   }
3914
3915   // Set the data format.
3916   stream->userFormat = format;
3917   stream->deviceFormat[mode] = format;
3918   if (format == RTAUDIO_SINT8) {
3919     result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP);
3920     result = alSetWidth(al_config, AL_SAMPLE_8);
3921   }
3922   else if (format == RTAUDIO_SINT16) {
3923     result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP);
3924     result = alSetWidth(al_config, AL_SAMPLE_16);
3925   }
3926   else if (format == RTAUDIO_SINT24) {
3927     // Our 24-bit format assumes the upper 3 bytes of a 4 byte word.
3928     // The AL library uses the lower 3 bytes, so we'll need to do our
3929     // own conversion.
3930     result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
3931     stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
3932   }
3933   else if (format == RTAUDIO_SINT32) {
3934     // The AL library doesn't seem to support the 32-bit integer
3935     // format, so we'll need to do our own conversion.
3936     result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
3937     stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
3938   }
3939   else if (format == RTAUDIO_FLOAT32)
3940     result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
3941   else if (format == RTAUDIO_FLOAT64)
3942     result = alSetSampFmt(al_config, AL_SAMPFMT_DOUBLE);
3943
3944   if ( result == -1 ) {
3945     sprintf(message,"RtAudio: AL error setting sample format in AL config: %s.",
3946             alGetErrorString(oserror()));
3947     error(RtAudioError::WARNING);
3948     return FAILURE;
3949   }
3950
3951   if (mode == PLAYBACK) {
3952
3953     // Set our device.
3954     if (device == 0)
3955       resource = AL_DEFAULT_OUTPUT;
3956     else
3957       resource = devices[device].id[0];
3958     result = alSetDevice(al_config, resource);
3959     if ( result == -1 ) {
3960       sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.",
3961               devices[device].name, alGetErrorString(oserror()));
3962       error(RtAudioError::WARNING);
3963       return FAILURE;
3964     }
3965
3966     // Open the port.
3967     port = alOpenPort("RtAudio Output Port", "w", al_config);
3968     if( !port ) {
3969       sprintf(message,"RtAudio: AL error opening output port: %s.",
3970               alGetErrorString(oserror()));
3971       error(RtAudioError::WARNING);
3972       return FAILURE;
3973     }
3974
3975     // Set the sample rate
3976     pvs[0].param = AL_MASTER_CLOCK;
3977     pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
3978     pvs[1].param = AL_RATE;
3979     pvs[1].value.ll = alDoubleToFixed((double)sampleRate);
3980     result = alSetParams(resource, pvs, 2);
3981     if ( result < 0 ) {
3982       alClosePort(port);
3983       sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.",
3984               sampleRate, devices[device].name, alGetErrorString(oserror()));
3985       error(RtAudioError::WARNING);
3986       return FAILURE;
3987     }
3988   }
3989   else { // mode == RECORD
3990
3991     // Set our device.
3992     if (device == 0)
3993       resource = AL_DEFAULT_INPUT;
3994     else
3995       resource = devices[device].id[1];
3996     result = alSetDevice(al_config, resource);
3997     if ( result == -1 ) {
3998       sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.",
3999               devices[device].name, alGetErrorString(oserror()));
4000       error(RtAudioError::WARNING);
4001       return FAILURE;
4002     }
4003
4004     // Open the port.
4005     port = alOpenPort("RtAudio Output Port", "r", al_config);
4006     if( !port ) {
4007       sprintf(message,"RtAudio: AL error opening input port: %s.",
4008               alGetErrorString(oserror()));
4009       error(RtAudioError::WARNING);
4010       return FAILURE;
4011     }
4012
4013     // Set the sample rate
4014     pvs[0].param = AL_MASTER_CLOCK;
4015     pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
4016     pvs[1].param = AL_RATE;
4017     pvs[1].value.ll = alDoubleToFixed((double)sampleRate);
4018     result = alSetParams(resource, pvs, 2);
4019     if ( result < 0 ) {
4020       alClosePort(port);
4021       sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.",
4022               sampleRate, devices[device].name, alGetErrorString(oserror()));
4023       error(RtAudioError::WARNING);
4024       return FAILURE;
4025     }
4026   }
4027
4028   alFreeConfig(al_config);
4029
4030   stream->nUserChannels[mode] = channels;
4031   stream->nDeviceChannels[mode] = channels;
4032
4033   // Set handle and flags for buffer conversion
4034   stream->handle[mode] = port;
4035   stream->doConvertBuffer[mode] = false;
4036   if (stream->userFormat != stream->deviceFormat[mode])
4037     stream->doConvertBuffer[mode] = true;
4038
4039   // Allocate necessary internal buffers
4040   if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
4041
4042     long buffer_bytes;
4043     if (stream->nUserChannels[0] >= stream->nUserChannels[1])
4044       buffer_bytes = stream->nUserChannels[0];
4045     else
4046       buffer_bytes = stream->nUserChannels[1];
4047
4048     buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
4049     if (stream->userBuffer) free(stream->userBuffer);
4050     stream->userBuffer = (char *) calloc(buffer_bytes, 1);
4051     if (stream->userBuffer == NULL)
4052       goto memory_error;
4053   }
4054
4055   if ( stream->doConvertBuffer[mode] ) {
4056
4057     long buffer_bytes;
4058     bool makeBuffer = true;
4059     if ( mode == PLAYBACK )
4060       buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
4061     else { // mode == RECORD
4062       buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
4063       if ( stream->mode == PLAYBACK ) {
4064         long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
4065         if ( buffer_bytes > bytes_out )
4066           buffer_bytes = (buffer_bytes > bytes_out) ? buffer_bytes : bytes_out;
4067         else
4068           makeBuffer = false;
4069       }
4070     }
4071
4072     if ( makeBuffer ) {
4073       buffer_bytes *= *bufferSize;
4074       if (stream->deviceBuffer) free(stream->deviceBuffer);
4075       stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
4076       if (stream->deviceBuffer == NULL)
4077         goto memory_error;
4078     }
4079   }
4080
4081   stream->device[mode] = device;
4082   stream->state = STREAM_STOPPED;
4083   if ( stream->mode == PLAYBACK && mode == RECORD )
4084     // We had already set up an output stream.
4085     stream->mode = DUPLEX;
4086   else
4087     stream->mode = mode;
4088   stream->nBuffers = nBuffers;
4089   stream->bufferSize = *bufferSize;
4090   stream->sampleRate = sampleRate;
4091
4092   return SUCCESS;
4093
4094  memory_error:
4095   if (stream->handle[0]) {
4096     alClosePort(stream->handle[0]);
4097     stream->handle[0] = 0;
4098   }
4099   if (stream->handle[1]) {
4100     alClosePort(stream->handle[1]);
4101     stream->handle[1] = 0;
4102   }
4103   if (stream->userBuffer) {
4104     free(stream->userBuffer);
4105     stream->userBuffer = 0;
4106   }
4107   sprintf(message, "RtAudio: ALSA error allocating buffer memory for device (%s).",
4108           devices[device].name);
4109   error(RtAudioError::WARNING);
4110   return FAILURE;
4111 }
4112
4113 void RtAudio :: cancelStreamCallback(int streamID)
4114 {
4115   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
4116
4117   if (stream->usingCallback) {
4118     stream->usingCallback = false;
4119     pthread_cancel(stream->thread);
4120     pthread_join(stream->thread, NULL);
4121     stream->thread = 0;
4122     stream->callback = NULL;
4123     stream->userData = NULL;
4124   }
4125 }
4126
4127 void RtAudio :: closeStream(int streamID)
4128 {
4129   // We don't want an exception to be thrown here because this
4130   // function is called by our class destructor.  So, do our own
4131   // streamID check.
4132   if ( streams.find( streamID ) == streams.end() ) {
4133     sprintf(message, "RtAudio: invalid stream identifier!");
4134     error(RtAudioError::WARNING);
4135     return;
4136   }
4137
4138   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamID];
4139
4140   if (stream->usingCallback) {
4141     pthread_cancel(stream->thread);
4142     pthread_join(stream->thread, NULL);
4143   }
4144
4145   pthread_mutex_destroy(&stream->mutex);
4146
4147   if (stream->handle[0])
4148     alClosePort(stream->handle[0]);
4149
4150   if (stream->handle[1])
4151     alClosePort(stream->handle[1]);
4152
4153   if (stream->userBuffer)
4154     free(stream->userBuffer);
4155
4156   if (stream->deviceBuffer)
4157     free(stream->deviceBuffer);
4158
4159   free(stream);
4160   streams.erase(streamID);
4161 }
4162
4163 void RtAudio :: startStream(int streamID)
4164 {
4165   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
4166
4167   if (stream->state == STREAM_RUNNING)
4168     return;
4169
4170   // The AL port is ready as soon as it is opened.
4171   stream->state = STREAM_RUNNING;
4172 }
4173
4174 void RtAudio :: stopStream(int streamID)
4175 {
4176   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
4177
4178   MUTEX_LOCK(&stream->mutex);
4179
4180   if (stream->state == STREAM_STOPPED)
4181     goto unlock;
4182
4183   int result;
4184   int buffer_size = stream->bufferSize * stream->nBuffers;
4185
4186   if (stream->mode == PLAYBACK || stream->mode == DUPLEX)
4187     alZeroFrames(stream->handle[0], buffer_size);
4188
4189   if (stream->mode == RECORD || stream->mode == DUPLEX) {
4190     result = alDiscardFrames(stream->handle[1], buffer_size);
4191     if (result == -1) {
4192       sprintf(message, "RtAudio: AL error draining stream device (%s): %s.",
4193               devices[stream->device[1]].name, alGetErrorString(oserror()));
4194       error(RtAudioError::DRIVER_ERROR);
4195     }
4196   }
4197   stream->state = STREAM_STOPPED;
4198
4199  unlock:
4200   MUTEX_UNLOCK(&stream->mutex);
4201 }
4202
4203 void RtAudio :: abortStream(int streamID)
4204 {
4205   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
4206
4207   MUTEX_LOCK(&stream->mutex);
4208
4209   if (stream->state == STREAM_STOPPED)
4210     goto unlock;
4211
4212   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
4213
4214     int buffer_size = stream->bufferSize * stream->nBuffers;
4215     int result = alDiscardFrames(stream->handle[0], buffer_size);
4216     if (result == -1) {
4217       sprintf(message, "RtAudio: AL error aborting stream device (%s): %s.",
4218               devices[stream->device[0]].name, alGetErrorString(oserror()));
4219       error(RtAudioError::DRIVER_ERROR);
4220     }
4221   }
4222
4223   // There is no clear action to take on the input stream, since the
4224   // port will continue to run in any event.
4225   stream->state = STREAM_STOPPED;
4226
4227  unlock:
4228   MUTEX_UNLOCK(&stream->mutex);
4229 }
4230
4231 int RtAudio :: streamWillBlock(int streamID)
4232 {
4233   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
4234
4235   MUTEX_LOCK(&stream->mutex);
4236
4237   int frames = 0;
4238   if (stream->state == STREAM_STOPPED)
4239     goto unlock;
4240
4241   int err = 0;
4242   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
4243     err = alGetFillable(stream->handle[0]);
4244     if (err < 0) {
4245       sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.",
4246               devices[stream->device[0]].name, alGetErrorString(oserror()));
4247       error(RtAudioError::DRIVER_ERROR);
4248     }
4249   }
4250
4251   frames = err;
4252
4253   if (stream->mode == RECORD || stream->mode == DUPLEX) {
4254     err = alGetFilled(stream->handle[1]);
4255     if (err < 0) {
4256       sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.",
4257               devices[stream->device[1]].name, alGetErrorString(oserror()));
4258       error(RtAudioError::DRIVER_ERROR);
4259     }
4260     if (frames > err) frames = err;
4261   }
4262
4263   frames = stream->bufferSize - frames;
4264   if (frames < 0) frames = 0;
4265
4266  unlock:
4267   MUTEX_UNLOCK(&stream->mutex);
4268   return frames;
4269 }
4270
4271 void RtAudio :: tickStream(int streamID)
4272 {
4273   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
4274
4275   int stopStream = 0;
4276   if (stream->state == STREAM_STOPPED) {
4277     if (stream->usingCallback) usleep(50000); // sleep 50 milliseconds
4278     return;
4279   }
4280   else if (stream->usingCallback) {
4281     stopStream = stream->callback(stream->userBuffer, stream->bufferSize, stream->userData);    
4282   }
4283
4284   MUTEX_LOCK(&stream->mutex);
4285
4286   // The state might change while waiting on a mutex.
4287   if (stream->state == STREAM_STOPPED)
4288     goto unlock;
4289
4290   char *buffer;
4291   int channels;
4292   RTAUDIO_FORMAT format;
4293   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
4294
4295     // Setup parameters and do buffer conversion if necessary.
4296     if (stream->doConvertBuffer[0]) {
4297       convertStreamBuffer(stream, PLAYBACK);
4298       buffer = stream->deviceBuffer;
4299       channels = stream->nDeviceChannels[0];
4300       format = stream->deviceFormat[0];
4301     }
4302     else {
4303       buffer = stream->userBuffer;
4304       channels = stream->nUserChannels[0];
4305       format = stream->userFormat;
4306     }
4307
4308     // Do byte swapping if necessary.
4309     if (stream->doByteSwap[0])
4310       byteSwapBuffer(buffer, stream->bufferSize * channels, format);
4311
4312     // Write interleaved samples to device.
4313     alWriteFrames(stream->handle[0], buffer, stream->bufferSize);
4314   }
4315
4316   if (stream->mode == RECORD || stream->mode == DUPLEX) {
4317
4318     // Setup parameters.
4319     if (stream->doConvertBuffer[1]) {
4320       buffer = stream->deviceBuffer;
4321       channels = stream->nDeviceChannels[1];
4322       format = stream->deviceFormat[1];
4323     }
4324     else {
4325       buffer = stream->userBuffer;
4326       channels = stream->nUserChannels[1];
4327       format = stream->userFormat;
4328     }
4329
4330     // Read interleaved samples from device.
4331     alReadFrames(stream->handle[1], buffer, stream->bufferSize);
4332
4333     // Do byte swapping if necessary.
4334     if (stream->doByteSwap[1])
4335       byteSwapBuffer(buffer, stream->bufferSize * channels, format);
4336
4337     // Do buffer conversion if necessary.
4338     if (stream->doConvertBuffer[1])
4339       convertStreamBuffer(stream, RECORD);
4340   }
4341
4342  unlock:
4343   MUTEX_UNLOCK(&stream->mutex);
4344
4345   if (stream->usingCallback && stopStream)
4346     this->stopStream(streamID);
4347 }
4348
4349 extern "C" void *callbackHandler(void *ptr)
4350 {
4351   RtAudio *object = thread_info.object;
4352   int stream = thread_info.streamID;
4353   bool *usingCallback = (bool *) ptr;
4354
4355   while ( *usingCallback ) {
4356     pthread_testcancel();
4357     try {
4358       object->tickStream(stream);
4359     }
4360     catch (RtAudioError &exception) {
4361       fprintf(stderr, "\nCallback thread error (%s) ... closing thread.\n\n",
4362               exception.getMessage());
4363       break;
4364     }
4365   }
4366
4367   return 0;
4368 }
4369
4370 //******************** End of __IRIX_AL_ *********************//
4371
4372 #endif
4373
4374
4375 // *************************************************** //
4376 //
4377 // Private common (OS-independent) RtAudio methods.
4378 //
4379 // *************************************************** //
4380
4381 // This method can be modified to control the behavior of error
4382 // message reporting and throwing.
4383 void RtAudio :: error(RtAudioError::TYPE type)
4384 {
4385   if (type == RtAudioError::WARNING)
4386     fprintf(stderr, "\n%s\n\n", message);
4387   else if (type == RtAudioError::DEBUG_WARNING) {
4388 #if defined(RTAUDIO_DEBUG)
4389     fprintf(stderr, "\n%s\n\n", message);
4390 #endif
4391   }
4392   else
4393     throw RtAudioError(message, type);
4394 }
4395
4396 void *RtAudio :: verifyStream(int streamID)
4397 {
4398   // Verify the stream key.
4399   if ( streams.find( streamID ) == streams.end() ) {
4400     sprintf(message, "RtAudio: invalid stream identifier!");
4401     error(RtAudioError::INVALID_STREAM);
4402   }
4403
4404   return streams[streamID];
4405 }
4406
4407 void RtAudio :: clearDeviceInfo(RTAUDIO_DEVICE *info)
4408 {
4409   // Don't clear the name or DEVICE_ID fields here ... they are
4410   // typically set prior to a call of this function.
4411   info->probed = false;
4412   info->maxOutputChannels = 0;
4413   info->maxInputChannels = 0;
4414   info->maxDuplexChannels = 0;
4415   info->minOutputChannels = 0;
4416   info->minInputChannels = 0;
4417   info->minDuplexChannels = 0;
4418   info->hasDuplexSupport = false;
4419   info->nSampleRates = 0;
4420   for (int i=0; i<MAX_SAMPLE_RATES; i++)
4421     info->sampleRates[i] = 0;
4422   info->nativeFormats = 0;
4423 }
4424
4425 int RtAudio :: formatBytes(RTAUDIO_FORMAT format)
4426 {
4427   if (format == RTAUDIO_SINT16)
4428     return 2;
4429   else if (format == RTAUDIO_SINT24 || format == RTAUDIO_SINT32 ||
4430            format == RTAUDIO_FLOAT32)
4431     return 4;
4432   else if (format == RTAUDIO_FLOAT64)
4433     return 8;
4434   else if (format == RTAUDIO_SINT8)
4435     return 1;
4436
4437   sprintf(message,"RtAudio: undefined format in formatBytes().");
4438   error(RtAudioError::WARNING);
4439
4440   return 0;
4441 }
4442
4443 void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
4444 {
4445   // This method does format conversion, input/output channel compensation, and
4446   // data interleaving/deinterleaving.  24-bit integers are assumed to occupy
4447   // the upper three bytes of a 32-bit integer.
4448
4449   int j, channels_in, channels_out, channels;
4450   RTAUDIO_FORMAT format_in, format_out;
4451   char *input, *output;
4452
4453   if (mode == RECORD) { // convert device to user buffer
4454     input = stream->deviceBuffer;
4455     output = stream->userBuffer;
4456     channels_in = stream->nDeviceChannels[1];
4457     channels_out = stream->nUserChannels[1];
4458     format_in = stream->deviceFormat[1];
4459     format_out = stream->userFormat;
4460   }
4461   else { // convert user to device buffer
4462     input = stream->userBuffer;
4463     output = stream->deviceBuffer;
4464     channels_in = stream->nUserChannels[0];
4465     channels_out = stream->nDeviceChannels[0];
4466     format_in = stream->userFormat;
4467     format_out = stream->deviceFormat[0];
4468
4469     // clear our device buffer when in/out duplex device channels are different
4470     if ( stream->mode == DUPLEX &&
4471          stream->nDeviceChannels[0] != stream->nDeviceChannels[1] )
4472       memset(output, 0, stream->bufferSize * channels_out * formatBytes(format_out));
4473   }
4474
4475   channels = (channels_in < channels_out) ? channels_in : channels_out;
4476
4477   // Set up the interleave/deinterleave offsets
4478   std::vector<int> offset_in(channels);
4479   std::vector<int> offset_out(channels);
4480   if (mode == RECORD && stream->deInterleave[1]) {
4481     for (int k=0; k<channels; k++) {
4482       offset_in[k] = k * stream->bufferSize;
4483       offset_out[k] = k;
4484     }
4485   }
4486   else if (mode == PLAYBACK && stream->deInterleave[0]) {
4487     for (int k=0; k<channels; k++) {
4488       offset_in[k] = k;
4489       offset_out[k] = k * stream->bufferSize;
4490     }
4491   }
4492   else {
4493     for (int k=0; k<channels; k++) {
4494       offset_in[k] = k;
4495       offset_out[k] = k;
4496     }
4497   }
4498
4499   if (format_out == RTAUDIO_FLOAT64) {
4500     FLOAT64 scale;
4501     FLOAT64 *out = (FLOAT64 *)output;
4502
4503     if (format_in == RTAUDIO_SINT8) {
4504       signed char *in = (signed char *)input;
4505       scale = 1.0 / 128.0;
4506       for (int i=0; i<stream->bufferSize; i++) {
4507         for (j=0; j<channels; j++) {
4508           out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
4509           out[offset_out[j]] *= scale;
4510         }
4511         in += channels_in;
4512         out += channels_out;
4513       }
4514     }
4515     else if (format_in == RTAUDIO_SINT16) {
4516       INT16 *in = (INT16 *)input;
4517       scale = 1.0 / 32768.0;
4518       for (int i=0; i<stream->bufferSize; i++) {
4519         for (j=0; j<channels; j++) {
4520           out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
4521           out[offset_out[j]] *= scale;
4522         }
4523         in += channels_in;
4524         out += channels_out;
4525       }
4526     }
4527     else if (format_in == RTAUDIO_SINT24) {
4528       INT32 *in = (INT32 *)input;
4529       scale = 1.0 / 2147483648.0;
4530       for (int i=0; i<stream->bufferSize; i++) {
4531         for (j=0; j<channels; j++) {
4532           out[offset_out[j]] = (FLOAT64) (in[offset_in[j]] & 0xffffff00);
4533           out[offset_out[j]] *= scale;
4534         }
4535         in += channels_in;
4536         out += channels_out;
4537       }
4538     }
4539     else if (format_in == RTAUDIO_SINT32) {
4540       INT32 *in = (INT32 *)input;
4541       scale = 1.0 / 2147483648.0;
4542       for (int i=0; i<stream->bufferSize; i++) {
4543         for (j=0; j<channels; j++) {
4544           out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
4545           out[offset_out[j]] *= scale;
4546         }
4547         in += channels_in;
4548         out += channels_out;
4549       }
4550     }
4551     else if (format_in == RTAUDIO_FLOAT32) {
4552       FLOAT32 *in = (FLOAT32 *)input;
4553       for (int i=0; i<stream->bufferSize; i++) {
4554         for (j=0; j<channels; j++) {
4555           out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
4556         }
4557         in += channels_in;
4558         out += channels_out;
4559       }
4560     }
4561     else if (format_in == RTAUDIO_FLOAT64) {
4562       // Channel compensation and/or (de)interleaving only.
4563       FLOAT64 *in = (FLOAT64 *)input;
4564       for (int i=0; i<stream->bufferSize; i++) {
4565         for (j=0; j<channels; j++) {
4566           out[offset_out[j]] = in[offset_in[j]];
4567         }
4568         in += channels_in;
4569         out += channels_out;
4570       }
4571     }
4572   }
4573   else if (format_out == RTAUDIO_FLOAT32) {
4574     FLOAT32 scale;
4575     FLOAT32 *out = (FLOAT32 *)output;
4576
4577     if (format_in == RTAUDIO_SINT8) {
4578       signed char *in = (signed char *)input;
4579       scale = 1.0 / 128.0;
4580       for (int i=0; i<stream->bufferSize; i++) {
4581         for (j=0; j<channels; j++) {
4582           out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
4583           out[offset_out[j]] *= scale;
4584         }
4585         in += channels_in;
4586         out += channels_out;
4587       }
4588     }
4589     else if (format_in == RTAUDIO_SINT16) {
4590       INT16 *in = (INT16 *)input;
4591       scale = 1.0 / 32768.0;
4592       for (int i=0; i<stream->bufferSize; i++) {
4593         for (j=0; j<channels; j++) {
4594           out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
4595           out[offset_out[j]] *= scale;
4596         }
4597         in += channels_in;
4598         out += channels_out;
4599       }
4600     }
4601     else if (format_in == RTAUDIO_SINT24) {
4602       INT32 *in = (INT32 *)input;
4603       scale = 1.0 / 2147483648.0;
4604       for (int i=0; i<stream->bufferSize; i++) {
4605         for (j=0; j<channels; j++) {
4606           out[offset_out[j]] = (FLOAT32) (in[offset_in[j]] & 0xffffff00);
4607           out[offset_out[j]] *= scale;
4608         }
4609         in += channels_in;
4610         out += channels_out;
4611       }
4612     }
4613     else if (format_in == RTAUDIO_SINT32) {
4614       INT32 *in = (INT32 *)input;
4615       scale = 1.0 / 2147483648.0;
4616       for (int i=0; i<stream->bufferSize; i++) {
4617         for (j=0; j<channels; j++) {
4618           out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
4619           out[offset_out[j]] *= scale;
4620         }
4621         in += channels_in;
4622         out += channels_out;
4623       }
4624     }
4625     else if (format_in == RTAUDIO_FLOAT32) {
4626       // Channel compensation and/or (de)interleaving only.
4627       FLOAT32 *in = (FLOAT32 *)input;
4628       for (int i=0; i<stream->bufferSize; i++) {
4629         for (j=0; j<channels; j++) {
4630           out[offset_out[j]] = in[offset_in[j]];
4631         }
4632         in += channels_in;
4633         out += channels_out;
4634       }
4635     }
4636     else if (format_in == RTAUDIO_FLOAT64) {
4637       FLOAT64 *in = (FLOAT64 *)input;
4638       for (int i=0; i<stream->bufferSize; i++) {
4639         for (j=0; j<channels; j++) {
4640           out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
4641         }
4642         in += channels_in;
4643         out += channels_out;
4644       }
4645     }
4646   }
4647   else if (format_out == RTAUDIO_SINT32) {
4648     INT32 *out = (INT32 *)output;
4649     if (format_in == RTAUDIO_SINT8) {
4650       signed char *in = (signed char *)input;
4651       for (int i=0; i<stream->bufferSize; i++) {
4652         for (j=0; j<channels; j++) {
4653           out[offset_out[j]] = (INT32) in[offset_in[j]];
4654           out[offset_out[j]] <<= 24;
4655         }
4656         in += channels_in;
4657         out += channels_out;
4658       }
4659     }
4660     else if (format_in == RTAUDIO_SINT16) {
4661       INT16 *in = (INT16 *)input;
4662       for (int i=0; i<stream->bufferSize; i++) {
4663         for (j=0; j<channels; j++) {
4664           out[offset_out[j]] = (INT32) in[offset_in[j]];
4665           out[offset_out[j]] <<= 16;
4666         }
4667         in += channels_in;
4668         out += channels_out;
4669       }
4670     }
4671     else if (format_in == RTAUDIO_SINT24) {
4672       INT32 *in = (INT32 *)input;
4673       for (int i=0; i<stream->bufferSize; i++) {
4674         for (j=0; j<channels; j++) {
4675           out[offset_out[j]] = (INT32) in[offset_in[j]];
4676         }
4677         in += channels_in;
4678         out += channels_out;
4679       }
4680     }
4681     else if (format_in == RTAUDIO_SINT32) {
4682       // Channel compensation and/or (de)interleaving only.
4683       INT32 *in = (INT32 *)input;
4684       for (int i=0; i<stream->bufferSize; i++) {
4685         for (j=0; j<channels; j++) {
4686           out[offset_out[j]] = in[offset_in[j]];
4687         }
4688         in += channels_in;
4689         out += channels_out;
4690       }
4691     }
4692     else if (format_in == RTAUDIO_FLOAT32) {
4693       FLOAT32 *in = (FLOAT32 *)input;
4694       for (int i=0; i<stream->bufferSize; i++) {
4695         for (j=0; j<channels; j++) {
4696           out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
4697         }
4698         in += channels_in;
4699         out += channels_out;
4700       }
4701     }
4702     else if (format_in == RTAUDIO_FLOAT64) {
4703       FLOAT64 *in = (FLOAT64 *)input;
4704       for (int i=0; i<stream->bufferSize; i++) {
4705         for (j=0; j<channels; j++) {
4706           out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
4707         }
4708         in += channels_in;
4709         out += channels_out;
4710       }
4711     }
4712   }
4713   else if (format_out == RTAUDIO_SINT24) {
4714     INT32 *out = (INT32 *)output;
4715     if (format_in == RTAUDIO_SINT8) {
4716       signed char *in = (signed char *)input;
4717       for (int i=0; i<stream->bufferSize; i++) {
4718         for (j=0; j<channels; j++) {
4719           out[offset_out[j]] = (INT32) in[offset_in[j]];
4720           out[offset_out[j]] <<= 24;
4721         }
4722         in += channels_in;
4723         out += channels_out;
4724       }
4725     }
4726     else if (format_in == RTAUDIO_SINT16) {
4727       INT16 *in = (INT16 *)input;
4728       for (int i=0; i<stream->bufferSize; i++) {
4729         for (j=0; j<channels; j++) {
4730           out[offset_out[j]] = (INT32) in[offset_in[j]];
4731           out[offset_out[j]] <<= 16;
4732         }
4733         in += channels_in;
4734         out += channels_out;
4735       }
4736     }
4737     else if (format_in == RTAUDIO_SINT24) {
4738       // Channel compensation and/or (de)interleaving only.
4739       INT32 *in = (INT32 *)input;
4740       for (int i=0; i<stream->bufferSize; i++) {
4741         for (j=0; j<channels; j++) {
4742           out[offset_out[j]] = in[offset_in[j]];
4743         }
4744         in += channels_in;
4745         out += channels_out;
4746       }
4747     }
4748     else if (format_in == RTAUDIO_SINT32) {
4749       INT32 *in = (INT32 *)input;
4750       for (int i=0; i<stream->bufferSize; i++) {
4751         for (j=0; j<channels; j++) {
4752           out[offset_out[j]] = (INT32) (in[offset_in[j]] & 0xffffff00);
4753         }
4754         in += channels_in;
4755         out += channels_out;
4756       }
4757     }
4758     else if (format_in == RTAUDIO_FLOAT32) {
4759       FLOAT32 *in = (FLOAT32 *)input;
4760       for (int i=0; i<stream->bufferSize; i++) {
4761         for (j=0; j<channels; j++) {
4762           out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
4763         }
4764         in += channels_in;
4765         out += channels_out;
4766       }
4767     }
4768     else if (format_in == RTAUDIO_FLOAT64) {
4769       FLOAT64 *in = (FLOAT64 *)input;
4770       for (int i=0; i<stream->bufferSize; i++) {
4771         for (j=0; j<channels; j++) {
4772           out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
4773         }
4774         in += channels_in;
4775         out += channels_out;
4776       }
4777     }
4778   }
4779   else if (format_out == RTAUDIO_SINT16) {
4780     INT16 *out = (INT16 *)output;
4781     if (format_in == RTAUDIO_SINT8) {
4782       signed char *in = (signed char *)input;
4783       for (int i=0; i<stream->bufferSize; i++) {
4784         for (j=0; j<channels; j++) {
4785           out[offset_out[j]] = (INT16) in[offset_in[j]];
4786           out[offset_out[j]] <<= 8;
4787         }
4788         in += channels_in;
4789         out += channels_out;
4790       }
4791     }
4792     else if (format_in == RTAUDIO_SINT16) {
4793       // Channel compensation and/or (de)interleaving only.
4794       INT16 *in = (INT16 *)input;
4795       for (int i=0; i<stream->bufferSize; i++) {
4796         for (j=0; j<channels; j++) {
4797           out[offset_out[j]] = in[offset_in[j]];
4798         }
4799         in += channels_in;
4800         out += channels_out;
4801       }
4802     }
4803     else if (format_in == RTAUDIO_SINT24) {
4804       INT32 *in = (INT32 *)input;
4805       for (int i=0; i<stream->bufferSize; i++) {
4806         for (j=0; j<channels; j++) {
4807           out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff);
4808         }
4809         in += channels_in;
4810         out += channels_out;
4811       }
4812     }
4813     else if (format_in == RTAUDIO_SINT32) {
4814       INT32 *in = (INT32 *)input;
4815       for (int i=0; i<stream->bufferSize; i++) {
4816         for (j=0; j<channels; j++) {
4817           out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff);
4818         }
4819         in += channels_in;
4820         out += channels_out;
4821       }
4822     }
4823     else if (format_in == RTAUDIO_FLOAT32) {
4824       FLOAT32 *in = (FLOAT32 *)input;
4825       for (int i=0; i<stream->bufferSize; i++) {
4826         for (j=0; j<channels; j++) {
4827           out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0);
4828         }
4829         in += channels_in;
4830         out += channels_out;
4831       }
4832     }
4833     else if (format_in == RTAUDIO_FLOAT64) {
4834       FLOAT64 *in = (FLOAT64 *)input;
4835       for (int i=0; i<stream->bufferSize; i++) {
4836         for (j=0; j<channels; j++) {
4837           out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0);
4838         }
4839         in += channels_in;
4840         out += channels_out;
4841       }
4842     }
4843   }
4844   else if (format_out == RTAUDIO_SINT8) {
4845     signed char *out = (signed char *)output;
4846     if (format_in == RTAUDIO_SINT8) {
4847       // Channel compensation and/or (de)interleaving only.
4848       signed char *in = (signed char *)input;
4849       for (int i=0; i<stream->bufferSize; i++) {
4850         for (j=0; j<channels; j++) {
4851           out[offset_out[j]] = in[offset_in[j]];
4852         }
4853         in += channels_in;
4854         out += channels_out;
4855       }
4856     }
4857     if (format_in == RTAUDIO_SINT16) {
4858       INT16 *in = (INT16 *)input;
4859       for (int i=0; i<stream->bufferSize; i++) {
4860         for (j=0; j<channels; j++) {
4861           out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 8) & 0x00ff);
4862         }
4863         in += channels_in;
4864         out += channels_out;
4865       }
4866     }
4867     else if (format_in == RTAUDIO_SINT24) {
4868       INT32 *in = (INT32 *)input;
4869       for (int i=0; i<stream->bufferSize; i++) {
4870         for (j=0; j<channels; j++) {
4871           out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff);
4872         }
4873         in += channels_in;
4874         out += channels_out;
4875       }
4876     }
4877     else if (format_in == RTAUDIO_SINT32) {
4878       INT32 *in = (INT32 *)input;
4879       for (int i=0; i<stream->bufferSize; i++) {
4880         for (j=0; j<channels; j++) {
4881           out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff);
4882         }
4883         in += channels_in;
4884         out += channels_out;
4885       }
4886     }
4887     else if (format_in == RTAUDIO_FLOAT32) {
4888       FLOAT32 *in = (FLOAT32 *)input;
4889       for (int i=0; i<stream->bufferSize; i++) {
4890         for (j=0; j<channels; j++) {
4891           out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0);
4892         }
4893         in += channels_in;
4894         out += channels_out;
4895       }
4896     }
4897     else if (format_in == RTAUDIO_FLOAT64) {
4898       FLOAT64 *in = (FLOAT64 *)input;
4899       for (int i=0; i<stream->bufferSize; i++) {
4900         for (j=0; j<channels; j++) {
4901           out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0);
4902         }
4903         in += channels_in;
4904         out += channels_out;
4905       }
4906     }
4907   }
4908 }
4909
4910 void RtAudio :: byteSwapBuffer(char *buffer, int samples, RTAUDIO_FORMAT format)
4911 {
4912   register char val;
4913   register char *ptr;
4914
4915   ptr = buffer;
4916   if (format == RTAUDIO_SINT16) {
4917     for (int i=0; i<samples; i++) {
4918       // Swap 1st and 2nd bytes.
4919       val = *(ptr);
4920       *(ptr) = *(ptr+1);
4921       *(ptr+1) = val;
4922
4923       // Increment 2 bytes.
4924       ptr += 2;
4925     }
4926   }
4927   else if (format == RTAUDIO_SINT24 ||
4928            format == RTAUDIO_SINT32 ||
4929            format == RTAUDIO_FLOAT32) {
4930     for (int i=0; i<samples; i++) {
4931       // Swap 1st and 4th bytes.
4932       val = *(ptr);
4933       *(ptr) = *(ptr+3);
4934       *(ptr+3) = val;
4935
4936       // Swap 2nd and 3rd bytes.
4937       ptr += 1;
4938       val = *(ptr);
4939       *(ptr) = *(ptr+1);
4940       *(ptr+1) = val;
4941
4942       // Increment 4 bytes.
4943       ptr += 4;
4944     }
4945   }
4946   else if (format == RTAUDIO_FLOAT64) {
4947     for (int i=0; i<samples; i++) {
4948       // Swap 1st and 8th bytes
4949       val = *(ptr);
4950       *(ptr) = *(ptr+7);
4951       *(ptr+7) = val;
4952
4953       // Swap 2nd and 7th bytes
4954       ptr += 1;
4955       val = *(ptr);
4956       *(ptr) = *(ptr+5);
4957       *(ptr+5) = val;
4958
4959       // Swap 3rd and 6th bytes
4960       ptr += 1;
4961       val = *(ptr);
4962       *(ptr) = *(ptr+3);
4963       *(ptr+3) = val;
4964
4965       // Swap 4th and 5th bytes
4966       ptr += 1;
4967       val = *(ptr);
4968       *(ptr) = *(ptr+1);
4969       *(ptr+1) = val;
4970
4971       // Increment 8 bytes.
4972       ptr += 8;
4973     }
4974   }
4975 }
4976
4977
4978 // *************************************************** //
4979 //
4980 // RtAudioError class definition.
4981 //
4982 // *************************************************** //
4983
4984 RtAudioError :: RtAudioError(const char *p, TYPE tipe)
4985 {
4986   type = tipe;
4987   strncpy(error_message, p, 256);
4988 }
4989
4990 RtAudioError :: ~RtAudioError()
4991 {
4992 }
4993
4994 void RtAudioError :: printMessage()
4995 {
4996   printf("\n%s\n\n", error_message);
4997 }