More detailed error message.
[rtaudio-cdist.git] / RtAudio.cpp
index bea68a88f717280e09b97be3f684693084a6d47a..18d1fd0af29b264fe835aa78649b09e9af5324fa 100644 (file)
@@ -114,7 +114,7 @@ const char* rtaudio_api_names[][2] = {
   { "ds"          , "DirectSound" },
   { "dummy"       , "Dummy" },
 };
-const unsigned int rtaudio_num_api_names = 
+const unsigned int rtaudio_num_api_names =
   sizeof(rtaudio_api_names)/sizeof(rtaudio_api_names[0]);
 
 // The order here will control the order of RtAudio's API search in
@@ -473,7 +473,7 @@ double RtApi :: getStreamTime( void )
   then = stream_.lastTickTimestamp;
   return stream_.streamTime +
     ((now.tv_sec + 0.000001 * now.tv_usec) -
-     (then.tv_sec + 0.000001 * then.tv_usec));     
+     (then.tv_sec + 0.000001 * then.tv_usec));
 #else
   return stream_.streamTime;
 #endif
@@ -1903,7 +1903,7 @@ bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,
           channelsLeft -= streamChannels;
         }
       }
-      
+
       if ( stream_.doConvertBuffer[1] ) { // convert from our internal "device" buffer
         convertBuffer( stream_.userBuffer[1],
                        stream_.deviceBuffer,
@@ -2801,7 +2801,7 @@ RtApiAsio :: RtApiAsio()
   // CoInitialize beforehand, but it must be for appartment threading
   // (in which case, CoInitilialize will return S_FALSE here).
   coInitialized_ = false;
-  HRESULT hr = CoInitialize( NULL ); 
+  HRESULT hr = CoInitialize( NULL );
   if ( FAILED(hr) ) {
     errorText_ = "RtApiAsio::ASIO requires a single-threaded appartment. Call CoInitializeEx(0,COINIT_APARTMENTTHREADED)";
     error( RtAudioError::WARNING );
@@ -3252,7 +3252,7 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
     errorText_ = errorStream_.str();
     goto error;
   }
-  buffersAllocated = true;  
+  buffersAllocated = true;
   stream_.state = STREAM_STOPPED;
 
   // Set flags for buffer conversion.
@@ -3731,13 +3731,13 @@ static long asioMessages( long selector, long value, void* /*message*/, double*
 
 static const char* getAsioErrorString( ASIOError result )
 {
-  struct Messages 
+  struct Messages
   {
     ASIOError value;
     const char*message;
   };
 
-  static const Messages m[] = 
+  static const Messages m[] =
     {
       {   ASE_NotPresent,    "Hardware input or output is not present or available." },
       {   ASE_HWMalfunction,  "Hardware is malfunctioning." },
@@ -3779,7 +3779,7 @@ static const char* getAsioErrorString( ASIOError result )
 #include <audioclient.h>
 #include <avrt.h>
 #include <mmdeviceapi.h>
-#include <FunctionDiscoveryKeys_devpkey.h>
+#include <functiondiscoverykeys_devpkey.h>
 
 #ifndef MF_E_TRANSFORM_NEED_MORE_INPUT
   #define MF_E_TRANSFORM_NEED_MORE_INPUT _HRESULT_TYPEDEF_(0xc00d6d72)
@@ -3972,7 +3972,7 @@ private:
 
 // In order to satisfy WASAPI's buffer requirements, we need a means of converting sample rate
 // between HW and the user. The WasapiResampler class is used to perform this conversion between
-// HwIn->UserIn and UserOut->HwOut during the stream callback loop.
+// HwIn->UserIn and UserO ut->HwOut during the stream callback loop.
 class WasapiResampler
 {
 public:
@@ -4414,7 +4414,9 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device )
 
   hr = audioClient->GetMixFormat( &deviceFormat );
   if ( FAILED( hr ) ) {
-    errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device mix format.";
+    char error[256];
+    snprintf(error, sizeof(error), "RtApiWasapi::getDeviceInfo: Unable to retrieve device mix format (%d)", hr);
+    errorText_ = error;
     goto Exit;
   }
 
@@ -5497,7 +5499,7 @@ Exit:
 #if defined(__WINDOWS_DS__) // Windows DirectSound API
 
 // Modified by Robin Davies, October 2005
-// - Improvements to DirectX pointer chasing. 
+// - Improvements to DirectX pointer chasing.
 // - Bug fix for non-power-of-two Asio granularity used by Edirol PCR-A30.
 // - Auto-call CoInitialize for DSOUND and ASIO platforms.
 // Various revisions for RtAudio 4.0 by Gary Scavone, April 2007
@@ -5541,7 +5543,7 @@ struct DsHandle {
   void *id[2];
   void *buffer[2];
   bool xrun[2];
-  UINT bufferPointer[2];  
+  UINT bufferPointer[2];
   DWORD dsBufferSize[2];
   DWORD dsPointerLeadTime[2]; // the number of bytes ahead of the safe pointer to lead by.
   HANDLE condition;
@@ -6394,7 +6396,7 @@ void RtApiDs :: startStream()
   // Increase scheduler frequency on lesser windows (a side-effect of
   // increasing timer accuracy).  On greater windows (Win2K or later),
   // this is already in effect.
-  timeBeginPeriod( 1 ); 
+  timeBeginPeriod( 1 );
 
   buffersRolling = false;
   duplexPrerollBytes = 0;
@@ -6716,7 +6718,7 @@ void RtApiDs :: callbackEvent()
   }
 
   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
-    
+
     LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
 
     if ( handle->drainCounter > 1 ) { // write zeros to the output stream
@@ -6783,7 +6785,7 @@ void RtApiDs :: callbackEvent()
     }
 
     if ( dsPointerBetween( nextWritePointer, safeWritePointer, currentWritePointer, dsBufferSize )
-         || dsPointerBetween( endWrite, safeWritePointer, currentWritePointer, dsBufferSize ) ) { 
+         || dsPointerBetween( endWrite, safeWritePointer, currentWritePointer, dsBufferSize ) ) {
       // We've strayed into the forbidden zone ... resync the read pointer.
       handle->xrun[0] = true;
       nextWritePointer = safeWritePointer + handle->dsPointerLeadTime[0] - bufferBytes;
@@ -6857,14 +6859,14 @@ void RtApiDs :: callbackEvent()
     if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset
     DWORD endRead = nextReadPointer + bufferBytes;
 
-    // Handling depends on whether we are INPUT or DUPLEX. 
+    // Handling depends on whether we are INPUT or DUPLEX.
     // If we're in INPUT mode then waiting is a good thing. If we're in DUPLEX mode,
     // then a wait here will drag the write pointers into the forbidden zone.
-    // 
-    // In DUPLEX mode, rather than wait, we will back off the read pointer until 
-    // it's in a safe position. This causes dropouts, but it seems to be the only 
-    // practical way to sync up the read and write pointers reliably, given the 
-    // the very complex relationship between phase and increment of the read and write 
+    //
+    // In DUPLEX mode, rather than wait, we will back off the read pointer until
+    // it's in a safe position. This causes dropouts, but it seems to be the only
+    // practical way to sync up the read and write pointers reliably, given the
+    // the very complex relationship between phase and increment of the read and write
     // pointers.
     //
     // In order to minimize audible dropouts in DUPLEX mode, we will
@@ -6915,7 +6917,7 @@ void RtApiDs :: callbackEvent()
           error( RtAudioError::SYSTEM_ERROR );
           return;
         }
-      
+
         if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset
       }
     }
@@ -8147,7 +8149,7 @@ void RtApiAlsa :: stopStream()
   AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
   snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;
   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
-    if ( apiInfo->synchronized ) 
+    if ( apiInfo->synchronized )
       result = snd_pcm_drop( handle[0] );
     else
       result = snd_pcm_drain( handle[0] );
@@ -8412,8 +8414,8 @@ static void *alsaCallbackHandler( void *ptr )
 
 #ifdef SCHED_RR // Undefined with some OSes (e.g. NetBSD 1.6.x with GNU Pthread)
   if ( info->doRealtime ) {
-    std::cerr << "RtAudio alsa: " << 
-             (sched_getscheduler(0) == SCHED_RR ? "" : "_NOT_ ") << 
+    std::cerr << "RtAudio alsa: " <<
+             (sched_getscheduler(0) == SCHED_RR ? "" : "_NOT_ ") <<
              "running realtime scheduling" << std::endl;
   }
 #endif
@@ -8580,7 +8582,7 @@ RtAudio::DeviceInfo RtApiPulse::getDeviceInfo( unsigned int /*device*/ )
   mainloop_ = 0;
 
   info.outputChannels = channels_;
-  
+
   return info;
 }
 
@@ -8589,15 +8591,15 @@ static void *pulseaudio_callback( void * user )
   CallbackInfo *cbi = static_cast<CallbackInfo *>( user );
   RtApiPulse *context = static_cast<RtApiPulse *>( cbi->object );
   volatile bool *isRunning = &cbi->isRunning;
-  
+
 #ifdef SCHED_RR // Undefined with some OSes (e.g. NetBSD 1.6.x with GNU Pthread)
   if (cbi->doRealtime) {
-    std::cerr << "RtAudio pulse: " << 
-             (sched_getscheduler(0) == SCHED_RR ? "" : "_NOT_ ") << 
+    std::cerr << "RtAudio pulse: " <<
+             (sched_getscheduler(0) == SCHED_RR ? "" : "_NOT_ ") <<
              "running realtime scheduling" << std::endl;
   }
 #endif
-  
+
   while ( *isRunning ) {
     pthread_testcancel();
     context->callbackEvent();
@@ -8715,7 +8717,7 @@ void RtApiPulse::callbackEvent( void )
     else
       bytes = stream_.nUserChannels[INPUT] * stream_.bufferSize *
         formatBytes( stream_.userFormat );
-            
+
     if ( pa_simple_read( pah->s_rec, pulse_in, bytes, &pa_error ) < 0 ) {
       errorStream_ << "RtApiPulse::callbackEvent: audio read error, " <<
         pa_strerror( pa_error ) << ".";
@@ -8974,7 +8976,38 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
     }
     break;
   case OUTPUT:
-    pah->s_play = pa_simple_new( NULL, streamName.c_str(), PA_STREAM_PLAYBACK, NULL, "Playback", &ss, NULL, NULL, &error );
+    /* XXX: hard-coded for DCP-o-matic */
+    pa_channel_map map;
+    pa_channel_map_init(&map);
+    /* XXX: need to check 7.1 */
+    map.channels = channels;
+
+    if (channels > 0) {
+      map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
+    }
+    if (channels > 1) {
+      map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
+    }
+    if (channels > 2) {
+      map.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER;
+    }
+    if (channels > 3) {
+      map.map[3] = PA_CHANNEL_POSITION_LFE;
+    }
+    if (channels > 4) {
+      map.map[4] = PA_CHANNEL_POSITION_REAR_LEFT;
+    }
+    if (channels > 5) {
+      map.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT;
+    }
+    if (channels > 6) {
+      map.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
+    }
+    if (channels > 7) {
+      map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
+    }
+
+    pah->s_play = pa_simple_new( NULL, streamName.c_str(), PA_STREAM_PLAYBACK, NULL, "Playback", &ss, &map, NULL, &error );
     if ( !pah->s_play ) {
       errorText_ = "RtApiPulse::probeDeviceOpen: error connecting output to PulseAudio server.";
       goto error;
@@ -8993,7 +9026,7 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
 
   if ( !stream_.callbackInfo.isRunning ) {
     stream_.callbackInfo.object = this;
-    
+
     stream_.state = STREAM_STOPPED;
     // Set the thread attributes for joinable and realtime scheduling
     // priority (optional).  The higher priority will only take affect
@@ -9014,7 +9047,7 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
       if ( priority < min ) priority = min;
       else if ( priority > max ) priority = max;
       param.sched_priority = priority;
-      
+
       // Set the policy BEFORE the priority. Otherwise it fails.
       pthread_attr_setschedpolicy(&attr, SCHED_RR);
       pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
@@ -9043,7 +9076,7 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
   }
 
   return SUCCESS;
+
  error:
   if ( pah && stream_.callbackInfo.isRunning ) {
     pthread_cond_destroy( &pah->runnable_cv );
@@ -9635,7 +9668,7 @@ bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
       if ( priority < min ) priority = min;
       else if ( priority > max ) priority = max;
       param.sched_priority = priority;
-      
+
       // Set the policy BEFORE the priority. Otherwise it fails.
       pthread_attr_setschedpolicy(&attr, SCHED_RR);
       pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
@@ -10023,8 +10056,8 @@ static void *ossCallbackHandler( void *ptr )
 
 #ifdef SCHED_RR // Undefined with some OSes (e.g. NetBSD 1.6.x with GNU Pthread)
   if (info->doRealtime) {
-    std::cerr << "RtAudio oss: " << 
-             (sched_getscheduler(0) == SCHED_RR ? "" : "_NOT_ ") << 
+    std::cerr << "RtAudio oss: " <<
+             (sched_getscheduler(0) == SCHED_RR ? "" : "_NOT_ ") <<
              "running realtime scheduling" << std::endl;
   }
 #endif
@@ -10745,4 +10778,3 @@ void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat
   // End:
   //
   // vim: et sts=2 sw=2
-