*/
/*
-* The text above constitutes the entire PortAudio license; however,
+* The text above constitutes the entire PortAudio license; however,
* the PortAudio community also makes the following non-binding requests:
*
* Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that
-* they can be incorporated into the canonical version. It is also
-* requested that these non-binding requests be included along with the
+* they can be incorporated into the canonical version. It is also
+* requested that these non-binding requests be included along with the
* license above.
*/
#include <windows.h>
#include <mmsystem.h>
-#ifndef __GNUC__ /* Fix for ticket #257: MinGW-w64: Inclusion of <winioctl.h> triggers multiple redefinition errors. */
#include <winioctl.h>
-#endif
#include <process.h>
#include <math.h>
#define DYNAMIC_GUID(data) {data}
#define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */
#undef DEFINE_GUID
-#define DEFINE_GUID(n,data) EXTERN_C const GUID n = {data}
-#define DEFINE_GUID_THUNK(n,data) DEFINE_GUID(n,data)
-#define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK(n, STATIC_##n)
+#if defined(__clang__) || (defined(_MSVC_TRADITIONAL) && !_MSVC_TRADITIONAL) /* clang-cl and new msvc preprocessor: avoid too many arguments error */
+ #define DEFINE_GUID(n, ...) EXTERN_C const GUID n = {__VA_ARGS__}
+ #define DEFINE_GUID_THUNK(n, ...) DEFINE_GUID(n, __VA_ARGS__)
+ #define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK(n, STATIC_##n)
+#else
+ #define DEFINE_GUID(n, data) EXTERN_C const GUID n = {data}
+ #define DEFINE_GUID_THUNK(n, data) DEFINE_GUID(n, data)
+ #define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK(n, STATIC_##n)
+#endif /* __clang__, !_MSVC_TRADITIONAL */
#endif
#include <setupapi.h>
-#include <winioctl.h>
#ifndef EXTERN_C
#define EXTERN_C extern
static PaWinWDMKSAvRtEntryPoints paWinWDMKSAvRtEntryPoints = {0};
/* An unspecified channel count (-1) is not treated correctly, so we replace it with
-* an arbitrarily large number */
+* an arbitrarily large number */
#define MAXIMUM_NUMBER_OF_CHANNELS 256
/* Forward definition to break circular type reference between pin and filter */
HANDLE *events; /* noOfPackets handles (WaveCyclic) 1 (WaveRT) */
DATAPACKET *packets; /* noOfPackets packets (WaveCyclic) 2 (WaveRT) */
/* WaveRT polled mode */
- unsigned lastPosition;
+ unsigned lastPosition;
unsigned pollCntr;
} PaWinWdmIOInfo;
};
/* Gather all processing variables in a struct */
-struct __PaProcessThreadInfo
+struct __PaProcessThreadInfo
{
PaWinWdmStream *stream;
PaStreamCallbackTimeInfo ti;
/* Used for transferring device infos during scanning / rescanning */
typedef struct __PaWinWDMScanDeviceInfosResults
-{
+{
PaDeviceInfo **deviceInfos;
PaDeviceIndex defaultInputDevice;
PaDeviceIndex defaultOutputDevice;
NOTE: GetVersionEx() is deprecated as of Windows 8.1 and can not be used to reliably detect
versions of Windows higher than Windows 8 (due to manifest requirements for reporting higher versions).
Microsoft recommends switching to VerifyVersionInfo (available on Win 2k and later), however GetVersionEx
-is is faster, for now we just disable the deprecation warning.
+is faster, for now we just disable the deprecation warning.
See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx
See: http://www.codeproject.com/Articles/678606/Part-Overcoming-Windows-s-deprecation-of-GetVe
*/
if (!bRes)
{
unsigned long error = GetLastError();
- if ( !(((error == ERROR_INSUFFICIENT_BUFFER ) || ( error == ERROR_MORE_DATA )) &&
+ if ( !(((error == ERROR_INSUFFICIENT_BUFFER ) || ( error == ERROR_MORE_DATA )) &&
( ioctlNumber == IOCTL_KS_PROPERTY ) &&
- ( outBufferCount == 0 ) ) )
+ ( outBufferCount == 0 ) ) )
{
KSPROPERTY* ksProperty = (KSPROPERTY*)inBuffer;
}
}
+ /* Some devices may report topologies that leave pins unconnected. This may be by design or driver installation
+ issues. Pass the error condition back to caller. */
PA_DEBUG(("FindStartConnectionFrom: returning NULL\n"));
- assert(FALSE);
return 0;
}
}
}
+ /* Unconnected pin. Inform caller. */
PA_DEBUG(("FindStartConnectionTo: returning NULL\n"));
- assert(FALSE);
return 0;
}
static ULONG GetConnectedPin(ULONG startPin, BOOL forward, PaWinWdmFilter* filter, int muxPosition, ULONG *muxInputPinId, ULONG *muxNodeId)
{
int limit=1000;
- const KSTOPOLOGY_CONNECTION *conn = NULL;
+ const KSTOPOLOGY_CONNECTION *conn = NULL;
TFnGetConnection fnGetConnection = forward ? GetConnectionTo : GetConnectionFrom ;
PA_LOGE_;
while (1)
{
limit--;
if (limit == 0) {
- PA_DEBUG(("GetConnectedPin: LOOP LIMIT REACHED\n"));
- break;
+ PA_DEBUG(("GetConnectedPin: LOOP LIMIT REACHED\n"));
+ break;
}
if (conn == NULL)
for (i=0; i < filter->connections->Count; ++i)
{
const KSTOPOLOGY_CONNECTION* pConn = connections + i;
- PA_DEBUG((" Connection: %u - FromNode=%u,FromPin=%u -> ToNode=%u,ToPin=%u\n",
+ PA_DEBUG((" Connection: %u - FromNode=%u,FromPin=%u -> ToNode=%u,ToPin=%u\n",
i,
pConn->FromNode, pConn->FromNodePin,
pConn->ToNode, pConn->ToNodePin
}
-typedef struct __PaUsbTerminalGUIDToName
+typedef struct __PaUsbTerminalGUIDToName
{
USHORT usbGUID;
wchar_t name[64];
PA_DEBUG(("PinNew: Pin name '%s'\n", pin->friendlyName));
#else
PA_DEBUG(("PinNew: Pin name '%S'\n", pin->friendlyName));
-#endif
+#endif
/* Set endpoint pin ID (this is the topology INPUT pin, since portmixer will always traverse the
filter in audio streaming direction, see http://msdn.microsoft.com/en-us/library/windows/hardware/ff536331(v=vs.85).aspx
FALSE,
pin->parentFilter->topologyFilter,
muxPos,
- &pin->inputs[i]->muxPinId,
+ &pin->inputs[i]->muxPinId,
&pin->inputs[i]->muxNodeId);
if (endpointPinId != KSFILTER_NODE)
}
else
{
- /* Should never come here! */
- assert(FALSE);
+ /* Unconnected pin */
+ goto error;
}
}
}
dataRange = (KSDATARANGE_AUDIO*)pin->dataRanges;
for(count = 0;
count<pin->dataRangesItem->Count;
- count++,
+ count++,
dataRange = (KSDATARANGE_AUDIO*)( ((char*)dataRange) + dataRange->DataRange.FormatSize)) /* Need to update dataRange here, due to 'continue' !! */
{
/* Check major format*/
PA_DEBUG(("\tBits:%d-%d\n",dataRange->MinimumBitsPerSample,dataRange->MaximumBitsPerSample));
PA_DEBUG(("\tSampleRate:%d-%d\n",dataRange->MinimumSampleFrequency,dataRange->MaximumSampleFrequency));
- if( dataRange->MaximumChannels != (ULONG)-1 &&
+ if( dataRange->MaximumChannels != (ULONG)-1 &&
dataRange->MaximumChannels < format->nChannels )
{
result = paInvalidChannelCount;
sizeof(BOOL),
NULL);
- if (result != paNoError)
+ if (result != paNoError)
{
PA_DEBUG(("Failed PinQueryNotificationSupport\n"));
}
sizeof(KSRTAUDIO_BUFFER),
NULL);
- if (result == paNoError)
+ if (result == paNoError)
{
*pBuffer = propOut.BufferAddress;
*pRequestedBufSize = propOut.ActualBufferSize;
*pbCallMemBarrier = propOut.CallMemoryBarrier;
}
- else
+ else
{
PA_DEBUG(("Failed to get buffer with notification\n"));
}
*pRequestedBufSize = propOut.ActualBufferSize;
*pbCallMemBarrier = propOut.CallMemoryBarrier;
}
- else
+ else
{
PA_DEBUG(("Failed to get buffer without notification\n"));
}
{
limit--;
if (limit == 0) {
- PA_DEBUG(("PinGetBuffer: LOOP LIMIT REACHED\n"));
- break;
+ PA_DEBUG(("PinGetBuffer: LOOP LIMIT REACHED\n"));
+ break;
}
if (pPin->pinKsSubType != SubType_kPolled)
return result;
}
-static PaError PinRegisterPositionRegister(PaWinWdmPin* pPin)
+static PaError PinRegisterPositionRegister(PaWinWdmPin* pPin)
{
PaError result = paNoError;
KSRTAUDIO_HWREGISTER_PROPERTY propIn;
sizeof(KSRTAUDIO_HWREGISTER),
NULL);
- if (result == paNoError)
+ if (result == paNoError)
{
pPin->positionRegister = (ULONG*)propOut.Register;
}
return result;
}
-static PaError PinRegisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle)
+static PaError PinRegisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle)
{
PaError result = paNoError;
KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY prop;
return result;
}
-static PaError PinUnregisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle)
+static PaError PinUnregisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle)
{
PaError result = paNoError;
KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY prop;
/***********************************************************************************************/
/**
-* Create a new filter object.
+* Create a new filter object.
*/
static PaWinWdmFilter* FilterNew( PaWDMKSType type, DWORD devNode, const wchar_t* filterName, const wchar_t* friendlyName, PaError* error )
{
return paNoError;
if (filter->pins != NULL)
- return paNoError;
+ return paNoError;
/* Allocate pointer array to hold the pins */
filter->pins = (PaWinWdmPin**)PaUtil_AllocateMemory( sizeof(PaWinWdmPin*) * filter->pinCount );
filter->pins[pinId] = newPin;
++filter->validPinCount;
}
+ else
+ {
+ filter->pins[pinId] = 0;
+ }
}
if (filter->validPinCount == 0)
/**
* Build the list of available filters
-* Use the SetupDi API to enumerate all devices in the KSCATEGORY_AUDIO which
-* have a KSCATEGORY_RENDER or KSCATEGORY_CAPTURE alias. For each of these
-* devices initialise a PaWinWdmFilter structure by calling our NewFilter()
-* function. We enumerate devices twice, once to count how many there are,
+* Use the SetupDi API to enumerate all devices in the KSCATEGORY_AUDIO which
+* have a KSCATEGORY_RENDER or KSCATEGORY_CAPTURE alias. For each of these
+* devices initialise a PaWinWdmFilter structure by calling our NewFilter()
+* function. We enumerate devices twice, once to count how many there are,
* and once to initialize the PaWinWdmFilter structures.
*
* Vista and later: Also check KSCATEGORY_REALTIME for WaveRT devices.
very literate. */
if (!SetupDiGetDeviceRegistryPropertyW(handle,
&devInfoData,
- SPDRP_LOCATION_INFORMATION,
+ SPDRP_LOCATION_INFORMATION,
&type,
(BYTE*)friendlyName,
sizeof(friendlyName),
TrimString(friendlyName, sizeFriendlyName);
- newFilter = FilterNew(streamingType,
+ newFilter = FilterNew(streamingType,
devInfoData.DevInst,
devInterfaceDetails->DevicePath,
friendlyName,
static PaError CreateHashEntry(PaNameHashObject* obj, const wchar_t* name, const BOOL input)
{
- ULONG hash = GetNameHash(name, input);
+ ULONG hash = GetNameHash(name, input);
PaNameHashIndex * pLast = NULL;
PaNameHashIndex * p = obj->list;
while (p != 0)
static unsigned GetNameIndex(PaNameHashObject* obj, const wchar_t* name, const BOOL input)
{
- ULONG hash = GetNameHash(name, input);
+ ULONG hash = GetNameHash(name, input);
PaNameHashIndex* p = obj->list;
while (p != NULL)
{
case Type_kWaveCyclic:
if (IsEarlierThanVista())
{
- /* XP doesn't tolerate low latency, unless the Process Priority Class is set to REALTIME_PRIORITY_CLASS
+ /* XP doesn't tolerate low latency, unless the Process Priority Class is set to REALTIME_PRIORITY_CLASS
through SetPriorityClass, then 10 ms is quite feasible. However, one should then bear in mind that ALL of
the process is running in REALTIME_PRIORITY_CLASS, which might not be appropriate for an application with
a GUI . In this case it is advisable to separate the audio engine in another process and use IPC to communicate
/* Check that the input format is supported */
channelMask = PaWin_DefaultChannelMask(inputChannelCount);
PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
- inputChannelCount,
+ inputChannelCount,
testFormat,
PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
sampleRate,
{
/* Try a WAVE_FORMAT_PCM instead */
PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
- inputChannelCount,
+ inputChannelCount,
testFormat,
PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
sampleRate);
/* Check that the output format is supported */
channelMask = PaWin_DefaultChannelMask(outputChannelCount);
PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
- outputChannelCount,
+ outputChannelCount,
testFormat,
PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
sampleRate,
{
/* Try a WAVE_FORMAT_PCM instead */
PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
- outputChannelCount,
+ outputChannelCount,
testFormat,
PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
sampleRate);
return result;
}
-static void ResetStreamEvents(PaWinWdmStream* stream)
+static void ResetStreamEvents(PaWinWdmStream* stream)
{
unsigned i;
ResetEvent(stream->eventAbort);
}
}
-static void CloseStreamEvents(PaWinWdmStream* stream)
+static void CloseStreamEvents(PaWinWdmStream* stream)
{
unsigned i;
PaWinWdmIOInfo* ios[2] = { &stream->capture, &stream->render };
else
{
userInputChannels = 0;
- inputSampleFormat = hostInputSampleFormat = paInt16; /* Supress 'uninitialised var' warnings. */
+ inputSampleFormat = paInt16; /* Suppress 'uninitialised var' warnings. */
}
if( outputParameters )
else
{
userOutputChannels = 0;
- outputSampleFormat = hostOutputSampleFormat = paInt16; /* Supress 'uninitialized var' warnings. */
+ outputSampleFormat = paInt16; /* Suppress 'uninitialized var' warnings. */
}
/* validate platform specific flags */
while (1)
{
PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
- channelsToProbe,
+ channelsToProbe,
hostInputSampleFormat,
PaWin_SampleFormatToLinearWaveFormatTag(hostInputSampleFormat),
sampleRate,
{
/* Try a WAVE_FORMAT_PCM instead */
PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
- channelsToProbe,
+ channelsToProbe,
hostInputSampleFormat,
PaWin_SampleFormatToLinearWaveFormatTag(hostInputSampleFormat),
sampleRate);
}
else
{
+ hostInputSampleFormat = (PaSampleFormat)0; /* Avoid uninitialized variable warning */
+
stream->capture.pPin = NULL;
stream->capture.bytesPerFrame = 0;
}
while (1)
{
PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
- channelsToProbe,
+ channelsToProbe,
hostOutputSampleFormat,
PaWin_SampleFormatToLinearWaveFormatTag(hostOutputSampleFormat),
sampleRate,
if( result != paNoError && result != paDeviceUnavailable )
{
PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
- channelsToProbe,
+ channelsToProbe,
hostOutputSampleFormat,
PaWin_SampleFormatToLinearWaveFormatTag(hostOutputSampleFormat),
sampleRate);
}
else
{
+ hostOutputSampleFormat = (PaSampleFormat)0; /* Avoid uninitialized variable warning */
+
stream->render.pPin = NULL;
stream->render.bytesPerFrame = 0;
}
stream->userInputChannels, inputSampleFormat, hostInputSampleFormat,
stream->userOutputChannels, outputSampleFormat, hostOutputSampleFormat,
sampleRate, streamFlags, framesPerUserBuffer,
- max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer),
+ max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer),
paUtilBoundedHostBufferSize,
streamCallback, userData );
if( result != paNoError )
ULONG hwFifoLatency = 0;
ULONG dummy;
result = PinGetBuffer(stream->capture.pPin, (void**)&stream->capture.hostBuffer, &dwRequestedSize, &bCallMemoryBarrier);
- if (!result)
+ if (!result)
{
PA_DEBUG(("Input buffer start = %p, size = %u\n", stream->capture.hostBuffer, dwRequestedSize));
if (dwRequestedSize != dwTotalSize)
stream->capture.pPin->fnMemBarrier = bCallMemoryBarrier ? MemoryBarrierRead : MemoryBarrierDummy;
}
- else
+ else
{
PA_DEBUG(("Failed to get input buffer (WaveRT)\n"));
PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to get input buffer (WaveRT)");
goto error;
}
}
- else
+ else
{
stream->capture.hostBuffer = 0;
}
ULONG hwFifoLatency = 0;
ULONG dummy;
result = PinGetBuffer(stream->render.pPin, (void**)&stream->render.hostBuffer, &dwRequestedSize, &bCallMemoryBarrier);
- if (!result)
+ if (!result)
{
PA_DEBUG(("Output buffer start = %p, size = %u, membarrier = %u\n", stream->render.hostBuffer, dwRequestedSize, bCallMemoryBarrier));
if (dwRequestedSize != dwTotalSize)
stream->render.pPin->fnMemBarrier = bCallMemoryBarrier ? MemoryBarrierWrite : MemoryBarrierDummy;
}
- else
+ else
{
PA_DEBUG(("Failed to get output buffer (with notification)\n"));
PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to get output buffer (with notification)");
goto error;
}
}
- else
+ else
{
stream->render.hostBuffer = 0;
}
PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to read capture position register (IOCTL)");
result = paUnanticipatedHostError;
goto error;
- }
+ }
}
else
{
}
/*
-Increase the priority of the calling thread to RT
+Increase the priority of the calling thread to RT
*/
-static HANDLE BumpThreadPriority()
+static HANDLE BumpThreadPriority()
{
HANDLE hThread = GetCurrentThread();
DWORD dwTask = 0;
HANDLE hAVRT = NULL;
/* If we have access to AVRT.DLL (Vista and later), use it */
- if (paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics != NULL)
+ if (paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics != NULL)
{
hAVRT = paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics("Pro Audio", &dwTask);
- if (hAVRT != NULL && hAVRT != INVALID_HANDLE_VALUE)
+ if (hAVRT != NULL && hAVRT != INVALID_HANDLE_VALUE)
{
BOOL bret = paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority(hAVRT, PA_AVRT_PRIORITY_CRITICAL);
if (!bret)
{
HANDLE hThread = GetCurrentThread();
- if (hAVRT != NULL)
+ if (hAVRT != NULL)
{
paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority(hAVRT, PA_AVRT_PRIORITY_NORMAL);
paWinWDMKSAvRtEntryPoints.AvRevertMmThreadCharacteristics(hAVRT);
pInfo->priming += pInfo->stream->render.noOfPackets;
++pInfo->pending;
SetEvent(pInfo->stream->render.events[0]);
- if (pInfo->stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
+ if (pInfo->stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
{
unsigned i;
for(i=1; i < pInfo->stream->render.noOfPackets; ++i)
framesProcessed = 0;
}
}
- else
+ else
{
framesProcessed = PaUtil_EndBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->cbResult);
}
assert(noOfHandles <= (info.stream->capture.noOfPackets + info.stream->render.noOfPackets + 1));
/* Prepare render and capture pins */
- if ((result = PreparePinsForStart(&info)) != paNoError)
+ if ((result = PreparePinsForStart(&info)) != paNoError)
{
PA_DEBUG(("Failed to prepare device(s)!\n"));
goto error;
unsigned eventSignalled = wait - WAIT_OBJECT_0;
DWORD dwCurrentTime = 0;
- if (wait == WAIT_FAILED)
+ if (wait == WAIT_FAILED)
{
PA_DEBUG(("Wait failed = %ld! \n",wait));
break;
/* Get event time */
dwCurrentTime = GetCurrentTimeInMillisecs();
- /* Since we can mix capture/render devices between WaveCyclic, WaveRT polled and WaveRT notification (3x3 combinations),
+ /* Since we can mix capture/render devices between WaveCyclic, WaveRT polled and WaveRT notification (3x3 combinations),
we can't rely on the timeout of WFMO to check for device timeouts, we need to keep tally. */
if (info.stream->capture.pPin && (dwCurrentTime - timeStamp[0]) >= info.timeout)
{
{
PA_HP_TRACE((pInfo->stream->hLog, ">>> Capture bogus event (no data): idx=%u", eventIndex));
- /* Bogus event, reset! This is to handle the behavior of this USB mic: http://shop.xtz.se/measurement-system/microphone-to-dirac-live-room-correction-suite
+ /* Bogus event, reset! This is to handle the behavior of this USB mic: http://shop.xtz.se/measurement-system/microphone-to-dirac-live-room-correction-suite
on startup of streaming, where it erroneously sets the event without the corresponding buffer being filled (DataUsed == 0) */
ResetEvent(packet->Signal.hEvent);
assert(packet != 0);
PA_HP_TRACE((pInfo->stream->hLog, "Capture submit: %u", eventIndex));
packet->Header.DataUsed = 0; /* Reset for reuse */
+ packet->Header.OptionsFlags = 0; /* Reset for reuse. Required for e.g. Focusrite Scarlett 2i4 (1st Gen) see #310 */
ResetEvent(packet->Signal.hEvent);
result = PinRead(pInfo->stream->capture.pPin->handle, packet);
++pInfo->pending;