RtAudio.cpp

Go to the documentation of this file.
00001 /******************************************/
00002 /*
00003   RtAudio - realtime sound I/O C++ class
00004   by Gary P. Scavone, 2001-2002.
00005 */
00006 /******************************************/
00007 
00008 #include "RtAudio.h"
00009 #include <vector>
00010 #include <stdio.h>
00011 
00012 // Static variable definitions.
00013 const unsigned int RtAudio :: SAMPLE_RATES[] = {
00014   4000, 5512, 8000, 9600, 11025, 16000, 22050,
00015   32000, 44100, 48000, 88200, 96000, 176400, 192000
00016 };
00017 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT8 = 1;
00018 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT16 = 2;
00019 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT24 = 4;
00020 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT32 = 8;
00021 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT32 = 16;
00022 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT64 = 32;
00023 
00024 #if defined(__WINDOWS_DS__)
00025   #define MUTEX_INITIALIZE(A) InitializeCriticalSection(A)
00026   #define MUTEX_LOCK(A)       EnterCriticalSection(A)
00027   #define MUTEX_UNLOCK(A)     LeaveCriticalSection(A)
00028   typedef unsigned THREAD_RETURN;
00029   typedef unsigned (__stdcall THREAD_FUNCTION)(void *);
00030 #else // pthread API
00031   #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL)
00032   #define MUTEX_LOCK(A)       pthread_mutex_lock(A)
00033   #define MUTEX_UNLOCK(A)     pthread_mutex_unlock(A)
00034   typedef void * THREAD_RETURN;
00035 #endif
00036 
00037 // *************************************************** //
00038 //
00039 // Public common (OS-independent) methods.
00040 //
00041 // *************************************************** //
00042 
00043 RtAudio :: RtAudio()
00044 {
00045   initialize();
00046 
00047   if (nDevices <= 0) {
00048     sprintf(message, "RtAudio: no audio devices found!");
00049     error(RtError::NO_DEVICES_FOUND);
00050  }
00051 }
00052 
00053 RtAudio :: RtAudio(int *streamId,
00054                    int outputDevice, int outputChannels,
00055                    int inputDevice, int inputChannels,
00056                    RTAUDIO_FORMAT format, int sampleRate,
00057                    int *bufferSize, int numberOfBuffers)
00058 {
00059   initialize();
00060 
00061   if (nDevices <= 0) {
00062     sprintf(message, "RtAudio: no audio devices found!");
00063     error(RtError::NO_DEVICES_FOUND);
00064   }
00065 
00066   try {
00067     *streamId = openStream(outputDevice, outputChannels, inputDevice, inputChannels,
00068                            format, sampleRate, bufferSize, numberOfBuffers);
00069   }
00070   catch (RtError &exception) {
00071     // deallocate the RTAUDIO_DEVICE structures
00072     if (devices) free(devices);
00073     error(exception.getType());
00074   }
00075 }
00076 
00077 RtAudio :: ~RtAudio()
00078 {
00079   // close any existing streams
00080   while ( streams.size() )
00081     closeStream( streams.begin()->first );
00082 
00083   // deallocate the RTAUDIO_DEVICE structures
00084   if (devices) free(devices);
00085 }
00086 
00087 int RtAudio :: openStream(int outputDevice, int outputChannels,
00088                           int inputDevice, int inputChannels,
00089                           RTAUDIO_FORMAT format, int sampleRate,
00090                           int *bufferSize, int numberOfBuffers)
00091 {
00092   static int streamKey = 0; // Unique stream identifier ... OK for multiple instances.
00093 
00094   if (outputChannels < 1 && inputChannels < 1) {
00095     sprintf(message,"RtAudio: one or both 'channel' parameters must be greater than zero.");
00096     error(RtError::INVALID_PARAMETER);
00097   }
00098 
00099   if ( formatBytes(format) == 0 ) {
00100     sprintf(message,"RtAudio: 'format' parameter value is undefined.");
00101     error(RtError::INVALID_PARAMETER);
00102   }
00103 
00104   if ( outputChannels > 0 ) {
00105     if (outputDevice >= nDevices || outputDevice < 0) {
00106       sprintf(message,"RtAudio: 'outputDevice' parameter value (%d) is invalid.", outputDevice);
00107       error(RtError::INVALID_PARAMETER);
00108     }
00109   }
00110 
00111   if ( inputChannels > 0 ) {
00112     if (inputDevice >= nDevices || inputDevice < 0) {
00113       sprintf(message,"RtAudio: 'inputDevice' parameter value (%d) is invalid.", inputDevice);
00114       error(RtError::INVALID_PARAMETER);
00115     }
00116   }
00117 
00118   // Allocate a new stream structure.
00119   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) calloc(1, sizeof(RTAUDIO_STREAM));
00120   if (stream == NULL) {
00121     sprintf(message, "RtAudio: memory allocation error!");
00122     error(RtError::MEMORY_ERROR);
00123   }
00124   streams[++streamKey] = (void *) stream;
00125   stream->mode = UNINITIALIZED;
00126   MUTEX_INITIALIZE(&stream->mutex);
00127 
00128   bool result = SUCCESS;
00129   int device;
00130   STREAM_MODE mode;
00131   int channels;
00132   if ( outputChannels > 0 ) {
00133 
00134     device = outputDevice;
00135     mode = PLAYBACK;
00136     channels = outputChannels;
00137 
00138     if (device == 0) { // Try default device first.
00139       for (int i=0; i<nDevices; i++) {
00140         if (devices[i].probed == false) {
00141           // If the device wasn't successfully probed before, try it
00142           // again now.
00143           clearDeviceInfo(&devices[i]);
00144           probeDeviceInfo(&devices[i]);
00145           if (devices[i].probed == false)
00146             continue;
00147         }
00148         result = probeDeviceOpen(i, stream, mode, channels, sampleRate,
00149                                  format, bufferSize, numberOfBuffers);
00150         if (result == SUCCESS)
00151           break;
00152       }
00153     }
00154     else {
00155       result = probeDeviceOpen(device, stream, mode, channels, sampleRate,
00156                                format, bufferSize, numberOfBuffers);
00157     }
00158   }
00159 
00160   if ( inputChannels > 0 && result == SUCCESS ) {
00161 
00162     device = inputDevice;
00163     mode = RECORD;
00164     channels = inputChannels;
00165 
00166     if (device == 0) { // Try default device first.
00167       for (int i=0; i<nDevices; i++) {
00168         if (devices[i].probed == false) {
00169           // If the device wasn't successfully probed before, try it
00170           // again now.
00171           clearDeviceInfo(&devices[i]);
00172           probeDeviceInfo(&devices[i]);
00173           if (devices[i].probed == false)
00174             continue;
00175         }
00176         result = probeDeviceOpen(i, stream, mode, channels, sampleRate,
00177                                  format, bufferSize, numberOfBuffers);
00178         if (result == SUCCESS)
00179           break;
00180       }
00181     }
00182     else {
00183       result = probeDeviceOpen(device, stream, mode, channels, sampleRate,
00184                                format, bufferSize, numberOfBuffers);
00185     }
00186   }
00187 
00188   if ( result == SUCCESS )
00189     return streamKey;
00190 
00191   // If we get here, all attempted probes failed.  Close any opened
00192   // devices and delete the allocated stream.
00193   closeStream(streamKey);
00194   sprintf(message,"RtAudio: no devices found for given parameters.");
00195   error(RtError::INVALID_PARAMETER);
00196 
00197   return -1;
00198 }
00199 
00200 int RtAudio :: getDeviceCount(void)
00201 {
00202   return nDevices;
00203 }
00204 
00205 void RtAudio :: getDeviceInfo(int device, RTAUDIO_DEVICE *info)
00206 {
00207   if (device >= nDevices || device < 0) {
00208     sprintf(message, "RtAudio: invalid device specifier (%d)!", device);
00209     error(RtError::INVALID_DEVICE);
00210   }
00211 
00212   // If the device wasn't successfully probed before, try it again.
00213   if (devices[device].probed == false) {
00214     clearDeviceInfo(&devices[device]);
00215     probeDeviceInfo(&devices[device]);
00216   }
00217 
00218   // Clear the info structure.
00219   memset(info, 0, sizeof(RTAUDIO_DEVICE));
00220 
00221   strncpy(info->name, devices[device].name, 128);
00222   info->probed = devices[device].probed;
00223   if ( info->probed == true ) {
00224     info->maxOutputChannels = devices[device].maxOutputChannels;
00225     info->maxInputChannels = devices[device].maxInputChannels;
00226     info->maxDuplexChannels = devices[device].maxDuplexChannels;
00227     info->minOutputChannels = devices[device].minOutputChannels;
00228     info->minInputChannels = devices[device].minInputChannels;
00229     info->minDuplexChannels = devices[device].minDuplexChannels;
00230     info->hasDuplexSupport = devices[device].hasDuplexSupport;
00231     info->nSampleRates = devices[device].nSampleRates;
00232     if (info->nSampleRates == -1) {
00233       info->sampleRates[0] = devices[device].sampleRates[0];
00234       info->sampleRates[1] = devices[device].sampleRates[1];
00235     }
00236     else {
00237       for (int i=0; i<info->nSampleRates; i++)
00238         info->sampleRates[i] = devices[device].sampleRates[i];
00239     }
00240     info->nativeFormats = devices[device].nativeFormats;
00241   }
00242 
00243   return;
00244 }
00245 
00246 char * const RtAudio :: getStreamBuffer(int streamId)
00247 {
00248   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
00249 
00250   return stream->userBuffer;
00251 }
00252 
00253 // This global structure is used to pass information to the thread
00254 // function.  I tried other methods but had intermittent errors due to
00255 // variable persistence during thread startup.
00256 struct {
00257   RtAudio *object;
00258   int streamId;
00259 } thread_info;
00260 
00261 extern "C" THREAD_RETURN THREAD_TYPE callbackHandler(void * ptr);
00262 
00263 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
00264 {
00265   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
00266 
00267   stream->callback = callback;
00268   stream->userData = userData;
00269   stream->usingCallback = true;
00270   thread_info.object = this;
00271   thread_info.streamId = streamId;
00272 
00273   int err = 0;
00274 #if defined(__WINDOWS_DS__)
00275   unsigned thread_id;
00276   stream->thread = _beginthreadex(NULL, 0, &callbackHandler,
00277                                   &stream->usingCallback, 0, &thread_id);
00278   if (stream->thread == 0) err = -1;
00279   // When spawning multiple threads in quick succession, it appears to be
00280   // necessary to wait a bit for each to initialize ... another windism!
00281   Sleep(1);
00282 #else
00283   err = pthread_create(&stream->thread, NULL, callbackHandler, &stream->usingCallback);
00284 #endif
00285 
00286   if (err) {
00287     stream->usingCallback = false;
00288     sprintf(message, "RtAudio: error starting callback thread!");
00289     error(RtError::THREAD_ERROR);
00290   }
00291 }
00292 
00293 // *************************************************** //
00294 //
00295 // OS/API-specific methods.
00296 //
00297 // *************************************************** //
00298 
00299 #if defined(__LINUX_ALSA__)
00300 
00301 #define MAX_DEVICES 16
00302 
00303 void RtAudio :: initialize(void)
00304 {
00305   int card, result, device;
00306   char name[32];
00307   char deviceNames[MAX_DEVICES][32];
00308   snd_ctl_t *handle;
00309   snd_ctl_card_info_t *info;
00310   snd_ctl_card_info_alloca(&info);
00311 
00312   // Count cards and devices
00313   nDevices = 0;
00314   card = -1;
00315   snd_card_next(&card);
00316   while ( card >= 0 ) {
00317     sprintf(name, "hw:%d", card);
00318     result = snd_ctl_open(&handle, name, 0);
00319     if (result < 0) {
00320       sprintf(message, "RtAudio: ALSA control open (%i): %s.", card, snd_strerror(result));
00321       error(RtError::WARNING);
00322       goto next_card;
00323                 }
00324     result = snd_ctl_card_info(handle, info);
00325                 if (result < 0) {
00326       sprintf(message, "RtAudio: ALSA control hardware info (%i): %s.", card, snd_strerror(result));
00327       error(RtError::WARNING);
00328       goto next_card;
00329                 }
00330                 device = -1;
00331                 while (1) {
00332       result = snd_ctl_pcm_next_device(handle, &device);
00333                         if (result < 0) {
00334         sprintf(message, "RtAudio: ALSA control next device (%i): %s.", card, snd_strerror(result));
00335         error(RtError::WARNING);
00336         break;
00337       }
00338                         if (device < 0)
00339         break;
00340       sprintf( deviceNames[nDevices++], "hw:%d,%d", card, device );
00341       if ( nDevices > MAX_DEVICES ) break;
00342     }
00343     if ( nDevices > MAX_DEVICES ) break;
00344   next_card:
00345     snd_ctl_close(handle);
00346     snd_card_next(&card);
00347   }
00348 
00349   if (nDevices == 0) return;
00350 
00351   //  Allocate the RTAUDIO_DEVICE structures.
00352   devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
00353   if (devices == NULL) {
00354     sprintf(message, "RtAudio: memory allocation error!");
00355     error(RtError::MEMORY_ERROR);
00356   }
00357 
00358   // Write device ascii identifiers to device structures and then
00359   // probe the device capabilities.
00360   for (int i=0; i<nDevices; i++) {
00361     strncpy(devices[i].name, deviceNames[i], 32);
00362     probeDeviceInfo(&devices[i]);
00363   }
00364 
00365   return;
00366 }
00367 
00368 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
00369 {
00370   int err;
00371   int open_mode = SND_PCM_ASYNC;
00372   snd_pcm_t *handle;
00373   snd_pcm_stream_t stream;
00374 
00375   // First try for playback
00376   stream = SND_PCM_STREAM_PLAYBACK;
00377   err = snd_pcm_open(&handle, info->name, stream, open_mode);
00378   if (err < 0) {
00379     sprintf(message, "RtAudio: ALSA pcm playback open (%s): %s.",
00380             info->name, snd_strerror(err));
00381     error(RtError::WARNING);
00382     goto capture_probe;
00383   }
00384 
00385   snd_pcm_hw_params_t *params;
00386   snd_pcm_hw_params_alloca(&params);
00387 
00388   // We have an open device ... allocate the parameter structure.
00389   err = snd_pcm_hw_params_any(handle, params);
00390   if (err < 0) {
00391     snd_pcm_close(handle);
00392     sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.",
00393             info->name, snd_strerror(err));
00394     error(RtError::WARNING);
00395     goto capture_probe;
00396   }
00397 
00398   // Get output channel information.
00399   info->minOutputChannels = snd_pcm_hw_params_get_channels_min(params);
00400   info->maxOutputChannels = snd_pcm_hw_params_get_channels_max(params);
00401 
00402   snd_pcm_close(handle);
00403 
00404  capture_probe:
00405   // Now try for capture
00406   stream = SND_PCM_STREAM_CAPTURE;
00407   err = snd_pcm_open(&handle, info->name, stream, open_mode);
00408   if (err < 0) {
00409     sprintf(message, "RtAudio: ALSA pcm capture open (%s): %s.",
00410             info->name, snd_strerror(err));
00411     error(RtError::WARNING);
00412     if (info->maxOutputChannels == 0)
00413       // didn't open for playback either ... device invalid
00414       return;
00415     goto probe_parameters;
00416   }
00417 
00418   // We have an open capture device ... allocate the parameter structure.
00419   err = snd_pcm_hw_params_any(handle, params);
00420   if (err < 0) {
00421     snd_pcm_close(handle);
00422     sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.",
00423             info->name, snd_strerror(err));
00424     error(RtError::WARNING);
00425     if (info->maxOutputChannels > 0)
00426       goto probe_parameters;
00427     else
00428       return;
00429   }
00430 
00431   // Get input channel information.
00432   info->minInputChannels = snd_pcm_hw_params_get_channels_min(params);
00433   info->maxInputChannels = snd_pcm_hw_params_get_channels_max(params);
00434 
00435   // If device opens for both playback and capture, we determine the channels.
00436   if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
00437     goto probe_parameters;
00438 
00439   info->hasDuplexSupport = true;
00440   info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
00441     info->maxInputChannels : info->maxOutputChannels;
00442   info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
00443     info->minInputChannels : info->minOutputChannels;
00444 
00445   snd_pcm_close(handle);
00446 
00447  probe_parameters:
00448   // At this point, we just need to figure out the supported data
00449   // formats and sample rates.  We'll proceed by opening the device in
00450   // the direction with the maximum number of channels, or playback if
00451   // they are equal.  This might limit our sample rate options, but so
00452   // be it.
00453 
00454   if (info->maxOutputChannels >= info->maxInputChannels)
00455     stream = SND_PCM_STREAM_PLAYBACK;
00456   else
00457     stream = SND_PCM_STREAM_CAPTURE;
00458 
00459   err = snd_pcm_open(&handle, info->name, stream, open_mode);
00460   if (err < 0) {
00461     sprintf(message, "RtAudio: ALSA pcm (%s) won't reopen during probe: %s.",
00462             info->name, snd_strerror(err));
00463     error(RtError::WARNING);
00464     return;
00465   }
00466 
00467   // We have an open device ... allocate the parameter structure.
00468   err = snd_pcm_hw_params_any(handle, params);
00469   if (err < 0) {
00470     snd_pcm_close(handle);
00471     sprintf(message, "RtAudio: ALSA hardware reopen probe error (%s): %s.",
00472             info->name, snd_strerror(err));
00473     error(RtError::WARNING);
00474     return;
00475   }
00476 
00477   // Test a non-standard sample rate to see if continuous rate is supported.
00478   int dir = 0;
00479   if (snd_pcm_hw_params_test_rate(handle, params, 35500, dir) == 0) {
00480     // It appears that continuous sample rate support is available.
00481     info->nSampleRates = -1;
00482     info->sampleRates[0] = snd_pcm_hw_params_get_rate_min(params, &dir);
00483     info->sampleRates[1] = snd_pcm_hw_params_get_rate_max(params, &dir);
00484   }
00485   else {
00486     // No continuous rate support ... test our discrete set of sample rate values.
00487     info->nSampleRates = 0;
00488     for (int i=0; i<MAX_SAMPLE_RATES; i++) {
00489       if (snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0) {
00490         info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
00491         info->nSampleRates++;
00492       }
00493     }
00494     if (info->nSampleRates == 0) {
00495       snd_pcm_close(handle);
00496       return;
00497     }
00498   }
00499 
00500   // Probe the supported data formats ... we don't care about endian-ness just yet
00501   snd_pcm_format_t format;
00502   info->nativeFormats = 0;
00503   format = SND_PCM_FORMAT_S8;
00504   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
00505     info->nativeFormats |= RTAUDIO_SINT8;
00506   format = SND_PCM_FORMAT_S16;
00507   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
00508     info->nativeFormats |= RTAUDIO_SINT16;
00509   format = SND_PCM_FORMAT_S24;
00510   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
00511     info->nativeFormats |= RTAUDIO_SINT24;
00512   format = SND_PCM_FORMAT_S32;
00513   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
00514     info->nativeFormats |= RTAUDIO_SINT32;
00515   format = SND_PCM_FORMAT_FLOAT;
00516   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
00517     info->nativeFormats |= RTAUDIO_FLOAT32;
00518   format = SND_PCM_FORMAT_FLOAT64;
00519   if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
00520     info->nativeFormats |= RTAUDIO_FLOAT64;
00521 
00522   // Check that we have at least one supported format
00523   if (info->nativeFormats == 0) {
00524     snd_pcm_close(handle);
00525     sprintf(message, "RtAudio: ALSA PCM device (%s) data format not supported by RtAudio.",
00526             info->name);
00527     error(RtError::WARNING);
00528     return;
00529   }
00530 
00531   // That's all ... close the device and return
00532   snd_pcm_close(handle);
00533   info->probed = true;
00534   return;
00535 }
00536 
00537 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
00538                                 STREAM_MODE mode, int channels, 
00539                                 int sampleRate, RTAUDIO_FORMAT format,
00540                                 int *bufferSize, int numberOfBuffers)
00541 {
00542 #if defined(RTAUDIO_DEBUG)
00543   snd_output_t *out;
00544   snd_output_stdio_attach(&out, stderr, 0);
00545 #endif
00546 
00547   // I'm not using the "plug" interface ... too much inconsistent behavior.
00548   const char *name = devices[device].name;
00549 
00550   snd_pcm_stream_t alsa_stream;
00551   if (mode == PLAYBACK)
00552     alsa_stream = SND_PCM_STREAM_PLAYBACK;
00553   else
00554     alsa_stream = SND_PCM_STREAM_CAPTURE;
00555 
00556   int err;
00557   snd_pcm_t *handle;
00558   int alsa_open_mode = SND_PCM_ASYNC;
00559   err = snd_pcm_open(&handle, name, alsa_stream, alsa_open_mode);
00560   if (err < 0) {
00561     sprintf(message,"RtAudio: ALSA pcm device (%s) won't open: %s.",
00562             name, snd_strerror(err));
00563     error(RtError::WARNING);
00564     return FAILURE;
00565   }
00566 
00567   // Fill the parameter structure.
00568   snd_pcm_hw_params_t *hw_params;
00569   snd_pcm_hw_params_alloca(&hw_params);
00570   err = snd_pcm_hw_params_any(handle, hw_params);
00571   if (err < 0) {
00572     snd_pcm_close(handle);
00573     sprintf(message, "RtAudio: ALSA error getting parameter handle (%s): %s.",
00574             name, snd_strerror(err));
00575     error(RtError::WARNING);
00576     return FAILURE;
00577   }
00578 
00579 #if defined(RTAUDIO_DEBUG)
00580   fprintf(stderr, "\nRtAudio: ALSA dump hardware params just after device open:\n\n");
00581   snd_pcm_hw_params_dump(hw_params, out);
00582 #endif
00583 
00584   // Set access ... try interleaved access first, then non-interleaved
00585   err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
00586   if (err < 0) {
00587     // No interleave support ... try non-interleave.
00588                 err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED);
00589     if (err < 0) {
00590       snd_pcm_close(handle);
00591       sprintf(message, "RtAudio: ALSA error setting access ( (%s): %s.",
00592               name, snd_strerror(err));
00593       error(RtError::WARNING);
00594       return FAILURE;
00595     }
00596     stream->deInterleave[mode] = true;
00597   }
00598 
00599   // Determine how to set the device format.
00600   stream->userFormat = format;
00601   snd_pcm_format_t device_format;
00602 
00603   if (format == RTAUDIO_SINT8)
00604     device_format = SND_PCM_FORMAT_S8;
00605   else if (format == RTAUDIO_SINT16)
00606     device_format = SND_PCM_FORMAT_S16;
00607   else if (format == RTAUDIO_SINT24)
00608     device_format = SND_PCM_FORMAT_S24;
00609   else if (format == RTAUDIO_SINT32)
00610     device_format = SND_PCM_FORMAT_S32;
00611   else if (format == RTAUDIO_FLOAT32)
00612     device_format = SND_PCM_FORMAT_FLOAT;
00613   else if (format == RTAUDIO_FLOAT64)
00614     device_format = SND_PCM_FORMAT_FLOAT64;
00615 
00616   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
00617     stream->deviceFormat[mode] = format;
00618     goto set_format;
00619   }
00620 
00621   // The user requested format is not natively supported by the device.
00622   device_format = SND_PCM_FORMAT_FLOAT64;
00623   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
00624     stream->deviceFormat[mode] = RTAUDIO_FLOAT64;
00625     goto set_format;
00626   }
00627 
00628   device_format = SND_PCM_FORMAT_FLOAT;
00629   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
00630     stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
00631     goto set_format;
00632   }
00633 
00634   device_format = SND_PCM_FORMAT_S32;
00635   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
00636     stream->deviceFormat[mode] = RTAUDIO_SINT32;
00637     goto set_format;
00638   }
00639 
00640   device_format = SND_PCM_FORMAT_S24;
00641   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
00642     stream->deviceFormat[mode] = RTAUDIO_SINT24;
00643     goto set_format;
00644   }
00645 
00646   device_format = SND_PCM_FORMAT_S16;
00647   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
00648     stream->deviceFormat[mode] = RTAUDIO_SINT16;
00649     goto set_format;
00650   }
00651 
00652   device_format = SND_PCM_FORMAT_S8;
00653   if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
00654     stream->deviceFormat[mode] = RTAUDIO_SINT8;
00655     goto set_format;
00656   }
00657 
00658   // If we get here, no supported format was found.
00659   sprintf(message,"RtAudio: ALSA pcm device (%s) data format not supported by RtAudio.", name);
00660   snd_pcm_close(handle);
00661   error(RtError::WARNING);
00662   return FAILURE;
00663 
00664  set_format:
00665   err = snd_pcm_hw_params_set_format(handle, hw_params, device_format);
00666   if (err < 0) {
00667     snd_pcm_close(handle);
00668     sprintf(message, "RtAudio: ALSA error setting format (%s): %s.",
00669             name, snd_strerror(err));
00670     error(RtError::WARNING);
00671     return FAILURE;
00672   }
00673 
00674   // Determine whether byte-swaping is necessary.
00675   stream->doByteSwap[mode] = false;
00676   if (device_format != SND_PCM_FORMAT_S8) {
00677     err = snd_pcm_format_cpu_endian(device_format);
00678     if (err == 0)
00679       stream->doByteSwap[mode] = true;
00680     else if (err < 0) {
00681       snd_pcm_close(handle);
00682       sprintf(message, "RtAudio: ALSA error getting format endian-ness (%s): %s.",
00683               name, snd_strerror(err));
00684       error(RtError::WARNING);
00685       return FAILURE;
00686     }
00687   }
00688 
00689   // Determine the number of channels for this device.  We support a possible
00690   // minimum device channel number > than the value requested by the user.
00691   stream->nUserChannels[mode] = channels;
00692   int device_channels = snd_pcm_hw_params_get_channels_max(hw_params);
00693   if (device_channels < channels) {
00694     snd_pcm_close(handle);
00695     sprintf(message, "RtAudio: channels (%d) not supported by device (%s).",
00696             channels, name);
00697     error(RtError::WARNING);
00698     return FAILURE;
00699   }
00700 
00701   device_channels = snd_pcm_hw_params_get_channels_min(hw_params);
00702   if (device_channels < channels) device_channels = channels;
00703   stream->nDeviceChannels[mode] = device_channels;
00704 
00705   // Set the device channels.
00706   err = snd_pcm_hw_params_set_channels(handle, hw_params, device_channels);
00707   if (err < 0) {
00708     snd_pcm_close(handle);
00709     sprintf(message, "RtAudio: ALSA error setting channels (%d) on device (%s): %s.",
00710             device_channels, name, snd_strerror(err));
00711     error(RtError::WARNING);
00712     return FAILURE;
00713   }
00714 
00715   // Set the sample rate.
00716   err = snd_pcm_hw_params_set_rate(handle, hw_params, (unsigned int)sampleRate, 0);
00717   if (err < 0) {
00718     snd_pcm_close(handle);
00719     sprintf(message, "RtAudio: ALSA error setting sample rate (%d) on device (%s): %s.",
00720             sampleRate, name, snd_strerror(err));
00721     error(RtError::WARNING);
00722     return FAILURE;
00723   }
00724 
00725   // Set the buffer number, which in ALSA is referred to as the "period".
00726   int dir;
00727   int periods = numberOfBuffers;
00728   // Even though the hardware might allow 1 buffer, it won't work reliably.
00729   if (periods < 2) periods = 2;
00730   err = snd_pcm_hw_params_get_periods_min(hw_params, &dir);
00731   if (err > periods) periods = err;
00732 
00733   err = snd_pcm_hw_params_set_periods(handle, hw_params, periods, 0);
00734   if (err < 0) {
00735     snd_pcm_close(handle);
00736     sprintf(message, "RtAudio: ALSA error setting periods (%s): %s.",
00737             name, snd_strerror(err));
00738     error(RtError::WARNING);
00739     return FAILURE;
00740   }
00741 
00742   // Set the buffer (or period) size.
00743   err = snd_pcm_hw_params_get_period_size_min(hw_params, &dir);
00744   if (err > *bufferSize) *bufferSize = err;
00745 
00746   err = snd_pcm_hw_params_set_period_size(handle, hw_params, *bufferSize, 0);
00747   if (err < 0) {
00748     snd_pcm_close(handle);
00749     sprintf(message, "RtAudio: ALSA error setting period size (%s): %s.",
00750             name, snd_strerror(err));
00751     error(RtError::WARNING);
00752     return FAILURE;
00753   }
00754 
00755   stream->bufferSize = *bufferSize;
00756 
00757   // Install the hardware configuration
00758   err = snd_pcm_hw_params(handle, hw_params);
00759   if (err < 0) {
00760     snd_pcm_close(handle);
00761     sprintf(message, "RtAudio: ALSA error installing hardware configuration (%s): %s.",
00762             name, snd_strerror(err));
00763     error(RtError::WARNING);
00764     return FAILURE;
00765   }
00766 
00767 #if defined(RTAUDIO_DEBUG)
00768   fprintf(stderr, "\nRtAudio: ALSA dump hardware params after installation:\n\n");
00769   snd_pcm_hw_params_dump(hw_params, out);
00770 #endif
00771 
00772   /*
00773   // Install the software configuration
00774   snd_pcm_sw_params_t *sw_params = NULL;
00775   snd_pcm_sw_params_alloca(&sw_params);
00776   snd_pcm_sw_params_current(handle, sw_params);
00777   err = snd_pcm_sw_params(handle, sw_params);
00778   if (err < 0) {
00779     snd_pcm_close(handle);
00780     sprintf(message, "RtAudio: ALSA error installing software configuration (%s): %s.",
00781             name, snd_strerror(err));
00782     error(RtError::WARNING);
00783     return FAILURE;
00784   }
00785   */
00786 
00787   // Set handle and flags for buffer conversion
00788   stream->handle[mode] = handle;
00789   stream->doConvertBuffer[mode] = false;
00790   if (stream->userFormat != stream->deviceFormat[mode])
00791     stream->doConvertBuffer[mode] = true;
00792   if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
00793     stream->doConvertBuffer[mode] = true;
00794   if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode])
00795     stream->doConvertBuffer[mode] = true;
00796 
00797   // Allocate necessary internal buffers
00798   if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
00799 
00800     long buffer_bytes;
00801     if (stream->nUserChannels[0] >= stream->nUserChannels[1])
00802       buffer_bytes = stream->nUserChannels[0];
00803     else
00804       buffer_bytes = stream->nUserChannels[1];
00805 
00806     buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
00807     if (stream->userBuffer) free(stream->userBuffer);
00808     stream->userBuffer = (char *) calloc(buffer_bytes, 1);
00809     if (stream->userBuffer == NULL)
00810       goto memory_error;
00811   }
00812 
00813   if ( stream->doConvertBuffer[mode] ) {
00814 
00815     long buffer_bytes;
00816     bool makeBuffer = true;
00817     if ( mode == PLAYBACK )
00818       buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
00819     else { // mode == RECORD
00820       buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
00821       if ( stream->mode == PLAYBACK ) {
00822         long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
00823         if ( buffer_bytes > bytes_out )
00824           buffer_bytes = (buffer_bytes > bytes_out) ? buffer_bytes : bytes_out;
00825         else
00826           makeBuffer = false;
00827       }
00828     }
00829 
00830     if ( makeBuffer ) {
00831       buffer_bytes *= *bufferSize;
00832       if (stream->deviceBuffer) free(stream->deviceBuffer);
00833       stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
00834       if (stream->deviceBuffer == NULL)
00835         goto memory_error;
00836     }
00837   }
00838 
00839   stream->device[mode] = device;
00840   stream->state = STREAM_STOPPED;
00841   if ( stream->mode == PLAYBACK && mode == RECORD )
00842     // We had already set up an output stream.
00843     stream->mode = DUPLEX;
00844   else
00845     stream->mode = mode;
00846   stream->nBuffers = periods;
00847   stream->sampleRate = sampleRate;
00848 
00849   return SUCCESS;
00850 
00851  memory_error:
00852   if (stream->handle[0]) {
00853     snd_pcm_close(stream->handle[0]);
00854     stream->handle[0] = 0;
00855   }
00856   if (stream->handle[1]) {
00857     snd_pcm_close(stream->handle[1]);
00858     stream->handle[1] = 0;
00859   }
00860   if (stream->userBuffer) {
00861     free(stream->userBuffer);
00862     stream->userBuffer = 0;
00863   }
00864   sprintf(message, "RtAudio: ALSA error allocating buffer memory (%s).", name);
00865   error(RtError::WARNING);
00866   return FAILURE;
00867 }
00868 
00869 void RtAudio :: cancelStreamCallback(int streamId)
00870 {
00871   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
00872 
00873   if (stream->usingCallback) {
00874     stream->usingCallback = false;
00875     pthread_cancel(stream->thread);
00876     pthread_join(stream->thread, NULL);
00877     stream->thread = 0;
00878     stream->callback = NULL;
00879     stream->userData = NULL;
00880   }
00881 }
00882 
00883 void RtAudio :: closeStream(int streamId)
00884 {
00885   // We don't want an exception to be thrown here because this
00886   // function is called by our class destructor.  So, do our own
00887   // streamId check.
00888   if ( streams.find( streamId ) == streams.end() ) {
00889     sprintf(message, "RtAudio: invalid stream identifier!");
00890     error(RtError::WARNING);
00891     return;
00892   }
00893 
00894   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
00895 
00896   if (stream->usingCallback) {
00897     pthread_cancel(stream->thread);
00898     pthread_join(stream->thread, NULL);
00899   }
00900 
00901   if (stream->state == STREAM_RUNNING) {
00902     if (stream->mode == PLAYBACK || stream->mode == DUPLEX)
00903       snd_pcm_drop(stream->handle[0]);
00904     if (stream->mode == RECORD || stream->mode == DUPLEX)
00905       snd_pcm_drop(stream->handle[1]);
00906   }
00907 
00908   pthread_mutex_destroy(&stream->mutex);
00909 
00910   if (stream->handle[0])
00911     snd_pcm_close(stream->handle[0]);
00912 
00913   if (stream->handle[1])
00914     snd_pcm_close(stream->handle[1]);
00915 
00916   if (stream->userBuffer)
00917     free(stream->userBuffer);
00918 
00919   if (stream->deviceBuffer)
00920     free(stream->deviceBuffer);
00921 
00922   free(stream);
00923   streams.erase(streamId);
00924 }
00925 
00926 void RtAudio :: startStream(int streamId)
00927 {
00928   // This method calls snd_pcm_prepare if the device isn't already in that state.
00929 
00930   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
00931 
00932   MUTEX_LOCK(&stream->mutex);
00933 
00934   if (stream->state == STREAM_RUNNING)
00935     goto unlock;
00936 
00937   int err;
00938   snd_pcm_state_t state;
00939   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
00940     state = snd_pcm_state(stream->handle[0]);
00941     if (state != SND_PCM_STATE_PREPARED) {
00942       err = snd_pcm_prepare(stream->handle[0]);
00943       if (err < 0) {
00944         sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.",
00945                 devices[stream->device[0]].name, snd_strerror(err));
00946         MUTEX_UNLOCK(&stream->mutex);
00947         error(RtError::DRIVER_ERROR);
00948       }
00949     }
00950   }
00951 
00952   if (stream->mode == RECORD || stream->mode == DUPLEX) {
00953     state = snd_pcm_state(stream->handle[1]);
00954     if (state != SND_PCM_STATE_PREPARED) {
00955       err = snd_pcm_prepare(stream->handle[1]);
00956       if (err < 0) {
00957         sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.",
00958                 devices[stream->device[1]].name, snd_strerror(err));
00959         MUTEX_UNLOCK(&stream->mutex);
00960         error(RtError::DRIVER_ERROR);
00961       }
00962     }
00963   }
00964   stream->state = STREAM_RUNNING;
00965 
00966  unlock:
00967   MUTEX_UNLOCK(&stream->mutex);
00968 }
00969 
00970 void RtAudio :: stopStream(int streamId)
00971 {
00972   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
00973 
00974   MUTEX_LOCK(&stream->mutex);
00975 
00976   if (stream->state == STREAM_STOPPED)
00977     goto unlock;
00978 
00979   int err;
00980   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
00981     err = snd_pcm_drain(stream->handle[0]);
00982     if (err < 0) {
00983       sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
00984               devices[stream->device[0]].name, snd_strerror(err));
00985       MUTEX_UNLOCK(&stream->mutex);
00986       error(RtError::DRIVER_ERROR);
00987     }
00988   }
00989 
00990   if (stream->mode == RECORD || stream->mode == DUPLEX) {
00991     err = snd_pcm_drain(stream->handle[1]);
00992     if (err < 0) {
00993       sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
00994               devices[stream->device[1]].name, snd_strerror(err));
00995       MUTEX_UNLOCK(&stream->mutex);
00996       error(RtError::DRIVER_ERROR);
00997     }
00998   }
00999   stream->state = STREAM_STOPPED;
01000 
01001  unlock:
01002   MUTEX_UNLOCK(&stream->mutex);
01003 }
01004 
01005 void RtAudio :: abortStream(int streamId)
01006 {
01007   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
01008 
01009   MUTEX_LOCK(&stream->mutex);
01010 
01011   if (stream->state == STREAM_STOPPED)
01012     goto unlock;
01013 
01014   int err;
01015   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
01016     err = snd_pcm_drop(stream->handle[0]);
01017     if (err < 0) {
01018       sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
01019               devices[stream->device[0]].name, snd_strerror(err));
01020       MUTEX_UNLOCK(&stream->mutex);
01021       error(RtError::DRIVER_ERROR);
01022     }
01023   }
01024 
01025   if (stream->mode == RECORD || stream->mode == DUPLEX) {
01026     err = snd_pcm_drop(stream->handle[1]);
01027     if (err < 0) {
01028       sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
01029               devices[stream->device[1]].name, snd_strerror(err));
01030       MUTEX_UNLOCK(&stream->mutex);
01031       error(RtError::DRIVER_ERROR);
01032     }
01033   }
01034   stream->state = STREAM_STOPPED;
01035 
01036  unlock:
01037   MUTEX_UNLOCK(&stream->mutex);
01038 }
01039 
01040 int RtAudio :: streamWillBlock(int streamId)
01041 {
01042   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
01043 
01044   MUTEX_LOCK(&stream->mutex);
01045 
01046   int err = 0, frames = 0;
01047   if (stream->state == STREAM_STOPPED)
01048     goto unlock;
01049 
01050   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
01051     err = snd_pcm_avail_update(stream->handle[0]);
01052     if (err < 0) {
01053       sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.",
01054               devices[stream->device[0]].name, snd_strerror(err));
01055       MUTEX_UNLOCK(&stream->mutex);
01056       error(RtError::DRIVER_ERROR);
01057     }
01058   }
01059 
01060   frames = err;
01061 
01062   if (stream->mode == RECORD || stream->mode == DUPLEX) {
01063     err = snd_pcm_avail_update(stream->handle[1]);
01064     if (err < 0) {
01065       sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.",
01066               devices[stream->device[1]].name, snd_strerror(err));
01067       MUTEX_UNLOCK(&stream->mutex);
01068       error(RtError::DRIVER_ERROR);
01069     }
01070     if (frames > err) frames = err;
01071   }
01072 
01073   frames = stream->bufferSize - frames;
01074   if (frames < 0) frames = 0;
01075 
01076  unlock:
01077   MUTEX_UNLOCK(&stream->mutex);
01078   return frames;
01079 }
01080 
01081 void RtAudio :: tickStream(int streamId)
01082 {
01083   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
01084 
01085   int stopStream = 0;
01086   if (stream->state == STREAM_STOPPED) {
01087     if (stream->usingCallback) usleep(50000); // sleep 50 milliseconds
01088     return;
01089   }
01090   else if (stream->usingCallback) {
01091     stopStream = stream->callback(stream->userBuffer, stream->bufferSize, stream->userData);
01092   }
01093 
01094   MUTEX_LOCK(&stream->mutex);
01095 
01096   // The state might change while waiting on a mutex.
01097   if (stream->state == STREAM_STOPPED)
01098     goto unlock;
01099 
01100   int err;
01101   char *buffer;
01102   int channels;
01103   RTAUDIO_FORMAT format;
01104   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
01105 
01106     // Setup parameters and do buffer conversion if necessary.
01107     if (stream->doConvertBuffer[0]) {
01108       convertStreamBuffer(stream, PLAYBACK);
01109       buffer = stream->deviceBuffer;
01110       channels = stream->nDeviceChannels[0];
01111       format = stream->deviceFormat[0];
01112     }
01113     else {
01114       buffer = stream->userBuffer;
01115       channels = stream->nUserChannels[0];
01116       format = stream->userFormat;
01117     }
01118 
01119     // Do byte swapping if necessary.
01120     if (stream->doByteSwap[0])
01121       byteSwapBuffer(buffer, stream->bufferSize * channels, format);
01122 
01123     // Write samples to device in interleaved/non-interleaved format.
01124     if (stream->deInterleave[0]) {
01125       void *bufs[channels];
01126       size_t offset = stream->bufferSize * formatBytes(format);
01127       for (int i=0; i<channels; i++)
01128         bufs[i] = (void *) (buffer + (i * offset));
01129       err = snd_pcm_writen(stream->handle[0], bufs, stream->bufferSize);
01130     }
01131     else
01132       err = snd_pcm_writei(stream->handle[0], buffer, stream->bufferSize);
01133 
01134     if (err < stream->bufferSize) {
01135       // Either an error or underrun occured.
01136       if (err == -EPIPE) {
01137         snd_pcm_state_t state = snd_pcm_state(stream->handle[0]);
01138         if (state == SND_PCM_STATE_XRUN) {
01139           sprintf(message, "RtAudio: ALSA underrun detected.");
01140           error(RtError::WARNING);
01141           err = snd_pcm_prepare(stream->handle[0]);
01142           if (err < 0) {
01143             sprintf(message, "RtAudio: ALSA error preparing handle after underrun: %s.",
01144                     snd_strerror(err));
01145             MUTEX_UNLOCK(&stream->mutex);
01146             error(RtError::DRIVER_ERROR);
01147           }
01148         }
01149         else {
01150           sprintf(message, "RtAudio: ALSA error, current state is %s.",
01151                   snd_pcm_state_name(state));
01152           MUTEX_UNLOCK(&stream->mutex);
01153           error(RtError::DRIVER_ERROR);
01154         }
01155         goto unlock;
01156       }
01157       else {
01158         sprintf(message, "RtAudio: ALSA audio write error for device (%s): %s.",
01159                 devices[stream->device[0]].name, snd_strerror(err));
01160         MUTEX_UNLOCK(&stream->mutex);
01161         error(RtError::DRIVER_ERROR);
01162       }
01163     }
01164   }
01165 
01166   if (stream->mode == RECORD || stream->mode == DUPLEX) {
01167 
01168     // Setup parameters.
01169     if (stream->doConvertBuffer[1]) {
01170       buffer = stream->deviceBuffer;
01171       channels = stream->nDeviceChannels[1];
01172       format = stream->deviceFormat[1];
01173     }
01174     else {
01175       buffer = stream->userBuffer;
01176       channels = stream->nUserChannels[1];
01177       format = stream->userFormat;
01178     }
01179 
01180     // Read samples from device in interleaved/non-interleaved format.
01181     if (stream->deInterleave[1]) {
01182       void *bufs[channels];
01183       size_t offset = stream->bufferSize * formatBytes(format);
01184       for (int i=0; i<channels; i++)
01185         bufs[i] = (void *) (buffer + (i * offset));
01186       err = snd_pcm_readn(stream->handle[1], bufs, stream->bufferSize);
01187     }
01188     else
01189       err = snd_pcm_readi(stream->handle[1], buffer, stream->bufferSize);
01190 
01191     if (err < stream->bufferSize) {
01192       // Either an error or underrun occured.
01193       if (err == -EPIPE) {
01194         snd_pcm_state_t state = snd_pcm_state(stream->handle[1]);
01195         if (state == SND_PCM_STATE_XRUN) {
01196           sprintf(message, "RtAudio: ALSA overrun detected.");
01197           error(RtError::WARNING);
01198           err = snd_pcm_prepare(stream->handle[1]);
01199           if (err < 0) {
01200             sprintf(message, "RtAudio: ALSA error preparing handle after overrun: %s.",
01201                     snd_strerror(err));
01202             MUTEX_UNLOCK(&stream->mutex);
01203             error(RtError::DRIVER_ERROR);
01204           }
01205         }
01206         else {
01207           sprintf(message, "RtAudio: ALSA error, current state is %s.",
01208                   snd_pcm_state_name(state));
01209           MUTEX_UNLOCK(&stream->mutex);
01210           error(RtError::DRIVER_ERROR);
01211         }
01212         goto unlock;
01213       }
01214       else {
01215         sprintf(message, "RtAudio: ALSA audio read error for device (%s): %s.",
01216                 devices[stream->device[1]].name, snd_strerror(err));
01217         MUTEX_UNLOCK(&stream->mutex);
01218         error(RtError::DRIVER_ERROR);
01219       }
01220     }
01221 
01222     // Do byte swapping if necessary.
01223     if (stream->doByteSwap[1])
01224       byteSwapBuffer(buffer, stream->bufferSize * channels, format);
01225 
01226     // Do buffer conversion if necessary.
01227     if (stream->doConvertBuffer[1])
01228       convertStreamBuffer(stream, RECORD);
01229   }
01230 
01231  unlock:
01232   MUTEX_UNLOCK(&stream->mutex);
01233 
01234   if (stream->usingCallback && stopStream)
01235     this->stopStream(streamId);
01236 }
01237 
01238 extern "C" void *callbackHandler(void *ptr)
01239 {
01240   RtAudio *object = thread_info.object;
01241   int stream = thread_info.streamId;
01242   bool *usingCallback = (bool *) ptr;
01243 
01244   while ( *usingCallback ) {
01245     pthread_testcancel();
01246     try {
01247       object->tickStream(stream);
01248     }
01249     catch (RtError &exception) {
01250       fprintf(stderr, "\nCallback thread error (%s) ... closing thread.\n\n",
01251               exception.getMessage());
01252       break;
01253     }
01254   }
01255 
01256   return 0;
01257 }
01258 
01259 //******************** End of __LINUX_ALSA__ *********************//
01260 
01261 #elif defined(__LINUX_OSS__)
01262 
01263 #include <sys/stat.h>
01264 #include <sys/types.h>
01265 #include <sys/ioctl.h>
01266 #include <unistd.h>
01267 #include <fcntl.h>
01268 #include <sys/soundcard.h>
01269 #include <errno.h>
01270 #include <math.h>
01271 
01272 #define DAC_NAME "/dev/dsp"
01273 #define MAX_DEVICES 16
01274 #define MAX_CHANNELS 16
01275 
01276 void RtAudio :: initialize(void)
01277 {
01278   // Count cards and devices
01279   nDevices = 0;
01280 
01281   // We check /dev/dsp before probing devices.  /dev/dsp is supposed to
01282   // be a link to the "default" audio device, of the form /dev/dsp0,
01283   // /dev/dsp1, etc...  However, I've seen one case where /dev/dsp was a
01284   // real device, so we need to check for that.  Also, sometimes the
01285   // link is to /dev/dspx and other times just dspx.  I'm not sure how
01286   // the latter works, but it does.
01287   char device_name[16];
01288   struct stat dspstat;
01289   int dsplink = -1;
01290   int i = 0;
01291   if (lstat(DAC_NAME, &dspstat) == 0) {
01292     if (S_ISLNK(dspstat.st_mode)) {
01293       i = readlink(DAC_NAME, device_name, sizeof(device_name));
01294       if (i > 0) {
01295         device_name[i] = '\0';
01296         if (i > 8) { // check for "/dev/dspx"
01297           if (!strncmp(DAC_NAME, device_name, 8))
01298             dsplink = atoi(&device_name[8]);
01299         }
01300         else if (i > 3) { // check for "dspx"
01301           if (!strncmp("dsp", device_name, 3))
01302             dsplink = atoi(&device_name[3]);
01303         }
01304       }
01305       else {
01306         sprintf(message, "RtAudio: cannot read value of symbolic link %s.", DAC_NAME);
01307         error(RtError::SYSTEM_ERROR);
01308       }
01309     }
01310   }
01311   else {
01312     sprintf(message, "RtAudio: cannot stat %s.", DAC_NAME);
01313     error(RtError::SYSTEM_ERROR);
01314   }
01315 
01316   // The OSS API doesn't provide a routine for determining the number
01317   // of devices.  Thus, we'll just pursue a brute force method.  The
01318   // idea is to start with /dev/dsp(0) and continue with higher device
01319   // numbers until we reach MAX_DSP_DEVICES.  This should tell us how
01320   // many devices we have ... it is not a fullproof scheme, but hopefully
01321   // it will work most of the time.
01322 
01323   int fd = 0;
01324   char names[MAX_DEVICES][16];
01325   for (i=-1; i<MAX_DEVICES; i++) {
01326 
01327     // Probe /dev/dsp first, since it is supposed to be the default device.
01328     if (i == -1)
01329       sprintf(device_name, "%s", DAC_NAME);
01330     else if (i == dsplink)
01331       continue; // We've aready probed this device via /dev/dsp link ... try next device.
01332     else
01333       sprintf(device_name, "%s%d", DAC_NAME, i);
01334 
01335     // First try to open the device for playback, then record mode.
01336     fd = open(device_name, O_WRONLY | O_NONBLOCK);
01337     if (fd == -1) {
01338       // Open device for playback failed ... either busy or doesn't exist.
01339       if (errno != EBUSY && errno != EAGAIN) {
01340         // Try to open for capture
01341         fd = open(device_name, O_RDONLY | O_NONBLOCK);
01342         if (fd == -1) {
01343           // Open device for record failed.
01344           if (errno != EBUSY && errno != EAGAIN)
01345             continue;
01346           else {
01347             sprintf(message, "RtAudio: OSS record device (%s) is busy.", device_name);
01348             error(RtError::WARNING);
01349             // still count it for now
01350           }
01351         }
01352       }
01353       else {
01354         sprintf(message, "RtAudio: OSS playback device (%s) is busy.", device_name);
01355         error(RtError::WARNING);
01356         // still count it for now
01357       }
01358     }
01359 
01360     if (fd >= 0) close(fd);
01361     strncpy(names[nDevices], device_name, 16);
01362     nDevices++;
01363   }
01364 
01365   if (nDevices == 0) return;
01366 
01367   //  Allocate the RTAUDIO_DEVICE structures.
01368   devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
01369   if (devices == NULL) {
01370     sprintf(message, "RtAudio: memory allocation error!");
01371     error(RtError::MEMORY_ERROR);
01372   }
01373 
01374   // Write device ascii identifiers to device control structure and then probe capabilities.
01375   for (i=0; i<nDevices; i++) {
01376     strncpy(devices[i].name, names[i], 16);
01377     probeDeviceInfo(&devices[i]);
01378   }
01379 
01380   return;
01381 }
01382 
01383 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
01384 {
01385   int i, fd, channels, mask;
01386 
01387   // The OSS API doesn't provide a means for probing the capabilities
01388   // of devices.  Thus, we'll just pursue a brute force method.
01389 
01390   // First try for playback
01391   fd = open(info->name, O_WRONLY | O_NONBLOCK);
01392   if (fd == -1) {
01393     // Open device failed ... either busy or doesn't exist
01394     if (errno == EBUSY || errno == EAGAIN)
01395       sprintf(message, "RtAudio: OSS playback device (%s) is busy and cannot be probed.",
01396               info->name);
01397     else
01398       sprintf(message, "RtAudio: OSS playback device (%s) open error.", info->name);
01399     error(RtError::WARNING);
01400     goto capture_probe;
01401   }
01402 
01403   // We have an open device ... see how many channels it can handle
01404   for (i=MAX_CHANNELS; i>0; i--) {
01405     channels = i;
01406     if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
01407       // This would normally indicate some sort of hardware error, but under ALSA's
01408       // OSS emulation, it sometimes indicates an invalid channel value.  Further,
01409       // the returned channel value is not changed. So, we'll ignore the possible
01410       // hardware error.
01411       continue; // try next channel number
01412     }
01413     // Check to see whether the device supports the requested number of channels
01414     if (channels != i ) continue; // try next channel number
01415     // If here, we found the largest working channel value
01416     break;
01417   }
01418   info->maxOutputChannels = channels;
01419 
01420   // Now find the minimum number of channels it can handle
01421   for (i=1; i<=info->maxOutputChannels; i++) {
01422     channels = i;
01423     if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
01424       continue; // try next channel number
01425     // If here, we found the smallest working channel value
01426     break;
01427   }
01428   info->minOutputChannels = channels;
01429   close(fd);
01430 
01431  capture_probe:
01432   // Now try for capture
01433   fd = open(info->name, O_RDONLY | O_NONBLOCK);
01434   if (fd == -1) {
01435     // Open device for capture failed ... either busy or doesn't exist
01436     if (errno == EBUSY || errno == EAGAIN)
01437       sprintf(message, "RtAudio: OSS capture device (%s) is busy and cannot be probed.",
01438               info->name);
01439     else
01440       sprintf(message, "RtAudio: OSS capture device (%s) open error.", info->name);
01441     error(RtError::WARNING);
01442     if (info->maxOutputChannels == 0)
01443       // didn't open for playback either ... device invalid
01444       return;
01445     goto probe_parameters;
01446   }
01447 
01448   // We have the device open for capture ... see how many channels it can handle
01449   for (i=MAX_CHANNELS; i>0; i--) {
01450     channels = i;
01451     if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
01452       continue; // as above
01453     }
01454     // If here, we found a working channel value
01455     break;
01456   }
01457   info->maxInputChannels = channels;
01458 
01459   // Now find the minimum number of channels it can handle
01460   for (i=1; i<=info->maxInputChannels; i++) {
01461     channels = i;
01462     if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
01463       continue; // try next channel number
01464     // If here, we found the smallest working channel value
01465     break;
01466   }
01467   info->minInputChannels = channels;
01468   close(fd);
01469 
01470   // If device opens for both playback and capture, we determine the channels.
01471   if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
01472     goto probe_parameters;
01473 
01474   fd = open(info->name, O_RDWR | O_NONBLOCK);
01475   if (fd == -1)
01476     goto probe_parameters;
01477 
01478   ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
01479   ioctl(fd, SNDCTL_DSP_GETCAPS, &mask);
01480   if (mask & DSP_CAP_DUPLEX) {
01481     info->hasDuplexSupport = true;
01482     // We have the device open for duplex ... see how many channels it can handle
01483     for (i=MAX_CHANNELS; i>0; i--) {
01484       channels = i;
01485       if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
01486         continue; // as above
01487       // If here, we found a working channel value
01488       break;
01489     }
01490     info->maxDuplexChannels = channels;
01491 
01492     // Now find the minimum number of channels it can handle
01493     for (i=1; i<=info->maxDuplexChannels; i++) {
01494       channels = i;
01495       if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
01496         continue; // try next channel number
01497       // If here, we found the smallest working channel value
01498       break;
01499     }
01500     info->minDuplexChannels = channels;
01501   }
01502   close(fd);
01503 
01504  probe_parameters:
01505   // At this point, we need to figure out the supported data formats
01506   // and sample rates.  We'll proceed by openning the device in the
01507   // direction with the maximum number of channels, or playback if
01508   // they are equal.  This might limit our sample rate options, but so
01509   // be it.
01510 
01511   if (info->maxOutputChannels >= info->maxInputChannels) {
01512     fd = open(info->name, O_WRONLY | O_NONBLOCK);
01513     channels = info->maxOutputChannels;
01514   }
01515   else {
01516     fd = open(info->name, O_RDONLY | O_NONBLOCK);
01517     channels = info->maxInputChannels;
01518   }
01519 
01520   if (fd == -1) {
01521     // We've got some sort of conflict ... abort
01522     sprintf(message, "RtAudio: OSS device (%s) won't reopen during probe.",
01523             info->name);
01524     error(RtError::WARNING);
01525     return;
01526   }
01527 
01528   // We have an open device ... set to maximum channels.
01529   i = channels;
01530   if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
01531     // We've got some sort of conflict ... abort
01532     close(fd);
01533     sprintf(message, "RtAudio: OSS device (%s) won't revert to previous channel setting.",
01534             info->name);
01535     error(RtError::WARNING);
01536     return;
01537   }
01538 
01539   if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
01540     close(fd);
01541     sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.",
01542             info->name);
01543     error(RtError::WARNING);
01544     return;
01545   }
01546 
01547   // Probe the supported data formats ... we don't care about endian-ness just yet.
01548   int format;
01549   info->nativeFormats = 0;
01550 #if defined (AFMT_S32_BE)
01551   // This format does not seem to be in the 2.4 kernel version of OSS soundcard.h
01552   if (mask & AFMT_S32_BE) {
01553     format = AFMT_S32_BE;
01554     info->nativeFormats |= RTAUDIO_SINT32;
01555   }
01556 #endif
01557 #if defined (AFMT_S32_LE)
01558   /* This format is not in the 2.4.4 kernel version of OSS soundcard.h */
01559   if (mask & AFMT_S32_LE) {
01560     format = AFMT_S32_LE;
01561     info->nativeFormats |= RTAUDIO_SINT32;
01562   }
01563 #endif
01564   if (mask & AFMT_S8) {
01565     format = AFMT_S8;
01566     info->nativeFormats |= RTAUDIO_SINT8;
01567   }
01568   if (mask & AFMT_S16_BE) {
01569     format = AFMT_S16_BE;
01570     info->nativeFormats |= RTAUDIO_SINT16;
01571   }
01572   if (mask & AFMT_S16_LE) {
01573     format = AFMT_S16_LE;
01574     info->nativeFormats |= RTAUDIO_SINT16;
01575   }
01576 
01577   // Check that we have at least one supported format
01578   if (info->nativeFormats == 0) {
01579     close(fd);
01580     sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.",
01581             info->name);
01582     error(RtError::WARNING);
01583     return;
01584   }
01585 
01586   // Set the format
01587   i = format;
01588   if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1 || format != i) {
01589     close(fd);
01590     sprintf(message, "RtAudio: OSS device (%s) error setting data format.",
01591             info->name);
01592     error(RtError::WARNING);
01593     return;
01594   }
01595 
01596   // Probe the supported sample rates ... first get lower limit
01597   int speed = 1;
01598   if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) {
01599     // If we get here, we're probably using an ALSA driver with OSS-emulation,
01600     // which doesn't conform to the OSS specification.  In this case,
01601     // we'll probe our predefined list of sample rates for working values.
01602     info->nSampleRates = 0;
01603     for (i=0; i<MAX_SAMPLE_RATES; i++) {
01604       speed = SAMPLE_RATES[i];
01605       if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) != -1) {
01606         info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
01607         info->nSampleRates++;
01608       }
01609     }
01610     if (info->nSampleRates == 0) {
01611       close(fd);
01612       return;
01613     }
01614     goto finished;
01615   }
01616   info->sampleRates[0] = speed;
01617 
01618   // Now get upper limit
01619   speed = 1000000;
01620   if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) {
01621     close(fd);
01622     sprintf(message, "RtAudio: OSS device (%s) error setting sample rate.",
01623             info->name);
01624     error(RtError::WARNING);
01625     return;
01626   }
01627   info->sampleRates[1] = speed;
01628   info->nSampleRates = -1;
01629 
01630  finished: // That's all ... close the device and return
01631   close(fd);
01632   info->probed = true;
01633   return;
01634 }
01635 
01636 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
01637                                 STREAM_MODE mode, int channels, 
01638                                 int sampleRate, RTAUDIO_FORMAT format,
01639                                 int *bufferSize, int numberOfBuffers)
01640 {
01641   int buffers, buffer_bytes, device_channels, device_format;
01642   int srate, temp, fd;
01643 
01644   const char *name = devices[device].name;
01645 
01646   if (mode == PLAYBACK)
01647     fd = open(name, O_WRONLY | O_NONBLOCK);
01648   else { // mode == RECORD
01649     if (stream->mode == PLAYBACK && stream->device[0] == device) {
01650       // We just set the same device for playback ... close and reopen for duplex (OSS only).
01651       close(stream->handle[0]);
01652       stream->handle[0] = 0;
01653       // First check that the number previously set channels is the same.
01654       if (stream->nUserChannels[0] != channels) {
01655         sprintf(message, "RtAudio: input/output channels must be equal for OSS duplex device (%s).", name);
01656         goto error;
01657       }
01658       fd = open(name, O_RDWR | O_NONBLOCK);
01659     }
01660     else
01661       fd = open(name, O_RDONLY | O_NONBLOCK);
01662   }
01663 
01664   if (fd == -1) {
01665     if (errno == EBUSY || errno == EAGAIN)
01666       sprintf(message, "RtAudio: OSS device (%s) is busy and cannot be opened.",
01667               name);
01668     else
01669       sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name);
01670     goto error;
01671   }
01672 
01673   // Now reopen in blocking mode.
01674   close(fd);
01675   if (mode == PLAYBACK)
01676     fd = open(name, O_WRONLY | O_SYNC);
01677   else { // mode == RECORD
01678     if (stream->mode == PLAYBACK && stream->device[0] == device)
01679       fd = open(name, O_RDWR | O_SYNC);
01680     else
01681       fd = open(name, O_RDONLY | O_SYNC);
01682   }
01683 
01684   if (fd == -1) {
01685     sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name);
01686     goto error;
01687   }
01688 
01689   // Get the sample format mask
01690   int mask;
01691   if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
01692     close(fd);
01693     sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.",
01694             name);
01695     goto error;
01696   }
01697 
01698   // Determine how to set the device format.
01699   stream->userFormat = format;
01700   device_format = -1;
01701   stream->doByteSwap[mode] = false;
01702   if (format == RTAUDIO_SINT8) {
01703     if (mask & AFMT_S8) {
01704       device_format = AFMT_S8;
01705       stream->deviceFormat[mode] = RTAUDIO_SINT8;
01706     }
01707   }
01708   else if (format == RTAUDIO_SINT16) {
01709     if (mask & AFMT_S16_NE) {
01710       device_format = AFMT_S16_NE;
01711       stream->deviceFormat[mode] = RTAUDIO_SINT16;
01712     }
01713 #if BYTE_ORDER == LITTLE_ENDIAN
01714     else if (mask & AFMT_S16_BE) {
01715       device_format = AFMT_S16_BE;
01716       stream->deviceFormat[mode] = RTAUDIO_SINT16;
01717       stream->doByteSwap[mode] = true;
01718     }
01719 #else
01720     else if (mask & AFMT_S16_LE) {
01721       device_format = AFMT_S16_LE;
01722       stream->deviceFormat[mode] = RTAUDIO_SINT16;
01723       stream->doByteSwap[mode] = true;
01724     }
01725 #endif
01726   }
01727 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
01728   else if (format == RTAUDIO_SINT32) {
01729     if (mask & AFMT_S32_NE) {
01730       device_format = AFMT_S32_NE;
01731       stream->deviceFormat[mode] = RTAUDIO_SINT32;
01732     }
01733 #if BYTE_ORDER == LITTLE_ENDIAN
01734     else if (mask & AFMT_S32_BE) {
01735       device_format = AFMT_S32_BE;
01736       stream->deviceFormat[mode] = RTAUDIO_SINT32;
01737       stream->doByteSwap[mode] = true;
01738     }
01739 #else
01740     else if (mask & AFMT_S32_LE) {
01741       device_format = AFMT_S32_LE;
01742       stream->deviceFormat[mode] = RTAUDIO_SINT32;
01743       stream->doByteSwap[mode] = true;
01744     }
01745 #endif
01746   }
01747 #endif
01748 
01749   if (device_format == -1) {
01750     // The user requested format is not natively supported by the device.
01751     if (mask & AFMT_S16_NE) {
01752       device_format = AFMT_S16_NE;
01753       stream->deviceFormat[mode] = RTAUDIO_SINT16;
01754     }
01755 #if BYTE_ORDER == LITTLE_ENDIAN
01756     else if (mask & AFMT_S16_BE) {
01757       device_format = AFMT_S16_BE;
01758       stream->deviceFormat[mode] = RTAUDIO_SINT16;
01759       stream->doByteSwap[mode] = true;
01760     }
01761 #else
01762     else if (mask & AFMT_S16_LE) {
01763       device_format = AFMT_S16_LE;
01764       stream->deviceFormat[mode] = RTAUDIO_SINT16;
01765       stream->doByteSwap[mode] = true;
01766     }
01767 #endif
01768 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
01769     else if (mask & AFMT_S32_NE) {
01770       device_format = AFMT_S32_NE;
01771       stream->deviceFormat[mode] = RTAUDIO_SINT32;
01772     }
01773 #if BYTE_ORDER == LITTLE_ENDIAN
01774     else if (mask & AFMT_S32_BE) {
01775       device_format = AFMT_S32_BE;
01776       stream->deviceFormat[mode] = RTAUDIO_SINT32;
01777       stream->doByteSwap[mode] = true;
01778     }
01779 #else
01780     else if (mask & AFMT_S32_LE) {
01781       device_format = AFMT_S32_LE;
01782       stream->deviceFormat[mode] = RTAUDIO_SINT32;
01783       stream->doByteSwap[mode] = true;
01784     }
01785 #endif
01786 #endif
01787     else if (mask & AFMT_S8) {
01788       device_format = AFMT_S8;
01789       stream->deviceFormat[mode] = RTAUDIO_SINT8;
01790     }
01791   }
01792 
01793   if (stream->deviceFormat[mode] == 0) {
01794     // This really shouldn't happen ...
01795     close(fd);
01796     sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.",
01797             name);
01798     goto error;
01799   }
01800 
01801   // Determine the number of channels for this device.  Note that the
01802   // channel value requested by the user might be < min_X_Channels.
01803   stream->nUserChannels[mode] = channels;
01804   device_channels = channels;
01805   if (mode == PLAYBACK) {
01806     if (channels < devices[device].minOutputChannels)
01807       device_channels = devices[device].minOutputChannels;
01808   }
01809   else { // mode == RECORD
01810     if (stream->mode == PLAYBACK && stream->device[0] == device) {
01811       // We're doing duplex setup here.
01812       if (channels < devices[device].minDuplexChannels)
01813         device_channels = devices[device].minDuplexChannels;
01814     }
01815     else {
01816       if (channels < devices[device].minInputChannels)
01817         device_channels = devices[device].minInputChannels;
01818     }
01819   }
01820   stream->nDeviceChannels[mode] = device_channels;
01821 
01822   // Attempt to set the buffer size.  According to OSS, the minimum
01823   // number of buffers is two.  The supposed minimum buffer size is 16
01824   // bytes, so that will be our lower bound.  The argument to this
01825   // call is in the form 0xMMMMSSSS (hex), where the buffer size (in
01826   // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM.
01827   // We'll check the actual value used near the end of the setup
01828   // procedure.
01829   buffer_bytes = *bufferSize * formatBytes(stream->deviceFormat[mode]) * device_channels;
01830   if (buffer_bytes < 16) buffer_bytes = 16;
01831   buffers = numberOfBuffers;
01832   if (buffers < 2) buffers = 2;
01833   temp = ((int) buffers << 16) + (int)(log10((double)buffer_bytes)/log10(2.0));
01834   if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &temp)) {
01835     close(fd);
01836     sprintf(message, "RtAudio: OSS error setting fragment size for device (%s).",
01837             name);
01838     goto error;
01839   }
01840   stream->nBuffers = buffers;
01841 
01842   // Set the data format.
01843   temp = device_format;
01844   if (ioctl(fd, SNDCTL_DSP_SETFMT, &device_format) == -1 || device_format != temp) {
01845     close(fd);
01846     sprintf(message, "RtAudio: OSS error setting data format for device (%s).",
01847             name);
01848     goto error;
01849   }
01850 
01851   // Set the number of channels.
01852   temp = device_channels;
01853   if (ioctl(fd, SNDCTL_DSP_CHANNELS, &device_channels) == -1 || device_channels != temp) {
01854     close(fd);
01855     sprintf(message, "RtAudio: OSS error setting %d channels on device (%s).",
01856             temp, name);
01857     goto error;
01858   }
01859 
01860   // Set the sample rate.
01861   srate = sampleRate;
01862   temp = srate;
01863   if (ioctl(fd, SNDCTL_DSP_SPEED, &srate) == -1) {
01864     close(fd);
01865     sprintf(message, "RtAudio: OSS error setting sample rate = %d on device (%s).",
01866             temp, name);
01867     goto error;
01868   }
01869 
01870   // Verify the sample rate setup worked.
01871   if (abs(srate - temp) > 100) {
01872     close(fd);
01873     sprintf(message, "RtAudio: OSS error ... audio device (%s) doesn't support sample rate of %d.",
01874             name, temp);
01875     goto error;
01876   }
01877   stream->sampleRate = sampleRate;
01878 
01879   if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &buffer_bytes) == -1) {
01880     close(fd);
01881     sprintf(message, "RtAudio: OSS error getting buffer size for device (%s).",
01882             name);
01883     goto error;
01884   }
01885 
01886   // Save buffer size (in sample frames).
01887   *bufferSize = buffer_bytes / (formatBytes(stream->deviceFormat[mode]) * device_channels);
01888   stream->bufferSize = *bufferSize;
01889 
01890   if (mode == RECORD && stream->mode == PLAYBACK &&
01891       stream->device[0] == device) {
01892     // We're doing duplex setup here.
01893     stream->deviceFormat[0] = stream->deviceFormat[1];
01894     stream->nDeviceChannels[0] = device_channels;
01895   }
01896 
01897   // Set flags for buffer conversion
01898   stream->doConvertBuffer[mode] = false;
01899   if (stream->userFormat != stream->deviceFormat[mode])
01900     stream->doConvertBuffer[mode] = true;
01901   if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
01902     stream->doConvertBuffer[mode] = true;
01903 
01904   // Allocate necessary internal buffers
01905   if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
01906 
01907     long buffer_bytes;
01908     if (stream->nUserChannels[0] >= stream->nUserChannels[1])
01909       buffer_bytes = stream->nUserChannels[0];
01910     else
01911       buffer_bytes = stream->nUserChannels[1];
01912 
01913     buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
01914     if (stream->userBuffer) free(stream->userBuffer);
01915     stream->userBuffer = (char *) calloc(buffer_bytes, 1);
01916     if (stream->userBuffer == NULL) {
01917       close(fd);
01918       sprintf(message, "RtAudio: OSS error allocating user buffer memory (%s).",
01919               name);
01920       goto error;
01921     }
01922   }
01923 
01924   if ( stream->doConvertBuffer[mode] ) {
01925 
01926     long buffer_bytes;
01927     bool makeBuffer = true;
01928     if ( mode == PLAYBACK )
01929       buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
01930     else { // mode == RECORD
01931       buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
01932       if ( stream->mode == PLAYBACK ) {
01933         long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
01934         if ( buffer_bytes > bytes_out )
01935           buffer_bytes = (buffer_bytes > bytes_out) ? buffer_bytes : bytes_out;
01936         else
01937           makeBuffer = false;
01938       }
01939     }
01940 
01941     if ( makeBuffer ) {
01942       buffer_bytes *= *bufferSize;
01943       if (stream->deviceBuffer) free(stream->deviceBuffer);
01944       stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
01945       if (stream->deviceBuffer == NULL) {
01946         close(fd);
01947         free(stream->userBuffer);
01948         sprintf(message, "RtAudio: OSS error allocating device buffer memory (%s).",
01949                 name);
01950         goto error;
01951       }
01952     }
01953   }
01954 
01955   stream->device[mode] = device;
01956   stream->handle[mode] = fd;
01957   stream->state = STREAM_STOPPED;
01958   if ( stream->mode == PLAYBACK && mode == RECORD ) {
01959     stream->mode = DUPLEX;
01960     if (stream->device[0] == device)
01961       stream->handle[0] = fd;
01962   }
01963   else
01964     stream->mode = mode;
01965 
01966   return SUCCESS;
01967 
01968  error:
01969   if (stream->handle[0]) {
01970     close(stream->handle[0]);
01971     stream->handle[0] = 0;
01972   }
01973   error(RtError::WARNING);
01974   return FAILURE;
01975 }
01976 
01977 void RtAudio :: cancelStreamCallback(int streamId)
01978 {
01979   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
01980 
01981   if (stream->usingCallback) {
01982     stream->usingCallback = false;
01983     pthread_cancel(stream->thread);
01984     pthread_join(stream->thread, NULL);
01985     stream->thread = 0;
01986     stream->callback = NULL;
01987     stream->userData = NULL;
01988   }
01989 }
01990 
01991 void RtAudio :: closeStream(int streamId)
01992 {
01993   // We don't want an exception to be thrown here because this
01994   // function is called by our class destructor.  So, do our own
01995   // streamId check.
01996   if ( streams.find( streamId ) == streams.end() ) {
01997     sprintf(message, "RtAudio: invalid stream identifier!");
01998     error(RtError::WARNING);
01999     return;
02000   }
02001 
02002   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
02003 
02004   if (stream->usingCallback) {
02005     pthread_cancel(stream->thread);
02006     pthread_join(stream->thread, NULL);
02007   }
02008 
02009   if (stream->state == STREAM_RUNNING) {
02010     if (stream->mode == PLAYBACK || stream->mode == DUPLEX)
02011       ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0);
02012     if (stream->mode == RECORD || stream->mode == DUPLEX)
02013       ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0);
02014   }
02015 
02016   pthread_mutex_destroy(&stream->mutex);
02017 
02018   if (stream->handle[0])
02019     close(stream->handle[0]);
02020 
02021   if (stream->handle[1])
02022     close(stream->handle[1]);
02023 
02024   if (stream->userBuffer)
02025     free(stream->userBuffer);
02026 
02027   if (stream->deviceBuffer)
02028     free(stream->deviceBuffer);
02029 
02030   free(stream);
02031   streams.erase(streamId);
02032 }
02033 
02034 void RtAudio :: startStream(int streamId)
02035 {
02036   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
02037 
02038   stream->state = STREAM_RUNNING;
02039 
02040   // No need to do anything else here ... OSS automatically starts when fed samples.
02041 }
02042 
02043 void RtAudio :: stopStream(int streamId)
02044 {
02045   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
02046 
02047   MUTEX_LOCK(&stream->mutex);
02048 
02049   if (stream->state == STREAM_STOPPED)
02050     goto unlock;
02051 
02052   int err;
02053   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
02054     err = ioctl(stream->handle[0], SNDCTL_DSP_SYNC, 0);
02055     if (err < -1) {
02056       sprintf(message, "RtAudio: OSS error stopping device (%s).",
02057               devices[stream->device[0]].name);
02058       error(RtError::DRIVER_ERROR);
02059     }
02060   }
02061   else {
02062     err = ioctl(stream->handle[1], SNDCTL_DSP_SYNC, 0);
02063     if (err < -1) {
02064       sprintf(message, "RtAudio: OSS error stopping device (%s).",
02065               devices[stream->device[1]].name);
02066       error(RtError::DRIVER_ERROR);
02067     }
02068   }
02069   stream->state = STREAM_STOPPED;
02070 
02071  unlock:
02072   MUTEX_UNLOCK(&stream->mutex);
02073 }
02074 
02075 void RtAudio :: abortStream(int streamId)
02076 {
02077   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
02078 
02079   MUTEX_LOCK(&stream->mutex);
02080 
02081   if (stream->state == STREAM_STOPPED)
02082     goto unlock;
02083 
02084   int err;
02085   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
02086     err = ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0);
02087     if (err < -1) {
02088       sprintf(message, "RtAudio: OSS error aborting device (%s).",
02089               devices[stream->device[0]].name);
02090       error(RtError::DRIVER_ERROR);
02091     }
02092   }
02093   else {
02094     err = ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0);
02095     if (err < -1) {
02096       sprintf(message, "RtAudio: OSS error aborting device (%s).",
02097               devices[stream->device[1]].name);
02098       error(RtError::DRIVER_ERROR);
02099     }
02100   }
02101   stream->state = STREAM_STOPPED;
02102 
02103  unlock:
02104   MUTEX_UNLOCK(&stream->mutex);
02105 }
02106 
02107 int RtAudio :: streamWillBlock(int streamId)
02108 {
02109   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
02110 
02111   MUTEX_LOCK(&stream->mutex);
02112 
02113   int bytes = 0, channels = 0, frames = 0;
02114   if (stream->state == STREAM_STOPPED)
02115     goto unlock;
02116 
02117   audio_buf_info info;
02118   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
02119     ioctl(stream->handle[0], SNDCTL_DSP_GETOSPACE, &info);
02120     bytes = info.bytes;
02121     channels = stream->nDeviceChannels[0];
02122   }
02123 
02124   if (stream->mode == RECORD || stream->mode == DUPLEX) {
02125     ioctl(stream->handle[1], SNDCTL_DSP_GETISPACE, &info);
02126     if (stream->mode == DUPLEX ) {
02127       bytes = (bytes < info.bytes) ? bytes : info.bytes;
02128       channels = stream->nDeviceChannels[0];
02129     }
02130     else {
02131       bytes = info.bytes;
02132       channels = stream->nDeviceChannels[1];
02133     }
02134   }
02135 
02136   frames = (int) (bytes / (channels * formatBytes(stream->deviceFormat[0])));
02137   frames -= stream->bufferSize;
02138   if (frames < 0) frames = 0;
02139 
02140  unlock:
02141   MUTEX_UNLOCK(&stream->mutex);
02142   return frames;
02143 }
02144 
02145 void RtAudio :: tickStream(int streamId)
02146 {
02147   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
02148 
02149   int stopStream = 0;
02150   if (stream->state == STREAM_STOPPED) {
02151     if (stream->usingCallback) usleep(50000); // sleep 50 milliseconds
02152     return;
02153   }
02154   else if (stream->usingCallback) {
02155     stopStream = stream->callback(stream->userBuffer, stream->bufferSize, stream->userData);
02156   }
02157 
02158   MUTEX_LOCK(&stream->mutex);
02159 
02160   // The state might change while waiting on a mutex.
02161   if (stream->state == STREAM_STOPPED)
02162     goto unlock;
02163 
02164   int result;
02165   char *buffer;
02166   int samples;
02167   RTAUDIO_FORMAT format;
02168   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
02169 
02170     // Setup parameters and do buffer conversion if necessary.
02171     if (stream->doConvertBuffer[0]) {
02172       convertStreamBuffer(stream, PLAYBACK);
02173       buffer = stream->deviceBuffer;
02174       samples = stream->bufferSize * stream->nDeviceChannels[0];
02175       format = stream->deviceFormat[0];
02176     }
02177     else {
02178       buffer = stream->userBuffer;
02179       samples = stream->bufferSize * stream->nUserChannels[0];
02180       format = stream->userFormat;
02181     }
02182 
02183     // Do byte swapping if necessary.
02184     if (stream->doByteSwap[0])
02185       byteSwapBuffer(buffer, samples, format);
02186 
02187     // Write samples to device.
02188     result = write(stream->handle[0], buffer, samples * formatBytes(format));
02189 
02190     if (result == -1) {
02191       // This could be an underrun, but the basic OSS API doesn't provide a means for determining that.
02192       sprintf(message, "RtAudio: OSS audio write error for device (%s).",
02193               devices[stream->device[0]].name);
02194       error(RtError::DRIVER_ERROR);
02195     }
02196   }
02197 
02198   if (stream->mode == RECORD || stream->mode == DUPLEX) {
02199 
02200     // Setup parameters.
02201     if (stream->doConvertBuffer[1]) {
02202       buffer = stream->deviceBuffer;
02203       samples = stream->bufferSize * stream->nDeviceChannels[1];
02204       format = stream->deviceFormat[1];
02205     }
02206     else {
02207       buffer = stream->userBuffer;
02208       samples = stream->bufferSize * stream->nUserChannels[1];
02209       format = stream->userFormat;
02210     }
02211 
02212     // Read samples from device.
02213     result = read(stream->handle[1], buffer, samples * formatBytes(format));
02214 
02215     if (result == -1) {
02216       // This could be an overrun, but the basic OSS API doesn't provide a means for determining that.
02217       sprintf(message, "RtAudio: OSS audio read error for device (%s).",
02218               devices[stream->device[1]].name);
02219       error(RtError::DRIVER_ERROR);
02220     }
02221 
02222     // Do byte swapping if necessary.
02223     if (stream->doByteSwap[1])
02224       byteSwapBuffer(buffer, samples, format);
02225 
02226     // Do buffer conversion if necessary.
02227     if (stream->doConvertBuffer[1])
02228       convertStreamBuffer(stream, RECORD);
02229   }
02230 
02231  unlock:
02232   MUTEX_UNLOCK(&stream->mutex);
02233 
02234   if (stream->usingCallback && stopStream)
02235     this->stopStream(streamId);
02236 }
02237 
02238 extern "C" void *callbackHandler(void *ptr)
02239 {
02240   RtAudio *object = thread_info.object;
02241   int stream = thread_info.streamId;
02242   bool *usingCallback = (bool *) ptr;
02243 
02244   while ( *usingCallback ) {
02245     pthread_testcancel();
02246     try {
02247       object->tickStream(stream);
02248     }
02249     catch (RtError &exception) {
02250       fprintf(stderr, "\nCallback thread error (%s) ... closing thread.\n\n",
02251               exception.getMessage());
02252       break;
02253     }
02254   }
02255 
02256   return 0;
02257 }
02258 
02259 //******************** End of __LINUX_OSS__ *********************//
02260 
02261 #elif defined(__WINDOWS_DS__) // Windows DirectSound API
02262 
02263 #include <dsound.h>
02264 
02265 // Declarations for utility functions, callbacks, and structures
02266 // specific to the DirectSound implementation.
02267 static bool CALLBACK deviceCountCallback(LPGUID lpguid,
02268                                          LPCSTR lpcstrDescription,
02269                                          LPCSTR lpcstrModule,
02270                                          LPVOID lpContext);
02271 
02272 static bool CALLBACK deviceInfoCallback(LPGUID lpguid,
02273                                         LPCSTR lpcstrDescription,
02274                                         LPCSTR lpcstrModule,
02275                                         LPVOID lpContext);
02276 
02277 static char* getErrorString(int code);
02278 
02279 struct enum_info {
02280   char name[64];
02281   LPGUID id;
02282   bool isInput;
02283   bool isValid;
02284 };
02285 
02286 // RtAudio methods for DirectSound implementation.
02287 void RtAudio :: initialize(void)
02288 {
02289   int i, ins = 0, outs = 0, count = 0;
02290   int index = 0;
02291   HRESULT result;
02292   nDevices = 0;
02293 
02294   // Count DirectSound devices.
02295   result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &outs);
02296   if ( FAILED(result) ) {
02297     sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.",
02298             getErrorString(result));
02299     error(RtError::DRIVER_ERROR);
02300   }
02301 
02302   // Count DirectSoundCapture devices.
02303   result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &ins);
02304   if ( FAILED(result) ) {
02305     sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.",
02306             getErrorString(result));
02307     error(RtError::DRIVER_ERROR);
02308   }
02309 
02310   count = ins + outs;
02311   if (count == 0) return;
02312 
02313   std::vector<enum_info> info(count);
02314   for (i=0; i<count; i++) {
02315     info[i].name[0] = '\0';
02316     if (i < outs) info[i].isInput = false;
02317     else info[i].isInput = true;
02318   }
02319 
02320   // Get playback device info and check capabilities.
02321   result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]);
02322   if ( FAILED(result) ) {
02323     sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.",
02324             getErrorString(result));
02325     error(RtError::DRIVER_ERROR);
02326   }
02327 
02328   // Get capture device info and check capabilities.
02329   result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]);
02330   if ( FAILED(result) ) {
02331     sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.",
02332             getErrorString(result));
02333     error(RtError::DRIVER_ERROR);
02334   }
02335 
02336   // Parse the devices and check validity.  Devices are considered
02337   // invalid if they cannot be opened, they report no supported data
02338   // formats, or they report < 1 supported channels.
02339   for (i=0; i<count; i++) {
02340     if (info[i].isValid && info[i].id == NULL ) // default device
02341       nDevices++;
02342   }
02343 
02344   // We group the default input and output devices together (as one
02345   // device) .
02346   if (nDevices > 0) {
02347     nDevices = 1;
02348     index = 1;
02349   }
02350 
02351   // Non-default devices are listed separately.
02352   for (i=0; i<count; i++) {
02353     if (info[i].isValid && info[i].id != NULL )
02354       nDevices++;
02355   }
02356 
02357   if (nDevices == 0) return;
02358 
02359   //  Allocate the RTAUDIO_DEVICE structures.
02360   devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
02361   if (devices == NULL) {
02362     sprintf(message, "RtAudio: memory allocation error!");
02363     error(RtError::MEMORY_ERROR);
02364   }
02365 
02366   // Initialize the GUIDs to NULL for later validation.
02367   for (i=0; i<nDevices; i++) {
02368     devices[i].id[0] = NULL;
02369     devices[i].id[1] = NULL;
02370   }
02371 
02372   // Rename the default device(s).
02373   if (index)
02374     strcpy(devices[0].name, "Default Input/Output Devices");
02375 
02376   // Copy the names and GUIDs to our devices structures.
02377   for (i=0; i<count; i++) {
02378     if (info[i].isValid && info[i].id != NULL ) {
02379       strncpy(devices[index].name, info[i].name, 64);
02380       if (info[i].isInput)
02381         devices[index].id[1] = info[i].id;
02382       else
02383         devices[index].id[0] = info[i].id;
02384       index++;
02385     }
02386   }
02387 
02388   for (i=0;i<nDevices; i++)
02389     probeDeviceInfo(&devices[i]);
02390 
02391   return;
02392 }
02393 
02394 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
02395 {
02396   HRESULT result;
02397 
02398   // Get the device index so that we can check the device handle.
02399   int index;
02400   for (index=0; index<nDevices; index++)
02401     if ( info == &devices[index] ) break;
02402 
02403   if ( index >= nDevices ) {
02404     sprintf(message, "RtAudio: device (%s) indexing error in DirectSound probeDeviceInfo().",
02405             info->name);
02406     error(RtError::WARNING);
02407     return;
02408   }
02409 
02410   // Do capture probe first.  If this is not the default device (index
02411   // = 0) _and_ GUID = NULL, then the capture handle is invalid.
02412   if ( index != 0 && info->id[1] == NULL )
02413     goto playback_probe;
02414 
02415   LPDIRECTSOUNDCAPTURE  input;
02416   result = DirectSoundCaptureCreate( info->id[0], &input, NULL );
02417   if ( FAILED(result) ) {
02418     sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.",
02419             info->name, getErrorString(result));
02420     error(RtError::WARNING);
02421     goto playback_probe;
02422   }
02423 
02424   DSCCAPS in_caps;
02425   in_caps.dwSize = sizeof(in_caps);
02426   result = input->GetCaps( &in_caps );
02427   if ( FAILED(result) ) {
02428     input->Release();
02429     sprintf(message, "RtAudio: Could not get DirectSound capture capabilities (%s): %s.",
02430             info->name, getErrorString(result));
02431     error(RtError::WARNING);
02432     goto playback_probe;
02433   }
02434 
02435   // Get input channel information.
02436   info->minInputChannels = 1;
02437   info->maxInputChannels = in_caps.dwChannels;
02438 
02439   // Get sample rate and format information.
02440   if( in_caps.dwChannels == 2 ) {
02441     if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->nativeFormats |= RTAUDIO_SINT16;
02442     if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->nativeFormats |= RTAUDIO_SINT16;
02443     if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->nativeFormats |= RTAUDIO_SINT16;
02444     if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->nativeFormats |= RTAUDIO_SINT8;
02445     if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->nativeFormats |= RTAUDIO_SINT8;
02446     if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->nativeFormats |= RTAUDIO_SINT8;
02447 
02448     if ( info->nativeFormats & RTAUDIO_SINT16 ) {
02449       if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->sampleRates[info->nSampleRates++] = 11025;
02450       if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->sampleRates[info->nSampleRates++] = 22050;
02451       if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->sampleRates[info->nSampleRates++] = 44100;
02452     }
02453     else if ( info->nativeFormats & RTAUDIO_SINT8 ) {
02454       if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->sampleRates[info->nSampleRates++] = 11025;
02455       if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->sampleRates[info->nSampleRates++] = 22050;
02456       if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->sampleRates[info->nSampleRates++] = 44100;
02457     }
02458   }
02459   else if ( in_caps.dwChannels == 1 ) {
02460     if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->nativeFormats |= RTAUDIO_SINT16;
02461     if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->nativeFormats |= RTAUDIO_SINT16;
02462     if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->nativeFormats |= RTAUDIO_SINT16;
02463     if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->nativeFormats |= RTAUDIO_SINT8;
02464     if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->nativeFormats |= RTAUDIO_SINT8;
02465     if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->nativeFormats |= RTAUDIO_SINT8;
02466 
02467     if ( info->nativeFormats & RTAUDIO_SINT16 ) {
02468       if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->sampleRates[info->nSampleRates++] = 11025;
02469       if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->sampleRates[info->nSampleRates++] = 22050;
02470       if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->sampleRates[info->nSampleRates++] = 44100;
02471     }
02472     else if ( info->nativeFormats & RTAUDIO_SINT8 ) {
02473       if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->sampleRates[info->nSampleRates++] = 11025;
02474       if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->sampleRates[info->nSampleRates++] = 22050;
02475       if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->sampleRates[info->nSampleRates++] = 44100;
02476     }
02477   }
02478   else info->minInputChannels = 0; // technically, this would be an error
02479 
02480   input->Release();
02481 
02482  playback_probe:
02483   LPDIRECTSOUND  output;
02484   DSCAPS out_caps;
02485 
02486   // Now do playback probe.  If this is not the default device (index
02487   // = 0) _and_ GUID = NULL, then the playback handle is invalid.
02488   if ( index != 0 && info->id[0] == NULL )
02489     goto check_parameters;
02490 
02491   result = DirectSoundCreate( info->id[0], &output, NULL );
02492   if ( FAILED(result) ) {
02493     sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.",
02494             info->name, getErrorString(result));
02495     error(RtError::WARNING);
02496     goto check_parameters;
02497   }
02498 
02499   out_caps.dwSize = sizeof(out_caps);
02500   result = output->GetCaps( &out_caps );
02501   if ( FAILED(result) ) {
02502     output->Release();
02503     sprintf(message, "RtAudio: Could not get DirectSound playback capabilities (%s): %s.",
02504             info->name, getErrorString(result));
02505     error(RtError::WARNING);
02506     goto check_parameters;
02507   }
02508 
02509   // Get output channel information.
02510   info->minOutputChannels = 1;
02511   info->maxOutputChannels = ( out_caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
02512 
02513   // Get sample rate information.  Use capture device rate information
02514   // if it exists.
02515   if ( info->nSampleRates == 0 ) {
02516     info->sampleRates[0] = (int) out_caps.dwMinSecondarySampleRate;
02517     info->sampleRates[1] = (int) out_caps.dwMaxSecondarySampleRate;
02518     if ( out_caps.dwFlags & DSCAPS_CONTINUOUSRATE )
02519       info->nSampleRates = -1;
02520     else if ( out_caps.dwMinSecondarySampleRate == out_caps.dwMaxSecondarySampleRate ) {
02521       if ( out_caps.dwMinSecondarySampleRate == 0 ) {
02522         // This is a bogus driver report ... fake the range and cross
02523         // your fingers.
02524         info->sampleRates[0] = 11025;
02525                                 info->sampleRates[1] = 48000;
02526         info->nSampleRates = -1; /* continuous range */
02527         sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using defaults (%s).",
02528                 info->name);
02529         error(RtError::WARNING);
02530       }
02531       else {
02532         info->nSampleRates = 1;
02533                         }
02534     }
02535     else if ( (out_caps.dwMinSecondarySampleRate < 1000.0) &&
02536               (out_caps.dwMaxSecondarySampleRate > 50000.0) ) {
02537       // This is a bogus driver report ... support for only two
02538       // distant rates.  We'll assume this is a range.
02539       info->nSampleRates = -1;
02540       sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using range (%s).",
02541               info->name);
02542       error(RtError::WARNING);
02543     }
02544     else info->nSampleRates = 2;
02545   }
02546   else {
02547     // Check input rates against output rate range
02548     for ( int i=info->nSampleRates-1; i>=0; i-- ) {
02549       if ( info->sampleRates[i] <= out_caps.dwMaxSecondarySampleRate )
02550         break;
02551       info->nSampleRates--;
02552     }
02553     while ( info->sampleRates[0] < out_caps.dwMinSecondarySampleRate ) {
02554       info->nSampleRates--;
02555       for ( int i=0; i<info->nSampleRates; i++)
02556         info->sampleRates[i] = info->sampleRates[i+1];
02557       if ( info->nSampleRates <= 0 ) break;
02558     }
02559   }
02560 
02561   // Get format information.
02562   if ( out_caps.dwFlags & DSCAPS_PRIMARY16BIT ) info->nativeFormats |= RTAUDIO_SINT16;
02563   if ( out_caps.dwFlags & DSCAPS_PRIMARY8BIT ) info->nativeFormats |= RTAUDIO_SINT8;
02564 
02565   output->Release();
02566 
02567  check_parameters:
02568   if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 )
02569     return;
02570   if ( info->nSampleRates == 0 || info->nativeFormats == 0 )
02571     return;
02572 
02573   // Determine duplex status.
02574   if (info->maxInputChannels < info->maxOutputChannels)
02575     info->maxDuplexChannels = info->maxInputChannels;
02576   else
02577     info->maxDuplexChannels = info->maxOutputChannels;
02578   if (info->minInputChannels < info->minOutputChannels)
02579     info->minDuplexChannels = info->minInputChannels;
02580   else
02581     info->minDuplexChannels = info->minOutputChannels;
02582 
02583   if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true;
02584   else info->hasDuplexSupport = false;
02585 
02586   info->probed = true;
02587 
02588   return;
02589 }
02590 
02591 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
02592                                 STREAM_MODE mode, int channels, 
02593                                 int sampleRate, RTAUDIO_FORMAT format,
02594                                 int *bufferSize, int numberOfBuffers)
02595 {
02596   HRESULT result;
02597   HWND hWnd = GetForegroundWindow();
02598   // According to a note in PortAudio, using GetDesktopWindow()
02599   // instead of GetForegroundWindow() is supposed to avoid problems
02600   // that occur when the application's window is not the foreground
02601   // window.  Also, if the application window closes before the
02602   // DirectSound buffer, DirectSound can crash.  However, for console
02603   // applications, no sound was produced when using GetDesktopWindow().
02604   long buffer_size;
02605   LPVOID audioPtr;
02606   DWORD dataLen;
02607   int nBuffers;
02608 
02609   // Check the numberOfBuffers parameter and limit the lowest value to
02610   // two.  This is a judgement call and a value of two is probably too
02611   // low for capture, but it should work for playback.
02612   if (numberOfBuffers < 2)
02613     nBuffers = 2;
02614   else
02615     nBuffers = numberOfBuffers;
02616 
02617   // Define the wave format structure (16-bit PCM, srate, channels)
02618   WAVEFORMATEX waveFormat;
02619   ZeroMemory(&waveFormat, sizeof(WAVEFORMATEX));
02620   waveFormat.wFormatTag = WAVE_FORMAT_PCM;
02621   waveFormat.nChannels = channels;
02622   waveFormat.nSamplesPerSec = (unsigned long) sampleRate;
02623 
02624   // Determine the data format.
02625   if ( devices[device].nativeFormats ) { // 8-bit and/or 16-bit support
02626     if ( format == RTAUDIO_SINT8 ) {
02627       if ( devices[device].nativeFormats & RTAUDIO_SINT8 )
02628         waveFormat.wBitsPerSample = 8;
02629       else
02630         waveFormat.wBitsPerSample = 16;
02631     }
02632     else {
02633       if ( devices[device].nativeFormats & RTAUDIO_SINT16 )
02634         waveFormat.wBitsPerSample = 16;
02635       else
02636         waveFormat.wBitsPerSample = 8;
02637     }
02638   }
02639   else {
02640     sprintf(message, "RtAudio: no reported data formats for DirectSound device (%s).",
02641             devices[device].name);
02642     error(RtError::WARNING);
02643     return FAILURE;
02644   }
02645 
02646   waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
02647   waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
02648 
02649   if ( mode == PLAYBACK ) {
02650 
02651     if ( devices[device].maxOutputChannels < channels )
02652       return FAILURE;
02653 
02654     LPGUID id = devices[device].id[0];
02655     LPDIRECTSOUND  object;
02656     LPDIRECTSOUNDBUFFER buffer;
02657     DSBUFFERDESC bufferDescription;
02658     
02659     result = DirectSoundCreate( id, &object, NULL );
02660     if ( FAILED(result) ) {
02661       sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.",
02662               devices[device].name, getErrorString(result));
02663       error(RtError::WARNING);
02664       return FAILURE;
02665     }
02666 
02667     // Set cooperative level to DSSCL_EXCLUSIVE
02668     result = object->SetCooperativeLevel(hWnd, DSSCL_EXCLUSIVE);
02669     if ( FAILED(result) ) {
02670       object->Release();
02671       sprintf(message, "RtAudio: Unable to set DirectSound cooperative level (%s): %s.",
02672               devices[device].name, getErrorString(result));
02673       error(RtError::WARNING);
02674       return FAILURE;
02675     }
02676 
02677     // Even though we will write to the secondary buffer, we need to
02678     // access the primary buffer to set the correct output format.
02679     // The default is 8-bit, 22 kHz!
02680     // Setup the DS primary buffer description.
02681     ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
02682     bufferDescription.dwSize = sizeof(DSBUFFERDESC);
02683     bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
02684     // Obtain the primary buffer
02685     result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
02686     if ( FAILED(result) ) {
02687       object->Release();
02688       sprintf(message, "RtAudio: Unable to access DS primary buffer (%s): %s.",
02689               devices[device].name, getErrorString(result));
02690       error(RtError::WARNING);
02691       return FAILURE;
02692     }
02693 
02694     // Set the primary DS buffer sound format.
02695     result = buffer->SetFormat(&waveFormat);
02696     if ( FAILED(result) ) {
02697       object->Release();
02698       sprintf(message, "RtAudio: Unable to set DS primary buffer format (%s): %s.",
02699               devices[device].name, getErrorString(result));
02700       error(RtError::WARNING);
02701       return FAILURE;
02702     }
02703 
02704     // Setup the secondary DS buffer description.
02705     buffer_size = channels * *bufferSize * nBuffers * waveFormat.wBitsPerSample / 8;
02706     ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
02707     bufferDescription.dwSize = sizeof(DSBUFFERDESC);
02708     bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
02709                                   DSBCAPS_GETCURRENTPOSITION2 |
02710                                   DSBCAPS_LOCHARDWARE );  // Force hardware mixing
02711     bufferDescription.dwBufferBytes = buffer_size;
02712     bufferDescription.lpwfxFormat = &waveFormat;
02713 
02714     // Try to create the secondary DS buffer.  If that doesn't work,
02715     // try to use software mixing.  Otherwise, there's a problem.
02716     result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
02717     if ( FAILED(result) ) {
02718       bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
02719                                     DSBCAPS_GETCURRENTPOSITION2 |
02720                                     DSBCAPS_LOCSOFTWARE );  // Force software mixing
02721       result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
02722       if ( FAILED(result) ) {
02723         object->Release();
02724         sprintf(message, "RtAudio: Unable to create secondary DS buffer (%s): %s.",
02725                 devices[device].name, getErrorString(result));
02726         error(RtError::WARNING);
02727         return FAILURE;
02728       }
02729     }
02730 
02731     // Get the buffer size ... might be different from what we specified.
02732     DSBCAPS dsbcaps;
02733     dsbcaps.dwSize = sizeof(DSBCAPS);
02734     buffer->GetCaps(&dsbcaps);
02735     buffer_size = dsbcaps.dwBufferBytes;
02736 
02737     // Lock the DS buffer
02738     result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0);
02739     if ( FAILED(result) ) {
02740       object->Release();
02741       sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.",
02742               devices[device].name, getErrorString(result));
02743       error(RtError::WARNING);
02744       return FAILURE;
02745     }
02746 
02747     // Zero the DS buffer
02748     ZeroMemory(audioPtr, dataLen);
02749 
02750     // Unlock the DS buffer
02751     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
02752     if ( FAILED(result) ) {
02753       object->Release();
02754       sprintf(message, "RtAudio: Unable to unlock DS buffer(%s): %s.",
02755               devices[device].name, getErrorString(result));
02756       error(RtError::WARNING);
02757       return FAILURE;
02758     }
02759 
02760     stream->handle[0].object = (void *) object;
02761     stream->handle[0].buffer = (void *) buffer;
02762     stream->nDeviceChannels[0] = channels;
02763   }
02764 
02765   if ( mode == RECORD ) {
02766 
02767     if ( devices[device].maxInputChannels < channels )
02768       return FAILURE;
02769 
02770     LPGUID id = devices[device].id[1];
02771     LPDIRECTSOUNDCAPTURE  object;
02772     LPDIRECTSOUNDCAPTUREBUFFER buffer;
02773     DSCBUFFERDESC bufferDescription;
02774 
02775     result = DirectSoundCaptureCreate( id, &object, NULL );
02776     if ( FAILED(result) ) {
02777       sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.",
02778               devices[device].name, getErrorString(result));
02779       error(RtError::WARNING);
02780       return FAILURE;
02781     }
02782 
02783     // Setup the secondary DS buffer description.
02784     buffer_size = channels * *bufferSize * nBuffers * waveFormat.wBitsPerSample / 8;
02785     ZeroMemory(&bufferDescription, sizeof(DSCBUFFERDESC));
02786     bufferDescription.dwSize = sizeof(DSCBUFFERDESC);
02787     bufferDescription.dwFlags = 0;
02788     bufferDescription.dwReserved = 0;
02789     bufferDescription.dwBufferBytes = buffer_size;
02790     bufferDescription.lpwfxFormat = &waveFormat;
02791 
02792     // Create the capture buffer.
02793     result = object->CreateCaptureBuffer(&bufferDescription, &buffer, NULL);
02794     if ( FAILED(result) ) {
02795       object->Release();
02796       sprintf(message, "RtAudio: Unable to create DS capture buffer (%s): %s.",
02797               devices[device].name, getErrorString(result));
02798       error(RtError::WARNING);
02799       return FAILURE;
02800     }
02801 
02802     // Lock the capture buffer
02803     result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0);
02804     if ( FAILED(result) ) {
02805       object->Release();
02806       sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
02807               devices[device].name, getErrorString(result));
02808       error(RtError::WARNING);
02809       return FAILURE;
02810     }
02811 
02812     // Zero the buffer
02813     ZeroMemory(audioPtr, dataLen);
02814 
02815     // Unlock the buffer
02816     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
02817     if ( FAILED(result) ) {
02818       object->Release();
02819       sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
02820               devices[device].name, getErrorString(result));
02821       error(RtError::WARNING);
02822       return FAILURE;
02823     }
02824 
02825     stream->handle[1].object = (void *) object;
02826     stream->handle[1].buffer = (void *) buffer;
02827     stream->nDeviceChannels[1] = channels;
02828   }
02829 
02830   stream->userFormat = format;
02831   if ( waveFormat.wBitsPerSample == 8 )
02832     stream->deviceFormat[mode] = RTAUDIO_SINT8;
02833   else
02834     stream->deviceFormat[mode] = RTAUDIO_SINT16;
02835   stream->nUserChannels[mode] = channels;
02836   *bufferSize = buffer_size / (channels * nBuffers * waveFormat.wBitsPerSample / 8);
02837   stream->bufferSize = *bufferSize;
02838 
02839   // Set flags for buffer conversion
02840   stream->doConvertBuffer[mode] = false;
02841   if (stream->userFormat != stream->deviceFormat[mode])
02842     stream->doConvertBuffer[mode] = true;
02843   if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
02844     stream->doConvertBuffer[mode] = true;
02845 
02846   // Allocate necessary internal buffers
02847   if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
02848 
02849     long buffer_bytes;
02850     if (stream->nUserChannels[0] >= stream->nUserChannels[1])
02851       buffer_bytes = stream->nUserChannels[0];
02852     else
02853       buffer_bytes = stream->nUserChannels[1];
02854 
02855     buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
02856     if (stream->userBuffer) free(stream->userBuffer);
02857     stream->userBuffer = (char *) calloc(buffer_bytes, 1);
02858     if (stream->userBuffer == NULL)
02859       goto memory_error;
02860   }
02861 
02862   if ( stream->doConvertBuffer[mode] ) {
02863 
02864     long buffer_bytes;
02865     bool makeBuffer = true;
02866     if ( mode == PLAYBACK )
02867       buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
02868     else { // mode == RECORD
02869       buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
02870       if ( stream->mode == PLAYBACK ) {
02871         long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
02872         if ( buffer_bytes > bytes_out )
02873           buffer_bytes = (buffer_bytes > bytes_out) ? buffer_bytes : bytes_out;
02874         else
02875           makeBuffer = false;
02876       }
02877     }
02878 
02879     if ( makeBuffer ) {
02880       buffer_bytes *= *bufferSize;
02881       if (stream->deviceBuffer) free(stream->deviceBuffer);
02882       stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
02883       if (stream->deviceBuffer == NULL)
02884         goto memory_error;
02885     }
02886   }
02887 
02888   stream->device[mode] = device;
02889   stream->state = STREAM_STOPPED;
02890   if ( stream->mode == PLAYBACK && mode == RECORD )
02891     // We had already set up an output stream.
02892     stream->mode = DUPLEX;
02893   else
02894     stream->mode = mode;
02895   stream->nBuffers = nBuffers;
02896   stream->sampleRate = sampleRate;
02897 
02898   return SUCCESS;
02899 
02900  memory_error:
02901   if (stream->handle[0].object) {
02902     LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object;
02903     LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
02904     if (buffer) {
02905       buffer->Release();
02906       stream->handle[0].buffer = NULL;
02907     }
02908     object->Release();
02909     stream->handle[0].object = NULL;
02910   }
02911   if (stream->handle[1].object) {
02912     LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object;
02913     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
02914     if (buffer) {
02915       buffer->Release();
02916       stream->handle[1].buffer = NULL;
02917     }
02918     object->Release();
02919     stream->handle[1].object = NULL;
02920   }
02921   if (stream->userBuffer) {
02922     free(stream->userBuffer);
02923     stream->userBuffer = 0;
02924   }
02925   sprintf(message, "RtAudio: error allocating buffer memory (%s).",
02926           devices[device].name);
02927   error(RtError::WARNING);
02928   return FAILURE;
02929 }
02930 
02931 void RtAudio :: cancelStreamCallback(int streamId)
02932 {
02933   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
02934 
02935   if (stream->usingCallback) {
02936     stream->usingCallback = false;
02937     WaitForSingleObject( (HANDLE)stream->thread, INFINITE );
02938     CloseHandle( (HANDLE)stream->thread );
02939     stream->thread = 0;
02940     stream->callback = NULL;
02941     stream->userData = NULL;
02942   }
02943 }
02944 
02945 void RtAudio :: closeStream(int streamId)
02946 {
02947   // We don't want an exception to be thrown here because this
02948   // function is called by our class destructor.  So, do our own
02949   // streamId check.
02950   if ( streams.find( streamId ) == streams.end() ) {
02951     sprintf(message, "RtAudio: invalid stream identifier!");
02952     error(RtError::WARNING);
02953     return;
02954   }
02955 
02956   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
02957 
02958   if (stream->usingCallback) {
02959     stream->usingCallback = false;
02960     WaitForSingleObject( (HANDLE)stream->thread, INFINITE );
02961     CloseHandle( (HANDLE)stream->thread );
02962   }
02963 
02964   DeleteCriticalSection(&stream->mutex);
02965 
02966   if (stream->handle[0].object) {
02967     LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object;
02968     LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
02969     if (buffer) {
02970       buffer->Stop();
02971       buffer->Release();
02972     }
02973     object->Release();
02974   }
02975 
02976   if (stream->handle[1].object) {
02977     LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object;
02978     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
02979     if (buffer) {
02980       buffer->Stop();
02981       buffer->Release();
02982     }
02983     object->Release();
02984   }
02985 
02986   if (stream->userBuffer)
02987     free(stream->userBuffer);
02988 
02989   if (stream->deviceBuffer)
02990     free(stream->deviceBuffer);
02991 
02992   free(stream);
02993   streams.erase(streamId);
02994 }
02995 
02996 void RtAudio :: startStream(int streamId)
02997 {
02998   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
02999 
03000   MUTEX_LOCK(&stream->mutex);
03001 
03002   if (stream->state == STREAM_RUNNING)
03003     goto unlock;
03004 
03005   HRESULT result;
03006   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
03007     LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
03008     result = buffer->Play(0, 0, DSBPLAY_LOOPING );
03009     if ( FAILED(result) ) {
03010       sprintf(message, "RtAudio: Unable to start DS buffer (%s): %s.",
03011               devices[stream->device[0]].name, getErrorString(result));
03012       error(RtError::DRIVER_ERROR);
03013     }
03014   }
03015 
03016   if (stream->mode == RECORD || stream->mode == DUPLEX) {
03017     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
03018     result = buffer->Start(DSCBSTART_LOOPING );
03019     if ( FAILED(result) ) {
03020       sprintf(message, "RtAudio: Unable to start DS capture buffer (%s): %s.",
03021               devices[stream->device[1]].name, getErrorString(result));
03022       error(RtError::DRIVER_ERROR);
03023     }
03024   }
03025   stream->state = STREAM_RUNNING;
03026 
03027  unlock:
03028   MUTEX_UNLOCK(&stream->mutex);
03029 }
03030 
03031 void RtAudio :: stopStream(int streamId)
03032 {
03033   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
03034 
03035   MUTEX_LOCK(&stream->mutex);
03036 
03037   if (stream->state == STREAM_STOPPED) {
03038     MUTEX_UNLOCK(&stream->mutex);
03039     return;
03040   }
03041 
03042   // There is no specific DirectSound API call to "drain" a buffer
03043   // before stopping.  We can hack this for playback by writing zeroes
03044   // for another bufferSize * nBuffers frames.  For capture, the
03045   // concept is less clear so we'll repeat what we do in the
03046   // abortStream() case.
03047   HRESULT result;
03048   DWORD dsBufferSize;
03049   LPVOID buffer1 = NULL;
03050   LPVOID buffer2 = NULL;
03051   DWORD bufferSize1 = 0;
03052   DWORD bufferSize2 = 0;
03053   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
03054 
03055     DWORD currentPos, safePos;
03056     long buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0];
03057     buffer_bytes *= formatBytes(stream->deviceFormat[0]);
03058 
03059     LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
03060     UINT nextWritePos = stream->handle[0].bufferPointer;
03061     dsBufferSize = buffer_bytes * stream->nBuffers;
03062 
03063     // Write zeroes for nBuffer counts.
03064     for (int i=0; i<stream->nBuffers; i++) {
03065 
03066       // Find out where the read and "safe write" pointers are.
03067       result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
03068       if ( FAILED(result) ) {
03069         sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
03070                 devices[stream->device[0]].name, getErrorString(result));
03071         error(RtError::DRIVER_ERROR);
03072       }
03073 
03074       if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
03075       DWORD endWrite = nextWritePos + buffer_bytes;
03076 
03077       // Check whether the entire write region is behind the play pointer.
03078       while ( currentPos < endWrite ) {
03079         float millis = (endWrite - currentPos) * 900.0;
03080         millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate);
03081         if ( millis < 1.0 ) millis = 1.0;
03082         Sleep( (DWORD) millis );
03083 
03084         // Wake up, find out where we are now
03085         result = dsBuffer->GetCurrentPosition( &currentPos, &safePos );
03086         if ( FAILED(result) ) {
03087           sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
03088                   devices[stream->device[0]].name, getErrorString(result));
03089           error(RtError::DRIVER_ERROR);
03090         }
03091         if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
03092       }
03093 
03094       // Lock free space in the buffer
03095       result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1,
03096                                &bufferSize1, &buffer2, &bufferSize2, 0);
03097       if ( FAILED(result) ) {
03098         sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.",
03099                 devices[stream->device[0]].name, getErrorString(result));
03100         error(RtError::DRIVER_ERROR);
03101       }
03102 
03103       // Zero the free space
03104       ZeroMemory(buffer1, bufferSize1);
03105       if (buffer2 != NULL) ZeroMemory(buffer2, bufferSize2);
03106 
03107       // Update our buffer offset and unlock sound buffer
03108       dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
03109       if ( FAILED(result) ) {
03110         sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.",
03111                 devices[stream->device[0]].name, getErrorString(result));
03112         error(RtError::DRIVER_ERROR);
03113       }
03114       nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize;
03115       stream->handle[0].bufferPointer = nextWritePos;
03116     }
03117 
03118     // If we play again, start at the beginning of the buffer.
03119     stream->handle[0].bufferPointer = 0;
03120   }
03121 
03122   if (stream->mode == RECORD || stream->mode == DUPLEX) {
03123     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
03124     buffer1 = NULL;
03125     bufferSize1 = 0;
03126 
03127     result = buffer->Stop();
03128     if ( FAILED(result) ) {
03129       sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s",
03130               devices[stream->device[1]].name, getErrorString(result));
03131       error(RtError::DRIVER_ERROR);
03132     }
03133 
03134     dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1];
03135     dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
03136 
03137     // Lock the buffer and clear it so that if we start to play again,
03138     // we won't have old data playing.
03139     result = buffer->Lock(0, dsBufferSize, &buffer1, &bufferSize1, NULL, NULL, 0);
03140     if ( FAILED(result) ) {
03141       sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
03142               devices[stream->device[1]].name, getErrorString(result));
03143       error(RtError::DRIVER_ERROR);
03144     }
03145 
03146     // Zero the DS buffer
03147     ZeroMemory(buffer1, bufferSize1);
03148 
03149     // Unlock the DS buffer
03150     result = buffer->Unlock(buffer1, bufferSize1, NULL, 0);
03151     if ( FAILED(result) ) {
03152       sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
03153               devices[stream->device[1]].name, getErrorString(result));
03154       error(RtError::DRIVER_ERROR);
03155     }
03156 
03157     // If we start recording again, we must begin at beginning of buffer.
03158     stream->handle[1].bufferPointer = 0;
03159   }
03160   stream->state = STREAM_STOPPED;
03161 
03162   MUTEX_UNLOCK(&stream->mutex);
03163 }
03164 
03165 void RtAudio :: abortStream(int streamId)
03166 {
03167   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
03168 
03169   MUTEX_LOCK(&stream->mutex);
03170 
03171   if (stream->state == STREAM_STOPPED)
03172     goto unlock;
03173 
03174   HRESULT result;
03175   long dsBufferSize;
03176   LPVOID audioPtr;
03177   DWORD dataLen;
03178   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
03179     LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
03180     result = buffer->Stop();
03181     if ( FAILED(result) ) {
03182       sprintf(message, "RtAudio: Unable to stop DS buffer (%s): %s",
03183               devices[stream->device[0]].name, getErrorString(result));
03184       error(RtError::DRIVER_ERROR);
03185     }
03186 
03187     dsBufferSize = stream->bufferSize * stream->nDeviceChannels[0];
03188     dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers;
03189 
03190     // Lock the buffer and clear it so that if we start to play again,
03191     // we won't have old data playing.
03192     result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0);
03193     if ( FAILED(result) ) {
03194       sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.",
03195               devices[stream->device[0]].name, getErrorString(result));
03196       error(RtError::DRIVER_ERROR);
03197     }
03198 
03199     // Zero the DS buffer
03200     ZeroMemory(audioPtr, dataLen);
03201 
03202     // Unlock the DS buffer
03203     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
03204     if ( FAILED(result) ) {
03205       sprintf(message, "RtAudio: Unable to unlock DS buffer (%s): %s.",
03206               devices[stream->device[0]].name, getErrorString(result));
03207       error(RtError::DRIVER_ERROR);
03208     }
03209 
03210     // If we start playing again, we must begin at beginning of buffer.
03211     stream->handle[0].bufferPointer = 0;
03212   }
03213 
03214   if (stream->mode == RECORD || stream->mode == DUPLEX) {
03215     LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
03216     audioPtr = NULL;
03217     dataLen = 0;
03218 
03219     result = buffer->Stop();
03220     if ( FAILED(result) ) {
03221       sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s",
03222               devices[stream->device[1]].name, getErrorString(result));
03223       error(RtError::DRIVER_ERROR);
03224     }
03225 
03226     dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1];
03227     dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
03228 
03229     // Lock the buffer and clear it so that if we start to play again,
03230     // we won't have old data playing.
03231     result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0);
03232     if ( FAILED(result) ) {
03233       sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
03234               devices[stream->device[1]].name, getErrorString(result));
03235       error(RtError::DRIVER_ERROR);
03236     }
03237 
03238     // Zero the DS buffer
03239     ZeroMemory(audioPtr, dataLen);
03240 
03241     // Unlock the DS buffer
03242     result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
03243     if ( FAILED(result) ) {
03244       sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
03245               devices[stream->device[1]].name, getErrorString(result));
03246       error(RtError::DRIVER_ERROR);
03247     }
03248 
03249     // If we start recording again, we must begin at beginning of buffer.
03250     stream->handle[1].bufferPointer = 0;
03251   }
03252   stream->state = STREAM_STOPPED;
03253 
03254  unlock:
03255   MUTEX_UNLOCK(&stream->mutex);
03256 }
03257 
03258 int RtAudio :: streamWillBlock(int streamId)
03259 {
03260   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
03261 
03262   MUTEX_LOCK(&stream->mutex);
03263 
03264   int channels;
03265   int frames = 0;
03266   if (stream->state == STREAM_STOPPED)
03267     goto unlock;
03268 
03269   HRESULT result;
03270   DWORD currentPos, safePos;
03271   channels = 1;
03272   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
03273 
03274     LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
03275     UINT nextWritePos = stream->handle[0].bufferPointer;
03276     channels = stream->nDeviceChannels[0];
03277     DWORD dsBufferSize = stream->bufferSize * channels;
03278     dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers;
03279 
03280     // Find out where the read and "safe write" pointers are.
03281     result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
03282     if ( FAILED(result) ) {
03283       sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
03284               devices[stream->device[0]].name, getErrorString(result));
03285       error(RtError::DRIVER_ERROR);
03286     }
03287 
03288     if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
03289     frames = currentPos - nextWritePos;
03290     frames /= channels * formatBytes(stream->deviceFormat[0]);
03291   }
03292 
03293   if (stream->mode == RECORD || stream->mode == DUPLEX) {
03294 
03295     LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
03296     UINT nextReadPos = stream->handle[1].bufferPointer;
03297     channels = stream->nDeviceChannels[1];
03298     DWORD dsBufferSize = stream->bufferSize * channels;
03299     dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
03300 
03301     // Find out where the write and "safe read" pointers are.
03302     result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
03303     if ( FAILED(result) ) {
03304       sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
03305               devices[stream->device[1]].name, getErrorString(result));
03306       error(RtError::DRIVER_ERROR);
03307     }
03308 
03309     if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
03310 
03311     if (stream->mode == DUPLEX ) {
03312       // Take largest value of the two.
03313       int temp = safePos - nextReadPos;
03314       temp /= channels * formatBytes(stream->deviceFormat[1]);
03315       frames = ( temp > frames ) ? temp : frames;
03316     }
03317     else {
03318       frames = safePos - nextReadPos;
03319       frames /= channels * formatBytes(stream->deviceFormat[1]);
03320     }
03321   }
03322 
03323   frames = stream->bufferSize - frames;
03324   if (frames < 0) frames = 0;
03325 
03326  unlock:
03327   MUTEX_UNLOCK(&stream->mutex);
03328   return frames;
03329 }
03330 
03331 void RtAudio :: tickStream(int streamId)
03332 {
03333   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
03334 
03335   int stopStream = 0;
03336   if (stream->state == STREAM_STOPPED) {
03337     if (stream->usingCallback) Sleep(50); // sleep 50 milliseconds
03338     return;
03339   }
03340   else if (stream->usingCallback) {
03341     stopStream = stream->callback(stream->userBuffer, stream->bufferSize, stream->userData);    
03342   }
03343 
03344   MUTEX_LOCK(&stream->mutex);
03345 
03346   // The state might change while waiting on a mutex.
03347   if (stream->state == STREAM_STOPPED) {
03348     MUTEX_UNLOCK(&stream->mutex);
03349     if (stream->usingCallback && stopStream)
03350       this->stopStream(streamId);
03351   }
03352 
03353   HRESULT result;
03354   DWORD currentPos, safePos;
03355   LPVOID buffer1 = NULL;
03356   LPVOID buffer2 = NULL;
03357   DWORD bufferSize1 = 0;
03358   DWORD bufferSize2 = 0;
03359   char *buffer;
03360   long buffer_bytes;
03361   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
03362 
03363     // Setup parameters and do buffer conversion if necessary.
03364     if (stream->doConvertBuffer[0]) {
03365       convertStreamBuffer(stream, PLAYBACK);
03366       buffer = stream->deviceBuffer;
03367       buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0];
03368       buffer_bytes *= formatBytes(stream->deviceFormat[0]);
03369     }
03370     else {
03371       buffer = stream->userBuffer;
03372       buffer_bytes = stream->bufferSize * stream->nUserChannels[0];
03373       buffer_bytes *= formatBytes(stream->userFormat);
03374     }
03375 
03376     // No byte swapping necessary in DirectSound implementation.
03377 
03378     LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
03379     UINT nextWritePos = stream->handle[0].bufferPointer;
03380     DWORD dsBufferSize = buffer_bytes * stream->nBuffers;
03381 
03382     // Find out where the read and "safe write" pointers are.
03383     result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
03384     if ( FAILED(result) ) {
03385       sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
03386               devices[stream->device[0]].name, getErrorString(result));
03387       error(RtError::DRIVER_ERROR);
03388     }
03389 
03390     if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
03391     DWORD endWrite = nextWritePos + buffer_bytes;
03392 
03393     // Check whether the entire write region is behind the play pointer.
03394     while ( currentPos < endWrite ) {
03395       // If we are here, then we must wait until the play pointer gets
03396       // beyond the write region.  The approach here is to use the
03397       // Sleep() function to suspend operation until safePos catches
03398       // up. Calculate number of milliseconds to wait as:
03399       //   time = distance * (milliseconds/second) * fudgefactor /
03400       //          ((bytes/sample) * (samples/second))
03401       // A "fudgefactor" less than 1 is used because it was found
03402       // that sleeping too long was MUCH worse than sleeping for
03403       // several shorter periods.
03404       float millis = (endWrite - currentPos) * 900.0;
03405       millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate);
03406       if ( millis < 1.0 ) millis = 1.0;
03407       Sleep( (DWORD) millis );
03408 
03409       // Wake up, find out where we are now
03410       result = dsBuffer->GetCurrentPosition( &currentPos, &safePos );
03411       if ( FAILED(result) ) {
03412         sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
03413               devices[stream->device[0]].name, getErrorString(result));
03414         error(RtError::DRIVER_ERROR);
03415       }
03416       if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
03417     }
03418 
03419     // Lock free space in the buffer
03420     result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1,
03421                              &bufferSize1, &buffer2, &bufferSize2, 0);
03422     if ( FAILED(result) ) {
03423       sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.",
03424               devices[stream->device[0]].name, getErrorString(result));
03425       error(RtError::DRIVER_ERROR);
03426     }
03427 
03428     // Copy our buffer into the DS buffer
03429     CopyMemory(buffer1, buffer, bufferSize1);
03430     if (buffer2 != NULL) CopyMemory(buffer2, buffer+bufferSize1, bufferSize2);
03431 
03432     // Update our buffer offset and unlock sound buffer
03433     dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
03434     if ( FAILED(result) ) {
03435       sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.",
03436               devices[stream->device[0]].name, getErrorString(result));
03437       error(RtError::DRIVER_ERROR);
03438     }
03439     nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize;
03440     stream->handle[0].bufferPointer = nextWritePos;
03441   }
03442 
03443   if (stream->mode == RECORD || stream->mode == DUPLEX) {
03444 
03445     // Setup parameters.
03446     if (stream->doConvertBuffer[1]) {
03447       buffer = stream->deviceBuffer;
03448       buffer_bytes = stream->bufferSize * stream->nDeviceChannels[1];
03449       buffer_bytes *= formatBytes(stream->deviceFormat[1]);
03450     }
03451     else {
03452       buffer = stream->userBuffer;
03453       buffer_bytes = stream->bufferSize * stream->nUserChannels[1];
03454       buffer_bytes *= formatBytes(stream->userFormat);
03455     }
03456 
03457     LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
03458     UINT nextReadPos = stream->handle[1].bufferPointer;
03459     DWORD dsBufferSize = buffer_bytes * stream->nBuffers;
03460 
03461     // Find out where the write and "safe read" pointers are.
03462     result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
03463     if ( FAILED(result) ) {
03464       sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
03465               devices[stream->device[1]].name, getErrorString(result));
03466       error(RtError::DRIVER_ERROR);
03467     }
03468 
03469     if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
03470     DWORD endRead = nextReadPos + buffer_bytes;
03471 
03472     // Check whether the entire write region is behind the play pointer.
03473     while ( safePos < endRead ) {
03474       // See comments for playback.
03475       float millis = (endRead - safePos) * 900.0;
03476       millis /= ( formatBytes(stream->deviceFormat[1]) * stream->sampleRate);
03477       if ( millis < 1.0 ) millis = 1.0;
03478       Sleep( (DWORD) millis );
03479 
03480       // Wake up, find out where we are now
03481       result = dsBuffer->GetCurrentPosition( &currentPos, &safePos );
03482       if ( FAILED(result) ) {
03483         sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
03484                 devices[stream->device[1]].name, getErrorString(result));
03485         error(RtError::DRIVER_ERROR);
03486       }
03487       
03488       if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
03489     }
03490 
03491     // Lock free space in the buffer
03492     result = dsBuffer->Lock (nextReadPos, buffer_bytes, &buffer1,
03493                              &bufferSize1, &buffer2, &bufferSize2, 0);
03494     if ( FAILED(result) ) {
03495       sprintf(message, "RtAudio: Unable to lock DS buffer during capture (%s): %s.",
03496               devices[stream->device[1]].name, getErrorString(result));
03497       error(RtError::DRIVER_ERROR);
03498     }
03499 
03500     // Copy our buffer into the DS buffer
03501     CopyMemory(buffer, buffer1, bufferSize1);
03502     if (buffer2 != NULL) CopyMemory(buffer+bufferSize1, buffer2, bufferSize2);
03503 
03504     // Update our buffer offset and unlock sound buffer
03505     nextReadPos = (nextReadPos + bufferSize1 + bufferSize2) % dsBufferSize;
03506     dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
03507     if ( FAILED(result) ) {
03508       sprintf(message, "RtAudio: Unable to unlock DS buffer during capture (%s): %s.",
03509               devices[stream->device[1]].name, getErrorString(result));
03510       error(RtError::DRIVER_ERROR);
03511     }
03512     stream->handle[1].bufferPointer = nextReadPos;
03513 
03514     // No byte swapping necessary in DirectSound implementation.
03515 
03516     // Do buffer conversion if necessary.
03517     if (stream->doConvertBuffer[1])
03518       convertStreamBuffer(stream, RECORD);
03519   }
03520 
03521   MUTEX_UNLOCK(&stream->mutex);
03522 
03523   if (stream->usingCallback && stopStream)
03524     this->stopStream(streamId);
03525 }
03526 
03527 // Definitions for utility functions and callbacks
03528 // specific to the DirectSound implementation.
03529 
03530 extern "C" unsigned __stdcall callbackHandler(void *ptr)
03531 {
03532   RtAudio *object = thread_info.object;
03533   int stream = thread_info.streamId;
03534   bool *usingCallback = (bool *) ptr;
03535 
03536   while ( *usingCallback ) {
03537     try {
03538       object->tickStream(stream);
03539     }
03540     catch (RtError &exception) {
03541       fprintf(stderr, "\nCallback thread error (%s) ... closing thread.\n\n",
03542               exception.getMessage());
03543       break;
03544     }
03545   }
03546 
03547   _endthreadex( 0 );
03548   return 0;
03549 }
03550 
03551 static bool CALLBACK deviceCountCallback(LPGUID lpguid,
03552                                          LPCSTR lpcstrDescription,
03553                                          LPCSTR lpcstrModule,
03554                                          LPVOID lpContext)
03555 {
03556   int *pointer = ((int *) lpContext);
03557   (*pointer)++;
03558 
03559   return true;
03560 }
03561 
03562 static bool CALLBACK deviceInfoCallback(LPGUID lpguid,
03563                                         LPCSTR lpcstrDescription,
03564                                         LPCSTR lpcstrModule,
03565                                         LPVOID lpContext)
03566 {
03567   enum_info *info = ((enum_info *) lpContext);
03568   while (strlen(info->name) > 0) info++;
03569 
03570   strncpy(info->name, lpcstrDescription, 64);
03571   info->id = lpguid;
03572 
03573         HRESULT    hr;
03574   info->isValid = false;
03575   if (info->isInput == true) {
03576     DSCCAPS               caps;
03577     LPDIRECTSOUNDCAPTURE  object;
03578 
03579     hr = DirectSoundCaptureCreate(  lpguid, &object,   NULL );
03580     if( hr != DS_OK ) return true;
03581 
03582     caps.dwSize = sizeof(caps);
03583     hr = object->GetCaps( &caps );
03584     if( hr == DS_OK ) {
03585       if (caps.dwChannels > 0 && caps.dwFormats > 0)
03586         info->isValid = true;
03587     }
03588     object->Release();
03589   }
03590   else {
03591     DSCAPS         caps;
03592     LPDIRECTSOUND  object;
03593     hr = DirectSoundCreate(  lpguid, &object,   NULL );
03594     if( hr != DS_OK ) return true;
03595 
03596     caps.dwSize = sizeof(caps);
03597     hr = object->GetCaps( &caps );
03598     if( hr == DS_OK ) {
03599       if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO )
03600         info->isValid = true;
03601     }
03602     object->Release();
03603   }
03604 
03605   return true;
03606 }
03607 
03608 static char* getErrorString(int code)
03609 {
03610         switch (code) {
03611 
03612   case DSERR_ALLOCATED:
03613     return "Direct Sound already allocated";
03614 
03615   case DSERR_CONTROLUNAVAIL:
03616     return "Direct Sound control unavailable";
03617 
03618   case DSERR_INVALIDPARAM:
03619     return "Direct Sound invalid parameter";
03620 
03621   case DSERR_INVALIDCALL:
03622     return "Direct Sound invalid call";
03623 
03624   case DSERR_GENERIC:
03625     return "Direct Sound generic error";
03626 
03627   case DSERR_PRIOLEVELNEEDED:
03628     return "Direct Sound Priority level needed";
03629 
03630   case DSERR_OUTOFMEMORY:
03631     return "Direct Sound out of memory";
03632 
03633   case DSERR_BADFORMAT:
03634     return "Direct Sound bad format";
03635 
03636   case DSERR_UNSUPPORTED:
03637     return "Direct Sound unsupported error";
03638 
03639   case DSERR_NODRIVER:
03640     return "Direct Sound no driver error";
03641 
03642   case DSERR_ALREADYINITIALIZED:
03643     return "Direct Sound already initialized";
03644 
03645   case DSERR_NOAGGREGATION:
03646     return "Direct Sound no aggregation";
03647 
03648   case DSERR_BUFFERLOST:
03649     return "Direct Sound buffer lost";
03650 
03651   case DSERR_OTHERAPPHASPRIO:
03652     return "Direct Sound other app has priority";
03653 
03654   case DSERR_UNINITIALIZED:
03655     return "Direct Sound uninitialized";
03656 
03657   default:
03658     return "Direct Sound unknown error";
03659         }
03660 }
03661 
03662 //******************** End of __WINDOWS_DS__ *********************//
03663 
03664 #elif defined(__IRIX_AL__) // SGI's AL API for IRIX
03665 
03666 #include <unistd.h>
03667 #include <errno.h>
03668 
03669 void RtAudio :: initialize(void)
03670 {
03671 
03672   // Count cards and devices
03673   nDevices = 0;
03674 
03675   // Determine the total number of input and output devices.
03676   nDevices = alQueryValues(AL_SYSTEM, AL_DEVICES, 0, 0, 0, 0);
03677   if (nDevices < 0) {
03678     sprintf(message, "RtAudio: AL error counting devices: %s.",
03679             alGetErrorString(oserror()));
03680     error(RtError::DRIVER_ERROR);
03681   }
03682 
03683   if (nDevices <= 0) return;
03684 
03685   ALvalue *vls = (ALvalue *) new ALvalue[nDevices];
03686 
03687   // Add one for our default input/output devices.
03688   nDevices++;
03689 
03690   //  Allocate the RTAUDIO_DEVICE structures.
03691   devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
03692   if (devices == NULL) {
03693     sprintf(message, "RtAudio: memory allocation error!");
03694     error(RtError::MEMORY_ERROR);
03695   }
03696 
03697   // Write device ascii identifiers to device info structure.
03698   char name[32];
03699   int outs, ins, i;
03700   ALpv pvs[1];
03701   pvs[0].param = AL_NAME;
03702   pvs[0].value.ptr = name;
03703   pvs[0].sizeIn = 32;
03704 
03705   strcpy(devices[0].name, "Default Input/Output Devices");
03706 
03707   outs = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, vls, nDevices-1, 0, 0);
03708   if (outs < 0) {
03709     sprintf(message, "RtAudio: AL error getting output devices: %s.",
03710             alGetErrorString(oserror()));
03711     error(RtError::DRIVER_ERROR);
03712   }
03713 
03714   for (i=0; i<outs; i++) {
03715     if (alGetParams(vls[i].i, pvs, 1) < 0) {
03716       sprintf(message, "RtAudio: AL error querying output devices: %s.",
03717               alGetErrorString(oserror()));
03718       error(RtError::DRIVER_ERROR);
03719     }
03720     strncpy(devices[i+1].name, name, 32);
03721     devices[i+1].id[0] = vls[i].i;
03722   }
03723 
03724   ins = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &vls[outs], nDevices-outs-1, 0, 0);
03725   if (ins < 0) {
03726     sprintf(message, "RtAudio: AL error getting input devices: %s.",
03727             alGetErrorString(oserror()));
03728     error(RtError::DRIVER_ERROR);
03729   }
03730 
03731   for (i=outs; i<ins+outs; i++) {
03732     if (alGetParams(vls[i].i, pvs, 1) < 0) {
03733       sprintf(message, "RtAudio: AL error querying input devices: %s.",
03734               alGetErrorString(oserror()));
03735       error(RtError::DRIVER_ERROR);
03736     }
03737     strncpy(devices[i+1].name, name, 32);
03738     devices[i+1].id[1] = vls[i].i;
03739   }
03740 
03741   delete [] vls;
03742 
03743   return;
03744 }
03745 
03746 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
03747 {
03748   int resource, result, i;
03749   ALvalue value;
03750   ALparamInfo pinfo;
03751 
03752   // Get output resource ID if it exists.
03753   if ( !strncmp(info->name, "Default Input/Output Devices", 28) ) {
03754     result = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, &value, 1, 0, 0);
03755     if (result < 0) {
03756       sprintf(message, "RtAudio: AL error getting default output device id: %s.",
03757               alGetErrorString(oserror()));
03758       error(RtError::WARNING);
03759     }
03760     else
03761       resource = value.i;
03762   }
03763   else
03764     resource = info->id[0];
03765 
03766   if (resource > 0) {
03767 
03768     // Probe output device parameters.
03769     result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0);
03770     if (result < 0) {
03771       sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.",
03772               info->name, alGetErrorString(oserror()));
03773       error(RtError::WARNING);
03774     }
03775     else {
03776       info->maxOutputChannels = value.i;
03777       info->minOutputChannels = 1;
03778     }
03779 
03780     result = alGetParamInfo(resource, AL_RATE, &pinfo);
03781     if (result < 0) {
03782       sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.",
03783               info->name, alGetErrorString(oserror()));
03784       error(RtError::WARNING);
03785     }
03786     else {
03787       info->nSampleRates = 0;
03788       for (i=0; i<MAX_SAMPLE_RATES; i++) {
03789         if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) {
03790           info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
03791           info->nSampleRates++;
03792         }
03793       }
03794     }
03795 
03796     // The AL library supports all our formats, except 24-bit and 32-bit ints.
03797     info->nativeFormats = (RTAUDIO_FORMAT) 51;
03798   }
03799 
03800   // Now get input resource ID if it exists.
03801   if ( !strncmp(info->name, "Default Input/Output Devices", 28) ) {
03802     result = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &value, 1, 0, 0);
03803     if (result < 0) {
03804       sprintf(message, "RtAudio: AL error getting default input device id: %s.",
03805               alGetErrorString(oserror()));
03806       error(RtError::WARNING);
03807     }
03808     else
03809       resource = value.i;
03810   }
03811   else
03812     resource = info->id[1];
03813 
03814   if (resource > 0) {
03815 
03816     // Probe input device parameters.
03817     result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0);
03818     if (result < 0) {
03819       sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.",
03820               info->name, alGetErrorString(oserror()));
03821       error(RtError::WARNING);
03822     }
03823     else {
03824       info->maxInputChannels = value.i;
03825       info->minInputChannels = 1;
03826     }
03827 
03828     result = alGetParamInfo(resource, AL_RATE, &pinfo);
03829     if (result < 0) {
03830       sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.",
03831               info->name, alGetErrorString(oserror()));
03832       error(RtError::WARNING);
03833     }
03834     else {
03835       // In the case of the default device, these values will
03836       // overwrite the rates determined for the output device.  Since
03837       // the input device is most likely to be more limited than the
03838       // output device, this is ok.
03839       info->nSampleRates = 0;
03840       for (i=0; i<MAX_SAMPLE_RATES; i++) {
03841         if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) {
03842           info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
03843           info->nSampleRates++;
03844         }
03845       }
03846     }
03847 
03848     // The AL library supports all our formats, except 24-bit and 32-bit ints.
03849     info->nativeFormats = (RTAUDIO_FORMAT) 51;
03850   }
03851 
03852   if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 )
03853     return;
03854   if ( info->nSampleRates == 0 )
03855     return;
03856 
03857   // Determine duplex status.
03858   if (info->maxInputChannels < info->maxOutputChannels)
03859     info->maxDuplexChannels = info->maxInputChannels;
03860   else
03861     info->maxDuplexChannels = info->maxOutputChannels;
03862   if (info->minInputChannels < info->minOutputChannels)
03863     info->minDuplexChannels = info->minInputChannels;
03864   else
03865     info->minDuplexChannels = info->minOutputChannels;
03866 
03867   if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true;
03868   else info->hasDuplexSupport = false;
03869 
03870   info->probed = true;
03871 
03872   return;
03873 }
03874 
03875 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
03876                                 STREAM_MODE mode, int channels, 
03877                                 int sampleRate, RTAUDIO_FORMAT format,
03878                                 int *bufferSize, int numberOfBuffers)
03879 {
03880   int result, resource, nBuffers;
03881   ALconfig al_config;
03882   ALport port;
03883   ALpv pvs[2];
03884 
03885   // Get a new ALconfig structure.
03886   al_config = alNewConfig();
03887   if ( !al_config ) {
03888     sprintf(message,"RtAudio: can't get AL config: %s.",
03889             alGetErrorString(oserror()));
03890     error(RtError::WARNING);
03891     return FAILURE;
03892   }
03893 
03894   // Set the channels.
03895   result = alSetChannels(al_config, channels);
03896   if ( result < 0 ) {
03897     sprintf(message,"RtAudio: can't set %d channels in AL config: %s.",
03898             channels, alGetErrorString(oserror()));
03899     error(RtError::WARNING);
03900     return FAILURE;
03901   }
03902 
03903   // Set the queue (buffer) size.
03904   if ( numberOfBuffers < 1 )
03905     nBuffers = 1;
03906   else
03907     nBuffers = numberOfBuffers;
03908   long buffer_size = *bufferSize * nBuffers;
03909   result = alSetQueueSize(al_config, buffer_size); // in sample frames
03910   if ( result < 0 ) {
03911     sprintf(message,"RtAudio: can't set buffer size (%ld) in AL config: %s.",
03912             buffer_size, alGetErrorString(oserror()));
03913     error(RtError::WARNING);
03914     return FAILURE;
03915   }
03916 
03917   // Set the data format.
03918   stream->userFormat = format;
03919   stream->deviceFormat[mode] = format;
03920   if (format == RTAUDIO_SINT8) {
03921     result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP);
03922     result = alSetWidth(al_config, AL_SAMPLE_8);
03923   }
03924   else if (format == RTAUDIO_SINT16) {
03925     result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP);
03926     result = alSetWidth(al_config, AL_SAMPLE_16);
03927   }
03928   else if (format == RTAUDIO_SINT24) {
03929     // Our 24-bit format assumes the upper 3 bytes of a 4 byte word.
03930     // The AL library uses the lower 3 bytes, so we'll need to do our
03931     // own conversion.
03932     result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
03933     stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
03934   }
03935   else if (format == RTAUDIO_SINT32) {
03936     // The AL library doesn't seem to support the 32-bit integer
03937     // format, so we'll need to do our own conversion.
03938     result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
03939     stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
03940   }
03941   else if (format == RTAUDIO_FLOAT32)
03942     result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
03943   else if (format == RTAUDIO_FLOAT64)
03944     result = alSetSampFmt(al_config, AL_SAMPFMT_DOUBLE);
03945 
03946   if ( result == -1 ) {
03947     sprintf(message,"RtAudio: AL error setting sample format in AL config: %s.",
03948             alGetErrorString(oserror()));
03949     error(RtError::WARNING);
03950     return FAILURE;
03951   }
03952 
03953   if (mode == PLAYBACK) {
03954 
03955     // Set our device.
03956     if (device == 0)
03957       resource = AL_DEFAULT_OUTPUT;
03958     else
03959       resource = devices[device].id[0];
03960     result = alSetDevice(al_config, resource);
03961     if ( result == -1 ) {
03962       sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.",
03963               devices[device].name, alGetErrorString(oserror()));
03964       error(RtError::WARNING);
03965       return FAILURE;
03966     }
03967 
03968     // Open the port.
03969     port = alOpenPort("RtAudio Output Port", "w", al_config);
03970     if( !port ) {
03971       sprintf(message,"RtAudio: AL error opening output port: %s.",
03972               alGetErrorString(oserror()));
03973       error(RtError::WARNING);
03974       return FAILURE;
03975     }
03976 
03977     // Set the sample rate
03978     pvs[0].param = AL_MASTER_CLOCK;
03979     pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
03980     pvs[1].param = AL_RATE;
03981     pvs[1].value.ll = alDoubleToFixed((double)sampleRate);
03982     result = alSetParams(resource, pvs, 2);
03983     if ( result < 0 ) {
03984       alClosePort(port);
03985       sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.",
03986               sampleRate, devices[device].name, alGetErrorString(oserror()));
03987       error(RtError::WARNING);
03988       return FAILURE;
03989     }
03990   }
03991   else { // mode == RECORD
03992 
03993     // Set our device.
03994     if (device == 0)
03995       resource = AL_DEFAULT_INPUT;
03996     else
03997       resource = devices[device].id[1];
03998     result = alSetDevice(al_config, resource);
03999     if ( result == -1 ) {
04000       sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.",
04001               devices[device].name, alGetErrorString(oserror()));
04002       error(RtError::WARNING);
04003       return FAILURE;
04004     }
04005 
04006     // Open the port.
04007     port = alOpenPort("RtAudio Output Port", "r", al_config);
04008     if( !port ) {
04009       sprintf(message,"RtAudio: AL error opening input port: %s.",
04010               alGetErrorString(oserror()));
04011       error(RtError::WARNING);
04012       return FAILURE;
04013     }
04014 
04015     // Set the sample rate
04016     pvs[0].param = AL_MASTER_CLOCK;
04017     pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
04018     pvs[1].param = AL_RATE;
04019     pvs[1].value.ll = alDoubleToFixed((double)sampleRate);
04020     result = alSetParams(resource, pvs, 2);
04021     if ( result < 0 ) {
04022       alClosePort(port);
04023       sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.",
04024               sampleRate, devices[device].name, alGetErrorString(oserror()));
04025       error(RtError::WARNING);
04026       return FAILURE;
04027     }
04028   }
04029 
04030   alFreeConfig(al_config);
04031 
04032   stream->nUserChannels[mode] = channels;
04033   stream->nDeviceChannels[mode] = channels;
04034 
04035   // Set handle and flags for buffer conversion
04036   stream->handle[mode] = port;
04037   stream->doConvertBuffer[mode] = false;
04038   if (stream->userFormat != stream->deviceFormat[mode])
04039     stream->doConvertBuffer[mode] = true;
04040 
04041   // Allocate necessary internal buffers
04042   if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
04043 
04044     long buffer_bytes;
04045     if (stream->nUserChannels[0] >= stream->nUserChannels[1])
04046       buffer_bytes = stream->nUserChannels[0];
04047     else
04048       buffer_bytes = stream->nUserChannels[1];
04049 
04050     buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
04051     if (stream->userBuffer) free(stream->userBuffer);
04052     stream->userBuffer = (char *) calloc(buffer_bytes, 1);
04053     if (stream->userBuffer == NULL)
04054       goto memory_error;
04055   }
04056 
04057   if ( stream->doConvertBuffer[mode] ) {
04058 
04059     long buffer_bytes;
04060     bool makeBuffer = true;
04061     if ( mode == PLAYBACK )
04062       buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
04063     else { // mode == RECORD
04064       buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
04065       if ( stream->mode == PLAYBACK ) {
04066         long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
04067         if ( buffer_bytes > bytes_out )
04068           buffer_bytes = (buffer_bytes > bytes_out) ? buffer_bytes : bytes_out;
04069         else
04070           makeBuffer = false;
04071       }
04072     }
04073 
04074     if ( makeBuffer ) {
04075       buffer_bytes *= *bufferSize;
04076       if (stream->deviceBuffer) free(stream->deviceBuffer);
04077       stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
04078       if (stream->deviceBuffer == NULL)
04079         goto memory_error;
04080     }
04081   }
04082 
04083   stream->device[mode] = device;
04084   stream->state = STREAM_STOPPED;
04085   if ( stream->mode == PLAYBACK && mode == RECORD )
04086     // We had already set up an output stream.
04087     stream->mode = DUPLEX;
04088   else
04089     stream->mode = mode;
04090   stream->nBuffers = nBuffers;
04091   stream->bufferSize = *bufferSize;
04092   stream->sampleRate = sampleRate;
04093 
04094   return SUCCESS;
04095 
04096  memory_error:
04097   if (stream->handle[0]) {
04098     alClosePort(stream->handle[0]);
04099     stream->handle[0] = 0;
04100   }
04101   if (stream->handle[1]) {
04102     alClosePort(stream->handle[1]);
04103     stream->handle[1] = 0;
04104   }
04105   if (stream->userBuffer) {
04106     free(stream->userBuffer);
04107     stream->userBuffer = 0;
04108   }
04109   sprintf(message, "RtAudio: ALSA error allocating buffer memory for device (%s).",
04110           devices[device].name);
04111   error(RtError::WARNING);
04112   return FAILURE;
04113 }
04114 
04115 void RtAudio :: cancelStreamCallback(int streamId)
04116 {
04117   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
04118 
04119   if (stream->usingCallback) {
04120     stream->usingCallback = false;
04121     pthread_cancel(stream->thread);
04122     pthread_join(stream->thread, NULL);
04123     stream->thread = 0;
04124     stream->callback = NULL;
04125     stream->userData = NULL;
04126   }
04127 }
04128 
04129 void RtAudio :: closeStream(int streamId)
04130 {
04131   // We don't want an exception to be thrown here because this
04132   // function is called by our class destructor.  So, do our own
04133   // streamId check.
04134   if ( streams.find( streamId ) == streams.end() ) {
04135     sprintf(message, "RtAudio: invalid stream identifier!");
04136     error(RtError::WARNING);
04137     return;
04138   }
04139 
04140   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
04141 
04142   if (stream->usingCallback) {
04143     pthread_cancel(stream->thread);
04144     pthread_join(stream->thread, NULL);
04145   }
04146 
04147   pthread_mutex_destroy(&stream->mutex);
04148 
04149   if (stream->handle[0])
04150     alClosePort(stream->handle[0]);
04151 
04152   if (stream->handle[1])
04153     alClosePort(stream->handle[1]);
04154 
04155   if (stream->userBuffer)
04156     free(stream->userBuffer);
04157 
04158   if (stream->deviceBuffer)
04159     free(stream->deviceBuffer);
04160 
04161   free(stream);
04162   streams.erase(streamId);
04163 }
04164 
04165 void RtAudio :: startStream(int streamId)
04166 {
04167   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
04168 
04169   if (stream->state == STREAM_RUNNING)
04170     return;
04171 
04172   // The AL port is ready as soon as it is opened.
04173   stream->state = STREAM_RUNNING;
04174 }
04175 
04176 void RtAudio :: stopStream(int streamId)
04177 {
04178   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
04179 
04180   MUTEX_LOCK(&stream->mutex);
04181 
04182   if (stream->state == STREAM_STOPPED)
04183     goto unlock;
04184 
04185   int result;
04186   int buffer_size = stream->bufferSize * stream->nBuffers;
04187 
04188   if (stream->mode == PLAYBACK || stream->mode == DUPLEX)
04189     alZeroFrames(stream->handle[0], buffer_size);
04190 
04191   if (stream->mode == RECORD || stream->mode == DUPLEX) {
04192     result = alDiscardFrames(stream->handle[1], buffer_size);
04193     if (result == -1) {
04194       sprintf(message, "RtAudio: AL error draining stream device (%s): %s.",
04195               devices[stream->device[1]].name, alGetErrorString(oserror()));
04196       error(RtError::DRIVER_ERROR);
04197     }
04198   }
04199   stream->state = STREAM_STOPPED;
04200 
04201  unlock:
04202   MUTEX_UNLOCK(&stream->mutex);
04203 }
04204 
04205 void RtAudio :: abortStream(int streamId)
04206 {
04207   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
04208 
04209   MUTEX_LOCK(&stream->mutex);
04210 
04211   if (stream->state == STREAM_STOPPED)
04212     goto unlock;
04213 
04214   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
04215 
04216     int buffer_size = stream->bufferSize * stream->nBuffers;
04217     int result = alDiscardFrames(stream->handle[0], buffer_size);
04218     if (result == -1) {
04219       sprintf(message, "RtAudio: AL error aborting stream device (%s): %s.",
04220               devices[stream->device[0]].name, alGetErrorString(oserror()));
04221       error(RtError::DRIVER_ERROR);
04222     }
04223   }
04224 
04225   // There is no clear action to take on the input stream, since the
04226   // port will continue to run in any event.
04227   stream->state = STREAM_STOPPED;
04228 
04229  unlock:
04230   MUTEX_UNLOCK(&stream->mutex);
04231 }
04232 
04233 int RtAudio :: streamWillBlock(int streamId)
04234 {
04235   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
04236 
04237   MUTEX_LOCK(&stream->mutex);
04238 
04239   int frames = 0;
04240   if (stream->state == STREAM_STOPPED)
04241     goto unlock;
04242 
04243   int err = 0;
04244   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
04245     err = alGetFillable(stream->handle[0]);
04246     if (err < 0) {
04247       sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.",
04248               devices[stream->device[0]].name, alGetErrorString(oserror()));
04249       error(RtError::DRIVER_ERROR);
04250     }
04251   }
04252 
04253   frames = err;
04254 
04255   if (stream->mode == RECORD || stream->mode == DUPLEX) {
04256     err = alGetFilled(stream->handle[1]);
04257     if (err < 0) {
04258       sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.",
04259               devices[stream->device[1]].name, alGetErrorString(oserror()));
04260       error(RtError::DRIVER_ERROR);
04261     }
04262     if (frames > err) frames = err;
04263   }
04264 
04265   frames = stream->bufferSize - frames;
04266   if (frames < 0) frames = 0;
04267 
04268  unlock:
04269   MUTEX_UNLOCK(&stream->mutex);
04270   return frames;
04271 }
04272 
04273 void RtAudio :: tickStream(int streamId)
04274 {
04275   RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
04276 
04277   int stopStream = 0;
04278   if (stream->state == STREAM_STOPPED) {
04279     if (stream->usingCallback) usleep(50000); // sleep 50 milliseconds
04280     return;
04281   }
04282   else if (stream->usingCallback) {
04283     stopStream = stream->callback(stream->userBuffer, stream->bufferSize, stream->userData);    
04284   }
04285 
04286   MUTEX_LOCK(&stream->mutex);
04287 
04288   // The state might change while waiting on a mutex.
04289   if (stream->state == STREAM_STOPPED)
04290     goto unlock;
04291 
04292   char *buffer;
04293   int channels;
04294   RTAUDIO_FORMAT format;
04295   if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
04296 
04297     // Setup parameters and do buffer conversion if necessary.
04298     if (stream->doConvertBuffer[0]) {
04299       convertStreamBuffer(stream, PLAYBACK);
04300       buffer = stream->deviceBuffer;
04301       channels = stream->nDeviceChannels[0];
04302       format = stream->deviceFormat[0];
04303     }
04304     else {
04305       buffer = stream->userBuffer;
04306       channels = stream->nUserChannels[0];
04307       format = stream->userFormat;
04308     }
04309 
04310     // Do byte swapping if necessary.
04311     if (stream->doByteSwap[0])
04312       byteSwapBuffer(buffer, stream->bufferSize * channels, format);
04313 
04314     // Write interleaved samples to device.
04315     alWriteFrames(stream->handle[0], buffer, stream->bufferSize);
04316   }
04317 
04318   if (stream->mode == RECORD || stream->mode == DUPLEX) {
04319 
04320     // Setup parameters.
04321     if (stream->doConvertBuffer[1]) {
04322       buffer = stream->deviceBuffer;
04323       channels = stream->nDeviceChannels[1];
04324       format = stream->deviceFormat[1];
04325     }
04326     else {
04327       buffer = stream->userBuffer;
04328       channels = stream->nUserChannels[1];
04329       format = stream->userFormat;
04330     }
04331 
04332     // Read interleaved samples from device.
04333     alReadFrames(stream->handle[1], buffer, stream->bufferSize);
04334 
04335     // Do byte swapping if necessary.
04336     if (stream->doByteSwap[1])
04337       byteSwapBuffer(buffer, stream->bufferSize * channels, format);
04338 
04339     // Do buffer conversion if necessary.
04340     if (stream->doConvertBuffer[1])
04341       convertStreamBuffer(stream, RECORD);
04342   }
04343 
04344  unlock:
04345   MUTEX_UNLOCK(&stream->mutex);
04346 
04347   if (stream->usingCallback && stopStream)
04348     this->stopStream(streamId);
04349 }
04350 
04351 extern "C" void *callbackHandler(void *ptr)
04352 {
04353   RtAudio *object = thread_info.object;
04354   int stream = thread_info.streamId;
04355   bool *usingCallback = (bool *) ptr;
04356 
04357   while ( *usingCallback ) {
04358     pthread_testcancel();
04359     try {
04360       object->tickStream(stream);
04361     }
04362     catch (RtError &exception) {
04363       fprintf(stderr, "\nCallback thread error (%s) ... closing thread.\n\n",
04364               exception.getMessage());
04365       break;
04366     }
04367   }
04368 
04369   return 0;
04370 }
04371 
04372 //******************** End of __IRIX_AL__ *********************//
04373 
04374 #endif
04375 
04376 
04377 // *************************************************** //
04378 //
04379 // Private common (OS-independent) RtAudio methods.
04380 //
04381 // *************************************************** //
04382 
04383 // This method can be modified to control the behavior of error
04384 // message reporting and throwing.
04385 void RtAudio :: error(RtError::TYPE type)
04386 {
04387   if (type == RtError::WARNING) {
04388 #if defined(RTAUDIO_DEBUG)
04389     fprintf(stderr, "\n%s\n\n", message);
04390   else if (type == RtError::DEBUG_WARNING) {
04391     fprintf(stderr, "\n%s\n\n", message);
04392 #endif
04393   }
04394   else {
04395     fprintf(stderr, "\n%s\n\n", message);
04396     throw RtError(message, type);
04397   }
04398 }
04399 
04400 void *RtAudio :: verifyStream(int streamId)
04401 {
04402   // Verify the stream key.
04403   if ( streams.find( streamId ) == streams.end() ) {
04404     sprintf(message, "RtAudio: invalid stream identifier!");
04405     error(RtError::INVALID_STREAM);
04406   }
04407 
04408   return streams[streamId];
04409 }
04410 
04411 void RtAudio :: clearDeviceInfo(RTAUDIO_DEVICE *info)
04412 {
04413   // Don't clear the name or DEVICE_ID fields here ... they are
04414   // typically set prior to a call of this function.
04415   info->probed = false;
04416   info->maxOutputChannels = 0;
04417   info->maxInputChannels = 0;
04418   info->maxDuplexChannels = 0;
04419   info->minOutputChannels = 0;
04420   info->minInputChannels = 0;
04421   info->minDuplexChannels = 0;
04422   info->hasDuplexSupport = false;
04423   info->nSampleRates = 0;
04424   for (int i=0; i<MAX_SAMPLE_RATES; i++)
04425     info->sampleRates[i] = 0;
04426   info->nativeFormats = 0;
04427 }
04428 
04429 int RtAudio :: formatBytes(RTAUDIO_FORMAT format)
04430 {
04431   if (format == RTAUDIO_SINT16)
04432     return 2;
04433   else if (format == RTAUDIO_SINT24 || format == RTAUDIO_SINT32 ||
04434            format == RTAUDIO_FLOAT32)
04435     return 4;
04436   else if (format == RTAUDIO_FLOAT64)
04437     return 8;
04438   else if (format == RTAUDIO_SINT8)
04439     return 1;
04440 
04441   sprintf(message,"RtAudio: undefined format in formatBytes().");
04442   error(RtError::WARNING);
04443 
04444   return 0;
04445 }
04446 
04447 void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
04448 {
04449   // This method does format conversion, input/output channel compensation, and
04450   // data interleaving/deinterleaving.  24-bit integers are assumed to occupy
04451   // the upper three bytes of a 32-bit integer.
04452 
04453   int j, channels_in, channels_out, channels;
04454   RTAUDIO_FORMAT format_in, format_out;
04455   char *input, *output;
04456 
04457   if (mode == RECORD) { // convert device to user buffer
04458     input = stream->deviceBuffer;
04459     output = stream->userBuffer;
04460     channels_in = stream->nDeviceChannels[1];
04461     channels_out = stream->nUserChannels[1];
04462     format_in = stream->deviceFormat[1];
04463     format_out = stream->userFormat;
04464   }
04465   else { // convert user to device buffer
04466     input = stream->userBuffer;
04467     output = stream->deviceBuffer;
04468     channels_in = stream->nUserChannels[0];
04469     channels_out = stream->nDeviceChannels[0];
04470     format_in = stream->userFormat;
04471     format_out = stream->deviceFormat[0];
04472 
04473     // clear our device buffer when in/out duplex device channels are different
04474     if ( stream->mode == DUPLEX &&
04475          stream->nDeviceChannels[0] != stream->nDeviceChannels[1] )
04476       memset(output, 0, stream->bufferSize * channels_out * formatBytes(format_out));
04477   }
04478 
04479   channels = (channels_in < channels_out) ? channels_in : channels_out;
04480 
04481   // Set up the interleave/deinterleave offsets
04482   std::vector<int> offset_in(channels);
04483   std::vector<int> offset_out(channels);
04484   if (mode == RECORD && stream->deInterleave[1]) {
04485     for (int k=0; k<channels; k++) {
04486       offset_in[k] = k * stream->bufferSize;
04487       offset_out[k] = k;
04488     }
04489   }
04490   else if (mode == PLAYBACK && stream->deInterleave[0]) {
04491     for (int k=0; k<channels; k++) {
04492       offset_in[k] = k;
04493       offset_out[k] = k * stream->bufferSize;
04494     }
04495   }
04496   else {
04497     for (int k=0; k<channels; k++) {
04498       offset_in[k] = k;
04499       offset_out[k] = k;
04500     }
04501   }
04502 
04503   if (format_out == RTAUDIO_FLOAT64) {
04504     FLOAT64 scale;
04505     FLOAT64 *out = (FLOAT64 *)output;
04506 
04507     if (format_in == RTAUDIO_SINT8) {
04508       signed char *in = (signed char *)input;
04509       scale = 1.0 / 128.0;
04510       for (int i=0; i<stream->bufferSize; i++) {
04511         for (j=0; j<channels; j++) {
04512           out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
04513           out[offset_out[j]] *= scale;
04514         }
04515         in += channels_in;
04516         out += channels_out;
04517       }
04518     }
04519     else if (format_in == RTAUDIO_SINT16) {
04520       INT16 *in = (INT16 *)input;
04521       scale = 1.0 / 32768.0;
04522       for (int i=0; i<stream->bufferSize; i++) {
04523         for (j=0; j<channels; j++) {
04524           out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
04525           out[offset_out[j]] *= scale;
04526         }
04527         in += channels_in;
04528         out += channels_out;
04529       }
04530     }
04531     else if (format_in == RTAUDIO_SINT24) {
04532       INT32 *in = (INT32 *)input;
04533       scale = 1.0 / 2147483648.0;
04534       for (int i=0; i<stream->bufferSize; i++) {
04535         for (j=0; j<channels; j++) {
04536           out[offset_out[j]] = (FLOAT64) (in[offset_in[j]] & 0xffffff00);
04537           out[offset_out[j]] *= scale;
04538         }
04539         in += channels_in;
04540         out += channels_out;
04541       }
04542     }
04543     else if (format_in == RTAUDIO_SINT32) {
04544       INT32 *in = (INT32 *)input;
04545       scale = 1.0 / 2147483648.0;
04546       for (int i=0; i<stream->bufferSize; i++) {
04547         for (j=0; j<channels; j++) {
04548           out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
04549           out[offset_out[j]] *= scale;
04550         }
04551         in += channels_in;
04552         out += channels_out;
04553       }
04554     }
04555     else if (format_in == RTAUDIO_FLOAT32) {
04556       FLOAT32 *in = (FLOAT32 *)input;
04557       for (int i=0; i<stream->bufferSize; i++) {
04558         for (j=0; j<channels; j++) {
04559           out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
04560         }
04561         in += channels_in;
04562         out += channels_out;
04563       }
04564     }
04565     else if (format_in == RTAUDIO_FLOAT64) {
04566       // Channel compensation and/or (de)interleaving only.
04567       FLOAT64 *in = (FLOAT64 *)input;
04568       for (int i=0; i<stream->bufferSize; i++) {
04569         for (j=0; j<channels; j++) {
04570           out[offset_out[j]] = in[offset_in[j]];
04571         }
04572         in += channels_in;
04573         out += channels_out;
04574       }
04575     }
04576   }
04577   else if (format_out == RTAUDIO_FLOAT32) {
04578     FLOAT32 scale;
04579     FLOAT32 *out = (FLOAT32 *)output;
04580 
04581     if (format_in == RTAUDIO_SINT8) {
04582       signed char *in = (signed char *)input;
04583       scale = 1.0 / 128.0;
04584       for (int i=0; i<stream->bufferSize; i++) {
04585         for (j=0; j<channels; j++) {
04586           out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
04587           out[offset_out[j]] *= scale;
04588         }
04589         in += channels_in;
04590         out += channels_out;
04591       }
04592     }
04593     else if (format_in == RTAUDIO_SINT16) {
04594       INT16 *in = (INT16 *)input;
04595       scale = 1.0 / 32768.0;
04596       for (int i=0; i<stream->bufferSize; i++) {
04597         for (j=0; j<channels; j++) {
04598           out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
04599           out[offset_out[j]] *= scale;
04600         }
04601         in += channels_in;
04602         out += channels_out;
04603       }
04604     }
04605     else if (format_in == RTAUDIO_SINT24) {
04606       INT32 *in = (INT32 *)input;
04607       scale = 1.0 / 2147483648.0;
04608       for (int i=0; i<stream->bufferSize; i++) {
04609         for (j=0; j<channels; j++) {
04610           out[offset_out[j]] = (FLOAT32) (in[offset_in[j]] & 0xffffff00);
04611           out[offset_out[j]] *= scale;
04612         }
04613         in += channels_in;
04614         out += channels_out;
04615       }
04616     }
04617     else if (format_in == RTAUDIO_SINT32) {
04618       INT32 *in = (INT32 *)input;
04619       scale = 1.0 / 2147483648.0;
04620       for (int i=0; i<stream->bufferSize; i++) {
04621         for (j=0; j<channels; j++) {
04622           out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
04623           out[offset_out[j]] *= scale;
04624         }
04625         in += channels_in;
04626         out += channels_out;
04627       }
04628     }
04629     else if (format_in == RTAUDIO_FLOAT32) {
04630       // Channel compensation and/or (de)interleaving only.
04631       FLOAT32 *in = (FLOAT32 *)input;
04632       for (int i=0; i<stream->bufferSize; i++) {
04633         for (j=0; j<channels; j++) {
04634           out[offset_out[j]] = in[offset_in[j]];
04635         }
04636         in += channels_in;
04637         out += channels_out;
04638       }
04639     }
04640     else if (format_in == RTAUDIO_FLOAT64) {
04641       FLOAT64 *in = (FLOAT64 *)input;
04642       for (int i=0; i<stream->bufferSize; i++) {
04643         for (j=0; j<channels; j++) {
04644           out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
04645         }
04646         in += channels_in;
04647         out += channels_out;
04648       }
04649     }
04650   }
04651   else if (format_out == RTAUDIO_SINT32) {
04652     INT32 *out = (INT32 *)output;
04653     if (format_in == RTAUDIO_SINT8) {
04654       signed char *in = (signed char *)input;
04655       for (int i=0; i<stream->bufferSize; i++) {
04656         for (j=0; j<channels; j++) {
04657           out[offset_out[j]] = (INT32) in[offset_in[j]];
04658           out[offset_out[j]] <<= 24;
04659         }
04660         in += channels_in;
04661         out += channels_out;
04662       }
04663     }
04664     else if (format_in == RTAUDIO_SINT16) {
04665       INT16 *in = (INT16 *)input;
04666       for (int i=0; i<stream->bufferSize; i++) {
04667         for (j=0; j<channels; j++) {
04668           out[offset_out[j]] = (INT32) in[offset_in[j]];
04669           out[offset_out[j]] <<= 16;
04670         }
04671         in += channels_in;
04672         out += channels_out;
04673       }
04674     }
04675     else if (format_in == RTAUDIO_SINT24) {
04676       INT32 *in = (INT32 *)input;
04677       for (int i=0; i<stream->bufferSize; i++) {
04678         for (j=0; j<channels; j++) {
04679           out[offset_out[j]] = (INT32) in[offset_in[j]];
04680         }
04681         in += channels_in;
04682         out += channels_out;
04683       }
04684     }
04685     else if (format_in == RTAUDIO_SINT32) {
04686       // Channel compensation and/or (de)interleaving only.
04687       INT32 *in = (INT32 *)input;
04688       for (int i=0; i<stream->bufferSize; i++) {
04689         for (j=0; j<channels; j++) {
04690           out[offset_out[j]] = in[offset_in[j]];
04691         }
04692         in += channels_in;
04693         out += channels_out;
04694       }
04695     }
04696     else if (format_in == RTAUDIO_FLOAT32) {
04697       FLOAT32 *in = (FLOAT32 *)input;
04698       for (int i=0; i<stream->bufferSize; i++) {
04699         for (j=0; j<channels; j++) {
04700           out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
04701         }
04702         in += channels_in;
04703         out += channels_out;
04704       }
04705     }
04706     else if (format_in == RTAUDIO_FLOAT64) {
04707       FLOAT64 *in = (FLOAT64 *)input;
04708       for (int i=0; i<stream->bufferSize; i++) {
04709         for (j=0; j<channels; j++) {
04710           out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
04711         }
04712         in += channels_in;
04713         out += channels_out;
04714       }
04715     }
04716   }
04717   else if (format_out == RTAUDIO_SINT24) {
04718     INT32 *out = (INT32 *)output;
04719     if (format_in == RTAUDIO_SINT8) {
04720       signed char *in = (signed char *)input;
04721       for (int i=0; i<stream->bufferSize; i++) {
04722         for (j=0; j<channels; j++) {
04723           out[offset_out[j]] = (INT32) in[offset_in[j]];
04724           out[offset_out[j]] <<= 24;
04725         }
04726         in += channels_in;
04727         out += channels_out;
04728       }
04729     }
04730     else if (format_in == RTAUDIO_SINT16) {
04731       INT16 *in = (INT16 *)input;
04732       for (int i=0; i<stream->bufferSize; i++) {
04733         for (j=0; j<channels; j++) {
04734           out[offset_out[j]] = (INT32) in[offset_in[j]];
04735           out[offset_out[j]] <<= 16;
04736         }
04737         in += channels_in;
04738         out += channels_out;
04739       }
04740     }
04741     else if (format_in == RTAUDIO_SINT24) {
04742       // Channel compensation and/or (de)interleaving only.
04743       INT32 *in = (INT32 *)input;
04744       for (int i=0; i<stream->bufferSize; i++) {
04745         for (j=0; j<channels; j++) {
04746           out[offset_out[j]] = in[offset_in[j]];
04747         }
04748         in += channels_in;
04749         out += channels_out;
04750       }
04751     }
04752     else if (format_in == RTAUDIO_SINT32) {
04753       INT32 *in = (INT32 *)input;
04754       for (int i=0; i<stream->bufferSize; i++) {
04755         for (j=0; j<channels; j++) {
04756           out[offset_out[j]] = (INT32) (in[offset_in[j]] & 0xffffff00);
04757         }
04758         in += channels_in;
04759         out += channels_out;
04760       }
04761     }
04762     else if (format_in == RTAUDIO_FLOAT32) {
04763       FLOAT32 *in = (FLOAT32 *)input;
04764       for (int i=0; i<stream->bufferSize; i++) {
04765         for (j=0; j<channels; j++) {
04766           out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
04767         }
04768         in += channels_in;
04769         out += channels_out;
04770       }
04771     }
04772     else if (format_in == RTAUDIO_FLOAT64) {
04773       FLOAT64 *in = (FLOAT64 *)input;
04774       for (int i=0; i<stream->bufferSize; i++) {
04775         for (j=0; j<channels; j++) {
04776           out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
04777         }
04778         in += channels_in;
04779         out += channels_out;
04780       }
04781     }
04782   }
04783   else if (format_out == RTAUDIO_SINT16) {
04784     INT16 *out = (INT16 *)output;
04785     if (format_in == RTAUDIO_SINT8) {
04786       signed char *in = (signed char *)input;
04787       for (int i=0; i<stream->bufferSize; i++) {
04788         for (j=0; j<channels; j++) {
04789           out[offset_out[j]] = (INT16) in[offset_in[j]];
04790           out[offset_out[j]] <<= 8;
04791         }
04792         in += channels_in;
04793         out += channels_out;
04794       }
04795     }
04796     else if (format_in == RTAUDIO_SINT16) {
04797       // Channel compensation and/or (de)interleaving only.
04798       INT16 *in = (INT16 *)input;
04799       for (int i=0; i<stream->bufferSize; i++) {
04800         for (j=0; j<channels; j++) {
04801           out[offset_out[j]] = in[offset_in[j]];
04802         }
04803         in += channels_in;
04804         out += channels_out;
04805       }
04806     }
04807     else if (format_in == RTAUDIO_SINT24) {
04808       INT32 *in = (INT32 *)input;
04809       for (int i=0; i<stream->bufferSize; i++) {
04810         for (j=0; j<channels; j++) {
04811           out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff);
04812         }
04813         in += channels_in;
04814         out += channels_out;
04815       }
04816     }
04817     else if (format_in == RTAUDIO_SINT32) {
04818       INT32 *in = (INT32 *)input;
04819       for (int i=0; i<stream->bufferSize; i++) {
04820         for (j=0; j<channels; j++) {
04821           out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff);
04822         }
04823         in += channels_in;
04824         out += channels_out;
04825       }
04826     }
04827     else if (format_in == RTAUDIO_FLOAT32) {
04828       FLOAT32 *in = (FLOAT32 *)input;
04829       for (int i=0; i<stream->bufferSize; i++) {
04830         for (j=0; j<channels; j++) {
04831           out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0);
04832         }
04833         in += channels_in;
04834         out += channels_out;
04835       }
04836     }
04837     else if (format_in == RTAUDIO_FLOAT64) {
04838       FLOAT64 *in = (FLOAT64 *)input;
04839       for (int i=0; i<stream->bufferSize; i++) {
04840         for (j=0; j<channels; j++) {
04841           out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0);
04842         }
04843         in += channels_in;
04844         out += channels_out;
04845       }
04846     }
04847   }
04848   else if (format_out == RTAUDIO_SINT8) {
04849     signed char *out = (signed char *)output;
04850     if (format_in == RTAUDIO_SINT8) {
04851       // Channel compensation and/or (de)interleaving only.
04852       signed char *in = (signed char *)input;
04853       for (int i=0; i<stream->bufferSize; i++) {
04854         for (j=0; j<channels; j++) {
04855           out[offset_out[j]] = in[offset_in[j]];
04856         }
04857         in += channels_in;
04858         out += channels_out;
04859       }
04860     }
04861     if (format_in == RTAUDIO_SINT16) {
04862       INT16 *in = (INT16 *)input;
04863       for (int i=0; i<stream->bufferSize; i++) {
04864         for (j=0; j<channels; j++) {
04865           out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 8) & 0x00ff);
04866         }
04867         in += channels_in;
04868         out += channels_out;
04869       }
04870     }
04871     else if (format_in == RTAUDIO_SINT24) {
04872       INT32 *in = (INT32 *)input;
04873       for (int i=0; i<stream->bufferSize; i++) {
04874         for (j=0; j<channels; j++) {
04875           out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff);
04876         }
04877         in += channels_in;
04878         out += channels_out;
04879       }
04880     }
04881     else if (format_in == RTAUDIO_SINT32) {
04882       INT32 *in = (INT32 *)input;
04883       for (int i=0; i<stream->bufferSize; i++) {
04884         for (j=0; j<channels; j++) {
04885           out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff);
04886         }
04887         in += channels_in;
04888         out += channels_out;
04889       }
04890     }
04891     else if (format_in == RTAUDIO_FLOAT32) {
04892       FLOAT32 *in = (FLOAT32 *)input;
04893       for (int i=0; i<stream->bufferSize; i++) {
04894         for (j=0; j<channels; j++) {
04895           out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0);
04896         }
04897         in += channels_in;
04898         out += channels_out;
04899       }
04900     }
04901     else if (format_in == RTAUDIO_FLOAT64) {
04902       FLOAT64 *in = (FLOAT64 *)input;
04903       for (int i=0; i<stream->bufferSize; i++) {
04904         for (j=0; j<channels; j++) {
04905           out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0);
04906         }
04907         in += channels_in;
04908         out += channels_out;
04909       }
04910     }
04911   }
04912 }
04913 
04914 void RtAudio :: byteSwapBuffer(char *buffer, int samples, RTAUDIO_FORMAT format)
04915 {
04916   register char val;
04917   register char *ptr;
04918 
04919   ptr = buffer;
04920   if (format == RTAUDIO_SINT16) {
04921     for (int i=0; i<samples; i++) {
04922       // Swap 1st and 2nd bytes.
04923       val = *(ptr);
04924       *(ptr) = *(ptr+1);
04925       *(ptr+1) = val;
04926 
04927       // Increment 2 bytes.
04928       ptr += 2;
04929     }
04930   }
04931   else if (format == RTAUDIO_SINT24 ||
04932            format == RTAUDIO_SINT32 ||
04933            format == RTAUDIO_FLOAT32) {
04934     for (int i=0; i<samples; i++) {
04935       // Swap 1st and 4th bytes.
04936       val = *(ptr);
04937       *(ptr) = *(ptr+3);
04938       *(ptr+3) = val;
04939 
04940       // Swap 2nd and 3rd bytes.
04941       ptr += 1;
04942       val = *(ptr);
04943       *(ptr) = *(ptr+1);
04944       *(ptr+1) = val;
04945 
04946       // Increment 4 bytes.
04947       ptr += 4;
04948     }
04949   }
04950   else if (format == RTAUDIO_FLOAT64) {
04951     for (int i=0; i<samples; i++) {
04952       // Swap 1st and 8th bytes
04953       val = *(ptr);
04954       *(ptr) = *(ptr+7);
04955       *(ptr+7) = val;
04956 
04957       // Swap 2nd and 7th bytes
04958       ptr += 1;
04959       val = *(ptr);
04960       *(ptr) = *(ptr+5);
04961       *(ptr+5) = val;
04962 
04963       // Swap 3rd and 6th bytes
04964       ptr += 1;
04965       val = *(ptr);
04966       *(ptr) = *(ptr+3);
04967       *(ptr+3) = val;
04968 
04969       // Swap 4th and 5th bytes
04970       ptr += 1;
04971       val = *(ptr);
04972       *(ptr) = *(ptr+1);
04973       *(ptr+1) = val;
04974 
04975       // Increment 8 bytes.
04976       ptr += 8;
04977     }
04978   }
04979 }
04980 
04981 
04982 // *************************************************** //
04983 //
04984 // RtError class definition.
04985 //
04986 // *************************************************** //
04987 
04988 RtError :: RtError(const char *p, TYPE tipe)
04989 {
04990   type = tipe;
04991   strncpy(error_message, p, 256);
04992 }
04993 
04994 RtError :: ~RtError()
04995 {
04996 }
04997 
04998 void RtError :: printMessage()
04999 {
05000   printf("\n%s\n\n", error_message);
05001 }

Generated on Tue Aug 12 22:33:44 2008 for CLAM by  doxygen 1.5.5