Fixed major ASIO duplex initialization bug. Added "preferredSampleRate" to the device...
authoryedey <myco@gmx.net>
Mon, 6 Oct 2014 12:08:51 +0000 (14:08 +0200)
committeryedey <myco@gmx.net>
Mon, 6 Oct 2014 12:08:51 +0000 (14:08 +0200)
RtAudio.cpp
RtAudio.h

index 6baddc9c5500899793aff7ee5c694d82eeea3dc7..fb4a27f80239cf7f0ac2db6a38769ab8b2e60030 100644 (file)
@@ -777,9 +777,14 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   bool haveValueRange = false;\r
   info.sampleRates.clear();\r
   for ( UInt32 i=0; i<nRanges; i++ ) {\r
-    if ( rangeList[i].mMinimum == rangeList[i].mMaximum )\r
-      info.sampleRates.push_back( (unsigned int) rangeList[i].mMinimum );\r
-    else {\r
+    if ( rangeList[i].mMinimum == rangeList[i].mMaximum ) {\r
+      unsigned int tmpSr = (unsigned int) rangeList[i].mMinimum;\r
+      info.sampleRates.push_back( tmpSr );\r
+\r
+      if ( !info.preferredSampleRate || ( tmpSr <= 48000 && tmpSr > info.preferredSampleRate ) )\r
+        info.preferredSampleRate = tmpSr;\r
+\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
@@ -788,8 +793,12 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
 \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
+      if ( SAMPLE_RATES[k] >= (unsigned int) minimumRate && SAMPLE_RATES[k] <= (unsigned int) maximumRate ) {\r
         info.sampleRates.push_back( SAMPLE_RATES[k] );\r
+\r
+        if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )\r
+          info.preferredSampleRate = SAMPLE_RATES[k];\r
+      }\r
     }\r
   }\r
 \r
@@ -2000,7 +2009,9 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
 \r
   // Get the current jack server sample rate.\r
   info.sampleRates.clear();\r
-  info.sampleRates.push_back( jack_get_sample_rate( client ) );\r
+\r
+  info.preferredSampleRate = jack_get_sample_rate( client );\r
+  info.sampleRates.push_back( info.preferredSampleRate );\r
 \r
   // Count the available ports containing the client name as device\r
   // channels.  Jack "input ports" equal RtAudio output channels.\r
@@ -2780,8 +2791,12 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
   info.sampleRates.clear();\r
   for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {\r
     result = ASIOCanSampleRate( (ASIOSampleRate) SAMPLE_RATES[i] );\r
-    if ( result == ASE_OK )\r
+    if ( result == ASE_OK ) {\r
       info.sampleRates.push_back( SAMPLE_RATES[i] );\r
+\r
+      if ( !info.preferredSampleRate || ( SAMPLE_RATES[i] <= 48000 && SAMPLE_RATES[i] > info.preferredSampleRate ) )\r
+        info.preferredSampleRate = SAMPLE_RATES[i];\r
+    }\r
   }\r
 \r
   // Determine supported data types ... just check first channel and assume rest are the same.\r
@@ -2840,9 +2855,12 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
                                    unsigned int firstChannel, unsigned int sampleRate,\r
                                    RtAudioFormat format, unsigned int *bufferSize,\r
                                    RtAudio::StreamOptions *options )\r
-{\r
+{////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r
+\r
+  bool isDuplexInput =  mode == INPUT && stream_.mode == OUTPUT;\r
+\r
   // For ASIO, a duplex stream MUST use the same driver.\r
-  if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] != device ) {\r
+  if ( isDuplexInput && stream_.device[0] != device ) {\r
     errorText_ = "RtApiAsio::probeDeviceOpen: an ASIO duplex stream must use the same device for input and output!";\r
     return FAILURE;\r
   }\r
@@ -2856,7 +2874,7 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   }\r
 \r
   // Only load the driver once for duplex stream.\r
-  if ( mode != INPUT || stream_.mode != OUTPUT ) {\r
+  if ( !isDuplexInput ) {\r
     // The getDeviceInfo() function will not work when a stream is open\r
     // because ASIO does not allow multiple devices to run at the same\r
     // time.  Thus, we'll probe the system before opening a stream and\r
@@ -2877,22 +2895,26 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
     }\r
   }\r
 \r
+  // keep them before any "goto error", they are used for error cleanup + goto device boundary checks\r
+  bool buffersAllocated = false;\r
+  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;\r
+  unsigned int nChannels;\r
+\r
+\r
   // Check the device channel count.\r
   long inputChannels, outputChannels;\r
   result = ASIOGetChannels( &inputChannels, &outputChannels );\r
   if ( result != ASE_OK ) {\r
-    drivers.removeCurrentDriver();\r
     errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ").";\r
     errorText_ = errorStream_.str();\r
-    return FAILURE;\r
+    goto error;\r
   }\r
 \r
   if ( ( mode == OUTPUT && (channels+firstChannel) > (unsigned int) outputChannels) ||\r
        ( mode == INPUT && (channels+firstChannel) > (unsigned int) inputChannels) ) {\r
-    drivers.removeCurrentDriver();\r
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested channel count (" << channels << ") + offset (" << firstChannel << ").";\r
     errorText_ = errorStream_.str();\r
-    return FAILURE;\r
+    goto error;\r
   }\r
   stream_.nDeviceChannels[mode] = channels;\r
   stream_.nUserChannels[mode] = channels;\r
@@ -2901,30 +2923,27 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   // Verify the sample rate is supported.\r
   result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate );\r
   if ( result != ASE_OK ) {\r
-    drivers.removeCurrentDriver();\r
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested sample rate (" << sampleRate << ").";\r
     errorText_ = errorStream_.str();\r
-    return FAILURE;\r
+    goto error;\r
   }\r
 \r
   // Get the current sample rate\r
   ASIOSampleRate currentRate;\r
   result = ASIOGetSampleRate( &currentRate );\r
   if ( result != ASE_OK ) {\r
-    drivers.removeCurrentDriver();\r
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error getting sample rate.";\r
     errorText_ = errorStream_.str();\r
-    return FAILURE;\r
+    goto error;\r
   }\r
 \r
   // Set the sample rate only if necessary\r
   if ( currentRate != sampleRate ) {\r
     result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );\r
     if ( result != ASE_OK ) {\r
-      drivers.removeCurrentDriver();\r
       errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error setting sample rate (" << sampleRate << ").";\r
       errorText_ = errorStream_.str();\r
-      return FAILURE;\r
+      goto error;\r
     }\r
   }\r
 \r
@@ -2935,10 +2954,9 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   else channelInfo.isInput = true;\r
   result = ASIOGetChannelInfo( &channelInfo );\r
   if ( result != ASE_OK ) {\r
-    drivers.removeCurrentDriver();\r
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting data format.";\r
     errorText_ = errorStream_.str();\r
-    return FAILURE;\r
+    goto error;\r
   }\r
 \r
   // Assuming WINDOWS host is always little-endian.\r
@@ -2967,10 +2985,9 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   }\r
 \r
   if ( stream_.deviceFormat[mode] == 0 ) {\r
-    drivers.removeCurrentDriver();\r
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") data format not supported by RtAudio.";\r
     errorText_ = errorStream_.str();\r
-    return FAILURE;\r
+    goto error;\r
   }\r
 \r
   // Set the buffer size.  For a duplex stream, this will end up\r
@@ -2979,49 +2996,62 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   long minSize, maxSize, preferSize, granularity;\r
   result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity );\r
   if ( result != ASE_OK ) {\r
-    drivers.removeCurrentDriver();\r
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting buffer size.";\r
     errorText_ = errorStream_.str();\r
-    return FAILURE;\r
+    goto error;\r
   }\r
 \r
-  if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;\r
-  else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;\r
-  else if ( granularity == -1 ) {\r
-    // Make sure bufferSize is a power of two.\r
-    int log2_of_min_size = 0;\r
-    int log2_of_max_size = 0;\r
+  if ( isDuplexInput ) {\r
+    // When this is the duplex input (output was opened before), then we have to use the same\r
+    // buffersize as the output, because it might use the preferred buffer size, which most\r
+    // likely wasn't passed as input to this. The buffer sizes have to be identically anyway,\r
+    // So instead of throwing an error, make them equal. The caller uses the reference\r
+    // to the "bufferSize" param as usual to set up processing buffers.\r
 \r
-    for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) {\r
-      if ( minSize & ((long)1 << i) ) log2_of_min_size = i;\r
-      if ( maxSize & ((long)1 << i) ) log2_of_max_size = i;\r
-    }\r
+    *bufferSize = stream_.bufferSize;\r
 \r
-    long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) );\r
-    int min_delta_num = log2_of_min_size;\r
+  } else {\r
+    if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;\r
+    else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;\r
+    else if ( granularity == -1 ) {\r
+      // Make sure bufferSize is a power of two.\r
+      int log2_of_min_size = 0;\r
+      int log2_of_max_size = 0;\r
 \r
-    for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) {\r
-      long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) );\r
-      if (current_delta < min_delta) {\r
-        min_delta = current_delta;\r
-        min_delta_num = i;\r
+      for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) {\r
+        if ( minSize & ((long)1 << i) ) log2_of_min_size = i;\r
+        if ( maxSize & ((long)1 << i) ) log2_of_max_size = i;\r
       }\r
-    }\r
 \r
-    *bufferSize = ( (unsigned int)1 << min_delta_num );\r
-    if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;\r
-    else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;\r
-  }\r
-  else if ( granularity != 0 ) {\r
-    // Set to an even multiple of granularity, rounding up.\r
-    *bufferSize = (*bufferSize + granularity-1) / granularity * granularity;\r
+      long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) );\r
+      int min_delta_num = log2_of_min_size;\r
+\r
+      for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) {\r
+        long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) );\r
+        if (current_delta < min_delta) {\r
+          min_delta = current_delta;\r
+          min_delta_num = i;\r
+        }\r
+      }\r
+\r
+      *bufferSize = ( (unsigned int)1 << min_delta_num );\r
+      if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;\r
+      else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;\r
+    }\r
+    else if ( granularity != 0 ) {\r
+      // Set to an even multiple of granularity, rounding up.\r
+      *bufferSize = (*bufferSize + granularity-1) / granularity * granularity;\r
+    }\r
   }\r
 \r
-  if ( mode == INPUT && stream_.mode == OUTPUT && stream_.bufferSize != *bufferSize ) {\r
-    drivers.removeCurrentDriver();\r
+  /*\r
+  // we don't use it anymore, see above!\r
+  // Just left it here for the case...\r
+  if ( isDuplexInput && stream_.bufferSize != *bufferSize ) {\r
     errorText_ = "RtApiAsio::probeDeviceOpen: input/output buffersize discrepancy!";\r
-    return FAILURE;\r
+    goto error;\r
   }\r
+  */\r
 \r
   stream_.bufferSize = *bufferSize;\r
   stream_.nBuffers = 2;\r
@@ -3033,16 +3063,13 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   stream_.deviceInterleaved[mode] = false;\r
 \r
   // Allocate, if necessary, our AsioHandle structure for the stream.\r
-  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;\r
   if ( handle == 0 ) {\r
     try {\r
       handle = new AsioHandle;\r
     }\r
     catch ( std::bad_alloc& ) {\r
-      //if ( handle == NULL ) {    \r
-      drivers.removeCurrentDriver();\r
       errorText_ = "RtApiAsio::probeDeviceOpen: error allocating AsioHandle memory.";\r
-      return FAILURE;\r
+      goto error;\r
     }\r
     handle->bufferInfos = 0;\r
 \r
@@ -3057,15 +3084,14 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   // Create the ASIO internal buffers.  Since RtAudio sets up input\r
   // and output separately, we'll have to dispose of previously\r
   // created output buffers for a duplex stream.\r
-  long inputLatency, outputLatency;\r
   if ( mode == INPUT && stream_.mode == OUTPUT ) {\r
     ASIODisposeBuffers();\r
     if ( handle->bufferInfos ) free( handle->bufferInfos );\r
   }\r
 \r
   // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure.\r
-  bool buffersAllocated = false;\r
-  unsigned int i, nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];\r
+  unsigned int i;\r
+  nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];\r
   handle->bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) );\r
   if ( handle->bufferInfos == NULL ) {\r
     errorStream_ << "RtApiAsio::probeDeviceOpen: error allocating bufferInfo memory for driver (" << driverName << ").";\r
@@ -3089,11 +3115,7 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   // prepare for callbacks\r
   stream_.sampleRate = sampleRate;\r
   stream_.device[mode] = device;\r
-  if ( stream_.mode == OUTPUT && mode == INPUT )\r
-    // We had already set up an output stream.\r
-    stream_.mode = DUPLEX;\r
-  else\r
-    stream_.mode = mode;\r
+  stream_.mode = isDuplexInput ? DUPLEX : mode;\r
 \r
   // store this class instance before registering callbacks, that are going to use it\r
   asioCallbackInfo = &stream_.callbackInfo;\r
@@ -3119,7 +3141,7 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
     errorText_ = errorStream_.str();\r
     goto error;\r
   }\r
-  buffersAllocated = true;\r
+  buffersAllocated = true;  \r
   stream_.state = STREAM_STOPPED;\r
 \r
   // Set flags for buffer conversion.\r
@@ -3143,7 +3165,7 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
 \r
     bool makeBuffer = true;\r
     bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );\r
-    if ( stream_.mode == DUPLEX && stream_.deviceBuffer ) {\r
+    if ( isDuplexInput && stream_.deviceBuffer ) {\r
       unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );\r
       if ( bufferBytes <= bytesOut ) makeBuffer = false;\r
     }\r
@@ -3160,6 +3182,7 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   }\r
 \r
   // Determine device latencies\r
+  long inputLatency, outputLatency;\r
   result = ASIOGetLatencies( &inputLatency, &outputLatency );\r
   if ( result != ASE_OK ) {\r
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting latency.";\r
@@ -3179,32 +3202,38 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   return SUCCESS;\r
 \r
  error:\r
-  if ( buffersAllocated )\r
-    ASIODisposeBuffers();\r
-  drivers.removeCurrentDriver();\r
+  if ( !isDuplexInput ) {\r
+    // the cleanup for error in the duplex input, is done by RtApi::openStream\r
+    // So we clean up for single channel only\r
 \r
-  if ( handle ) {\r
-    CloseHandle( handle->condition );\r
-    if ( handle->bufferInfos )\r
-      free( handle->bufferInfos );\r
-    delete handle;\r
-    stream_.apiHandle = 0;\r
-  }\r
+    if ( buffersAllocated )\r
+      ASIODisposeBuffers();\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
+    drivers.removeCurrentDriver();\r
+\r
+    if ( handle ) {\r
+      CloseHandle( handle->condition );\r
+      if ( handle->bufferInfos )\r
+        free( handle->bufferInfos );\r
+\r
+      delete handle;\r
+      stream_.apiHandle = 0;\r
     }\r
-  }\r
 \r
-  if ( stream_.deviceBuffer ) {\r
-    free( stream_.deviceBuffer );\r
-    stream_.deviceBuffer = 0;\r
+\r
+    if ( stream_.userBuffer[mode] ) {\r
+      free( stream_.userBuffer[mode] );\r
+      stream_.userBuffer[mode] = 0;\r
+    }\r
+\r
+    if ( stream_.deviceBuffer ) {\r
+      free( stream_.deviceBuffer );\r
+      stream_.deviceBuffer = 0;\r
+    }\r
   }\r
 \r
   return FAILURE;\r
-}\r
+}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\r
 \r
 void RtApiAsio :: closeStream()\r
 {\r
@@ -4128,6 +4157,7 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device )
   for ( unsigned int i = 0; i < MAX_SAMPLE_RATES; i++ ) {\r
     info.sampleRates.push_back( SAMPLE_RATES[i] );\r
   }\r
+  info.preferredSampleRate = deviceFormat->nSamplesPerSec;\r
 \r
   // native format\r
   info.nativeFormats = 0;\r
@@ -5326,8 +5356,12 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
   info.sampleRates.clear();\r
   for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {\r
     if ( SAMPLE_RATES[k] >= (unsigned int) outCaps.dwMinSecondarySampleRate &&\r
-         SAMPLE_RATES[k] <= (unsigned int) outCaps.dwMaxSecondarySampleRate )\r
+         SAMPLE_RATES[k] <= (unsigned int) outCaps.dwMaxSecondarySampleRate ) {\r
       info.sampleRates.push_back( SAMPLE_RATES[k] );\r
+\r
+      if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )\r
+        info.preferredSampleRate = SAMPLE_RATES[k];\r
+    }\r
   }\r
 \r
   // Get format information.\r
@@ -7036,8 +7070,12 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
   // Test our discrete set of sample rate values.\r
   info.sampleRates.clear();\r
   for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {\r
-    if ( snd_pcm_hw_params_test_rate( phandle, params, SAMPLE_RATES[i], 0 ) == 0 )\r
+    if ( snd_pcm_hw_params_test_rate( phandle, params, SAMPLE_RATES[i], 0 ) == 0 ) {\r
       info.sampleRates.push_back( SAMPLE_RATES[i] );\r
+\r
+      if ( !info.preferredSampleRate || ( SAMPLE_RATES[i] <= 48000 && SAMPLE_RATES[i] > info.preferredSampleRate ) )\r
+        info.preferredSampleRate = SAMPLE_RATES[i];\r
+    }\r
   }\r
   if ( info.sampleRates.size() == 0 ) {\r
     snd_pcm_close( phandle );\r
@@ -8070,6 +8108,7 @@ RtAudio::DeviceInfo RtApiPulse::getDeviceInfo( unsigned int /*device*/ )
   for ( const unsigned int *sr = SUPPORTED_SAMPLERATES; *sr; ++sr )\r
     info.sampleRates.push_back( *sr );\r
 \r
+  info.preferredSampleRate = 48000;\r
   info.nativeFormats = RTAUDIO_SINT16 | RTAUDIO_SINT32 | RTAUDIO_FLOAT32;\r
 \r
   return info;\r
@@ -8638,6 +8677,10 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
       for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {\r
         if ( ainfo.rates[i] == SAMPLE_RATES[k] ) {\r
           info.sampleRates.push_back( SAMPLE_RATES[k] );\r
+\r
+          if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )\r
+            info.preferredSampleRate = SAMPLE_RATES[k];\r
+\r
           break;\r
         }\r
       }\r
@@ -8646,8 +8689,12 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
   else {\r
     // Check min and max rate values;\r
     for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {\r
-      if ( ainfo.min_rate <= (int) SAMPLE_RATES[k] && ainfo.max_rate >= (int) SAMPLE_RATES[k] )\r
+      if ( ainfo.min_rate <= (int) SAMPLE_RATES[k] && ainfo.max_rate >= (int) SAMPLE_RATES[k] ) {\r
         info.sampleRates.push_back( SAMPLE_RATES[k] );\r
+\r
+        if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )\r
+          info.preferredSampleRate = SAMPLE_RATES[k];\r
+      }\r
     }\r
   }\r
 \r
index 57d2c8dcd2423e828f23fdc60930815ac0274664..ea08fdaa34153c321076d6176e6b10f7150f0631 100644 (file)
--- a/RtAudio.h
+++ b/RtAudio.h
@@ -286,12 +286,13 @@ class RtAudio
     bool isDefaultOutput;         /*!< true if this is the default output device. */
     bool isDefaultInput;          /*!< true if this is the default input device. */
     std::vector<unsigned int> sampleRates; /*!< Supported sample rates (queried from list of standard rates). */
+    unsigned int preferredSampleRate; /*!< Preferred sample rate, eg. for WASAPI the system sample rate. */
     RtAudioFormat nativeFormats;  /*!< Bit mask of supported data formats. */
 
     // Default constructor.
     DeviceInfo()
       :probed(false), outputChannels(0), inputChannels(0), duplexChannels(0),
-       isDefaultOutput(false), isDefaultInput(false), nativeFormats(0) {}
+       isDefaultOutput(false), isDefaultInput(false), preferredSampleRate(0), nativeFormats(0) {}
   };
 
   //! The structure for specifying input or ouput stream parameters.