diff options
| author | Gary Scavone <gary@music.mcgill.ca> | 2014-04-15 20:40:51 -0400 |
|---|---|---|
| committer | Gary Scavone <gary@music.mcgill.ca> | 2014-04-15 20:40:51 -0400 |
| commit | 3db24e95fea1c57cdf5bb014fc1c380668bdfe2f (patch) | |
| tree | f44dd441d8ba6fa9d22b6dd9d5f37e4ca3d655db /RtAudio.cpp | |
| parent | 4be80163cd9b85cbda79c37460ae1fc03608fd33 (diff) | |
Updates to WASAPI API to support MinGW compile.
Diffstat (limited to 'RtAudio.cpp')
| -rw-r--r-- | RtAudio.cpp | 476 |
1 files changed, 339 insertions, 137 deletions
diff --git a/RtAudio.cpp b/RtAudio.cpp index eb3eadc..dd06b52 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -38,7 +38,7 @@ */
/************************************************************************/
-// RtAudio: Version 4.1.0
+// RtAudio: Version 4.1.1pre
#include "RtAudio.h"
#include <iostream>
@@ -3578,21 +3578,16 @@ static const char* getAsioErrorString( ASIOError result ) #if defined(__WINDOWS_WASAPI__) // Windows WASAPI API
+#ifndef INITGUID
+ #define INITGUID
+#endif
#include <audioclient.h>
#include <avrt.h>
-#include <functiondiscoverykeys.h>
#include <mmdeviceapi.h>
+#include <functiondiscoverykeys_devpkey.h>
//=============================================================================
-#define EXIT_ON_ERROR( hr, errorType, errorText )\
-if ( FAILED( hr ) )\
-{\
- errorText_ = __FUNCTION__ ": " errorText;\
- error( errorType );\
- goto Exit;\
-}
-
#define SAFE_RELEASE( objectPtr )\
if ( objectPtr )\
{\
@@ -3783,7 +3778,7 @@ void convertBufferWasapi( char* outBuffer, float sampleRatio = ( float ) outSampleRate / inSampleRate;
float sampleStep = 1.0f / sampleRatio;
float inSampleFraction = 0.0f;
- unsigned int commonChannelCount = min( inChannelCount, outChannelCount );
+ unsigned int commonChannelCount = std::min( inChannelCount, outChannelCount );
outSampleCount = ( unsigned int ) ( inSampleCount * sampleRatio );
@@ -3851,7 +3846,7 @@ RtApiWasapi::RtApiWasapi() if ( !FAILED( hr ) )
coInitialized_ = true;
- // instantiate device enumerator
+ // Instantiate device enumerator
hr = CoCreateInstance( __uuidof( MMDeviceEnumerator ), NULL,
CLSCTX_ALL, __uuidof( IMMDeviceEnumerator ),
( void** ) &deviceEnumerator_ );
@@ -3888,26 +3883,43 @@ unsigned int RtApiWasapi::getDeviceCount( void ) IMMDeviceCollection* captureDevices = NULL;
IMMDeviceCollection* renderDevices = NULL;
- // count capture devices
+ // Count capture devices
+ errorText_.clear();
HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture device collection" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device collection.";
+ goto Exit;
+ }
hr = captureDevices->GetCount( &captureDeviceCount );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture device count" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device count.";
+ goto Exit;
+ }
- // count render devices
+ // Count render devices
hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render device collection" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device collection.";
+ goto Exit;
+ }
hr = renderDevices->GetCount( &renderDeviceCount );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render device count" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device count.";
+ goto Exit;
+ }
Exit:
// release all references
SAFE_RELEASE( captureDevices );
SAFE_RELEASE( renderDevices );
- return captureDeviceCount + renderDeviceCount;
+ if ( errorText_.empty() )
+ return captureDeviceCount + renderDeviceCount;
+
+ error( RtAudioError::DRIVER_ERROR );
+ return 0;
}
//-----------------------------------------------------------------------------
@@ -3938,67 +3950,105 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device ) // probed
info.probed = false;
- // count capture devices
+ // Count capture devices
+ errorText_.clear();
+ RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;
HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture device collection" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device collection.";
+ goto Exit;
+ }
hr = captureDevices->GetCount( &captureDeviceCount );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture device count" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device count.";
+ goto Exit;
+ }
- // count render devices
+ // Count render devices
hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render device collection" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device collection.";
+ goto Exit;
+ }
hr = renderDevices->GetCount( &renderDeviceCount );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render device count" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device count.";
+ goto Exit;
+ }
// validate device index
- if ( device >= captureDeviceCount + renderDeviceCount )
- EXIT_ON_ERROR( -1, RtAudioError::INVALID_USE, "Invalid device index" );
+ if ( device >= captureDeviceCount + renderDeviceCount ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Invalid device index.";
+ errorType = RtAudioError::INVALID_USE;
+ goto Exit;
+ }
// determine whether index falls within capture or render devices
if ( device >= renderDeviceCount ) {
hr = captureDevices->Item( device - renderDeviceCount, &devicePtr );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture device handle" );
-
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device handle.";
+ goto Exit;
+ }
isCaptureDevice = true;
}
else {
hr = renderDevices->Item( device, &devicePtr );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render device handle" );
-
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device handle.";
+ goto Exit;
+ }
isCaptureDevice = false;
}
// get default device name
if ( isCaptureDevice ) {
hr = deviceEnumerator_->GetDefaultAudioEndpoint( eCapture, eConsole, &defaultDevicePtr );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve default render device handle" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default capture device handle.";
+ goto Exit;
+ }
}
else {
hr = deviceEnumerator_->GetDefaultAudioEndpoint( eRender, eConsole, &defaultDevicePtr );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve default capture device handle" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default render device handle.";
+ goto Exit;
+ }
}
hr = defaultDevicePtr->OpenPropertyStore( STGM_READ, &defaultDevicePropStore );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to open default device property store" );
-
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open default device property store.";
+ goto Exit;
+ }
PropVariantInit( &defaultDeviceNameProp );
hr = defaultDevicePropStore->GetValue( PKEY_Device_FriendlyName, &defaultDeviceNameProp );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve default device property: PKEY_Device_FriendlyName" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default device property: PKEY_Device_FriendlyName.";
+ goto Exit;
+ }
deviceName = defaultDeviceNameProp.pwszVal;
defaultDeviceName = std::string( deviceName.begin(), deviceName.end() );
// name
hr = devicePtr->OpenPropertyStore( STGM_READ, &devicePropStore );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to open device property store" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open device property store.";
+ goto Exit;
+ }
PropVariantInit( &deviceNameProp );
hr = devicePropStore->GetValue( PKEY_Device_FriendlyName, &deviceNameProp );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve device property: PKEY_Device_FriendlyName" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device property: PKEY_Device_FriendlyName.";
+ goto Exit;
+ }
deviceName = deviceNameProp.pwszVal;
info.name = std::string( deviceName.begin(), deviceName.end() );
@@ -4015,10 +4065,16 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device ) // channel count
hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL, NULL, ( void** ) &audioClient );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve device audio client" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device audio client.";
+ goto Exit;
+ }
hr = audioClient->GetMixFormat( &deviceFormat );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve device mix format" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device mix format.";
+ goto Exit;
+ }
if ( isCaptureDevice ) {
info.inputChannels = deviceFormat->nChannels;
@@ -4099,6 +4155,8 @@ Exit: CoTaskMemFree( deviceFormat );
CoTaskMemFree( closestMatchFormat );
+ if ( !errorText_.empty() )
+ error( errorType );
return info;
}
@@ -4133,7 +4191,7 @@ unsigned int RtApiWasapi::getDefaultInputDevice( void ) void RtApiWasapi::closeStream( void )
{
if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiWasapi::closeStream: No open stream to close";
+ errorText_ = "RtApiWasapi::closeStream: No open stream to close.";
error( RtAudioError::WARNING );
return;
}
@@ -4154,7 +4212,7 @@ void RtApiWasapi::closeStream( void ) if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent )
CloseHandle( ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent );
- delete stream_.apiHandle;
+ delete ( WasapiHandle* ) stream_.apiHandle;
stream_.apiHandle = NULL;
for ( int i = 0; i < 2; i++ ) {
@@ -4180,7 +4238,7 @@ void RtApiWasapi::startStream( void ) verifyStream();
if ( stream_.state == STREAM_RUNNING ) {
- errorText_ = "RtApiWasapi::startStream: The stream is already running";
+ errorText_ = "RtApiWasapi::startStream: The stream is already running.";
error( RtAudioError::WARNING );
return;
}
@@ -4189,10 +4247,10 @@ void RtApiWasapi::startStream( void ) stream_.state = STREAM_RUNNING;
// create WASAPI stream thread
- stream_.callbackInfo.thread = ( unsigned int ) CreateThread( NULL, 0, runWasapiThread, this, CREATE_SUSPENDED, NULL );
+ stream_.callbackInfo.thread = ( ThreadHandle ) CreateThread( NULL, 0, runWasapiThread, this, CREATE_SUSPENDED, NULL );
if ( !stream_.callbackInfo.thread ) {
- errorText_ = "RtApiWasapi::startStream: Unable to instantiate callback thread";
+ errorText_ = "RtApiWasapi::startStream: Unable to instantiate callback thread.";
error( RtAudioError::THREAD_ERROR );
}
else {
@@ -4208,7 +4266,7 @@ void RtApiWasapi::stopStream( void ) verifyStream();
if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiWasapi::stopStream: The stream is already stopped";
+ errorText_ = "RtApiWasapi::stopStream: The stream is already stopped.";
error( RtAudioError::WARNING );
return;
}
@@ -4228,8 +4286,9 @@ void RtApiWasapi::stopStream( void ) if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) {
HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop();
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::stopStream: Unable to stop capture stream";
+ errorText_ = "RtApiWasapi::stopStream: Unable to stop capture stream.";
error( RtAudioError::DRIVER_ERROR );
+ return;
}
}
@@ -4237,18 +4296,20 @@ void RtApiWasapi::stopStream( void ) if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) {
HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop();
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::stopStream: Unable to stop render stream";
+ errorText_ = "RtApiWasapi::stopStream: Unable to stop render stream.";
error( RtAudioError::DRIVER_ERROR );
+ return;
}
}
// close thread handle
if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) {
- errorText_ = "RtApiWasapi::stopStream: Unable to close callback thread";
+ errorText_ = "RtApiWasapi::stopStream: Unable to close callback thread.";
error( RtAudioError::THREAD_ERROR );
+ return;
}
- stream_.callbackInfo.thread = NULL;
+ stream_.callbackInfo.thread = (ThreadHandle) NULL;
}
//-----------------------------------------------------------------------------
@@ -4258,7 +4319,7 @@ void RtApiWasapi::abortStream( void ) verifyStream();
if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiWasapi::abortStream: The stream is already stopped";
+ errorText_ = "RtApiWasapi::abortStream: The stream is already stopped.";
error( RtAudioError::WARNING );
return;
}
@@ -4275,8 +4336,9 @@ void RtApiWasapi::abortStream( void ) if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) {
HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop();
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::stopStream: Unable to stop capture stream";
+ errorText_ = "RtApiWasapi::abortStream: Unable to stop capture stream.";
error( RtAudioError::DRIVER_ERROR );
+ return;
}
}
@@ -4284,18 +4346,20 @@ void RtApiWasapi::abortStream( void ) if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) {
HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop();
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::stopStream: Unable to stop render stream";
+ errorText_ = "RtApiWasapi::abortStream: Unable to stop render stream.";
error( RtAudioError::DRIVER_ERROR );
+ return;
}
}
// close thread handle
if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) {
- errorText_ = "RtApiWasapi::stopStream: Unable to close callback thread";
+ errorText_ = "RtApiWasapi::abortStream: Unable to close callback thread.";
error( RtAudioError::THREAD_ERROR );
+ return;
}
- stream_.callbackInfo.thread = NULL;
+ stream_.callbackInfo.thread = (ThreadHandle) NULL;
}
//-----------------------------------------------------------------------------
@@ -4313,66 +4377,109 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigne IMMDeviceCollection* renderDevices = NULL;
IMMDevice* devicePtr = NULL;
WAVEFORMATEX* deviceFormat = NULL;
+ unsigned int bufferBytes;
+ stream_.state = STREAM_STOPPED;
// create API Handle if not already created
if ( !stream_.apiHandle )
stream_.apiHandle = ( void* ) new WasapiHandle();
- // count capture devices
+ // Count capture devices
+ errorText_.clear();
+ RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;
HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture device collection" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device collection.";
+ goto Exit;
+ }
hr = captureDevices->GetCount( &captureDeviceCount );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture device count" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device count.";
+ goto Exit;
+ }
- // count render devices
+ // Count render devices
hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render device collection" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device collection.";
+ goto Exit;
+ }
hr = renderDevices->GetCount( &renderDeviceCount );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render device count" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device count.";
+ goto Exit;
+ }
// validate device index
- if ( device >= captureDeviceCount + renderDeviceCount )
- EXIT_ON_ERROR( -1, RtAudioError::INVALID_USE, "Invalid device index" );
+ if ( device >= captureDeviceCount + renderDeviceCount ) {
+ errorType = RtAudioError::INVALID_USE;
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Invalid device index.";
+ goto Exit;
+ }
// determine whether index falls within capture or render devices
if ( device >= renderDeviceCount ) {
- if ( mode != INPUT )
- EXIT_ON_ERROR( -1, RtAudioError::INVALID_USE, "Capture device selected as output device" );
+ if ( mode != INPUT ) {
+ errorType = RtAudioError::INVALID_USE;
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Capture device selected as output device.";
+ goto Exit;
+ }
// retrieve captureAudioClient from devicePtr
IAudioClient*& captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient;
hr = captureDevices->Item( device - renderDeviceCount, &devicePtr );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture device handle" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device handle.";
+ goto Exit;
+ }
hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,
NULL, ( void** ) &captureAudioClient );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve device audio client" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";
+ goto Exit;
+ }
hr = captureAudioClient->GetMixFormat( &deviceFormat );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve device mix format" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";
+ goto Exit;
+ }
stream_.nDeviceChannels[mode] = deviceFormat->nChannels;
captureAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );
}
else {
- if ( mode != OUTPUT )
- EXIT_ON_ERROR( -1, RtAudioError::INVALID_USE, "Render device selected as input device" );
+ if ( mode != OUTPUT ) {
+ errorType = RtAudioError::INVALID_USE;
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Render device selected as input device.";
+ goto Exit;
+ }
// retrieve renderAudioClient from devicePtr
IAudioClient*& renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;
hr = renderDevices->Item( device, &devicePtr );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render device handle" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device handle.";
+ goto Exit;
+ }
hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,
NULL, ( void** ) &renderAudioClient );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve device audio client" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";
+ goto Exit;
+ }
hr = renderAudioClient->GetMixFormat( &deviceFormat );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve device mix format" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";
+ goto Exit;
+ }
stream_.nDeviceChannels[mode] = deviceFormat->nChannels;
renderAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );
@@ -4388,7 +4495,6 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigne }
stream_.device[mode] = device;
- stream_.state = STREAM_STOPPED;
stream_.doByteSwap[mode] = false;
stream_.sampleRate = sampleRate;
stream_.bufferSize = *bufferSize;
@@ -4416,11 +4522,14 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigne setConvertInfo( mode, 0 );
// Allocate necessary internal buffers
- unsigned int bufferBytes = stream_.nUserChannels[mode] * stream_.bufferSize * formatBytes( stream_.userFormat );
+ bufferBytes = stream_.nUserChannels[mode] * stream_.bufferSize * formatBytes( stream_.userFormat );
stream_.userBuffer[mode] = ( char* ) calloc( bufferBytes, 1 );
- if ( !stream_.userBuffer[mode] )
- EXIT_ON_ERROR( -1, RtAudioError::MEMORY_ERROR, "Error allocating user buffer memory" );
+ if ( !stream_.userBuffer[mode] ) {
+ errorType = RtAudioError::MEMORY_ERROR;
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Error allocating user buffer memory.";
+ goto Exit;
+ }
if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME )
stream_.callbackInfo.priority = 15;
@@ -4434,17 +4543,17 @@ bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigne Exit:
//clean up
-
SAFE_RELEASE( captureDevices );
SAFE_RELEASE( renderDevices );
SAFE_RELEASE( devicePtr );
-
CoTaskMemFree( deviceFormat );
// if method failed, close the stream
if ( methodResult == FAILURE )
closeStream();
+ if ( !errorText_.empty() )
+ error( errorType );
return methodResult;
}
@@ -4497,6 +4606,25 @@ void RtApiWasapi::wasapiThread() WasapiBuffer captureBuffer;
WasapiBuffer renderBuffer;
+ // declare local stream variables
+ RtAudioCallback callback = ( RtAudioCallback ) stream_.callbackInfo.callback;
+ BYTE* streamBuffer = NULL;
+ unsigned long captureFlags = 0;
+ unsigned int bufferFrameCount = 0;
+ unsigned int numFramesPadding = 0;
+ unsigned int convBufferSize = 0;
+ bool callbackPushed = false;
+ bool callbackPulled = false;
+ bool callbackStopped = false;
+ int callbackResult = 0;
+
+ // convBuffer is used to store converted buffers between WASAPI and the user
+ char* convBuffer = NULL;
+ unsigned int deviceBufferSize = 0;
+
+ errorText_.clear();
+ RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;
+
// Attempt to assign "Pro Audio" characteristic to thread
HMODULE AvrtDll = LoadLibrary( "AVRT.dll" );
if ( AvrtDll ) {
@@ -4509,7 +4637,10 @@ void RtApiWasapi::wasapiThread() // start capture stream if applicable
if ( captureAudioClient ) {
hr = captureAudioClient->GetMixFormat( &captureFormat );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve device mix format" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";
+ goto Exit;
+ }
captureSrRatio = ( ( float ) captureFormat->nSamplesPerSec / stream_.sampleRate );
@@ -4524,19 +4655,31 @@ void RtApiWasapi::wasapiThread() desiredBufferPeriod,
captureFormat,
NULL );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to initialize capture audio client" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize capture audio client.";
+ goto Exit;
+ }
hr = captureAudioClient->GetService( __uuidof( IAudioCaptureClient ),
( void** ) &captureClient );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture client handle" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture client handle.";
+ goto Exit;
+ }
// configure captureEvent to trigger on every available capture buffer
captureEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- if ( !captureEvent )
- EXIT_ON_ERROR( -1, RtAudioError::SYSTEM_ERROR, "Unable to create capture event" );
+ if ( !captureEvent ) {
+ errorType = RtAudioError::SYSTEM_ERROR;
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to create capture event.";
+ goto Exit;
+ }
hr = captureAudioClient->SetEventHandle( captureEvent );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to set capture event handle" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to set capture event handle.";
+ goto Exit;
+ }
( ( WasapiHandle* ) stream_.apiHandle )->captureClient = captureClient;
( ( WasapiHandle* ) stream_.apiHandle )->captureEvent = captureEvent;
@@ -4544,7 +4687,10 @@ void RtApiWasapi::wasapiThread() unsigned int inBufferSize = 0;
hr = captureAudioClient->GetBufferSize( &inBufferSize );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to get capture buffer size" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to get capture buffer size.";
+ goto Exit;
+ }
// scale outBufferSize according to stream->user sample rate ratio
unsigned int outBufferSize = ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT];
@@ -4555,17 +4701,26 @@ void RtApiWasapi::wasapiThread() // reset the capture stream
hr = captureAudioClient->Reset();
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to reset capture stream" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to reset capture stream.";
+ goto Exit;
+ }
// start the capture stream
hr = captureAudioClient->Start();
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to start capture stream" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to start capture stream.";
+ goto Exit;
+ }
}
// start render stream if applicable
if ( renderAudioClient ) {
hr = renderAudioClient->GetMixFormat( &renderFormat );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve device mix format" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";
+ goto Exit;
+ }
renderSrRatio = ( ( float ) renderFormat->nSamplesPerSec / stream_.sampleRate );
@@ -4580,19 +4735,31 @@ void RtApiWasapi::wasapiThread() desiredBufferPeriod,
renderFormat,
NULL );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to initialize render audio client" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize render audio client.";
+ goto Exit;
+ }
hr = renderAudioClient->GetService( __uuidof( IAudioRenderClient ),
( void** ) &renderClient );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render client handle" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render client handle.";
+ goto Exit;
+ }
// configure renderEvent to trigger on every available render buffer
renderEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- if ( !renderEvent )
- EXIT_ON_ERROR( -1, RtAudioError::SYSTEM_ERROR, "Unable to create render event" );
+ if ( !renderEvent ) {
+ errorType = RtAudioError::SYSTEM_ERROR;
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to create render event.";
+ goto Exit;
+ }
hr = renderAudioClient->SetEventHandle( renderEvent );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to set render event handle" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to set render event handle.";
+ goto Exit;
+ }
( ( WasapiHandle* ) stream_.apiHandle )->renderClient = renderClient;
( ( WasapiHandle* ) stream_.apiHandle )->renderEvent = renderEvent;
@@ -4600,7 +4767,10 @@ void RtApiWasapi::wasapiThread() unsigned int outBufferSize = 0;
hr = renderAudioClient->GetBufferSize( &outBufferSize );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to get render buffer size" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to get render buffer size.";
+ goto Exit;
+ }
// scale inBufferSize according to user->stream sample rate ratio
unsigned int inBufferSize = ( unsigned int ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT];
@@ -4611,31 +4781,19 @@ void RtApiWasapi::wasapiThread() // reset the render stream
hr = renderAudioClient->Reset();
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to reset render stream" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to reset render stream.";
+ goto Exit;
+ }
// start the render stream
hr = renderAudioClient->Start();
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to start render stream" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to start render stream.";
+ goto Exit;
+ }
}
- // declare local stream variables
- RtAudioCallback callback = ( RtAudioCallback ) stream_.callbackInfo.callback;
-
- BYTE* streamBuffer = NULL;
- unsigned long captureFlags = 0;
-
- unsigned int bufferFrameCount = 0;
- unsigned int numFramesPadding = 0;
- unsigned int convBufferSize = 0;
-
- bool callbackPushed = false;
- bool callbackPulled = false;
- bool callbackStopped = false;
-
- int callbackResult = 0;
-
- // convBuffer is used to store converted buffers between WASAPI and the user
- unsigned int deviceBufferSize = 0;
if ( stream_.mode == INPUT ) {
deviceBufferSize = ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] );
}
@@ -4643,14 +4801,17 @@ void RtApiWasapi::wasapiThread() deviceBufferSize = ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] );
}
else if ( stream_.mode == DUPLEX ) {
- deviceBufferSize = max( ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),
+ deviceBufferSize = std::max( ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),
( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) );
}
- char* convBuffer = ( char* ) malloc( deviceBufferSize );
+ convBuffer = ( char* ) malloc( deviceBufferSize );
stream_.deviceBuffer = ( char* ) malloc( deviceBufferSize );
- if ( !convBuffer || !stream_.deviceBuffer )
- EXIT_ON_ERROR( -1, RtAudioError::MEMORY_ERROR, "Error allocating device buffer memory" );
+ if ( !convBuffer || !stream_.deviceBuffer ) {
+ errorType = RtAudioError::MEMORY_ERROR;
+ errorText_ = "RtApiWasapi::wasapiThread: Error allocating device buffer memory.";
+ goto Exit;
+ }
// stream process loop
while ( stream_.state != STREAM_STOPPING ) {
@@ -4716,26 +4877,32 @@ void RtApiWasapi::wasapiThread() // Handle return value from callback
if ( callbackResult == 1 ) {
// instantiate a thread to stop this thread
- HANDLE threadHandle = CreateThread( NULL, 0, stopWasapiThread, this, NULL, NULL );
-
+ HANDLE threadHandle = CreateThread( NULL, 0, stopWasapiThread, this, 0, NULL );
if ( !threadHandle ) {
- EXIT_ON_ERROR( -1, RtAudioError::THREAD_ERROR, "Unable to instantiate stream stop thread" );
+ errorType = RtAudioError::THREAD_ERROR;
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream stop thread.";
+ goto Exit;
}
else if ( !CloseHandle( threadHandle ) ) {
- EXIT_ON_ERROR( -1, RtAudioError::THREAD_ERROR, "Unable to close stream stop thread handle" );
+ errorType = RtAudioError::THREAD_ERROR;
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream stop thread handle.";
+ goto Exit;
}
callbackStopped = true;
}
else if ( callbackResult == 2 ) {
// instantiate a thread to stop this thread
- HANDLE threadHandle = CreateThread( NULL, 0, abortWasapiThread, this, NULL, NULL );
-
+ HANDLE threadHandle = CreateThread( NULL, 0, abortWasapiThread, this, 0, NULL );
if ( !threadHandle ) {
- EXIT_ON_ERROR( -1, RtAudioError::THREAD_ERROR, "Unable to instantiate stream abort thread" );
+ errorType = RtAudioError::THREAD_ERROR;
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream abort thread.";
+ goto Exit;
}
else if ( !CloseHandle( threadHandle ) ) {
- EXIT_ON_ERROR( -1, RtAudioError::THREAD_ERROR, "Unable to close stream abort thread handle" );
+ errorType = RtAudioError::THREAD_ERROR;
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream abort thread handle.";
+ goto Exit;
}
callbackStopped = true;
@@ -4802,7 +4969,10 @@ void RtApiWasapi::wasapiThread() hr = captureClient->GetBuffer( &streamBuffer,
&bufferFrameCount,
&captureFlags, NULL, NULL );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture buffer" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture buffer.";
+ goto Exit;
+ }
if ( bufferFrameCount != 0 ) {
// Push capture buffer into inputBuffer
@@ -4812,20 +4982,29 @@ void RtApiWasapi::wasapiThread() {
// Release capture buffer
hr = captureClient->ReleaseBuffer( bufferFrameCount );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to release capture buffer" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
+ goto Exit;
+ }
}
else
{
// Inform WASAPI that capture was unsuccessful
hr = captureClient->ReleaseBuffer( 0 );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to release capture buffer" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
+ goto Exit;
+ }
}
}
else
{
// Inform WASAPI that capture was unsuccessful
hr = captureClient->ReleaseBuffer( 0 );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to release capture buffer" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
+ goto Exit;
+ }
}
}
@@ -4844,16 +5023,25 @@ void RtApiWasapi::wasapiThread() // Get render buffer from stream
hr = renderAudioClient->GetBufferSize( &bufferFrameCount );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render buffer size" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer size.";
+ goto Exit;
+ }
hr = renderAudioClient->GetCurrentPadding( &numFramesPadding );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render buffer padding" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer padding.";
+ goto Exit;
+ }
bufferFrameCount -= numFramesPadding;
if ( bufferFrameCount != 0 ) {
hr = renderClient->GetBuffer( bufferFrameCount, &streamBuffer );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render buffer" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer.";
+ goto Exit;
+ }
// Pull next buffer from outputBuffer
// Fill render buffer with next buffer
@@ -4863,20 +5051,29 @@ void RtApiWasapi::wasapiThread() {
// Release render buffer
hr = renderClient->ReleaseBuffer( bufferFrameCount, 0 );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to release render buffer" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
+ goto Exit;
+ }
}
else
{
// Inform WASAPI that render was unsuccessful
hr = renderClient->ReleaseBuffer( 0, 0 );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to release render buffer" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
+ goto Exit;
+ }
}
}
else
{
// Inform WASAPI that render was unsuccessful
hr = renderClient->ReleaseBuffer( 0, 0 );
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to release render buffer" );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
+ goto Exit;
+ }
}
}
@@ -4901,6 +5098,11 @@ Exit: // update stream state
stream_.state = STREAM_STOPPED;
+
+ if ( errorText_.empty() )
+ return;
+ else
+ error( errorType );
}
//******************** End of __WINDOWS_WASAPI__ *********************//
|
