From 2e7545f17fc7f0ed4a85d0ae21361f091e607cc0 Mon Sep 17 00:00:00 2001 From: dmitrykos Date: Wed, 3 Aug 2016 22:39:41 +0300 Subject: [PATCH 1/7] wasapi: ported to WinRT (UWP) os: compatibility fixes for compilation of PortAudio as Windows Store library (only WASAPI hostapi is compatible with Windows Store APIs) --- src/hostapi/wasapi/pa_win_wasapi.c | 449 ++++++++++++++++++++++++++--- src/os/win/pa_win_coinitialize.c | 6 +- src/os/win/pa_win_util.c | 21 +- src/os/win/pa_win_waveformat.c | 31 ++ 4 files changed, 454 insertions(+), 53 deletions(-) diff --git a/src/hostapi/wasapi/pa_win_wasapi.c b/src/hostapi/wasapi/pa_win_wasapi.c index 6e62a4a..1f071fb 100644 --- a/src/hostapi/wasapi/pa_win_wasapi.c +++ b/src/hostapi/wasapi/pa_win_wasapi.c @@ -42,12 +42,18 @@ @note pa_wasapi currently requires minimum VC 2005, and the latest Vista SDK */ -#define WIN32_LEAN_AND_MEAN // exclude rare headers #include #include #include #include -#include + +// WinRT +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) + #define WIN32_WINRT + #define INITGUID +#endif + +// WASAPI #include // must be before other Wasapi headers #if defined(_MSC_VER) && (_MSC_VER >= 1400) #include @@ -61,9 +67,9 @@ #undef INITGUID #endif #ifndef __MWERKS__ -#include -#include -#endif /* __MWERKS__ */ + #include + #include +#endif #include "pa_util.h" #include "pa_allocation.h" @@ -74,10 +80,9 @@ #include "pa_win_wasapi.h" #include "pa_debugprint.h" #include "pa_ringbuffer.h" - #include "pa_win_coinitialize.h" -#ifndef NTDDI_VERSION +#if !defined(NTDDI_VERSION) #undef WINVER #undef _WIN32_WINNT @@ -125,6 +130,7 @@ #include #include #else + #ifndef WIN32_WINRT typedef struct _BYTE_BLOB { unsigned long clSize; @@ -133,6 +139,7 @@ typedef /* [unique] */ __RPC_unique_pointer BYTE_BLOB *UP_BYTE_BLOB; typedef LONGLONG REFERENCE_TIME; #define NONAMELESSUNION + #endif #endif #ifndef WAVE_FORMAT_IEEE_FLOAT @@ -160,6 +167,36 @@ #endif // NTDDI_VERSION +// Missing declarations for WinRT +#ifdef WIN32_WINRT + + typedef enum _EDataFlow + { + eRender = 0, + eCapture = ( eRender + 1 ) , + eAll = ( eCapture + 1 ) , + EDataFlow_enum_count = ( eAll + 1 ) + } + EDataFlow; + + typedef enum _EndpointFormFactor + { + RemoteNetworkDevice = 0, + Speakers = ( RemoteNetworkDevice + 1 ) , + LineLevel = ( Speakers + 1 ) , + Headphones = ( LineLevel + 1 ) , + Microphone = ( Headphones + 1 ) , + Headset = ( Microphone + 1 ) , + Handset = ( Headset + 1 ) , + UnknownDigitalPassthrough = ( Handset + 1 ) , + SPDIF = ( UnknownDigitalPassthrough + 1 ) , + HDMI = ( SPDIF + 1 ) , + UnknownFormFactor = ( HDMI + 1 ) + } + EndpointFormFactor; + +#endif + #ifndef GUID_SECT #define GUID_SECT #endif @@ -192,6 +229,7 @@ PA_DEFINE_IID(IDeviceTopology, 2A07407E, 6497, 4A18, 97, 87, 32, f7, 9b, d0 PA_DEFINE_IID(IPart, AE2DE0E4, 5BCA, 4F2D, aa, 46, 5d, 13, f8, fd, b3, a9); // *4509F757-2D46-4637-8E62-CE7DB944F57B* PA_DEFINE_IID(IKsJackDescription, 4509F757, 2D46, 4637, 8e, 62, ce, 7d, b9, 44, f5, 7b); + // Media formats: __DEFINE_GUID(pa_KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); __DEFINE_GUID(pa_KSDATAFORMAT_SUBTYPE_ADPCM, 0x00000002, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); @@ -272,13 +310,13 @@ enum { WASAPI_PACKETS_PER_INPUT_BUFFER = 6 }; typedef void (*MixMonoToStereoF) (void *__to, void *__from, UINT32 count); // AVRT is the new "multimedia schedulling stuff" +#ifndef WIN32_WINRT typedef BOOL (WINAPI *FAvRtCreateThreadOrderingGroup) (PHANDLE,PLARGE_INTEGER,GUID*,PLARGE_INTEGER); typedef BOOL (WINAPI *FAvRtDeleteThreadOrderingGroup) (HANDLE); typedef BOOL (WINAPI *FAvRtWaitOnThreadOrderingGroup) (HANDLE); typedef HANDLE (WINAPI *FAvSetMmThreadCharacteristics) (LPCSTR,LPDWORD); typedef BOOL (WINAPI *FAvRevertMmThreadCharacteristics)(HANDLE); typedef BOOL (WINAPI *FAvSetMmThreadPriority) (HANDLE,AVRT_PRIORITY); - static HMODULE hDInputDLL = 0; FAvRtCreateThreadOrderingGroup pAvRtCreateThreadOrderingGroup = NULL; FAvRtDeleteThreadOrderingGroup pAvRtDeleteThreadOrderingGroup = NULL; @@ -286,6 +324,7 @@ FAvRtWaitOnThreadOrderingGroup pAvRtWaitOnThreadOrderingGroup = NULL; FAvSetMmThreadCharacteristics pAvSetMmThreadCharacteristics = NULL; FAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL; FAvSetMmThreadPriority pAvSetMmThreadPriority = NULL; +#endif #define _GetProc(fun, type, name) { \ fun = (type) GetProcAddress(hDInputDLL,name); \ @@ -351,7 +390,9 @@ static signed long GetStreamWriteAvailable( PaStream* stream ); typedef struct PaWasapiDeviceInfo { // Device +#ifndef WIN32_WINRT IMMDevice *device; +#endif // from GetId WCHAR szDeviceID[MAX_STR_LEN]; @@ -359,9 +400,6 @@ typedef struct PaWasapiDeviceInfo // from GetState DWORD state; - // Fields filled from IMMEndpoint'sGetDataFlow - EDataFlow flow; - // Fields filled from IAudioDevice (_prior_ to Initialize) // from GetDevicePeriod( REFERENCE_TIME DefaultDevicePeriod; @@ -373,6 +411,9 @@ typedef struct PaWasapiDeviceInfo // Default format (setup through Control Panel by user) WAVEFORMATEXTENSIBLE DefaultFormat; + // Fields filled from IMMEndpoint'sGetDataFlow + EDataFlow flow; + // Formfactor EndpointFormFactor formFactor; } @@ -393,7 +434,9 @@ typedef struct PaWinUtilComInitializationResult comInitializationResult; //in case we later need the synch +#ifndef WIN32_WINRT IMMDeviceEnumerator *enumerator; +#endif //this is the REAL number of devices, whether they are usefull to PA or not! UINT32 deviceCount; @@ -428,7 +471,9 @@ PaWasapiAudioClientParams; typedef struct PaWasapiSubStream { IAudioClient *clientParent; +#ifndef WIN32_WINRT IStream *clientStream; +#endif IAudioClient *clientProc; WAVEFORMATEXTENSIBLE wavex; @@ -478,14 +523,18 @@ typedef struct PaWasapiStream // input PaWasapiSubStream in; IAudioCaptureClient *captureClientParent; +#ifndef WIN32_WINRT IStream *captureClientStream; +#endif IAudioCaptureClient *captureClient; IAudioEndpointVolume *inVol; // output PaWasapiSubStream out; IAudioRenderClient *renderClientParent; +#ifndef WIN32_WINRT IStream *renderClientStream; +#endif IAudioRenderClient *renderClient; IAudioEndpointVolume *outVol; @@ -812,6 +861,7 @@ static UINT32 GetFramesSleepTimeMicroseconds(UINT32 nFrames, UINT32 nSamplesPerS } // ------------------------------------------------------------------------------------------ +#ifndef WIN32_WINRT static BOOL SetupAVRT() { hDInputDLL = LoadLibraryA("avrt.dll"); @@ -832,18 +882,23 @@ static BOOL SetupAVRT() pAvRevertMmThreadCharacteristics && pAvSetMmThreadPriority; } +#endif // ------------------------------------------------------------------------------------------ static void CloseAVRT() { +#ifndef WIN32_WINRT if (hDInputDLL != NULL) FreeLibrary(hDInputDLL); hDInputDLL = NULL; +#endif } // ------------------------------------------------------------------------------------------ static BOOL IsWow64() { +#ifndef WIN32_WINRT + // http://msdn.microsoft.com/en-us/library/ms684139(VS.85).aspx typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); @@ -865,6 +920,12 @@ static BOOL IsWow64() return FALSE; return bIsWow64; + +#else + + return FALSE; + +#endif } // ------------------------------------------------------------------------------------------ @@ -880,6 +941,7 @@ typedef enum EWindowsVersion } EWindowsVersion; // Alternative way for checking Windows version (allows to check version on Windows 8.1 and up) +#ifndef WIN32_WINRT static BOOL IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor) { typedef ULONGLONG (NTAPI *LPFN_VERSETCONDITIONMASK)(ULONGLONG ConditionMask, DWORD TypeMask, BYTE Condition); @@ -909,9 +971,11 @@ static BOOL IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WO return (fnVerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE); } +#endif // Get Windows version static EWindowsVersion GetWindowsVersion() { +#ifndef WIN32_WINRT static EWindowsVersion version = WINDOWS_UNKNOWN; if (version == WINDOWS_UNKNOWN) @@ -996,6 +1060,9 @@ static EWindowsVersion GetWindowsVersion() } return version; +#else + return WINDOWS_8_SERVER2012; +#endif } // ------------------------------------------------------------------------------------------ @@ -1167,6 +1234,179 @@ static MixMonoToStereoF _GetMonoToStereoMixer(PaSampleFormat format, EMixerDir d return NULL; } +// ------------------------------------------------------------------------------------------ +#ifdef WIN32_WINRT +typedef struct _CActivateAudioInterfaceCompletionHandler +{ + IActivateAudioInterfaceCompletionHandler parent; + ULONG refs; + volatile BOOL done; + struct + { + HRESULT hr; + IAudioClient *client; + } + out; +} +CActivateAudioInterfaceCompletionHandler; + +static HRESULT ( STDMETHODCALLTYPE CActivateAudioInterfaceCompletionHandler_QueryInterface )( + IActivateAudioInterfaceCompletionHandler * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject) +{ + CActivateAudioInterfaceCompletionHandler *handler = (CActivateAudioInterfaceCompletionHandler *)This; + + // From MSDN: + // "The IAgileObject interface is a marker interface that indicates that an object + // is free threaded and can be called from any apartment." + if (IsEqualIID(riid, &IID_IAgileObject)) + { + handler->parent.lpVtbl->AddRef((IActivateAudioInterfaceCompletionHandler *)handler); + (*ppvObject) = handler; + return S_OK; + } + + return S_FALSE; +} + +static ULONG ( STDMETHODCALLTYPE CActivateAudioInterfaceCompletionHandler_AddRef )( + IActivateAudioInterfaceCompletionHandler * This) +{ + CActivateAudioInterfaceCompletionHandler *handler = (CActivateAudioInterfaceCompletionHandler *)This; + return ++ handler->refs; +} + +static ULONG ( STDMETHODCALLTYPE CActivateAudioInterfaceCompletionHandler_Release )( + IActivateAudioInterfaceCompletionHandler * This) +{ + CActivateAudioInterfaceCompletionHandler *handler = (CActivateAudioInterfaceCompletionHandler *)This; + if (handler->refs == 0) + { + PaUtil_FreeMemory(handler->parent.lpVtbl); + PaUtil_FreeMemory(handler); + return 0; + } + return -- handler->refs; +} + +static HRESULT ( STDMETHODCALLTYPE CActivateAudioInterfaceCompletionHandler_ActivateCompleted )( + IActivateAudioInterfaceCompletionHandler * This, + /* [annotation][in] */ + _In_ IActivateAudioInterfaceAsyncOperation *activateOperation) +{ + CActivateAudioInterfaceCompletionHandler *handler = (CActivateAudioInterfaceCompletionHandler *)This; + + HRESULT hr = S_OK; + HRESULT hrActivateResult = S_OK; + IUnknown *punkAudioInterface = NULL; + + // Check for a successful activation result + hr = activateOperation->lpVtbl->GetActivateResult(activateOperation, &hrActivateResult, &punkAudioInterface); + if (SUCCEEDED(hr) && SUCCEEDED(hrActivateResult)) + { + // Get the pointer for the Audio Client + punkAudioInterface->lpVtbl->QueryInterface(punkAudioInterface, GetAudioClientIID(), &handler->out.client); + if (handler->out.client == NULL) + hrActivateResult = E_FAIL; + } + SAFE_RELEASE(punkAudioInterface); + + if (SUCCEEDED(hr)) + handler->out.hr = hrActivateResult; + else + handler->out.hr = hr; + + handler->done = TRUE; + return hr; +} + +static IActivateAudioInterfaceCompletionHandler *CreateActivateAudioInterfaceCompletionHandler() +{ + CActivateAudioInterfaceCompletionHandler *handler = PaUtil_AllocateMemory(sizeof(CActivateAudioInterfaceCompletionHandler)); + ZeroMemory(handler, sizeof(*handler)); + handler->parent.lpVtbl = PaUtil_AllocateMemory(sizeof(*handler->parent.lpVtbl)); + handler->parent.lpVtbl->QueryInterface = &CActivateAudioInterfaceCompletionHandler_QueryInterface; + handler->parent.lpVtbl->AddRef = &CActivateAudioInterfaceCompletionHandler_AddRef; + handler->parent.lpVtbl->Release = &CActivateAudioInterfaceCompletionHandler_Release; + handler->parent.lpVtbl->ActivateCompleted = &CActivateAudioInterfaceCompletionHandler_ActivateCompleted; + return (IActivateAudioInterfaceCompletionHandler *)handler; +} +#endif + +// ------------------------------------------------------------------------------------------ +#ifdef WIN32_WINRT +static HRESULT ActivateAudioInterface_WINRT(const PaWasapiDeviceInfo *deviceInfo, IAudioClient **client) +{ + PaError result = paNoError; + HRESULT hr = S_OK; + HRESULT activateResult = S_OK; + IActivateAudioInterfaceAsyncOperation *asyncOp = NULL; + IActivateAudioInterfaceCompletionHandler *handler = CreateActivateAudioInterfaceCompletionHandler(); + CActivateAudioInterfaceCompletionHandler *ñhandler = (CActivateAudioInterfaceCompletionHandler *)handler; + OLECHAR devicePath[64] = { 0 }; + + // Get device path in form L"{DEVICE_GUID}" + switch (deviceInfo->flow) + { + case eRender: + StringFromGUID2(&DEVINTERFACE_AUDIO_RENDER, devicePath, 63); + break; + case eCapture: + StringFromGUID2(&DEVINTERFACE_AUDIO_CAPTURE, devicePath, 63); + break; + default: + return S_FALSE; + } + + // Async operation will call back to IActivateAudioInterfaceCompletionHandler::ActivateCompleted + // which must be an agile interface implementation + hr = ActivateAudioInterfaceAsync(devicePath, GetAudioClientIID(), NULL, handler, &asyncOp); + IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + + // Wait in busy loop for async operation to complete + while (SUCCEEDED(hr) && !ñhandler->done) + { + Pa_Sleep(1); + } + + (*client) = ñhandler->out.client; + hr = ñhandler->out.hr; + +error: + + SAFE_RELEASE(asyncOp); + SAFE_RELEASE(handler); + + return hr; +} +#endif + +// ------------------------------------------------------------------------------------------ +static HRESULT ActivateAudioInterface(const PaWasapiDeviceInfo *deviceInfo, IAudioClient **client) +{ +#ifndef WIN32_WINRT + return IMMDevice_Activate(deviceInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void **)client); +#else + return ActivateAudioInterface_WINRT(deviceInfo, client); +#endif +} + +// ------------------------------------------------------------------------------------------ +#ifdef WIN32_WINRT +static DWORD SignalObjectAndWait( + _In_ HANDLE hObjectToSignal, + _In_ HANDLE hObjectToWaitOn, + _In_ DWORD dwMilliseconds, + _In_ BOOL bAlertable +) +{ + SetEvent(hObjectToSignal); + return WaitForSingleObjectEx(hObjectToWaitOn, dwMilliseconds, bAlertable); +} +#endif + // ------------------------------------------------------------------------------------------ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { @@ -1174,14 +1414,19 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd PaWasapiHostApiRepresentation *paWasapi; PaDeviceInfo *deviceInfoArray; HRESULT hr = S_OK; +#ifndef WIN32_WINRT IMMDeviceCollection* pEndPoints = NULL; +#endif UINT i; + WAVEFORMATEX *mixFormat; +#ifndef WIN32_WINRT if (!SetupAVRT()) { PRINT(("WASAPI: No AVRT! (not VISTA?)")); return paNoError; } +#endif paWasapi = (PaWasapiHostApiRepresentation *)PaUtil_AllocateMemory( sizeof(PaWasapiHostApiRepresentation) ); if (paWasapi == NULL) @@ -1213,6 +1458,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd (*hostApi)->info.defaultInputDevice = paNoDevice; (*hostApi)->info.defaultOutputDevice = paNoDevice; +#ifndef WIN32_WINRT paWasapi->enumerator = NULL; hr = CoCreateInstance(&pa_CLSID_IMMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &pa_IID_IMMDeviceEnumerator, (void **)&paWasapi->enumerator); @@ -1282,6 +1528,10 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd // [IF_FAILED_JUMP(hResult, error);] IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); +#else + paWasapi->deviceCount = 2; +#endif + paWasapi->devInfo = (PaWasapiDeviceInfo *)PaUtil_AllocateMemory(sizeof(PaWasapiDeviceInfo) * paWasapi->deviceCount); if (paWasapi->devInfo == NULL) { @@ -1320,6 +1570,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd PA_DEBUG(("WASAPI: device idx: %02d\n", i)); PA_DEBUG(("WASAPI: ---------------\n")); + #ifndef WIN32_WINRT hr = IMMDeviceCollection_Item(pEndPoints, i, &paWasapi->devInfo[i].device); // We need to set the result to a value otherwise we will return paNoError // [IF_FAILED_JUMP(hResult, error);] @@ -1424,8 +1675,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd SAFE_RELEASE(pProperty); } - - + // Endpoint data { IMMEndpoint *endpoint = NULL; @@ -1436,18 +1686,23 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd SAFE_RELEASE(endpoint); } } + #endif // Getting a temporary IAudioClient for more fields // we make sure NOT to call Initialize yet! { - IAudioClient *tmpClient = NULL; + #ifdef WIN32_WINRT + // Set flow as ActivateAudioInterface depends on it and selects corresponding + // direction for the Audio Client + paWasapi->devInfo[i].flow = (i == 0 ? eRender : eCapture); + #endif - hr = IMMDevice_Activate(paWasapi->devInfo[i].device, GetAudioClientIID(), - CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient); - // We need to set the result to a value otherwise we will return paNoError - // [IF_FAILED_JUMP(hResult, error);] + // Create temp Audio Client instance to query additional details + IAudioClient *tmpClient = NULL; + hr = ActivateAudioInterface(&paWasapi->devInfo[i], &tmpClient); IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + // Get latency hr = IAudioClient_GetDevicePeriod(tmpClient, &paWasapi->devInfo[i].DefaultDevicePeriod, &paWasapi->devInfo[i].MinimumDevicePeriod); @@ -1462,10 +1717,42 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd // ignore error, let continue further without failing with paInternalError hr = S_OK; } + + #ifdef WIN32_WINRT + // Get mix format which will treat as default device format + hr = IAudioClient_GetMixFormat(tmpClient, &mixFormat); + if (SUCCEEDED(hr)) + { + // Default device + if (i == 0) + (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount; + else + (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount; - //hr = tmpClient->GetMixFormat(&paWasapi->devInfo[i].MixFormat); + // State + paWasapi->devInfo[i].state = 1; // DEVICE_STATE_ACTIVE - // Release client + // Default format + memcpy(&paWasapi->devInfo[i].DefaultFormat, mixFormat, min(sizeof(paWasapi->devInfo[i].DefaultFormat), sizeof(*mixFormat))); + CoTaskMemFree(mixFormat); + + // Form-factor + paWasapi->devInfo[i].formFactor = UnknownFormFactor; + + // Name + deviceInfo->name = PaUtil_GroupAllocateMemory(paWasapi->allocations, MAX_STR_LEN + 1); + if (deviceInfo->name == NULL) + { + SAFE_RELEASE(tmpClient); + result = paInsufficientMemory; + goto error; + } + _snprintf(deviceInfo->name, MAX_STR_LEN - 1, "WASAPI_%s:%d", (i == 0 ? "Output" : "Input"), i); + PA_DEBUG(("WASAPI:%d| name[%s]\n", i, deviceInfo->name)); + } + #endif + + // Release tmp client SAFE_RELEASE(tmpClient); if (hr != S_OK) @@ -1479,7 +1766,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd goto error; } } - + // we can now fill in portaudio device data deviceInfo->maxInputChannels = 0; deviceInfo->maxOutputChannels = 0; @@ -1532,7 +1819,9 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd // findout if platform workaround is required paWasapi->useWOW64Workaround = UseWOW64Workaround(); +#ifndef WIN32_WINRT SAFE_RELEASE(pEndPoints); +#endif PRINT(("WASAPI: initialized ok\n")); @@ -1542,7 +1831,9 @@ error: PRINT(("WASAPI: failed %s error[%d|%s]\n", __FUNCTION__, result, Pa_GetErrorText(result))); +#ifndef WIN32_WINRT SAFE_RELEASE(pEndPoints); +#endif Terminate((PaUtilHostApiRepresentation *)paWasapi); @@ -1563,12 +1854,16 @@ static void Terminate( PaUtilHostApiRepresentation *hostApi ) return; // Release IMMDeviceEnumerator +#ifndef WIN32_WINRT SAFE_RELEASE(paWasapi->enumerator); +#endif for (i = 0; i < paWasapi->deviceCount; ++i) { PaWasapiDeviceInfo *info = &paWasapi->devInfo[i]; + #ifndef WIN32_WINRT SAFE_RELEASE(info->device); + #endif //if (info->MixFormat) // CoTaskMemFree(info->MixFormat); @@ -1830,25 +2125,25 @@ static PaError MakeWaveFormatFromParams(WAVEFORMATEXTENSIBLE *wavex, const PaStr { switch (params->channelCount) { - case 1: wavex->dwChannelMask = KSAUDIO_SPEAKER_MONO; break; - case 2: wavex->dwChannelMask = KSAUDIO_SPEAKER_STEREO; break; - case 3: wavex->dwChannelMask = KSAUDIO_SPEAKER_STEREO|SPEAKER_LOW_FREQUENCY; break; - case 4: wavex->dwChannelMask = KSAUDIO_SPEAKER_QUAD; break; - case 5: wavex->dwChannelMask = KSAUDIO_SPEAKER_QUAD|SPEAKER_LOW_FREQUENCY; break; -#ifdef KSAUDIO_SPEAKER_5POINT1_SURROUND - case 6: wavex->dwChannelMask = KSAUDIO_SPEAKER_5POINT1_SURROUND; break; + case 1: wavex->dwChannelMask = PAWIN_SPEAKER_MONO; break; + case 2: wavex->dwChannelMask = PAWIN_SPEAKER_STEREO; break; + case 3: wavex->dwChannelMask = PAWIN_SPEAKER_STEREO|SPEAKER_LOW_FREQUENCY; break; + case 4: wavex->dwChannelMask = PAWIN_SPEAKER_QUAD; break; + case 5: wavex->dwChannelMask = PAWIN_SPEAKER_QUAD|SPEAKER_LOW_FREQUENCY; break; +#ifdef PAWIN_SPEAKER_5POINT1_SURROUND + case 6: wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1_SURROUND; break; #else - case 6: wavex->dwChannelMask = KSAUDIO_SPEAKER_5POINT1; break; + case 6: wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1; break; #endif -#ifdef KSAUDIO_SPEAKER_5POINT1_SURROUND - case 7: wavex->dwChannelMask = KSAUDIO_SPEAKER_5POINT1_SURROUND|SPEAKER_BACK_CENTER; break; +#ifdef PAWIN_SPEAKER_5POINT1_SURROUND + case 7: wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1_SURROUND|SPEAKER_BACK_CENTER; break; #else - case 7: wavex->dwChannelMask = KSAUDIO_SPEAKER_5POINT1|SPEAKER_BACK_CENTER; break; + case 7: wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1|SPEAKER_BACK_CENTER; break; #endif -#ifdef KSAUDIO_SPEAKER_7POINT1_SURROUND - case 8: wavex->dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND; break; +#ifdef PAWIN_SPEAKER_7POINT1_SURROUND + case 8: wavex->dwChannelMask = PAWIN_SPEAKER_7POINT1_SURROUND; break; #else - case 8: wavex->dwChannelMask = KSAUDIO_SPEAKER_7POINT1; break; + case 8: wavex->dwChannelMask = PAWIN_SPEAKER_7POINT1; break; #endif default: wavex->dwChannelMask = 0; @@ -1869,9 +2164,9 @@ static PaError MakeWaveFormatFromParams(WAVEFORMATEXTENSIBLE *wavex, const PaStr pwfext->Format.nChannels = (WORD)channelCount; pwfext->Format.nSamplesPerSec = (DWORD)sampleRate; if(channelCount == 1) - pwfext->dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT; + pwfext->dwChannelMask = PAWIN_SPEAKER_DIRECTOUT; else - pwfext->dwChannelMask = KSAUDIO_SPEAKER_STEREO; + pwfext->dwChannelMask = PAWIN_SPEAKER_STEREO; if(sampleFormat == paFloat32) { pwfext->Format.nBlockAlign = (WORD)(channelCount * 4); @@ -2154,8 +2449,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, if (inputStreamInfo && (inputStreamInfo->flags & paWinWasapiExclusive)) shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; - hr = IMMDevice_Activate(paWasapi->devInfo[inputParameters->device].device, - GetAudioClientIID(), CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient); + hr = ActivateAudioInterface(&paWasapi->devInfo[inputParameters->device], &tmpClient); if (hr != S_OK) { LogHostError(hr); @@ -2180,8 +2474,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, if (outputStreamInfo && (outputStreamInfo->flags & paWinWasapiExclusive)) shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; - hr = IMMDevice_Activate(paWasapi->devInfo[outputParameters->device].device, - GetAudioClientIID(), CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient); + hr = ActivateAudioInterface(&paWasapi->devInfo[outputParameters->device], &tmpClient); if (hr != S_OK) { LogHostError(hr); @@ -2281,7 +2574,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu } // Get the audio client - hr = IMMDevice_Activate(pInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void **)&audioClient); + hr = ActivateAudioInterface(pInfo, &audioClient); if (hr != S_OK) { (*pa_error) = paInsufficientMemory; @@ -2495,7 +2788,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu SAFE_RELEASE(audioClient); // Create a new audio client - hr = IMMDevice_Activate(pInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void**)&audioClient); + hr = ActivateAudioInterface(pInfo, &audioClient); if (hr != S_OK) { (*pa_error) = paInsufficientMemory; @@ -2526,7 +2819,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu SAFE_RELEASE(audioClient); // Create a new audio client - hr = IMMDevice_Activate(pInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void**)&audioClient); + hr = ActivateAudioInterface(pInfo, &audioClient); if (hr != S_OK) { (*pa_error) = paInsufficientMemory; @@ -2566,7 +2859,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu SAFE_RELEASE(audioClient); // Create a new audio client - hr = IMMDevice_Activate(pInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void**)&audioClient); + hr = ActivateAudioInterface(pInfo, &audioClient); if (hr != S_OK) { (*pa_error) = paInsufficientMemory; @@ -3249,6 +3542,7 @@ static PaError CloseStream( PaStream* s ) // ------------------------------------------------------------------------------------------ HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream) { +#ifndef WIN32_WINRT HRESULT hResult = S_OK; HRESULT hFirstBadResult = S_OK; substream->clientProc = NULL; @@ -3262,11 +3556,16 @@ HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream) } return hFirstBadResult; + +#else + return S_OK; +#endif } // ------------------------------------------------------------------------------------------ HRESULT UnmarshalStreamComPointers(PaWasapiStream *stream) { +#ifndef WIN32_WINRT HRESULT hResult = S_OK; HRESULT hFirstBadResult = S_OK; stream->captureClient = NULL; @@ -3311,6 +3610,33 @@ HRESULT UnmarshalStreamComPointers(PaWasapiStream *stream) } return hFirstBadResult; +#else + if (stream->in.clientParent != NULL) + { + stream->in.clientProc = stream->in.clientParent; + IAudioClient_AddRef(stream->in.clientParent); + } + + if (stream->out.clientParent != NULL) + { + stream->out.clientProc = stream->out.clientParent; + IAudioClient_AddRef(stream->out.clientParent); + } + + if (stream->renderClientParent != NULL) + { + stream->renderClient = stream->renderClientParent; + IAudioRenderClient_AddRef(stream->renderClientParent); + } + + if (stream->captureClientParent != NULL) + { + stream->captureClient = stream->captureClientParent; + IAudioCaptureClient_AddRef(stream->captureClientParent); + } + + return S_OK; +#endif } // ----------------------------------------------------------------------------------------- @@ -3334,6 +3660,7 @@ void ReleaseUnmarshaledComPointers(PaWasapiStream *stream) // ------------------------------------------------------------------------------------------ HRESULT MarshalSubStreamComPointers(PaWasapiSubStream *substream) { +#ifndef WIN32_WINRT HRESULT hResult; substream->clientStream = NULL; @@ -3350,11 +3677,15 @@ marshal_sub_error: UnmarshalSubStreamComPointers(substream); ReleaseUnmarshaledSubComPointers(substream); return hResult; +#else + return S_OK; +#endif } // ------------------------------------------------------------------------------------------ HRESULT MarshalStreamComPointers(PaWasapiStream *stream) { +#ifndef WIN32_WINRT HRESULT hResult = S_OK; stream->captureClientStream = NULL; stream->in.clientStream = NULL; @@ -3395,6 +3726,9 @@ marshal_error: UnmarshalStreamComPointers(stream); ReleaseUnmarshaledComPointers(stream); return hResult; +#else + return S_OK; +#endif } // ------------------------------------------------------------------------------------------ @@ -3743,7 +4077,7 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long frames ) { if ((sleep = ThreadIdleScheduler_NextSleep(&sched)) != 0) { - Sleep(sleep); + Pa_Sleep(sleep); sleep = 0; } } @@ -4079,6 +4413,7 @@ static void WaspiHostProcessingLoop( void *inputBuffer, long inputFrames, // ------------------------------------------------------------------------------------------ HANDLE MMCSS_activate(const char *name) { +#ifndef WIN32_WINRT DWORD task_idx = 0; HANDLE hTask = pAvSetMmThreadCharacteristics(name, &task_idx); if (hTask == NULL) @@ -4100,6 +4435,9 @@ HANDLE MMCSS_activate(const char *name) } return hTask; +#else + return NULL; +#endif } // ------------------------------------------------------------------------------------------ @@ -4108,10 +4446,12 @@ void MMCSS_deactivate(HANDLE hTask) if (!hTask) return; +#ifndef WIN32_WINRT if (pAvRevertMmThreadCharacteristics(hTask) == FALSE) { PRINT(("WASAPI: AvRevertMmThreadCharacteristics failed!\n")); } +#endif } // ------------------------------------------------------------------------------------------ @@ -4161,6 +4501,7 @@ PaError PaWasapi_ThreadPriorityRevert(void *hTask) PaError PaWasapi_GetJackCount(PaDeviceIndex nDevice, int *jcount) { +#ifndef WIN32_WINRT PaError ret; HRESULT hr = S_OK; PaDeviceIndex index; @@ -4230,9 +4571,13 @@ error: LogHostError(hr); return paNoError; +#else + return paUnanticipatedHostError; +#endif } // ------------------------------------------------------------------------------------------ +#ifndef WIN32_WINRT static PaWasapiJackConnectionType ConvertJackConnectionTypeWASAPIToPA(int connType) { switch (connType) @@ -4256,8 +4601,10 @@ static PaWasapiJackConnectionType ConvertJackConnectionTypeWASAPIToPA(int connTy } return eJackConnTypeUnknown; } +#endif // ------------------------------------------------------------------------------------------ +#ifndef WIN32_WINRT static PaWasapiJackGeoLocation ConvertJackGeoLocationWASAPIToPA(int geoLoc) { switch (geoLoc) @@ -4282,8 +4629,10 @@ static PaWasapiJackGeoLocation ConvertJackGeoLocationWASAPIToPA(int geoLoc) } return eJackGeoLocUnk; } +#endif // ------------------------------------------------------------------------------------------ +#ifndef WIN32_WINRT static PaWasapiJackGenLocation ConvertJackGenLocationWASAPIToPA(int genLoc) { switch (genLoc) @@ -4299,8 +4648,10 @@ static PaWasapiJackGenLocation ConvertJackGenLocationWASAPIToPA(int genLoc) } return eJackGenLocPrimaryBox; } +#endif // ------------------------------------------------------------------------------------------ +#ifndef WIN32_WINRT static PaWasapiJackPortConnection ConvertJackPortConnectionWASAPIToPA(int portConn) { switch (portConn) @@ -4312,6 +4663,7 @@ static PaWasapiJackPortConnection ConvertJackPortConnectionWASAPIToPA(int portCo } return eJackPortConnJack; } +#endif // ------------------------------------------------------------------------------------------ // Described at: @@ -4319,6 +4671,7 @@ static PaWasapiJackPortConnection ConvertJackPortConnectionWASAPIToPA(int portCo PaError PaWasapi_GetJackDescription(PaDeviceIndex nDevice, int jindex, PaWasapiJackDescription *pJackDescription) { +#ifndef WIN32_WINRT PaError ret; HRESULT hr = S_OK; PaDeviceIndex index; @@ -4394,6 +4747,10 @@ error: LogHostError(hr); return ret; + +#else + return paUnanticipatedHostError; +#endif } // ------------------------------------------------------------------------------------------ diff --git a/src/os/win/pa_win_coinitialize.c b/src/os/win/pa_win_coinitialize.c index 5c31716..c4c6dde 100644 --- a/src/os/win/pa_win_coinitialize.c +++ b/src/os/win/pa_win_coinitialize.c @@ -52,7 +52,7 @@ #include "pa_win_coinitialize.h" -#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && !defined(_WIN32_WCE) /* MSC version 6 and above */ +#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && !defined(_WIN32_WCE) && !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)) /* MSC version 6 and above */ #pragma comment( lib, "ole32.lib" ) #endif @@ -76,7 +76,11 @@ PaError PaWinUtil_CoInitialize( PaHostApiTypeId hostApiType, PaWinUtilComInitial RPC_E_CHANGED_MODE was returned. */ +#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP) hr = CoInitialize(0); /* use legacy-safe equivalent to CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) */ +#else + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); +#endif if( FAILED(hr) && hr != RPC_E_CHANGED_MODE ) { PA_DEBUG(("CoInitialize(0) failed. hr=%d\n", hr)); diff --git a/src/os/win/pa_win_util.c b/src/os/win/pa_win_util.c index 1e965ac..2de7684 100644 --- a/src/os/win/pa_win_util.c +++ b/src/os/win/pa_win_util.c @@ -44,14 +44,17 @@ */ #include -#include /* for timeGetTime() */ -#include "pa_util.h" - -#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && !defined(_WIN32_WCE) /* MSC version 6 and above */ -#pragma comment( lib, "winmm.lib" ) +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) + #include /* for _ftime_s() */ +#else + #include /* for timeGetTime() */ + #if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && !defined(_WIN32_WCE) /* MSC version 6 and above */ + #pragma comment( lib, "winmm.lib" ) + #endif #endif +#include "pa_util.h" /* Track memory allocations to avoid leaks. @@ -144,8 +147,14 @@ double PaUtil_GetTime( void ) } else { -#ifndef UNDER_CE +#ifndef UNDER_CE + #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) + struct _timeb tv = { 0 }; + _ftime_s(&tv); + return (double)tv.time + tv.millitm * .001; + #else return timeGetTime() * .001; + #endif #else return GetTickCount() * .001; #endif diff --git a/src/os/win/pa_win_waveformat.c b/src/os/win/pa_win_waveformat.c index c128c32..2e1c671 100644 --- a/src/os/win/pa_win_waveformat.c +++ b/src/os/win/pa_win_waveformat.c @@ -47,6 +47,37 @@ #define WAVE_FORMAT_EXTENSIBLE 0xFFFE #endif + +#if !defined(WAVE_FORMAT_PCM) +#define WAVE_FORMAT_PCM 1 +typedef struct tWAVEFORMAT +{ + WORD wFormatTag; + WORD nChannels; + DWORD nSamplesPerSec; + DWORD nAvgBytesPerSec; + WORD nBlockAlign; +} +WAVEFORMAT; +#endif + + +#if !defined(_WAVEFORMATEX_) +#define _WAVEFORMATEX_ +typedef struct tWAVEFORMATEX +{ + WORD wFormatTag; + WORD nChannels; + DWORD nSamplesPerSec; + DWORD nAvgBytesPerSec; + WORD nBlockAlign; + WORD wBitsPerSample; + WORD cbSize; +} +WAVEFORMATEX; +#endif + + static GUID pawin_ksDataFormatSubtypeGuidBase = { (USHORT)(WAVE_FORMAT_PCM), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }; From 26c0dc4458d7e3acd24c948f5e8355cf3d0ecba3 Mon Sep 17 00:00:00 2001 From: dmitrykos Date: Mon, 8 Aug 2016 21:09:15 +0300 Subject: [PATCH 2/7] wasapi: code cleanup, removed compiler warnings --- src/hostapi/wasapi/pa_win_wasapi.c | 99 +++++++++++++++++------------- src/os/win/pa_win_waveformat.c | 24 ++++---- 2 files changed, 68 insertions(+), 55 deletions(-) diff --git a/src/hostapi/wasapi/pa_win_wasapi.c b/src/hostapi/wasapi/pa_win_wasapi.c index 1f071fb..eab2a8c 100644 --- a/src/hostapi/wasapi/pa_win_wasapi.c +++ b/src/hostapi/wasapi/pa_win_wasapi.c @@ -130,7 +130,6 @@ #include #include #else - #ifndef WIN32_WINRT typedef struct _BYTE_BLOB { unsigned long clSize; @@ -139,7 +138,6 @@ typedef /* [unique] */ __RPC_unique_pointer BYTE_BLOB *UP_BYTE_BLOB; typedef LONGLONG REFERENCE_TIME; #define NONAMELESSUNION - #endif #endif #ifndef WAVE_FORMAT_IEEE_FLOAT @@ -170,6 +168,8 @@ // Missing declarations for WinRT #ifdef WIN32_WINRT + #define DEVICE_STATE_ACTIVE 0x00000001 + typedef enum _EDataFlow { eRender = 0, @@ -405,9 +405,6 @@ typedef struct PaWasapiDeviceInfo REFERENCE_TIME DefaultDevicePeriod; REFERENCE_TIME MinimumDevicePeriod; - // from GetMixFormat - // WAVEFORMATEX *MixFormat;//needs to be CoTaskMemFree'd after use! - // Default format (setup through Control Panel by user) WAVEFORMATEXTENSIBLE DefaultFormat; @@ -815,6 +812,7 @@ static UINT32 AlignFramesPerBuffer(UINT32 nFrames, UINT32 nSamplesPerSec, UINT32 long frame_bytes = nFrames * nBlockAlign; long packets; + (void)nSamplesPerSec; // align to packet size frame_bytes = pAlignFunc(frame_bytes, HDA_PACKET_SIZE); // use ALIGN_FWD if bigger but safer period is more desired @@ -1236,7 +1234,7 @@ static MixMonoToStereoF _GetMonoToStereoMixer(PaSampleFormat format, EMixerDir d // ------------------------------------------------------------------------------------------ #ifdef WIN32_WINRT -typedef struct _CActivateAudioInterfaceCompletionHandler +typedef struct PaActivateAudioInterfaceCompletionHandler { IActivateAudioInterfaceCompletionHandler parent; ULONG refs; @@ -1248,15 +1246,15 @@ typedef struct _CActivateAudioInterfaceCompletionHandler } out; } -CActivateAudioInterfaceCompletionHandler; +PaActivateAudioInterfaceCompletionHandler; -static HRESULT ( STDMETHODCALLTYPE CActivateAudioInterfaceCompletionHandler_QueryInterface )( +static HRESULT ( STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_QueryInterface )( IActivateAudioInterfaceCompletionHandler * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ _COM_Outptr_ void **ppvObject) { - CActivateAudioInterfaceCompletionHandler *handler = (CActivateAudioInterfaceCompletionHandler *)This; + PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This; // From MSDN: // "The IAgileObject interface is a marker interface that indicates that an object @@ -1271,17 +1269,17 @@ static HRESULT ( STDMETHODCALLTYPE CActivateAudioInterfaceCompletionHandler_Quer return S_FALSE; } -static ULONG ( STDMETHODCALLTYPE CActivateAudioInterfaceCompletionHandler_AddRef )( +static ULONG ( STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_AddRef )( IActivateAudioInterfaceCompletionHandler * This) { - CActivateAudioInterfaceCompletionHandler *handler = (CActivateAudioInterfaceCompletionHandler *)This; + PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This; return ++ handler->refs; } -static ULONG ( STDMETHODCALLTYPE CActivateAudioInterfaceCompletionHandler_Release )( +static ULONG ( STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Release )( IActivateAudioInterfaceCompletionHandler * This) { - CActivateAudioInterfaceCompletionHandler *handler = (CActivateAudioInterfaceCompletionHandler *)This; + PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This; if (handler->refs == 0) { PaUtil_FreeMemory(handler->parent.lpVtbl); @@ -1291,12 +1289,12 @@ static ULONG ( STDMETHODCALLTYPE CActivateAudioInterfaceCompletionHandler_Releas return -- handler->refs; } -static HRESULT ( STDMETHODCALLTYPE CActivateAudioInterfaceCompletionHandler_ActivateCompleted )( +static HRESULT ( STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_ActivateCompleted )( IActivateAudioInterfaceCompletionHandler * This, /* [annotation][in] */ _In_ IActivateAudioInterfaceAsyncOperation *activateOperation) { - CActivateAudioInterfaceCompletionHandler *handler = (CActivateAudioInterfaceCompletionHandler *)This; + PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This; HRESULT hr = S_OK; HRESULT hrActivateResult = S_OK; @@ -1324,13 +1322,13 @@ static HRESULT ( STDMETHODCALLTYPE CActivateAudioInterfaceCompletionHandler_Acti static IActivateAudioInterfaceCompletionHandler *CreateActivateAudioInterfaceCompletionHandler() { - CActivateAudioInterfaceCompletionHandler *handler = PaUtil_AllocateMemory(sizeof(CActivateAudioInterfaceCompletionHandler)); + PaActivateAudioInterfaceCompletionHandler *handler = PaUtil_AllocateMemory(sizeof(PaActivateAudioInterfaceCompletionHandler)); ZeroMemory(handler, sizeof(*handler)); handler->parent.lpVtbl = PaUtil_AllocateMemory(sizeof(*handler->parent.lpVtbl)); - handler->parent.lpVtbl->QueryInterface = &CActivateAudioInterfaceCompletionHandler_QueryInterface; - handler->parent.lpVtbl->AddRef = &CActivateAudioInterfaceCompletionHandler_AddRef; - handler->parent.lpVtbl->Release = &CActivateAudioInterfaceCompletionHandler_Release; - handler->parent.lpVtbl->ActivateCompleted = &CActivateAudioInterfaceCompletionHandler_ActivateCompleted; + handler->parent.lpVtbl->QueryInterface = &PaActivateAudioInterfaceCompletionHandler_QueryInterface; + handler->parent.lpVtbl->AddRef = &PaActivateAudioInterfaceCompletionHandler_AddRef; + handler->parent.lpVtbl->Release = &PaActivateAudioInterfaceCompletionHandler_Release; + handler->parent.lpVtbl->ActivateCompleted = &PaActivateAudioInterfaceCompletionHandler_ActivateCompleted; return (IActivateAudioInterfaceCompletionHandler *)handler; } #endif @@ -1339,22 +1337,23 @@ static IActivateAudioInterfaceCompletionHandler *CreateActivateAudioInterfaceCom #ifdef WIN32_WINRT static HRESULT ActivateAudioInterface_WINRT(const PaWasapiDeviceInfo *deviceInfo, IAudioClient **client) { +#define PA_WASAPI_DEVICE_PATH_LEN 64 + PaError result = paNoError; HRESULT hr = S_OK; - HRESULT activateResult = S_OK; IActivateAudioInterfaceAsyncOperation *asyncOp = NULL; IActivateAudioInterfaceCompletionHandler *handler = CreateActivateAudioInterfaceCompletionHandler(); - CActivateAudioInterfaceCompletionHandler *ñhandler = (CActivateAudioInterfaceCompletionHandler *)handler; - OLECHAR devicePath[64] = { 0 }; + PaActivateAudioInterfaceCompletionHandler *handlerImpl = (PaActivateAudioInterfaceCompletionHandler *)handler; + OLECHAR devicePath[PA_WASAPI_DEVICE_PATH_LEN] = { 0 }; // Get device path in form L"{DEVICE_GUID}" switch (deviceInfo->flow) { case eRender: - StringFromGUID2(&DEVINTERFACE_AUDIO_RENDER, devicePath, 63); + StringFromGUID2(&DEVINTERFACE_AUDIO_RENDER, devicePath, PA_WASAPI_DEVICE_PATH_LEN - 1); break; case eCapture: - StringFromGUID2(&DEVINTERFACE_AUDIO_CAPTURE, devicePath, 63); + StringFromGUID2(&DEVINTERFACE_AUDIO_CAPTURE, devicePath, PA_WASAPI_DEVICE_PATH_LEN - 1); break; default: return S_FALSE; @@ -1366,13 +1365,13 @@ static HRESULT ActivateAudioInterface_WINRT(const PaWasapiDeviceInfo *deviceInfo IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); // Wait in busy loop for async operation to complete - while (SUCCEEDED(hr) && !ñhandler->done) + while (SUCCEEDED(hr) && !handlerImpl->done) { Pa_Sleep(1); } - (*client) = ñhandler->out.client; - hr = ñhandler->out.hr; + (*client) = handlerImpl->out.client; + hr = handlerImpl->out.hr; error: @@ -1380,6 +1379,8 @@ error: SAFE_RELEASE(handler); return hr; + +#undef PA_WASAPI_DEVICE_PATH_LEN } #endif @@ -1414,11 +1415,12 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd PaWasapiHostApiRepresentation *paWasapi; PaDeviceInfo *deviceInfoArray; HRESULT hr = S_OK; + UINT i; #ifndef WIN32_WINRT IMMDeviceCollection* pEndPoints = NULL; -#endif - UINT i; +#else WAVEFORMATEX *mixFormat; +#endif #ifndef WIN32_WINRT if (!SetupAVRT()) @@ -1562,7 +1564,6 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd for (i = 0; i < paWasapi->deviceCount; ++i) { - DWORD state = 0; PaDeviceInfo *deviceInfo = &deviceInfoArray[i]; deviceInfo->structVersion = 2; deviceInfo->hostApi = hostApiIndex; @@ -1603,7 +1604,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd if (paWasapi->devInfo[i].state != DEVICE_STATE_ACTIVE) { - PRINT(("WASAPI device: %d is not currently available (state:%d)\n",i,state)); + PRINT(("WASAPI device: %d is not currently available (state:%d)\n", i, paWasapi->devInfo[i].state)); } { @@ -1630,9 +1631,9 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd goto error; } if (value.pwszVal) - WideCharToMultiByte(CP_UTF8, 0, value.pwszVal, (int)wcslen(value.pwszVal), deviceName, MAX_STR_LEN-1, 0, 0); + WideCharToMultiByte(CP_UTF8, 0, value.pwszVal, (int)wcslen(value.pwszVal), deviceName, MAX_STR_LEN - 1, 0, 0); else - _snprintf(deviceName, MAX_STR_LEN-1, "baddev%d", i); + _snprintf(deviceName, MAX_STR_LEN - 1, "baddev%d", i); deviceInfo->name = deviceName; PropVariantClear(&value); PA_DEBUG(("WASAPI:%d| name[%s]\n", i, deviceInfo->name)); @@ -1700,6 +1701,8 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd // Create temp Audio Client instance to query additional details IAudioClient *tmpClient = NULL; hr = ActivateAudioInterface(&paWasapi->devInfo[i], &tmpClient); + // We need to set the result to a value otherwise we will return paNoError + // [IF_FAILED_JUMP(hResult, error);] IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); // Get latency @@ -1730,7 +1733,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount; // State - paWasapi->devInfo[i].state = 1; // DEVICE_STATE_ACTIVE + paWasapi->devInfo[i].state = DEVICE_STATE_ACTIVE; // Default format memcpy(&paWasapi->devInfo[i].DefaultFormat, mixFormat, min(sizeof(paWasapi->devInfo[i].DefaultFormat), sizeof(*mixFormat))); @@ -1740,14 +1743,14 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd paWasapi->devInfo[i].formFactor = UnknownFormFactor; // Name - deviceInfo->name = PaUtil_GroupAllocateMemory(paWasapi->allocations, MAX_STR_LEN + 1); + deviceInfo->name = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, MAX_STR_LEN + 1); if (deviceInfo->name == NULL) { SAFE_RELEASE(tmpClient); result = paInsufficientMemory; goto error; } - _snprintf(deviceInfo->name, MAX_STR_LEN - 1, "WASAPI_%s:%d", (i == 0 ? "Output" : "Input"), i); + _snprintf((char *)deviceInfo->name, MAX_STR_LEN - 1, "WASAPI_%s:%d", (i == 0 ? "Output" : "Input"), i); PA_DEBUG(("WASAPI:%d| name[%s]\n", i, deviceInfo->name)); } #endif @@ -1858,15 +1861,15 @@ static void Terminate( PaUtilHostApiRepresentation *hostApi ) SAFE_RELEASE(paWasapi->enumerator); #endif + // Release device info bound objects and device info itself for (i = 0; i < paWasapi->deviceCount; ++i) { PaWasapiDeviceInfo *info = &paWasapi->devInfo[i]; #ifndef WIN32_WINRT SAFE_RELEASE(info->device); + #else + (void)info; #endif - - //if (info->MixFormat) - // CoTaskMemFree(info->MixFormat); } PaUtil_FreeMemory(paWasapi->devInfo); @@ -2211,6 +2214,7 @@ static PaError GetClosestFormat(IAudioClient *myClient, double sampleRate, WAVEFORMATEX *sharedClosestMatch = NULL; HRESULT hr = !S_OK; PaStreamParameters params = (*_params); + (void)output; /* It was not noticed that 24-bit Input producing no output while device accepts this format. To fix this issue let's ask for 32-bits and let PA converters convert host 32-bit data @@ -2552,7 +2556,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu const PaStreamParameters *params = &pSub->params.stream_params; UINT32 framesPerLatency = pSub->params.frames_per_buffer; double sampleRate = pSub->params.sample_rate; - BOOL blocking = pSub->params.blocking; + //BOOL blocking = pSub->params.blocking; BOOL fullDuplex = pSub->params.full_duplex; const UINT32 userFramesPerBuffer = framesPerLatency; @@ -3558,6 +3562,7 @@ HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream) return hFirstBadResult; #else + (void)substream; return S_OK; #endif } @@ -3678,6 +3683,7 @@ marshal_sub_error: ReleaseUnmarshaledSubComPointers(substream); return hResult; #else + (void)substream; return S_OK; #endif } @@ -3727,6 +3733,7 @@ marshal_error: ReleaseUnmarshaledComPointers(stream); return hResult; #else + (void)stream; return S_OK; #endif } @@ -4436,6 +4443,7 @@ HANDLE MMCSS_activate(const char *name) return hTask; #else + (void)name; return NULL; #endif } @@ -4572,6 +4580,8 @@ error: LogHostError(hr); return paNoError; #else + (void)nDevice; + (void)jcount; return paUnanticipatedHostError; #endif } @@ -4749,6 +4759,9 @@ error: return ret; #else + (void)nDevice; + (void)jindex; + (void)pJackDescription; return paUnanticipatedHostError; #endif } @@ -4975,7 +4988,7 @@ PA_THREAD_FUNC ProcThreadEvent(void *param) if (FAILED(hr) && (hr != RPC_E_CHANGED_MODE)) { PRINT(("WASAPI: failed ProcThreadEvent CoInitialize")); - return paUnanticipatedHostError; + return (UINT32)paUnanticipatedHostError; } if (hr != RPC_E_CHANGED_MODE) bThreadComInitialized = TRUE; @@ -5182,7 +5195,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param) if (FAILED(hr) && (hr != RPC_E_CHANGED_MODE)) { PRINT(("WASAPI: failed ProcThreadPoll CoInitialize")); - return paUnanticipatedHostError; + return (UINT32)paUnanticipatedHostError; } if (hr != RPC_E_CHANGED_MODE) bThreadComInitialized = TRUE; diff --git a/src/os/win/pa_win_waveformat.c b/src/os/win/pa_win_waveformat.c index 2e1c671..afb3648 100644 --- a/src/os/win/pa_win_waveformat.c +++ b/src/os/win/pa_win_waveformat.c @@ -52,11 +52,11 @@ #define WAVE_FORMAT_PCM 1 typedef struct tWAVEFORMAT { - WORD wFormatTag; - WORD nChannels; - DWORD nSamplesPerSec; - DWORD nAvgBytesPerSec; - WORD nBlockAlign; + WORD wFormatTag; + WORD nChannels; + DWORD nSamplesPerSec; + DWORD nAvgBytesPerSec; + WORD nBlockAlign; } WAVEFORMAT; #endif @@ -66,13 +66,13 @@ WAVEFORMAT; #define _WAVEFORMATEX_ typedef struct tWAVEFORMATEX { - WORD wFormatTag; - WORD nChannels; - DWORD nSamplesPerSec; - DWORD nAvgBytesPerSec; - WORD nBlockAlign; - WORD wBitsPerSample; - WORD cbSize; + WORD wFormatTag; + WORD nChannels; + DWORD nSamplesPerSec; + DWORD nAvgBytesPerSec; + WORD nBlockAlign; + WORD wBitsPerSample; + WORD cbSize; } WAVEFORMATEX; #endif From 326549c55ee09bcb3cd95540d870540aefc43c3d Mon Sep 17 00:00:00 2001 From: dmitrykos Date: Sun, 14 Aug 2016 10:52:36 +0300 Subject: [PATCH 3/7] wasapi: use Windows common Sleep() API instead of PA_Sleep() use GetTickCount64() API which is awailable for Windows Store app instead of _ftime_s() remove WAVEFORMAT and WAVEFORMATEX declaration and use the corresponding Windows include file instead --- src/hostapi/wasapi/pa_win_wasapi.c | 4 ++-- src/os/win/pa_win_util.c | 4 +--- src/os/win/pa_win_waveformat.c | 33 +++--------------------------- 3 files changed, 6 insertions(+), 35 deletions(-) diff --git a/src/hostapi/wasapi/pa_win_wasapi.c b/src/hostapi/wasapi/pa_win_wasapi.c index eab2a8c..789c635 100644 --- a/src/hostapi/wasapi/pa_win_wasapi.c +++ b/src/hostapi/wasapi/pa_win_wasapi.c @@ -1367,7 +1367,7 @@ static HRESULT ActivateAudioInterface_WINRT(const PaWasapiDeviceInfo *deviceInfo // Wait in busy loop for async operation to complete while (SUCCEEDED(hr) && !handlerImpl->done) { - Pa_Sleep(1); + Sleep(1); } (*client) = handlerImpl->out.client; @@ -4084,7 +4084,7 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long frames ) { if ((sleep = ThreadIdleScheduler_NextSleep(&sched)) != 0) { - Pa_Sleep(sleep); + Sleep(sleep); sleep = 0; } } diff --git a/src/os/win/pa_win_util.c b/src/os/win/pa_win_util.c index 2de7684..1cd3525 100644 --- a/src/os/win/pa_win_util.c +++ b/src/os/win/pa_win_util.c @@ -149,9 +149,7 @@ double PaUtil_GetTime( void ) { #ifndef UNDER_CE #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) - struct _timeb tv = { 0 }; - _ftime_s(&tv); - return (double)tv.time + tv.millitm * .001; + return GetTickCount64() * .001; #else return timeGetTime() * .001; #endif diff --git a/src/os/win/pa_win_waveformat.c b/src/os/win/pa_win_waveformat.c index afb3648..bd5addd 100644 --- a/src/os/win/pa_win_waveformat.c +++ b/src/os/win/pa_win_waveformat.c @@ -38,6 +38,9 @@ #include #include +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) + #include /* for WAVEFORMATEX */ +#endif #include "portaudio.h" #include "pa_win_waveformat.h" @@ -48,36 +51,6 @@ #endif -#if !defined(WAVE_FORMAT_PCM) -#define WAVE_FORMAT_PCM 1 -typedef struct tWAVEFORMAT -{ - WORD wFormatTag; - WORD nChannels; - DWORD nSamplesPerSec; - DWORD nAvgBytesPerSec; - WORD nBlockAlign; -} -WAVEFORMAT; -#endif - - -#if !defined(_WAVEFORMATEX_) -#define _WAVEFORMATEX_ -typedef struct tWAVEFORMATEX -{ - WORD wFormatTag; - WORD nChannels; - DWORD nSamplesPerSec; - DWORD nAvgBytesPerSec; - WORD nBlockAlign; - WORD wBitsPerSample; - WORD cbSize; -} -WAVEFORMATEX; -#endif - - static GUID pawin_ksDataFormatSubtypeGuidBase = { (USHORT)(WAVE_FORMAT_PCM), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }; From ef449bb5bff4fb8d8219984d515628469b65dc3e Mon Sep 17 00:00:00 2001 From: dmitrykos Date: Sun, 14 Aug 2016 19:01:20 +0300 Subject: [PATCH 4/7] wasapi: more cleanup - normalized WIN32_WINRT to PA_WINRT, removed excessive declarations from SignalObjectAndWait, ActivateAudioInterfaceCompletionHandler set of functions --- src/hostapi/wasapi/pa_win_wasapi.c | 106 +++++++++++++---------------- 1 file changed, 48 insertions(+), 58 deletions(-) diff --git a/src/hostapi/wasapi/pa_win_wasapi.c b/src/hostapi/wasapi/pa_win_wasapi.c index 789c635..4564826 100644 --- a/src/hostapi/wasapi/pa_win_wasapi.c +++ b/src/hostapi/wasapi/pa_win_wasapi.c @@ -49,7 +49,7 @@ // WinRT #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) - #define WIN32_WINRT + #define PA_WINRT #define INITGUID #endif @@ -166,7 +166,7 @@ #endif // NTDDI_VERSION // Missing declarations for WinRT -#ifdef WIN32_WINRT +#ifdef PA_WINRT #define DEVICE_STATE_ACTIVE 0x00000001 @@ -310,7 +310,7 @@ enum { WASAPI_PACKETS_PER_INPUT_BUFFER = 6 }; typedef void (*MixMonoToStereoF) (void *__to, void *__from, UINT32 count); // AVRT is the new "multimedia schedulling stuff" -#ifndef WIN32_WINRT +#ifndef PA_WINRT typedef BOOL (WINAPI *FAvRtCreateThreadOrderingGroup) (PHANDLE,PLARGE_INTEGER,GUID*,PLARGE_INTEGER); typedef BOOL (WINAPI *FAvRtDeleteThreadOrderingGroup) (HANDLE); typedef BOOL (WINAPI *FAvRtWaitOnThreadOrderingGroup) (HANDLE); @@ -390,7 +390,7 @@ static signed long GetStreamWriteAvailable( PaStream* stream ); typedef struct PaWasapiDeviceInfo { // Device -#ifndef WIN32_WINRT +#ifndef PA_WINRT IMMDevice *device; #endif @@ -431,7 +431,7 @@ typedef struct PaWinUtilComInitializationResult comInitializationResult; //in case we later need the synch -#ifndef WIN32_WINRT +#ifndef PA_WINRT IMMDeviceEnumerator *enumerator; #endif @@ -468,7 +468,7 @@ PaWasapiAudioClientParams; typedef struct PaWasapiSubStream { IAudioClient *clientParent; -#ifndef WIN32_WINRT +#ifndef PA_WINRT IStream *clientStream; #endif IAudioClient *clientProc; @@ -520,7 +520,7 @@ typedef struct PaWasapiStream // input PaWasapiSubStream in; IAudioCaptureClient *captureClientParent; -#ifndef WIN32_WINRT +#ifndef PA_WINRT IStream *captureClientStream; #endif IAudioCaptureClient *captureClient; @@ -529,7 +529,7 @@ typedef struct PaWasapiStream // output PaWasapiSubStream out; IAudioRenderClient *renderClientParent; -#ifndef WIN32_WINRT +#ifndef PA_WINRT IStream *renderClientStream; #endif IAudioRenderClient *renderClient; @@ -859,7 +859,7 @@ static UINT32 GetFramesSleepTimeMicroseconds(UINT32 nFrames, UINT32 nSamplesPerS } // ------------------------------------------------------------------------------------------ -#ifndef WIN32_WINRT +#ifndef PA_WINRT static BOOL SetupAVRT() { hDInputDLL = LoadLibraryA("avrt.dll"); @@ -885,7 +885,7 @@ static BOOL SetupAVRT() // ------------------------------------------------------------------------------------------ static void CloseAVRT() { -#ifndef WIN32_WINRT +#ifndef PA_WINRT if (hDInputDLL != NULL) FreeLibrary(hDInputDLL); hDInputDLL = NULL; @@ -895,7 +895,7 @@ static void CloseAVRT() // ------------------------------------------------------------------------------------------ static BOOL IsWow64() { -#ifndef WIN32_WINRT +#ifndef PA_WINRT // http://msdn.microsoft.com/en-us/library/ms684139(VS.85).aspx @@ -939,7 +939,7 @@ typedef enum EWindowsVersion } EWindowsVersion; // Alternative way for checking Windows version (allows to check version on Windows 8.1 and up) -#ifndef WIN32_WINRT +#ifndef PA_WINRT static BOOL IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor) { typedef ULONGLONG (NTAPI *LPFN_VERSETCONDITIONMASK)(ULONGLONG ConditionMask, DWORD TypeMask, BYTE Condition); @@ -973,7 +973,7 @@ static BOOL IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WO // Get Windows version static EWindowsVersion GetWindowsVersion() { -#ifndef WIN32_WINRT +#ifndef PA_WINRT static EWindowsVersion version = WINDOWS_UNKNOWN; if (version == WINDOWS_UNKNOWN) @@ -1233,7 +1233,7 @@ static MixMonoToStereoF _GetMonoToStereoMixer(PaSampleFormat format, EMixerDir d } // ------------------------------------------------------------------------------------------ -#ifdef WIN32_WINRT +#ifdef PA_WINRT typedef struct PaActivateAudioInterfaceCompletionHandler { IActivateAudioInterfaceCompletionHandler parent; @@ -1248,11 +1248,8 @@ typedef struct PaActivateAudioInterfaceCompletionHandler } PaActivateAudioInterfaceCompletionHandler; -static HRESULT ( STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_QueryInterface )( - IActivateAudioInterfaceCompletionHandler * This, - /* [in] */ REFIID riid, - /* [annotation][iid_is][out] */ - _COM_Outptr_ void **ppvObject) +static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_QueryInterface)( + IActivateAudioInterfaceCompletionHandler *This, REFIID riid, void **ppvObject) { PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This; @@ -1269,15 +1266,15 @@ static HRESULT ( STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Que return S_FALSE; } -static ULONG ( STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_AddRef )( - IActivateAudioInterfaceCompletionHandler * This) +static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_AddRef)( + IActivateAudioInterfaceCompletionHandler *This) { PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This; return ++ handler->refs; } -static ULONG ( STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Release )( - IActivateAudioInterfaceCompletionHandler * This) +static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Release)( + IActivateAudioInterfaceCompletionHandler *This) { PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This; if (handler->refs == 0) @@ -1289,10 +1286,8 @@ static ULONG ( STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Relea return -- handler->refs; } -static HRESULT ( STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_ActivateCompleted )( - IActivateAudioInterfaceCompletionHandler * This, - /* [annotation][in] */ - _In_ IActivateAudioInterfaceAsyncOperation *activateOperation) +static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_ActivateCompleted)( + IActivateAudioInterfaceCompletionHandler *This, IActivateAudioInterfaceAsyncOperation *activateOperation) { PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This; @@ -1334,7 +1329,7 @@ static IActivateAudioInterfaceCompletionHandler *CreateActivateAudioInterfaceCom #endif // ------------------------------------------------------------------------------------------ -#ifdef WIN32_WINRT +#ifdef PA_WINRT static HRESULT ActivateAudioInterface_WINRT(const PaWasapiDeviceInfo *deviceInfo, IAudioClient **client) { #define PA_WASAPI_DEVICE_PATH_LEN 64 @@ -1387,7 +1382,7 @@ error: // ------------------------------------------------------------------------------------------ static HRESULT ActivateAudioInterface(const PaWasapiDeviceInfo *deviceInfo, IAudioClient **client) { -#ifndef WIN32_WINRT +#ifndef PA_WINRT return IMMDevice_Activate(deviceInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void **)client); #else return ActivateAudioInterface_WINRT(deviceInfo, client); @@ -1395,13 +1390,8 @@ static HRESULT ActivateAudioInterface(const PaWasapiDeviceInfo *deviceInfo, IAud } // ------------------------------------------------------------------------------------------ -#ifdef WIN32_WINRT -static DWORD SignalObjectAndWait( - _In_ HANDLE hObjectToSignal, - _In_ HANDLE hObjectToWaitOn, - _In_ DWORD dwMilliseconds, - _In_ BOOL bAlertable -) +#ifdef PA_WINRT +static DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable) { SetEvent(hObjectToSignal); return WaitForSingleObjectEx(hObjectToWaitOn, dwMilliseconds, bAlertable); @@ -1416,13 +1406,13 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd PaDeviceInfo *deviceInfoArray; HRESULT hr = S_OK; UINT i; -#ifndef WIN32_WINRT +#ifndef PA_WINRT IMMDeviceCollection* pEndPoints = NULL; #else WAVEFORMATEX *mixFormat; #endif -#ifndef WIN32_WINRT +#ifndef PA_WINRT if (!SetupAVRT()) { PRINT(("WASAPI: No AVRT! (not VISTA?)")); @@ -1460,7 +1450,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd (*hostApi)->info.defaultInputDevice = paNoDevice; (*hostApi)->info.defaultOutputDevice = paNoDevice; -#ifndef WIN32_WINRT +#ifndef PA_WINRT paWasapi->enumerator = NULL; hr = CoCreateInstance(&pa_CLSID_IMMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &pa_IID_IMMDeviceEnumerator, (void **)&paWasapi->enumerator); @@ -1571,7 +1561,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd PA_DEBUG(("WASAPI: device idx: %02d\n", i)); PA_DEBUG(("WASAPI: ---------------\n")); - #ifndef WIN32_WINRT + #ifndef PA_WINRT hr = IMMDeviceCollection_Item(pEndPoints, i, &paWasapi->devInfo[i].device); // We need to set the result to a value otherwise we will return paNoError // [IF_FAILED_JUMP(hResult, error);] @@ -1692,7 +1682,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd // Getting a temporary IAudioClient for more fields // we make sure NOT to call Initialize yet! { - #ifdef WIN32_WINRT + #ifdef PA_WINRT // Set flow as ActivateAudioInterface depends on it and selects corresponding // direction for the Audio Client paWasapi->devInfo[i].flow = (i == 0 ? eRender : eCapture); @@ -1721,7 +1711,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd hr = S_OK; } - #ifdef WIN32_WINRT + #ifdef PA_WINRT // Get mix format which will treat as default device format hr = IAudioClient_GetMixFormat(tmpClient, &mixFormat); if (SUCCEEDED(hr)) @@ -1822,7 +1812,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd // findout if platform workaround is required paWasapi->useWOW64Workaround = UseWOW64Workaround(); -#ifndef WIN32_WINRT +#ifndef PA_WINRT SAFE_RELEASE(pEndPoints); #endif @@ -1834,7 +1824,7 @@ error: PRINT(("WASAPI: failed %s error[%d|%s]\n", __FUNCTION__, result, Pa_GetErrorText(result))); -#ifndef WIN32_WINRT +#ifndef PA_WINRT SAFE_RELEASE(pEndPoints); #endif @@ -1857,7 +1847,7 @@ static void Terminate( PaUtilHostApiRepresentation *hostApi ) return; // Release IMMDeviceEnumerator -#ifndef WIN32_WINRT +#ifndef PA_WINRT SAFE_RELEASE(paWasapi->enumerator); #endif @@ -1865,7 +1855,7 @@ static void Terminate( PaUtilHostApiRepresentation *hostApi ) for (i = 0; i < paWasapi->deviceCount; ++i) { PaWasapiDeviceInfo *info = &paWasapi->devInfo[i]; - #ifndef WIN32_WINRT + #ifndef PA_WINRT SAFE_RELEASE(info->device); #else (void)info; @@ -3546,7 +3536,7 @@ static PaError CloseStream( PaStream* s ) // ------------------------------------------------------------------------------------------ HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream) { -#ifndef WIN32_WINRT +#ifndef PA_WINRT HRESULT hResult = S_OK; HRESULT hFirstBadResult = S_OK; substream->clientProc = NULL; @@ -3570,7 +3560,7 @@ HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream) // ------------------------------------------------------------------------------------------ HRESULT UnmarshalStreamComPointers(PaWasapiStream *stream) { -#ifndef WIN32_WINRT +#ifndef PA_WINRT HRESULT hResult = S_OK; HRESULT hFirstBadResult = S_OK; stream->captureClient = NULL; @@ -3665,7 +3655,7 @@ void ReleaseUnmarshaledComPointers(PaWasapiStream *stream) // ------------------------------------------------------------------------------------------ HRESULT MarshalSubStreamComPointers(PaWasapiSubStream *substream) { -#ifndef WIN32_WINRT +#ifndef PA_WINRT HRESULT hResult; substream->clientStream = NULL; @@ -3691,7 +3681,7 @@ marshal_sub_error: // ------------------------------------------------------------------------------------------ HRESULT MarshalStreamComPointers(PaWasapiStream *stream) { -#ifndef WIN32_WINRT +#ifndef PA_WINRT HRESULT hResult = S_OK; stream->captureClientStream = NULL; stream->in.clientStream = NULL; @@ -4420,7 +4410,7 @@ static void WaspiHostProcessingLoop( void *inputBuffer, long inputFrames, // ------------------------------------------------------------------------------------------ HANDLE MMCSS_activate(const char *name) { -#ifndef WIN32_WINRT +#ifndef PA_WINRT DWORD task_idx = 0; HANDLE hTask = pAvSetMmThreadCharacteristics(name, &task_idx); if (hTask == NULL) @@ -4454,7 +4444,7 @@ void MMCSS_deactivate(HANDLE hTask) if (!hTask) return; -#ifndef WIN32_WINRT +#ifndef PA_WINRT if (pAvRevertMmThreadCharacteristics(hTask) == FALSE) { PRINT(("WASAPI: AvRevertMmThreadCharacteristics failed!\n")); @@ -4509,7 +4499,7 @@ PaError PaWasapi_ThreadPriorityRevert(void *hTask) PaError PaWasapi_GetJackCount(PaDeviceIndex nDevice, int *jcount) { -#ifndef WIN32_WINRT +#ifndef PA_WINRT PaError ret; HRESULT hr = S_OK; PaDeviceIndex index; @@ -4587,7 +4577,7 @@ error: } // ------------------------------------------------------------------------------------------ -#ifndef WIN32_WINRT +#ifndef PA_WINRT static PaWasapiJackConnectionType ConvertJackConnectionTypeWASAPIToPA(int connType) { switch (connType) @@ -4614,7 +4604,7 @@ static PaWasapiJackConnectionType ConvertJackConnectionTypeWASAPIToPA(int connTy #endif // ------------------------------------------------------------------------------------------ -#ifndef WIN32_WINRT +#ifndef PA_WINRT static PaWasapiJackGeoLocation ConvertJackGeoLocationWASAPIToPA(int geoLoc) { switch (geoLoc) @@ -4642,7 +4632,7 @@ static PaWasapiJackGeoLocation ConvertJackGeoLocationWASAPIToPA(int geoLoc) #endif // ------------------------------------------------------------------------------------------ -#ifndef WIN32_WINRT +#ifndef PA_WINRT static PaWasapiJackGenLocation ConvertJackGenLocationWASAPIToPA(int genLoc) { switch (genLoc) @@ -4661,7 +4651,7 @@ static PaWasapiJackGenLocation ConvertJackGenLocationWASAPIToPA(int genLoc) #endif // ------------------------------------------------------------------------------------------ -#ifndef WIN32_WINRT +#ifndef PA_WINRT static PaWasapiJackPortConnection ConvertJackPortConnectionWASAPIToPA(int portConn) { switch (portConn) @@ -4681,7 +4671,7 @@ static PaWasapiJackPortConnection ConvertJackPortConnectionWASAPIToPA(int portCo PaError PaWasapi_GetJackDescription(PaDeviceIndex nDevice, int jindex, PaWasapiJackDescription *pJackDescription) { -#ifndef WIN32_WINRT +#ifndef PA_WINRT PaError ret; HRESULT hr = S_OK; PaDeviceIndex index; From 46bce3c39fac3c747e41adb89607b4487b047f18 Mon Sep 17 00:00:00 2001 From: dmitrykos Date: Wed, 24 Aug 2016 22:04:17 +0300 Subject: [PATCH 5/7] wasapi: use InterlockedXXX APIs to secure inter-thread r/w access to variables to avoid possible deadlocks or logic corruption --- src/hostapi/wasapi/pa_win_wasapi.c | 64 ++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/src/hostapi/wasapi/pa_win_wasapi.c b/src/hostapi/wasapi/pa_win_wasapi.c index 4564826..367b87d 100644 --- a/src/hostapi/wasapi/pa_win_wasapi.c +++ b/src/hostapi/wasapi/pa_win_wasapi.c @@ -543,7 +543,7 @@ typedef struct PaWasapiStream // must be volatile to avoid race condition on user query while // thread is being started - volatile BOOL running; + volatile LONG running; PA_THREAD_ID dwThreadId; HANDLE hThread; @@ -1237,8 +1237,8 @@ static MixMonoToStereoF _GetMonoToStereoMixer(PaSampleFormat format, EMixerDir d typedef struct PaActivateAudioInterfaceCompletionHandler { IActivateAudioInterfaceCompletionHandler parent; - ULONG refs; - volatile BOOL done; + volatile LONG refs; + volatile LONG done; struct { HRESULT hr; @@ -1256,7 +1256,8 @@ static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Quer // From MSDN: // "The IAgileObject interface is a marker interface that indicates that an object // is free threaded and can be called from any apartment." - if (IsEqualIID(riid, &IID_IAgileObject)) + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IAgileObject)) { handler->parent.lpVtbl->AddRef((IActivateAudioInterfaceCompletionHandler *)handler); (*ppvObject) = handler; @@ -1270,20 +1271,23 @@ static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_AddRef IActivateAudioInterfaceCompletionHandler *This) { PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This; - return ++ handler->refs; + + return InterlockedIncrement(&handler->refs); } static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Release)( IActivateAudioInterfaceCompletionHandler *This) { PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This; - if (handler->refs == 0) + ULONG refs; + + if ((refs = InterlockedDecrement(&handler->refs)) == 0) { PaUtil_FreeMemory(handler->parent.lpVtbl); PaUtil_FreeMemory(handler); - return 0; } - return -- handler->refs; + + return refs; } static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_ActivateCompleted)( @@ -1311,7 +1315,9 @@ static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Acti else handler->out.hr = hr; - handler->done = TRUE; + // Got client object, stop busy waiting in ActivateAudioInterface_WINRT + InterlockedExchange(&handler->done, TRUE); + return hr; } @@ -1324,6 +1330,7 @@ static IActivateAudioInterfaceCompletionHandler *CreateActivateAudioInterfaceCom handler->parent.lpVtbl->AddRef = &PaActivateAudioInterfaceCompletionHandler_AddRef; handler->parent.lpVtbl->Release = &PaActivateAudioInterfaceCompletionHandler_Release; handler->parent.lpVtbl->ActivateCompleted = &PaActivateAudioInterfaceCompletionHandler_ActivateCompleted; + handler->refs = 1; return (IActivateAudioInterfaceCompletionHandler *)handler; } #endif @@ -1360,7 +1367,7 @@ static HRESULT ActivateAudioInterface_WINRT(const PaWasapiDeviceInfo *deviceInfo IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); // Wait in busy loop for async operation to complete - while (SUCCEEDED(hr) && !handlerImpl->done) + while (SUCCEEDED(hr) && !InterlockedCompareExchange(&handlerImpl->done, FALSE, FALSE)) { Sleep(1); } @@ -3849,7 +3856,7 @@ static PaError StartStream( PaStream *s ) stream->out.clientProc = stream->out.clientParent; // Signal: stream running. - stream->running = TRUE; + InterlockedExchange(&stream->running, TRUE); } return result; @@ -3891,7 +3898,8 @@ void _StreamFinish(PaWasapiStream *stream) // Cleanup handles _StreamCleanup(stream); - stream->running = FALSE; + // Notify: not running + InterlockedExchange(&stream->running, FALSE); } // ------------------------------------------------------------------------------------------ @@ -3906,6 +3914,18 @@ void _StreamCleanup(PaWasapiStream *stream) SAFE_CLOSE(stream->hBlockingOpStreamWR); } +// ------------------------------------------------------------------------------------------ +static BOOL _IsStreamRunning(PaWasapiStream *stream) +{ + LONG retv; + do + { + retv = stream->running; + } + while (InterlockedCompareExchange(&stream->running, FALSE, FALSE) != retv); + return retv; +} + // ------------------------------------------------------------------------------------------ static PaError StopStream( PaStream *s ) { @@ -3925,13 +3945,13 @@ static PaError AbortStream( PaStream *s ) // ------------------------------------------------------------------------------------------ static PaError IsStreamStopped( PaStream *s ) { - return !((PaWasapiStream *)s)->running; + return !_IsStreamRunning((PaWasapiStream *)s); } // ------------------------------------------------------------------------------------------ static PaError IsStreamActive( PaStream *s ) { - return ((PaWasapiStream *)s)->running; + return _IsStreamRunning((PaWasapiStream *)s); } // ------------------------------------------------------------------------------------------ @@ -3965,7 +3985,7 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long frames ) ThreadIdleScheduler sched; // validate - if (!stream->running) + if (!_IsStreamRunning(stream)) return paStreamIsStopped; if (stream->captureClient == NULL) return paBadStreamPtr; @@ -4144,7 +4164,7 @@ static PaError WriteStream( PaStream* s, const void *_buffer, unsigned long fram ThreadIdleScheduler sched; // validate - if (!stream->running) + if (!_IsStreamRunning(stream)) return paStreamIsStopped; if (stream->renderClient == NULL) return paBadStreamPtr; @@ -4258,7 +4278,7 @@ static signed long GetStreamReadAvailable( PaStream* s ) UINT32 available = 0; // validate - if (!stream->running) + if (!_IsStreamRunning(stream)) return paStreamIsStopped; if (stream->captureClient == NULL) return paBadStreamPtr; @@ -4284,7 +4304,7 @@ static signed long GetStreamWriteAvailable( PaStream* s ) UINT32 available = 0; // validate - if (!stream->running) + if (!_IsStreamRunning(stream)) return paStreamIsStopped; if (stream->renderClient == NULL) return paBadStreamPtr; @@ -5074,7 +5094,7 @@ PA_THREAD_FUNC ProcThreadEvent(void *param) } // Signal: stream running - stream->running = TRUE; + InterlockedExchange(&stream->running, TRUE); // Notify: thread started SetEvent(stream->hThreadStart); @@ -5141,7 +5161,7 @@ thread_end: CoUninitialize(); // Notify: not running - stream->running = FALSE; + InterlockedExchange(&stream->running, FALSE); // Notify: thread exited SetEvent(stream->hThreadExit); @@ -5308,7 +5328,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param) } // Signal: stream running - stream->running = TRUE; + InterlockedExchange(&stream->running, TRUE); // Notify: thread started SetEvent(stream->hThreadStart); @@ -5663,7 +5683,7 @@ thread_end: CoUninitialize(); // Notify: not running - stream->running = FALSE; + InterlockedExchange(&stream->running, FALSE); // Notify: thread exited SetEvent(stream->hThreadExit); From dae0d7f8e7e91940d4327b7a0c5e4a6abad328ed Mon Sep 17 00:00:00 2001 From: dmitrykos Date: Fri, 26 Aug 2016 09:43:50 +0300 Subject: [PATCH 6/7] wasapi: reverted the usage of Interlocked APIs for PaWasapiStream::running --- src/hostapi/wasapi/pa_win_wasapi.c | 39 ++++++++++-------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/src/hostapi/wasapi/pa_win_wasapi.c b/src/hostapi/wasapi/pa_win_wasapi.c index 367b87d..be3115a 100644 --- a/src/hostapi/wasapi/pa_win_wasapi.c +++ b/src/hostapi/wasapi/pa_win_wasapi.c @@ -543,7 +543,7 @@ typedef struct PaWasapiStream // must be volatile to avoid race condition on user query while // thread is being started - volatile LONG running; + volatile BOOL running; PA_THREAD_ID dwThreadId; HANDLE hThread; @@ -3856,7 +3856,7 @@ static PaError StartStream( PaStream *s ) stream->out.clientProc = stream->out.clientParent; // Signal: stream running. - InterlockedExchange(&stream->running, TRUE); + stream->running = TRUE; } return result; @@ -3898,8 +3898,7 @@ void _StreamFinish(PaWasapiStream *stream) // Cleanup handles _StreamCleanup(stream); - // Notify: not running - InterlockedExchange(&stream->running, FALSE); + stream->running = FALSE; } // ------------------------------------------------------------------------------------------ @@ -3914,18 +3913,6 @@ void _StreamCleanup(PaWasapiStream *stream) SAFE_CLOSE(stream->hBlockingOpStreamWR); } -// ------------------------------------------------------------------------------------------ -static BOOL _IsStreamRunning(PaWasapiStream *stream) -{ - LONG retv; - do - { - retv = stream->running; - } - while (InterlockedCompareExchange(&stream->running, FALSE, FALSE) != retv); - return retv; -} - // ------------------------------------------------------------------------------------------ static PaError StopStream( PaStream *s ) { @@ -3945,13 +3932,13 @@ static PaError AbortStream( PaStream *s ) // ------------------------------------------------------------------------------------------ static PaError IsStreamStopped( PaStream *s ) { - return !_IsStreamRunning((PaWasapiStream *)s); + return !((PaWasapiStream *)s)->running; } // ------------------------------------------------------------------------------------------ static PaError IsStreamActive( PaStream *s ) { - return _IsStreamRunning((PaWasapiStream *)s); + return ((PaWasapiStream *)s)->running; } // ------------------------------------------------------------------------------------------ @@ -3985,7 +3972,7 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long frames ) ThreadIdleScheduler sched; // validate - if (!_IsStreamRunning(stream)) + if (!stream->running) return paStreamIsStopped; if (stream->captureClient == NULL) return paBadStreamPtr; @@ -4164,7 +4151,7 @@ static PaError WriteStream( PaStream* s, const void *_buffer, unsigned long fram ThreadIdleScheduler sched; // validate - if (!_IsStreamRunning(stream)) + if (!stream->running) return paStreamIsStopped; if (stream->renderClient == NULL) return paBadStreamPtr; @@ -4278,7 +4265,7 @@ static signed long GetStreamReadAvailable( PaStream* s ) UINT32 available = 0; // validate - if (!_IsStreamRunning(stream)) + if (!stream->running) return paStreamIsStopped; if (stream->captureClient == NULL) return paBadStreamPtr; @@ -4304,7 +4291,7 @@ static signed long GetStreamWriteAvailable( PaStream* s ) UINT32 available = 0; // validate - if (!_IsStreamRunning(stream)) + if (!stream->running) return paStreamIsStopped; if (stream->renderClient == NULL) return paBadStreamPtr; @@ -5094,7 +5081,7 @@ PA_THREAD_FUNC ProcThreadEvent(void *param) } // Signal: stream running - InterlockedExchange(&stream->running, TRUE); + stream->running = TRUE; // Notify: thread started SetEvent(stream->hThreadStart); @@ -5161,7 +5148,7 @@ thread_end: CoUninitialize(); // Notify: not running - InterlockedExchange(&stream->running, FALSE); + stream->running = FALSE; // Notify: thread exited SetEvent(stream->hThreadExit); @@ -5328,7 +5315,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param) } // Signal: stream running - InterlockedExchange(&stream->running, TRUE); + stream->running = TRUE; // Notify: thread started SetEvent(stream->hThreadStart); @@ -5683,7 +5670,7 @@ thread_end: CoUninitialize(); // Notify: not running - InterlockedExchange(&stream->running, FALSE); + stream->running = FALSE; // Notify: thread exited SetEvent(stream->hThreadExit); From 319b19203aca10c0f241faf2ff89ec300c3aba4c Mon Sep 17 00:00:00 2001 From: dmitrykos Date: Fri, 26 Aug 2016 22:31:45 +0300 Subject: [PATCH 7/7] wasapi: replaced InterlockedCompareExchange with InterlockedOr and added clarifying comment why Interlocked API is used --- src/hostapi/wasapi/pa_win_wasapi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hostapi/wasapi/pa_win_wasapi.c b/src/hostapi/wasapi/pa_win_wasapi.c index be3115a..e865c7b 100644 --- a/src/hostapi/wasapi/pa_win_wasapi.c +++ b/src/hostapi/wasapi/pa_win_wasapi.c @@ -1367,7 +1367,8 @@ static HRESULT ActivateAudioInterface_WINRT(const PaWasapiDeviceInfo *deviceInfo IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); // Wait in busy loop for async operation to complete - while (SUCCEEDED(hr) && !InterlockedCompareExchange(&handlerImpl->done, FALSE, FALSE)) + // Use Interlocked API here to ensure that ->done variable is read every time through the loop + while (SUCCEEDED(hr) && !InterlockedOr(&handlerImpl->done, 0)) { Sleep(1); }