Merge branch 'winrt' into 'master'

WASAPI: ported to WinRT (UWP) platform, compatibility fixes to compile PortAudio as Windows Store library

+1: Phil Burk, Ross Bencina

Merged-on: https://assembla.com/code/portaudio/git/merge_requests/3643753
This commit is contained in:
Ross Bencina 2016-08-28 00:14:32 +00:00
commit 0648f7e63b
4 changed files with 447 additions and 64 deletions

View file

@ -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 <windows.h>
#include <stdio.h>
#include <process.h>
#include <assert.h>
#include <mmsystem.h>
// WinRT
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
#define PA_WINRT
#define INITGUID
#endif
// WASAPI
#include <mmreg.h> // must be before other Wasapi headers
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
#include <Avrt.h>
@ -61,9 +67,9 @@
#undef INITGUID
#endif
#ifndef __MWERKS__
#include <malloc.h>
#include <memory.h>
#endif /* __MWERKS__ */
#include <malloc.h>
#include <memory.h>
#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
@ -160,6 +165,38 @@
#endif // NTDDI_VERSION
// Missing declarations for WinRT
#ifdef PA_WINRT
#define DEVICE_STATE_ACTIVE 0x00000001
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 PA_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 PA_WINRT
IMMDevice *device;
#endif
// from GetId
WCHAR szDeviceID[MAX_STR_LEN];
@ -359,20 +400,17 @@ 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;
REFERENCE_TIME MinimumDevicePeriod;
// from GetMixFormat
// WAVEFORMATEX *MixFormat;//needs to be CoTaskMemFree'd after use!
// Default format (setup through Control Panel by user)
WAVEFORMATEXTENSIBLE DefaultFormat;
// Fields filled from IMMEndpoint'sGetDataFlow
EDataFlow flow;
// Formfactor
EndpointFormFactor formFactor;
}
@ -393,7 +431,9 @@ typedef struct
PaWinUtilComInitializationResult comInitializationResult;
//in case we later need the synch
#ifndef PA_WINRT
IMMDeviceEnumerator *enumerator;
#endif
//this is the REAL number of devices, whether they are usefull to PA or not!
UINT32 deviceCount;
@ -428,7 +468,9 @@ PaWasapiAudioClientParams;
typedef struct PaWasapiSubStream
{
IAudioClient *clientParent;
#ifndef PA_WINRT
IStream *clientStream;
#endif
IAudioClient *clientProc;
WAVEFORMATEXTENSIBLE wavex;
@ -478,14 +520,18 @@ typedef struct PaWasapiStream
// input
PaWasapiSubStream in;
IAudioCaptureClient *captureClientParent;
#ifndef PA_WINRT
IStream *captureClientStream;
#endif
IAudioCaptureClient *captureClient;
IAudioEndpointVolume *inVol;
// output
PaWasapiSubStream out;
IAudioRenderClient *renderClientParent;
#ifndef PA_WINRT
IStream *renderClientStream;
#endif
IAudioRenderClient *renderClient;
IAudioEndpointVolume *outVol;
@ -766,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
@ -812,6 +859,7 @@ static UINT32 GetFramesSleepTimeMicroseconds(UINT32 nFrames, UINT32 nSamplesPerS
}
// ------------------------------------------------------------------------------------------
#ifndef PA_WINRT
static BOOL SetupAVRT()
{
hDInputDLL = LoadLibraryA("avrt.dll");
@ -832,18 +880,23 @@ static BOOL SetupAVRT()
pAvRevertMmThreadCharacteristics &&
pAvSetMmThreadPriority;
}
#endif
// ------------------------------------------------------------------------------------------
static void CloseAVRT()
{
#ifndef PA_WINRT
if (hDInputDLL != NULL)
FreeLibrary(hDInputDLL);
hDInputDLL = NULL;
#endif
}
// ------------------------------------------------------------------------------------------
static BOOL IsWow64()
{
#ifndef PA_WINRT
// http://msdn.microsoft.com/en-us/library/ms684139(VS.85).aspx
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
@ -865,6 +918,12 @@ static BOOL IsWow64()
return FALSE;
return bIsWow64;
#else
return FALSE;
#endif
}
// ------------------------------------------------------------------------------------------
@ -880,6 +939,7 @@ typedef enum EWindowsVersion
}
EWindowsVersion;
// Alternative way for checking Windows version (allows to check version on Windows 8.1 and up)
#ifndef PA_WINRT
static BOOL IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
{
typedef ULONGLONG (NTAPI *LPFN_VERSETCONDITIONMASK)(ULONGLONG ConditionMask, DWORD TypeMask, BYTE Condition);
@ -909,9 +969,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 PA_WINRT
static EWindowsVersion version = WINDOWS_UNKNOWN;
if (version == WINDOWS_UNKNOWN)
@ -996,6 +1058,9 @@ static EWindowsVersion GetWindowsVersion()
}
return version;
#else
return WINDOWS_8_SERVER2012;
#endif
}
// ------------------------------------------------------------------------------------------
@ -1167,6 +1232,180 @@ static MixMonoToStereoF _GetMonoToStereoMixer(PaSampleFormat format, EMixerDir d
return NULL;
}
// ------------------------------------------------------------------------------------------
#ifdef PA_WINRT
typedef struct PaActivateAudioInterfaceCompletionHandler
{
IActivateAudioInterfaceCompletionHandler parent;
volatile LONG refs;
volatile LONG done;
struct
{
HRESULT hr;
IAudioClient *client;
}
out;
}
PaActivateAudioInterfaceCompletionHandler;
static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_QueryInterface)(
IActivateAudioInterfaceCompletionHandler *This, REFIID riid, void **ppvObject)
{
PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)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_IUnknown) ||
IsEqualIID(riid, &IID_IAgileObject))
{
handler->parent.lpVtbl->AddRef((IActivateAudioInterfaceCompletionHandler *)handler);
(*ppvObject) = handler;
return S_OK;
}
return S_FALSE;
}
static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_AddRef)(
IActivateAudioInterfaceCompletionHandler *This)
{
PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This;
return InterlockedIncrement(&handler->refs);
}
static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Release)(
IActivateAudioInterfaceCompletionHandler *This)
{
PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This;
ULONG refs;
if ((refs = InterlockedDecrement(&handler->refs)) == 0)
{
PaUtil_FreeMemory(handler->parent.lpVtbl);
PaUtil_FreeMemory(handler);
}
return refs;
}
static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_ActivateCompleted)(
IActivateAudioInterfaceCompletionHandler *This, IActivateAudioInterfaceAsyncOperation *activateOperation)
{
PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)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;
// Got client object, stop busy waiting in ActivateAudioInterface_WINRT
InterlockedExchange(&handler->done, TRUE);
return hr;
}
static IActivateAudioInterfaceCompletionHandler *CreateActivateAudioInterfaceCompletionHandler()
{
PaActivateAudioInterfaceCompletionHandler *handler = PaUtil_AllocateMemory(sizeof(PaActivateAudioInterfaceCompletionHandler));
ZeroMemory(handler, sizeof(*handler));
handler->parent.lpVtbl = PaUtil_AllocateMemory(sizeof(*handler->parent.lpVtbl));
handler->parent.lpVtbl->QueryInterface = &PaActivateAudioInterfaceCompletionHandler_QueryInterface;
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
// ------------------------------------------------------------------------------------------
#ifdef PA_WINRT
static HRESULT ActivateAudioInterface_WINRT(const PaWasapiDeviceInfo *deviceInfo, IAudioClient **client)
{
#define PA_WASAPI_DEVICE_PATH_LEN 64
PaError result = paNoError;
HRESULT hr = S_OK;
IActivateAudioInterfaceAsyncOperation *asyncOp = NULL;
IActivateAudioInterfaceCompletionHandler *handler = CreateActivateAudioInterfaceCompletionHandler();
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, PA_WASAPI_DEVICE_PATH_LEN - 1);
break;
case eCapture:
StringFromGUID2(&DEVINTERFACE_AUDIO_CAPTURE, devicePath, PA_WASAPI_DEVICE_PATH_LEN - 1);
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
// 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);
}
(*client) = handlerImpl->out.client;
hr = handlerImpl->out.hr;
error:
SAFE_RELEASE(asyncOp);
SAFE_RELEASE(handler);
return hr;
#undef PA_WASAPI_DEVICE_PATH_LEN
}
#endif
// ------------------------------------------------------------------------------------------
static HRESULT ActivateAudioInterface(const PaWasapiDeviceInfo *deviceInfo, IAudioClient **client)
{
#ifndef PA_WINRT
return IMMDevice_Activate(deviceInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void **)client);
#else
return ActivateAudioInterface_WINRT(deviceInfo, client);
#endif
}
// ------------------------------------------------------------------------------------------
#ifdef PA_WINRT
static DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable)
{
SetEvent(hObjectToSignal);
return WaitForSingleObjectEx(hObjectToWaitOn, dwMilliseconds, bAlertable);
}
#endif
// ------------------------------------------------------------------------------------------
PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
{
@ -1174,14 +1413,20 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
PaWasapiHostApiRepresentation *paWasapi;
PaDeviceInfo *deviceInfoArray;
HRESULT hr = S_OK;
IMMDeviceCollection* pEndPoints = NULL;
UINT i;
#ifndef PA_WINRT
IMMDeviceCollection* pEndPoints = NULL;
#else
WAVEFORMATEX *mixFormat;
#endif
#ifndef PA_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 PA_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)
{
@ -1312,7 +1562,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;
@ -1320,6 +1569,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
PA_DEBUG(("WASAPI: device idx: %02d\n", i));
PA_DEBUG(("WASAPI: ---------------\n"));
#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);]
@ -1352,7 +1602,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));
}
{
@ -1379,9 +1629,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));
@ -1424,8 +1674,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
SAFE_RELEASE(pProperty);
}
// Endpoint data
{
IMMEndpoint *endpoint = NULL;
@ -1436,18 +1685,25 @@ 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 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);
#endif
hr = IMMDevice_Activate(paWasapi->devInfo[i].device, GetAudioClientIID(),
CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient);
// 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
hr = IAudioClient_GetDevicePeriod(tmpClient,
&paWasapi->devInfo[i].DefaultDevicePeriod,
&paWasapi->devInfo[i].MinimumDevicePeriod);
@ -1462,10 +1718,42 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
// ignore error, let continue further without failing with paInternalError
hr = S_OK;
}
#ifdef PA_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 = 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 = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, MAX_STR_LEN + 1);
if (deviceInfo->name == NULL)
{
SAFE_RELEASE(tmpClient);
result = paInsufficientMemory;
goto error;
}
_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
// Release tmp client
SAFE_RELEASE(tmpClient);
if (hr != S_OK)
@ -1479,7 +1767,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 +1820,9 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
// findout if platform workaround is required
paWasapi->useWOW64Workaround = UseWOW64Workaround();
#ifndef PA_WINRT
SAFE_RELEASE(pEndPoints);
#endif
PRINT(("WASAPI: initialized ok\n"));
@ -1542,7 +1832,9 @@ error:
PRINT(("WASAPI: failed %s error[%d|%s]\n", __FUNCTION__, result, Pa_GetErrorText(result)));
#ifndef PA_WINRT
SAFE_RELEASE(pEndPoints);
#endif
Terminate((PaUtilHostApiRepresentation *)paWasapi);
@ -1563,15 +1855,19 @@ static void Terminate( PaUtilHostApiRepresentation *hostApi )
return;
// Release IMMDeviceEnumerator
#ifndef PA_WINRT
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 PA_WINRT
SAFE_RELEASE(info->device);
//if (info->MixFormat)
// CoTaskMemFree(info->MixFormat);
#else
(void)info;
#endif
}
PaUtil_FreeMemory(paWasapi->devInfo);
@ -1830,25 +2126,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 +2165,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);
@ -1916,6 +2212,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
@ -2154,8 +2451,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 +2476,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);
@ -2259,7 +2554,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;
@ -2281,7 +2576,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 +2790,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 +2821,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 +2861,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 +3544,7 @@ static PaError CloseStream( PaStream* s )
// ------------------------------------------------------------------------------------------
HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream)
{
#ifndef PA_WINRT
HRESULT hResult = S_OK;
HRESULT hFirstBadResult = S_OK;
substream->clientProc = NULL;
@ -3262,11 +3558,17 @@ HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream)
}
return hFirstBadResult;
#else
(void)substream;
return S_OK;
#endif
}
// ------------------------------------------------------------------------------------------
HRESULT UnmarshalStreamComPointers(PaWasapiStream *stream)
{
#ifndef PA_WINRT
HRESULT hResult = S_OK;
HRESULT hFirstBadResult = S_OK;
stream->captureClient = NULL;
@ -3311,6 +3613,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 +3663,7 @@ void ReleaseUnmarshaledComPointers(PaWasapiStream *stream)
// ------------------------------------------------------------------------------------------
HRESULT MarshalSubStreamComPointers(PaWasapiSubStream *substream)
{
#ifndef PA_WINRT
HRESULT hResult;
substream->clientStream = NULL;
@ -3350,11 +3680,16 @@ marshal_sub_error:
UnmarshalSubStreamComPointers(substream);
ReleaseUnmarshaledSubComPointers(substream);
return hResult;
#else
(void)substream;
return S_OK;
#endif
}
// ------------------------------------------------------------------------------------------
HRESULT MarshalStreamComPointers(PaWasapiStream *stream)
{
#ifndef PA_WINRT
HRESULT hResult = S_OK;
stream->captureClientStream = NULL;
stream->in.clientStream = NULL;
@ -3395,6 +3730,10 @@ marshal_error:
UnmarshalStreamComPointers(stream);
ReleaseUnmarshaledComPointers(stream);
return hResult;
#else
(void)stream;
return S_OK;
#endif
}
// ------------------------------------------------------------------------------------------
@ -4079,6 +4418,7 @@ static void WaspiHostProcessingLoop( void *inputBuffer, long inputFrames,
// ------------------------------------------------------------------------------------------
HANDLE MMCSS_activate(const char *name)
{
#ifndef PA_WINRT
DWORD task_idx = 0;
HANDLE hTask = pAvSetMmThreadCharacteristics(name, &task_idx);
if (hTask == NULL)
@ -4100,6 +4440,10 @@ HANDLE MMCSS_activate(const char *name)
}
return hTask;
#else
(void)name;
return NULL;
#endif
}
// ------------------------------------------------------------------------------------------
@ -4108,10 +4452,12 @@ void MMCSS_deactivate(HANDLE hTask)
if (!hTask)
return;
#ifndef PA_WINRT
if (pAvRevertMmThreadCharacteristics(hTask) == FALSE)
{
PRINT(("WASAPI: AvRevertMmThreadCharacteristics failed!\n"));
}
#endif
}
// ------------------------------------------------------------------------------------------
@ -4161,6 +4507,7 @@ PaError PaWasapi_ThreadPriorityRevert(void *hTask)
PaError PaWasapi_GetJackCount(PaDeviceIndex nDevice, int *jcount)
{
#ifndef PA_WINRT
PaError ret;
HRESULT hr = S_OK;
PaDeviceIndex index;
@ -4230,9 +4577,15 @@ error:
LogHostError(hr);
return paNoError;
#else
(void)nDevice;
(void)jcount;
return paUnanticipatedHostError;
#endif
}
// ------------------------------------------------------------------------------------------
#ifndef PA_WINRT
static PaWasapiJackConnectionType ConvertJackConnectionTypeWASAPIToPA(int connType)
{
switch (connType)
@ -4256,8 +4609,10 @@ static PaWasapiJackConnectionType ConvertJackConnectionTypeWASAPIToPA(int connTy
}
return eJackConnTypeUnknown;
}
#endif
// ------------------------------------------------------------------------------------------
#ifndef PA_WINRT
static PaWasapiJackGeoLocation ConvertJackGeoLocationWASAPIToPA(int geoLoc)
{
switch (geoLoc)
@ -4282,8 +4637,10 @@ static PaWasapiJackGeoLocation ConvertJackGeoLocationWASAPIToPA(int geoLoc)
}
return eJackGeoLocUnk;
}
#endif
// ------------------------------------------------------------------------------------------
#ifndef PA_WINRT
static PaWasapiJackGenLocation ConvertJackGenLocationWASAPIToPA(int genLoc)
{
switch (genLoc)
@ -4299,8 +4656,10 @@ static PaWasapiJackGenLocation ConvertJackGenLocationWASAPIToPA(int genLoc)
}
return eJackGenLocPrimaryBox;
}
#endif
// ------------------------------------------------------------------------------------------
#ifndef PA_WINRT
static PaWasapiJackPortConnection ConvertJackPortConnectionWASAPIToPA(int portConn)
{
switch (portConn)
@ -4312,6 +4671,7 @@ static PaWasapiJackPortConnection ConvertJackPortConnectionWASAPIToPA(int portCo
}
return eJackPortConnJack;
}
#endif
// ------------------------------------------------------------------------------------------
// Described at:
@ -4319,6 +4679,7 @@ static PaWasapiJackPortConnection ConvertJackPortConnectionWASAPIToPA(int portCo
PaError PaWasapi_GetJackDescription(PaDeviceIndex nDevice, int jindex, PaWasapiJackDescription *pJackDescription)
{
#ifndef PA_WINRT
PaError ret;
HRESULT hr = S_OK;
PaDeviceIndex index;
@ -4394,6 +4755,13 @@ error:
LogHostError(hr);
return ret;
#else
(void)nDevice;
(void)jindex;
(void)pJackDescription;
return paUnanticipatedHostError;
#endif
}
// ------------------------------------------------------------------------------------------
@ -4618,7 +4986,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;
@ -4825,7 +5193,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;

View file

@ -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));

View file

@ -44,14 +44,17 @@
*/
#include <windows.h>
#include <mmsystem.h> /* 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 <sys/timeb.h> /* for _ftime_s() */
#else
#include <mmsystem.h> /* 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,12 @@ double PaUtil_GetTime( void )
}
else
{
#ifndef UNDER_CE
#ifndef UNDER_CE
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
return GetTickCount64() * .001;
#else
return timeGetTime() * .001;
#endif
#else
return GetTickCount() * .001;
#endif

View file

@ -38,6 +38,9 @@
#include <windows.h>
#include <mmsystem.h>
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
#include <mmreg.h> /* for WAVEFORMATEX */
#endif
#include "portaudio.h"
#include "pa_win_waveformat.h"
@ -47,6 +50,7 @@
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
#endif
static GUID pawin_ksDataFormatSubtypeGuidBase =
{ (USHORT)(WAVE_FORMAT_PCM), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 };