#define PA_WASAPI_MAX_CONST_DEVICE_COUNT 0 // Force basic behavior by defining 0 if not defined by user
#endif
-// Fallback from Event to the Polling method in case if latency is higher than 21.33ms, as it allows to use
+// Fallback from Event to the Polling method in case if latency is higher than 21.33ms, as it allows to use
// 100% of CPU inside the PA's callback.
-// Note: Some USB DAC drivers are buggy when Polling method is forced in Exclusive mode, audio output becomes
-// unstable with a lot of interruptions, therefore this define is optional. The default behavior is to
+// Note: Some USB DAC drivers are buggy when Polling method is forced in Exclusive mode, audio output becomes
+// unstable with a lot of interruptions, therefore this define is optional. The default behavior is to
// not change the Event mode to Polling and use the mode which user provided.
//#define PA_WASAPI_FORCE_POLL_IF_LARGE_BUFFER
#include "pa_win_coinitialize.h"
#if !defined(NTDDI_VERSION) || (defined(__GNUC__) && (__GNUC__ <= 6) && !defined(__MINGW64__))
-
+
#undef WINVER
#undef _WIN32_WINNT
#define WINVER 0x0600 // VISTA
#ifndef __unaligned
#define __unaligned
#endif
-
+
#ifndef __C89_NAMELESS
#define __C89_NAMELESS
#endif
#define FASTCALL
#include <oleidl.h>
#include <objidl.h>
- #else
+ #else
typedef struct _BYTE_BLOB
{
unsigned long clSize;
#ifndef NT_SUCCESS
typedef LONG NTSTATUS;
#endif
-
+
#ifndef WAVE_FORMAT_IEEE_FLOAT
#define WAVE_FORMAT_IEEE_FLOAT 0x0003 // 32-bit floating-point
- #endif
-
+ #endif
+
#ifndef __MINGW_EXTENSION
#if defined(__GNUC__) || defined(__GNUG__)
#define __MINGW_EXTENSION __extension__
#else
#define __MINGW_EXTENSION
#endif
- #endif
+ #endif
#include <sdkddkver.h>
#include <propkeydef.h>
#define DEVICE_STATE_ACTIVE 0x00000001
typedef enum _EDataFlow
- {
+ {
eRender = 0,
eCapture = ( eRender + 1 ) ,
eAll = ( eCapture + 1 ) ,
EDataFlow;
typedef enum _EndpointFormFactor
- {
+ {
RemoteNetworkDevice = 0,
Speakers = ( RemoteNetworkDevice + 1 ) ,
LineLevel = ( Speakers + 1 ) ,
UnknownDigitalPassthrough = ( Handset + 1 ) ,
SPDIF = ( UnknownDigitalPassthrough + 1 ) ,
HDMI = ( SPDIF + 1 ) ,
- UnknownFormFactor = ( HDMI + 1 )
- }
+ UnknownFormFactor = ( HDMI + 1 )
+ }
EndpointFormFactor;
#endif
__DEFINE_GUID(pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
#ifdef __IAudioClient2_INTERFACE_DEFINED__
-typedef enum _pa_AUDCLNT_STREAMOPTIONS {
+typedef enum _pa_AUDCLNT_STREAMOPTIONS {
pa_AUDCLNT_STREAMOPTIONS_NONE = 0x00,
pa_AUDCLNT_STREAMOPTIONS_RAW = 0x01,
pa_AUDCLNT_STREAMOPTIONS_MATCH_FORMAT = 0x02
PaWasapiWinrtDeviceListContextEntry;
typedef struct PaWasapiWinrtDeviceListContext
{
- PaWasapiWinrtDeviceListContextEntry devices[PA_WASAPI_DEVICE_MAX_COUNT * 2];
+ PaWasapiWinrtDeviceListContextEntry devices[PA_WASAPI_DEVICE_MAX_COUNT * 2];
}
PaWasapiWinrtDeviceListContext;
#endif
#else
(void)granularity;
- // UWP does not support increase of the timer precision change and thus calling WaitForSingleObject with anything
+ // UWP does not support increase of the timer precision change and thus calling WaitForSingleObject with anything
// below 10 milliseconds will cause underruns for input and output stream.
timer->granularity = 10;
#endif
// Note: paCustomFormat stands for 8.24 format (24-bits inside 32-bit containers)
static PaSampleFormat GetSampleFormatForIO(PaSampleFormat format_id)
{
- return ((format_id & ~paNonInterleaved) == paCustomFormat ?
+ return ((format_id & ~paNonInterleaved) == paCustomFormat ?
(paInt32 | (format_id & paNonInterleaved ? paNonInterleaved : 0)) : format_id);
}
if (version == WINDOWS_UNKNOWN)
{
DWORD dwMajorVersion = 0xFFFFFFFFU, dwMinorVersion = 0, dwBuild = 0;
-
- // RTL_OSVERSIONINFOW equals OSVERSIONINFOW but it is missing inb MinGW winnt.h header,
+
+ // RTL_OSVERSIONINFOW equals OSVERSIONINFOW but it is missing inb MinGW winnt.h header,
// thus use OSVERSIONINFOW for greater portability
typedef NTSTATUS (WINAPI *LPFN_RTLGETVERSION)(POSVERSIONINFOW lpVersionInformation);
LPFN_RTLGETVERSION fnRtlGetVersion;
// ------------------------------------------------------------------------------------------
typedef enum EMixDirection
-{
+{
MIX_DIR__1TO2, //!< mix one channel to L and R
MIX_DIR__2TO1, //!< mix L and R channels to one channel
MIX_DIR__2TO1_L //!< mix only L channel (of total 2 channels) to one channel
-}
+}
EMixDirection;
// ------------------------------------------------------------------------------------------
static void _MixMonoToStereo_1TO2_8_24(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_1_TO_2(int); /* !!! int24 data is contained in 32-bit containers*/ }
static void _MixMonoToStereo_1TO2_32(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_1_TO_2(int); }
static void _MixMonoToStereo_1TO2_32f(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_1_TO_2(float); }
-static void _MixMonoToStereo_1TO2_24(void *__to, const void *__from, UINT32 count)
+static void _MixMonoToStereo_1TO2_24(void *__to, const void *__from, UINT32 count)
{
const UCHAR * __restrict from = (const UCHAR *)__from;
UCHAR * __restrict to = (UCHAR *)__to;
static void _MixMonoToStereo_2TO1_8_24(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_INT32(int); /* !!! int24 data is contained in 32-bit containers*/ }
static void _MixMonoToStereo_2TO1_32(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_INT64(int); }
static void _MixMonoToStereo_2TO1_32f(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_FLT32(float); }
-static void _MixMonoToStereo_2TO1_24(void *__to, const void *__from, UINT32 count)
+static void _MixMonoToStereo_2TO1_24(void *__to, const void *__from, UINT32 count)
{
const UCHAR * __restrict from = (const UCHAR *)__from;
UCHAR * __restrict to = (UCHAR *)__to;
while (to != end)
{
- tempL = (((PaInt32)from[0]) << 8);
+ tempL = (((PaInt32)from[0]) << 8);
tempL = tempL | (((PaInt32)from[1]) << 16);
tempL = tempL | (((PaInt32)from[2]) << 24);
- tempR = (((PaInt32)from[3]) << 8);
+ tempR = (((PaInt32)from[3]) << 8);
tempR = tempR | (((PaInt32)from[4]) << 16);
tempR = tempR | (((PaInt32)from[5]) << 24);
static void _MixMonoToStereo_2TO1_8_24_L(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_L(int); /* !!! int24 data is contained in 32-bit containers*/ }
static void _MixMonoToStereo_2TO1_32_L(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_L(int); }
static void _MixMonoToStereo_2TO1_32f_L(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_L(float); }
-static void _MixMonoToStereo_2TO1_24_L(void *__to, const void *__from, UINT32 count)
+static void _MixMonoToStereo_2TO1_24_L(void *__to, const void *__from, UINT32 count)
{
const UCHAR * __restrict from = (const UCHAR *)__from;
UCHAR * __restrict to = (UCHAR *)__to;
static MixMonoToStereoF GetMonoToStereoMixer(const WAVEFORMATEXTENSIBLE *fmtext, EMixDirection dir)
{
PaSampleFormat format = WaveToPaFormat(fmtext);
-
+
switch (dir)
{
case MIX_DIR__1TO2:
}
PaActivateAudioInterfaceCompletionHandler;
-static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_QueryInterface)(
+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
+ // "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) ||
+ if (IsEqualIID(riid, &IID_IUnknown) ||
IsEqualIID(riid, &IID_IAgileObject))
{
IActivateAudioInterfaceCompletionHandler_AddRef((IActivateAudioInterfaceCompletionHandler *)handler);
return E_NOINTERFACE;
}
-
-static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_AddRef)(
+
+static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_AddRef)(
IActivateAudioInterfaceCompletionHandler *This)
{
PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This;
return InterlockedIncrement(&handler->refs);
}
-
-static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Release)(
+
+static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Release)(
IActivateAudioInterfaceCompletionHandler *This)
{
PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This;
return refs;
}
-
-static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_ActivateCompleted)(
+
+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 = IActivateAudioInterfaceAsyncOperation_GetActivateResult(activateOperation, &hrActivateResult, &punkAudioInterface);
if (SUCCEEDED(hr) && SUCCEEDED(hrActivateResult))
handler->out.hr = hrActivateResult;
else
handler->out.hr = hr;
-
+
// Got client object, stop busy waiting in ActivateAudioInterface
InterlockedExchange(&handler->done, TRUE);
static IActivateAudioInterfaceCompletionHandler *CreateActivateAudioInterfaceCompletionHandler(const IID *iid, void **client)
{
PaActivateAudioInterfaceCompletionHandler *handler = PaUtil_AllocateMemory(sizeof(PaActivateAudioInterfaceCompletionHandler));
-
+
memset(handler, 0, sizeof(*handler));
-
+
handler->parent.lpVtbl = PaUtil_AllocateMemory(sizeof(*handler->parent.lpVtbl));
handler->parent.lpVtbl->QueryInterface = &PaActivateAudioInterfaceCompletionHandler_QueryInterface;
handler->parent.lpVtbl->AddRef = &PaActivateAudioInterfaceCompletionHandler_AddRef;
handler->refs = 1;
handler->in.iid = iid;
handler->in.obj = client;
-
+
return (IActivateAudioInterfaceCompletionHandler *)handler;
}
#endif
break;
default:
return S_FALSE;
- }
+ }
return S_OK;
}
// ------------------------------------------------------------------------------------------
#ifdef PA_WINRT
static HRESULT WinRT_ActivateAudioInterface(const WCHAR *deviceId, const IID *iid, void **client)
-{
+{
PaError result = paNoError;
HRESULT hr = S_OK;
IActivateAudioInterfaceAsyncOperation *asyncOp = NULL;
IActivateAudioInterfaceCompletionHandler *handler = CreateActivateAudioInterfaceCompletionHandler(iid, client);
PaActivateAudioInterfaceCompletionHandler *handlerImpl = (PaActivateAudioInterfaceCompletionHandler *)handler;
UINT32 sleepToggle = 0;
-
- // Async operation will call back to IActivateAudioInterfaceCompletionHandler::ActivateCompleted
+
+ // Async operation will call back to IActivateAudioInterfaceCompletionHandler::ActivateCompleted
// which must be an agile interface implementation
hr = ActivateAudioInterfaceAsync(deviceId, iid, NULL, handler, &asyncOp);
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
#endif
// ------------------------------------------------------------------------------------------
-static HRESULT ActivateAudioInterface(const PaWasapiDeviceInfo *deviceInfo, const PaWasapiStreamInfo *streamInfo,
+static HRESULT ActivateAudioInterface(const PaWasapiDeviceInfo *deviceInfo, const PaWasapiStreamInfo *streamInfo,
IAudioClient **client)
{
HRESULT hr;
// ------------------------------------------------------------------------------------------
#ifdef PA_WINRT
// Windows 10 SDK 10.0.15063.0 has SignalObjectAndWait defined again (unlike in 10.0.14393.0 and lower)
-#if !defined(WDK_NTDDI_VERSION) || (WDK_NTDDI_VERSION < NTDDI_WIN10_RS2)
+#if !defined(WDK_NTDDI_VERSION) || (WDK_NTDDI_VERSION < NTDDI_WIN10_RS2)
static DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable)
{
SetEvent(hObjectToSignal);
if (FAILED(hr))
flags |= paWasapiStreamStateError;
-
+
stream->fnStateHandler((PaStream *)stream, flags, hr, stream->pStateHandlerUserData);
}
}
// ------------------------------------------------------------------------------------------
-static PaError FillDeviceInfo(PaWasapiHostApiRepresentation *paWasapi, void *pEndPoints, INT32 index, const WCHAR *defaultRenderId,
+static PaError FillDeviceInfo(PaWasapiHostApiRepresentation *paWasapi, void *pEndPoints, INT32 index, const WCHAR *defaultRenderId,
const WCHAR *defaultCaptureId, PaDeviceInfo *deviceInfo, PaWasapiDeviceInfo *wasapiDeviceInfo
#ifdef PA_WINRT
, PaWasapiWinrtDeviceListContext *deviceListContext
WideCharToMultiByte(CP_UTF8, 0, value.pwszVal, (INT32)wcslen(value.pwszVal), (char *)deviceInfo->name, PA_WASAPI_DEVICE_NAME_LEN - 1, 0, 0);
else
_snprintf((char *)deviceInfo->name, PA_WASAPI_DEVICE_NAME_LEN - 1, "baddev%d", index);
-
+
PropVariantClear(&value);
PA_DEBUG(("WASAPI:%d| name[%s]\n", index, deviceInfo->name));
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
memcpy(&wasapiDeviceInfo->DefaultFormat, value.blob.pBlobData, min(sizeof(wasapiDeviceInfo->DefaultFormat), value.blob.cbSize));
-
+
PropVariantClear(&value);
}
// Set default Output/Input devices
if ((defaultRenderId != NULL) && (wcsncmp(wasapiDeviceInfo->deviceId, defaultRenderId, PA_WASAPI_DEVICE_NAME_LEN - 1) == 0))
- hostApi->info.defaultOutputDevice = hostApi->info.deviceCount;
+ hostApi->info.defaultOutputDevice = hostApi->info.deviceCount;
if ((defaultCaptureId != NULL) && (wcsncmp(wasapiDeviceInfo->deviceId, defaultCaptureId, PA_WASAPI_DEVICE_NAME_LEN - 1) == 0))
hostApi->info.defaultInputDevice = hostApi->info.deviceCount;
// ignore error, let continue further without failing with paInternalError
hr = S_OK;
}
-
+
// Get mix format
hr = IAudioClient_GetMixFormat(tmpClient, &mixFormat);
if (SUCCEEDED(hr))
goto error;
}
}
-
+
// Fill basic device data
deviceInfo->maxInputChannels = 0;
deviceInfo->maxOutputChannels = 0;
PaUtilHostApiRepresentation *hostApi = (PaUtilHostApiRepresentation *)paWasapi;
PaDeviceInfo *deviceInfoArray = NULL;
- if ((paWasapi->devInfo = (PaWasapiDeviceInfo *)PaUtil_GroupAllocateMemory(paWasapi->allocations,
+ if ((paWasapi->devInfo = (PaWasapiDeviceInfo *)PaUtil_GroupAllocateMemory(paWasapi->allocations,
sizeof(PaWasapiDeviceInfo) * paWasapi->deviceCount)) == NULL)
{
return NULL;
deviceCount = PA_WASAPI_MAX_CONST_DEVICE_COUNT;
#endif
- if ((hostApi->deviceInfos = (PaDeviceInfo **)PaUtil_GroupAllocateMemory(paWasapi->allocations,
+ if ((hostApi->deviceInfos = (PaDeviceInfo **)PaUtil_GroupAllocateMemory(paWasapi->allocations,
sizeof(PaDeviceInfo *) * deviceCount)) == NULL)
{
return NULL;
hostApi->deviceInfos[i] = NULL;
// Allocate all device info structs in a contiguous block
- if ((deviceInfoArray = (PaDeviceInfo *)PaUtil_GroupAllocateMemory(paWasapi->allocations,
+ if ((deviceInfoArray = (PaDeviceInfo *)PaUtil_GroupAllocateMemory(paWasapi->allocations,
sizeof(PaDeviceInfo) * deviceCount)) == NULL)
{
return NULL;
return paInternalError;
#ifndef PA_WINRT
- hr = CoCreateInstance(&pa_CLSID_IMMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER,
+ hr = CoCreateInstance(&pa_CLSID_IMMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER,
&pa_IID_IMMDeviceEnumerator, (void **)&pEnumerator);
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(pEnumerator, eRender, eMultimedia, &device);
if (hr != S_OK)
{
- if (hr != E_NOTFOUND)
+ if (hr != E_NOTFOUND)
{
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
}
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(pEnumerator, eCapture, eMultimedia, &device);
if (hr != S_OK)
{
- if (hr != E_NOTFOUND)
+ if (hr != E_NOTFOUND)
{
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
}
deviceListContext.devices[paWasapi->deviceCount].info = &g_DeviceListInfo.render.devices[i];
deviceListContext.devices[paWasapi->deviceCount].flow = eRender;
paWasapi->deviceCount++;
- }
+ }
}
if (g_DeviceListInfo.capture.deviceCount == 0)
deviceListContext.devices[paWasapi->deviceCount].info = &defaultCapture;
deviceListContext.devices[paWasapi->deviceCount].flow = eCapture;
paWasapi->deviceCount++;
-
+
SAFE_RELEASE(tmpClient);
}
}
deviceListContext.devices[paWasapi->deviceCount].info = &g_DeviceListInfo.capture.devices[i];
deviceListContext.devices[paWasapi->deviceCount].flow = eCapture;
paWasapi->deviceCount++;
- }
+ }
}
#endif
FillBaseDeviceInfo(deviceInfo, hostApiIndex);
- if ((result = FillDeviceInfo(paWasapi, pEndPoints, i, defaultRenderId, defaultCaptureId,
+ if ((result = FillDeviceInfo(paWasapi, pEndPoints, i, defaultRenderId, defaultCaptureId,
deviceInfo, &paWasapi->devInfo[i]
#ifdef PA_WINRT
, &deviceListContext
- #endif
+ #endif
)) != paNoError)
{
// Faulty device is made inactive
// Fill the remaining slots with inactive device info
#if defined(PA_WASAPI_MAX_CONST_DEVICE_COUNT) && (PA_WASAPI_MAX_CONST_DEVICE_COUNT > 0)
if ((hostApi->info.deviceCount != 0) && (hostApi->info.deviceCount < PA_WASAPI_MAX_CONST_DEVICE_COUNT))
- {
+ {
for (i = hostApi->info.deviceCount; i < PA_WASAPI_MAX_CONST_DEVICE_COUNT; ++i)
{
PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
return result;
error:
-
+
// Safety if error was not set so that we do not think initialize was a success
if (result == paNoError)
result = paInternalError;
{
result = paInsufficientMemory;
goto error;
- }
+ }
memset(paWasapi, 0, sizeof(PaWasapiHostApiRepresentation)); /* ensure all fields are zeroed. especially paWasapi->allocations */
// Initialize COM subsystem
PaWasapiStream *stream = (PaWasapiStream *)pStream;
if (stream == NULL)
return paBadStreamPtr;
-
+
format = (bOutput == TRUE ? &stream->out.wavex : &stream->in.wavex);
size = min(formatSize, (UINT32)sizeof(*format));
// Validate index
if ((UINT32)index >= paWasapi->deviceCount)
return paInvalidDevice;
-
+
size = min(formatSize, (UINT32)sizeof(paWasapi->devInfo[ index ].DefaultFormat));
memcpy(pFormat, &paWasapi->devInfo[ index ].DefaultFormat, size);
// Validate index
if ((UINT32)index >= paWasapi->deviceCount)
return paInvalidDevice;
-
+
size = min(formatSize, (UINT32)sizeof(paWasapi->devInfo[ index ].MixFormat));
memcpy(pFormat, &paWasapi->devInfo[ index ].MixFormat, size);
case WAVE_FORMAT_PCM: PRINT(("wFormatTag =WAVE_FORMAT_PCM\n")); break;
case WAVE_FORMAT_IEEE_FLOAT: PRINT(("wFormatTag =WAVE_FORMAT_IEEE_FLOAT\n")); break;
- default:
+ default:
PRINT(("wFormatTag =UNKNOWN(%d)\n",old->wFormatTag)); break;
}
case 7: wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1_SURROUND|SPEAKER_BACK_CENTER; break;
#else
case 7: wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1|SPEAKER_BACK_CENTER; break;
-#endif
+#endif
#ifdef PAWIN_SPEAKER_7POINT1_SURROUND
case 8: wavex->dwChannelMask = PAWIN_SPEAKER_7POINT1_SURROUND; break;
#else
}
// ------------------------------------------------------------------------------------------
-static HRESULT GetAlternativeSampleFormatExclusive(IAudioClient *client, double sampleRate,
+static HRESULT GetAlternativeSampleFormatExclusive(IAudioClient *client, double sampleRate,
const PaStreamParameters *params, WAVEFORMATEXTENSIBLE *outWavex, BOOL packedSampleFormatOnly)
{
HRESULT hr = !S_OK;
}
}
}
-
+
return hr;
}
// ------------------------------------------------------------------------------------------
-static PaError GetClosestFormat(IAudioClient *client, double sampleRate, const PaStreamParameters *_params,
+static PaError GetClosestFormat(IAudioClient *client, double sampleRate, const PaStreamParameters *_params,
AUDCLNT_SHAREMODE shareMode, WAVEFORMATEXTENSIBLE *outWavex, BOOL output)
{
PaWasapiStreamInfo *streamInfo = (PaWasapiStreamInfo *)_params->hostApiSpecificStreamInfo;
// Try standard approach, e.g. if data is > 16 bits it will be packed into 32-bit containers
MakeWaveFormatFromParams(outWavex, ¶ms, sampleRate, FALSE);
-
+
// If built-in PCM converter requested then shared mode format will always succeed
- if ((GetWindowsVersion() >= WINDOWS_7_SERVER2008R2) &&
- (shareMode == AUDCLNT_SHAREMODE_SHARED) &&
+ if ((GetWindowsVersion() >= WINDOWS_7_SERVER2008R2) &&
+ (shareMode == AUDCLNT_SHAREMODE_SHARED) &&
((streamInfo != NULL) && (streamInfo->flags & paWinWasapiAutoConvert)))
return paFormatIsSupported;
hr = IAudioClient_IsFormatSupported(client, shareMode, &outWavex->Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));
-
+
// Exclusive mode can require packed format for some devices
if ((hr != S_OK) && (shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE))
{
// Enforce packed only format, e.g. data bits will not be packed into 32-bit containers in any case
MakeWaveFormatFromParams(outWavex, ¶ms, sampleRate, TRUE);
- hr = IAudioClient_IsFormatSupported(client, shareMode, &outWavex->Format, NULL);
+ hr = IAudioClient_IsFormatSupported(client, shareMode, &outWavex->Format, NULL);
}
if (hr == S_OK)
static void _CalculatePeriodicity(PaWasapiSubStream *pSub, BOOL output, REFERENCE_TIME *periodicity)
{
// Note: according Microsoft docs for IAudioClient::Initialize we can set periodicity of the buffer
- // only for Exclusive mode. By setting periodicity almost equal to the user buffer frames we can
+ // only for Exclusive mode. By setting periodicity almost equal to the user buffer frames we can
// achieve high quality (less glitchy) low-latency audio.
if (pSub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)
{
(*periodicity) = pSub->period;
// Try make buffer ready for I/O once we request the buffer readiness for it. Only Polling mode
- // because for Event mode buffer size and periodicity must be equal according Microsoft
+ // because for Event mode buffer size and periodicity must be equal according Microsoft
// documentation for IAudioClient::Initialize.
- //
+ //
// TO-DO: try spread to capture and full-duplex cases (not tested and therefore disabled)
//
- if (((pSub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) == 0) &&
+ if (((pSub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) == 0) &&
(output && !pSub->params.full_duplex))
- {
+ {
UINT32 alignedFrames;
REFERENCE_TIME userPeriodicity;
// Must not be smaller than minimum supported by the device
if (userPeriodicity < pInfo->MinimumDevicePeriod)
userPeriodicity = pInfo->MinimumDevicePeriod;
-
+
(*periodicity) = userPeriodicity;
}
}
// Set device scheduling period (always 0 in Shared mode according Microsoft docs)
_CalculatePeriodicity(pSub, output, &eventPeriodicity);
-
+
// Open the stream and associate it with an audio session
hr = IAudioClient_Initialize(audioClient,
pSub->shareMode,
eventPeriodicity,
&pSub->wavex.Format,
NULL);
-
- // [Output only] Check if buffer size is the one we requested in Exclusive mode, for UAC1 USB DACs WASAPI
- // can allocate internal buffer equal to 8 times of pSub->period that has to be corrected in order to match
+
+ // [Output only] Check if buffer size is the one we requested in Exclusive mode, for UAC1 USB DACs WASAPI
+ // can allocate internal buffer equal to 8 times of pSub->period that has to be corrected in order to match
// the requested latency
if (output && SUCCEEDED(hr) && (pSub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE))
{
UINT32 ratio = maxBufferFrames / framesPerLatency;
PRINT(("WASAPI: CreateAudioClient: detected %d times larger buffer than requested, correct to match user latency\n", ratio));
-
+
// Get new aligned frames lowered by calculated ratio
framesPerLatency = MakeFramesFromHns(pSub->period / ratio, pSub->wavex.Format.nSamplesPerSec);
_CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_BWD);
// Make sure we are not below the minimum period
if (pSub->period < pInfo->MinimumDevicePeriod)
pSub->period = pInfo->MinimumDevicePeriod;
-
+
// Release previous client
SAFE_RELEASE(audioClient);
}
// Error has no workaround, fail completely
- if (FAILED(hr))
+ if (FAILED(hr))
{
(*pa_error) = paInvalidDevice;
LogHostError(hr);
stream->in.streamFlags = 0; // polling interface is implemented for full-duplex mode also
// Use built-in PCM converter (channel count and sample rate) if requested
- if ((GetWindowsVersion() >= WINDOWS_7_SERVER2008R2) &&
- (stream->in.shareMode == AUDCLNT_SHAREMODE_SHARED) &&
+ if ((GetWindowsVersion() >= WINDOWS_7_SERVER2008R2) &&
+ (stream->in.shareMode == AUDCLNT_SHAREMODE_SHARED) &&
((inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiAutoConvert)))
stream->in.streamFlags |= (AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY);
stream->out.streamFlags = 0; // polling interface is implemented for full-duplex mode also
// Use built-in PCM converter (channel count and sample rate) if requested
- if ((GetWindowsVersion() >= WINDOWS_7_SERVER2008R2) &&
- (stream->out.shareMode == AUDCLNT_SHAREMODE_SHARED) &&
+ if ((GetWindowsVersion() >= WINDOWS_7_SERVER2008R2) &&
+ (stream->out.shareMode == AUDCLNT_SHAREMODE_SHARED) &&
((outputStreamInfo != NULL) && (outputStreamInfo->flags & paWinWasapiAutoConvert)))
stream->out.streamFlags |= (AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY);
}
// ------------------------------------------------------------------------------------------
-HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream)
+HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream)
{
#ifndef PA_WINRT
HRESULT hResult = S_OK;
// IAudioClient
hResult = CoGetInterfaceAndReleaseStream(substream->clientStream, GetAudioClientIID(), (LPVOID*)&substream->clientProc);
substream->clientStream = NULL;
- if (hResult != S_OK)
+ if (hResult != S_OK)
{
hFirstBadResult = (hFirstBadResult == S_OK) ? hResult : hFirstBadResult;
}
}
// ------------------------------------------------------------------------------------------
-HRESULT UnmarshalStreamComPointers(PaWasapiStream *stream)
+HRESULT UnmarshalStreamComPointers(PaWasapiStream *stream)
{
#ifndef PA_WINRT
HRESULT hResult = S_OK;
stream->in.clientProc = NULL;
stream->out.clientProc = NULL;
- if (NULL != stream->in.clientParent)
+ if (NULL != stream->in.clientParent)
{
// SubStream pointers
hResult = UnmarshalSubStreamComPointers(&stream->in);
- if (hResult != S_OK)
+ if (hResult != S_OK)
{
hFirstBadResult = (hFirstBadResult == S_OK) ? hResult : hFirstBadResult;
}
// IAudioCaptureClient
hResult = CoGetInterfaceAndReleaseStream(stream->captureClientStream, &pa_IID_IAudioCaptureClient, (LPVOID*)&stream->captureClient);
stream->captureClientStream = NULL;
- if (hResult != S_OK)
+ if (hResult != S_OK)
{
hFirstBadResult = (hFirstBadResult == S_OK) ? hResult : hFirstBadResult;
}
}
- if (NULL != stream->out.clientParent)
+ if (NULL != stream->out.clientParent)
{
// SubStream pointers
hResult = UnmarshalSubStreamComPointers(&stream->out);
- if (hResult != S_OK)
+ if (hResult != S_OK)
{
hFirstBadResult = (hFirstBadResult == S_OK) ? hResult : hFirstBadResult;
}
// IAudioRenderClient
hResult = CoGetInterfaceAndReleaseStream(stream->renderClientStream, &pa_IID_IAudioRenderClient, (LPVOID*)&stream->renderClient);
stream->renderClientStream = NULL;
- if (hResult != S_OK)
+ if (hResult != S_OK)
{
hFirstBadResult = (hFirstBadResult == S_OK) ? hResult : hFirstBadResult;
}
}
// -----------------------------------------------------------------------------------------
-void ReleaseUnmarshaledSubComPointers(PaWasapiSubStream *substream)
+void ReleaseUnmarshaledSubComPointers(PaWasapiSubStream *substream)
{
SAFE_RELEASE(substream->clientProc);
}
// -----------------------------------------------------------------------------------------
-void ReleaseUnmarshaledComPointers(PaWasapiStream *stream)
+void ReleaseUnmarshaledComPointers(PaWasapiStream *stream)
{
// Release AudioClient services first
SAFE_RELEASE(stream->captureClient);
}
// ------------------------------------------------------------------------------------------
-HRESULT MarshalSubStreamComPointers(PaWasapiSubStream *substream)
+HRESULT MarshalSubStreamComPointers(PaWasapiSubStream *substream)
{
#ifndef PA_WINRT
HRESULT hResult;
}
// ------------------------------------------------------------------------------------------
-HRESULT MarshalStreamComPointers(PaWasapiStream *stream)
+HRESULT MarshalStreamComPointers(PaWasapiStream *stream)
{
#ifndef PA_WINRT
HRESULT hResult = S_OK;
stream->renderClientStream = NULL;
stream->out.clientStream = NULL;
- if (NULL != stream->in.clientParent)
+ if (NULL != stream->in.clientParent)
{
// SubStream pointers
hResult = MarshalSubStreamComPointers(&stream->in);
- if (hResult != S_OK)
+ if (hResult != S_OK)
goto marshal_error;
// IAudioCaptureClient
hResult = CoMarshalInterThreadInterfaceInStream(&pa_IID_IAudioCaptureClient, (LPUNKNOWN)stream->captureClientParent, &stream->captureClientStream);
- if (hResult != S_OK)
+ if (hResult != S_OK)
goto marshal_error;
}
- if (NULL != stream->out.clientParent)
+ if (NULL != stream->out.clientParent)
{
// SubStream pointers
hResult = MarshalSubStreamComPointers(&stream->out);
- if (hResult != S_OK)
+ if (hResult != S_OK)
goto marshal_error;
// IAudioRenderClient
hResult = CoMarshalInterThreadInterfaceInStream(&pa_IID_IAudioRenderClient, (LPUNKNOWN)stream->renderClientParent, &stream->renderClientStream);
- if (hResult != S_OK)
+ if (hResult != S_OK)
goto marshal_error;
}
_StreamCleanup(stream);
// Create close event
- if ((stream->hCloseRequest = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
+ if ((stream->hCloseRequest = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
{
result = paInsufficientMemory;
goto start_error;
}
// Marshal WASAPI interface pointers for safe use in thread created below.
- if ((hr = MarshalStreamComPointers(stream)) != S_OK)
+ if ((hr = MarshalStreamComPointers(stream)) != S_OK)
{
PRINT(("Failed marshaling stream COM pointers."));
result = paUnanticipatedHostError;
if ((stream->in.clientParent && (stream->in.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)) ||
(stream->out.clientParent && (stream->out.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)))
{
- if ((stream->hThread = CREATE_THREAD(ProcThreadEvent)) == NULL)
+ if ((stream->hThread = CREATE_THREAD(ProcThreadEvent)) == NULL)
{
PRINT(("Failed creating thread: ProcThreadEvent."));
result = paUnanticipatedHostError;
}
else
{
- if ((stream->hThread = CREATE_THREAD(ProcThreadPoll)) == NULL)
+ if ((stream->hThread = CREATE_THREAD(ProcThreadPoll)) == NULL)
{
PRINT(("Failed creating thread: ProcThreadPoll."));
result = paUnanticipatedHostError;
}
// Wait for thread to start
- if (WaitForSingleObject(stream->hThreadStart, 60*1000) == WAIT_TIMEOUT)
+ if (WaitForSingleObject(stream->hThreadStart, 60*1000) == WAIT_TIMEOUT)
{
PRINT(("Failed starting thread: timeout."));
result = paUnanticipatedHostError;
else
{
// Create blocking operation events (non-signaled event means - blocking operation is pending)
- if (stream->out.clientParent != NULL)
+ if (stream->out.clientParent != NULL)
{
- if ((stream->hBlockingOpStreamWR = CreateEvent(NULL, TRUE, TRUE, NULL)) == NULL)
+ if ((stream->hBlockingOpStreamWR = CreateEvent(NULL, TRUE, TRUE, NULL)) == NULL)
{
result = paInsufficientMemory;
goto start_error;
}
}
- if (stream->in.clientParent != NULL)
+ if (stream->in.clientParent != NULL)
{
- if ((stream->hBlockingOpStreamRD = CreateEvent(NULL, TRUE, TRUE, NULL)) == NULL)
+ if ((stream->hBlockingOpStreamRD = CreateEvent(NULL, TRUE, TRUE, NULL)) == NULL)
{
result = paInsufficientMemory;
goto start_error;
desired = available;
if ((UINT32)desired > frames)
desired = frames;
-
+
// Get pointers to read regions
read = PaUtil_GetRingBufferReadRegions(stream->in.tailBuffer, desired, &buf1, &buf1_size, &buf2, &buf2_size);
goto end;
}
- // Keep waiting again (on Vista it was noticed that WASAPI could SOMETIMES return NULL pointer
+ // Keep waiting again (on Vista it was noticed that WASAPI could SOMETIMES return NULL pointer
// to buffer without returning AUDCLNT_E_BUFFER_TOO_LARGE instead)
if (wasapi_buffer == NULL)
continue;
DWORD task_idx = 0;
HANDLE hTask;
-
+
if ((UINT32)nPriorityClass >= STATIC_ARRAY_SIZE(mmcs_name))
return paUnanticipatedHostError;
-
+
if ((hTask = pAvSetMmThreadCharacteristics(mmcs_name[nPriorityClass], &task_idx)) == NULL)
{
PRINT(("WASAPI: AvSetMmThreadCharacteristics failed: error[%d]\n", GetLastError()));
}
// ------------------------------------------------------------------------------------------
-PaError PaWasapiWinrt_PopulateDeviceList( const unsigned short **pId, const unsigned short **pName,
+PaError PaWasapiWinrt_PopulateDeviceList( const unsigned short **pId, const unsigned short **pName,
const PaWasapiDeviceRole *pRole, unsigned int count, int bOutput )
{
#ifdef PA_WINRT
(*available) = 0;
- // GetCurrentPadding() has opposite meaning to Output stream
+ // GetCurrentPadding() has opposite meaning to Output stream
if ((hr = IAudioClient_GetCurrentPadding(stream->in.clientProc, available)) != S_OK)
return LogHostError(hr);
void _StreamOnStop(PaWasapiStream *stream)
{
// Stop INPUT/OUTPUT clients
- if (!stream->bBlocking)
+ if (!stream->bBlocking)
{
if (stream->in.clientProc != NULL)
IAudioClient_Stop(stream->in.clientProc);
if (stream->out.clientProc != NULL)
IAudioClient_Stop(stream->out.clientProc);
- }
- else
+ }
+ else
{
if (stream->in.clientParent != NULL)
IAudioClient_Stop(stream->in.clientParent);
If COM is already initialized CoInitialize will either return
FALSE, or RPC_E_CHANGED_MODE if it was initialized in a different
threading mode. In either case we shouldn't consider it an error
- but we need to be careful to not call CoUninitialize() if
+ but we need to be careful to not call CoUninitialize() if
RPC_E_CHANGED_MODE was returned.
*/
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
UINT32 sleepTime;
// According to the issue [https://github.com/PortAudio/portaudio/issues/303] glitches may occur when user frames
- // equal to 1/2 of the host buffer frames, therefore the empirical workaround for this problem is to lower
+ // equal to 1/2 of the host buffer frames, therefore the empirical workaround for this problem is to lower
// the sleep time by 2
if (userFramesOut != 0)
{
// polled according its packet length
if (stream->bufferMode != paUtilFixedHostBufferSize)
{
- userFramesOut = (stream->bufferProcessor.framesPerUserBuffer ? stream->bufferProcessor.framesPerUserBuffer :
+ userFramesOut = (stream->bufferProcessor.framesPerUserBuffer ? stream->bufferProcessor.framesPerUserBuffer :
stream->out.params.frames_per_buffer);
}
}
// ------------------------------------------------------------------------------------------
-static inline INT32 GetNextSleepTime(SystemTimer *timer, ThreadIdleScheduler *scheduler, LONGLONG startTime,
+static inline INT32 GetNextSleepTime(SystemTimer *timer, ThreadIdleScheduler *scheduler, LONGLONG startTime,
UINT32 sleepTime)
{
INT32 nextSleepTime;
UINT32 framesProc = stream->out.framesPerBuffer;
// If we got less frames avoid sleeping again as it might be the corner case and buffer
- // has sufficient number of frames now, in case 'out.framesPerBuffer' is 1/2 of the host
- // buffer sleeping again may cause underruns. Do short busy waiting (normally might take
+ // has sufficient number of frames now, in case 'out.framesPerBuffer' is 1/2 of the host
+ // buffer sleeping again may cause underruns. Do short busy waiting (normally might take
// 1-2 iterations)
if (framesAvail < framesProc)
{
UINT32 i_frames = 0, i_processed = 0, o_frames = 0;
BYTE *i_data = NULL, *o_data = NULL, *o_data_host = NULL;
DWORD i_flags = 0;
-
+
startTime = SystemTimer_GetTime(&timer);
#ifdef PA_WASAPI_LOG_TIME_SLOTS