Updates to OS-X sample rate querying, other small changes suggested by Martin Koegler.
[rtaudio-cdist.git] / RtAudio.cpp
index 8477ef995ad7b9d7a77eb4a13bf16d95da7551cb..0a7d9ebda0537975a6c247acde50b46ae201d797 100644 (file)
@@ -10,7 +10,7 @@
     RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/\r
 \r
     RtAudio: realtime audio i/o C++ classes\r
-    Copyright (c) 2001-2012 Gary P. Scavone\r
+    Copyright (c) 2001-2013 Gary P. Scavone\r
 \r
     Permission is hereby granted, free of charge, to any person\r
     obtaining a copy of this software and associated documentation files\r
@@ -38,7 +38,7 @@
 */\r
 /************************************************************************/\r
 \r
-// RtAudio: Version 4.0.11\r
+// RtAudio: Version 4.0.12\r
 \r
 #include "RtAudio.h"\r
 #include <iostream>\r
@@ -75,6 +75,11 @@ const unsigned int RtApi::SAMPLE_RATES[] = {
 //\r
 // *************************************************** //\r
 \r
+std::string RtAudio :: getVersion( void ) throw()\r
+{\r
+  return std::string( RTAUDIO_VERSION );\r
+}\r
+\r
 void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis ) throw()\r
 {\r
   apis.clear();\r
@@ -176,7 +181,8 @@ RtAudio :: RtAudio( RtAudio::Api api ) throw()
   // definition __RTAUDIO_DUMMY__ is automatically defined if no\r
   // API-specific definitions are passed to the compiler. But just in\r
   // case something weird happens, we'll print out an error message.\r
-  std::cerr << "\nRtAudio: no compiled API support found ... critical error!!\n\n";\r
+  std::string errorText = "\nRtAudio: no compiled API support found ... critical error!!\n\n";\r
+  throw( RtAudioError( errorText, RtAudioError::UNSPECIFIED ) );\r
 }\r
 \r
 RtAudio :: ~RtAudio() throw()\r
@@ -189,11 +195,12 @@ void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters,
                             RtAudioFormat format, unsigned int sampleRate,\r
                             unsigned int *bufferFrames,\r
                             RtAudioCallback callback, void *userData,\r
-                            RtAudio::StreamOptions *options )\r
+                            RtAudio::StreamOptions *options,\r
+                            RtAudioErrorCallback errorCallback )\r
 {\r
   return rtapi_->openStream( outputParameters, inputParameters, format,\r
                              sampleRate, bufferFrames, callback,\r
-                             userData, options );\r
+                             userData, options, errorCallback );\r
 }\r
 \r
 // *************************************************** //\r
@@ -212,6 +219,7 @@ RtApi :: RtApi()
   stream_.userBuffer[1] = 0;\r
   MUTEX_INITIALIZE( &stream_.mutex );\r
   showWarnings_ = true;\r
+  firstErrorOccurred_ = false;\r
 }\r
 \r
 RtApi :: ~RtApi()\r
@@ -224,31 +232,37 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
                           RtAudioFormat format, unsigned int sampleRate,\r
                           unsigned int *bufferFrames,\r
                           RtAudioCallback callback, void *userData,\r
-                          RtAudio::StreamOptions *options )\r
+                          RtAudio::StreamOptions *options,\r
+                          RtAudioErrorCallback errorCallback )\r
 {\r
   if ( stream_.state != STREAM_CLOSED ) {\r
     errorText_ = "RtApi::openStream: a stream is already open!";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
+    return;\r
   }\r
 \r
   if ( oParams && oParams->nChannels < 1 ) {\r
     errorText_ = "RtApi::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one.";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
+    return;\r
   }\r
 \r
   if ( iParams && iParams->nChannels < 1 ) {\r
     errorText_ = "RtApi::openStream: a non-NULL input StreamParameters structure cannot have an nChannels value less than one.";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
+    return;\r
   }\r
 \r
   if ( oParams == NULL && iParams == NULL ) {\r
     errorText_ = "RtApi::openStream: input and output StreamParameters structures are both NULL!";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
+    return;\r
   }\r
 \r
   if ( formatBytes(format) == 0 ) {\r
     errorText_ = "RtApi::openStream: 'format' parameter value is undefined.";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
+    return;\r
   }\r
 \r
   unsigned int nDevices = getDeviceCount();\r
@@ -257,7 +271,8 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
     oChannels = oParams->nChannels;\r
     if ( oParams->deviceId >= nDevices ) {\r
       errorText_ = "RtApi::openStream: output device parameter value is invalid.";\r
-      error( RtError::INVALID_USE );\r
+      error( RtAudioError::INVALID_USE );\r
+      return;\r
     }\r
   }\r
 \r
@@ -266,7 +281,8 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
     iChannels = iParams->nChannels;\r
     if ( iParams->deviceId >= nDevices ) {\r
       errorText_ = "RtApi::openStream: input device parameter value is invalid.";\r
-      error( RtError::INVALID_USE );\r
+      error( RtAudioError::INVALID_USE );\r
+      return;\r
     }\r
   }\r
 \r
@@ -277,7 +293,10 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
 \r
     result = probeDeviceOpen( oParams->deviceId, OUTPUT, oChannels, oParams->firstChannel,\r
                               sampleRate, format, bufferFrames, options );\r
-    if ( result == false ) error( RtError::SYSTEM_ERROR );\r
+    if ( result == false ) {\r
+      error( RtAudioError::SYSTEM_ERROR );\r
+      return;\r
+    }\r
   }\r
 \r
   if ( iChannels > 0 ) {\r
@@ -286,12 +305,14 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
                               sampleRate, format, bufferFrames, options );\r
     if ( result == false ) {\r
       if ( oChannels > 0 ) closeStream();\r
-      error( RtError::SYSTEM_ERROR );\r
+      error( RtAudioError::SYSTEM_ERROR );\r
+      return;\r
     }\r
   }\r
 \r
   stream_.callbackInfo.callback = (void *) callback;\r
   stream_.callbackInfo.userData = userData;\r
+  stream_.callbackInfo.errorCallback = (void *) errorCallback;\r
 \r
   if ( options ) options->numberOfBuffers = stream_.nBuffers;\r
   stream_.state = STREAM_STOPPED;\r
@@ -315,10 +336,10 @@ void RtApi :: closeStream( void )
   return;\r
 }\r
 \r
-bool RtApi :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,\r
-                               unsigned int firstChannel, unsigned int sampleRate,\r
-                               RtAudioFormat format, unsigned int *bufferSize,\r
-                               RtAudio::StreamOptions *options )\r
+bool RtApi :: probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/,\r
+                               unsigned int /*firstChannel*/, unsigned int /*sampleRate*/,\r
+                               RtAudioFormat /*format*/, unsigned int * /*bufferSize*/,\r
+                               RtAudio::StreamOptions * /*options*/ )\r
 {\r
   // MUST be implemented in subclasses!\r
   return FAILURE;\r
@@ -423,8 +444,6 @@ struct CoreHandle {
     :deviceBuffer(0), drainCounter(0), internalDrain(false) { nStreams[0] = 1; nStreams[1] = 1; id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }\r
 };\r
 \r
-ThreadHandle threadId;\r
-\r
 RtApiCore:: RtApiCore()\r
 {\r
 #if defined( AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER )\r
@@ -439,7 +458,7 @@ RtApiCore:: RtApiCore()
   OSStatus result = AudioObjectSetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);\r
   if ( result != noErr ) {\r
     errorText_ = "RtApiCore::RtApiCore: error setting run loop property!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
   }\r
 #endif\r
 }\r
@@ -460,7 +479,7 @@ unsigned int RtApiCore :: getDeviceCount( void )
   OSStatus result = AudioObjectGetPropertyDataSize( kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize );\r
   if ( result != noErr ) {\r
     errorText_ = "RtApiCore::getDeviceCount: OS-X error getting device info!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return 0;\r
   }\r
 \r
@@ -478,7 +497,7 @@ unsigned int RtApiCore :: getDefaultInputDevice( void )
   OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &id );\r
   if ( result != noErr ) {\r
     errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device.";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return 0;\r
   }\r
 \r
@@ -488,7 +507,7 @@ unsigned int RtApiCore :: getDefaultInputDevice( void )
   result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList );\r
   if ( result != noErr ) {\r
     errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device IDs.";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return 0;\r
   }\r
 \r
@@ -496,7 +515,7 @@ unsigned int RtApiCore :: getDefaultInputDevice( void )
     if ( id == deviceList[i] ) return i;\r
 \r
   errorText_ = "RtApiCore::getDefaultInputDevice: No default device found!";\r
-  error( RtError::WARNING );\r
+  error( RtAudioError::WARNING );\r
   return 0;\r
 }\r
 \r
@@ -511,7 +530,7 @@ unsigned int RtApiCore :: getDefaultOutputDevice( void )
   OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &id );\r
   if ( result != noErr ) {\r
     errorText_ = "RtApiCore::getDefaultOutputDevice: OS-X system error getting device.";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return 0;\r
   }\r
 \r
@@ -521,7 +540,7 @@ unsigned int RtApiCore :: getDefaultOutputDevice( void )
   result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList );\r
   if ( result != noErr ) {\r
     errorText_ = "RtApiCore::getDefaultOutputDevice: OS-X system error getting device IDs.";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return 0;\r
   }\r
 \r
@@ -529,7 +548,7 @@ unsigned int RtApiCore :: getDefaultOutputDevice( void )
     if ( id == deviceList[i] ) return i;\r
 \r
   errorText_ = "RtApiCore::getDefaultOutputDevice: No default device found!";\r
-  error( RtError::WARNING );\r
+  error( RtAudioError::WARNING );\r
   return 0;\r
 }\r
 \r
@@ -542,12 +561,14 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   unsigned int nDevices = getDeviceCount();\r
   if ( nDevices == 0 ) {\r
     errorText_ = "RtApiCore::getDeviceInfo: no devices found!";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
   }\r
 \r
   if ( device >= nDevices ) {\r
     errorText_ = "RtApiCore::getDeviceInfo: device ID is invalid!";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
   }\r
 \r
   AudioDeviceID deviceList[ nDevices ];\r
@@ -559,7 +580,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
                                                 0, NULL, &dataSize, (void *) &deviceList );\r
   if ( result != noErr ) {\r
     errorText_ = "RtApiCore::getDeviceInfo: OS-X system error getting device IDs.";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -574,7 +595,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   if ( result != noErr ) {\r
     errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device manufacturer.";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -592,7 +613,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   if ( result != noErr ) {\r
     errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device name.";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -614,7 +635,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   if ( result != noErr || dataSize == 0 ) {\r
     errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration info for device (" << device << ").";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -622,7 +643,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   bufferList = (AudioBufferList *) malloc( dataSize );\r
   if ( bufferList == NULL ) {\r
     errorText_ = "RtApiCore::getDeviceInfo: memory error allocating output AudioBufferList.";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -631,7 +652,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
     free( bufferList );\r
     errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration for device (" << device << ").";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -647,7 +668,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   if ( result != noErr || dataSize == 0 ) {\r
     errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration info for device (" << device << ").";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -655,7 +676,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   bufferList = (AudioBufferList *) malloc( dataSize );\r
   if ( bufferList == NULL ) {\r
     errorText_ = "RtApiCore::getDeviceInfo: memory error allocating input AudioBufferList.";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -664,7 +685,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
     free( bufferList );\r
     errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration for device (" << device << ").";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -689,7 +710,7 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   if ( result != kAudioHardwareNoError || dataSize == 0 ) {\r
     errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rate info.";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -699,26 +720,45 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   if ( result != kAudioHardwareNoError ) {\r
     errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rates.";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
-  Float64 minimumRate = 100000000.0, maximumRate = 0.0;\r
+  // The sample rate reporting mechanism is a bit of a mystery.  It\r
+  // seems that it can either return individual rates or a range of\r
+  // rates.  I assume that if the min / max range values are the same,\r
+  // then that represents a single supported rate and if the min / max\r
+  // range values are different, the device supports an arbitrary\r
+  // range of values (though there might be multiple ranges, so we'll\r
+  // use the most conservative range).\r
+  Float64 minimumRate = 1.0, maximumRate = 10000000000.0;\r
+  bool haveValueRange = false;\r
+  info.sampleRates.clear();\r
   for ( UInt32 i=0; i<nRanges; i++ ) {\r
-    if ( rangeList[i].mMinimum < minimumRate ) minimumRate = rangeList[i].mMinimum;\r
-    if ( rangeList[i].mMaximum > maximumRate ) maximumRate = rangeList[i].mMaximum;\r
+    if ( rangeList[i].mMinimum == rangeList[i].mMaximum )\r
+      info.sampleRates.push_back( (unsigned int) rangeList[i].mMinimum );\r
+    else {\r
+      haveValueRange = true;\r
+      if ( rangeList[i].mMinimum > minimumRate ) minimumRate = rangeList[i].mMinimum;\r
+      if ( rangeList[i].mMaximum < maximumRate ) maximumRate = rangeList[i].mMaximum;\r
+    }\r
   }\r
 \r
-  info.sampleRates.clear();\r
-  for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {\r
-    if ( SAMPLE_RATES[k] >= (unsigned int) minimumRate && SAMPLE_RATES[k] <= (unsigned int) maximumRate )\r
-      info.sampleRates.push_back( SAMPLE_RATES[k] );\r
+  if ( haveValueRange ) {\r
+    for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {\r
+      if ( SAMPLE_RATES[k] >= (unsigned int) minimumRate && SAMPLE_RATES[k] <= (unsigned int) maximumRate )\r
+        info.sampleRates.push_back( SAMPLE_RATES[k] );\r
+    }\r
   }\r
 \r
+  // Sort and remove any redundant values\r
+  std::sort( info.sampleRates.begin(), info.sampleRates.end() );\r
+  info.sampleRates.erase( unique( info.sampleRates.begin(), info.sampleRates.end() ), info.sampleRates.end() );\r
+\r
   if ( info.sampleRates.size() == 0 ) {\r
     errorStream_ << "RtApiCore::probeDeviceInfo: No supported sample rates found for device (" << device << ").";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -736,13 +776,13 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   return info;\r
 }\r
 \r
-OSStatus callbackHandler( AudioDeviceID inDevice,\r
-                          const AudioTimeStamp* inNow,\r
-                          const AudioBufferList* inInputData,\r
-                          const AudioTimeStamp* inInputTime,\r
-                          AudioBufferList* outOutputData,\r
-                          const AudioTimeStamp* inOutputTime, \r
-                          void* infoPointer )\r
+static OSStatus callbackHandler( AudioDeviceID inDevice,\r
+                                 const AudioTimeStamp* /*inNow*/,\r
+                                 const AudioBufferList* inInputData,\r
+                                 const AudioTimeStamp* /*inInputTime*/,\r
+                                 AudioBufferList* outOutputData,\r
+                                 const AudioTimeStamp* /*inOutputTime*/,\r
+                                 void* infoPointer )\r
 {\r
   CallbackInfo *info = (CallbackInfo *) infoPointer;\r
 \r
@@ -753,10 +793,10 @@ OSStatus callbackHandler( AudioDeviceID inDevice,
     return kAudioHardwareNoError;\r
 }\r
 \r
-OSStatus xrunListener( AudioObjectID inDevice,\r
-                         UInt32 nAddresses,\r
-                         const AudioObjectPropertyAddress properties[],\r
-                         void* handlePointer )\r
+static OSStatus xrunListener( AudioObjectID /*inDevice*/,\r
+                              UInt32 nAddresses,\r
+                              const AudioObjectPropertyAddress properties[],\r
+                              void* handlePointer )\r
 {\r
   CoreHandle *handle = (CoreHandle *) handlePointer;\r
   for ( UInt32 i=0; i<nAddresses; i++ ) {\r
@@ -771,12 +811,11 @@ OSStatus xrunListener( AudioObjectID inDevice,
   return kAudioHardwareNoError;\r
 }\r
 \r
-OSStatus rateListener( AudioObjectID inDevice,\r
-                       UInt32 nAddresses,\r
-                       const AudioObjectPropertyAddress properties[],\r
-                       void* ratePointer )\r
+static OSStatus rateListener( AudioObjectID inDevice,\r
+                              UInt32 /*nAddresses*/,\r
+                              const AudioObjectPropertyAddress /*properties*/[],\r
+                              void* ratePointer )\r
 {\r
-\r
   Float64 *rate = (Float64 *) ratePointer;\r
   UInt32 dataSize = sizeof( Float64 );\r
   AudioObjectPropertyAddress property = { kAudioDevicePropertyNominalSampleRate,\r
@@ -848,6 +887,7 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
 \r
   result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList );\r
   if (result != noErr || dataSize == 0) {\r
+    free( bufferList );\r
     errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream configuration for device (" << device << ").";\r
     errorText_ = errorStream_.str();\r
     return FAILURE;\r
@@ -988,7 +1028,6 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   dataSize = sizeof( Float64 );\r
   property.mSelector = kAudioDevicePropertyNominalSampleRate;\r
   result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &nominalRate );\r
-\r
   if ( result != noErr ) {\r
     errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting current sample rate.";\r
     errorText_ = errorStream_.str();\r
@@ -1010,8 +1049,8 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
 \r
     nominalRate = (Float64) sampleRate;\r
     result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &nominalRate );\r
-\r
     if ( result != noErr ) {\r
+      AudioObjectRemovePropertyListener( id, &tmp, rateListener, (void *) &reportedRate );\r
       errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate for device (" << device << ").";\r
       errorText_ = errorStream_.str();\r
       return FAILURE;\r
@@ -1145,7 +1184,7 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
     else {\r
       errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting device latency for device (" << device << ").";\r
       errorText_ = errorStream_.str();\r
-      error( RtError::WARNING );\r
+      error( RtAudioError::WARNING );\r
     }\r
   }\r
 \r
@@ -1300,6 +1339,7 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
     stream_.deviceBuffer = 0;\r
   }\r
 \r
+  stream_.state = STREAM_CLOSED;\r
   return FAILURE;\r
 }\r
 \r
@@ -1307,7 +1347,7 @@ void RtApiCore :: closeStream( void )
 {\r
   if ( stream_.state == STREAM_CLOSED ) {\r
     errorText_ = "RtApiCore::closeStream(): no open stream to close!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -1360,7 +1400,7 @@ void RtApiCore :: startStream( void )
   verifyStream();\r
   if ( stream_.state == STREAM_RUNNING ) {\r
     errorText_ = "RtApiCore::startStream(): the stream is already running!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -1393,7 +1433,7 @@ void RtApiCore :: startStream( void )
 \r
  unlock:\r
   if ( result == noErr ) return;\r
-  error( RtError::SYSTEM_ERROR );\r
+  error( RtAudioError::SYSTEM_ERROR );\r
 }\r
 \r
 void RtApiCore :: stopStream( void )\r
@@ -1401,7 +1441,7 @@ void RtApiCore :: stopStream( void )
   verifyStream();\r
   if ( stream_.state == STREAM_STOPPED ) {\r
     errorText_ = "RtApiCore::stopStream(): the stream is already stopped!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -1436,7 +1476,7 @@ void RtApiCore :: stopStream( void )
 \r
  unlock:\r
   if ( result == noErr ) return;\r
-  error( RtError::SYSTEM_ERROR );\r
+  error( RtAudioError::SYSTEM_ERROR );\r
 }\r
 \r
 void RtApiCore :: abortStream( void )\r
@@ -1444,7 +1484,7 @@ void RtApiCore :: abortStream( void )
   verifyStream();\r
   if ( stream_.state == STREAM_STOPPED ) {\r
     errorText_ = "RtApiCore::abortStream(): the stream is already stopped!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -1459,7 +1499,7 @@ void RtApiCore :: abortStream( void )
 // aborted.  It is better to handle it this way because the\r
 // callbackEvent() function probably should return before the AudioDeviceStop()\r
 // function is called.\r
-extern "C" void *coreStopStream( void *ptr )\r
+static void *coreStopStream( void *ptr )\r
 {\r
   CallbackInfo *info = (CallbackInfo *) ptr;\r
   RtApiCore *object = (RtApiCore *) info->object;\r
@@ -1475,7 +1515,7 @@ bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,
   if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;\r
   if ( stream_.state == STREAM_CLOSED ) {\r
     errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return FAILURE;\r
   }\r
 \r
@@ -1484,6 +1524,7 @@ bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,
 \r
   // Check if we were draining the stream and signal is finished.\r
   if ( handle->drainCounter > 3 ) {\r
+    ThreadHandle threadId;\r
 \r
     stream_.state = STREAM_STOPPING;\r
     if ( handle->internalDrain == true )\r
@@ -1821,8 +1862,7 @@ struct JackHandle {
     :client(0), drainCounter(0), internalDrain(false) { ports[0] = 0; ports[1] = 0; xrun[0] = false; xrun[1] = false; }\r
 };\r
 \r
-ThreadHandle threadId;\r
-void jackSilentError( const char * ) {};\r
+static void jackSilentError( const char * ) {};\r
 \r
 RtApiJack :: RtApiJack()\r
 {\r
@@ -1881,7 +1921,7 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
   jack_client_t *client = jack_client_open( "RtApiJackInfo", options, status );\r
   if ( client == 0 ) {\r
     errorText_ = "RtApiJack::getDeviceInfo: Jack server not found or connection error!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -1910,7 +1950,8 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
   if ( device >= nDevices ) {\r
     jack_client_close( client );\r
     errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
   }\r
 \r
   // Get the current jack server sample rate.\r
@@ -1939,7 +1980,7 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
   if ( info.outputChannels == 0 && info.inputChannels == 0 ) {\r
     jack_client_close(client);\r
     errorText_ = "RtApiJack::getDeviceInfo: error determining Jack input/output channels!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -1961,7 +2002,7 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
   return info;\r
 }\r
 \r
-int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )\r
+static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )\r
 {\r
   CallbackInfo *info = (CallbackInfo *) infoPointer;\r
 \r
@@ -1975,7 +2016,7 @@ int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )
 // server signals that it is shutting down.  It is necessary to handle\r
 // it this way because the jackShutdown() function must return before\r
 // the jack_deactivate() function (in closeStream()) will return.\r
-extern "C" void *jackCloseStream( void *ptr )\r
+static void *jackCloseStream( void *ptr )\r
 {\r
   CallbackInfo *info = (CallbackInfo *) ptr;\r
   RtApiJack *object = (RtApiJack *) info->object;\r
@@ -1984,7 +2025,7 @@ extern "C" void *jackCloseStream( void *ptr )
 \r
   pthread_exit( NULL );\r
 }\r
-void jackShutdown( void *infoPointer )\r
+static void jackShutdown( void *infoPointer )\r
 {\r
   CallbackInfo *info = (CallbackInfo *) infoPointer;\r
   RtApiJack *object = (RtApiJack *) info->object;\r
@@ -1996,11 +2037,12 @@ void jackShutdown( void *infoPointer )
   // other problem occurred and we should close the stream.\r
   if ( object->isStreamRunning() == false ) return;\r
 \r
+  ThreadHandle threadId;\r
   pthread_create( &threadId, NULL, jackCloseStream, info );\r
   std::cerr << "\nRtApiJack: the Jack server is shutting down this client ... stream stopped and closed!!\n" << std::endl;\r
 }\r
 \r
-int jackXrun( void *infoPointer )\r
+static int jackXrun( void *infoPointer )\r
 {\r
   JackHandle *handle = (JackHandle *) infoPointer;\r
 \r
@@ -2028,7 +2070,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
       client = jack_client_open( "RtApiJack", jackoptions, status );\r
     if ( client == 0 ) {\r
       errorText_ = "RtApiJack::probeDeviceOpen: Jack server not found or connection error!";\r
-      error( RtError::WARNING );\r
+      error( RtAudioError::WARNING );\r
       return FAILURE;\r
     }\r
   }\r
@@ -2265,7 +2307,7 @@ void RtApiJack :: closeStream( void )
 {\r
   if ( stream_.state == STREAM_CLOSED ) {\r
     errorText_ = "RtApiJack::closeStream(): no open stream to close!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -2307,7 +2349,7 @@ void RtApiJack :: startStream( void )
   verifyStream();\r
   if ( stream_.state == STREAM_RUNNING ) {\r
     errorText_ = "RtApiJack::startStream(): the stream is already running!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -2373,7 +2415,7 @@ void RtApiJack :: startStream( void )
 \r
  unlock:\r
   if ( result == 0 ) return;\r
-  error( RtError::SYSTEM_ERROR );\r
+  error( RtAudioError::SYSTEM_ERROR );\r
 }\r
 \r
 void RtApiJack :: stopStream( void )\r
@@ -2381,7 +2423,7 @@ void RtApiJack :: stopStream( void )
   verifyStream();\r
   if ( stream_.state == STREAM_STOPPED ) {\r
     errorText_ = "RtApiJack::stopStream(): the stream is already stopped!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -2403,7 +2445,7 @@ void RtApiJack :: abortStream( void )
   verifyStream();\r
   if ( stream_.state == STREAM_STOPPED ) {\r
     errorText_ = "RtApiJack::abortStream(): the stream is already stopped!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -2418,7 +2460,7 @@ void RtApiJack :: abortStream( void )
 // aborted.  It is necessary to handle it this way because the\r
 // callbackEvent() function must return before the jack_deactivate()\r
 // function will return.\r
-extern "C" void *jackStopStream( void *ptr )\r
+static void *jackStopStream( void *ptr )\r
 {\r
   CallbackInfo *info = (CallbackInfo *) ptr;\r
   RtApiJack *object = (RtApiJack *) info->object;\r
@@ -2432,12 +2474,12 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
   if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;\r
   if ( stream_.state == STREAM_CLOSED ) {\r
     errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return FAILURE;\r
   }\r
   if ( stream_.bufferSize != nframes ) {\r
     errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size has changed ... cannot process!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return FAILURE;\r
   }\r
 \r
@@ -2446,6 +2488,7 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
 \r
   // Check if we were draining the stream and signal is finished.\r
   if ( handle->drainCounter > 3 ) {\r
+    ThreadHandle threadId;\r
 \r
     stream_.state = STREAM_STOPPING;\r
     if ( handle->internalDrain == true )\r
@@ -2565,11 +2608,11 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
 #include "asiodrivers.h"\r
 #include <cmath>\r
 \r
-AsioDrivers drivers;\r
-ASIOCallbacks asioCallbacks;\r
-ASIODriverInfo driverInfo;\r
-CallbackInfo *asioCallbackInfo;\r
-bool asioXRun;\r
+static AsioDrivers drivers;\r
+static ASIOCallbacks asioCallbacks;\r
+static ASIODriverInfo driverInfo;\r
+static CallbackInfo *asioCallbackInfo;\r
+static bool asioXRun;\r
 \r
 struct AsioHandle {\r
   int drainCounter;       // Tracks callback counts when draining\r
@@ -2583,8 +2626,8 @@ struct AsioHandle {
 \r
 // Function declarations (definitions at end of section)\r
 static const char* getAsioErrorString( ASIOError result );\r
-void sampleRateChanged( ASIOSampleRate sRate );\r
-long asioMessages( long selector, long value, void* message, double* opt );\r
+static void sampleRateChanged( ASIOSampleRate sRate );\r
+static long asioMessages( long selector, long value, void* message, double* opt );\r
 \r
 RtApiAsio :: RtApiAsio()\r
 {\r
@@ -2595,7 +2638,7 @@ RtApiAsio :: RtApiAsio()
   HRESULT hr = CoInitialize( NULL ); \r
   if ( FAILED(hr) ) {\r
     errorText_ = "RtApiAsio::ASIO requires a single-threaded appartment. Call CoInitializeEx(0,COINIT_APARTMENTTHREADED)";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
   }\r
   coInitialized_ = true;\r
 \r
@@ -2626,19 +2669,21 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
   unsigned int nDevices = getDeviceCount();\r
   if ( nDevices == 0 ) {\r
     errorText_ = "RtApiAsio::getDeviceInfo: no devices found!";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
   }\r
 \r
   if ( device >= nDevices ) {\r
     errorText_ = "RtApiAsio::getDeviceInfo: device ID is invalid!";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
   }\r
 \r
   // If a stream is already open, we cannot probe other devices.  Thus, use the saved results.\r
   if ( stream_.state != STREAM_CLOSED ) {\r
     if ( device >= devices_.size() ) {\r
       errorText_ = "RtApiAsio::getDeviceInfo: device ID was not present before stream was opened.";\r
-      error( RtError::WARNING );\r
+      error( RtAudioError::WARNING );\r
       return info;\r
     }\r
     return devices_[ device ];\r
@@ -2649,7 +2694,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
   if ( result != ASE_OK ) {\r
     errorStream_ << "RtApiAsio::getDeviceInfo: unable to get driver name (" << getAsioErrorString( result ) << ").";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -2658,7 +2703,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
   if ( !drivers.loadDriver( driverName ) ) {\r
     errorStream_ << "RtApiAsio::getDeviceInfo: unable to load driver (" << driverName << ").";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -2666,7 +2711,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
   if ( result != ASE_OK ) {\r
     errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") initializing driver (" << driverName << ").";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -2677,7 +2722,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
     drivers.removeCurrentDriver();\r
     errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ").";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -2704,7 +2749,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
     drivers.removeCurrentDriver();\r
     errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") getting driver channel info (" << driverName << ").";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -2730,7 +2775,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
   return info;\r
 }\r
 \r
-void bufferSwitch( long index, ASIOBool processNow )\r
+static void bufferSwitch( long index, ASIOBool processNow )\r
 {\r
   RtApiAsio *object = (RtApiAsio *) asioCallbackInfo->object;\r
   object->callbackEvent( index );\r
@@ -3064,7 +3109,7 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   if ( result != ASE_OK ) {\r
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting latency.";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING); // warn but don't fail\r
+    error( RtAudioError::WARNING); // warn but don't fail\r
   }\r
   else {\r
     stream_.latency[0] = outputLatency;\r
@@ -3110,7 +3155,7 @@ void RtApiAsio :: closeStream()
 {\r
   if ( stream_.state == STREAM_CLOSED ) {\r
     errorText_ = "RtApiAsio::closeStream(): no open stream to close!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -3153,7 +3198,7 @@ void RtApiAsio :: startStream()
   verifyStream();\r
   if ( stream_.state == STREAM_RUNNING ) {\r
     errorText_ = "RtApiAsio::startStream(): the stream is already running!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -3175,7 +3220,7 @@ void RtApiAsio :: startStream()
   stopThreadCalled = false;\r
 \r
   if ( result == ASE_OK ) return;\r
-  error( RtError::SYSTEM_ERROR );\r
+  error( RtAudioError::SYSTEM_ERROR );\r
 }\r
 \r
 void RtApiAsio :: stopStream()\r
@@ -3183,7 +3228,7 @@ void RtApiAsio :: stopStream()
   verifyStream();\r
   if ( stream_.state == STREAM_STOPPED ) {\r
     errorText_ = "RtApiAsio::stopStream(): the stream is already stopped!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -3204,7 +3249,7 @@ void RtApiAsio :: stopStream()
   }\r
 \r
   if ( result == ASE_OK ) return;\r
-  error( RtError::SYSTEM_ERROR );\r
+  error( RtAudioError::SYSTEM_ERROR );\r
 }\r
 \r
 void RtApiAsio :: abortStream()\r
@@ -3212,7 +3257,7 @@ void RtApiAsio :: abortStream()
   verifyStream();\r
   if ( stream_.state == STREAM_STOPPED ) {\r
     errorText_ = "RtApiAsio::abortStream(): the stream is already stopped!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -3230,7 +3275,7 @@ void RtApiAsio :: abortStream()
 // aborted.  It is necessary to handle it this way because the\r
 // callbackEvent() function must return before the ASIOStop()\r
 // function will return.\r
-extern "C" unsigned __stdcall asioStopStream( void *ptr )\r
+static unsigned __stdcall asioStopStream( void *ptr )\r
 {\r
   CallbackInfo *info = (CallbackInfo *) ptr;\r
   RtApiAsio *object = (RtApiAsio *) info->object;\r
@@ -3245,7 +3290,7 @@ bool RtApiAsio :: callbackEvent( long bufferIndex )
   if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;\r
   if ( stream_.state == STREAM_CLOSED ) {\r
     errorText_ = "RtApiAsio::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return FAILURE;\r
   }\r
 \r
@@ -3393,7 +3438,7 @@ bool RtApiAsio :: callbackEvent( long bufferIndex )
   return SUCCESS;\r
 }\r
 \r
-void sampleRateChanged( ASIOSampleRate sRate )\r
+static void sampleRateChanged( ASIOSampleRate sRate )\r
 {\r
   // The ASIO documentation says that this usually only happens during\r
   // external sync.  Audio processing is not stopped by the driver,\r
@@ -3405,7 +3450,7 @@ void sampleRateChanged( ASIOSampleRate sRate )
   try {\r
     object->stopStream();\r
   }\r
-  catch ( RtError &exception ) {\r
+  catch ( RtAudioError &exception ) {\r
     std::cerr << "\nRtApiAsio: sampleRateChanged() error (" << exception.getMessage() << ")!\n" << std::endl;\r
     return;\r
   }\r
@@ -3413,7 +3458,7 @@ void sampleRateChanged( ASIOSampleRate sRate )
   std::cerr << "\nRtApiAsio: driver reports sample rate changed to " << sRate << " ... stream stopped!!!\n" << std::endl;\r
 }\r
 \r
-long asioMessages( long selector, long value, void* message, double* opt )\r
+static long asioMessages( long selector, long value, void* message, double* opt )\r
 {\r
   long ret = 0;\r
 \r
@@ -3491,7 +3536,7 @@ static const char* getAsioErrorString( ASIOError result )
     const char*message;\r
   };\r
 \r
-  static Messages m[] = \r
+  static const Messages m[] = \r
     {\r
       {   ASE_NotPresent,    "Hardware input or output is not present or available." },\r
       {   ASE_HWMalfunction,  "Hardware is malfunctioning." },\r
@@ -3572,7 +3617,7 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
 \r
 static const char* getErrorString( int code );\r
 \r
-extern "C" unsigned __stdcall callbackHandler( void *ptr );\r
+static unsigned __stdcall callbackHandler( void *ptr );\r
 \r
 struct DsDevice {\r
   LPGUID id[2];\r
@@ -3584,7 +3629,10 @@ struct DsDevice {
   : found(false) { validId[0] = false; validId[1] = false; }\r
 };\r
 \r
-std::vector< DsDevice > dsDevices;\r
+struct DsProbeData {\r
+  bool isInput;\r
+  std::vector<struct DsDevice>* dsDevices;\r
+};\r
 \r
 RtApiDs :: RtApiDs()\r
 {\r
@@ -3622,21 +3670,23 @@ unsigned int RtApiDs :: getDeviceCount( void )
     dsDevices[i].found = false;\r
 \r
   // Query DirectSound devices.\r
-  bool isInput = false;\r
-  HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &isInput );\r
+  struct DsProbeData probeInfo;\r
+  probeInfo.isInput = false;\r
+  probeInfo.dsDevices = &dsDevices;\r
+  HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );\r
   if ( FAILED( result ) ) {\r
     errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating output devices!";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
   }\r
 \r
   // Query DirectSoundCapture devices.\r
-  isInput = true;\r
-  result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &isInput );\r
+  probeInfo.isInput = true;\r
+  result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );\r
   if ( FAILED( result ) ) {\r
     errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating input devices!";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
   }\r
 \r
   // Clean out any devices that may have disappeared.\r
@@ -3660,13 +3710,15 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
     getDeviceCount();\r
     if ( dsDevices.size() == 0 ) {\r
       errorText_ = "RtApiDs::getDeviceInfo: no devices found!";\r
-      error( RtError::INVALID_USE );\r
+      error( RtAudioError::INVALID_USE );\r
+      return info;\r
     }\r
   }\r
 \r
   if ( device >= dsDevices.size() ) {\r
     errorText_ = "RtApiDs::getDeviceInfo: device ID is invalid!";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
   }\r
 \r
   HRESULT result;\r
@@ -3678,7 +3730,7 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
   if ( FAILED( result ) ) {\r
     errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     goto probeInput;\r
   }\r
 \r
@@ -3688,7 +3740,7 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
     output->Release();\r
     errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting capabilities!";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     goto probeInput;\r
   }\r
 \r
@@ -3725,7 +3777,7 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
   if ( FAILED( result ) ) {\r
     errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -3736,7 +3788,7 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
     input->Release();\r
     errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting object capabilities (" << dsDevices[ device ].name << ")!";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -4321,6 +4373,7 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
     stream_.deviceBuffer = 0;\r
   }\r
 \r
+  stream_.state = STREAM_CLOSED;\r
   return FAILURE;\r
 }\r
 \r
@@ -4328,7 +4381,7 @@ void RtApiDs :: closeStream()
 {\r
   if ( stream_.state == STREAM_CLOSED ) {\r
     errorText_ = "RtApiDs::closeStream(): no open stream to close!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -4383,7 +4436,7 @@ void RtApiDs :: startStream()
   verifyStream();\r
   if ( stream_.state == STREAM_RUNNING ) {\r
     errorText_ = "RtApiDs::startStream(): the stream is already running!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -4431,7 +4484,7 @@ void RtApiDs :: startStream()
   stream_.state = STREAM_RUNNING;\r
 \r
  unlock:\r
-  if ( FAILED( result ) ) error( RtError::SYSTEM_ERROR );\r
+  if ( FAILED( result ) ) error( RtAudioError::SYSTEM_ERROR );\r
 }\r
 \r
 void RtApiDs :: stopStream()\r
@@ -4439,7 +4492,7 @@ void RtApiDs :: stopStream()
   verifyStream();\r
   if ( stream_.state == STREAM_STOPPED ) {\r
     errorText_ = "RtApiDs::stopStream(): the stream is already stopped!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -4528,7 +4581,7 @@ void RtApiDs :: stopStream()
 \r
  unlock:\r
   timeEndPeriod( 1 ); // revert to normal scheduler frequency on lesser windows.\r
-  if ( FAILED( result ) ) error( RtError::SYSTEM_ERROR );\r
+  if ( FAILED( result ) ) error( RtAudioError::SYSTEM_ERROR );\r
 }\r
 \r
 void RtApiDs :: abortStream()\r
@@ -4536,7 +4589,7 @@ void RtApiDs :: abortStream()
   verifyStream();\r
   if ( stream_.state == STREAM_STOPPED ) {\r
     errorText_ = "RtApiDs::abortStream(): the stream is already stopped!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -4555,7 +4608,7 @@ void RtApiDs :: callbackEvent()
 \r
   if ( stream_.state == STREAM_CLOSED ) {\r
     errorText_ = "RtApiDs::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -4641,26 +4694,30 @@ void RtApiDs :: callbackEvent()
       if ( FAILED( result ) ) {\r
         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";\r
         errorText_ = errorStream_.str();\r
-        error( RtError::SYSTEM_ERROR );\r
+        error( RtAudioError::SYSTEM_ERROR );\r
+        return;\r
       }\r
       result = dsCaptureBuffer->GetCurrentPosition( NULL, &startSafeReadPointer );\r
       if ( FAILED( result ) ) {\r
         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";\r
         errorText_ = errorStream_.str();\r
-        error( RtError::SYSTEM_ERROR );\r
+        error( RtAudioError::SYSTEM_ERROR );\r
+        return;\r
       }\r
       while ( true ) {\r
         result = dsWriteBuffer->GetCurrentPosition( NULL, &safeWritePointer );\r
         if ( FAILED( result ) ) {\r
           errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";\r
           errorText_ = errorStream_.str();\r
-          error( RtError::SYSTEM_ERROR );\r
+          error( RtAudioError::SYSTEM_ERROR );\r
+          return;\r
         }\r
         result = dsCaptureBuffer->GetCurrentPosition( NULL, &safeReadPointer );\r
         if ( FAILED( result ) ) {\r
           errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";\r
           errorText_ = errorStream_.str();\r
-          error( RtError::SYSTEM_ERROR );\r
+          error( RtAudioError::SYSTEM_ERROR );\r
+          return;\r
         }\r
         if ( safeWritePointer != startSafeWritePointer && safeReadPointer != startSafeReadPointer ) break;\r
         Sleep( 1 );\r
@@ -4680,7 +4737,8 @@ void RtApiDs :: callbackEvent()
       if ( FAILED( result ) ) {\r
         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";\r
         errorText_ = errorStream_.str();\r
-        error( RtError::SYSTEM_ERROR );\r
+        error( RtAudioError::SYSTEM_ERROR );\r
+        return;\r
       }\r
       handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0];\r
       if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0];\r
@@ -4730,7 +4788,8 @@ void RtApiDs :: callbackEvent()
       if ( FAILED( result ) ) {\r
         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";\r
         errorText_ = errorStream_.str();\r
-        error( RtError::SYSTEM_ERROR );\r
+        error( RtAudioError::SYSTEM_ERROR );\r
+        return;\r
       }\r
 \r
       // We will copy our output buffer into the region between\r
@@ -4770,7 +4829,8 @@ void RtApiDs :: callbackEvent()
     if ( FAILED( result ) ) {\r
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking buffer during playback!";\r
       errorText_ = errorStream_.str();\r
-      error( RtError::SYSTEM_ERROR );\r
+      error( RtAudioError::SYSTEM_ERROR );\r
+      return;\r
     }\r
 \r
     // Copy our buffer into the DS buffer\r
@@ -4782,7 +4842,8 @@ void RtApiDs :: callbackEvent()
     if ( FAILED( result ) ) {\r
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!";\r
       errorText_ = errorStream_.str();\r
-      error( RtError::SYSTEM_ERROR );\r
+      error( RtAudioError::SYSTEM_ERROR );\r
+      return;\r
     }\r
     nextWritePointer = ( nextWritePointer + bufferSize1 + bufferSize2 ) % dsBufferSize;\r
     handle->bufferPointer[0] = nextWritePointer;\r
@@ -4816,7 +4877,8 @@ void RtApiDs :: callbackEvent()
     if ( FAILED( result ) ) {\r
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";\r
       errorText_ = errorStream_.str();\r
-      error( RtError::SYSTEM_ERROR );\r
+      error( RtAudioError::SYSTEM_ERROR );\r
+      return;\r
     }\r
 \r
     if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset\r
@@ -4876,7 +4938,8 @@ void RtApiDs :: callbackEvent()
         if ( FAILED( result ) ) {\r
           errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";\r
           errorText_ = errorStream_.str();\r
-          error( RtError::SYSTEM_ERROR );\r
+          error( RtAudioError::SYSTEM_ERROR );\r
+          return;\r
         }\r
       \r
         if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset\r
@@ -4889,7 +4952,8 @@ void RtApiDs :: callbackEvent()
     if ( FAILED( result ) ) {\r
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking capture buffer!";\r
       errorText_ = errorStream_.str();\r
-      error( RtError::SYSTEM_ERROR );\r
+      error( RtAudioError::SYSTEM_ERROR );\r
+      return;\r
     }\r
 \r
     if ( duplexPrerollBytes <= 0 ) {\r
@@ -4909,7 +4973,8 @@ void RtApiDs :: callbackEvent()
     if ( FAILED( result ) ) {\r
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking capture buffer!";\r
       errorText_ = errorStream_.str();\r
-      error( RtError::SYSTEM_ERROR );\r
+      error( RtAudioError::SYSTEM_ERROR );\r
+      return;\r
     }\r
     handle->bufferPointer[1] = nextReadPointer;\r
 \r
@@ -4931,7 +4996,7 @@ void RtApiDs :: callbackEvent()
 // Definitions for utility functions and callbacks\r
 // specific to the DirectSound implementation.\r
 \r
-extern "C" unsigned __stdcall callbackHandler( void *ptr )\r
+static unsigned __stdcall callbackHandler( void *ptr )\r
 {\r
   CallbackInfo *info = (CallbackInfo *) ptr;\r
   RtApiDs *object = (RtApiDs *) info->object;\r
@@ -4947,12 +5012,12 @@ extern "C" unsigned __stdcall callbackHandler( void *ptr )
 \r
 #include "tchar.h"\r
 \r
-std::string convertTChar( LPCTSTR name )\r
+static std::string convertTChar( LPCTSTR name )\r
 {\r
 #if defined( UNICODE ) || defined( _UNICODE )\r
   int length = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL);\r
-  std::string s( length, 0 );\r
-  length = WideCharToMultiByte(CP_UTF8, 0, name, wcslen(name), &s[0], length, NULL, NULL);\r
+  std::string s( length-1, '\0' );\r
+  WideCharToMultiByte(CP_UTF8, 0, name, -1, &s[0], length, NULL, NULL);\r
 #else\r
   std::string s( name );\r
 #endif\r
@@ -4965,11 +5030,12 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
                                           LPCTSTR module,\r
                                           LPVOID lpContext )\r
 {\r
-  bool *isInput = (bool *) lpContext;\r
+  struct DsProbeData& probeInfo = *(struct DsProbeData*) lpContext;\r
+  std::vector<struct DsDevice>& dsDevices = *probeInfo.dsDevices;\r
 \r
   HRESULT hr;\r
   bool validDevice = false;\r
-  if ( *isInput == true ) {\r
+  if ( probeInfo.isInput == true ) {\r
     DSCCAPS caps;\r
     LPDIRECTSOUNDCAPTURE object;\r
 \r
@@ -5001,13 +5067,14 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
 \r
   // If good device, then save its name and guid.\r
   std::string name = convertTChar( description );\r
-  if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" )\r
+  //if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" )\r
+  if ( lpguid == NULL )\r
     name = "Default Device";\r
   if ( validDevice ) {\r
     for ( unsigned int i=0; i<dsDevices.size(); i++ ) {\r
       if ( dsDevices[i].name == name ) {\r
         dsDevices[i].found = true;\r
-        if ( *isInput ) {\r
+        if ( probeInfo.isInput ) {\r
           dsDevices[i].id[1] = lpguid;\r
           dsDevices[i].validId[1] = true;\r
         }\r
@@ -5022,7 +5089,7 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
     DsDevice device;\r
     device.name = name;\r
     device.found = true;\r
-    if ( *isInput ) {\r
+    if ( probeInfo.isInput ) {\r
       device.id[1] = lpguid;\r
       device.validId[1] = true;\r
     }\r
@@ -5111,7 +5178,7 @@ struct AlsaHandle {
     :synchronized(false), runnable(false) { xrun[0] = false; xrun[1] = false; }\r
 };\r
 \r
-extern "C" void *alsaCallbackHandler( void * ptr );\r
+static void *alsaCallbackHandler( void * ptr );\r
 \r
 RtApiAlsa :: RtApiAlsa()\r
 {\r
@@ -5139,7 +5206,7 @@ unsigned int RtApiAlsa :: getDeviceCount( void )
     if ( result < 0 ) {\r
       errorStream_ << "RtApiAlsa::getDeviceCount: control open, card = " << card << ", " << snd_strerror( result ) << ".";\r
       errorText_ = errorStream_.str();\r
-      error( RtError::WARNING );\r
+      error( RtAudioError::WARNING );\r
       goto nextcard;\r
     }\r
     subdevice = -1;\r
@@ -5148,7 +5215,7 @@ unsigned int RtApiAlsa :: getDeviceCount( void )
       if ( result < 0 ) {\r
         errorStream_ << "RtApiAlsa::getDeviceCount: control next device, card = " << card << ", " << snd_strerror( result ) << ".";\r
         errorText_ = errorStream_.str();\r
-        error( RtError::WARNING );\r
+        error( RtAudioError::WARNING );\r
         break;\r
       }\r
       if ( subdevice < 0 )\r
@@ -5160,6 +5227,12 @@ unsigned int RtApiAlsa :: getDeviceCount( void )
     snd_card_next( &card );\r
   }\r
 \r
+  result = snd_ctl_open( &handle, "default", 0 );\r
+  if (result == 0) {\r
+    nDevices++;\r
+    snd_ctl_close( handle );\r
+  }\r
+\r
   return nDevices;\r
 }\r
 \r
@@ -5182,7 +5255,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
     if ( result < 0 ) {\r
       errorStream_ << "RtApiAlsa::getDeviceInfo: control open, card = " << card << ", " << snd_strerror( result ) << ".";\r
       errorText_ = errorStream_.str();\r
-      error( RtError::WARNING );\r
+      error( RtAudioError::WARNING );\r
       goto nextcard;\r
     }\r
     subdevice = -1;\r
@@ -5191,7 +5264,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
       if ( result < 0 ) {\r
         errorStream_ << "RtApiAlsa::getDeviceInfo: control next device, card = " << card << ", " << snd_strerror( result ) << ".";\r
         errorText_ = errorStream_.str();\r
-        error( RtError::WARNING );\r
+        error( RtAudioError::WARNING );\r
         break;\r
       }\r
       if ( subdevice < 0 ) break;\r
@@ -5206,14 +5279,25 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
     snd_card_next( &card );\r
   }\r
 \r
+  result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK );\r
+  if ( result == 0 ) {\r
+    if ( nDevices == device ) {\r
+      strcpy( name, "default" );\r
+      goto foundDevice;\r
+    }\r
+    nDevices++;\r
+  }\r
+\r
   if ( nDevices == 0 ) {\r
     errorText_ = "RtApiAlsa::getDeviceInfo: no devices found!";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
   }\r
 \r
   if ( device >= nDevices ) {\r
     errorText_ = "RtApiAlsa::getDeviceInfo: device ID is invalid!";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
   }\r
 \r
  foundDevice:\r
@@ -5225,7 +5309,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
     snd_ctl_close( chandle );\r
     if ( device >= devices_.size() ) {\r
       errorText_ = "RtApiAlsa::getDeviceInfo: device ID was not present before stream was opened.";\r
-      error( RtError::WARNING );\r
+      error( RtAudioError::WARNING );\r
       return info;\r
     }\r
     return devices_[ device ];\r
@@ -5239,23 +5323,25 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
   snd_pcm_hw_params_t *params;\r
   snd_pcm_hw_params_alloca( &params );\r
 \r
-  // First try for playback\r
+  // First try for playback unless default device (which has subdev -1)\r
   stream = SND_PCM_STREAM_PLAYBACK;\r
-  snd_pcm_info_set_device( pcminfo, subdevice );\r
-  snd_pcm_info_set_subdevice( pcminfo, 0 );\r
   snd_pcm_info_set_stream( pcminfo, stream );\r
+  if ( subdevice != -1 ) {\r
+    snd_pcm_info_set_device( pcminfo, subdevice );\r
+    snd_pcm_info_set_subdevice( pcminfo, 0 );\r
 \r
-  result = snd_ctl_pcm_info( chandle, pcminfo );\r
-  if ( result < 0 ) {\r
-    // Device probably doesn't support playback.\r
-    goto captureProbe;\r
+    result = snd_ctl_pcm_info( chandle, pcminfo );\r
+    if ( result < 0 ) {\r
+      // Device probably doesn't support playback.\r
+      goto captureProbe;\r
+    }\r
   }\r
 \r
   result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK );\r
   if ( result < 0 ) {\r
     errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     goto captureProbe;\r
   }\r
 \r
@@ -5265,7 +5351,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
     snd_pcm_close( phandle );\r
     errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     goto captureProbe;\r
   }\r
 \r
@@ -5276,30 +5362,34 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
     snd_pcm_close( phandle );\r
     errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") output channels, " << snd_strerror( result ) << ".";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     goto captureProbe;\r
   }\r
   info.outputChannels = value;\r
   snd_pcm_close( phandle );\r
 \r
  captureProbe:\r
-  // Now try for capture\r
   stream = SND_PCM_STREAM_CAPTURE;\r
   snd_pcm_info_set_stream( pcminfo, stream );\r
 \r
-  result = snd_ctl_pcm_info( chandle, pcminfo );\r
-  snd_ctl_close( chandle );\r
-  if ( result < 0 ) {\r
-    // Device probably doesn't support capture.\r
-    if ( info.outputChannels == 0 ) return info;\r
-    goto probeParameters;\r
+  // Now try for capture unless default device (with subdev = -1)\r
+  if ( subdevice != -1 ) {\r
+    result = snd_ctl_pcm_info( chandle, pcminfo );\r
+    snd_ctl_close( chandle );\r
+    if ( result < 0 ) {\r
+      // Device probably doesn't support capture.\r
+      if ( info.outputChannels == 0 ) return info;\r
+      goto probeParameters;\r
+    }\r
   }\r
+  else\r
+    snd_ctl_close( chandle );\r
 \r
   result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK);\r
   if ( result < 0 ) {\r
     errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     if ( info.outputChannels == 0 ) return info;\r
     goto probeParameters;\r
   }\r
@@ -5310,7 +5400,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
     snd_pcm_close( phandle );\r
     errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     if ( info.outputChannels == 0 ) return info;\r
     goto probeParameters;\r
   }\r
@@ -5320,7 +5410,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
     snd_pcm_close( phandle );\r
     errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") input channels, " << snd_strerror( result ) << ".";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     if ( info.outputChannels == 0 ) return info;\r
     goto probeParameters;\r
   }\r
@@ -5354,7 +5444,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
   if ( result < 0 ) {\r
     errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -5364,7 +5454,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
     snd_pcm_close( phandle );\r
     errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -5378,7 +5468,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
     snd_pcm_close( phandle );\r
     errorStream_ << "RtApiAlsa::getDeviceInfo: no supported sample rates found for device (" << name << ").";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -5406,17 +5496,20 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
 \r
   // Check that we have at least one supported format\r
   if ( info.nativeFormats == 0 ) {\r
+    snd_pcm_close( phandle );\r
     errorStream_ << "RtApiAlsa::getDeviceInfo: pcm device (" << name << ") data format not supported by RtAudio.";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
   // Get the device name\r
   char *cardname;\r
   result = snd_card_get_name( card, &cardname );\r
-  if ( result >= 0 )\r
+  if ( result >= 0 ) {\r
     sprintf( name, "hw:%s,%d", cardname, subdevice );\r
+    free( cardname );\r
+  }\r
   info.name = name;\r
 \r
   // That's all ... close the device and return\r
@@ -5483,6 +5576,15 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
       snd_card_next( &card );\r
     }\r
 \r
+    result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK );\r
+    if ( result == 0 ) {\r
+      if ( nDevices == device ) {\r
+        strcpy( name, "default" );\r
+        goto foundDevice;\r
+      }\r
+      nDevices++;\r
+    }\r
+\r
     if ( nDevices == 0 ) {\r
       // This should not happen because a check is made before this function is called.\r
       errorText_ = "RtApiAlsa::probeDeviceOpen: no devices found!";\r
@@ -5863,7 +5965,7 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
       apiInfo->synchronized = true;\r
     else {\r
       errorText_ = "RtApiAlsa::probeDeviceOpen: unable to synchronize input and output devices.";\r
-      error( RtError::WARNING );\r
+      error( RtAudioError::WARNING );\r
     }\r
   }\r
   else {\r
@@ -5881,22 +5983,21 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
     pthread_attr_t attr;\r
     pthread_attr_init( &attr );\r
     pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );\r
+\r
 #ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)\r
     if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {\r
-      struct sched_param param;\r
+      // We previously attempted to increase the audio callback priority\r
+      // to SCHED_RR here via the attributes.  However, while no errors\r
+      // were reported in doing so, it did not work.  So, now this is\r
+      // done in the alsaCallbackHandler function.\r
+      stream_.callbackInfo.doRealtime = true;\r
       int priority = options->priority;\r
       int min = sched_get_priority_min( SCHED_RR );\r
       int max = sched_get_priority_max( SCHED_RR );\r
       if ( priority < min ) priority = min;\r
       else if ( priority > max ) priority = max;\r
-      param.sched_priority = priority;\r
-      pthread_attr_setschedpolicy( &attr, SCHED_RR );\r
-      pthread_attr_setschedparam( &attr, &param );\r
+      stream_.callbackInfo.priority = priority;\r
     }\r
-    else\r
-      pthread_attr_setschedpolicy( &attr, SCHED_OTHER );\r
-#else\r
-    pthread_attr_setschedpolicy( &attr, SCHED_OTHER );\r
 #endif\r
 \r
     stream_.callbackInfo.isRunning = true;\r
@@ -5934,6 +6035,7 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
     stream_.deviceBuffer = 0;\r
   }\r
 \r
+  stream_.state = STREAM_CLOSED;\r
   return FAILURE;\r
 }\r
 \r
@@ -5941,7 +6043,7 @@ void RtApiAlsa :: closeStream()
 {\r
   if ( stream_.state == STREAM_CLOSED ) {\r
     errorText_ = "RtApiAlsa::closeStream(): no open stream to close!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -5994,7 +6096,7 @@ void RtApiAlsa :: startStream()
   verifyStream();\r
   if ( stream_.state == STREAM_RUNNING ) {\r
     errorText_ = "RtApiAlsa::startStream(): the stream is already running!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -6017,6 +6119,7 @@ void RtApiAlsa :: startStream()
   }\r
 \r
   if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) {\r
+    result = snd_pcm_drop(handle[1]); // fix to remove stale data received since device has been open\r
     state = snd_pcm_state( handle[1] );\r
     if ( state != SND_PCM_STATE_PREPARED ) {\r
       result = snd_pcm_prepare( handle[1] );\r
@@ -6031,12 +6134,12 @@ void RtApiAlsa :: startStream()
   stream_.state = STREAM_RUNNING;\r
 \r
  unlock:\r
-  apiInfo->runnable = true;\r
+  apiInfo->runnable = false; // fixes high CPU usage when stopped\r
   pthread_cond_signal( &apiInfo->runnable_cv );\r
   MUTEX_UNLOCK( &stream_.mutex );\r
 \r
   if ( result >= 0 ) return;\r
-  error( RtError::SYSTEM_ERROR );\r
+  error( RtAudioError::SYSTEM_ERROR );\r
 }\r
 \r
 void RtApiAlsa :: stopStream()\r
@@ -6044,7 +6147,7 @@ void RtApiAlsa :: stopStream()
   verifyStream();\r
   if ( stream_.state == STREAM_STOPPED ) {\r
     errorText_ = "RtApiAlsa::stopStream(): the stream is already stopped!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -6076,10 +6179,11 @@ void RtApiAlsa :: stopStream()
   }\r
 \r
  unlock:\r
+  apiInfo->runnable = false; // fixes high CPU usage when stopped\r
   MUTEX_UNLOCK( &stream_.mutex );\r
 \r
   if ( result >= 0 ) return;\r
-  error( RtError::SYSTEM_ERROR );\r
+  error( RtAudioError::SYSTEM_ERROR );\r
 }\r
 \r
 void RtApiAlsa :: abortStream()\r
@@ -6087,7 +6191,7 @@ void RtApiAlsa :: abortStream()
   verifyStream();\r
   if ( stream_.state == STREAM_STOPPED ) {\r
     errorText_ = "RtApiAlsa::abortStream(): the stream is already stopped!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -6119,7 +6223,7 @@ void RtApiAlsa :: abortStream()
   MUTEX_UNLOCK( &stream_.mutex );\r
 \r
   if ( result >= 0 ) return;\r
-  error( RtError::SYSTEM_ERROR );\r
+  error( RtAudioError::SYSTEM_ERROR );\r
 }\r
 \r
 void RtApiAlsa :: callbackEvent()\r
@@ -6139,7 +6243,7 @@ void RtApiAlsa :: callbackEvent()
 \r
   if ( stream_.state == STREAM_CLOSED ) {\r
     errorText_ = "RtApiAlsa::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -6222,7 +6326,7 @@ void RtApiAlsa :: callbackEvent()
         errorStream_ << "RtApiAlsa::callbackEvent: audio read error, " << snd_strerror( result ) << ".";\r
         errorText_ = errorStream_.str();\r
       }\r
-      error( RtError::WARNING );\r
+      error( RtAudioError::WARNING );\r
       goto tryOutput;\r
     }\r
 \r
@@ -6292,7 +6396,7 @@ void RtApiAlsa :: callbackEvent()
         errorStream_ << "RtApiAlsa::callbackEvent: audio write error, " << snd_strerror( result ) << ".";\r
         errorText_ = errorStream_.str();\r
       }\r
-      error( RtError::WARNING );\r
+      error( RtAudioError::WARNING );\r
       goto unlock;\r
     }\r
 \r
@@ -6308,12 +6412,20 @@ void RtApiAlsa :: callbackEvent()
   if ( doStopStream == 1 ) this->stopStream();\r
 }\r
 \r
-extern "C" void *alsaCallbackHandler( void *ptr )\r
+static void *alsaCallbackHandler( void *ptr )\r
 {\r
   CallbackInfo *info = (CallbackInfo *) ptr;\r
   RtApiAlsa *object = (RtApiAlsa *) info->object;\r
   bool *isRunning = &info->isRunning;\r
 \r
+#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)\r
+  if ( &info->doRealtime ) {\r
+    pthread_t tID = pthread_self();     // ID of this thread\r
+    sched_param prio = { info->priority }; // scheduling priority of thread\r
+    pthread_setschedparam( tID, SCHED_RR, &prio );\r
+  }\r
+#endif\r
+\r
   while ( *isRunning == true ) {\r
     pthread_testcancel();\r
     object->callbackEvent();\r
@@ -6334,9 +6446,8 @@ extern "C" void *alsaCallbackHandler( void *ptr )
 #include <pulse/simple.h>\r
 #include <cstdio>\r
 \r
-namespace {\r
-const unsigned int SUPPORTED_SAMPLERATES[] = { 8000, 16000, 22050, 32000,\r
-                                               44100, 48000, 96000, 0}; }\r
+static const unsigned int SUPPORTED_SAMPLERATES[] = { 8000, 16000, 22050, 32000,\r
+                                                      44100, 48000, 96000, 0};\r
 \r
 struct rtaudio_pa_format_mapping_t {\r
   RtAudioFormat rtaudio_format;\r
@@ -6388,7 +6499,7 @@ RtAudio::DeviceInfo RtApiPulse::getDeviceInfo( unsigned int device )
   return info;\r
 }\r
 \r
-extern "C" void *pulseaudio_callback( void * user )\r
+static void *pulseaudio_callback( void * user )\r
 {\r
   CallbackInfo *cbi = static_cast<CallbackInfo *>( user );\r
   RtApiPulse *context = static_cast<RtApiPulse *>( cbi->object );\r
@@ -6460,14 +6571,14 @@ void RtApiPulse::callbackEvent( void )
   if ( stream_.state == STREAM_CLOSED ) {\r
     errorText_ = "RtApiPulse::callbackEvent(): the stream is closed ... "\r
       "this shouldn't happen!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
   RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;\r
   double streamTime = getStreamTime();\r
   RtAudioStreamStatus status = 0;\r
-  int doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1],\r
+  int doStopStream = callback( stream_.userBuffer[OUTPUT], stream_.userBuffer[INPUT],\r
                                stream_.bufferSize, streamTime, status,\r
                                stream_.callbackInfo.userData );\r
 \r
@@ -6477,50 +6588,52 @@ void RtApiPulse::callbackEvent( void )
   }\r
 \r
   MUTEX_LOCK( &stream_.mutex );\r
+  void *pulse_in = stream_.doConvertBuffer[INPUT] ? stream_.deviceBuffer : stream_.userBuffer[INPUT];\r
+  void *pulse_out = stream_.doConvertBuffer[OUTPUT] ? stream_.deviceBuffer : stream_.userBuffer[OUTPUT];\r
 \r
   if ( stream_.state != STREAM_RUNNING )\r
     goto unlock;\r
 \r
   int pa_error;\r
   size_t bytes;\r
-  switch ( stream_.mode ) {\r
-  case INPUT:\r
-    bytes = stream_.nUserChannels[1] * stream_.bufferSize * formatBytes( stream_.userFormat );\r
-    if ( pa_simple_read( pah->s_rec, stream_.userBuffer[1], bytes, &pa_error ) < 0 ) {\r
-      errorStream_ << "RtApiPulse::callbackEvent: audio read error, " <<\r
-        pa_strerror( pa_error ) << ".";\r
-      errorText_ = errorStream_.str();\r
-      error( RtError::WARNING );\r
-    }\r
-    break;\r
-  case OUTPUT:\r
-    bytes = stream_.nUserChannels[0] * stream_.bufferSize * formatBytes( stream_.userFormat );\r
-    if ( pa_simple_write( pah->s_play, stream_.userBuffer[0], bytes, &pa_error ) < 0 ) {\r
+  if (stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {\r
+    if ( stream_.doConvertBuffer[OUTPUT] ) {\r
+        convertBuffer( stream_.deviceBuffer,\r
+                       stream_.userBuffer[OUTPUT],\r
+                       stream_.convertInfo[OUTPUT] );\r
+        bytes = stream_.nDeviceChannels[OUTPUT] * stream_.bufferSize *\r
+                formatBytes( stream_.deviceFormat[OUTPUT] );\r
+    } else\r
+        bytes = stream_.nUserChannels[OUTPUT] * stream_.bufferSize *\r
+                formatBytes( stream_.userFormat );\r
+\r
+    if ( pa_simple_write( pah->s_play, pulse_out, bytes, &pa_error ) < 0 ) {\r
       errorStream_ << "RtApiPulse::callbackEvent: audio write error, " <<\r
         pa_strerror( pa_error ) << ".";\r
       errorText_ = errorStream_.str();\r
-      error( RtError::WARNING );\r
+      error( RtAudioError::WARNING );\r
     }\r
-    break;\r
-  case DUPLEX:\r
-    bytes = stream_.nUserChannels[1] * stream_.bufferSize * formatBytes( stream_.userFormat );\r
-    if ( pa_simple_read( pah->s_rec, stream_.userBuffer[1], bytes, &pa_error ) < 0 ) {\r
+  }\r
+\r
+  if ( stream_.mode == INPUT || stream_.mode == DUPLEX) {\r
+    if ( stream_.doConvertBuffer[INPUT] )\r
+      bytes = stream_.nDeviceChannels[INPUT] * stream_.bufferSize *\r
+        formatBytes( stream_.deviceFormat[INPUT] );\r
+    else\r
+      bytes = stream_.nUserChannels[INPUT] * stream_.bufferSize *\r
+        formatBytes( stream_.userFormat );\r
+            \r
+    if ( pa_simple_read( pah->s_rec, pulse_in, bytes, &pa_error ) < 0 ) {\r
       errorStream_ << "RtApiPulse::callbackEvent: audio read error, " <<\r
         pa_strerror( pa_error ) << ".";\r
       errorText_ = errorStream_.str();\r
-      error( RtError::WARNING );\r
+      error( RtAudioError::WARNING );\r
     }\r
-    bytes = stream_.nUserChannels[0] * stream_.bufferSize * formatBytes( stream_.userFormat );\r
-    if ( pa_simple_write( pah->s_play, stream_.userBuffer[0], bytes, &pa_error ) < 0) {\r
-      errorStream_ << "RtApiPulse::callbackEvent: audio write error, " <<\r
-        pa_strerror( pa_error ) << ".";\r
-      errorText_ = errorStream_.str();\r
-      error( RtError::WARNING );\r
+    if ( stream_.doConvertBuffer[INPUT] ) {\r
+      convertBuffer( stream_.userBuffer[INPUT],\r
+                     stream_.deviceBuffer,\r
+                     stream_.convertInfo[INPUT] );\r
     }\r
-    break;\r
-  default:\r
-    // ERROR\r
-    break;\r
   }\r
 \r
  unlock:\r
@@ -6537,12 +6650,12 @@ void RtApiPulse::startStream( void )
 \r
   if ( stream_.state == STREAM_CLOSED ) {\r
     errorText_ = "RtApiPulse::startStream(): the stream is not open!";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
     return;\r
   }\r
   if ( stream_.state == STREAM_RUNNING ) {\r
     errorText_ = "RtApiPulse::startStream(): the stream is already running!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -6561,12 +6674,12 @@ void RtApiPulse::stopStream( void )
 \r
   if ( stream_.state == STREAM_CLOSED ) {\r
     errorText_ = "RtApiPulse::stopStream(): the stream is not open!";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
     return;\r
   }\r
   if ( stream_.state == STREAM_STOPPED ) {\r
     errorText_ = "RtApiPulse::stopStream(): the stream is already stopped!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -6580,7 +6693,8 @@ void RtApiPulse::stopStream( void )
         pa_strerror( pa_error ) << ".";\r
       errorText_ = errorStream_.str();\r
       MUTEX_UNLOCK( &stream_.mutex );\r
-      error( RtError::SYSTEM_ERROR );\r
+      error( RtAudioError::SYSTEM_ERROR );\r
+      return;\r
     }\r
   }\r
 \r
@@ -6594,12 +6708,12 @@ void RtApiPulse::abortStream( void )
 \r
   if ( stream_.state == STREAM_CLOSED ) {\r
     errorText_ = "RtApiPulse::abortStream(): the stream is not open!";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
     return;\r
   }\r
   if ( stream_.state == STREAM_STOPPED ) {\r
     errorText_ = "RtApiPulse::abortStream(): the stream is already stopped!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -6613,7 +6727,8 @@ void RtApiPulse::abortStream( void )
         pa_strerror( pa_error ) << ".";\r
       errorText_ = errorStream_.str();\r
       MUTEX_UNLOCK( &stream_.mutex );\r
-      error( RtError::SYSTEM_ERROR );\r
+      error( RtAudioError::SYSTEM_ERROR );\r
+      return;\r
     }\r
   }\r
 \r
@@ -6669,20 +6784,16 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
     return false;\r
   }\r
 \r
-  if ( options && ( options->flags & RTAUDIO_NONINTERLEAVED ) ) {\r
-    errorText_ = "RtApiPulse::probeDeviceOpen: only interleaved audio data supported.";\r
-    return false;\r
-  }\r
-\r
-  stream_.userInterleaved = true;\r
-  stream_.nBuffers = 1;\r
-\r
+  // Set interleaving parameters.\r
+  if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;\r
+  else stream_.userInterleaved = true;\r
   stream_.deviceInterleaved[mode] = true;\r
+  stream_.nBuffers = 1;\r
   stream_.doByteSwap[mode] = false;\r
-  stream_.doConvertBuffer[mode] = false;\r
+  stream_.doConvertBuffer[mode] = channels > 1 && !stream_.userInterleaved;\r
   stream_.deviceFormat[mode] = stream_.userFormat;\r
   stream_.nUserChannels[mode] = channels;\r
-  stream_.nDeviceChannels[mode] = channels;\r
+  stream_.nDeviceChannels[mode] = channels + firstChannel;\r
   stream_.channelOffset[mode] = 0;\r
 \r
   // Allocate necessary internal buffers.\r
@@ -6694,6 +6805,33 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
   }\r
   stream_.bufferSize = *bufferSize;\r
 \r
+  if ( stream_.doConvertBuffer[mode] ) {\r
+\r
+    bool makeBuffer = true;\r
+    bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );\r
+    if ( mode == INPUT ) {\r
+      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {\r
+        unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );\r
+        if ( bufferBytes <= bytesOut ) makeBuffer = false;\r
+      }\r
+    }\r
+\r
+    if ( makeBuffer ) {\r
+      bufferBytes *= *bufferSize;\r
+      if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );\r
+      stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );\r
+      if ( stream_.deviceBuffer == NULL ) {\r
+        errorText_ = "RtApiPulse::probeDeviceOpen: error allocating device buffer memory.";\r
+        goto error;\r
+      }\r
+    }\r
+  }\r
+\r
+  stream_.device[mode] = device;\r
+\r
+  // Setup the buffer conversion information structure.\r
+  if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );\r
+\r
   if ( !stream_.apiHandle ) {\r
     PulseAudioHandle *pah = new PulseAudioHandle;\r
     if ( !pah ) {\r
@@ -6710,9 +6848,15 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
   pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );\r
 \r
   int error;\r
+  std::string streamName = "RtAudio";\r
+  if ( !options->streamName.empty() ) streamName = options->streamName;\r
   switch ( mode ) {\r
   case INPUT:\r
-    pah->s_rec = pa_simple_new( NULL, "RtAudio", PA_STREAM_RECORD, NULL, "Record", &ss, NULL, NULL, &error );\r
+    pa_buffer_attr buffer_attr;\r
+    buffer_attr.fragsize = bufferBytes;\r
+    buffer_attr.maxlength = -1;\r
+\r
+    pah->s_rec = pa_simple_new( NULL, streamName.c_str(), PA_STREAM_RECORD, NULL, "Record", &ss, NULL, &buffer_attr, &error );\r
     if ( !pah->s_rec ) {\r
       errorText_ = "RtApiPulse::probeDeviceOpen: error connecting input to PulseAudio server.";\r
       goto error;\r
@@ -6736,8 +6880,6 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
   else\r
     stream_.mode = DUPLEX;\r
 \r
-  stream_.state = STREAM_STOPPED;\r
-\r
   if ( !stream_.callbackInfo.isRunning ) {\r
     stream_.callbackInfo.object = this;\r
     stream_.callbackInfo.isRunning = true;\r
@@ -6746,11 +6888,30 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
       goto error;\r
     }\r
   }\r
+\r
+  stream_.state = STREAM_STOPPED;\r
   return true;\r
  \r
  error:\r
-  closeStream();\r
-  return false;\r
+  if ( pah && stream_.callbackInfo.isRunning ) {\r
+    pthread_cond_destroy( &pah->runnable_cv );\r
+    delete pah;\r
+    stream_.apiHandle = 0;\r
+  }\r
+\r
+  for ( int i=0; i<2; i++ ) {\r
+    if ( stream_.userBuffer[i] ) {\r
+      free( stream_.userBuffer[i] );\r
+      stream_.userBuffer[i] = 0;\r
+    }\r
+  }\r
+\r
+  if ( stream_.deviceBuffer ) {\r
+    free( stream_.deviceBuffer );\r
+    stream_.deviceBuffer = 0;\r
+  }\r
+\r
+  return FAILURE;\r
 }\r
 \r
 //******************** End of __LINUX_PULSE__ *********************//\r
@@ -6762,11 +6923,11 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
 #include <sys/ioctl.h>\r
 #include <unistd.h>\r
 #include <fcntl.h>\r
-#include "soundcard.h"\r
+#include <sys/soundcard.h>\r
 #include <errno.h>\r
 #include <math.h>\r
 \r
-extern "C" void *ossCallbackHandler(void * ptr);\r
+static void *ossCallbackHandler(void * ptr);\r
 \r
 // A structure to hold various information related to the OSS API\r
 // implementation.\r
@@ -6795,7 +6956,7 @@ unsigned int RtApiOss :: getDeviceCount( void )
   int mixerfd = open( "/dev/mixer", O_RDWR, 0 );\r
   if ( mixerfd == -1 ) {\r
     errorText_ = "RtApiOss::getDeviceCount: error opening '/dev/mixer'.";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return 0;\r
   }\r
 \r
@@ -6803,7 +6964,7 @@ unsigned int RtApiOss :: getDeviceCount( void )
   if ( ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo ) == -1 ) {\r
     close( mixerfd );\r
     errorText_ = "RtApiOss::getDeviceCount: error getting sysinfo, OSS version >= 4.0 is required.";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return 0;\r
   }\r
 \r
@@ -6819,7 +6980,7 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
   int mixerfd = open( "/dev/mixer", O_RDWR, 0 );\r
   if ( mixerfd == -1 ) {\r
     errorText_ = "RtApiOss::getDeviceInfo: error opening '/dev/mixer'.";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -6828,7 +6989,7 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
   if ( result == -1 ) {\r
     close( mixerfd );\r
     errorText_ = "RtApiOss::getDeviceInfo: error getting sysinfo, OSS version >= 4.0 is required.";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -6836,13 +6997,15 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
   if ( nDevices == 0 ) {\r
     close( mixerfd );\r
     errorText_ = "RtApiOss::getDeviceInfo: no devices found!";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
   }\r
 \r
   if ( device >= nDevices ) {\r
     close( mixerfd );\r
     errorText_ = "RtApiOss::getDeviceInfo: device ID is invalid!";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
+    return info;\r
   }\r
 \r
   oss_audioinfo ainfo;\r
@@ -6852,7 +7015,7 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
   if ( result == -1 ) {\r
     errorStream_ << "RtApiOss::getDeviceInfo: error getting device (" << ainfo.name << ") info.";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -6881,7 +7044,7 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
   if ( info.nativeFormats == 0 ) {\r
     errorStream_ << "RtApiOss::getDeviceInfo: device (" << ainfo.name << ") data format not supported by RtAudio.";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return info;\r
   }\r
 \r
@@ -6908,7 +7071,7 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
   if ( info.sampleRates.size() == 0 ) {\r
     errorStream_ << "RtApiOss::getDeviceInfo: no supported sample rates found for device (" << ainfo.name << ").";\r
     errorText_ = errorStream_.str();\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
   }\r
   else {\r
     info.probed = true;\r
@@ -7357,7 +7520,7 @@ void RtApiOss :: closeStream()
 {\r
   if ( stream_.state == STREAM_CLOSED ) {\r
     errorText_ = "RtApiOss::closeStream(): no open stream to close!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -7406,7 +7569,7 @@ void RtApiOss :: startStream()
   verifyStream();\r
   if ( stream_.state == STREAM_RUNNING ) {\r
     errorText_ = "RtApiOss::startStream(): the stream is already running!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -7428,7 +7591,7 @@ void RtApiOss :: stopStream()
   verifyStream();\r
   if ( stream_.state == STREAM_STOPPED ) {\r
     errorText_ = "RtApiOss::stopStream(): the stream is already stopped!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -7465,7 +7628,7 @@ void RtApiOss :: stopStream()
       result = write( handle->id[0], buffer, samples * formatBytes(format) );\r
       if ( result == -1 ) {\r
         errorText_ = "RtApiOss::stopStream: audio write error.";\r
-        error( RtError::WARNING );\r
+        error( RtAudioError::WARNING );\r
       }\r
     }\r
 \r
@@ -7492,7 +7655,7 @@ void RtApiOss :: stopStream()
   MUTEX_UNLOCK( &stream_.mutex );\r
 \r
   if ( result != -1 ) return;\r
-  error( RtError::SYSTEM_ERROR );\r
+  error( RtAudioError::SYSTEM_ERROR );\r
 }\r
 \r
 void RtApiOss :: abortStream()\r
@@ -7500,7 +7663,7 @@ void RtApiOss :: abortStream()
   verifyStream();\r
   if ( stream_.state == STREAM_STOPPED ) {\r
     errorText_ = "RtApiOss::abortStream(): the stream is already stopped!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -7538,7 +7701,7 @@ void RtApiOss :: abortStream()
   MUTEX_UNLOCK( &stream_.mutex );\r
 \r
   if ( result != -1 ) return;\r
-  error( RtError::SYSTEM_ERROR );\r
+  error( RtAudioError::SYSTEM_ERROR );\r
 }\r
 \r
 void RtApiOss :: callbackEvent()\r
@@ -7556,7 +7719,7 @@ void RtApiOss :: callbackEvent()
 \r
   if ( stream_.state == STREAM_CLOSED ) {\r
     errorText_ = "RtApiOss::callbackEvent(): the stream is closed ... this shouldn't happen!";\r
-    error( RtError::WARNING );\r
+    error( RtAudioError::WARNING );\r
     return;\r
   }\r
 \r
@@ -7626,7 +7789,7 @@ void RtApiOss :: callbackEvent()
       // specific means for determining that.\r
       handle->xrun[0] = true;\r
       errorText_ = "RtApiOss::callbackEvent: audio write error.";\r
-      error( RtError::WARNING );\r
+      error( RtAudioError::WARNING );\r
       // Continue on to input section.\r
     }\r
   }\r
@@ -7653,7 +7816,7 @@ void RtApiOss :: callbackEvent()
       // specific means for determining that.\r
       handle->xrun[1] = true;\r
       errorText_ = "RtApiOss::callbackEvent: audio read error.";\r
-      error( RtError::WARNING );\r
+      error( RtAudioError::WARNING );\r
       goto unlock;\r
     }\r
 \r
@@ -7673,7 +7836,7 @@ void RtApiOss :: callbackEvent()
   if ( doStopStream == 1 ) this->stopStream();\r
 }\r
 \r
-extern "C" void *ossCallbackHandler( void *ptr )\r
+static void *ossCallbackHandler( void *ptr )\r
 {\r
   CallbackInfo *info = (CallbackInfo *) ptr;\r
   RtApiOss *object = (RtApiOss *) info->object;\r
@@ -7699,20 +7862,41 @@ extern "C" void *ossCallbackHandler( void *ptr )
 \r
 // This method can be modified to control the behavior of error\r
 // message printing.\r
-void RtApi :: error( RtError::Type type )\r
+void RtApi :: error( RtAudioError::Type type )\r
 {\r
   errorStream_.str(""); // clear the ostringstream\r
-  if ( type == RtError::WARNING && showWarnings_ == true )\r
+\r
+  RtAudioErrorCallback errorCallback = (RtAudioErrorCallback) stream_.callbackInfo.errorCallback;\r
+  if ( errorCallback ) {\r
+    // abortStream() can generate new error messages. Ignore them. Just keep original one.\r
+\r
+    if ( firstErrorOccurred_ )\r
+      return;\r
+\r
+    firstErrorOccurred_ = true;\r
+    const std::string errorMessage = errorText_;\r
+\r
+    if ( type != RtAudioError::WARNING && stream_.state != STREAM_STOPPED) {\r
+      stream_.callbackInfo.isRunning = false; // exit from the thread\r
+      abortStream();\r
+    }\r
+\r
+    errorCallback( type, errorMessage );\r
+    firstErrorOccurred_ = false;\r
+    return;\r
+  }\r
+\r
+  if ( type == RtAudioError::WARNING && showWarnings_ == true )\r
     std::cerr << '\n' << errorText_ << "\n\n";\r
-  else if ( type != RtError::WARNING )\r
-    throw( RtError( errorText_, type ) );\r
+  else if ( type != RtAudioError::WARNING )\r
+    throw( RtAudioError( errorText_, type ) );\r
 }\r
 \r
 void RtApi :: verifyStream()\r
 {\r
   if ( stream_.state == STREAM_CLOSED ) {\r
     errorText_ = "RtApi:: a stream is not open!";\r
-    error( RtError::INVALID_USE );\r
+    error( RtAudioError::INVALID_USE );\r
   }\r
 }\r
 \r
@@ -7731,6 +7915,7 @@ void RtApi :: clearStreamInfo()
   stream_.callbackInfo.callback = 0;\r
   stream_.callbackInfo.userData = 0;\r
   stream_.callbackInfo.isRunning = false;\r
+  stream_.callbackInfo.errorCallback = 0;\r
   for ( int i=0; i<2; i++ ) {\r
     stream_.device[i] = 11111;\r
     stream_.doConvertBuffer[i] = false;\r
@@ -7766,7 +7951,7 @@ unsigned int RtApi :: formatBytes( RtAudioFormat format )
     return 1;\r
 \r
   errorText_ = "RtApi::formatBytes: undefined format.";\r
-  error( RtError::WARNING );\r
+  error( RtAudioError::WARNING );\r
 \r
   return 0;\r
 }\r