*/\r
/************************************************************************/\r
\r
-// RtAudio: Version 4.1.0\r
+// RtAudio: Version 4.1.1pre\r
\r
#include "RtAudio.h"\r
#include <iostream>\r
\r
#if defined(__WINDOWS_WASAPI__) // Windows WASAPI API\r
\r
+#ifndef INITGUID\r
+ #define INITGUID\r
+#endif\r
#include <audioclient.h>\r
#include <avrt.h>\r
-#include <functiondiscoverykeys.h>\r
#include <mmdeviceapi.h>\r
+#include <functiondiscoverykeys_devpkey.h>\r
\r
//=============================================================================\r
\r
-#define EXIT_ON_ERROR( hr, errorType, errorText )\\r
-if ( FAILED( hr ) )\\r
-{\\r
- errorText_ = __FUNCTION__ ": " errorText;\\r
- error( errorType );\\r
- goto Exit;\\r
-}\r
-\r
#define SAFE_RELEASE( objectPtr )\\r
if ( objectPtr )\\r
{\\r
float sampleRatio = ( float ) outSampleRate / inSampleRate;\r
float sampleStep = 1.0f / sampleRatio;\r
float inSampleFraction = 0.0f;\r
- unsigned int commonChannelCount = min( inChannelCount, outChannelCount );\r
+ unsigned int commonChannelCount = std::min( inChannelCount, outChannelCount );\r
\r
outSampleCount = ( unsigned int ) ( inSampleCount * sampleRatio );\r
\r
if ( !FAILED( hr ) )\r
coInitialized_ = true;\r
\r
- // instantiate device enumerator\r
+ // Instantiate device enumerator\r
hr = CoCreateInstance( __uuidof( MMDeviceEnumerator ), NULL,\r
CLSCTX_ALL, __uuidof( IMMDeviceEnumerator ),\r
( void** ) &deviceEnumerator_ );\r
IMMDeviceCollection* captureDevices = NULL;\r
IMMDeviceCollection* renderDevices = NULL;\r
\r
- // count capture devices\r
+ // Count capture devices\r
+ errorText_.clear();\r
HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture device collection" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device collection.";\r
+ goto Exit;\r
+ }\r
\r
hr = captureDevices->GetCount( &captureDeviceCount );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture device count" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device count.";\r
+ goto Exit;\r
+ }\r
\r
- // count render devices\r
+ // Count render devices\r
hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render device collection" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device collection.";\r
+ goto Exit;\r
+ }\r
\r
hr = renderDevices->GetCount( &renderDeviceCount );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render device count" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device count.";\r
+ goto Exit;\r
+ }\r
\r
Exit:\r
// release all references\r
SAFE_RELEASE( captureDevices );\r
SAFE_RELEASE( renderDevices );\r
\r
- return captureDeviceCount + renderDeviceCount;\r
+ if ( errorText_.empty() )\r
+ return captureDeviceCount + renderDeviceCount;\r
+\r
+ error( RtAudioError::DRIVER_ERROR );\r
+ return 0;\r
}\r
\r
//-----------------------------------------------------------------------------\r
// probed\r
info.probed = false;\r
\r
- // count capture devices\r
+ // Count capture devices\r
+ errorText_.clear();\r
+ RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;\r
HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture device collection" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device collection.";\r
+ goto Exit;\r
+ }\r
\r
hr = captureDevices->GetCount( &captureDeviceCount );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture device count" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device count.";\r
+ goto Exit;\r
+ }\r
\r
- // count render devices\r
+ // Count render devices\r
hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render device collection" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device collection.";\r
+ goto Exit;\r
+ }\r
\r
hr = renderDevices->GetCount( &renderDeviceCount );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render device count" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device count.";\r
+ goto Exit;\r
+ }\r
\r
// validate device index\r
- if ( device >= captureDeviceCount + renderDeviceCount )\r
- EXIT_ON_ERROR( -1, RtAudioError::INVALID_USE, "Invalid device index" );\r
+ if ( device >= captureDeviceCount + renderDeviceCount ) {\r
+ errorText_ = "RtApiWasapi::getDeviceInfo: Invalid device index.";\r
+ errorType = RtAudioError::INVALID_USE;\r
+ goto Exit;\r
+ }\r
\r
// determine whether index falls within capture or render devices\r
if ( device >= renderDeviceCount ) {\r
hr = captureDevices->Item( device - renderDeviceCount, &devicePtr );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture device handle" );\r
-\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device handle.";\r
+ goto Exit;\r
+ }\r
isCaptureDevice = true;\r
}\r
else {\r
hr = renderDevices->Item( device, &devicePtr );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render device handle" );\r
-\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device handle.";\r
+ goto Exit;\r
+ }\r
isCaptureDevice = false;\r
}\r
\r
// get default device name\r
if ( isCaptureDevice ) {\r
hr = deviceEnumerator_->GetDefaultAudioEndpoint( eCapture, eConsole, &defaultDevicePtr );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve default render device handle" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default capture device handle.";\r
+ goto Exit;\r
+ }\r
}\r
else {\r
hr = deviceEnumerator_->GetDefaultAudioEndpoint( eRender, eConsole, &defaultDevicePtr );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve default capture device handle" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default render device handle.";\r
+ goto Exit;\r
+ }\r
}\r
\r
hr = defaultDevicePtr->OpenPropertyStore( STGM_READ, &defaultDevicePropStore );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to open default device property store" );\r
-\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open default device property store.";\r
+ goto Exit;\r
+ }\r
PropVariantInit( &defaultDeviceNameProp );\r
\r
hr = defaultDevicePropStore->GetValue( PKEY_Device_FriendlyName, &defaultDeviceNameProp );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve default device property: PKEY_Device_FriendlyName" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default device property: PKEY_Device_FriendlyName.";\r
+ goto Exit;\r
+ }\r
\r
deviceName = defaultDeviceNameProp.pwszVal;\r
defaultDeviceName = std::string( deviceName.begin(), deviceName.end() );\r
\r
// name\r
hr = devicePtr->OpenPropertyStore( STGM_READ, &devicePropStore );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to open device property store" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open device property store.";\r
+ goto Exit;\r
+ }\r
\r
PropVariantInit( &deviceNameProp );\r
\r
hr = devicePropStore->GetValue( PKEY_Device_FriendlyName, &deviceNameProp );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve device property: PKEY_Device_FriendlyName" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device property: PKEY_Device_FriendlyName.";\r
+ goto Exit;\r
+ }\r
\r
deviceName = deviceNameProp.pwszVal;\r
info.name = std::string( deviceName.begin(), deviceName.end() );\r
\r
// channel count\r
hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL, NULL, ( void** ) &audioClient );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve device audio client" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device audio client.";\r
+ goto Exit;\r
+ }\r
\r
hr = audioClient->GetMixFormat( &deviceFormat );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve device mix format" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device mix format.";\r
+ goto Exit;\r
+ }\r
\r
if ( isCaptureDevice ) {\r
info.inputChannels = deviceFormat->nChannels;\r
CoTaskMemFree( deviceFormat );\r
CoTaskMemFree( closestMatchFormat );\r
\r
+ if ( !errorText_.empty() )\r
+ error( errorType );\r
return info;\r
}\r
\r
void RtApiWasapi::closeStream( void )\r
{\r
if ( stream_.state == STREAM_CLOSED ) {\r
- errorText_ = "RtApiWasapi::closeStream: No open stream to close";\r
+ errorText_ = "RtApiWasapi::closeStream: No open stream to close.";\r
error( RtAudioError::WARNING );\r
return;\r
}\r
if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent )\r
CloseHandle( ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent );\r
\r
- delete stream_.apiHandle;\r
+ delete ( WasapiHandle* ) stream_.apiHandle;\r
stream_.apiHandle = NULL;\r
\r
for ( int i = 0; i < 2; i++ ) {\r
verifyStream();\r
\r
if ( stream_.state == STREAM_RUNNING ) {\r
- errorText_ = "RtApiWasapi::startStream: The stream is already running";\r
+ errorText_ = "RtApiWasapi::startStream: The stream is already running.";\r
error( RtAudioError::WARNING );\r
return;\r
}\r
stream_.state = STREAM_RUNNING;\r
\r
// create WASAPI stream thread\r
- stream_.callbackInfo.thread = ( unsigned int ) CreateThread( NULL, 0, runWasapiThread, this, CREATE_SUSPENDED, NULL );\r
+ stream_.callbackInfo.thread = ( ThreadHandle ) CreateThread( NULL, 0, runWasapiThread, this, CREATE_SUSPENDED, NULL );\r
\r
if ( !stream_.callbackInfo.thread ) {\r
- errorText_ = "RtApiWasapi::startStream: Unable to instantiate callback thread";\r
+ errorText_ = "RtApiWasapi::startStream: Unable to instantiate callback thread.";\r
error( RtAudioError::THREAD_ERROR );\r
}\r
else {\r
verifyStream();\r
\r
if ( stream_.state == STREAM_STOPPED ) {\r
- errorText_ = "RtApiWasapi::stopStream: The stream is already stopped";\r
+ errorText_ = "RtApiWasapi::stopStream: The stream is already stopped.";\r
error( RtAudioError::WARNING );\r
return;\r
}\r
if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) {\r
HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop();\r
if ( FAILED( hr ) ) {\r
- errorText_ = "RtApiWasapi::stopStream: Unable to stop capture stream";\r
+ errorText_ = "RtApiWasapi::stopStream: Unable to stop capture stream.";\r
error( RtAudioError::DRIVER_ERROR );\r
+ return;\r
}\r
}\r
\r
if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) {\r
HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop();\r
if ( FAILED( hr ) ) {\r
- errorText_ = "RtApiWasapi::stopStream: Unable to stop render stream";\r
+ errorText_ = "RtApiWasapi::stopStream: Unable to stop render stream.";\r
error( RtAudioError::DRIVER_ERROR );\r
+ return;\r
}\r
}\r
\r
// close thread handle\r
if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) {\r
- errorText_ = "RtApiWasapi::stopStream: Unable to close callback thread";\r
+ errorText_ = "RtApiWasapi::stopStream: Unable to close callback thread.";\r
error( RtAudioError::THREAD_ERROR );\r
+ return;\r
}\r
\r
- stream_.callbackInfo.thread = NULL;\r
+ stream_.callbackInfo.thread = (ThreadHandle) NULL;\r
}\r
\r
//-----------------------------------------------------------------------------\r
verifyStream();\r
\r
if ( stream_.state == STREAM_STOPPED ) {\r
- errorText_ = "RtApiWasapi::abortStream: The stream is already stopped";\r
+ errorText_ = "RtApiWasapi::abortStream: The stream is already stopped.";\r
error( RtAudioError::WARNING );\r
return;\r
}\r
if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) {\r
HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop();\r
if ( FAILED( hr ) ) {\r
- errorText_ = "RtApiWasapi::stopStream: Unable to stop capture stream";\r
+ errorText_ = "RtApiWasapi::abortStream: Unable to stop capture stream.";\r
error( RtAudioError::DRIVER_ERROR );\r
+ return;\r
}\r
}\r
\r
if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) {\r
HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop();\r
if ( FAILED( hr ) ) {\r
- errorText_ = "RtApiWasapi::stopStream: Unable to stop render stream";\r
+ errorText_ = "RtApiWasapi::abortStream: Unable to stop render stream.";\r
error( RtAudioError::DRIVER_ERROR );\r
+ return;\r
}\r
}\r
\r
// close thread handle\r
if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) {\r
- errorText_ = "RtApiWasapi::stopStream: Unable to close callback thread";\r
+ errorText_ = "RtApiWasapi::abortStream: Unable to close callback thread.";\r
error( RtAudioError::THREAD_ERROR );\r
+ return;\r
}\r
\r
- stream_.callbackInfo.thread = NULL;\r
+ stream_.callbackInfo.thread = (ThreadHandle) NULL;\r
}\r
\r
//-----------------------------------------------------------------------------\r
IMMDeviceCollection* renderDevices = NULL;\r
IMMDevice* devicePtr = NULL;\r
WAVEFORMATEX* deviceFormat = NULL;\r
+ unsigned int bufferBytes;\r
+ stream_.state = STREAM_STOPPED;\r
\r
// create API Handle if not already created\r
if ( !stream_.apiHandle )\r
stream_.apiHandle = ( void* ) new WasapiHandle();\r
\r
- // count capture devices\r
+ // Count capture devices\r
+ errorText_.clear();\r
+ RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;\r
HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture device collection" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device collection.";\r
+ goto Exit;\r
+ }\r
\r
hr = captureDevices->GetCount( &captureDeviceCount );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture device count" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device count.";\r
+ goto Exit;\r
+ }\r
\r
- // count render devices\r
+ // Count render devices\r
hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render device collection" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device collection.";\r
+ goto Exit;\r
+ }\r
\r
hr = renderDevices->GetCount( &renderDeviceCount );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render device count" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device count.";\r
+ goto Exit;\r
+ }\r
\r
// validate device index\r
- if ( device >= captureDeviceCount + renderDeviceCount )\r
- EXIT_ON_ERROR( -1, RtAudioError::INVALID_USE, "Invalid device index" );\r
+ if ( device >= captureDeviceCount + renderDeviceCount ) {\r
+ errorType = RtAudioError::INVALID_USE;\r
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Invalid device index.";\r
+ goto Exit;\r
+ }\r
\r
// determine whether index falls within capture or render devices\r
if ( device >= renderDeviceCount ) {\r
- if ( mode != INPUT )\r
- EXIT_ON_ERROR( -1, RtAudioError::INVALID_USE, "Capture device selected as output device" );\r
+ if ( mode != INPUT ) {\r
+ errorType = RtAudioError::INVALID_USE;\r
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Capture device selected as output device.";\r
+ goto Exit;\r
+ }\r
\r
// retrieve captureAudioClient from devicePtr\r
IAudioClient*& captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient;\r
\r
hr = captureDevices->Item( device - renderDeviceCount, &devicePtr );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture device handle" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device handle.";\r
+ goto Exit;\r
+ }\r
\r
hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,\r
NULL, ( void** ) &captureAudioClient );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve device audio client" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";\r
+ goto Exit;\r
+ }\r
\r
hr = captureAudioClient->GetMixFormat( &deviceFormat );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve device mix format" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";\r
+ goto Exit;\r
+ }\r
\r
stream_.nDeviceChannels[mode] = deviceFormat->nChannels;\r
captureAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );\r
}\r
else {\r
- if ( mode != OUTPUT )\r
- EXIT_ON_ERROR( -1, RtAudioError::INVALID_USE, "Render device selected as input device" );\r
+ if ( mode != OUTPUT ) {\r
+ errorType = RtAudioError::INVALID_USE;\r
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Render device selected as input device.";\r
+ goto Exit;\r
+ }\r
\r
// retrieve renderAudioClient from devicePtr\r
IAudioClient*& renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;\r
\r
hr = renderDevices->Item( device, &devicePtr );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render device handle" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device handle.";\r
+ goto Exit;\r
+ }\r
\r
hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,\r
NULL, ( void** ) &renderAudioClient );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve device audio client" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";\r
+ goto Exit;\r
+ }\r
\r
hr = renderAudioClient->GetMixFormat( &deviceFormat );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve device mix format" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";\r
+ goto Exit;\r
+ }\r
\r
stream_.nDeviceChannels[mode] = deviceFormat->nChannels;\r
renderAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );\r
}\r
\r
stream_.device[mode] = device;\r
- stream_.state = STREAM_STOPPED;\r
stream_.doByteSwap[mode] = false;\r
stream_.sampleRate = sampleRate;\r
stream_.bufferSize = *bufferSize;\r
setConvertInfo( mode, 0 );\r
\r
// Allocate necessary internal buffers\r
- unsigned int bufferBytes = stream_.nUserChannels[mode] * stream_.bufferSize * formatBytes( stream_.userFormat );\r
+ bufferBytes = stream_.nUserChannels[mode] * stream_.bufferSize * formatBytes( stream_.userFormat );\r
\r
stream_.userBuffer[mode] = ( char* ) calloc( bufferBytes, 1 );\r
- if ( !stream_.userBuffer[mode] )\r
- EXIT_ON_ERROR( -1, RtAudioError::MEMORY_ERROR, "Error allocating user buffer memory" );\r
+ if ( !stream_.userBuffer[mode] ) {\r
+ errorType = RtAudioError::MEMORY_ERROR;\r
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Error allocating user buffer memory.";\r
+ goto Exit;\r
+ }\r
\r
if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME )\r
stream_.callbackInfo.priority = 15;\r
\r
Exit:\r
//clean up\r
-\r
SAFE_RELEASE( captureDevices );\r
SAFE_RELEASE( renderDevices );\r
SAFE_RELEASE( devicePtr );\r
-\r
CoTaskMemFree( deviceFormat );\r
\r
// if method failed, close the stream\r
if ( methodResult == FAILURE )\r
closeStream();\r
\r
+ if ( !errorText_.empty() )\r
+ error( errorType );\r
return methodResult;\r
}\r
\r
WasapiBuffer captureBuffer;\r
WasapiBuffer renderBuffer;\r
\r
+ // declare local stream variables\r
+ RtAudioCallback callback = ( RtAudioCallback ) stream_.callbackInfo.callback;\r
+ BYTE* streamBuffer = NULL;\r
+ unsigned long captureFlags = 0;\r
+ unsigned int bufferFrameCount = 0;\r
+ unsigned int numFramesPadding = 0;\r
+ unsigned int convBufferSize = 0;\r
+ bool callbackPushed = false;\r
+ bool callbackPulled = false;\r
+ bool callbackStopped = false;\r
+ int callbackResult = 0;\r
+\r
+ // convBuffer is used to store converted buffers between WASAPI and the user\r
+ char* convBuffer = NULL;\r
+ unsigned int deviceBufferSize = 0;\r
+\r
+ errorText_.clear();\r
+ RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;\r
+\r
// Attempt to assign "Pro Audio" characteristic to thread\r
HMODULE AvrtDll = LoadLibrary( "AVRT.dll" );\r
if ( AvrtDll ) {\r
// start capture stream if applicable\r
if ( captureAudioClient ) {\r
hr = captureAudioClient->GetMixFormat( &captureFormat );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve device mix format" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";\r
+ goto Exit;\r
+ }\r
\r
captureSrRatio = ( ( float ) captureFormat->nSamplesPerSec / stream_.sampleRate );\r
\r
desiredBufferPeriod,\r
captureFormat,\r
NULL );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to initialize capture audio client" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize capture audio client.";\r
+ goto Exit;\r
+ }\r
\r
hr = captureAudioClient->GetService( __uuidof( IAudioCaptureClient ),\r
( void** ) &captureClient );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture client handle" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture client handle.";\r
+ goto Exit;\r
+ }\r
\r
// configure captureEvent to trigger on every available capture buffer\r
captureEvent = CreateEvent( NULL, FALSE, FALSE, NULL );\r
- if ( !captureEvent )\r
- EXIT_ON_ERROR( -1, RtAudioError::SYSTEM_ERROR, "Unable to create capture event" );\r
+ if ( !captureEvent ) {\r
+ errorType = RtAudioError::SYSTEM_ERROR;\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to create capture event.";\r
+ goto Exit;\r
+ }\r
\r
hr = captureAudioClient->SetEventHandle( captureEvent );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to set capture event handle" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to set capture event handle.";\r
+ goto Exit;\r
+ }\r
\r
( ( WasapiHandle* ) stream_.apiHandle )->captureClient = captureClient;\r
( ( WasapiHandle* ) stream_.apiHandle )->captureEvent = captureEvent;\r
\r
unsigned int inBufferSize = 0;\r
hr = captureAudioClient->GetBufferSize( &inBufferSize );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to get capture buffer size" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to get capture buffer size.";\r
+ goto Exit;\r
+ }\r
\r
// scale outBufferSize according to stream->user sample rate ratio\r
unsigned int outBufferSize = ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT];\r
\r
// reset the capture stream\r
hr = captureAudioClient->Reset();\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to reset capture stream" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to reset capture stream.";\r
+ goto Exit;\r
+ }\r
\r
// start the capture stream\r
hr = captureAudioClient->Start();\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to start capture stream" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to start capture stream.";\r
+ goto Exit;\r
+ }\r
}\r
\r
// start render stream if applicable\r
if ( renderAudioClient ) {\r
hr = renderAudioClient->GetMixFormat( &renderFormat );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve device mix format" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";\r
+ goto Exit;\r
+ }\r
\r
renderSrRatio = ( ( float ) renderFormat->nSamplesPerSec / stream_.sampleRate );\r
\r
desiredBufferPeriod,\r
renderFormat,\r
NULL );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to initialize render audio client" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize render audio client.";\r
+ goto Exit;\r
+ }\r
\r
hr = renderAudioClient->GetService( __uuidof( IAudioRenderClient ),\r
( void** ) &renderClient );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render client handle" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render client handle.";\r
+ goto Exit;\r
+ }\r
\r
// configure renderEvent to trigger on every available render buffer\r
renderEvent = CreateEvent( NULL, FALSE, FALSE, NULL );\r
- if ( !renderEvent )\r
- EXIT_ON_ERROR( -1, RtAudioError::SYSTEM_ERROR, "Unable to create render event" );\r
+ if ( !renderEvent ) {\r
+ errorType = RtAudioError::SYSTEM_ERROR;\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to create render event.";\r
+ goto Exit;\r
+ }\r
\r
hr = renderAudioClient->SetEventHandle( renderEvent );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to set render event handle" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to set render event handle.";\r
+ goto Exit;\r
+ }\r
\r
( ( WasapiHandle* ) stream_.apiHandle )->renderClient = renderClient;\r
( ( WasapiHandle* ) stream_.apiHandle )->renderEvent = renderEvent;\r
\r
unsigned int outBufferSize = 0;\r
hr = renderAudioClient->GetBufferSize( &outBufferSize );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to get render buffer size" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to get render buffer size.";\r
+ goto Exit;\r
+ }\r
\r
// scale inBufferSize according to user->stream sample rate ratio\r
unsigned int inBufferSize = ( unsigned int ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT];\r
\r
// reset the render stream\r
hr = renderAudioClient->Reset();\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to reset render stream" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to reset render stream.";\r
+ goto Exit;\r
+ }\r
\r
// start the render stream\r
hr = renderAudioClient->Start();\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to start render stream" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to start render stream.";\r
+ goto Exit;\r
+ }\r
}\r
\r
- // declare local stream variables\r
- RtAudioCallback callback = ( RtAudioCallback ) stream_.callbackInfo.callback;\r
-\r
- BYTE* streamBuffer = NULL;\r
- unsigned long captureFlags = 0;\r
-\r
- unsigned int bufferFrameCount = 0;\r
- unsigned int numFramesPadding = 0;\r
- unsigned int convBufferSize = 0;\r
-\r
- bool callbackPushed = false;\r
- bool callbackPulled = false;\r
- bool callbackStopped = false;\r
-\r
- int callbackResult = 0;\r
-\r
- // convBuffer is used to store converted buffers between WASAPI and the user\r
- unsigned int deviceBufferSize = 0;\r
if ( stream_.mode == INPUT ) {\r
deviceBufferSize = ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] );\r
}\r
deviceBufferSize = ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] );\r
}\r
else if ( stream_.mode == DUPLEX ) {\r
- deviceBufferSize = max( ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),\r
+ deviceBufferSize = std::max( ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),\r
( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) );\r
}\r
\r
- char* convBuffer = ( char* ) malloc( deviceBufferSize );\r
+ convBuffer = ( char* ) malloc( deviceBufferSize );\r
stream_.deviceBuffer = ( char* ) malloc( deviceBufferSize );\r
- if ( !convBuffer || !stream_.deviceBuffer )\r
- EXIT_ON_ERROR( -1, RtAudioError::MEMORY_ERROR, "Error allocating device buffer memory" );\r
+ if ( !convBuffer || !stream_.deviceBuffer ) {\r
+ errorType = RtAudioError::MEMORY_ERROR;\r
+ errorText_ = "RtApiWasapi::wasapiThread: Error allocating device buffer memory.";\r
+ goto Exit;\r
+ }\r
\r
// stream process loop\r
while ( stream_.state != STREAM_STOPPING ) {\r
// Handle return value from callback\r
if ( callbackResult == 1 ) {\r
// instantiate a thread to stop this thread\r
- HANDLE threadHandle = CreateThread( NULL, 0, stopWasapiThread, this, NULL, NULL );\r
-\r
+ HANDLE threadHandle = CreateThread( NULL, 0, stopWasapiThread, this, 0, NULL );\r
if ( !threadHandle ) {\r
- EXIT_ON_ERROR( -1, RtAudioError::THREAD_ERROR, "Unable to instantiate stream stop thread" );\r
+ errorType = RtAudioError::THREAD_ERROR;\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream stop thread.";\r
+ goto Exit;\r
}\r
else if ( !CloseHandle( threadHandle ) ) {\r
- EXIT_ON_ERROR( -1, RtAudioError::THREAD_ERROR, "Unable to close stream stop thread handle" );\r
+ errorType = RtAudioError::THREAD_ERROR;\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream stop thread handle.";\r
+ goto Exit;\r
}\r
\r
callbackStopped = true;\r
}\r
else if ( callbackResult == 2 ) {\r
// instantiate a thread to stop this thread\r
- HANDLE threadHandle = CreateThread( NULL, 0, abortWasapiThread, this, NULL, NULL );\r
-\r
+ HANDLE threadHandle = CreateThread( NULL, 0, abortWasapiThread, this, 0, NULL );\r
if ( !threadHandle ) {\r
- EXIT_ON_ERROR( -1, RtAudioError::THREAD_ERROR, "Unable to instantiate stream abort thread" );\r
+ errorType = RtAudioError::THREAD_ERROR;\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream abort thread.";\r
+ goto Exit;\r
}\r
else if ( !CloseHandle( threadHandle ) ) {\r
- EXIT_ON_ERROR( -1, RtAudioError::THREAD_ERROR, "Unable to close stream abort thread handle" );\r
+ errorType = RtAudioError::THREAD_ERROR;\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream abort thread handle.";\r
+ goto Exit;\r
}\r
\r
callbackStopped = true;\r
hr = captureClient->GetBuffer( &streamBuffer,\r
&bufferFrameCount,\r
&captureFlags, NULL, NULL );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve capture buffer" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture buffer.";\r
+ goto Exit;\r
+ }\r
\r
if ( bufferFrameCount != 0 ) {\r
// Push capture buffer into inputBuffer\r
{\r
// Release capture buffer\r
hr = captureClient->ReleaseBuffer( bufferFrameCount );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to release capture buffer" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";\r
+ goto Exit;\r
+ }\r
}\r
else\r
{\r
// Inform WASAPI that capture was unsuccessful\r
hr = captureClient->ReleaseBuffer( 0 );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to release capture buffer" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";\r
+ goto Exit;\r
+ }\r
}\r
}\r
else\r
{\r
// Inform WASAPI that capture was unsuccessful\r
hr = captureClient->ReleaseBuffer( 0 );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to release capture buffer" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";\r
+ goto Exit;\r
+ }\r
}\r
}\r
\r
\r
// Get render buffer from stream\r
hr = renderAudioClient->GetBufferSize( &bufferFrameCount );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render buffer size" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer size.";\r
+ goto Exit;\r
+ }\r
\r
hr = renderAudioClient->GetCurrentPadding( &numFramesPadding );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render buffer padding" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer padding.";\r
+ goto Exit;\r
+ }\r
\r
bufferFrameCount -= numFramesPadding;\r
\r
if ( bufferFrameCount != 0 ) {\r
hr = renderClient->GetBuffer( bufferFrameCount, &streamBuffer );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to retrieve render buffer" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer.";\r
+ goto Exit;\r
+ }\r
\r
// Pull next buffer from outputBuffer\r
// Fill render buffer with next buffer\r
{\r
// Release render buffer\r
hr = renderClient->ReleaseBuffer( bufferFrameCount, 0 );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to release render buffer" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";\r
+ goto Exit;\r
+ }\r
}\r
else\r
{\r
// Inform WASAPI that render was unsuccessful\r
hr = renderClient->ReleaseBuffer( 0, 0 );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to release render buffer" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";\r
+ goto Exit;\r
+ }\r
}\r
}\r
else\r
{\r
// Inform WASAPI that render was unsuccessful\r
hr = renderClient->ReleaseBuffer( 0, 0 );\r
- EXIT_ON_ERROR( hr, RtAudioError::DRIVER_ERROR, "Unable to release render buffer" );\r
+ if ( FAILED( hr ) ) {\r
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";\r
+ goto Exit;\r
+ }\r
}\r
}\r
\r
\r
// update stream state\r
stream_.state = STREAM_STOPPED;\r
+\r
+ if ( errorText_.empty() )\r
+ return;\r
+ else\r
+ error( errorType );\r
}\r
\r
//******************** End of __WINDOWS_WASAPI__ *********************//\r