From: dmitrykos Date: Wed, 3 Aug 2016 19:39:41 +0000 (+0300) Subject: wasapi: ported to WinRT (UWP) X-Git-Tag: pa_stable_v190600_20161030~15^2~6 X-Git-Url: https://andrewgundersen.net/repos?a=commitdiff_plain;h=2e7545f17fc7f0ed4a85d0ae21361f091e607cc0;p=portaudio 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) --- 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; + + // State + paWasapi->devInfo[i].state = 1; // DEVICE_STATE_ACTIVE + + // 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; - //hr = tmpClient->GetMixFormat(&paWasapi->devInfo[i].MixFormat); + // 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 client + // 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 };