summaryrefslogtreecommitdiff
path: root/portaudio/src/hostapi/wdmks
diff options
context:
space:
mode:
Diffstat (limited to 'portaudio/src/hostapi/wdmks')
-rw-r--r--portaudio/src/hostapi/wdmks/pa_win_wdmks.c6807
-rw-r--r--portaudio/src/hostapi/wdmks/readme.txt85
2 files changed, 0 insertions, 6892 deletions
diff --git a/portaudio/src/hostapi/wdmks/pa_win_wdmks.c b/portaudio/src/hostapi/wdmks/pa_win_wdmks.c
deleted file mode 100644
index 161c264..0000000
--- a/portaudio/src/hostapi/wdmks/pa_win_wdmks.c
+++ /dev/null
@@ -1,6807 +0,0 @@
-/*
-* $Id$
-* PortAudio Windows WDM-KS interface
-*
-* Author: Andrew Baldwin, Robert Bielik (WaveRT)
-* Based on the Open Source API proposed by Ross Bencina
-* Copyright (c) 1999-2004 Andrew Baldwin, Ross Bencina, Phil Burk
-*
-* Permission is hereby granted, free of charge, to any person obtaining
-* a copy of this software and associated documentation files
-* (the "Software"), to deal in the Software without restriction,
-* including without limitation the rights to use, copy, modify, merge,
-* publish, distribute, sublicense, and/or sell copies of the Software,
-* and to permit persons to whom the Software is furnished to do so,
-* subject to the following conditions:
-*
-* The above copyright notice and this permission notice shall be
-* included in all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
-* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
-* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-/*
-* 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
-* license above.
-*/
-
-/** @file
-@ingroup hostapi_src
-@brief Portaudio WDM-KS host API.
-
-@note This is the implementation of the Portaudio host API using the
-Windows WDM/Kernel Streaming API in order to enable very low latency
-playback and recording on all modern Windows platforms (e.g. 2K, XP, Vista, Win7)
-Note: This API accesses the device drivers below the usual KMIXER
-component which is normally used to enable multi-client mixing and
-format conversion. That means that it will lock out all other users
-of a device for the duration of active stream using those devices
-*/
-
-#include <stdio.h>
-
-#if (defined(_WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */
-#pragma comment( lib, "setupapi.lib" )
-#endif
-
-/* Debugging/tracing support */
-
-#define PA_LOGE_
-#define PA_LOGL_
-
-#ifdef __GNUC__
-#include <initguid.h>
-#define _WIN32_WINNT 0x0501
-#define WINVER 0x0501
-#endif
-
-#include <string.h> /* strlen() */
-#include <assert.h>
-#include <wchar.h> /* iswspace() */
-
-#include "pa_util.h"
-#include "pa_allocation.h"
-#include "pa_hostapi.h"
-#include "pa_stream.h"
-#include "pa_cpuload.h"
-#include "pa_process.h"
-#include "portaudio.h"
-#include "pa_debugprint.h"
-#include "pa_memorybarrier.h"
-#include "pa_ringbuffer.h"
-#include "pa_trace.h"
-#include "pa_win_waveformat.h"
-
-#include "pa_win_wdmks.h"
-
-#ifndef DRV_QUERYDEVICEINTERFACE
-#define DRV_QUERYDEVICEINTERFACE (DRV_RESERVED + 12)
-#endif
-#ifndef DRV_QUERYDEVICEINTERFACESIZE
-#define DRV_QUERYDEVICEINTERFACESIZE (DRV_RESERVED + 13)
-#endif
-
-#include <windows.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>
-
-#ifdef _MSC_VER
-#define snprintf _snprintf
-#define vsnprintf _vsnprintf
-#endif
-
-/* The PA_HP_TRACE macro is used in RT parts, so it can be switched off without affecting
-the rest of the debug tracing */
-#if 1
-#define PA_HP_TRACE(x) PaUtil_AddHighSpeedLogMessage x ;
-#else
-#define PA_HP_TRACE(x)
-#endif
-
-/* A define that selects whether the resulting pin names are chosen from pin category
-instead of the available pin names, who sometimes can be quite cheesy, like "Volume control".
-Default is to use the pin category.
-*/
-#ifndef PA_WDMKS_USE_CATEGORY_FOR_PIN_NAMES
-#define PA_WDMKS_USE_CATEGORY_FOR_PIN_NAMES 1
-#endif
-
-#ifdef __GNUC__
-#undef PA_LOGE_
-#define PA_LOGE_ PA_DEBUG(("%s {\n",__FUNCTION__))
-#undef PA_LOGL_
-#define PA_LOGL_ PA_DEBUG(("} %s\n",__FUNCTION__))
-/* These defines are set in order to allow the WIndows DirectX
-* headers to compile with a GCC compiler such as MinGW
-* NOTE: The headers may generate a few warning in GCC, but
-* they should compile */
-#define _INC_MMSYSTEM
-#define _INC_MMREG
-#define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */
-#define DEFINE_GUID_THUNK(name,guid) DEFINE_GUID(name,guid)
-#define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK( n, STATIC_##n )
-#if !defined( DEFINE_WAVEFORMATEX_GUID )
-#define DEFINE_WAVEFORMATEX_GUID(x) (USHORT)(x), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
-#endif
-#define WAVE_FORMAT_ADPCM 0x0002
-#define WAVE_FORMAT_IEEE_FLOAT 0x0003
-#define WAVE_FORMAT_ALAW 0x0006
-#define WAVE_FORMAT_MULAW 0x0007
-#define WAVE_FORMAT_MPEG 0x0050
-#define WAVE_FORMAT_DRM 0x0009
-#define DYNAMIC_GUID_THUNK(l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
-#define DYNAMIC_GUID(data) DYNAMIC_GUID_THUNK(data)
-#endif
-
-/* use CreateThread for CYGWIN/Windows Mobile, _beginthreadex for all others */
-#if !defined(__CYGWIN__) && !defined(_WIN32_WCE)
-#define CREATE_THREAD_FUNCTION (HANDLE)_beginthreadex
-#define PA_THREAD_FUNC static unsigned WINAPI
-#else
-#define CREATE_THREAD_FUNCTION CreateThread
-#define PA_THREAD_FUNC static DWORD WINAPI
-#endif
-
-#ifdef _MSC_VER
-#define NOMMIDS
-#define DYNAMIC_GUID(data) {data}
-#define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */
-#undef DEFINE_GUID
-#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>
-
-#ifndef EXTERN_C
-#define EXTERN_C extern
-#endif
-
-#if defined(__GNUC__)
-
-/* For MinGW we reference mingw-include files supplied with WASAPI */
-#define WINBOOL BOOL
-
-#include "../wasapi/mingw-include/ks.h"
-#include "../wasapi/mingw-include/ksmedia.h"
-
-#else
-
-#include <mmreg.h>
-#include <ks.h>
-
-/* Note that Windows SDK V6.0A or later is needed for WaveRT specific structs to be present in
- ksmedia.h. Also make sure that the SDK include path is before other include paths (that may contain
- an "old" ksmedia.h), so the proper ksmedia.h is used */
-#include <ksmedia.h>
-
-#endif
-
-#include <assert.h>
-#include <stdio.h>
-
-/* These next definitions allow the use of the KSUSER DLL */
-typedef /*KSDDKAPI*/ DWORD WINAPI KSCREATEPIN(HANDLE, PKSPIN_CONNECT, ACCESS_MASK, PHANDLE);
-extern HMODULE DllKsUser;
-extern KSCREATEPIN* FunctionKsCreatePin;
-
-/* These definitions allows the use of AVRT.DLL on Vista and later OSs */
-typedef enum _PA_AVRT_PRIORITY
-{
- PA_AVRT_PRIORITY_LOW = -1,
- PA_AVRT_PRIORITY_NORMAL,
- PA_AVRT_PRIORITY_HIGH,
- PA_AVRT_PRIORITY_CRITICAL
-} PA_AVRT_PRIORITY, *PPA_AVRT_PRIORITY;
-
-typedef struct
-{
- HINSTANCE hInstance;
-
- HANDLE (WINAPI *AvSetMmThreadCharacteristics) (LPCSTR, LPDWORD);
- BOOL (WINAPI *AvRevertMmThreadCharacteristics) (HANDLE);
- BOOL (WINAPI *AvSetMmThreadPriority) (HANDLE, PA_AVRT_PRIORITY);
-} PaWinWDMKSAvRtEntryPoints;
-
-static PaWinWDMKSAvRtEntryPoints paWinWDMKSAvRtEntryPoints = {0};
-
-/* An unspecified channel count (-1) is not treated correctly, so we replace it with
-* an arbitrarily large number */
-#define MAXIMUM_NUMBER_OF_CHANNELS 256
-
-/* Forward definition to break circular type reference between pin and filter */
-struct __PaWinWdmFilter;
-typedef struct __PaWinWdmFilter PaWinWdmFilter;
-
-struct __PaWinWdmPin;
-typedef struct __PaWinWdmPin PaWinWdmPin;
-
-struct __PaWinWdmStream;
-typedef struct __PaWinWdmStream PaWinWdmStream;
-
-/* Function prototype for getting audio position */
-typedef PaError (*FunctionGetPinAudioPosition)(PaWinWdmPin*, unsigned long*);
-
-/* Function prototype for memory barrier */
-typedef void (*FunctionMemoryBarrier)(void);
-
-struct __PaProcessThreadInfo;
-typedef struct __PaProcessThreadInfo PaProcessThreadInfo;
-
-typedef PaError (*FunctionPinHandler)(PaProcessThreadInfo* pInfo, unsigned eventIndex);
-
-typedef enum __PaStreamStartEnum
-{
- StreamStart_kOk,
- StreamStart_kFailed,
- StreamStart_kCnt
-} PaStreamStartEnum;
-
-/* Multiplexed input structure.
-* Very often several physical inputs are multiplexed through a MUX node (represented in the topology filter) */
-typedef struct __PaWinWdmMuxedInput
-{
- wchar_t friendlyName[MAX_PATH];
- ULONG muxPinId;
- ULONG muxNodeId;
- ULONG endpointPinId;
-} PaWinWdmMuxedInput;
-
-/* The Pin structure
-* A pin is an input or output node, e.g. for audio flow */
-struct __PaWinWdmPin
-{
- HANDLE handle;
- PaWinWdmMuxedInput** inputs;
- unsigned inputCount;
- wchar_t friendlyName[MAX_PATH];
-
- PaWinWdmFilter* parentFilter;
- PaWDMKSSubType pinKsSubType;
- unsigned long pinId;
- unsigned long endpointPinId; /* For output pins */
- KSPIN_CONNECT* pinConnect;
- unsigned long pinConnectSize;
- KSDATAFORMAT_WAVEFORMATEX* ksDataFormatWfx;
- KSPIN_COMMUNICATION communication;
- KSDATARANGE* dataRanges;
- KSMULTIPLE_ITEM* dataRangesItem;
- KSPIN_DATAFLOW dataFlow;
- KSPIN_CINSTANCES instances;
- unsigned long frameSize;
- int maxChannels;
- unsigned long formats;
- int defaultSampleRate;
- ULONG *positionRegister; /* WaveRT */
- ULONG hwLatency; /* WaveRT */
- FunctionMemoryBarrier fnMemBarrier; /* WaveRT */
- FunctionGetPinAudioPosition fnAudioPosition; /* WaveRT */
- FunctionPinHandler fnEventHandler;
- FunctionPinHandler fnSubmitHandler;
-};
-
-/* The Filter structure
-* A filter has a number of pins and a "friendly name" */
-struct __PaWinWdmFilter
-{
- HANDLE handle;
- PaWinWDMKSDeviceInfo devInfo; /* This will hold information that is exposed in PaDeviceInfo */
-
- DWORD deviceNode;
- int pinCount;
- PaWinWdmPin** pins;
- PaWinWdmFilter* topologyFilter;
- wchar_t friendlyName[MAX_PATH];
- int validPinCount;
- int usageCount;
- KSMULTIPLE_ITEM* connections;
- KSMULTIPLE_ITEM* nodes;
- int filterRefCount;
-};
-
-
-typedef struct __PaWinWdmDeviceInfo
-{
- PaDeviceInfo inheritedDeviceInfo;
- char compositeName[MAX_PATH]; /* Composite name consists of pin name + device name in utf8 */
- PaWinWdmFilter* filter;
- unsigned long pin;
- int muxPosition; /* Used only for input devices */
- int endpointPinId;
-}
-PaWinWdmDeviceInfo;
-
-/* PaWinWdmHostApiRepresentation - host api datastructure specific to this implementation */
-typedef struct __PaWinWdmHostApiRepresentation
-{
- PaUtilHostApiRepresentation inheritedHostApiRep;
- PaUtilStreamInterface callbackStreamInterface;
- PaUtilStreamInterface blockingStreamInterface;
-
- PaUtilAllocationGroup* allocations;
- int deviceCount;
-}
-PaWinWdmHostApiRepresentation;
-
-typedef struct __DATAPACKET
-{
- KSSTREAM_HEADER Header;
- OVERLAPPED Signal;
-} DATAPACKET;
-
-typedef struct __PaIOPacket
-{
- DATAPACKET* packet;
- unsigned startByte;
- unsigned lengthBytes;
-} PaIOPacket;
-
-typedef struct __PaWinWdmIOInfo
-{
- PaWinWdmPin* pPin;
- char* hostBuffer;
- unsigned hostBufferSize;
- unsigned framesPerBuffer;
- unsigned bytesPerFrame;
- unsigned bytesPerSample;
- unsigned noOfPackets; /* Only used in WaveCyclic */
- HANDLE *events; /* noOfPackets handles (WaveCyclic) 1 (WaveRT) */
- DATAPACKET *packets; /* noOfPackets packets (WaveCyclic) 2 (WaveRT) */
- /* WaveRT polled mode */
- unsigned lastPosition;
- unsigned pollCntr;
-} PaWinWdmIOInfo;
-
-/* PaWinWdmStream - a stream data structure specifically for this implementation */
-struct __PaWinWdmStream
-{
- PaUtilStreamRepresentation streamRepresentation;
- PaWDMKSSpecificStreamInfo hostApiStreamInfo; /* This holds info that is exposed through PaStreamInfo */
- PaUtilCpuLoadMeasurer cpuLoadMeasurer;
- PaUtilBufferProcessor bufferProcessor;
-
-#if PA_TRACE_REALTIME_EVENTS
- LogHandle hLog;
-#endif
-
- PaUtilAllocationGroup* allocGroup;
- PaWinWdmIOInfo capture;
- PaWinWdmIOInfo render;
- int streamStarted;
- int streamActive;
- int streamStop;
- int streamAbort;
- int oldProcessPriority;
- HANDLE streamThread;
- HANDLE eventAbort;
- HANDLE eventStreamStart[StreamStart_kCnt]; /* 0 = OK, 1 = Failed */
- PaError threadResult;
- PaStreamFlags streamFlags;
-
- /* Capture ring buffer */
- PaUtilRingBuffer ringBuffer;
- char* ringBufferData;
-
- /* These values handle the case where the user wants to use fewer
- * channels than the device has */
- int userInputChannels;
- int deviceInputChannels;
- int userOutputChannels;
- int deviceOutputChannels;
-};
-
-/* Gather all processing variables in a struct */
-struct __PaProcessThreadInfo
-{
- PaWinWdmStream *stream;
- PaStreamCallbackTimeInfo ti;
- PaStreamCallbackFlags underover;
- int cbResult;
- volatile int pending;
- volatile int priming;
- volatile int pinsStarted;
- unsigned long timeout;
- unsigned captureHead;
- unsigned captureTail;
- unsigned renderHead;
- unsigned renderTail;
- PaIOPacket capturePackets[4];
- PaIOPacket renderPackets[4];
-};
-
-/* Used for transferring device infos during scanning / rescanning */
-typedef struct __PaWinWDMScanDeviceInfosResults
-{
- PaDeviceInfo **deviceInfos;
- PaDeviceIndex defaultInputDevice;
- PaDeviceIndex defaultOutputDevice;
-} PaWinWDMScanDeviceInfosResults;
-
-static const unsigned cPacketsArrayMask = 3;
-
-HMODULE DllKsUser = NULL;
-KSCREATEPIN* FunctionKsCreatePin = NULL;
-
-/* prototypes for functions declared in this file */
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
- PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-/* Low level I/O functions */
-static PaError WdmSyncIoctl(HANDLE handle,
- unsigned long ioctlNumber,
- void* inBuffer,
- unsigned long inBufferCount,
- void* outBuffer,
- unsigned long outBufferCount,
- unsigned long* bytesReturned);
-
-static PaError WdmGetPropertySimple(HANDLE handle,
- const GUID* const guidPropertySet,
- unsigned long property,
- void* value,
- unsigned long valueCount);
-
-static PaError WdmSetPropertySimple(HANDLE handle,
- const GUID* const guidPropertySet,
- unsigned long property,
- void* value,
- unsigned long valueCount,
- void* instance,
- unsigned long instanceCount);
-
-static PaError WdmGetPinPropertySimple(HANDLE handle,
- unsigned long pinId,
- const GUID* const guidPropertySet,
- unsigned long property,
- void* value,
- unsigned long valueCount,
- unsigned long* byteCount);
-
-static PaError WdmGetPinPropertyMulti(HANDLE handle,
- unsigned long pinId,
- const GUID* const guidPropertySet,
- unsigned long property,
- KSMULTIPLE_ITEM** ksMultipleItem);
-
-static PaError WdmGetPropertyMulti(HANDLE handle,
- const GUID* const guidPropertySet,
- unsigned long property,
- KSMULTIPLE_ITEM** ksMultipleItem);
-
-static PaError WdmSetMuxNodeProperty(HANDLE handle,
- ULONG nodeId,
- ULONG pinId);
-
-
-/** Pin management functions */
-static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, PaError* error);
-static void PinFree(PaWinWdmPin* pin);
-static void PinClose(PaWinWdmPin* pin);
-static PaError PinInstantiate(PaWinWdmPin* pin);
-/*static PaError PinGetState(PaWinWdmPin* pin, KSSTATE* state); NOT USED */
-static PaError PinSetState(PaWinWdmPin* pin, KSSTATE state);
-static PaError PinSetFormat(PaWinWdmPin* pin, const WAVEFORMATEX* format);
-static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format);
-/* WaveRT support */
-static PaError PinQueryNotificationSupport(PaWinWdmPin* pPin, BOOL* pbResult);
-static PaError PinGetBuffer(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier);
-static PaError PinRegisterPositionRegister(PaWinWdmPin* pPin);
-static PaError PinRegisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle);
-static PaError PinUnregisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle);
-static PaError PinGetHwLatency(PaWinWdmPin* pPin, ULONG* pFifoSize, ULONG* pChipsetDelay, ULONG* pCodecDelay);
-static PaError PinGetAudioPositionMemoryMapped(PaWinWdmPin* pPin, ULONG* pPosition);
-static PaError PinGetAudioPositionViaIOCTLRead(PaWinWdmPin* pPin, ULONG* pPosition);
-static PaError PinGetAudioPositionViaIOCTLWrite(PaWinWdmPin* pPin, ULONG* pPosition);
-
-/* Filter management functions */
-static PaWinWdmFilter* FilterNew(PaWDMKSType type, DWORD devNode, const wchar_t* filterName, const wchar_t* friendlyName, PaError* error);
-static PaError FilterInitializePins(PaWinWdmFilter* filter);
-static void FilterFree(PaWinWdmFilter* filter);
-static void FilterAddRef(PaWinWdmFilter* filter);
-static PaWinWdmPin* FilterCreatePin(
- PaWinWdmFilter* filter,
- int pinId,
- const WAVEFORMATEX* wfex,
- PaError* error);
-static PaError FilterUse(PaWinWdmFilter* filter);
-static void FilterRelease(PaWinWdmFilter* filter);
-
-/* Hot plug functions */
-static BOOL IsDeviceTheSame(const PaWinWdmDeviceInfo* pDev1,
- const PaWinWdmDeviceInfo* pDev2);
-
-/* Interface functions */
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
-static PaError IsFormatSupported(
-struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate );
-
-static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void **newDeviceInfos, int *newDeviceCount );
-static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *deviceInfos, int deviceCount );
-static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *deviceInfos, int deviceCount );
-
-static PaError OpenStream(
-struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData );
-static PaError CloseStream( PaStream* stream );
-static PaError StartStream( PaStream *stream );
-static PaError StopStream( PaStream *stream );
-static PaError AbortStream( PaStream *stream );
-static PaError IsStreamStopped( PaStream *s );
-static PaError IsStreamActive( PaStream *stream );
-static PaTime GetStreamTime( PaStream *stream );
-static double GetStreamCpuLoad( PaStream* stream );
-static PaError ReadStream(
- PaStream* stream,
- void *buffer,
- unsigned long frames );
-static PaError WriteStream(
- PaStream* stream,
- const void *buffer,
- unsigned long frames );
-static signed long GetStreamReadAvailable( PaStream* stream );
-static signed long GetStreamWriteAvailable( PaStream* stream );
-
-/* Utility functions */
-static unsigned long GetWfexSize(const WAVEFORMATEX* wfex);
-static PaWinWdmFilter** BuildFilterList(int* filterCount, int* noOfPaDevices, PaError* result);
-static BOOL PinWrite(HANDLE h, DATAPACKET* p);
-static BOOL PinRead(HANDLE h, DATAPACKET* p);
-static void DuplicateFirstChannelInt16(void* buffer, int channels, int samples);
-static void DuplicateFirstChannelInt24(void* buffer, int channels, int samples);
-PA_THREAD_FUNC ProcessingThread(void*);
-
-/* Pin handler functions */
-static PaError PaPinCaptureEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex);
-static PaError PaPinCaptureSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex);
-
-static PaError PaPinRenderEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex);
-static PaError PaPinRenderSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex);
-
-static PaError PaPinCaptureEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex);
-static PaError PaPinCaptureEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex);
-static PaError PaPinCaptureSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex);
-static PaError PaPinCaptureSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex);
-
-static PaError PaPinRenderEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex);
-static PaError PaPinRenderEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex);
-static PaError PaPinRenderSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex);
-static PaError PaPinRenderSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex);
-
-/* Function bodies */
-
-#if defined(_DEBUG) && defined(PA_ENABLE_DEBUG_OUTPUT)
-#define PA_WDMKS_SET_TREF
-static PaTime tRef = 0;
-
-static void PaWinWdmDebugPrintf(const char* fmt, ...)
-{
- va_list list;
- char buffer[1024];
- PaTime t = PaUtil_GetTime() - tRef;
- va_start(list, fmt);
- _vsnprintf(buffer, 1023, fmt, list);
- va_end(list);
- PaUtil_DebugPrint("%6.3lf: %s", t, buffer);
-}
-
-#ifdef PA_DEBUG
-#undef PA_DEBUG
-#define PA_DEBUG(x) PaWinWdmDebugPrintf x ;
-#endif
-#endif
-
-static BOOL IsDeviceTheSame(const PaWinWdmDeviceInfo* pDev1,
- const PaWinWdmDeviceInfo* pDev2)
-{
- if (pDev1 == NULL || pDev2 == NULL)
- return FALSE;
-
- if (pDev1 == pDev2)
- return TRUE;
-
- if (strcmp(pDev1->compositeName, pDev2->compositeName) == 0)
- return TRUE;
-
- return FALSE;
-}
-
-static BOOL IsEarlierThanVista()
-{
-/*
-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 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
-*/
-#pragma warning (disable : 4996) /* use of GetVersionEx */
-
- OSVERSIONINFO osvi;
- osvi.dwOSVersionInfoSize = sizeof(osvi);
- if (GetVersionEx(&osvi) && osvi.dwMajorVersion<6)
- {
- return TRUE;
- }
- return FALSE;
-
-#pragma warning (default : 4996)
-}
-
-
-
-static void MemoryBarrierDummy(void)
-{
- /* Do nothing */
-}
-
-static void MemoryBarrierRead(void)
-{
- PaUtil_ReadMemoryBarrier();
-}
-
-static void MemoryBarrierWrite(void)
-{
- PaUtil_WriteMemoryBarrier();
-}
-
-static unsigned long GetWfexSize(const WAVEFORMATEX* wfex)
-{
- if( wfex->wFormatTag == WAVE_FORMAT_PCM )
- {
- return sizeof( WAVEFORMATEX );
- }
- else
- {
- return (sizeof( WAVEFORMATEX ) + wfex->cbSize);
- }
-}
-
-static void PaWinWDM_SetLastErrorInfo(long errCode, const char* fmt, ...)
-{
- va_list list;
- char buffer[1024];
- va_start(list, fmt);
- _vsnprintf(buffer, 1023, fmt, list);
- va_end(list);
- PaUtil_SetLastHostErrorInfo(paWDMKS, errCode, buffer);
-}
-
-/*
-Low level pin/filter access functions
-*/
-static PaError WdmSyncIoctl(
- HANDLE handle,
- unsigned long ioctlNumber,
- void* inBuffer,
- unsigned long inBufferCount,
- void* outBuffer,
- unsigned long outBufferCount,
- unsigned long* bytesReturned)
-{
- PaError result = paNoError;
- unsigned long dummyBytesReturned = 0;
- BOOL bRes;
-
- if( !bytesReturned )
- {
- /* Use a dummy as the caller hasn't supplied one */
- bytesReturned = &dummyBytesReturned;
- }
-
- bRes = DeviceIoControl(handle, ioctlNumber, inBuffer, inBufferCount, outBuffer, outBufferCount, bytesReturned, NULL);
- if (!bRes)
- {
- unsigned long error = GetLastError();
- if ( !(((error == ERROR_INSUFFICIENT_BUFFER ) || ( error == ERROR_MORE_DATA )) &&
- ( ioctlNumber == IOCTL_KS_PROPERTY ) &&
- ( outBufferCount == 0 ) ) )
- {
- KSPROPERTY* ksProperty = (KSPROPERTY*)inBuffer;
-
- PaWinWDM_SetLastErrorInfo(result, "WdmSyncIoctl: DeviceIoControl GLE = 0x%08X (prop_set = {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}, prop_id = %u)",
- error,
- ksProperty->Set.Data1, ksProperty->Set.Data2, ksProperty->Set.Data3,
- ksProperty->Set.Data4[0], ksProperty->Set.Data4[1],
- ksProperty->Set.Data4[2], ksProperty->Set.Data4[3],
- ksProperty->Set.Data4[4], ksProperty->Set.Data4[5],
- ksProperty->Set.Data4[6], ksProperty->Set.Data4[7],
- ksProperty->Id
- );
- result = paUnanticipatedHostError;
- }
- }
- return result;
-}
-
-static PaError WdmGetPropertySimple(HANDLE handle,
- const GUID* const guidPropertySet,
- unsigned long property,
- void* value,
- unsigned long valueCount)
-{
- PaError result;
- KSPROPERTY ksProperty;
-
- ksProperty.Set = *guidPropertySet;
- ksProperty.Id = property;
- ksProperty.Flags = KSPROPERTY_TYPE_GET;
-
- result = WdmSyncIoctl(
- handle,
- IOCTL_KS_PROPERTY,
- &ksProperty,
- sizeof(KSPROPERTY),
- value,
- valueCount,
- NULL);
-
- return result;
-}
-
-static PaError WdmSetPropertySimple(
- HANDLE handle,
- const GUID* const guidPropertySet,
- unsigned long property,
- void* value,
- unsigned long valueCount,
- void* instance,
- unsigned long instanceCount)
-{
- PaError result;
- KSPROPERTY* ksProperty;
- unsigned long propertyCount = 0;
-
- propertyCount = sizeof(KSPROPERTY) + instanceCount;
- ksProperty = (KSPROPERTY*)_alloca( propertyCount );
- if( !ksProperty )
- {
- return paInsufficientMemory;
- }
-
- ksProperty->Set = *guidPropertySet;
- ksProperty->Id = property;
- ksProperty->Flags = KSPROPERTY_TYPE_SET;
-
- if( instance )
- {
- memcpy((void*)((char*)ksProperty + sizeof(KSPROPERTY)), instance, instanceCount);
- }
-
- result = WdmSyncIoctl(
- handle,
- IOCTL_KS_PROPERTY,
- ksProperty,
- propertyCount,
- value,
- valueCount,
- NULL);
-
- return result;
-}
-
-static PaError WdmGetPinPropertySimple(
- HANDLE handle,
- unsigned long pinId,
- const GUID* const guidPropertySet,
- unsigned long property,
- void* value,
- unsigned long valueCount,
- unsigned long *byteCount)
-{
- PaError result;
-
- KSP_PIN ksPProp;
- ksPProp.Property.Set = *guidPropertySet;
- ksPProp.Property.Id = property;
- ksPProp.Property.Flags = KSPROPERTY_TYPE_GET;
- ksPProp.PinId = pinId;
- ksPProp.Reserved = 0;
-
- result = WdmSyncIoctl(
- handle,
- IOCTL_KS_PROPERTY,
- &ksPProp,
- sizeof(KSP_PIN),
- value,
- valueCount,
- byteCount);
-
- return result;
-}
-
-static PaError WdmGetPinPropertyMulti(
- HANDLE handle,
- unsigned long pinId,
- const GUID* const guidPropertySet,
- unsigned long property,
- KSMULTIPLE_ITEM** ksMultipleItem)
-{
- PaError result;
- unsigned long multipleItemSize = 0;
- KSP_PIN ksPProp;
-
- ksPProp.Property.Set = *guidPropertySet;
- ksPProp.Property.Id = property;
- ksPProp.Property.Flags = KSPROPERTY_TYPE_GET;
- ksPProp.PinId = pinId;
- ksPProp.Reserved = 0;
-
- result = WdmSyncIoctl(
- handle,
- IOCTL_KS_PROPERTY,
- &ksPProp.Property,
- sizeof(KSP_PIN),
- NULL,
- 0,
- &multipleItemSize);
- if( result != paNoError )
- {
- return result;
- }
-
- *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize );
- if( !*ksMultipleItem )
- {
- return paInsufficientMemory;
- }
-
- result = WdmSyncIoctl(
- handle,
- IOCTL_KS_PROPERTY,
- &ksPProp,
- sizeof(KSP_PIN),
- (void*)*ksMultipleItem,
- multipleItemSize,
- NULL);
-
- if( result != paNoError )
- {
- PaUtil_FreeMemory( ksMultipleItem );
- }
-
- return result;
-}
-
-static PaError WdmGetPropertyMulti(HANDLE handle,
- const GUID* const guidPropertySet,
- unsigned long property,
- KSMULTIPLE_ITEM** ksMultipleItem)
-{
- PaError result;
- unsigned long multipleItemSize = 0;
- KSPROPERTY ksProp;
-
- ksProp.Set = *guidPropertySet;
- ksProp.Id = property;
- ksProp.Flags = KSPROPERTY_TYPE_GET;
-
- result = WdmSyncIoctl(
- handle,
- IOCTL_KS_PROPERTY,
- &ksProp,
- sizeof(KSPROPERTY),
- NULL,
- 0,
- &multipleItemSize);
- if( result != paNoError )
- {
- return result;
- }
-
- *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize );
- if( !*ksMultipleItem )
- {
- return paInsufficientMemory;
- }
-
- result = WdmSyncIoctl(
- handle,
- IOCTL_KS_PROPERTY,
- &ksProp,
- sizeof(KSPROPERTY),
- (void*)*ksMultipleItem,
- multipleItemSize,
- NULL);
-
- if( result != paNoError )
- {
- PaUtil_FreeMemory( ksMultipleItem );
- }
-
- return result;
-}
-
-static PaError WdmSetMuxNodeProperty(HANDLE handle,
- ULONG nodeId,
- ULONG pinId)
-{
- PaError result = paNoError;
- KSNODEPROPERTY prop;
- prop.Property.Set = KSPROPSETID_Audio;
- prop.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE;
- prop.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY;
- prop.NodeId = nodeId;
- prop.Reserved = 0;
-
- result = WdmSyncIoctl(handle, IOCTL_KS_PROPERTY, &prop, sizeof(KSNODEPROPERTY), &pinId, sizeof(ULONG), NULL);
-
- return result;
-}
-
-/* Used when traversing topology for outputs */
-static const KSTOPOLOGY_CONNECTION* GetConnectionTo(const KSTOPOLOGY_CONNECTION* pFrom, PaWinWdmFilter* filter, int muxIdx)
-{
- unsigned i;
- const KSTOPOLOGY_CONNECTION* retval = NULL;
- const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
- (void)muxIdx;
- PA_DEBUG(("GetConnectionTo: Checking %u connections... (pFrom = %p)", filter->connections->Count, pFrom));
- for (i = 0; i < filter->connections->Count; ++i)
- {
- const KSTOPOLOGY_CONNECTION* pConn = connections + i;
- if (pConn == pFrom)
- continue;
-
- if (pConn->FromNode == pFrom->ToNode)
- {
- retval = pConn;
- break;
- }
- }
- PA_DEBUG(("GetConnectionTo: Returning %p\n", retval));
- return retval;
-}
-
-/* Used when traversing topology for inputs */
-static const KSTOPOLOGY_CONNECTION* GetConnectionFrom(const KSTOPOLOGY_CONNECTION* pTo, PaWinWdmFilter* filter, int muxIdx)
-{
- unsigned i;
- const KSTOPOLOGY_CONNECTION* retval = NULL;
- const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
- int muxCntr = 0;
- PA_DEBUG(("GetConnectionFrom: Checking %u connections... (pTo = %p)\n", filter->connections->Count, pTo));
- for (i = 0; i < filter->connections->Count; ++i)
- {
- const KSTOPOLOGY_CONNECTION* pConn = connections + i;
- if (pConn == pTo)
- continue;
-
- if (pConn->ToNode == pTo->FromNode)
- {
- if (muxIdx >= 0)
- {
- if (muxCntr < muxIdx)
- {
- ++muxCntr;
- continue;
- }
- }
- retval = pConn;
- break;
- }
- }
- PA_DEBUG(("GetConnectionFrom: Returning %p\n", retval));
- return retval;
-}
-
-static ULONG GetNumberOfConnectionsTo(const KSTOPOLOGY_CONNECTION* pTo, PaWinWdmFilter* filter)
-{
- ULONG retval = 0;
- unsigned i;
- const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
- PA_DEBUG(("GetNumberOfConnectionsTo: Checking %u connections...\n", filter->connections->Count));
- for (i = 0; i < filter->connections->Count; ++i)
- {
- const KSTOPOLOGY_CONNECTION* pConn = connections + i;
- if (pConn->ToNode == pTo->FromNode &&
- (pTo->FromNode != KSFILTER_NODE || pConn->ToNodePin == pTo->FromNodePin))
- {
- ++retval;
- }
- }
- PA_DEBUG(("GetNumberOfConnectionsTo: Returning %d\n", retval));
- return retval;
-}
-
-typedef const KSTOPOLOGY_CONNECTION *(*TFnGetConnection)(const KSTOPOLOGY_CONNECTION*, PaWinWdmFilter*, int);
-
-static const KSTOPOLOGY_CONNECTION* FindStartConnectionFrom(ULONG startPin, PaWinWdmFilter* filter)
-{
- unsigned i;
- const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
- PA_DEBUG(("FindStartConnectionFrom: Startpin %u, Checking %u connections...\n", startPin, filter->connections->Count));
- for (i = 0; i < filter->connections->Count; ++i)
- {
- const KSTOPOLOGY_CONNECTION* pConn = connections + i;
- if (pConn->ToNode == KSFILTER_NODE && pConn->ToNodePin == startPin)
- {
- PA_DEBUG(("FindStartConnectionFrom: returning %p\n", pConn));
- return pConn;
- }
- }
-
- /* 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"));
- return 0;
-}
-
-static const KSTOPOLOGY_CONNECTION* FindStartConnectionTo(ULONG startPin, PaWinWdmFilter* filter)
-{
- unsigned i;
- const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
- PA_DEBUG(("FindStartConnectionTo: Startpin %u, Checking %u connections...\n", startPin, filter->connections->Count));
- for (i = 0; i < filter->connections->Count; ++i)
- {
- const KSTOPOLOGY_CONNECTION* pConn = connections + i;
- if (pConn->FromNode == KSFILTER_NODE && pConn->FromNodePin == startPin)
- {
- PA_DEBUG(("FindStartConnectionTo: returning %p\n", pConn));
- return pConn;
- }
- }
-
- /* Unconnected pin. Inform caller. */
- PA_DEBUG(("FindStartConnectionTo: returning NULL\n"));
- 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;
- TFnGetConnection fnGetConnection = forward ? GetConnectionTo : GetConnectionFrom ;
- PA_LOGE_;
- while (1)
- {
- limit--;
- if (limit == 0) {
- PA_DEBUG(("GetConnectedPin: LOOP LIMIT REACHED\n"));
- break;
- }
-
- if (conn == NULL)
- {
- conn = forward ? FindStartConnectionTo(startPin, filter) : FindStartConnectionFrom(startPin, filter);
- }
- else
- {
- conn = fnGetConnection(conn, filter, -1);
- }
-
- /* Handling case of erroneous connection list */
- if (conn == NULL)
- {
- break;
- }
-
- if (forward ? conn->ToNode == KSFILTER_NODE : conn->FromNode == KSFILTER_NODE)
- {
- return forward ? conn->ToNodePin : conn->FromNodePin;
- }
- else
- {
- PA_DEBUG(("GetConnectedPin: count=%d, forward=%d, muxPosition=%d\n", filter->nodes->Count, forward, muxPosition));
- if (filter->nodes->Count > 0 && !forward && muxPosition >= 0)
- {
- const GUID* nodes = (const GUID*)(filter->nodes + 1);
- if (IsEqualGUID(&nodes[conn->FromNode], &KSNODETYPE_MUX))
- {
- ULONG nConn = GetNumberOfConnectionsTo(conn, filter);
- conn = fnGetConnection(conn, filter, muxPosition);
- if (conn == NULL)
- {
- break;
- }
- if (muxInputPinId != 0)
- {
- *muxInputPinId = conn->ToNodePin;
- }
- if (muxNodeId != 0)
- {
- *muxNodeId = conn->ToNode;
- }
- }
- }
- }
- }
- PA_LOGL_;
- return KSFILTER_NODE;
-}
-
-static void DumpConnectionsAndNodes(PaWinWdmFilter* filter)
-{
- unsigned i;
- const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
- const GUID* nodes = (const GUID*)(filter->nodes + 1);
-
- PA_LOGE_;
- PA_DEBUG(("DumpConnectionsAndNodes: connections=%d, nodes=%d\n", filter->connections->Count, filter->nodes->Count));
-
- 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",
- i,
- pConn->FromNode, pConn->FromNodePin,
- pConn->ToNode, pConn->ToNodePin
- ));
- }
-
- for (i=0; i < filter->nodes->Count; ++i)
- {
- const GUID* pConn = nodes + i;
- PA_DEBUG((" Node: %d - {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
- i,
- pConn->Data1, pConn->Data2, pConn->Data3,
- pConn->Data4[0], pConn->Data4[1],
- pConn->Data4[2], pConn->Data4[3],
- pConn->Data4[4], pConn->Data4[5],
- pConn->Data4[6], pConn->Data4[7]
- ));
- }
- PA_LOGL_;
-
-}
-
-typedef struct __PaUsbTerminalGUIDToName
-{
- USHORT usbGUID;
- wchar_t name[64];
-} PaUsbTerminalGUIDToName;
-
-static const PaUsbTerminalGUIDToName kNames[] =
-{
- /* Types copied from: http://msdn.microsoft.com/en-us/library/ff537742(v=vs.85).aspx */
- /* Input terminal types */
- { 0x0201, L"Microphone" },
- { 0x0202, L"Desktop Microphone" },
- { 0x0203, L"Personal Microphone" },
- { 0x0204, L"Omni Directional Microphone" },
- { 0x0205, L"Microphone Array" },
- { 0x0206, L"Processing Microphone Array" },
- /* Output terminal types */
- { 0x0301, L"Speakers" },
- { 0x0302, L"Headphones" },
- { 0x0303, L"Head Mounted Display Audio" },
- { 0x0304, L"Desktop Speaker" },
- { 0x0305, L"Room Speaker" },
- { 0x0306, L"Communication Speaker" },
- { 0x0307, L"LFE Speakers" },
- /* External terminal types */
- { 0x0601, L"Analog" },
- { 0x0602, L"Digital" },
- { 0x0603, L"Line" },
- { 0x0604, L"Audio" },
- { 0x0605, L"SPDIF" },
-};
-
-static const unsigned kNamesCnt = sizeof(kNames)/sizeof(PaUsbTerminalGUIDToName);
-
-static int PaUsbTerminalGUIDToNameCmp(const void* lhs, const void* rhs)
-{
- const PaUsbTerminalGUIDToName* pL = (const PaUsbTerminalGUIDToName*)lhs;
- const PaUsbTerminalGUIDToName* pR = (const PaUsbTerminalGUIDToName*)rhs;
- return ((int)(pL->usbGUID) - (int)(pR->usbGUID));
-}
-
-static PaError GetNameFromCategory(const GUID* pGUID, BOOL input, wchar_t* name, unsigned length)
-{
- PaError result = paUnanticipatedHostError;
- USHORT usbTerminalGUID = (USHORT)(pGUID->Data1 - 0xDFF219E0);
-
- PA_LOGE_;
- if (input && usbTerminalGUID >= 0x301 && usbTerminalGUID < 0x400)
- {
- /* Output terminal name for an input !? Set it to Line! */
- usbTerminalGUID = 0x603;
- }
- if (!input && usbTerminalGUID >= 0x201 && usbTerminalGUID < 0x300)
- {
- /* Input terminal name for an output !? Set it to Line! */
- usbTerminalGUID = 0x603;
- }
- if (usbTerminalGUID >= 0x201 && usbTerminalGUID < 0x713)
- {
- PaUsbTerminalGUIDToName s = { usbTerminalGUID };
- const PaUsbTerminalGUIDToName* ptr = bsearch(
- &s,
- kNames,
- kNamesCnt,
- sizeof(PaUsbTerminalGUIDToName),
- PaUsbTerminalGUIDToNameCmp
- );
- if (ptr != 0)
- {
- PA_DEBUG(("GetNameFromCategory: USB GUID %04X -> '%S'\n", usbTerminalGUID, ptr->name));
-
- if (name != NULL && length > 0)
- {
- int n = _snwprintf(name, length, L"%s", ptr->name);
- if (usbTerminalGUID >= 0x601 && usbTerminalGUID < 0x700)
- {
- _snwprintf(name + n, length - n, L" %s", (input ? L"In":L"Out"));
- }
- }
- result = paNoError;
- }
- }
- else
- {
- PaWinWDM_SetLastErrorInfo(result, "GetNameFromCategory: usbTerminalGUID = %04X ", usbTerminalGUID);
- }
- PA_LOGL_;
- return result;
-}
-
-static BOOL IsFrequencyWithinRange(const KSDATARANGE_AUDIO* range, int frequency)
-{
- if (frequency < (int)range->MinimumSampleFrequency)
- return FALSE;
- if (frequency > (int)range->MaximumSampleFrequency)
- return FALSE;
- return TRUE;
-}
-
-static BOOL IsBitsWithinRange(const KSDATARANGE_AUDIO* range, int noOfBits)
-{
- if (noOfBits < (int)range->MinimumBitsPerSample)
- return FALSE;
- if (noOfBits > (int)range->MaximumBitsPerSample)
- return FALSE;
- return TRUE;
-}
-
-/* Note: Somewhat different order compared to WMME implementation, as we want to focus on fidelity first */
-static const int defaultSampleRateSearchOrder[] =
-{ 44100, 48000, 88200, 96000, 192000, 32000, 24000, 22050, 16000, 12000, 11025, 9600, 8000 };
-static const int defaultSampleRateSearchOrderCount = sizeof(defaultSampleRateSearchOrder)/sizeof(defaultSampleRateSearchOrder[0]);
-
-static int DefaultSampleFrequencyIndex(const KSDATARANGE_AUDIO* range)
-{
- int i;
-
- for(i=0; i < defaultSampleRateSearchOrderCount; ++i)
- {
- int currentFrequency = defaultSampleRateSearchOrder[i];
-
- if (IsFrequencyWithinRange(range, currentFrequency))
- {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
-Create a new pin object belonging to a filter
-The pin object holds all the configuration information about the pin
-before it is opened, and then the handle of the pin after is opened
-*/
-static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, PaError* error)
-{
- PaWinWdmPin* pin;
- PaError result;
- unsigned long i;
- KSMULTIPLE_ITEM* item = NULL;
- KSIDENTIFIER* identifier;
- KSDATARANGE* dataRange;
- const ULONG streamingId = (parentFilter->devInfo.streamingType == Type_kWaveRT) ? KSINTERFACE_STANDARD_LOOPED_STREAMING : KSINTERFACE_STANDARD_STREAMING;
- int defaultSampleRateIndex = defaultSampleRateSearchOrderCount;
-
- PA_LOGE_;
- PA_DEBUG(("PinNew: Creating pin %d:\n",pinId));
-
- /* Allocate the new PIN object */
- pin = (PaWinWdmPin*)PaUtil_AllocateMemory( sizeof(PaWinWdmPin) );
- if( !pin )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- /* Zero the pin object */
- /* memset( (void*)pin, 0, sizeof(PaWinWdmPin) ); */
-
- pin->parentFilter = parentFilter;
- pin->pinId = pinId;
-
- /* Allocate a connect structure */
- pin->pinConnectSize = sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX);
- pin->pinConnect = (KSPIN_CONNECT*)PaUtil_AllocateMemory( pin->pinConnectSize );
- if( !pin->pinConnect )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- /* Configure the connect structure with default values */
- pin->pinConnect->Interface.Set = KSINTERFACESETID_Standard;
- pin->pinConnect->Interface.Id = streamingId;
- pin->pinConnect->Interface.Flags = 0;
- pin->pinConnect->Medium.Set = KSMEDIUMSETID_Standard;
- pin->pinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
- pin->pinConnect->Medium.Flags = 0;
- pin->pinConnect->PinId = pinId;
- pin->pinConnect->PinToHandle = NULL;
- pin->pinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
- pin->pinConnect->Priority.PrioritySubClass = 1;
- pin->ksDataFormatWfx = (KSDATAFORMAT_WAVEFORMATEX*)(pin->pinConnect + 1);
- pin->ksDataFormatWfx->DataFormat.FormatSize = sizeof(KSDATAFORMAT_WAVEFORMATEX);
- pin->ksDataFormatWfx->DataFormat.Flags = 0;
- pin->ksDataFormatWfx->DataFormat.Reserved = 0;
- pin->ksDataFormatWfx->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
- pin->ksDataFormatWfx->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- pin->ksDataFormatWfx->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
-
- pin->frameSize = 0; /* Unknown until we instantiate pin */
-
- /* Get the COMMUNICATION property */
- result = WdmGetPinPropertySimple(
- parentFilter->handle,
- pinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_COMMUNICATION,
- &pin->communication,
- sizeof(KSPIN_COMMUNICATION),
- NULL);
- if( result != paNoError )
- goto error;
-
- if( /*(pin->communication != KSPIN_COMMUNICATION_SOURCE) &&*/
- (pin->communication != KSPIN_COMMUNICATION_SINK) &&
- (pin->communication != KSPIN_COMMUNICATION_BOTH) )
- {
- PA_DEBUG(("PinNew: Not source/sink\n"));
- result = paInvalidDevice;
- goto error;
- }
-
- /* Get dataflow information */
- result = WdmGetPinPropertySimple(
- parentFilter->handle,
- pinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_DATAFLOW,
- &pin->dataFlow,
- sizeof(KSPIN_DATAFLOW),
- NULL);
-
- if( result != paNoError )
- goto error;
-
- /* Get the INTERFACE property list */
- result = WdmGetPinPropertyMulti(
- parentFilter->handle,
- pinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_INTERFACES,
- &item);
-
- if( result != paNoError )
- goto error;
-
- identifier = (KSIDENTIFIER*)(item+1);
-
- /* Check that at least one interface is STANDARD_STREAMING */
- result = paUnanticipatedHostError;
- for( i = 0; i < item->Count; i++ )
- {
- if( IsEqualGUID(&identifier[i].Set, &KSINTERFACESETID_Standard) && ( identifier[i].Id == streamingId ) )
- {
- result = paNoError;
- break;
- }
- }
-
- if( result != paNoError )
- {
- PA_DEBUG(("PinNew: No %s streaming\n", streamingId==KSINTERFACE_STANDARD_LOOPED_STREAMING?"looped":"standard"));
- goto error;
- }
-
- /* Don't need interfaces any more */
- PaUtil_FreeMemory( item );
- item = NULL;
-
- /* Get the MEDIUM properties list */
- result = WdmGetPinPropertyMulti(
- parentFilter->handle,
- pinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_MEDIUMS,
- &item);
-
- if( result != paNoError )
- goto error;
-
- identifier = (KSIDENTIFIER*)(item+1); /* Not actually necessary... */
-
- /* Check that at least one medium is STANDARD_DEVIO */
- result = paUnanticipatedHostError;
- for( i = 0; i < item->Count; i++ )
- {
- if( IsEqualGUID(&identifier[i].Set, &KSMEDIUMSETID_Standard) && ( identifier[i].Id == KSMEDIUM_STANDARD_DEVIO ) )
- {
- result = paNoError;
- break;
- }
- }
-
- if( result != paNoError )
- {
- PA_DEBUG(("No standard devio\n"));
- goto error;
- }
- /* Don't need mediums any more */
- PaUtil_FreeMemory( item );
- item = NULL;
-
- /* Get DATARANGES */
- result = WdmGetPinPropertyMulti(
- parentFilter->handle,
- pinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_DATARANGES,
- &pin->dataRangesItem);
-
- if( result != paNoError )
- goto error;
-
- pin->dataRanges = (KSDATARANGE*)(pin->dataRangesItem +1);
-
- /* Check that at least one datarange supports audio */
- result = paUnanticipatedHostError;
- dataRange = pin->dataRanges;
- pin->maxChannels = 0;
- pin->defaultSampleRate = 0;
- pin->formats = 0;
- PA_DEBUG(("PinNew: Checking %u no of dataranges...\n", pin->dataRangesItem->Count));
- for( i = 0; i < pin->dataRangesItem->Count; i++)
- {
- PA_DEBUG(("PinNew: DR major format %x\n",*(unsigned long*)(&(dataRange->MajorFormat))));
- /* Check that subformat is WAVEFORMATEX, PCM or WILDCARD */
- if( IS_VALID_WAVEFORMATEX_GUID(&dataRange->SubFormat) ||
- IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) ||
- IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) ||
- IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_WILDCARD) ||
- IsEqualGUID(&dataRange->MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) )
- {
- int defaultIndex;
- result = paNoError;
- /* Record the maximum possible channels with this pin */
- if( ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels == (ULONG) -1 )
- {
- pin->maxChannels = MAXIMUM_NUMBER_OF_CHANNELS;
- }
- else if( (int) ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels > pin->maxChannels )
- {
- pin->maxChannels = (int) ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels;
- }
- PA_DEBUG(("PinNew: MaxChannel: %d\n",pin->maxChannels));
-
- /* Record the formats (bit depths) that are supported */
- if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 8) )
- {
- pin->formats |= paInt8;
- PA_DEBUG(("PinNew: Format PCM 8 bit supported\n"));
- }
- if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 16) )
- {
- pin->formats |= paInt16;
- PA_DEBUG(("PinNew: Format PCM 16 bit supported\n"));
- }
- if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 24) )
- {
- pin->formats |= paInt24;
- PA_DEBUG(("PinNew: Format PCM 24 bit supported\n"));
- }
- if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 32) )
- {
- if (IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
- {
- pin->formats |= paFloat32;
- PA_DEBUG(("PinNew: Format IEEE float 32 bit supported\n"));
- }
- else
- {
- pin->formats |= paInt32;
- PA_DEBUG(("PinNew: Format PCM 32 bit supported\n"));
- }
- }
-
- defaultIndex = DefaultSampleFrequencyIndex((KSDATARANGE_AUDIO*)dataRange);
- if (defaultIndex >= 0 && defaultIndex < defaultSampleRateIndex)
- {
- defaultSampleRateIndex = defaultIndex;
- }
- }
- dataRange = (KSDATARANGE*)( ((char*)dataRange) + dataRange->FormatSize);
- }
-
- if( result != paNoError )
- goto error;
-
- /* If none of the frequencies searched for are present, there's something seriously wrong */
- if (defaultSampleRateIndex == defaultSampleRateSearchOrderCount)
- {
- PA_DEBUG(("PinNew: No default sample rate found, skipping pin!\n"));
- PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "PinNew: No default sample rate found");
- result = paUnanticipatedHostError;
- goto error;
- }
-
- /* Set the default sample rate */
- pin->defaultSampleRate = defaultSampleRateSearchOrder[defaultSampleRateIndex];
- PA_DEBUG(("PinNew: Default sample rate = %d Hz\n", pin->defaultSampleRate));
-
- /* Get instance information */
- result = WdmGetPinPropertySimple(
- parentFilter->handle,
- pinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_CINSTANCES,
- &pin->instances,
- sizeof(KSPIN_CINSTANCES),
- NULL);
-
- if( result != paNoError )
- goto error;
-
- /* If WaveRT, check if pin supports notification mode */
- if (parentFilter->devInfo.streamingType == Type_kWaveRT)
- {
- BOOL bSupportsNotification = FALSE;
- if (PinQueryNotificationSupport(pin, &bSupportsNotification) == paNoError)
- {
- pin->pinKsSubType = bSupportsNotification ? SubType_kNotification : SubType_kPolled;
- }
- }
-
- /* Query pin name (which means we need to traverse to non IRP pin, via physical connection to topology filter pin, through
- its nodes to the endpoint pin, and get that ones name... phew...) */
- PA_DEBUG(("PinNew: Finding topology pin...\n"));
-
- {
- ULONG topoPinId = GetConnectedPin(pinId, (pin->dataFlow == KSPIN_DATAFLOW_IN), parentFilter, -1, NULL, NULL);
- const wchar_t kInputName[] = L"Input";
- const wchar_t kOutputName[] = L"Output";
-
- if (topoPinId != KSFILTER_NODE)
- {
- /* Get physical connection for topo pin */
- unsigned long cbBytes = 0;
- PA_DEBUG(("PinNew: Getting physical connection...\n"));
- result = WdmGetPinPropertySimple(parentFilter->handle,
- topoPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_PHYSICALCONNECTION,
- 0,
- 0,
- &cbBytes
- );
-
- if (result != paNoError)
- {
- /* No physical connection -> there is no topology filter! So we get the name of the pin! */
- PA_DEBUG(("PinNew: No physical connection! Getting the pin name\n"));
- result = WdmGetPinPropertySimple(parentFilter->handle,
- topoPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_NAME,
- pin->friendlyName,
- MAX_PATH,
- NULL);
- if (result != paNoError)
- {
- GUID category = {0};
-
- /* Get pin category information */
- result = WdmGetPinPropertySimple(parentFilter->handle,
- topoPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_CATEGORY,
- &category,
- sizeof(GUID),
- NULL);
-
- if (result == paNoError)
- {
- result = GetNameFromCategory(&category, (pin->dataFlow == KSPIN_DATAFLOW_OUT), pin->friendlyName, MAX_PATH);
- }
- }
-
- /* Make sure pin gets a name here... */
- if (wcslen(pin->friendlyName) == 0)
- {
- wcscpy(pin->friendlyName, (pin->dataFlow == KSPIN_DATAFLOW_IN) ? kOutputName : kInputName);
-#ifdef UNICODE
- PA_DEBUG(("PinNew: Setting pin friendly name to '%s'\n", pin->friendlyName));
-#else
- PA_DEBUG(("PinNew: Setting pin friendly name to '%S'\n", pin->friendlyName));
-#endif
- }
-
- /* This is then == the endpoint pin */
- pin->endpointPinId = (pin->dataFlow == KSPIN_DATAFLOW_IN) ? pinId : topoPinId;
- }
- else
- {
- KSPIN_PHYSICALCONNECTION* pc = (KSPIN_PHYSICALCONNECTION*)PaUtil_AllocateMemory(cbBytes + 2);
- ULONG pcPin;
- wchar_t symbLinkName[MAX_PATH];
- PA_DEBUG(("PinNew: Physical connection found!\n"));
- if (pc == NULL)
- {
- result = paInsufficientMemory;
- goto error;
- }
- result = WdmGetPinPropertySimple(parentFilter->handle,
- topoPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_PHYSICALCONNECTION,
- pc,
- cbBytes,
- NULL
- );
-
- pcPin = pc->Pin;
- wcsncpy(symbLinkName, pc->SymbolicLinkName, MAX_PATH);
- PaUtil_FreeMemory( pc );
-
- if (result != paNoError)
- {
- /* Shouldn't happen, but fail if it does */
- PA_DEBUG(("PinNew: failed to retrieve physical connection!\n"));
- goto error;
- }
-
- if (symbLinkName[1] == TEXT('?'))
- {
- symbLinkName[1] = TEXT('\\');
- }
-
- if (pin->parentFilter->topologyFilter == NULL)
- {
- PA_DEBUG(("PinNew: Creating topology filter '%S'\n", symbLinkName));
-
- pin->parentFilter->topologyFilter = FilterNew(Type_kNotUsed, 0, symbLinkName, L"", &result);
- if (pin->parentFilter->topologyFilter == NULL)
- {
- PA_DEBUG(("PinNew: Failed creating topology filter\n"));
- result = paUnanticipatedHostError;
- PaWinWDM_SetLastErrorInfo(result, "Failed to create topology filter '%S'", symbLinkName);
- goto error;
- }
-
- /* Copy info so we have it in device info */
- wcsncpy(pin->parentFilter->devInfo.topologyPath, symbLinkName, MAX_PATH);
- }
- else
- {
- /* Must be the same */
- assert(wcscmp(symbLinkName, pin->parentFilter->topologyFilter->devInfo.filterPath) == 0);
- }
-
- PA_DEBUG(("PinNew: Opening topology filter..."));
-
- result = FilterUse(pin->parentFilter->topologyFilter);
- if (result == paNoError)
- {
- unsigned long endpointPinId;
-
- if (pin->dataFlow == KSPIN_DATAFLOW_IN)
- {
- /* The "endpointPinId" is what WASAPI looks at for pin names */
- GUID category = {0};
-
- PA_DEBUG(("PinNew: Checking for output endpoint pin id...\n"));
-
- endpointPinId = GetConnectedPin(pcPin, TRUE, pin->parentFilter->topologyFilter, -1, NULL, NULL);
-
- if (endpointPinId == KSFILTER_NODE)
- {
- result = paUnanticipatedHostError;
- PaWinWDM_SetLastErrorInfo(result, "Failed to get endpoint pin ID on topology filter!");
- goto error;
- }
-
- PA_DEBUG(("PinNew: Found endpoint pin id %u\n", endpointPinId));
-
- /* Get pin category information */
- result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
- endpointPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_CATEGORY,
- &category,
- sizeof(GUID),
- NULL);
-
- if (result == paNoError)
- {
-#if !PA_WDMKS_USE_CATEGORY_FOR_PIN_NAMES
- wchar_t pinName[MAX_PATH];
-
- PA_DEBUG(("PinNew: Getting pin name property..."));
-
- /* Ok, try pin name also, and favor that if available */
- result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
- endpointPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_NAME,
- pinName,
- MAX_PATH,
- NULL);
-
- if (result == paNoError && wcslen(pinName)>0)
- {
- wcsncpy(pin->friendlyName, pinName, MAX_PATH);
- }
- else
-#endif
- {
- result = GetNameFromCategory(&category, (pin->dataFlow == KSPIN_DATAFLOW_OUT), pin->friendlyName, MAX_PATH);
- }
- }
-
- /* Make sure we get a name for the pin */
- if (wcslen(pin->friendlyName) == 0)
- {
- wcscpy(pin->friendlyName, kOutputName);
- }
-#ifdef UNICODE
- PA_DEBUG(("PinNew: Pin name '%s'\n", pin->friendlyName));
-#else
- PA_DEBUG(("PinNew: Pin name '%S'\n", pin->friendlyName));
-#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
- for more information)
- */
- pin->endpointPinId = pcPin;
- }
- else
- {
- unsigned muxCount = 0;
- int muxPos = 0;
- /* Max 64 multiplexer inputs... sanity check :) */
- for (i = 0; i < 64; ++i)
- {
- ULONG muxNodeIdTest = (unsigned)-1;
- PA_DEBUG(("PinNew: Checking for input endpoint pin id (%d)...\n", i));
-
- endpointPinId = GetConnectedPin(pcPin,
- FALSE,
- pin->parentFilter->topologyFilter,
- (int)i,
- NULL,
- &muxNodeIdTest);
-
- if (endpointPinId == KSFILTER_NODE)
- {
- /* We're done */
- PA_DEBUG(("PinNew: Done with inputs.\n", endpointPinId));
- break;
- }
- else
- {
- /* The "endpointPinId" is what WASAPI looks at for pin names */
- GUID category = {0};
-
- PA_DEBUG(("PinNew: Found endpoint pin id %u\n", endpointPinId));
-
- /* Get pin category information */
- result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
- endpointPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_CATEGORY,
- &category,
- sizeof(GUID),
- NULL);
-
- if (result == paNoError)
- {
- if (muxNodeIdTest == (unsigned)-1)
- {
- /* Ok, try pin name, and favor that if available */
- result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
- endpointPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_NAME,
- pin->friendlyName,
- MAX_PATH,
- NULL);
-
- if (result != paNoError)
- {
- result = GetNameFromCategory(&category, TRUE, pin->friendlyName, MAX_PATH);
- }
- break;
- }
- else
- {
- result = GetNameFromCategory(&category, TRUE, NULL, 0);
-
- if (result == paNoError)
- {
- ++muxCount;
- }
- }
- }
- else
- {
- PA_DEBUG(("PinNew: Failed to get pin category"));
- }
- }
- }
-
- if (muxCount == 0)
- {
- pin->endpointPinId = endpointPinId;
- /* Make sure we get a name for the pin */
- if (wcslen(pin->friendlyName) == 0)
- {
- wcscpy(pin->friendlyName, kInputName);
- }
-#ifdef UNICODE
- PA_DEBUG(("PinNew: Input friendly name '%s'\n", pin->friendlyName));
-#else
- PA_DEBUG(("PinNew: Input friendly name '%S'\n", pin->friendlyName));
-#endif
- }
- else // muxCount > 0
- {
- PA_DEBUG(("PinNew: Setting up %u inputs\n", muxCount));
-
- /* Now we redo the operation once known how many multiplexer positions there are */
- pin->inputs = (PaWinWdmMuxedInput**)PaUtil_AllocateMemory(muxCount * sizeof(PaWinWdmMuxedInput*));
- if (pin->inputs == NULL)
- {
- FilterRelease(pin->parentFilter->topologyFilter);
- result = paInsufficientMemory;
- goto error;
- }
- pin->inputCount = muxCount;
-
- for (i = 0; i < muxCount; ++muxPos)
- {
- PA_DEBUG(("PinNew: Setting up input %u...\n", i));
-
- if (pin->inputs[i] == NULL)
- {
- pin->inputs[i] = (PaWinWdmMuxedInput*)PaUtil_AllocateMemory(sizeof(PaWinWdmMuxedInput));
- if (pin->inputs[i] == NULL)
- {
- FilterRelease(pin->parentFilter->topologyFilter);
- result = paInsufficientMemory;
- goto error;
- }
- }
-
- endpointPinId = GetConnectedPin(pcPin,
- FALSE,
- pin->parentFilter->topologyFilter,
- muxPos,
- &pin->inputs[i]->muxPinId,
- &pin->inputs[i]->muxNodeId);
-
- if (endpointPinId != KSFILTER_NODE)
- {
- /* The "endpointPinId" is what WASAPI looks at for pin names */
- GUID category = {0};
-
- /* Set input endpoint ID */
- pin->inputs[i]->endpointPinId = endpointPinId;
-
- /* Get pin category information */
- result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
- endpointPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_CATEGORY,
- &category,
- sizeof(GUID),
- NULL);
-
- if (result == paNoError)
- {
- /* Try pin name first, and if that is not defined, use category instead */
- result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
- endpointPinId,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_NAME,
- pin->inputs[i]->friendlyName,
- MAX_PATH,
- NULL);
-
- if (result != paNoError)
- {
- result = GetNameFromCategory(&category, TRUE, pin->inputs[i]->friendlyName, MAX_PATH);
- if (result != paNoError)
- {
- /* Only specify name, let name hash in ScanDeviceInfos fix postfix enumerators */
- wcscpy(pin->inputs[i]->friendlyName, kInputName);
- }
- }
-#ifdef UNICODE
- PA_DEBUG(("PinNew: Input (%u) friendly name '%s'\n", i, pin->inputs[i]->friendlyName));
-#else
- PA_DEBUG(("PinNew: Input (%u) friendly name '%S'\n", i, pin->inputs[i]->friendlyName));
-#endif
- ++i;
- }
- }
- else
- {
- /* Unconnected pin */
- goto error;
- }
- }
- }
- }
- }
- }
- }
- else
- {
- PA_DEBUG(("PinNew: No topology pin id found. Bad...\n"));
- /* No TOPO pin id ??? This is bad. Ok, so we just say it is an input or output... */
- wcscpy(pin->friendlyName, (pin->dataFlow == KSPIN_DATAFLOW_IN) ? kOutputName : kInputName);
- }
- }
-
- /* Release topology filter if it has been used */
- if (pin->parentFilter->topologyFilter && pin->parentFilter->topologyFilter->handle != NULL)
- {
- PA_DEBUG(("PinNew: Releasing topology filter...\n"));
- FilterRelease(pin->parentFilter->topologyFilter);
- }
-
- /* Success */
- *error = paNoError;
- PA_DEBUG(("Pin created successfully\n"));
- PA_LOGL_;
- return pin;
-
-error:
- PA_DEBUG(("PinNew: Error %d\n", result));
- /*
- Error cleanup
- */
-
- if (pin->parentFilter->topologyFilter && pin->parentFilter->topologyFilter->handle != NULL)
- {
- FilterRelease(pin->parentFilter->topologyFilter);
- }
-
- PaUtil_FreeMemory( item );
- PinFree(pin);
-
- *error = result;
- PA_LOGL_;
- return NULL;
-}
-
-/*
-Safely free all resources associated with the pin
-*/
-static void PinFree(PaWinWdmPin* pin)
-{
- unsigned i;
- PA_LOGE_;
- if( pin )
- {
- PinClose(pin);
- if( pin->pinConnect )
- {
- PaUtil_FreeMemory( pin->pinConnect );
- }
- if( pin->dataRangesItem )
- {
- PaUtil_FreeMemory( pin->dataRangesItem );
- }
- if( pin->inputs )
- {
- for (i = 0; i < pin->inputCount; ++i)
- {
- PaUtil_FreeMemory( pin->inputs[i] );
- }
- PaUtil_FreeMemory( pin->inputs );
- }
- PaUtil_FreeMemory( pin );
- }
- PA_LOGL_;
-}
-
-/*
-If the pin handle is open, close it
-*/
-static void PinClose(PaWinWdmPin* pin)
-{
- PA_LOGE_;
- if( pin == NULL )
- {
- PA_DEBUG(("Closing NULL pin!"));
- PA_LOGL_;
- return;
- }
- if( pin->handle != NULL )
- {
- PinSetState( pin, KSSTATE_PAUSE );
- PinSetState( pin, KSSTATE_STOP );
- CloseHandle( pin->handle );
- pin->handle = NULL;
- FilterRelease(pin->parentFilter);
- }
- PA_LOGL_;
-}
-
-/*
-Set the state of this (instantiated) pin
-*/
-static PaError PinSetState(PaWinWdmPin* pin, KSSTATE state)
-{
- PaError result = paNoError;
- KSPROPERTY prop;
-
- PA_LOGE_;
- prop.Set = KSPROPSETID_Connection;
- prop.Id = KSPROPERTY_CONNECTION_STATE;
- prop.Flags = KSPROPERTY_TYPE_SET;
-
- if( pin == NULL )
- return paInternalError;
- if( pin->handle == NULL )
- return paInternalError;
-
- result = WdmSyncIoctl(pin->handle, IOCTL_KS_PROPERTY, &prop, sizeof(KSPROPERTY), &state, sizeof(KSSTATE), NULL);
-
- PA_LOGL_;
- return result;
-}
-
-static PaError PinInstantiate(PaWinWdmPin* pin)
-{
- PaError result;
- unsigned long createResult;
- KSALLOCATOR_FRAMING ksaf;
- KSALLOCATOR_FRAMING_EX ksafex;
-
- PA_LOGE_;
-
- if( pin == NULL )
- return paInternalError;
- if(!pin->pinConnect)
- return paInternalError;
-
- FilterUse(pin->parentFilter);
-
- createResult = FunctionKsCreatePin(
- pin->parentFilter->handle,
- pin->pinConnect,
- GENERIC_WRITE | GENERIC_READ,
- &pin->handle
- );
-
- PA_DEBUG(("Pin create result = 0x%08x\n",createResult));
- if( createResult != ERROR_SUCCESS )
- {
- FilterRelease(pin->parentFilter);
- pin->handle = NULL;
- switch (createResult)
- {
- case ERROR_INVALID_PARAMETER:
- /* First case when pin actually don't support the format */
- return paSampleFormatNotSupported;
- case ERROR_BAD_COMMAND:
- /* Case when pin is occupied (by another application) */
- return paDeviceUnavailable;
- default:
- /* All other cases */
- return paInvalidDevice;
- }
- }
-
- if (pin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
- {
- /* Framing size query only valid for WaveCyclic devices */
- result = WdmGetPropertySimple(
- pin->handle,
- &KSPROPSETID_Connection,
- KSPROPERTY_CONNECTION_ALLOCATORFRAMING,
- &ksaf,
- sizeof(ksaf));
-
- if( result != paNoError )
- {
- result = WdmGetPropertySimple(
- pin->handle,
- &KSPROPSETID_Connection,
- KSPROPERTY_CONNECTION_ALLOCATORFRAMING_EX,
- &ksafex,
- sizeof(ksafex));
- if( result == paNoError )
- {
- pin->frameSize = ksafex.FramingItem[0].FramingRange.Range.MinFrameSize;
- }
- }
- else
- {
- pin->frameSize = ksaf.FrameSize;
- }
- }
-
- PA_LOGL_;
-
- return paNoError;
-}
-
-static PaError PinSetFormat(PaWinWdmPin* pin, const WAVEFORMATEX* format)
-{
- unsigned long size;
- void* newConnect;
-
- PA_LOGE_;
-
- if( pin == NULL )
- return paInternalError;
- if( format == NULL )
- return paInternalError;
-
- size = GetWfexSize(format) + sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX) - sizeof(WAVEFORMATEX);
-
- if( pin->pinConnectSize != size )
- {
- newConnect = PaUtil_AllocateMemory( size );
- if( newConnect == NULL )
- return paInsufficientMemory;
- memcpy( newConnect, (void*)pin->pinConnect, min(pin->pinConnectSize,size) );
- PaUtil_FreeMemory( pin->pinConnect );
- pin->pinConnect = (KSPIN_CONNECT*)newConnect;
- pin->pinConnectSize = size;
- pin->ksDataFormatWfx = (KSDATAFORMAT_WAVEFORMATEX*)((KSPIN_CONNECT*)newConnect + 1);
- pin->ksDataFormatWfx->DataFormat.FormatSize = size - sizeof(KSPIN_CONNECT);
- }
-
- memcpy( (void*)&(pin->ksDataFormatWfx->WaveFormatEx), format, GetWfexSize(format) );
- pin->ksDataFormatWfx->DataFormat.SampleSize = (unsigned short)(format->nChannels * (format->wBitsPerSample / 8));
-
- PA_LOGL_;
-
- return paNoError;
-}
-
-static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format)
-{
- KSDATARANGE_AUDIO* dataRange;
- unsigned long count;
- GUID guid = DYNAMIC_GUID( DEFINE_WAVEFORMATEX_GUID(format->wFormatTag) );
- PaError result = paInvalidDevice;
- const WAVEFORMATEXTENSIBLE* pFormatExt = (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE) ? (const WAVEFORMATEXTENSIBLE*)format : 0;
-
- PA_LOGE_;
-
- if( pFormatExt != 0 )
- {
- guid = pFormatExt->SubFormat;
- }
- dataRange = (KSDATARANGE_AUDIO*)pin->dataRanges;
- for(count = 0;
- count<pin->dataRangesItem->Count;
- count++,
- dataRange = (KSDATARANGE_AUDIO*)( ((char*)dataRange) + dataRange->DataRange.FormatSize)) /* Need to update dataRange here, due to 'continue' !! */
- {
- /* Check major format*/
- if (!(IsEqualGUID(&(dataRange->DataRange.MajorFormat), &KSDATAFORMAT_TYPE_AUDIO) ||
- IsEqualGUID(&(dataRange->DataRange.MajorFormat), &KSDATAFORMAT_TYPE_WILDCARD)))
- {
- continue;
- }
-
- /* This is an audio or wildcard datarange... */
- if (! (IsEqualGUID(&(dataRange->DataRange.SubFormat), &KSDATAFORMAT_SUBTYPE_WILDCARD) ||
- IsEqualGUID(&(dataRange->DataRange.SubFormat), &KSDATAFORMAT_SUBTYPE_PCM) ||
- IsEqualGUID(&(dataRange->DataRange.SubFormat), &guid) ))
- {
- continue;
- }
-
- /* Check specifier... */
- if (! (IsEqualGUID(&(dataRange->DataRange.Specifier), &KSDATAFORMAT_SPECIFIER_WILDCARD) ||
- IsEqualGUID(&(dataRange->DataRange.Specifier), &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)) )
- {
- continue;
- }
-
- PA_DEBUG(("Pin:%x, DataRange:%d\n",(void*)pin,count));
- PA_DEBUG(("\tFormatSize:%d, SampleSize:%d\n",dataRange->DataRange.FormatSize,dataRange->DataRange.SampleSize));
- PA_DEBUG(("\tMaxChannels:%d\n",dataRange->MaximumChannels));
- 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 &&
- dataRange->MaximumChannels < format->nChannels )
- {
- result = paInvalidChannelCount;
- continue;
- }
-
- if (pFormatExt != 0)
- {
- if (!IsBitsWithinRange(dataRange, pFormatExt->Samples.wValidBitsPerSample))
- {
- result = paSampleFormatNotSupported;
- continue;
- }
- }
- else
- {
- if (!IsBitsWithinRange(dataRange, format->wBitsPerSample))
- {
- result = paSampleFormatNotSupported;
- continue;
- }
- }
-
- if (!IsFrequencyWithinRange(dataRange, format->nSamplesPerSec))
- {
- result = paInvalidSampleRate;
- continue;
- }
-
- /* Success! */
- result = paNoError;
- break;
- }
-
- PA_LOGL_;
- return result;
-}
-
-static PaError PinQueryNotificationSupport(PaWinWdmPin* pPin, BOOL* pbResult)
-{
- PaError result = paNoError;
- KSPROPERTY propIn;
-
- PA_LOGE_;
-
- propIn.Set = KSPROPSETID_RtAudio;
- propIn.Id = 8; /* = KSPROPERTY_RTAUDIO_QUERY_NOTIFICATION_SUPPORT */
- propIn.Flags = KSPROPERTY_TYPE_GET;
-
- result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
- &propIn,
- sizeof(KSPROPERTY),
- pbResult,
- sizeof(BOOL),
- NULL);
-
- if (result != paNoError)
- {
- PA_DEBUG(("Failed PinQueryNotificationSupport\n"));
- }
-
- PA_LOGL_;
- return result;
-}
-
-static PaError PinGetBufferWithNotification(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier)
-{
- PaError result = paNoError;
- KSRTAUDIO_BUFFER_PROPERTY_WITH_NOTIFICATION propIn;
- KSRTAUDIO_BUFFER propOut;
-
- PA_LOGE_;
-
- propIn.BaseAddress = 0;
- propIn.NotificationCount = 2;
- propIn.RequestedBufferSize = *pRequestedBufSize;
- propIn.Property.Set = KSPROPSETID_RtAudio;
- propIn.Property.Id = KSPROPERTY_RTAUDIO_BUFFER_WITH_NOTIFICATION;
- propIn.Property.Flags = KSPROPERTY_TYPE_GET;
-
- result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
- &propIn,
- sizeof(KSRTAUDIO_BUFFER_PROPERTY_WITH_NOTIFICATION),
- &propOut,
- sizeof(KSRTAUDIO_BUFFER),
- NULL);
-
- if (result == paNoError)
- {
- *pBuffer = propOut.BufferAddress;
- *pRequestedBufSize = propOut.ActualBufferSize;
- *pbCallMemBarrier = propOut.CallMemoryBarrier;
- }
- else
- {
- PA_DEBUG(("Failed to get buffer with notification\n"));
- }
-
- PA_LOGL_;
- return result;
-}
-
-static PaError PinGetBufferWithoutNotification(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier)
-{
- PaError result = paNoError;
- KSRTAUDIO_BUFFER_PROPERTY propIn;
- KSRTAUDIO_BUFFER propOut;
-
- PA_LOGE_;
-
- propIn.BaseAddress = NULL;
- propIn.RequestedBufferSize = *pRequestedBufSize;
- propIn.Property.Set = KSPROPSETID_RtAudio;
- propIn.Property.Id = KSPROPERTY_RTAUDIO_BUFFER;
- propIn.Property.Flags = KSPROPERTY_TYPE_GET;
-
- result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
- &propIn,
- sizeof(KSRTAUDIO_BUFFER_PROPERTY),
- &propOut,
- sizeof(KSRTAUDIO_BUFFER),
- NULL);
-
- if (result == paNoError)
- {
- *pBuffer = propOut.BufferAddress;
- *pRequestedBufSize = propOut.ActualBufferSize;
- *pbCallMemBarrier = propOut.CallMemoryBarrier;
- }
- else
- {
- PA_DEBUG(("Failed to get buffer without notification\n"));
- }
-
- PA_LOGL_;
- return result;
-}
-
-/* greatest common divisor - PGCD in French */
-static unsigned long PaWinWDMGCD( unsigned long a, unsigned long b )
-{
- return (b==0) ? a : PaWinWDMGCD( b, a%b);
-}
-
-
-/* This function will handle getting the cyclic buffer from a WaveRT driver. Certain WaveRT drivers needs to have
-requested buffer size on multiples of 128 bytes:
-
-*/
-static PaError PinGetBuffer(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier)
-{
- PaError result = paNoError;
- int limit = 1000;
- PA_LOGE_;
-
- while (1)
- {
- limit--;
- if (limit == 0) {
- PA_DEBUG(("PinGetBuffer: LOOP LIMIT REACHED\n"));
- break;
- }
-
- if (pPin->pinKsSubType != SubType_kPolled)
- {
- /* In case of unknown (or notification), we try both modes */
- result = PinGetBufferWithNotification(pPin, pBuffer, pRequestedBufSize, pbCallMemBarrier);
- if (result == paNoError)
- {
- PA_DEBUG(("PinGetBuffer: SubType_kNotification\n"));
- pPin->pinKsSubType = SubType_kNotification;
- break;
- }
- }
-
- result = PinGetBufferWithoutNotification(pPin, pBuffer, pRequestedBufSize, pbCallMemBarrier);
- if (result == paNoError)
- {
- PA_DEBUG(("PinGetBuffer: SubType_kPolled\n"));
- pPin->pinKsSubType = SubType_kPolled;
- break;
- }
-
- /* Check if requested size is on a 128 byte boundary */
- if (((*pRequestedBufSize) % 128UL) == 0)
- {
- PA_DEBUG(("Buffer size on 128 byte boundary, still fails :(\n"));
- /* Ok, can't do much more */
- break;
- }
- else
- {
- /* Compute LCM so we know which sizes are on a 128 byte boundary */
- const unsigned gcd = PaWinWDMGCD(128UL, pPin->ksDataFormatWfx->WaveFormatEx.nBlockAlign);
- const unsigned lcm = (128UL * pPin->ksDataFormatWfx->WaveFormatEx.nBlockAlign) / gcd;
- DWORD dwOldSize = *pRequestedBufSize;
-
- /* Align size to (next larger) LCM byte boundary, and then we try again. Note that LCM is not necessarily a
- power of 2. */
- *pRequestedBufSize = ((*pRequestedBufSize + lcm - 1) / lcm) * lcm;
-
- PA_DEBUG(("Adjusting buffer size from %u to %u bytes (128 byte boundary, LCM=%u)\n", dwOldSize, *pRequestedBufSize, lcm));
- }
- }
-
- PA_LOGL_;
-
- return result;
-}
-
-static PaError PinRegisterPositionRegister(PaWinWdmPin* pPin)
-{
- PaError result = paNoError;
- KSRTAUDIO_HWREGISTER_PROPERTY propIn;
- KSRTAUDIO_HWREGISTER propOut;
-
- PA_LOGE_;
-
- propIn.BaseAddress = NULL;
- propIn.Property.Set = KSPROPSETID_RtAudio;
- propIn.Property.Id = KSPROPERTY_RTAUDIO_POSITIONREGISTER;
- propIn.Property.Flags = KSPROPERTY_TYPE_SET;
-
- result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
- &propIn,
- sizeof(KSRTAUDIO_HWREGISTER_PROPERTY),
- &propOut,
- sizeof(KSRTAUDIO_HWREGISTER),
- NULL);
-
- if (result == paNoError)
- {
- pPin->positionRegister = (ULONG*)propOut.Register;
- }
- else
- {
- PA_DEBUG(("Failed to register position register\n"));
- }
-
- PA_LOGL_;
-
- return result;
-}
-
-static PaError PinRegisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle)
-{
- PaError result = paNoError;
- KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY prop;
-
- PA_LOGE_;
-
- prop.NotificationEvent = handle;
- prop.Property.Set = KSPROPSETID_RtAudio;
- prop.Property.Id = KSPROPERTY_RTAUDIO_REGISTER_NOTIFICATION_EVENT;
- prop.Property.Flags = KSPROPERTY_TYPE_SET;
-
- result = WdmSyncIoctl(pPin->handle,
- IOCTL_KS_PROPERTY,
- &prop,
- sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY),
- &prop,
- sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY),
- NULL);
-
- if (result != paNoError) {
- PA_DEBUG(("Failed to register notification handle 0x%08X\n", handle));
- }
-
- PA_LOGL_;
-
- return result;
-}
-
-static PaError PinUnregisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle)
-{
- PaError result = paNoError;
- KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY prop;
-
- PA_LOGE_;
-
- if (handle != NULL)
- {
- prop.NotificationEvent = handle;
- prop.Property.Set = KSPROPSETID_RtAudio;
- prop.Property.Id = KSPROPERTY_RTAUDIO_UNREGISTER_NOTIFICATION_EVENT;
- prop.Property.Flags = KSPROPERTY_TYPE_SET;
-
- result = WdmSyncIoctl(pPin->handle,
- IOCTL_KS_PROPERTY,
- &prop,
- sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY),
- &prop,
- sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY),
- NULL);
-
- if (result != paNoError) {
- PA_DEBUG(("Failed to unregister notification handle 0x%08X\n", handle));
- }
- }
- PA_LOGL_;
-
- return result;
-}
-
-static PaError PinGetHwLatency(PaWinWdmPin* pPin, ULONG* pFifoSize, ULONG* pChipsetDelay, ULONG* pCodecDelay)
-{
- PaError result = paNoError;
- KSPROPERTY propIn;
- KSRTAUDIO_HWLATENCY propOut;
-
- PA_LOGE_;
-
- propIn.Set = KSPROPSETID_RtAudio;
- propIn.Id = KSPROPERTY_RTAUDIO_HWLATENCY;
- propIn.Flags = KSPROPERTY_TYPE_GET;
-
- result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
- &propIn,
- sizeof(KSPROPERTY),
- &propOut,
- sizeof(KSRTAUDIO_HWLATENCY),
- NULL);
-
- if (result == paNoError)
- {
- *pFifoSize = propOut.FifoSize;
- *pChipsetDelay = propOut.ChipsetDelay;
- *pCodecDelay = propOut.CodecDelay;
- }
- else
- {
- PA_DEBUG(("Failed to retrieve hardware FIFO size!\n"));
- }
-
- PA_LOGL_;
-
- return result;
-}
-
-/* This one is used for WaveRT */
-static PaError PinGetAudioPositionMemoryMapped(PaWinWdmPin* pPin, ULONG* pPosition)
-{
- *pPosition = (*pPin->positionRegister);
- return paNoError;
-}
-
-/* This one also, but in case the driver hasn't implemented memory mapped access to the position register */
-static PaError PinGetAudioPositionViaIOCTLRead(PaWinWdmPin* pPin, ULONG* pPosition)
-{
- PaError result = paNoError;
- KSPROPERTY propIn;
- KSAUDIO_POSITION propOut;
-
- PA_LOGE_;
-
- propIn.Set = KSPROPSETID_Audio;
- propIn.Id = KSPROPERTY_AUDIO_POSITION;
- propIn.Flags = KSPROPERTY_TYPE_GET;
-
- result = WdmSyncIoctl(pPin->handle,
- IOCTL_KS_PROPERTY,
- &propIn, sizeof(KSPROPERTY),
- &propOut, sizeof(KSAUDIO_POSITION),
- NULL);
-
- if (result == paNoError)
- {
- *pPosition = (ULONG)(propOut.PlayOffset);
- }
- else
- {
- PA_DEBUG(("Failed to get audio play position!\n"));
- }
-
- PA_LOGL_;
-
- return result;
-
-}
-
-/* This one also, but in case the driver hasn't implemented memory mapped access to the position register */
-static PaError PinGetAudioPositionViaIOCTLWrite(PaWinWdmPin* pPin, ULONG* pPosition)
-{
- PaError result = paNoError;
- KSPROPERTY propIn;
- KSAUDIO_POSITION propOut;
-
- PA_LOGE_;
-
- propIn.Set = KSPROPSETID_Audio;
- propIn.Id = KSPROPERTY_AUDIO_POSITION;
- propIn.Flags = KSPROPERTY_TYPE_GET;
-
- result = WdmSyncIoctl(pPin->handle,
- IOCTL_KS_PROPERTY,
- &propIn, sizeof(KSPROPERTY),
- &propOut, sizeof(KSAUDIO_POSITION),
- NULL);
-
- if (result == paNoError)
- {
- *pPosition = (ULONG)(propOut.WriteOffset);
- }
- else
- {
- PA_DEBUG(("Failed to get audio write position!\n"));
- }
-
- PA_LOGL_;
-
- return result;
-
-}
-
-/***********************************************************************************************/
-
-/**
-* Create a new filter object.
-*/
-static PaWinWdmFilter* FilterNew( PaWDMKSType type, DWORD devNode, const wchar_t* filterName, const wchar_t* friendlyName, PaError* error )
-{
- PaWinWdmFilter* filter = 0;
- PaError result;
-
- /* Allocate the new filter object */
- filter = (PaWinWdmFilter*)PaUtil_AllocateMemory( sizeof(PaWinWdmFilter) );
- if( !filter )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- PA_DEBUG(("FilterNew: Creating filter '%S'\n", friendlyName));
-
- /* Set type flag */
- filter->devInfo.streamingType = type;
-
- /* Store device node */
- filter->deviceNode = devNode;
-
- /* Zero the filter object - done by AllocateMemory */
- /* memset( (void*)filter, 0, sizeof(PaWinWdmFilter) ); */
-
- /* Copy the filter name */
- wcsncpy(filter->devInfo.filterPath, filterName, MAX_PATH);
-
- /* Copy the friendly name */
- wcsncpy(filter->friendlyName, friendlyName, MAX_PATH);
-
- PA_DEBUG(("FilterNew: Opening filter...\n", friendlyName));
-
- /* Open the filter handle */
- result = FilterUse(filter);
- if( result != paNoError )
- {
- goto error;
- }
-
- /* Get pin count */
- result = WdmGetPinPropertySimple
- (
- filter->handle,
- 0,
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_CTYPES,
- &filter->pinCount,
- sizeof(filter->pinCount),
- NULL);
-
- if( result != paNoError)
- {
- goto error;
- }
-
- /* Get connections & nodes for filter */
- result = WdmGetPropertyMulti(
- filter->handle,
- &KSPROPSETID_Topology,
- KSPROPERTY_TOPOLOGY_CONNECTIONS,
- &filter->connections);
-
- if( result != paNoError)
- {
- goto error;
- }
-
- result = WdmGetPropertyMulti(
- filter->handle,
- &KSPROPSETID_Topology,
- KSPROPERTY_TOPOLOGY_NODES,
- &filter->nodes);
-
- if( result != paNoError)
- {
- goto error;
- }
-
- /* For debugging purposes */
- DumpConnectionsAndNodes(filter);
-
- /* Get product GUID (it might not be supported) */
- {
- KSCOMPONENTID compId;
- if (WdmGetPropertySimple(filter->handle, &KSPROPSETID_General, KSPROPERTY_GENERAL_COMPONENTID, &compId, sizeof(KSCOMPONENTID)) == paNoError)
- {
- filter->devInfo.deviceProductGuid = compId.Product;
- }
- }
-
- /* This section is not executed for topology filters */
- if (type != Type_kNotUsed)
- {
- /* Initialize the pins */
- result = FilterInitializePins(filter);
-
- if( result != paNoError)
- {
- goto error;
- }
- }
-
- /* Close the filter handle for now
- * It will be opened later when needed */
- FilterRelease(filter);
-
- *error = paNoError;
- return filter;
-
-error:
- PA_DEBUG(("FilterNew: Error %d\n", result));
- /*
- Error cleanup
- */
- FilterFree(filter);
-
- *error = result;
- return NULL;
-}
-
-/**
-* Add reference to filter
-*/
-static void FilterAddRef( PaWinWdmFilter* filter )
-{
- if (filter != 0)
- {
- filter->filterRefCount++;
- }
-}
-
-
-/**
-* Initialize the pins of the filter. This is separated from FilterNew because this might fail if there is another
-* process using the pin(s).
-*/
-PaError FilterInitializePins( PaWinWdmFilter* filter )
-{
- PaError result = paNoError;
- int pinId;
-
- if (filter->devInfo.streamingType == Type_kNotUsed)
- return paNoError;
-
- if (filter->pins != NULL)
- return paNoError;
-
- /* Allocate pointer array to hold the pins */
- filter->pins = (PaWinWdmPin**)PaUtil_AllocateMemory( sizeof(PaWinWdmPin*) * filter->pinCount );
- if( !filter->pins )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- /* Create all the pins we can */
- for(pinId = 0; pinId < filter->pinCount; pinId++)
- {
- /* Create the pin with this Id */
- PaWinWdmPin* newPin;
- newPin = PinNew(filter, pinId, &result);
- if( result == paInsufficientMemory )
- goto error;
- if( newPin != NULL )
- {
- filter->pins[pinId] = newPin;
- ++filter->validPinCount;
- }
- else
- {
- filter->pins[pinId] = 0;
- }
- }
-
- if (filter->validPinCount == 0)
- {
- result = paDeviceUnavailable;
- goto error;
- }
-
- return paNoError;
-
-error:
-
- if (filter->pins)
- {
- for (pinId = 0; pinId < filter->pinCount; ++pinId)
- {
- if (filter->pins[pinId])
- {
- PinFree(filter->pins[pinId]);
- filter->pins[pinId] = 0;
- }
- }
- PaUtil_FreeMemory( filter->pins );
- filter->pins = 0;
- }
-
- return result;
-}
-
-
-/**
-* Free a previously created filter
-*/
-static void FilterFree(PaWinWdmFilter* filter)
-{
- PA_LOGL_;
- if( filter )
- {
- if (--filter->filterRefCount > 0)
- {
- /* Ok, a stream has a ref count to this filter */
- return;
- }
-
- if ( filter->topologyFilter )
- {
- FilterFree(filter->topologyFilter);
- filter->topologyFilter = 0;
- }
- if ( filter->pins )
- {
- int pinId;
- for( pinId = 0; pinId < filter->pinCount; pinId++ )
- PinFree(filter->pins[pinId]);
- PaUtil_FreeMemory( filter->pins );
- filter->pins = 0;
- }
- if( filter->connections )
- {
- PaUtil_FreeMemory(filter->connections);
- filter->connections = 0;
- }
- if( filter->nodes )
- {
- PaUtil_FreeMemory(filter->nodes);
- filter->nodes = 0;
- }
- if( filter->handle )
- CloseHandle( filter->handle );
- PaUtil_FreeMemory( filter );
- }
- PA_LOGE_;
-}
-
-/**
-* Reopen the filter handle if necessary so it can be used
-**/
-static PaError FilterUse(PaWinWdmFilter* filter)
-{
- assert( filter );
-
- PA_LOGE_;
- if( filter->handle == NULL )
- {
- /* Open the filter */
- filter->handle = CreateFileW(
- filter->devInfo.filterPath,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
- NULL);
-
- if( filter->handle == NULL )
- {
- return paDeviceUnavailable;
- }
- }
- filter->usageCount++;
- PA_LOGL_;
- return paNoError;
-}
-
-/**
-* Release the filter handle if nobody is using it
-**/
-static void FilterRelease(PaWinWdmFilter* filter)
-{
- assert( filter );
- assert( filter->usageCount > 0 );
-
- PA_LOGE_;
- /* Check first topology filter, if used */
- if (filter->topologyFilter != NULL && filter->topologyFilter->handle != NULL)
- {
- FilterRelease(filter->topologyFilter);
- }
-
- filter->usageCount--;
- if( filter->usageCount == 0 )
- {
- if( filter->handle != NULL )
- {
- CloseHandle( filter->handle );
- filter->handle = NULL;
- }
- }
- PA_LOGL_;
-}
-
-/**
-* Create a render or playback pin using the supplied format
-**/
-static PaWinWdmPin* FilterCreatePin(PaWinWdmFilter* filter,
- int pinId,
- const WAVEFORMATEX* wfex,
- PaError* error)
-{
- PaError result = paNoError;
- PaWinWdmPin* pin = NULL;
- assert( filter );
- assert( pinId < filter->pinCount );
- pin = filter->pins[pinId];
- assert( pin );
- result = PinSetFormat(pin,wfex);
- if( result == paNoError )
- {
- result = PinInstantiate(pin);
- }
- *error = result;
- return result == paNoError ? pin : 0;
-}
-
-static const wchar_t kUsbPrefix[] = L"\\\\?\\USB";
-
-static BOOL IsUSBDevice(const wchar_t* devicePath)
-{
- /* Alex Lessard pointed out that different devices might present the device path with
- lower case letters. */
- return (_wcsnicmp(devicePath, kUsbPrefix, sizeof(kUsbPrefix)/sizeof(kUsbPrefix[0]) ) == 0);
-}
-
-/* This should make it more language tolerant, I hope... */
-static const wchar_t kUsbNamePrefix[] = L"USB Audio";
-
-static BOOL IsNameUSBAudioDevice(const wchar_t* friendlyName)
-{
- return (_wcsnicmp(friendlyName, kUsbNamePrefix, sizeof(kUsbNamePrefix)/sizeof(kUsbNamePrefix[0])) == 0);
-}
-
-typedef enum _tag_EAlias
-{
- Alias_kRender = (1<<0),
- Alias_kCapture = (1<<1),
- Alias_kRealtime = (1<<2),
-} EAlias;
-
-/* Trim whitespace from string */
-static void TrimString(wchar_t* str, size_t length)
-{
- wchar_t* s = str;
- wchar_t* e = 0;
-
- /* Find start of string */
- while (iswspace(*s)) ++s;
- e=s+min(length,wcslen(s))-1;
-
- /* Find end of string */
- while(e>s && iswspace(*e)) --e;
- ++e;
-
- length = e - s;
- memmove(str, s, length * sizeof(wchar_t));
- str[length] = 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,
-* and once to initialize the PaWinWdmFilter structures.
-*
-* Vista and later: Also check KSCATEGORY_REALTIME for WaveRT devices.
-*/
-//PaError BuildFilterList( PaWinWdmHostApiRepresentation* wdmHostApi, int* noOfPaDevices )
-PaWinWdmFilter** BuildFilterList( int* pFilterCount, int* pNoOfPaDevices, PaError* pResult )
-{
- PaWinWdmFilter** ppFilters = NULL;
- HDEVINFO handle = NULL;
- int device;
- int invalidDevices;
- int slot;
- SP_DEVICE_INTERFACE_DATA interfaceData;
- SP_DEVICE_INTERFACE_DATA aliasData;
- SP_DEVINFO_DATA devInfoData;
- int noError;
- const int sizeInterface = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR));
- unsigned char interfaceDetailsArray[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR))];
- SP_DEVICE_INTERFACE_DETAIL_DATA_W* devInterfaceDetails = (SP_DEVICE_INTERFACE_DETAIL_DATA_W*)interfaceDetailsArray;
- const GUID* category = (const GUID*)&KSCATEGORY_AUDIO;
- const GUID* alias_render = (const GUID*)&KSCATEGORY_RENDER;
- const GUID* alias_capture = (const GUID*)&KSCATEGORY_CAPTURE;
- const GUID* category_realtime = (const GUID*)&KSCATEGORY_REALTIME;
- DWORD aliasFlags;
- PaWDMKSType streamingType;
- int filterCount = 0;
- int noOfPaDevices = 0;
-
- PA_LOGE_;
-
- assert(pFilterCount != NULL);
- assert(pNoOfPaDevices != NULL);
- assert(pResult != NULL);
-
- devInterfaceDetails->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
- *pFilterCount = 0;
- *pNoOfPaDevices = 0;
-
- /* Open a handle to search for devices (filters) */
- handle = SetupDiGetClassDevs(category,NULL,NULL,DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
- if( handle == INVALID_HANDLE_VALUE )
- {
- *pResult = paUnanticipatedHostError;
- return NULL;
- }
- PA_DEBUG(("Setup called\n"));
-
- /* First let's count the number of devices so we can allocate a list */
- invalidDevices = 0;
- for( device = 0;;device++ )
- {
- interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- interfaceData.Reserved = 0;
- aliasData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- aliasData.Reserved = 0;
- noError = SetupDiEnumDeviceInterfaces(handle,NULL,category,device,&interfaceData);
- PA_DEBUG(("Enum called\n"));
- if( !noError )
- break; /* No more devices */
-
- /* Check this one has the render or capture alias */
- aliasFlags = 0;
- noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_render,&aliasData);
- PA_DEBUG(("noError = %d\n",noError));
- if(noError)
- {
- if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
- {
- PA_DEBUG(("Device %d has render alias\n",device));
- aliasFlags |= Alias_kRender; /* Has render alias */
- }
- else
- {
- PA_DEBUG(("Device %d has no render alias\n",device));
- }
- }
- noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_capture,&aliasData);
- if(noError)
- {
- if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
- {
- PA_DEBUG(("Device %d has capture alias\n",device));
- aliasFlags |= Alias_kCapture; /* Has capture alias */
- }
- else
- {
- PA_DEBUG(("Device %d has no capture alias\n",device));
- }
- }
- if(!aliasFlags)
- invalidDevices++; /* This was not a valid capture or render audio device */
- }
- /* Remember how many there are */
- filterCount = device-invalidDevices;
-
- PA_DEBUG(("Interfaces found: %d\n",device-invalidDevices));
-
- /* Now allocate the list of pointers to devices */
- ppFilters = (PaWinWdmFilter**)PaUtil_AllocateMemory( sizeof(PaWinWdmFilter*) * filterCount);
- if( ppFilters == 0 )
- {
- if(handle != NULL)
- SetupDiDestroyDeviceInfoList(handle);
- *pResult = paInsufficientMemory;
- return NULL;
- }
-
- /* Now create filter objects for each interface found */
- slot = 0;
- for( device = 0;;device++ )
- {
- interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- interfaceData.Reserved = 0;
- aliasData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- aliasData.Reserved = 0;
- devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
- devInfoData.Reserved = 0;
- streamingType = Type_kWaveCyclic;
-
- noError = SetupDiEnumDeviceInterfaces(handle,NULL,category,device,&interfaceData);
- if( !noError )
- break; /* No more devices */
-
- /* Check this one has the render or capture alias */
- aliasFlags = 0;
- noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_render,&aliasData);
- if(noError)
- {
- if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
- {
- PA_DEBUG(("Device %d has render alias\n",device));
- aliasFlags |= Alias_kRender; /* Has render alias */
- }
- }
- noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_capture,&aliasData);
- if(noError)
- {
- if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
- {
- PA_DEBUG(("Device %d has capture alias\n",device));
- aliasFlags |= Alias_kCapture; /* Has capture alias */
- }
- }
- if(!aliasFlags)
- {
- continue; /* This was not a valid capture or render audio device */
- }
- else
- {
- /* Check if filter is WaveRT, if not it is a WaveCyclic */
- noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,category_realtime,&aliasData);
- if (noError)
- {
- PA_DEBUG(("Device %d has realtime alias\n",device));
- aliasFlags |= Alias_kRealtime;
- streamingType = Type_kWaveRT;
- }
- }
-
- noError = SetupDiGetDeviceInterfaceDetailW(handle,&interfaceData,devInterfaceDetails,sizeInterface,NULL,&devInfoData);
- if( noError )
- {
- DWORD type;
- WCHAR friendlyName[MAX_PATH] = {0};
- DWORD sizeFriendlyName;
- PaWinWdmFilter* newFilter = 0;
-
- PaError result = paNoError;
- /* Try to get the "friendly name" for this interface */
- sizeFriendlyName = sizeof(friendlyName);
-
- if (IsEarlierThanVista() && IsUSBDevice(devInterfaceDetails->DevicePath))
- {
- /* XP and USB audio device needs to look elsewhere, otherwise it'll only be a "USB Audio Device". Not
- very literate. */
- if (!SetupDiGetDeviceRegistryPropertyW(handle,
- &devInfoData,
- SPDRP_LOCATION_INFORMATION,
- &type,
- (BYTE*)friendlyName,
- sizeof(friendlyName),
- NULL))
- {
- friendlyName[0] = 0;
- }
- }
-
- if (friendlyName[0] == 0 || IsNameUSBAudioDevice(friendlyName))
- {
- /* Fix contributed by Ben Allison
- * Removed KEY_SET_VALUE from flags on following call
- * as its causes failure when running without admin rights
- * and it was not required */
- HKEY hkey=SetupDiOpenDeviceInterfaceRegKey(handle,&interfaceData,0,KEY_QUERY_VALUE);
- if(hkey!=INVALID_HANDLE_VALUE)
- {
- noError = RegQueryValueExW(hkey,L"FriendlyName",0,&type,(BYTE*)friendlyName,&sizeFriendlyName);
- if( noError == ERROR_SUCCESS )
- {
- PA_DEBUG(("Interface %d, Name: %s\n",device,friendlyName));
- RegCloseKey(hkey);
- }
- else
- {
- friendlyName[0] = 0;
- }
- }
- }
-
- TrimString(friendlyName, sizeFriendlyName);
-
- newFilter = FilterNew(streamingType,
- devInfoData.DevInst,
- devInterfaceDetails->DevicePath,
- friendlyName,
- &result);
-
- if( result == paNoError )
- {
- int pin;
- unsigned filterIOs = 0;
-
- /* Increment number of "devices" */
- for (pin = 0; pin < newFilter->pinCount; ++pin)
- {
- PaWinWdmPin* pPin = newFilter->pins[pin];
- if (pPin == NULL)
- continue;
-
- filterIOs += max(1, pPin->inputCount);
- }
-
- noOfPaDevices += filterIOs;
-
- PA_DEBUG(("Filter (%s) created with %d valid pins (total I/Os: %u)\n", ((newFilter->devInfo.streamingType==Type_kWaveRT)?"WaveRT":"WaveCyclic"), newFilter->validPinCount, filterIOs));
-
- assert(slot < filterCount);
-
- ppFilters[slot] = newFilter;
-
- slot++;
- }
- else
- {
- PA_DEBUG(("Filter NOT created\n"));
- /* As there are now less filters than we initially thought
- * we must reduce the count by one */
- filterCount--;
- }
- }
- }
-
- /* Clean up */
- if(handle != NULL)
- SetupDiDestroyDeviceInfoList(handle);
-
- *pFilterCount = filterCount;
- *pNoOfPaDevices = noOfPaDevices;
-
- return ppFilters;
-}
-
-typedef struct PaNameHashIndex
-{
- unsigned index;
- unsigned count;
- ULONG hash;
- struct PaNameHashIndex *next;
-} PaNameHashIndex;
-
-typedef struct PaNameHashObject
-{
- PaNameHashIndex* list;
- PaUtilAllocationGroup* allocGroup;
-} PaNameHashObject;
-
-static ULONG GetNameHash(const wchar_t* str, const BOOL input)
-{
- /* This is to make sure that a name that exists as both input & output won't get the same hash value */
- const ULONG fnv_prime = (input ? 0x811C9DD7 : 0x811FEB0B);
- ULONG hash = 0;
- for(; *str != 0; str++)
- {
- hash *= fnv_prime;
- hash ^= (*str);
- }
- assert(hash != 0);
- return hash;
-}
-
-static PaError CreateHashEntry(PaNameHashObject* obj, const wchar_t* name, const BOOL input)
-{
- ULONG hash = GetNameHash(name, input);
- PaNameHashIndex * pLast = NULL;
- PaNameHashIndex * p = obj->list;
- while (p != 0)
- {
- if (p->hash == hash)
- {
- break;
- }
- pLast = p;
- p = p->next;
- }
- if (p == NULL)
- {
- p = (PaNameHashIndex*)PaUtil_GroupAllocateMemory(obj->allocGroup, sizeof(PaNameHashIndex));
- if (p == NULL)
- {
- return paInsufficientMemory;
- }
- p->hash = hash;
- p->count = 1;
- if (pLast != 0)
- {
- assert(pLast->next == 0);
- pLast->next = p;
- }
- if (obj->list == 0)
- {
- obj->list = p;
- }
- }
- else
- {
- ++p->count;
- }
- return paNoError;
-}
-
-static PaError InitNameHashObject(PaNameHashObject* obj, PaWinWdmFilter* pFilter)
-{
- int i;
-
- obj->allocGroup = PaUtil_CreateAllocationGroup();
- if (obj->allocGroup == NULL)
- {
- return paInsufficientMemory;
- }
-
- for (i = 0; i < pFilter->pinCount; ++i)
- {
- unsigned m;
- PaWinWdmPin* pin = pFilter->pins[i];
-
- if (pin == NULL)
- continue;
-
- for (m = 0; m < max(1, pin->inputCount); ++m)
- {
- const BOOL isInput = (pin->dataFlow == KSPIN_DATAFLOW_OUT);
- const wchar_t* name = (pin->inputs == NULL) ? pin->friendlyName : pin->inputs[m]->friendlyName;
-
- PaError result = CreateHashEntry(obj, name, isInput);
-
- if (result != paNoError)
- {
- return result;
- }
- }
- }
- return paNoError;
-}
-
-static void DeinitNameHashObject(PaNameHashObject* obj)
-{
- assert(obj != 0);
- PaUtil_FreeAllAllocations(obj->allocGroup);
- PaUtil_DestroyAllocationGroup(obj->allocGroup);
- memset(obj, 0, sizeof(PaNameHashObject));
-}
-
-static unsigned GetNameIndex(PaNameHashObject* obj, const wchar_t* name, const BOOL input)
-{
- ULONG hash = GetNameHash(name, input);
- PaNameHashIndex* p = obj->list;
- while (p != NULL)
- {
- if (p->hash == hash)
- {
- if (p->count > 1)
- {
- return (++p->index);
- }
- else
- {
- return 0;
- }
- }
-
- p = p->next;
- }
- // Should never get here!!
- assert(FALSE);
- return 0;
-}
-
-static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex, void **scanResults, int *newDeviceCount )
-{
- PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
- PaError result = paNoError;
- PaWinWdmFilter** ppFilters = 0;
- PaWinWDMScanDeviceInfosResults *outArgument = 0;
- int filterCount = 0;
- int totalDeviceCount = 0;
- int idxDevice = 0;
- DWORD defaultInDevPathSize = 0;
- DWORD defaultOutDevPathSize = 0;
- wchar_t* defaultInDevPath = 0;
- wchar_t* defaultOutDevPath = 0;
-
- ppFilters = BuildFilterList( &filterCount, &totalDeviceCount, &result );
- if( result != paNoError )
- {
- goto error;
- }
-
- // Get hold of default device paths for capture & playback
- if( waveInMessage(0, DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&defaultInDevPathSize, 0 ) == MMSYSERR_NOERROR )
- {
- defaultInDevPath = (wchar_t *)PaUtil_AllocateMemory((defaultInDevPathSize + 1) * sizeof(wchar_t));
- waveInMessage(0, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)defaultInDevPath, defaultInDevPathSize);
- }
- if( waveOutMessage(0, DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&defaultOutDevPathSize, 0 ) == MMSYSERR_NOERROR )
- {
- defaultOutDevPath = (wchar_t *)PaUtil_AllocateMemory((defaultOutDevPathSize + 1) * sizeof(wchar_t));
- waveOutMessage(0, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)defaultOutDevPath, defaultOutDevPathSize);
- }
-
- if( totalDeviceCount > 0 )
- {
- PaWinWdmDeviceInfo *deviceInfoArray = 0;
- int idxFilter;
- int i;
- unsigned devIsDefaultIn = 0, devIsDefaultOut = 0;
-
- /* Allocate the out param for all the info we need */
- outArgument = (PaWinWDMScanDeviceInfosResults *) PaUtil_GroupAllocateMemory(
- wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults) );
- if( !outArgument )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- outArgument->defaultInputDevice = paNoDevice;
- outArgument->defaultOutputDevice = paNoDevice;
-
- outArgument->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
- wdmHostApi->allocations, sizeof(PaDeviceInfo*) * totalDeviceCount );
- if( !outArgument->deviceInfos )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- /* allocate all device info structs in a contiguous block */
- deviceInfoArray = (PaWinWdmDeviceInfo*)PaUtil_GroupAllocateMemory(
- wdmHostApi->allocations, sizeof(PaWinWdmDeviceInfo) * totalDeviceCount );
- if( !deviceInfoArray )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- /* Make sure all items in array */
- for( i = 0 ; i < totalDeviceCount; ++i )
- {
- PaDeviceInfo *deviceInfo = &deviceInfoArray[i].inheritedDeviceInfo;
- deviceInfo->structVersion = 2;
- deviceInfo->hostApi = hostApiIndex;
- deviceInfo->name = 0;
- outArgument->deviceInfos[ i ] = deviceInfo;
- }
-
- idxDevice = 0;
- for (idxFilter = 0; idxFilter < filterCount; ++idxFilter)
- {
- PaNameHashObject nameHash = {0};
- PaWinWdmFilter* pFilter = ppFilters[idxFilter];
- if( pFilter == NULL )
- continue;
-
- if (InitNameHashObject(&nameHash, pFilter) != paNoError)
- {
- DeinitNameHashObject(&nameHash);
- continue;
- }
-
- devIsDefaultIn = (defaultInDevPath && (_wcsicmp(pFilter->devInfo.filterPath, defaultInDevPath) == 0));
- devIsDefaultOut = (defaultOutDevPath && (_wcsicmp(pFilter->devInfo.filterPath, defaultOutDevPath) == 0));
-
- for (i = 0; i < pFilter->pinCount; ++i)
- {
- unsigned m;
- ULONG nameIndex = 0;
- ULONG nameIndexHash = 0;
- PaWinWdmPin* pin = pFilter->pins[i];
-
- if (pin == NULL)
- continue;
-
- for (m = 0; m < max(1, pin->inputCount); ++m)
- {
- PaWinWdmDeviceInfo *wdmDeviceInfo = (PaWinWdmDeviceInfo *)outArgument->deviceInfos[idxDevice];
- PaDeviceInfo *deviceInfo = &wdmDeviceInfo->inheritedDeviceInfo;
- wchar_t localCompositeName[MAX_PATH];
- unsigned nameIndex = 0;
- const BOOL isInput = (pin->dataFlow == KSPIN_DATAFLOW_OUT);
-
- wdmDeviceInfo->filter = pFilter;
-
- deviceInfo->structVersion = 2;
- deviceInfo->hostApi = hostApiIndex;
- deviceInfo->name = wdmDeviceInfo->compositeName;
- /* deviceInfo->hostApiSpecificDeviceInfo = &pFilter->devInfo; */
-
- wdmDeviceInfo->pin = pin->pinId;
-
- /* Get the name of the "device" */
- if (pin->inputs == NULL)
- {
- wcsncpy(localCompositeName, pin->friendlyName, MAX_PATH);
- wdmDeviceInfo->muxPosition = -1;
- wdmDeviceInfo->endpointPinId = pin->endpointPinId;
- }
- else
- {
- PaWinWdmMuxedInput* input = pin->inputs[m];
- wcsncpy(localCompositeName, input->friendlyName, MAX_PATH);
- wdmDeviceInfo->muxPosition = (int)m;
- wdmDeviceInfo->endpointPinId = input->endpointPinId;
- }
-
- {
- /* Get base length */
- size_t n = wcslen(localCompositeName);
-
- /* Check if there are more entries with same name (which might very well be the case), if there
- are, the name will be postfixed with an index. */
- nameIndex = GetNameIndex(&nameHash, localCompositeName, isInput);
- if (nameIndex > 0)
- {
- /* This name has multiple instances, so we post fix with a number */
- n += _snwprintf(localCompositeName + n, MAX_PATH - n, L" %u", nameIndex);
- }
- /* Postfix with filter name */
- _snwprintf(localCompositeName + n, MAX_PATH - n, L" (%s)", pFilter->friendlyName);
- }
-
- /* Convert wide char string to utf-8 */
- WideCharToMultiByte(CP_UTF8, 0, localCompositeName, -1, wdmDeviceInfo->compositeName, MAX_PATH, NULL, NULL);
-
- /* NB! WDM/KS has no concept of a full-duplex device, each pin is either an input or an output */
- if (isInput)
- {
- /* INPUT ! */
- deviceInfo->maxInputChannels = pin->maxChannels;
- deviceInfo->maxOutputChannels = 0;
-
- /* RoBi NB: Due to the fact that input audio endpoints in Vista (& later OSs) can be the same device, but with
- different input mux settings, there might be a discrepancy between the default input device chosen, and
- that which will be used by Portaudio. Not much to do about that unfortunately.
- */
- if ((defaultInDevPath == 0 || devIsDefaultIn) &&
- outArgument->defaultInputDevice == paNoDevice)
- {
- outArgument->defaultInputDevice = idxDevice;
- }
- }
- else
- {
- /* OUTPUT ! */
- deviceInfo->maxInputChannels = 0;
- deviceInfo->maxOutputChannels = pin->maxChannels;
-
- if ((defaultOutDevPath == 0 || devIsDefaultOut) &&
- outArgument->defaultOutputDevice == paNoDevice)
- {
- outArgument->defaultOutputDevice = idxDevice;
- }
- }
-
- /* These low values are not very useful because
- * a) The lowest latency we end up with can depend on many factors such
- * as the device buffer sizes/granularities, sample rate, channels and format
- * b) We cannot know the device buffer sizes until we try to open/use it at
- * a particular setting
- * So: we give 512x48000Hz frames as the default low input latency
- **/
- switch (pFilter->devInfo.streamingType)
- {
- case Type_kWaveCyclic:
- if (IsEarlierThanVista())
- {
- /* 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
- with it. */
- deviceInfo->defaultLowInputLatency = 0.02;
- deviceInfo->defaultLowOutputLatency = 0.02;
- }
- else
- {
- /* This is a conservative estimate. Most WaveCyclic drivers will limit the available latency, but f.i. my Edirol
- PCR-A30 can reach 3 ms latency easily... */
- deviceInfo->defaultLowInputLatency = 0.01;
- deviceInfo->defaultLowOutputLatency = 0.01;
- }
- deviceInfo->defaultHighInputLatency = (4096.0/48000.0);
- deviceInfo->defaultHighOutputLatency = (4096.0/48000.0);
- deviceInfo->defaultSampleRate = (double)(pin->defaultSampleRate);
- break;
- case Type_kWaveRT:
- /* This is also a conservative estimate, based on WaveRT polled mode. In polled mode, the latency will be dictated
- by the buffer size given by the driver. */
- deviceInfo->defaultLowInputLatency = 0.01;
- deviceInfo->defaultLowOutputLatency = 0.01;
- deviceInfo->defaultHighInputLatency = 0.04;
- deviceInfo->defaultHighOutputLatency = 0.04;
- deviceInfo->defaultSampleRate = (double)(pin->defaultSampleRate);
- break;
- default:
- assert(0);
- break;
- }
-
- /* Add reference to filter */
- FilterAddRef(wdmDeviceInfo->filter);
-
- assert(idxDevice < totalDeviceCount);
- ++idxDevice;
- }
- }
-
- /* If no one has add ref'd the filter, drop it */
- if (pFilter->filterRefCount == 0)
- {
- FilterFree(pFilter);
- }
-
- /* Deinitialize name hash object */
- DeinitNameHashObject(&nameHash);
- }
- }
-
- *scanResults = outArgument;
- *newDeviceCount = idxDevice;
- return result;
-
-error:
- result = DisposeDeviceInfos(hostApi, outArgument, totalDeviceCount);
-
- return result;
-}
-
-static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *scanResults, int deviceCount )
-{
- PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
-
- hostApi->info.deviceCount = 0;
- hostApi->info.defaultInputDevice = paNoDevice;
- hostApi->info.defaultOutputDevice = paNoDevice;
-
- /* Free any old memory which might be in the device info */
- if( hostApi->deviceInfos )
- {
- PaWinWDMScanDeviceInfosResults* localScanResults = (PaWinWDMScanDeviceInfosResults*)PaUtil_GroupAllocateMemory(
- wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults));
- localScanResults->deviceInfos = hostApi->deviceInfos;
-
- DisposeDeviceInfos(hostApi, &localScanResults, hostApi->info.deviceCount);
-
- hostApi->deviceInfos = NULL;
- }
-
- if( scanResults != NULL )
- {
- PaWinWDMScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinWDMScanDeviceInfosResults * ) scanResults;
-
- if( deviceCount > 0 )
- {
- /* use the array allocated in ScanDeviceInfos() as our deviceInfos */
- hostApi->deviceInfos = scanDeviceInfosResults->deviceInfos;
-
- hostApi->info.defaultInputDevice = scanDeviceInfosResults->defaultInputDevice;
- hostApi->info.defaultOutputDevice = scanDeviceInfosResults->defaultOutputDevice;
-
- hostApi->info.deviceCount = deviceCount;
- }
-
- PaUtil_GroupFreeMemory( wdmHostApi->allocations, scanDeviceInfosResults );
- }
-
- return paNoError;
-
-}
-
-static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *scanResults, int deviceCount )
-{
- PaWinWdmHostApiRepresentation *winDsHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
-
- if( scanResults != NULL )
- {
- PaWinWDMScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinWDMScanDeviceInfosResults * ) scanResults;
-
- if( scanDeviceInfosResults->deviceInfos )
- {
- int i;
- for (i = 0; i < deviceCount; ++i)
- {
- PaWinWdmDeviceInfo* pDevice = (PaWinWdmDeviceInfo*)scanDeviceInfosResults->deviceInfos[i];
- if (pDevice->filter != 0)
- {
- FilterFree(pDevice->filter);
- }
- }
-
- PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults->deviceInfos[0] ); /* all device info structs are allocated in a block so we can destroy them here */
- PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults->deviceInfos );
- }
-
- PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults );
- }
-
- return paNoError;
-
-}
-
-PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
-{
- PaError result = paNoError;
- int deviceCount = 0;
- void *scanResults = 0;
- PaWinWdmHostApiRepresentation *wdmHostApi = NULL;
-
- PA_LOGE_;
-
-#ifdef PA_WDMKS_SET_TREF
- tRef = PaUtil_GetTime();
-#endif
-
- /*
- Attempt to load the KSUSER.DLL without which we cannot create pins
- We will unload this on termination
- */
- if(DllKsUser == NULL)
- {
- DllKsUser = LoadLibrary(TEXT("ksuser.dll"));
- if(DllKsUser == NULL)
- goto error;
- }
- FunctionKsCreatePin = (KSCREATEPIN*)GetProcAddress(DllKsUser, "KsCreatePin");
- if(FunctionKsCreatePin == NULL)
- goto error;
-
- /* Attempt to load AVRT.DLL, if we can't, then we'll just use time critical prio instead... */
- if(paWinWDMKSAvRtEntryPoints.hInstance == NULL)
- {
- paWinWDMKSAvRtEntryPoints.hInstance = LoadLibrary(TEXT("avrt.dll"));
- if (paWinWDMKSAvRtEntryPoints.hInstance != NULL)
- {
- paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics =
- (HANDLE(WINAPI*)(LPCSTR,LPDWORD))GetProcAddress(paWinWDMKSAvRtEntryPoints.hInstance,"AvSetMmThreadCharacteristicsA");
- paWinWDMKSAvRtEntryPoints.AvRevertMmThreadCharacteristics =
- (BOOL(WINAPI*)(HANDLE))GetProcAddress(paWinWDMKSAvRtEntryPoints.hInstance, "AvRevertMmThreadCharacteristics");
- paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority =
- (BOOL(WINAPI*)(HANDLE,PA_AVRT_PRIORITY))GetProcAddress(paWinWDMKSAvRtEntryPoints.hInstance, "AvSetMmThreadPriority");
- }
- }
-
- wdmHostApi = (PaWinWdmHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinWdmHostApiRepresentation) );
- if( !wdmHostApi )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- wdmHostApi->allocations = PaUtil_CreateAllocationGroup();
- if( !wdmHostApi->allocations )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- *hostApi = &wdmHostApi->inheritedHostApiRep;
- (*hostApi)->info.structVersion = 1;
- (*hostApi)->info.type = paWDMKS;
- (*hostApi)->info.name = "Windows WDM-KS";
-
- /* these are all updated by CommitDeviceInfos() */
- (*hostApi)->info.deviceCount = 0;
- (*hostApi)->info.defaultInputDevice = paNoDevice;
- (*hostApi)->info.defaultOutputDevice = paNoDevice;
- (*hostApi)->deviceInfos = 0;
-
- result = ScanDeviceInfos(&wdmHostApi->inheritedHostApiRep, hostApiIndex, &scanResults, &deviceCount);
- if (result != paNoError)
- {
- goto error;
- }
-
- CommitDeviceInfos(&wdmHostApi->inheritedHostApiRep, hostApiIndex, scanResults, deviceCount);
-
- (*hostApi)->Terminate = Terminate;
- (*hostApi)->OpenStream = OpenStream;
- (*hostApi)->IsFormatSupported = IsFormatSupported;
- /* In preparation for hotplug
- (*hostApi)->ScanDeviceInfos = ScanDeviceInfos;
- (*hostApi)->CommitDeviceInfos = CommitDeviceInfos;
- (*hostApi)->DisposeDeviceInfos = DisposeDeviceInfos;
- */
- PaUtil_InitializeStreamInterface( &wdmHostApi->callbackStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, GetStreamCpuLoad,
- PaUtil_DummyRead, PaUtil_DummyWrite,
- PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
-
- PaUtil_InitializeStreamInterface( &wdmHostApi->blockingStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, PaUtil_DummyGetCpuLoad,
- ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
-
- PA_LOGL_;
- return result;
-
-error:
- Terminate( (PaUtilHostApiRepresentation*)wdmHostApi );
-
- PA_LOGL_;
- return result;
-}
-
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
-{
- PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
- PA_LOGE_;
-
- /* Do not unload the libraries */
- if( DllKsUser != NULL )
- {
- FreeLibrary( DllKsUser );
- DllKsUser = NULL;
- }
-
- if( paWinWDMKSAvRtEntryPoints.hInstance != NULL )
- {
- FreeLibrary( paWinWDMKSAvRtEntryPoints.hInstance );
- paWinWDMKSAvRtEntryPoints.hInstance = NULL;
- }
-
- if( wdmHostApi)
- {
- PaWinWDMScanDeviceInfosResults* localScanResults = (PaWinWDMScanDeviceInfosResults*)PaUtil_GroupAllocateMemory(
- wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults));
- localScanResults->deviceInfos = hostApi->deviceInfos;
- DisposeDeviceInfos(hostApi, localScanResults, hostApi->info.deviceCount);
-
- if( wdmHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( wdmHostApi->allocations );
- PaUtil_DestroyAllocationGroup( wdmHostApi->allocations );
- }
- PaUtil_FreeMemory( wdmHostApi );
- }
- PA_LOGL_;
-}
-
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate )
-{
- int inputChannelCount, outputChannelCount;
- PaSampleFormat inputSampleFormat, outputSampleFormat;
- PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
- PaWinWdmFilter* pFilter;
- int result = paFormatIsSupported;
- WAVEFORMATEXTENSIBLE wfx;
- PaWinWaveFormatChannelMask channelMask;
-
- PA_LOGE_;
-
- if( inputParameters )
- {
- PaWinWdmDeviceInfo* pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device];
- PaWinWdmPin* pin;
- unsigned fmt;
- unsigned long testFormat = 0;
- unsigned validBits = 0;
-
- inputChannelCount = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
-
- /* all standard sample formats are supported by the buffer adapter,
- this implementation doesn't support any custom sample formats */
- if( inputSampleFormat & paCustomFormat )
- {
- PaWinWDM_SetLastErrorInfo(paSampleFormatNotSupported, "IsFormatSupported: Custom input format not supported");
- return paSampleFormatNotSupported;
- }
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
- {
- PaWinWDM_SetLastErrorInfo(paInvalidDevice, "IsFormatSupported: paUseHostApiSpecificDeviceSpecification not supported");
- return paInvalidDevice;
- }
-
- /* check that input device can support inputChannelCount */
- if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
- {
- PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "IsFormatSupported: Invalid input channel count");
- return paInvalidChannelCount;
- }
-
- /* validate inputStreamInfo */
- if( inputParameters->hostApiSpecificStreamInfo )
- {
- PaWinWDM_SetLastErrorInfo(paIncompatibleHostApiSpecificStreamInfo, "Host API stream info not supported");
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- }
-
- pFilter = pDeviceInfo->filter;
- pin = pFilter->pins[pDeviceInfo->pin];
-
- /* Find out the testing format */
- for (fmt = paFloat32; fmt <= paUInt8; fmt <<= 1)
- {
- if ((fmt & pin->formats) != 0)
- {
- /* Found a matching format! */
- testFormat = fmt;
- break;
- }
- }
- if (testFormat == 0)
- {
- PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(capture) failed: no testformat found!");
- return paUnanticipatedHostError;
- }
-
- /* Due to special considerations, WaveRT devices with paInt24 should be tested with paInt32 and
- valid bits = 24 (instead of 24 bit samples) */
- if (pFilter->devInfo.streamingType == Type_kWaveRT && testFormat == paInt24)
- {
- PA_DEBUG(("IsFormatSupported (capture): WaveRT overriding testFormat paInt24 with paInt32 (24 valid bits)"));
- testFormat = paInt32;
- validBits = 24;
- }
-
- /* Check that the input format is supported */
- channelMask = PaWin_DefaultChannelMask(inputChannelCount);
- PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
- inputChannelCount,
- testFormat,
- PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
- sampleRate,
- channelMask );
- if (validBits != 0)
- {
- wfx.Samples.wValidBitsPerSample = validBits;
- }
-
- result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx);
- if( result != paNoError )
- {
- /* Try a WAVE_FORMAT_PCM instead */
- PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
- inputChannelCount,
- testFormat,
- PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
- sampleRate);
-
- if (validBits != 0)
- {
- wfx.Samples.wValidBitsPerSample = validBits;
- }
-
- result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx);
- if( result != paNoError )
- {
- PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(capture) failed: sr=%u,ch=%u,bits=%u", wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample);
- return result;
- }
- }
- }
- else
- {
- inputChannelCount = 0;
- }
-
- if( outputParameters )
- {
- PaWinWdmDeviceInfo* pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device];
- PaWinWdmPin* pin;
- unsigned fmt;
- unsigned long testFormat = 0;
- unsigned validBits = 0;
-
- outputChannelCount = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
-
- /* all standard sample formats are supported by the buffer adapter,
- this implementation doesn't support any custom sample formats */
- if( outputSampleFormat & paCustomFormat )
- {
- PaWinWDM_SetLastErrorInfo(paSampleFormatNotSupported, "IsFormatSupported: Custom output format not supported");
- return paSampleFormatNotSupported;
- }
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
- {
- PaWinWDM_SetLastErrorInfo(paInvalidDevice, "IsFormatSupported: paUseHostApiSpecificDeviceSpecification not supported");
- return paInvalidDevice;
- }
-
- /* check that output device can support outputChannelCount */
- if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
- {
- PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "Invalid output channel count");
- return paInvalidChannelCount;
- }
-
- /* validate outputStreamInfo */
- if( outputParameters->hostApiSpecificStreamInfo )
- {
- PaWinWDM_SetLastErrorInfo(paIncompatibleHostApiSpecificStreamInfo, "Host API stream info not supported");
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- }
-
- pFilter = pDeviceInfo->filter;
- pin = pFilter->pins[pDeviceInfo->pin];
-
- /* Find out the testing format */
- for (fmt = paFloat32; fmt <= paUInt8; fmt <<= 1)
- {
- if ((fmt & pin->formats) != 0)
- {
- /* Found a matching format! */
- testFormat = fmt;
- break;
- }
- }
- if (testFormat == 0)
- {
- PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(render) failed: no testformat found!");
- return paUnanticipatedHostError;
- }
-
- /* Due to special considerations, WaveRT devices with paInt24 should be tested with paInt32 and
- valid bits = 24 (instead of 24 bit samples) */
- if (pFilter->devInfo.streamingType == Type_kWaveRT && testFormat == paInt24)
- {
- PA_DEBUG(("IsFormatSupported (render): WaveRT overriding testFormat paInt24 with paInt32 (24 valid bits)"));
- testFormat = paInt32;
- validBits = 24;
- }
-
- /* Check that the output format is supported */
- channelMask = PaWin_DefaultChannelMask(outputChannelCount);
- PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
- outputChannelCount,
- testFormat,
- PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
- sampleRate,
- channelMask );
-
- if (validBits != 0)
- {
- wfx.Samples.wValidBitsPerSample = validBits;
- }
-
- result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx);
- if( result != paNoError )
- {
- /* Try a WAVE_FORMAT_PCM instead */
- PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
- outputChannelCount,
- testFormat,
- PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
- sampleRate);
-
- if (validBits != 0)
- {
- wfx.Samples.wValidBitsPerSample = validBits;
- }
-
- result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx);
- if( result != paNoError )
- {
- PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(render) failed: %u,%u,%u", wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample);
- return result;
- }
- }
-
- }
- else
- {
- outputChannelCount = 0;
- }
-
- /*
- IMPLEMENT ME:
-
- - if a full duplex stream is requested, check that the combination
- of input and output parameters is supported if necessary
-
- - check that the device supports sampleRate
-
- Because the buffer adapter handles conversion between all standard
- sample formats, the following checks are only required if paCustomFormat
- is implemented, or under some other unusual conditions.
-
- - check that input device can support inputSampleFormat, or that
- we have the capability to convert from inputSampleFormat to
- a native format
-
- - check that output device can support outputSampleFormat, or that
- we have the capability to convert from outputSampleFormat to
- a native format
- */
- if((inputChannelCount == 0)&&(outputChannelCount == 0))
- {
- PaWinWDM_SetLastErrorInfo(paSampleFormatNotSupported, "No input or output channels defined");
- result = paSampleFormatNotSupported; /* Not right error */
- }
-
- PA_LOGL_;
- return result;
-}
-
-static void ResetStreamEvents(PaWinWdmStream* stream)
-{
- unsigned i;
- ResetEvent(stream->eventAbort);
- ResetEvent(stream->eventStreamStart[StreamStart_kOk]);
- ResetEvent(stream->eventStreamStart[StreamStart_kFailed]);
-
- for (i=0; i<stream->capture.noOfPackets; ++i)
- {
- if (stream->capture.events && stream->capture.events[i])
- {
- ResetEvent(stream->capture.events[i]);
- }
- }
-
- for (i=0; i<stream->render.noOfPackets; ++i)
- {
- if (stream->render.events && stream->render.events[i])
- {
- ResetEvent(stream->render.events[i]);
- }
- }
-}
-
-static void CloseStreamEvents(PaWinWdmStream* stream)
-{
- unsigned i;
- PaWinWdmIOInfo* ios[2] = { &stream->capture, &stream->render };
-
- if (stream->eventAbort)
- {
- CloseHandle(stream->eventAbort);
- stream->eventAbort = 0;
- }
- if (stream->eventStreamStart[StreamStart_kOk])
- {
- CloseHandle(stream->eventStreamStart[StreamStart_kOk]);
- }
- if (stream->eventStreamStart[StreamStart_kFailed])
- {
- CloseHandle(stream->eventStreamStart[StreamStart_kFailed]);
- }
-
- for (i = 0; i < 2; ++i)
- {
- unsigned j;
- /* Unregister notification handles for WaveRT */
- if (ios[i]->pPin && ios[i]->pPin->parentFilter->devInfo.streamingType == Type_kWaveRT &&
- ios[i]->pPin->pinKsSubType == SubType_kNotification &&
- ios[i]->events != 0)
- {
- PinUnregisterNotificationHandle(ios[i]->pPin, ios[i]->events[0]);
- }
-
- for (j=0; j < ios[i]->noOfPackets; ++j)
- {
- if (ios[i]->events && ios[i]->events[j])
- {
- CloseHandle(ios[i]->events[j]);
- ios[i]->events[j] = 0;
- }
- }
- }
-}
-
-static unsigned NextPowerOf2(unsigned val)
-{
- val--;
- val = (val >> 1) | val;
- val = (val >> 2) | val;
- val = (val >> 4) | val;
- val = (val >> 8) | val;
- val = (val >> 16) | val;
- return ++val;
-}
-
-static PaError ValidateSpecificStreamParameters(
- const PaStreamParameters *streamParameters,
- const PaWinWDMKSInfo *streamInfo,
- unsigned isInput)
-{
- if( streamInfo )
- {
- if( streamInfo->size != sizeof( PaWinWDMKSInfo )
- || streamInfo->version != 1 )
- {
- PA_DEBUG(("Stream parameters: size or version not correct"));
- return paIncompatibleHostApiSpecificStreamInfo;
- }
-
- if (!!(streamInfo->flags & ~(paWinWDMKSOverrideFramesize | paWinWDMKSUseGivenChannelMask)))
- {
- PA_DEBUG(("Stream parameters: non supported flags set"));
- return paIncompatibleHostApiSpecificStreamInfo;
- }
-
- if (streamInfo->noOfPackets != 0 &&
- (streamInfo->noOfPackets < 2 || streamInfo->noOfPackets > 8))
- {
- PA_DEBUG(("Stream parameters: noOfPackets %u out of range [2,8]", streamInfo->noOfPackets));
- return paIncompatibleHostApiSpecificStreamInfo;
- }
-
- if (streamInfo->flags & paWinWDMKSUseGivenChannelMask)
- {
- if (isInput)
- {
- PA_DEBUG(("Stream parameters: Channels mask setting not supported for input stream"));
- return paIncompatibleHostApiSpecificStreamInfo;
- }
-
- if (streamInfo->channelMask & PAWIN_SPEAKER_RESERVED)
- {
- PA_DEBUG(("Stream parameters: Given channels mask 0x%08X not supported", streamInfo->channelMask));
- return paIncompatibleHostApiSpecificStreamInfo;
- }
- }
-
- }
-
- return paNoError;
-}
-
-
-
-
-/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
-
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerUserBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData )
-{
- PaError result = paNoError;
- PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
- PaWinWdmStream *stream = 0;
- /* unsigned long framesPerHostBuffer; these may not be equivalent for all implementations */
- PaSampleFormat inputSampleFormat, outputSampleFormat;
- PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
- int userInputChannels,userOutputChannels;
- WAVEFORMATEXTENSIBLE wfx;
-
- PA_LOGE_;
- PA_DEBUG(("OpenStream:sampleRate = %f\n",sampleRate));
- PA_DEBUG(("OpenStream:framesPerBuffer = %lu\n",framesPerUserBuffer));
-
- if( inputParameters )
- {
- userInputChannels = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
- {
- PaWinWDM_SetLastErrorInfo(paInvalidDevice, "paUseHostApiSpecificDeviceSpecification(in) not supported");
- return paInvalidDevice;
- }
-
- /* check that input device can support stream->userInputChannels */
- if( userInputChannels > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
- {
- PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "Invalid input channel count");
- return paInvalidChannelCount;
- }
-
- /* validate inputStreamInfo */
- result = ValidateSpecificStreamParameters(inputParameters, inputParameters->hostApiSpecificStreamInfo, 1 );
- if(result != paNoError)
- {
- PaWinWDM_SetLastErrorInfo(result, "Host API stream info not supported (in)");
- return result; /* this implementation doesn't use custom stream info */
- }
- }
- else
- {
- userInputChannels = 0;
- inputSampleFormat = paInt16; /* Suppress 'uninitialised var' warnings. */
- }
-
- if( outputParameters )
- {
- userOutputChannels = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
- {
- PaWinWDM_SetLastErrorInfo(paInvalidDevice, "paUseHostApiSpecificDeviceSpecification(out) not supported");
- return paInvalidDevice;
- }
-
- /* check that output device can support stream->userInputChannels */
- if( userOutputChannels > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
- {
- PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "Invalid output channel count");
- return paInvalidChannelCount;
- }
-
- /* validate outputStreamInfo */
- result = ValidateSpecificStreamParameters( outputParameters, outputParameters->hostApiSpecificStreamInfo, 0 );
- if (result != paNoError)
- {
- PaWinWDM_SetLastErrorInfo(result, "Host API stream info not supported (out)");
- return result; /* this implementation doesn't use custom stream info */
- }
- }
- else
- {
- userOutputChannels = 0;
- outputSampleFormat = paInt16; /* Suppress 'uninitialized var' warnings. */
- }
-
- /* validate platform specific flags */
- if( (streamFlags & paPlatformSpecificFlags) != 0 )
- {
- PaWinWDM_SetLastErrorInfo(paInvalidFlag, "Invalid flag supplied");
- return paInvalidFlag; /* unexpected platform specific flag */
- }
-
- stream = (PaWinWdmStream*)PaUtil_AllocateMemory( sizeof(PaWinWdmStream) );
- if( !stream )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- /* Create allocation group */
- stream->allocGroup = PaUtil_CreateAllocationGroup();
- if( !stream->allocGroup )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- /* Zero the stream object */
- /* memset((void*)stream,0,sizeof(PaWinWdmStream)); */
-
- if( streamCallback )
- {
- PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- &wdmHostApi->callbackStreamInterface, streamCallback, userData );
- }
- else
- {
- /* PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- &wdmHostApi->blockingStreamInterface, streamCallback, userData ); */
-
- /* We don't support the blocking API yet */
- PA_DEBUG(("Blocking API not supported yet!\n"));
- PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Blocking API not supported yet");
- result = paUnanticipatedHostError;
- goto error;
- }
-
- PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
-
- /* Instantiate the input pin if necessary */
- if(userInputChannels > 0)
- {
- PaWinWdmFilter* pFilter;
- PaWinWdmDeviceInfo* pDeviceInfo;
- PaWinWdmPin* pPin;
- unsigned validBitsPerSample = 0;
- PaWinWaveFormatChannelMask channelMask = PaWin_DefaultChannelMask( userInputChannels );
-
- result = paSampleFormatNotSupported;
- pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device];
- pFilter = pDeviceInfo->filter;
- pPin = pFilter->pins[pDeviceInfo->pin];
-
- stream->userInputChannels = userInputChannels;
-
- hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( pPin->formats, inputSampleFormat );
- if (hostInputSampleFormat == paSampleFormatNotSupported)
- {
- result = paUnanticipatedHostError;
- PaWinWDM_SetLastErrorInfo(result, "PU_SCAF(%X,%X) failed (input)", pPin->formats, inputSampleFormat);
- goto error;
- }
- else if (pFilter->devInfo.streamingType == Type_kWaveRT && hostInputSampleFormat == paInt24)
- {
- /* For WaveRT, we choose 32 bit format instead of paInt24, since we MIGHT need to align buffer on a
- 128 byte boundary (see PinGetBuffer) */
- hostInputSampleFormat = paInt32;
- /* But we'll tell the driver that it's 24 bit in 32 bit container */
- validBitsPerSample = 24;
- }
-
- while (hostInputSampleFormat <= paUInt8)
- {
- unsigned channelsToProbe = stream->userInputChannels;
- /* Some or all KS devices can only handle the exact number of channels
- * they specify. But PortAudio clients expect to be able to
- * at least specify mono I/O on a multi-channel device
- * If this is the case, then we will do the channel mapping internally
- * The following loop tests this case
- **/
- while (1)
- {
- PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
- channelsToProbe,
- hostInputSampleFormat,
- PaWin_SampleFormatToLinearWaveFormatTag(hostInputSampleFormat),
- sampleRate,
- channelMask );
- stream->capture.bytesPerFrame = wfx.Format.nBlockAlign;
- if (validBitsPerSample != 0)
- {
- wfx.Samples.wValidBitsPerSample = validBitsPerSample;
- }
- stream->capture.pPin = FilterCreatePin(pFilter, pPin->pinId, (WAVEFORMATEX*)&wfx, &result);
- stream->deviceInputChannels = channelsToProbe;
-
- if( result != paNoError && result != paDeviceUnavailable )
- {
- /* Try a WAVE_FORMAT_PCM instead */
- PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
- channelsToProbe,
- hostInputSampleFormat,
- PaWin_SampleFormatToLinearWaveFormatTag(hostInputSampleFormat),
- sampleRate);
- if (validBitsPerSample != 0)
- {
- wfx.Samples.wValidBitsPerSample = validBitsPerSample;
- }
- stream->capture.pPin = FilterCreatePin(pFilter, pPin->pinId, (const WAVEFORMATEX*)&wfx, &result);
- }
-
- if (result == paDeviceUnavailable) goto occupied;
-
- if (result == paNoError)
- {
- /* We're done */
- break;
- }
-
- if (channelsToProbe < (unsigned)pPin->maxChannels)
- {
- /* Go to next multiple of 2 */
- channelsToProbe = min((((channelsToProbe>>1)+1)<<1), (unsigned)pPin->maxChannels);
- continue;
- }
-
- break;
- }
-
- if (result == paNoError)
- {
- /* We're done */
- break;
- }
-
- /* Go to next format in line with lower resolution */
- hostInputSampleFormat <<= 1;
- }
-
- if(stream->capture.pPin == NULL)
- {
- PaWinWDM_SetLastErrorInfo(result, "Failed to create capture pin: sr=%u,ch=%u,bits=%u,align=%u",
- wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample, wfx.Format.nBlockAlign);
- goto error;
- }
-
- /* Select correct mux input on MUX node of topology filter */
- if (pDeviceInfo->muxPosition >= 0)
- {
- assert(pPin->parentFilter->topologyFilter != NULL);
-
- result = FilterUse(pPin->parentFilter->topologyFilter);
- if (result != paNoError)
- {
- PaWinWDM_SetLastErrorInfo(result, "Failed to open topology filter");
- goto error;
- }
-
- result = WdmSetMuxNodeProperty(pPin->parentFilter->topologyFilter->handle,
- pPin->inputs[pDeviceInfo->muxPosition]->muxNodeId,
- pPin->inputs[pDeviceInfo->muxPosition]->muxPinId);
-
- FilterRelease(pPin->parentFilter->topologyFilter);
-
- if(result != paNoError)
- {
- PaWinWDM_SetLastErrorInfo(result, "Failed to set topology mux node");
- goto error;
- }
- }
-
- stream->capture.bytesPerSample = stream->capture.bytesPerFrame / stream->deviceInputChannels;
- stream->capture.pPin->frameSize /= stream->capture.bytesPerFrame;
- PA_DEBUG(("Capture pin frames: %d\n",stream->capture.pPin->frameSize));
- }
- else
- {
- hostInputSampleFormat = (PaSampleFormat)0; /* Avoid uninitialized variable warning */
-
- stream->capture.pPin = NULL;
- stream->capture.bytesPerFrame = 0;
- }
-
- /* Instantiate the output pin if necessary */
- if(userOutputChannels > 0)
- {
- PaWinWdmFilter* pFilter;
- PaWinWdmDeviceInfo* pDeviceInfo;
- PaWinWdmPin* pPin;
- PaWinWDMKSInfo* pInfo = (PaWinWDMKSInfo*)(outputParameters->hostApiSpecificStreamInfo);
- unsigned validBitsPerSample = 0;
- PaWinWaveFormatChannelMask channelMask = PaWin_DefaultChannelMask( userOutputChannels );
- if (pInfo && (pInfo->flags & paWinWDMKSUseGivenChannelMask))
- {
- PA_DEBUG(("Using channelMask 0x%08X instead of default 0x%08X\n",
- pInfo->channelMask,
- channelMask));
- channelMask = pInfo->channelMask;
- }
-
- result = paSampleFormatNotSupported;
- pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device];
- pFilter = pDeviceInfo->filter;
- pPin = pFilter->pins[pDeviceInfo->pin];
-
- stream->userOutputChannels = userOutputChannels;
-
- hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( pPin->formats, outputSampleFormat );
- if (hostOutputSampleFormat == paSampleFormatNotSupported)
- {
- result = paUnanticipatedHostError;
- PaWinWDM_SetLastErrorInfo(result, "PU_SCAF(%X,%X) failed (output)", pPin->formats, hostOutputSampleFormat);
- goto error;
- }
- else if (pFilter->devInfo.streamingType == Type_kWaveRT && hostOutputSampleFormat == paInt24)
- {
- /* For WaveRT, we choose 32 bit format instead of paInt24, since we MIGHT need to align buffer on a
- 128 byte boundary (see PinGetBuffer) */
- hostOutputSampleFormat = paInt32;
- /* But we'll tell the driver that it's 24 bit in 32 bit container */
- validBitsPerSample = 24;
- }
-
- while (hostOutputSampleFormat <= paUInt8)
- {
- unsigned channelsToProbe = stream->userOutputChannels;
- /* Some or all KS devices can only handle the exact number of channels
- * they specify. But PortAudio clients expect to be able to
- * at least specify mono I/O on a multi-channel device
- * If this is the case, then we will do the channel mapping internally
- * The following loop tests this case
- **/
- while (1)
- {
- PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
- channelsToProbe,
- hostOutputSampleFormat,
- PaWin_SampleFormatToLinearWaveFormatTag(hostOutputSampleFormat),
- sampleRate,
- channelMask );
- stream->render.bytesPerFrame = wfx.Format.nBlockAlign;
- if (validBitsPerSample != 0)
- {
- wfx.Samples.wValidBitsPerSample = validBitsPerSample;
- }
- stream->render.pPin = FilterCreatePin(pFilter, pPin->pinId, (WAVEFORMATEX*)&wfx, &result);
- stream->deviceOutputChannels = channelsToProbe;
-
- if( result != paNoError && result != paDeviceUnavailable )
- {
- PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
- channelsToProbe,
- hostOutputSampleFormat,
- PaWin_SampleFormatToLinearWaveFormatTag(hostOutputSampleFormat),
- sampleRate);
- if (validBitsPerSample != 0)
- {
- wfx.Samples.wValidBitsPerSample = validBitsPerSample;
- }
- stream->render.pPin = FilterCreatePin(pFilter, pPin->pinId, (const WAVEFORMATEX*)&wfx, &result);
- }
-
- if (result == paDeviceUnavailable) goto occupied;
-
- if (result == paNoError)
- {
- /* We're done */
- break;
- }
-
- if (channelsToProbe < (unsigned)pPin->maxChannels)
- {
- /* Go to next multiple of 2 */
- channelsToProbe = min((((channelsToProbe>>1)+1)<<1), (unsigned)pPin->maxChannels);
- continue;
- }
-
- break;
- };
-
- if (result == paNoError)
- {
- /* We're done */
- break;
- }
-
- /* Go to next format in line with lower resolution */
- hostOutputSampleFormat <<= 1;
- }
-
- if(stream->render.pPin == NULL)
- {
- PaWinWDM_SetLastErrorInfo(result, "Failed to create render pin: sr=%u,ch=%u,bits=%u,align=%u",
- wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample, wfx.Format.nBlockAlign);
- goto error;
- }
-
- stream->render.bytesPerSample = stream->render.bytesPerFrame / stream->deviceOutputChannels;
- stream->render.pPin->frameSize /= stream->render.bytesPerFrame;
- PA_DEBUG(("Render pin frames: %d\n",stream->render.pPin->frameSize));
- }
- else
- {
- hostOutputSampleFormat = (PaSampleFormat)0; /* Avoid uninitialized variable warning */
-
- stream->render.pPin = NULL;
- stream->render.bytesPerFrame = 0;
- }
-
- /* Calculate the framesPerHostXxxxBuffer size based upon the suggested latency values */
- /* Record the buffer length */
- if(inputParameters)
- {
- /* Calculate the frames from the user's value - add a bit to round up */
- stream->capture.framesPerBuffer = (unsigned long)((inputParameters->suggestedLatency*sampleRate)+0.0001);
- if(stream->capture.framesPerBuffer > (unsigned long)sampleRate)
- { /* Upper limit is 1 second */
- stream->capture.framesPerBuffer = (unsigned long)sampleRate;
- }
- else if(stream->capture.framesPerBuffer < stream->capture.pPin->frameSize)
- {
- stream->capture.framesPerBuffer = stream->capture.pPin->frameSize;
- }
- PA_DEBUG(("Input frames chosen:%ld\n",stream->capture.framesPerBuffer));
-
- /* Setup number of packets to use */
- stream->capture.noOfPackets = 2;
-
- if (inputParameters->hostApiSpecificStreamInfo)
- {
- PaWinWDMKSInfo* pInfo = (PaWinWDMKSInfo*)inputParameters->hostApiSpecificStreamInfo;
-
- if (stream->capture.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic &&
- pInfo->noOfPackets != 0)
- {
- stream->capture.noOfPackets = pInfo->noOfPackets;
- }
- }
- }
-
- if(outputParameters)
- {
- /* Calculate the frames from the user's value - add a bit to round up */
- stream->render.framesPerBuffer = (unsigned long)((outputParameters->suggestedLatency*sampleRate)+0.0001);
- if(stream->render.framesPerBuffer > (unsigned long)sampleRate)
- { /* Upper limit is 1 second */
- stream->render.framesPerBuffer = (unsigned long)sampleRate;
- }
- else if(stream->render.framesPerBuffer < stream->render.pPin->frameSize)
- {
- stream->render.framesPerBuffer = stream->render.pPin->frameSize;
- }
- PA_DEBUG(("Output frames chosen:%ld\n",stream->render.framesPerBuffer));
-
- /* Setup number of packets to use */
- stream->render.noOfPackets = 2;
-
- if (outputParameters->hostApiSpecificStreamInfo)
- {
- PaWinWDMKSInfo* pInfo = (PaWinWDMKSInfo*)outputParameters->hostApiSpecificStreamInfo;
-
- if (stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic &&
- pInfo->noOfPackets != 0)
- {
- stream->render.noOfPackets = pInfo->noOfPackets;
- }
- }
- }
-
- /* Host buffer size is bound to the largest of the input and output frame sizes */
- result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
- stream->userInputChannels, inputSampleFormat, hostInputSampleFormat,
- stream->userOutputChannels, outputSampleFormat, hostOutputSampleFormat,
- sampleRate, streamFlags, framesPerUserBuffer,
- max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer),
- paUtilBoundedHostBufferSize,
- streamCallback, userData );
- if( result != paNoError )
- {
- PaWinWDM_SetLastErrorInfo(result, "PaUtil_InitializeBufferProcessor failed: ich=%u, isf=%u, hisf=%u, och=%u, osf=%u, hosf=%u, sr=%lf, flags=0x%X, fpub=%u, fphb=%u",
- stream->userInputChannels, inputSampleFormat, hostInputSampleFormat,
- stream->userOutputChannels, outputSampleFormat, hostOutputSampleFormat,
- sampleRate, streamFlags, framesPerUserBuffer,
- max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer));
- goto error;
- }
-
- /* Allocate/get all the buffers for host I/O */
- if (stream->userInputChannels > 0)
- {
- stream->streamRepresentation.streamInfo.inputLatency = stream->capture.framesPerBuffer / sampleRate;
-
- switch (stream->capture.pPin->parentFilter->devInfo.streamingType)
- {
- case Type_kWaveCyclic:
- {
- unsigned size = stream->capture.noOfPackets * stream->capture.framesPerBuffer * stream->capture.bytesPerFrame;
- /* Allocate input host buffer */
- stream->capture.hostBuffer = (char*)PaUtil_GroupAllocateMemory(stream->allocGroup, size);
- PA_DEBUG(("Input buffer allocated (size = %u)\n", size));
- if( !stream->capture.hostBuffer )
- {
- PA_DEBUG(("Cannot allocate host input buffer!\n"));
- PaWinWDM_SetLastErrorInfo(paInsufficientMemory, "Failed to allocate input buffer");
- result = paInsufficientMemory;
- goto error;
- }
- stream->capture.hostBufferSize = size;
- PA_DEBUG(("Input buffer start = %p (size=%u)\n",stream->capture.hostBuffer, stream->capture.hostBufferSize));
- stream->capture.pPin->fnEventHandler = PaPinCaptureEventHandler_WaveCyclic;
- stream->capture.pPin->fnSubmitHandler = PaPinCaptureSubmitHandler_WaveCyclic;
- }
- break;
- case Type_kWaveRT:
- {
- const DWORD dwTotalSize = 2 * stream->capture.framesPerBuffer * stream->capture.bytesPerFrame;
- DWORD dwRequestedSize = dwTotalSize;
- BOOL bCallMemoryBarrier = FALSE;
- ULONG hwFifoLatency = 0;
- ULONG dummy;
- result = PinGetBuffer(stream->capture.pPin, (void**)&stream->capture.hostBuffer, &dwRequestedSize, &bCallMemoryBarrier);
- if (!result)
- {
- PA_DEBUG(("Input buffer start = %p, size = %u\n", stream->capture.hostBuffer, dwRequestedSize));
- if (dwRequestedSize != dwTotalSize)
- {
- PA_DEBUG(("Buffer length changed by driver from %u to %u !\n", dwTotalSize, dwRequestedSize));
- /* Recalculate to what the driver has given us */
- stream->capture.framesPerBuffer = dwRequestedSize / (2 * stream->capture.bytesPerFrame);
- }
- stream->capture.hostBufferSize = dwRequestedSize;
-
- if (stream->capture.pPin->pinKsSubType == SubType_kPolled)
- {
- stream->capture.pPin->fnEventHandler = PaPinCaptureEventHandler_WaveRTPolled;
- stream->capture.pPin->fnSubmitHandler = PaPinCaptureSubmitHandler_WaveRTPolled;
- }
- else
- {
- stream->capture.pPin->fnEventHandler = PaPinCaptureEventHandler_WaveRTEvent;
- stream->capture.pPin->fnSubmitHandler = PaPinCaptureSubmitHandler_WaveRTEvent;
- }
-
- stream->capture.pPin->fnMemBarrier = bCallMemoryBarrier ? MemoryBarrierRead : MemoryBarrierDummy;
- }
- else
- {
- PA_DEBUG(("Failed to get input buffer (WaveRT)\n"));
- PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to get input buffer (WaveRT)");
- result = paUnanticipatedHostError;
- goto error;
- }
-
- /* Get latency */
- result = PinGetHwLatency(stream->capture.pPin, &hwFifoLatency, &dummy, &dummy);
- if (result == paNoError)
- {
- stream->capture.pPin->hwLatency = hwFifoLatency;
-
- /* Add HW latency into total input latency */
- stream->streamRepresentation.streamInfo.inputLatency += ((hwFifoLatency / stream->capture.bytesPerFrame) / sampleRate);
- }
- else
- {
- PA_DEBUG(("Failed to get size of FIFO hardware buffer (is set to zero)\n"));
- stream->capture.pPin->hwLatency = 0;
- }
- }
- break;
- default:
- /* Undefined wave type!! */
- assert(0);
- result = paInternalError;
- PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType);
- goto error;
- }
- }
- else
- {
- stream->capture.hostBuffer = 0;
- }
-
- if (stream->userOutputChannels > 0)
- {
- stream->streamRepresentation.streamInfo.outputLatency = stream->render.framesPerBuffer / sampleRate;
-
- switch (stream->render.pPin->parentFilter->devInfo.streamingType)
- {
- case Type_kWaveCyclic:
- {
- unsigned size = stream->render.noOfPackets * stream->render.framesPerBuffer * stream->render.bytesPerFrame;
- /* Allocate output device buffer */
- stream->render.hostBuffer = (char*)PaUtil_GroupAllocateMemory(stream->allocGroup, size);
- PA_DEBUG(("Output buffer allocated (size = %u)\n", size));
- if( !stream->render.hostBuffer )
- {
- PA_DEBUG(("Cannot allocate host output buffer!\n"));
- PaWinWDM_SetLastErrorInfo(paInsufficientMemory, "Failed to allocate output buffer");
- result = paInsufficientMemory;
- goto error;
- }
- stream->render.hostBufferSize = size;
- PA_DEBUG(("Output buffer start = %p (size=%u)\n",stream->render.hostBuffer, stream->render.hostBufferSize));
-
- stream->render.pPin->fnEventHandler = PaPinRenderEventHandler_WaveCyclic;
- stream->render.pPin->fnSubmitHandler = PaPinRenderSubmitHandler_WaveCyclic;
- }
- break;
- case Type_kWaveRT:
- {
- const DWORD dwTotalSize = 2 * stream->render.framesPerBuffer * stream->render.bytesPerFrame;
- DWORD dwRequestedSize = dwTotalSize;
- BOOL bCallMemoryBarrier = FALSE;
- ULONG hwFifoLatency = 0;
- ULONG dummy;
- result = PinGetBuffer(stream->render.pPin, (void**)&stream->render.hostBuffer, &dwRequestedSize, &bCallMemoryBarrier);
- if (!result)
- {
- PA_DEBUG(("Output buffer start = %p, size = %u, membarrier = %u\n", stream->render.hostBuffer, dwRequestedSize, bCallMemoryBarrier));
- if (dwRequestedSize != dwTotalSize)
- {
- PA_DEBUG(("Buffer length changed by driver from %u to %u !\n", dwTotalSize, dwRequestedSize));
- /* Recalculate to what the driver has given us */
- stream->render.framesPerBuffer = dwRequestedSize / (2 * stream->render.bytesPerFrame);
- }
- stream->render.hostBufferSize = dwRequestedSize;
-
- if (stream->render.pPin->pinKsSubType == SubType_kPolled)
- {
- stream->render.pPin->fnEventHandler = PaPinRenderEventHandler_WaveRTPolled;
- stream->render.pPin->fnSubmitHandler = PaPinRenderSubmitHandler_WaveRTPolled;
- }
- else
- {
- stream->render.pPin->fnEventHandler = PaPinRenderEventHandler_WaveRTEvent;
- stream->render.pPin->fnSubmitHandler = PaPinRenderSubmitHandler_WaveRTEvent;
- }
-
- stream->render.pPin->fnMemBarrier = bCallMemoryBarrier ? MemoryBarrierWrite : MemoryBarrierDummy;
- }
- else
- {
- PA_DEBUG(("Failed to get output buffer (with notification)\n"));
- PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to get output buffer (with notification)");
- result = paUnanticipatedHostError;
- goto error;
- }
-
- /* Get latency */
- result = PinGetHwLatency(stream->render.pPin, &hwFifoLatency, &dummy, &dummy);
- if (result == paNoError)
- {
- stream->render.pPin->hwLatency = hwFifoLatency;
-
- /* Add HW latency into total output latency */
- stream->streamRepresentation.streamInfo.outputLatency += ((hwFifoLatency / stream->render.bytesPerFrame) / sampleRate);
- }
- else
- {
- PA_DEBUG(("Failed to get size of FIFO hardware buffer (is set to zero)\n"));
- stream->render.pPin->hwLatency = 0;
- }
- }
- break;
- default:
- /* Undefined wave type!! */
- assert(0);
- result = paInternalError;
- PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType);
- goto error;
- }
- }
- else
- {
- stream->render.hostBuffer = 0;
- }
-
- stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
-
- PA_DEBUG(("BytesPerInputFrame = %d\n",stream->capture.bytesPerFrame));
- PA_DEBUG(("BytesPerOutputFrame = %d\n",stream->render.bytesPerFrame));
-
- /* memset(stream->hostBuffer,0,size); */
-
- /* Abort */
- stream->eventAbort = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (stream->eventAbort == 0)
- {
- result = paInsufficientMemory;
- goto error;
- }
- stream->eventStreamStart[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (stream->eventStreamStart[0] == 0)
- {
- result = paInsufficientMemory;
- goto error;
- }
- stream->eventStreamStart[1] = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (stream->eventStreamStart[1] == 0)
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- if(stream->userInputChannels > 0)
- {
- const unsigned bufferSizeInBytes = stream->capture.framesPerBuffer * stream->capture.bytesPerFrame;
- const unsigned ringBufferFrameSize = NextPowerOf2( 1024 + 2 * max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer) );
-
- stream->capture.events = (HANDLE*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->capture.noOfPackets * sizeof(HANDLE));
- if (stream->capture.events == NULL)
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- stream->capture.packets = (DATAPACKET*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->capture.noOfPackets * sizeof(DATAPACKET));
- if (stream->capture.packets == NULL)
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- switch(stream->capture.pPin->parentFilter->devInfo.streamingType)
- {
- case Type_kWaveCyclic:
- {
- /* WaveCyclic case */
- unsigned i;
- for (i = 0; i < stream->capture.noOfPackets; ++i)
- {
- /* Set up the packets */
- DATAPACKET *p = stream->capture.packets + i;
-
- /* Record event */
- stream->capture.events[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
-
- p->Signal.hEvent = stream->capture.events[i];
- p->Header.Data = stream->capture.hostBuffer + (i*bufferSizeInBytes);
- p->Header.FrameExtent = bufferSizeInBytes;
- p->Header.DataUsed = 0;
- p->Header.Size = sizeof(p->Header);
- p->Header.PresentationTime.Numerator = 1;
- p->Header.PresentationTime.Denominator = 1;
- }
- }
- break;
- case Type_kWaveRT:
- {
- /* Set up the "packets" */
- DATAPACKET *p = stream->capture.packets + 0;
-
- /* Record event: WaveRT has a single event for 2 notification per buffer */
- stream->capture.events[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
-
- p->Header.Data = stream->capture.hostBuffer;
- p->Header.FrameExtent = bufferSizeInBytes;
- p->Header.DataUsed = 0;
- p->Header.Size = sizeof(p->Header);
- p->Header.PresentationTime.Numerator = 1;
- p->Header.PresentationTime.Denominator = 1;
-
- ++p;
- p->Header.Data = stream->capture.hostBuffer + bufferSizeInBytes;
- p->Header.FrameExtent = bufferSizeInBytes;
- p->Header.DataUsed = 0;
- p->Header.Size = sizeof(p->Header);
- p->Header.PresentationTime.Numerator = 1;
- p->Header.PresentationTime.Denominator = 1;
-
- if (stream->capture.pPin->pinKsSubType == SubType_kNotification)
- {
- result = PinRegisterNotificationHandle(stream->capture.pPin, stream->capture.events[0]);
-
- if (result != paNoError)
- {
- PA_DEBUG(("Failed to register capture notification handle\n"));
- PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to register capture notification handle");
- result = paUnanticipatedHostError;
- goto error;
- }
- }
-
- result = PinRegisterPositionRegister(stream->capture.pPin);
-
- if (result != paNoError)
- {
- unsigned long pos = 0xdeadc0de;
- PA_DEBUG(("Failed to register capture position register, using PinGetAudioPositionViaIOCTLWrite\n"));
- stream->capture.pPin->fnAudioPosition = PinGetAudioPositionViaIOCTLWrite;
- /* Test position function */
- result = (stream->capture.pPin->fnAudioPosition)(stream->capture.pPin, &pos);
- if (result != paNoError || pos != 0x0)
- {
- PA_DEBUG(("Failed to read capture position register (IOCTL)\n"));
- PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to read capture position register (IOCTL)");
- result = paUnanticipatedHostError;
- goto error;
- }
- }
- else
- {
- stream->capture.pPin->fnAudioPosition = PinGetAudioPositionMemoryMapped;
- }
- }
- break;
- default:
- /* Undefined wave type!! */
- assert(0);
- result = paInternalError;
- PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType);
- goto error;
- }
-
- /* Setup the input ring buffer here */
- stream->ringBufferData = (char*)PaUtil_GroupAllocateMemory(stream->allocGroup, ringBufferFrameSize * stream->capture.bytesPerFrame);
- if (stream->ringBufferData == NULL)
- {
- result = paInsufficientMemory;
- goto error;
- }
- PaUtil_InitializeRingBuffer(&stream->ringBuffer, stream->capture.bytesPerFrame, ringBufferFrameSize, stream->ringBufferData);
- }
- if(stream->userOutputChannels > 0)
- {
- const unsigned bufferSizeInBytes = stream->render.framesPerBuffer * stream->render.bytesPerFrame;
-
- stream->render.events = (HANDLE*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->render.noOfPackets * sizeof(HANDLE));
- if (stream->render.events == NULL)
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- stream->render.packets = (DATAPACKET*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->render.noOfPackets * sizeof(DATAPACKET));
- if (stream->render.packets == NULL)
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- switch(stream->render.pPin->parentFilter->devInfo.streamingType)
- {
- case Type_kWaveCyclic:
- {
- /* WaveCyclic case */
- unsigned i;
- for (i = 0; i < stream->render.noOfPackets; ++i)
- {
- /* Set up the packets */
- DATAPACKET *p = stream->render.packets + i;
-
- /* Playback event */
- stream->render.events[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
-
- /* In this case, we just use the packets as ptr to the device buffer */
- p->Signal.hEvent = stream->render.events[i];
- p->Header.Data = stream->render.hostBuffer + (i*bufferSizeInBytes);
- p->Header.FrameExtent = bufferSizeInBytes;
- p->Header.DataUsed = bufferSizeInBytes;
- p->Header.Size = sizeof(p->Header);
- p->Header.PresentationTime.Numerator = 1;
- p->Header.PresentationTime.Denominator = 1;
- }
- }
- break;
- case Type_kWaveRT:
- {
- /* WaveRT case */
-
- /* Set up the "packets" */
- DATAPACKET *p = stream->render.packets;
-
- /* The only playback event */
- stream->render.events[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
-
- /* In this case, we just use the packets as ptr to the device buffer */
- p->Header.Data = stream->render.hostBuffer;
- p->Header.FrameExtent = stream->render.framesPerBuffer*stream->render.bytesPerFrame;
- p->Header.DataUsed = stream->render.framesPerBuffer*stream->render.bytesPerFrame;
- p->Header.Size = sizeof(p->Header);
- p->Header.PresentationTime.Numerator = 1;
- p->Header.PresentationTime.Denominator = 1;
-
- ++p;
- p->Header.Data = stream->render.hostBuffer + stream->render.framesPerBuffer*stream->render.bytesPerFrame;
- p->Header.FrameExtent = stream->render.framesPerBuffer*stream->render.bytesPerFrame;
- p->Header.DataUsed = stream->render.framesPerBuffer*stream->render.bytesPerFrame;
- p->Header.Size = sizeof(p->Header);
- p->Header.PresentationTime.Numerator = 1;
- p->Header.PresentationTime.Denominator = 1;
-
- if (stream->render.pPin->pinKsSubType == SubType_kNotification)
- {
- result = PinRegisterNotificationHandle(stream->render.pPin, stream->render.events[0]);
-
- if (result != paNoError)
- {
- PA_DEBUG(("Failed to register rendering notification handle\n"));
- PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to register rendering notification handle");
- result = paUnanticipatedHostError;
- goto error;
- }
- }
-
- result = PinRegisterPositionRegister(stream->render.pPin);
-
- if (result != paNoError)
- {
- unsigned long pos = 0xdeadc0de;
- PA_DEBUG(("Failed to register rendering position register, using PinGetAudioPositionViaIOCTLRead\n"));
- stream->render.pPin->fnAudioPosition = PinGetAudioPositionViaIOCTLRead;
- /* Test position function */
- result = (stream->render.pPin->fnAudioPosition)(stream->render.pPin, &pos);
- if (result != paNoError || pos != 0x0)
- {
- PA_DEBUG(("Failed to read render position register (IOCTL)\n"));
- PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to read render position register (IOCTL)");
- result = paUnanticipatedHostError;
- goto error;
- }
- }
- else
- {
- stream->render.pPin->fnAudioPosition = PinGetAudioPositionMemoryMapped;
- }
- }
- break;
- default:
- /* Undefined wave type!! */
- assert(0);
- result = paInternalError;
- PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType);
- goto error;
- }
- }
-
- stream->streamStarted = 0;
- stream->streamActive = 0;
- stream->streamStop = 0;
- stream->streamAbort = 0;
- stream->streamFlags = streamFlags;
- stream->oldProcessPriority = REALTIME_PRIORITY_CLASS;
-
- /* Increase ref count on filters in use, so that a CommitDeviceInfos won't delete them */
- if (stream->capture.pPin != 0)
- {
- FilterAddRef(stream->capture.pPin->parentFilter);
- }
- if (stream->render.pPin != 0)
- {
- FilterAddRef(stream->render.pPin->parentFilter);
- }
-
- /* Ok, now update our host API specific stream info */
- if (stream->userInputChannels)
- {
- PaWinWdmDeviceInfo *pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device];
-
- stream->hostApiStreamInfo.input.device = Pa_HostApiDeviceIndexToDeviceIndex(Pa_HostApiTypeIdToHostApiIndex(paWDMKS), inputParameters->device);
- stream->hostApiStreamInfo.input.channels = stream->deviceInputChannels;
- stream->hostApiStreamInfo.input.muxNodeId = -1;
- if (stream->capture.pPin->inputs)
- {
- stream->hostApiStreamInfo.input.muxNodeId = stream->capture.pPin->inputs[pDeviceInfo->muxPosition]->muxNodeId;
- }
- stream->hostApiStreamInfo.input.endpointPinId = pDeviceInfo->endpointPinId;
- stream->hostApiStreamInfo.input.framesPerHostBuffer = stream->capture.framesPerBuffer;
- stream->hostApiStreamInfo.input.streamingSubType = stream->capture.pPin->pinKsSubType;
- }
- else
- {
- stream->hostApiStreamInfo.input.device = paNoDevice;
- }
- if (stream->userOutputChannels)
- {
- stream->hostApiStreamInfo.output.device = Pa_HostApiDeviceIndexToDeviceIndex(Pa_HostApiTypeIdToHostApiIndex(paWDMKS), outputParameters->device);
- stream->hostApiStreamInfo.output.channels = stream->deviceOutputChannels;
- stream->hostApiStreamInfo.output.framesPerHostBuffer = stream->render.framesPerBuffer;
- stream->hostApiStreamInfo.output.endpointPinId = stream->render.pPin->endpointPinId;
- stream->hostApiStreamInfo.output.streamingSubType = stream->render.pPin->pinKsSubType;
- }
- else
- {
- stream->hostApiStreamInfo.output.device = paNoDevice;
- }
- /*stream->streamRepresentation.streamInfo.hostApiTypeId = paWDMKS;
- stream->streamRepresentation.streamInfo.hostApiSpecificStreamInfo = &stream->hostApiStreamInfo;*/
- stream->streamRepresentation.streamInfo.structVersion = 2;
-
- *s = (PaStream*)stream;
-
- PA_LOGL_;
- return result;
-
-occupied:
- /* Ok, someone else is hogging the pin, bail out */
- assert (result == paDeviceUnavailable);
- PaWinWDM_SetLastErrorInfo(result, "Device is occupied");
-
-error:
- PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
-
- CloseStreamEvents(stream);
-
- if (stream->allocGroup)
- {
- PaUtil_FreeAllAllocations(stream->allocGroup);
- PaUtil_DestroyAllocationGroup(stream->allocGroup);
- stream->allocGroup = 0;
- }
-
- if(stream->render.pPin)
- PinClose(stream->render.pPin);
- if(stream->capture.pPin)
- PinClose(stream->capture.pPin);
-
- PaUtil_FreeMemory( stream );
-
- PA_LOGL_;
- return result;
-}
-
-/*
-When CloseStream() is called, the multi-api layer ensures that
-the stream has already been stopped or aborted.
-*/
-static PaError CloseStream( PaStream* s )
-{
- PaError result = paNoError;
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
-
- PA_LOGE_;
-
- assert(!stream->streamStarted);
- assert(!stream->streamActive);
-
- PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
- PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
-
- CloseStreamEvents(stream);
-
- if (stream->allocGroup)
- {
- PaUtil_FreeAllAllocations(stream->allocGroup);
- PaUtil_DestroyAllocationGroup(stream->allocGroup);
- stream->allocGroup = 0;
- }
-
- if(stream->render.pPin)
- {
- PinClose(stream->render.pPin);
- }
- if(stream->capture.pPin)
- {
- PinClose(stream->capture.pPin);
- }
-
- if (stream->render.pPin)
- {
- FilterFree(stream->render.pPin->parentFilter);
- }
- if (stream->capture.pPin)
- {
- FilterFree(stream->capture.pPin->parentFilter);
- }
-
- PaUtil_FreeMemory( stream );
-
- PA_LOGL_;
- return result;
-}
-
-/*
-Write the supplied packet to the pin
-Asynchronous
-Should return paNoError on success
-*/
-static PaError PinWrite(HANDLE h, DATAPACKET* p)
-{
- PaError result = paNoError;
- unsigned long cbReturned = 0;
- BOOL fRes = DeviceIoControl(h,
- IOCTL_KS_WRITE_STREAM,
- NULL,
- 0,
- &p->Header,
- p->Header.Size,
- &cbReturned,
- &p->Signal);
- if (!fRes)
- {
- unsigned long error = GetLastError();
- if (error != ERROR_IO_PENDING)
- {
- result = paInternalError;
- }
- }
- return result;
-}
-
-/*
-Read to the supplied packet from the pin
-Asynchronous
-Should return paNoError on success
-*/
-static PaError PinRead(HANDLE h, DATAPACKET* p)
-{
- PaError result = paNoError;
- unsigned long cbReturned = 0;
- BOOL fRes = DeviceIoControl(h,
- IOCTL_KS_READ_STREAM,
- NULL,
- 0,
- &p->Header,
- p->Header.Size,
- &cbReturned,
- &p->Signal);
- if (!fRes)
- {
- unsigned long error = GetLastError();
- if (error != ERROR_IO_PENDING)
- {
- result = paInternalError;
- }
- }
- return result;
-}
-
-/*
-Copy the first interleaved channel of 16 bit data to the other channels
-*/
-static void DuplicateFirstChannelInt16(void* buffer, int channels, int samples)
-{
- unsigned short* data = (unsigned short*)buffer;
- int channel;
- unsigned short sourceSample;
- while( samples-- )
- {
- sourceSample = *data++;
- channel = channels-1;
- while( channel-- )
- {
- *data++ = sourceSample;
- }
- }
-}
-
-/*
-Copy the first interleaved channel of 24 bit data to the other channels
-*/
-static void DuplicateFirstChannelInt24(void* buffer, int channels, int samples)
-{
- unsigned char* data = (unsigned char*)buffer;
- int channel;
- unsigned char sourceSample[3];
- while( samples-- )
- {
- sourceSample[0] = data[0];
- sourceSample[1] = data[1];
- sourceSample[2] = data[2];
- data += 3;
- channel = channels-1;
- while( channel-- )
- {
- data[0] = sourceSample[0];
- data[1] = sourceSample[1];
- data[2] = sourceSample[2];
- data += 3;
- }
- }
-}
-
-/*
-Copy the first interleaved channel of 32 bit data to the other channels
-*/
-static void DuplicateFirstChannelInt32(void* buffer, int channels, int samples)
-{
- unsigned long* data = (unsigned long*)buffer;
- int channel;
- unsigned long sourceSample;
- while( samples-- )
- {
- sourceSample = *data++;
- channel = channels-1;
- while( channel-- )
- {
- *data++ = sourceSample;
- }
- }
-}
-
-/*
-Increase the priority of the calling thread to RT
-*/
-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)
- {
- hAVRT = paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics("Pro Audio", &dwTask);
- if (hAVRT != NULL && hAVRT != INVALID_HANDLE_VALUE)
- {
- BOOL bret = paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority(hAVRT, PA_AVRT_PRIORITY_CRITICAL);
- if (!bret)
- {
- PA_DEBUG(("Set mm thread prio to critical failed!\n"));
- }
- else
- {
- return hAVRT;
- }
- }
- else
- {
- PA_DEBUG(("Set mm thread characteristic to 'Pro Audio' failed, reverting to SetThreadPriority\n"));
- }
- }
-
- /* For XP and earlier, or if AvSetMmThreadCharacteristics fails (MMCSS disabled ?) */
- if (timeBeginPeriod(1) != TIMERR_NOERROR) {
- PA_DEBUG(("timeBeginPeriod(1) failed!\n"));
- }
-
- if (!SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL)) {
- PA_DEBUG(("SetThreadPriority failed!\n"));
- }
-
- return hAVRT;
-}
-
-/*
-Decrease the priority of the calling thread to normal
-*/
-static void DropThreadPriority(HANDLE hAVRT)
-{
- HANDLE hThread = GetCurrentThread();
-
- if (hAVRT != NULL)
- {
- paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority(hAVRT, PA_AVRT_PRIORITY_NORMAL);
- paWinWDMKSAvRtEntryPoints.AvRevertMmThreadCharacteristics(hAVRT);
- return;
- }
-
- SetThreadPriority(hThread, THREAD_PRIORITY_NORMAL);
- timeEndPeriod(1);
-}
-
-static PaError PreparePinForStart(PaWinWdmPin* pin)
-{
- PaError result;
- result = PinSetState(pin, KSSTATE_ACQUIRE);
- if (result != paNoError)
- {
- goto error;
- }
- result = PinSetState(pin, KSSTATE_PAUSE);
- if (result != paNoError)
- {
- goto error;
- }
- return result;
-
-error:
- PinSetState(pin, KSSTATE_STOP);
- return result;
-}
-
-static PaError PreparePinsForStart(PaProcessThreadInfo* pInfo)
-{
- PaError result = paNoError;
- /* Submit buffers */
- if (pInfo->stream->capture.pPin)
- {
- if ((result = PreparePinForStart(pInfo->stream->capture.pPin)) != paNoError)
- {
- goto error;
- }
-
- if (pInfo->stream->capture.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
- {
- unsigned i;
- for(i=0; i < pInfo->stream->capture.noOfPackets; ++i)
- {
- if ((result = PinRead(pInfo->stream->capture.pPin->handle, pInfo->stream->capture.packets + i)) != paNoError)
- {
- goto error;
- }
- ++pInfo->pending;
- }
- }
- else
- {
- pInfo->pending = 2;
- }
- }
-
- if(pInfo->stream->render.pPin)
- {
- if ((result = PreparePinForStart(pInfo->stream->render.pPin)) != paNoError)
- {
- goto error;
- }
-
- pInfo->priming += pInfo->stream->render.noOfPackets;
- ++pInfo->pending;
- SetEvent(pInfo->stream->render.events[0]);
- if (pInfo->stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
- {
- unsigned i;
- for(i=1; i < pInfo->stream->render.noOfPackets; ++i)
- {
- SetEvent(pInfo->stream->render.events[i]);
- ++pInfo->pending;
- }
- }
- }
-
-error:
- PA_DEBUG(("PreparePinsForStart = %d\n", result));
- return result;
-}
-
-static PaError StartPin(PaWinWdmPin* pin)
-{
- return PinSetState(pin, KSSTATE_RUN);
-}
-
-static PaError StartPins(PaProcessThreadInfo* pInfo)
-{
- PaError result = paNoError;
- /* Start the pins as synced as possible */
- if (pInfo->stream->capture.pPin)
- {
- result = StartPin(pInfo->stream->capture.pPin);
- }
- if(pInfo->stream->render.pPin)
- {
- result = StartPin(pInfo->stream->render.pPin);
- }
- PA_DEBUG(("StartPins = %d\n", result));
- return result;
-}
-
-
-static PaError StopPin(PaWinWdmPin* pin)
-{
- PinSetState(pin, KSSTATE_PAUSE);
- PinSetState(pin, KSSTATE_STOP);
- return paNoError;
-}
-
-
-static PaError StopPins(PaProcessThreadInfo* pInfo)
-{
- PaError result = paNoError;
- if(pInfo->stream->render.pPin)
- {
- StopPin(pInfo->stream->render.pPin);
- }
- if(pInfo->stream->capture.pPin)
- {
- StopPin(pInfo->stream->capture.pPin);
- }
- return result;
-}
-
-typedef void (*TSetInputFrameCount)(PaUtilBufferProcessor*, unsigned long);
-typedef void (*TSetInputChannel)(PaUtilBufferProcessor*, unsigned int, void *, unsigned int);
-static const TSetInputFrameCount fnSetInputFrameCount[2] = { PaUtil_SetInputFrameCount, PaUtil_Set2ndInputFrameCount };
-static const TSetInputChannel fnSetInputChannel[2] = { PaUtil_SetInputChannel, PaUtil_Set2ndInputChannel };
-
-static PaError PaDoProcessing(PaProcessThreadInfo* pInfo)
-{
- PaError result = paNoError;
- int i, framesProcessed = 0, doChannelCopy = 0;
- ring_buffer_size_t inputFramesAvailable = PaUtil_GetRingBufferReadAvailable(&pInfo->stream->ringBuffer);
-
- /* Do necessary buffer processing (which will invoke user callback if necessary) */
- if (pInfo->cbResult == paContinue &&
- (pInfo->renderHead != pInfo->renderTail || inputFramesAvailable))
- {
- unsigned processFullDuplex = pInfo->stream->capture.pPin && pInfo->stream->render.pPin && (!pInfo->priming);
-
- PA_HP_TRACE((pInfo->stream->hLog, "DoProcessing: InputFrames=%u", inputFramesAvailable));
-
- PaUtil_BeginCpuLoadMeasurement( &pInfo->stream->cpuLoadMeasurer );
-
- pInfo->ti.currentTime = PaUtil_GetTime();
-
- PaUtil_BeginBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->ti, pInfo->underover);
- pInfo->underover = 0; /* Reset the (under|over)flow status */
-
- if (pInfo->renderTail != pInfo->renderHead)
- {
- DATAPACKET* packet = pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet;
-
- assert(packet != 0);
- assert(packet->Header.Data != 0);
-
- PaUtil_SetOutputFrameCount(&pInfo->stream->bufferProcessor, pInfo->stream->render.framesPerBuffer);
-
- for(i=0;i<pInfo->stream->userOutputChannels;i++)
- {
- /* Only write the user output channels. Leave the rest blank */
- PaUtil_SetOutputChannel(&pInfo->stream->bufferProcessor,
- i,
- ((unsigned char*)(packet->Header.Data))+(i*pInfo->stream->render.bytesPerSample),
- pInfo->stream->deviceOutputChannels);
- }
-
- /* We will do a copy to the other channels after the data has been written */
- doChannelCopy = ( pInfo->stream->userOutputChannels == 1 );
- }
-
- if (inputFramesAvailable && (!pInfo->stream->userOutputChannels || inputFramesAvailable >= (int)pInfo->stream->render.framesPerBuffer))
- {
- unsigned wrapCntr = 0;
- void* data[2] = {0};
- ring_buffer_size_t size[2] = {0};
-
- /* If full-duplex, we just extract output buffer number of frames */
- if (pInfo->stream->userOutputChannels)
- {
- inputFramesAvailable = min(inputFramesAvailable, (int)pInfo->stream->render.framesPerBuffer);
- }
-
- inputFramesAvailable = PaUtil_GetRingBufferReadRegions(&pInfo->stream->ringBuffer,
- inputFramesAvailable,
- &data[0],
- &size[0],
- &data[1],
- &size[1]);
-
- for (wrapCntr = 0; wrapCntr < 2; ++wrapCntr)
- {
- if (size[wrapCntr] == 0)
- break;
-
- fnSetInputFrameCount[wrapCntr](&pInfo->stream->bufferProcessor, size[wrapCntr]);
- for(i=0;i<pInfo->stream->userInputChannels;i++)
- {
- /* Only read as many channels as the user wants */
- fnSetInputChannel[wrapCntr](&pInfo->stream->bufferProcessor,
- i,
- ((unsigned char*)(data[wrapCntr]))+(i*pInfo->stream->capture.bytesPerSample),
- pInfo->stream->deviceInputChannels);
- }
- }
- }
- else
- {
- /* We haven't consumed anything from the ring buffer... */
- inputFramesAvailable = 0;
- /* If we have full-duplex, this is at startup, so mark no-input! */
- if (pInfo->stream->userOutputChannels>0 && pInfo->stream->userInputChannels>0)
- {
- PA_HP_TRACE((pInfo->stream->hLog, "Input startup, marking no input."));
- PaUtil_SetNoInput(&pInfo->stream->bufferProcessor);
- }
- }
-
- if (processFullDuplex) /* full duplex */
- {
- /* Only call the EndBufferProcessing function when the total input frames == total output frames */
- const unsigned long totalInputFrameCount = pInfo->stream->bufferProcessor.hostInputFrameCount[0] + pInfo->stream->bufferProcessor.hostInputFrameCount[1];
- const unsigned long totalOutputFrameCount = pInfo->stream->bufferProcessor.hostOutputFrameCount[0] + pInfo->stream->bufferProcessor.hostOutputFrameCount[1];
-
- if(totalInputFrameCount == totalOutputFrameCount && totalOutputFrameCount != 0)
- {
- framesProcessed = PaUtil_EndBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->cbResult);
- }
- else
- {
- framesProcessed = 0;
- }
- }
- else
- {
- framesProcessed = PaUtil_EndBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->cbResult);
- }
-
- PA_HP_TRACE((pInfo->stream->hLog, "Frames processed: %u %s", framesProcessed, (pInfo->priming ? "(priming)":"")));
-
- if( doChannelCopy )
- {
- DATAPACKET* packet = pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet;
- /* Copy the first output channel to the other channels */
- switch (pInfo->stream->render.bytesPerSample)
- {
- case 2:
- DuplicateFirstChannelInt16(packet->Header.Data, pInfo->stream->deviceOutputChannels, pInfo->stream->render.framesPerBuffer);
- break;
- case 3:
- DuplicateFirstChannelInt24(packet->Header.Data, pInfo->stream->deviceOutputChannels, pInfo->stream->render.framesPerBuffer);
- break;
- case 4:
- DuplicateFirstChannelInt32(packet->Header.Data, pInfo->stream->deviceOutputChannels, pInfo->stream->render.framesPerBuffer);
- break;
- default:
- assert(0); /* Unsupported format! */
- break;
- }
- }
- PaUtil_EndCpuLoadMeasurement( &pInfo->stream->cpuLoadMeasurer, framesProcessed );
-
- if (inputFramesAvailable)
- {
- PaUtil_AdvanceRingBufferReadIndex(&pInfo->stream->ringBuffer, inputFramesAvailable);
- }
-
- if (pInfo->renderTail != pInfo->renderHead)
- {
- if (!pInfo->stream->streamStop)
- {
- result = pInfo->stream->render.pPin->fnSubmitHandler(pInfo, pInfo->renderTail);
- if (result != paNoError)
- {
- PA_HP_TRACE((pInfo->stream->hLog, "Capture submit handler failed with result %d", result));
- return result;
- }
- }
- pInfo->renderTail++;
- if (!pInfo->pinsStarted && pInfo->priming == 0)
- {
- /* We start the pins here to allow "prime time" */
- if ((result = StartPins(pInfo)) == paNoError)
- {
- PA_HP_TRACE((pInfo->stream->hLog, "Starting pins!"));
- pInfo->pinsStarted = 1;
- }
- }
- }
- }
-
- return result;
-}
-
-static VOID CALLBACK TimerAPCWaveRTPolledMode(
- LPVOID lpArgToCompletionRoutine,
- DWORD dwTimerLowValue,
- DWORD dwTimerHighValue)
-{
- HANDLE* pHandles = (HANDLE*)lpArgToCompletionRoutine;
- if (pHandles[0]) SetEvent(pHandles[0]);
- if (pHandles[1]) SetEvent(pHandles[1]);
-}
-
-static DWORD GetCurrentTimeInMillisecs()
-{
- return timeGetTime();
-}
-
-PA_THREAD_FUNC ProcessingThread(void* pParam)
-{
- PaError result = paNoError;
- HANDLE hAVRT = NULL;
- HANDLE hTimer = NULL;
- HANDLE *handleArray = NULL;
- HANDLE timerEventHandles[2] = {0};
- unsigned noOfHandles = 0;
- unsigned captureEvents = 0;
- unsigned renderEvents = 0;
- unsigned timerPeriod = 0;
- DWORD timeStamp[2] = {0};
-
- PaProcessThreadInfo info;
- memset(&info, 0, sizeof(PaProcessThreadInfo));
- info.stream = (PaWinWdmStream*)pParam;
-
- info.stream->threadResult = paNoError;
-
- PA_LOGE_;
-
- info.ti.inputBufferAdcTime = 0.0;
- info.ti.currentTime = 0.0;
- info.ti.outputBufferDacTime = 0.0;
-
- PA_DEBUG(("In buffer len: %.3f ms\n",(2000*info.stream->capture.framesPerBuffer) / info.stream->streamRepresentation.streamInfo.sampleRate));
- PA_DEBUG(("Out buffer len: %.3f ms\n",(2000*info.stream->render.framesPerBuffer) / info.stream->streamRepresentation.streamInfo.sampleRate));
- info.timeout = (DWORD)max(
- (2000*info.stream->render.framesPerBuffer/info.stream->streamRepresentation.streamInfo.sampleRate + 0.5),
- (2000*info.stream->capture.framesPerBuffer/info.stream->streamRepresentation.streamInfo.sampleRate + 0.5));
- info.timeout = max(info.timeout*8, 100);
- timerPeriod = info.timeout;
- PA_DEBUG(("Timeout = %ld ms\n",info.timeout));
-
- /* Allocate handle array */
- handleArray = (HANDLE*)PaUtil_AllocateMemory((info.stream->capture.noOfPackets + info.stream->render.noOfPackets + 1) * sizeof(HANDLE));
-
- /* Setup handle array for WFMO */
- if (info.stream->capture.pPin != 0)
- {
- handleArray[noOfHandles++] = info.stream->capture.events[0];
- if (info.stream->capture.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
- {
- unsigned i;
- for(i=1; i < info.stream->capture.noOfPackets; ++i)
- {
- handleArray[noOfHandles++] = info.stream->capture.events[i];
- }
- }
- captureEvents = noOfHandles;
- renderEvents = noOfHandles;
- }
-
- if (info.stream->render.pPin != 0)
- {
- handleArray[noOfHandles++] = info.stream->render.events[0];
- if (info.stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
- {
- unsigned i;
- for(i=1; i < info.stream->render.noOfPackets; ++i)
- {
- handleArray[noOfHandles++] = info.stream->render.events[i];
- }
- }
- renderEvents = noOfHandles;
- }
- handleArray[noOfHandles++] = info.stream->eventAbort;
- assert(noOfHandles <= (info.stream->capture.noOfPackets + info.stream->render.noOfPackets + 1));
-
- /* Prepare render and capture pins */
- if ((result = PreparePinsForStart(&info)) != paNoError)
- {
- PA_DEBUG(("Failed to prepare device(s)!\n"));
- goto error;
- }
-
- /* Init high speed logger */
- if (PaUtil_InitializeHighSpeedLog(&info.stream->hLog, 1000000) != paNoError)
- {
- PA_DEBUG(("Failed to init high speed logger!\n"));
- goto error;
- }
-
- /* Heighten priority here */
- hAVRT = BumpThreadPriority();
-
- /* If input only, we start the pins immediately */
- if (info.stream->render.pPin == 0)
- {
- if ((result = StartPins(&info)) != paNoError)
- {
- PA_DEBUG(("Failed to start device(s)!\n"));
- goto error;
- }
- info.pinsStarted = 1;
- }
-
- /* Handle WaveRT polled mode */
- {
- const unsigned fs = (unsigned)info.stream->streamRepresentation.streamInfo.sampleRate;
- if (info.stream->capture.pPin != 0 && info.stream->capture.pPin->pinKsSubType == SubType_kPolled)
- {
- timerEventHandles[0] = info.stream->capture.events[0];
- timerPeriod = min(timerPeriod, (1000*info.stream->capture.framesPerBuffer)/fs);
- }
-
- if (info.stream->render.pPin != 0 && info.stream->render.pPin->pinKsSubType == SubType_kPolled)
- {
- timerEventHandles[1] = info.stream->render.events[0];
- timerPeriod = min(timerPeriod, (1000*info.stream->render.framesPerBuffer)/fs);
- }
-
- if (timerEventHandles[0] || timerEventHandles[1])
- {
- LARGE_INTEGER dueTime = {0};
-
- timerPeriod=max(timerPeriod/5,1);
- PA_DEBUG(("Timer event handles=0x%04X,0x%04X period=%u ms", timerEventHandles[0], timerEventHandles[1], timerPeriod));
- hTimer = CreateWaitableTimer(0, FALSE, NULL);
- if (hTimer == NULL)
- {
- result = paUnanticipatedHostError;
- goto error;
- }
- /* invoke first timeout immediately */
- if (!SetWaitableTimer(hTimer, &dueTime, timerPeriod, TimerAPCWaveRTPolledMode, timerEventHandles, FALSE))
- {
- result = paUnanticipatedHostError;
- goto error;
- }
- PA_DEBUG(("Waitable timer started, period = %u ms\n", timerPeriod));
- }
- }
-
- /* Mark stream as active */
- info.stream->streamActive = 1;
- info.stream->threadResult = paNoError;
-
- /* Up and running... */
- SetEvent(info.stream->eventStreamStart[StreamStart_kOk]);
-
- /* Take timestamp here */
- timeStamp[0] = timeStamp[1] = GetCurrentTimeInMillisecs();
-
- while(!info.stream->streamAbort)
- {
- unsigned doProcessing = 1;
- unsigned wait = WaitForMultipleObjects(noOfHandles, handleArray, FALSE, 0);
- unsigned eventSignalled = wait - WAIT_OBJECT_0;
- DWORD dwCurrentTime = 0;
-
- if (wait == WAIT_FAILED)
- {
- PA_DEBUG(("Wait failed = %ld! \n",wait));
- break;
- }
- if (wait == WAIT_TIMEOUT)
- {
- wait = WaitForMultipleObjectsEx(noOfHandles, handleArray, FALSE, 50, TRUE);
- eventSignalled = wait - WAIT_OBJECT_0;
- }
- else
- {
- if (eventSignalled < captureEvents)
- {
- if (PaUtil_GetRingBufferWriteAvailable(&info.stream->ringBuffer) == 0)
- {
- PA_HP_TRACE((info.stream->hLog, "!!!!! Input overflow !!!!!"));
- info.underover |= paInputOverflow;
- }
- }
- else if (eventSignalled < renderEvents)
- {
- if (!info.priming && info.renderHead - info.renderTail > 1)
- {
- PA_HP_TRACE((info.stream->hLog, "!!!!! Output underflow !!!!!"));
- info.underover |= paOutputUnderflow;
- }
- }
- }
-
- /* Get event time */
- dwCurrentTime = GetCurrentTimeInMillisecs();
-
- /* 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_DEBUG(("Timeout for capture device (%u ms)!", info.timeout, (dwCurrentTime - timeStamp[0])));
- result = paTimedOut;
- break;
- }
- if (info.stream->render.pPin && (dwCurrentTime - timeStamp[1]) >= info.timeout)
- {
- PA_DEBUG(("Timeout for render device (%u ms)!", info.timeout, (dwCurrentTime - timeStamp[1])));
- result = paTimedOut;
- break;
- }
-
- if (wait == WAIT_IO_COMPLETION)
- {
- /* Waitable timer has fired! */
- PA_HP_TRACE((info.stream->hLog, "WAIT_IO_COMPLETION"));
- continue;
- }
-
- if (wait == WAIT_TIMEOUT)
- {
- continue;
- }
- else
- {
- if (eventSignalled < captureEvents)
- {
- if (info.stream->capture.pPin->fnEventHandler(&info, eventSignalled) == paNoError)
- {
- timeStamp[0] = dwCurrentTime;
-
- /* Since we use the ring buffer, we can submit the buffers directly */
- if (!info.stream->streamStop)
- {
- result = info.stream->capture.pPin->fnSubmitHandler(&info, info.captureTail);
- if (result != paNoError)
- {
- PA_HP_TRACE((info.stream->hLog, "Capture submit handler failed with result %d", result));
- break;
- }
- }
- ++info.captureTail;
- /* If full-duplex, let _only_ render event trigger processing. We still need the stream stop
- handling working, so let that be processed anyways... */
- if (info.stream->userOutputChannels > 0)
- {
- doProcessing = 0;
- }
- }
- }
- else if (eventSignalled < renderEvents)
- {
- timeStamp[1] = dwCurrentTime;
- eventSignalled -= captureEvents;
- info.stream->render.pPin->fnEventHandler(&info, eventSignalled);
- }
- else
- {
- assert(info.stream->streamAbort);
- PA_HP_TRACE((info.stream->hLog, "Stream abort!"));
- continue;
- }
- }
-
- /* Handle processing */
- if (doProcessing)
- {
- result = PaDoProcessing(&info);
- if (result != paNoError)
- {
- PA_HP_TRACE((info.stream->hLog, "PaDoProcessing failed!"));
- break;
- }
- }
-
- if(info.stream->streamStop && info.cbResult != paComplete)
- {
- PA_HP_TRACE((info.stream->hLog, "Stream stop! pending=%d",info.pending));
- info.cbResult = paComplete; /* Stop, but play remaining buffers */
- }
-
- if(info.pending<=0)
- {
- PA_HP_TRACE((info.stream->hLog, "pending==0 finished..."));
- break;
- }
- if((!info.stream->render.pPin)&&(info.cbResult!=paContinue))
- {
- PA_HP_TRACE((info.stream->hLog, "record only cbResult=%d...",info.cbResult));
- break;
- }
- }
-
- PA_DEBUG(("Finished processing loop\n"));
-
- info.stream->threadResult = result;
- goto bailout;
-
-error:
- PA_DEBUG(("Error starting processing thread\n"));
- /* Set the "error" event together with result */
- info.stream->threadResult = result;
- SetEvent(info.stream->eventStreamStart[StreamStart_kFailed]);
-
-bailout:
- if (hTimer)
- {
- PA_DEBUG(("Waitable timer stopped\n", timerPeriod));
- CancelWaitableTimer(hTimer);
- CloseHandle(hTimer);
- hTimer = 0;
- }
-
- if (info.pinsStarted)
- {
- StopPins(&info);
- }
-
- /* Lower prio here */
- DropThreadPriority(hAVRT);
-
- if (handleArray != NULL)
- {
- PaUtil_FreeMemory(handleArray);
- }
-
-#if PA_TRACE_REALTIME_EVENTS
- if (info.stream->hLog)
- {
- PA_DEBUG(("Dumping highspeed trace...\n"));
- PaUtil_DumpHighSpeedLog(info.stream->hLog, "hp_trace.log");
- PaUtil_DiscardHighSpeedLog(info.stream->hLog);
- info.stream->hLog = 0;
- }
-#endif
- info.stream->streamActive = 0;
-
- if((!info.stream->streamStop)&&(!info.stream->streamAbort))
- {
- /* Invoke the user stream finished callback */
- /* Only do it from here if not being stopped/aborted by user */
- if( info.stream->streamRepresentation.streamFinishedCallback != 0 )
- info.stream->streamRepresentation.streamFinishedCallback( info.stream->streamRepresentation.userData );
- }
- info.stream->streamStop = 0;
- info.stream->streamAbort = 0;
-
- PA_LOGL_;
- return 0;
-}
-
-
-static PaError StartStream( PaStream *s )
-{
- PaError result = paNoError;
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
-
- PA_LOGE_;
-
- if (stream->streamThread != NULL)
- {
- return paStreamIsNotStopped;
- }
-
- stream->streamStop = 0;
- stream->streamAbort = 0;
-
- ResetStreamEvents(stream);
-
- PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
-
- stream->oldProcessPriority = GetPriorityClass(GetCurrentProcess());
- /* Uncomment the following line to enable dynamic boosting of the process
- * priority to real time for best low latency support
- * Disabled by default because RT processes can easily block the OS */
- /*ret = SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS);
- PA_DEBUG(("Class ret = %d;",ret));*/
-
- stream->streamThread = CREATE_THREAD_FUNCTION (NULL, 0, ProcessingThread, stream, CREATE_SUSPENDED, NULL);
- if(stream->streamThread == NULL)
- {
- result = paInsufficientMemory;
- goto end;
- }
- ResumeThread(stream->streamThread);
-
- switch (WaitForMultipleObjects(2, stream->eventStreamStart, FALSE, 5000))
- {
- case WAIT_OBJECT_0 + StreamStart_kOk:
- PA_DEBUG(("Processing thread started!\n"));
- result = paNoError;
- /* streamActive is set in processing thread */
- stream->streamStarted = 1;
- break;
- case WAIT_OBJECT_0 + StreamStart_kFailed:
- PA_DEBUG(("Processing thread start failed! (result=%d)\n", stream->threadResult));
- result = stream->threadResult;
- /* Wait for the stream to really exit */
- WaitForSingleObject(stream->streamThread, 200);
- CloseHandle(stream->streamThread);
- stream->streamThread = 0;
- break;
- case WAIT_TIMEOUT:
- default:
- result = paTimedOut;
- PaWinWDM_SetLastErrorInfo(result, "Failed to start processing thread (timeout)!");
- break;
- }
-
-end:
- PA_LOGL_;
- return result;
-}
-
-
-static PaError StopStream( PaStream *s )
-{
- PaError result = paNoError;
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
- BOOL doCb = FALSE;
-
- PA_LOGE_;
-
- if(stream->streamActive)
- {
- DWORD dwExitCode;
- doCb = TRUE;
- stream->streamStop = 1;
- if (GetExitCodeThread(stream->streamThread, &dwExitCode) && dwExitCode == STILL_ACTIVE)
- {
- if (WaitForSingleObject(stream->streamThread, INFINITE) != WAIT_OBJECT_0)
- {
- PA_DEBUG(("StopStream: stream thread terminated\n"));
- TerminateThread(stream->streamThread, -1);
- result = paTimedOut;
- }
- }
- else
- {
- PA_DEBUG(("StopStream: GECT says not active, but streamActive is not false ??"));
- result = paUnanticipatedHostError;
- PaWinWDM_SetLastErrorInfo(result, "StopStream: GECT says not active, but streamActive = %d", stream->streamActive);
- }
- }
- else
- {
- if (stream->threadResult != paNoError)
- {
- PA_DEBUG(("StopStream: Stream not active (%d)\n", stream->threadResult));
- result = stream->threadResult;
- stream->threadResult = paNoError;
- }
- }
-
- if (stream->streamThread != NULL)
- {
- CloseHandle(stream->streamThread);
- stream->streamThread = 0;
- }
- stream->streamStarted = 0;
- stream->streamActive = 0;
-
- if(doCb)
- {
- /* Do user callback now after all state has been reset */
- /* This means it should be safe for the called function */
- /* to invoke e.g. StartStream */
- if( stream->streamRepresentation.streamFinishedCallback != 0 )
- stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
- }
-
- PA_LOGL_;
- return result;
-}
-
-static PaError AbortStream( PaStream *s )
-{
- PaError result = paNoError;
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
- int doCb = 0;
-
- PA_LOGE_;
-
- if(stream->streamActive)
- {
- doCb = 1;
- stream->streamAbort = 1;
- SetEvent(stream->eventAbort); /* Signal immediately */
- if (WaitForSingleObject(stream->streamThread, 10000) != WAIT_OBJECT_0)
- {
- TerminateThread(stream->streamThread, -1);
- result = paTimedOut;
-
- PA_DEBUG(("AbortStream: stream thread terminated\n"));
- }
- assert(!stream->streamActive);
- }
- CloseHandle(stream->streamThread);
- stream->streamThread = NULL;
- stream->streamStarted = 0;
-
- if(doCb)
- {
- /* Do user callback now after all state has been reset */
- /* This means it should be safe for the called function */
- /* to invoke e.g. StartStream */
- if( stream->streamRepresentation.streamFinishedCallback != 0 )
- stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
- }
-
- stream->streamActive = 0;
- stream->streamStarted = 0;
-
- PA_LOGL_;
- return result;
-}
-
-
-static PaError IsStreamStopped( PaStream *s )
-{
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
- int result = 0;
-
- PA_LOGE_;
-
- if(!stream->streamStarted)
- result = 1;
-
- PA_LOGL_;
- return result;
-}
-
-
-static PaError IsStreamActive( PaStream *s )
-{
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
- int result = 0;
-
- PA_LOGE_;
-
- if(stream->streamActive)
- result = 1;
-
- PA_LOGL_;
- return result;
-}
-
-
-static PaTime GetStreamTime( PaStream* s )
-{
- PA_LOGE_;
- PA_LOGL_;
- (void)s;
- return PaUtil_GetTime();
-}
-
-
-static double GetStreamCpuLoad( PaStream* s )
-{
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
- double result;
- PA_LOGE_;
- result = PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
- PA_LOGL_;
- return result;
-}
-
-
-/*
-As separate stream interfaces are used for blocking and callback
-streams, the following functions can be guaranteed to only be called
-for blocking streams.
-*/
-
-static PaError ReadStream( PaStream* s,
- void *buffer,
- unsigned long frames )
-{
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
-
- PA_LOGE_;
-
- /* suppress unused variable warnings */
- (void) buffer;
- (void) frames;
- (void) stream;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
- PA_LOGL_;
- return paInternalError;
-}
-
-
-static PaError WriteStream( PaStream* s,
- const void *buffer,
- unsigned long frames )
-{
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
-
- PA_LOGE_;
-
- /* suppress unused variable warnings */
- (void) buffer;
- (void) frames;
- (void) stream;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
- PA_LOGL_;
- return paInternalError;
-}
-
-
-static signed long GetStreamReadAvailable( PaStream* s )
-{
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
-
- PA_LOGE_;
-
- /* suppress unused variable warnings */
- (void) stream;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
- PA_LOGL_;
- return 0;
-}
-
-
-static signed long GetStreamWriteAvailable( PaStream* s )
-{
- PaWinWdmStream *stream = (PaWinWdmStream*)s;
-
- PA_LOGE_;
- /* suppress unused variable warnings */
- (void) stream;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
- PA_LOGL_;
- return 0;
-}
-
-/***************************************************************************************/
-/* Event and submit handlers for WaveCyclic */
-/***************************************************************************************/
-
-static PaError PaPinCaptureEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex)
-{
- PaError result = paNoError;
- ring_buffer_size_t frameCount;
- DATAPACKET* packet = pInfo->stream->capture.packets + eventIndex;
-
- assert( eventIndex < pInfo->stream->capture.noOfPackets );
-
- if (packet->Header.DataUsed == 0)
- {
- 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
- on startup of streaming, where it erroneously sets the event without the corresponding buffer being filled (DataUsed == 0) */
- ResetEvent(packet->Signal.hEvent);
-
- result = -1; /* Only need this to be NOT paNoError */
- }
- else
- {
- pInfo->capturePackets[pInfo->captureHead & cPacketsArrayMask].packet = packet;
-
- frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer, packet->Header.Data, pInfo->stream->capture.framesPerBuffer);
-
- PA_HP_TRACE((pInfo->stream->hLog, ">>> Capture event: idx=%u (frames=%u)", eventIndex, frameCount));
- ++pInfo->captureHead;
- }
-
- --pInfo->pending; /* This needs to be done in either case */
- return result;
-}
-
-static PaError PaPinCaptureSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex)
-{
- PaError result = paNoError;
- DATAPACKET* packet = pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet;
- pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet = 0;
- 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;
- return result;
-}
-
-static PaError PaPinRenderEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex)
-{
- assert( eventIndex < pInfo->stream->render.noOfPackets );
-
- pInfo->renderPackets[pInfo->renderHead & cPacketsArrayMask].packet = pInfo->stream->render.packets + eventIndex;
- PA_HP_TRACE((pInfo->stream->hLog, "<<< Render event : idx=%u head=%u", eventIndex, pInfo->renderHead));
- ++pInfo->renderHead;
- --pInfo->pending;
- return paNoError;
-}
-
-static PaError PaPinRenderSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex)
-{
- PaError result = paNoError;
- DATAPACKET* packet = pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet;
- pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet = 0;
- assert(packet != 0);
-
- PA_HP_TRACE((pInfo->stream->hLog, "Render submit : %u idx=%u", pInfo->renderTail, (unsigned)(packet - pInfo->stream->render.packets)));
- ResetEvent(packet->Signal.hEvent);
- result = PinWrite(pInfo->stream->render.pPin->handle, packet);
- /* Reset event, just in case we have an analogous situation to capture (see PaPinCaptureSubmitHandler_WaveCyclic) */
- ++pInfo->pending;
- if (pInfo->priming)
- {
- --pInfo->priming;
- }
- return result;
-}
-
-/***************************************************************************************/
-/* Event and submit handlers for WaveRT */
-/***************************************************************************************/
-
-static PaError PaPinCaptureEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex)
-{
- unsigned long pos;
- unsigned realInBuf;
- unsigned frameCount;
- PaWinWdmIOInfo* pCapture = &pInfo->stream->capture;
- const unsigned halfInputBuffer = pCapture->hostBufferSize >> 1;
- PaWinWdmPin* pin = pCapture->pPin;
- DATAPACKET* packet = 0;
-
- /* Get hold of current ADC position */
- pin->fnAudioPosition(pin, &pos);
- /* Wrap it (robi: why not use hw latency compensation here ?? because pos then gets _way_ off from
- where it should be, i.e. at beginning or half buffer position. Why? No idea.) */
-
- pos %= pCapture->hostBufferSize;
- /* Then realInBuf will point to "other" half of double buffer */
- realInBuf = pos < halfInputBuffer ? 1U : 0U;
-
- packet = pInfo->stream->capture.packets + realInBuf;
-
- /* Call barrier (or dummy) */
- pin->fnMemBarrier();
-
- /* Put it in queue */
- frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer, packet->Header.Data, pCapture->framesPerBuffer);
-
- pInfo->capturePackets[pInfo->captureHead & cPacketsArrayMask].packet = packet;
-
- PA_HP_TRACE((pInfo->stream->hLog, "Capture event (WaveRT): idx=%u head=%u (pos = %4.1lf%%, frames=%u)", realInBuf, pInfo->captureHead, (pos * 100.0 / pCapture->hostBufferSize), frameCount));
-
- ++pInfo->captureHead;
- --pInfo->pending;
-
- return paNoError;
-}
-
-static PaError PaPinCaptureEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex)
-{
- unsigned long pos;
- unsigned bytesToRead;
- PaWinWdmIOInfo* pCapture = &pInfo->stream->capture;
- const unsigned halfInputBuffer = pCapture->hostBufferSize>>1;
- PaWinWdmPin* pin = pInfo->stream->capture.pPin;
-
- /* Get hold of current ADC position */
- pin->fnAudioPosition(pin, &pos);
- /* Wrap it (robi: why not use hw latency compensation here ?? because pos then gets _way_ off from
- where it should be, i.e. at beginning or half buffer position. Why? No idea.) */
- /* Compensate for HW FIFO to get to last read buffer position */
- pos += pin->hwLatency;
- pos %= pCapture->hostBufferSize;
- /* Need to align position on frame boundary */
- pos &= ~(pCapture->bytesPerFrame - 1);
-
- /* Call barrier (or dummy) */
- pin->fnMemBarrier();
-
- /* Put it in "queue" */
- bytesToRead = (pCapture->hostBufferSize + pos - pCapture->lastPosition) % pCapture->hostBufferSize;
- if (bytesToRead > 0)
- {
- unsigned frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer,
- pCapture->hostBuffer + pCapture->lastPosition,
- bytesToRead / pCapture->bytesPerFrame);
-
- pCapture->lastPosition = (pCapture->lastPosition + frameCount * pCapture->bytesPerFrame) % pCapture->hostBufferSize;
-
- PA_HP_TRACE((pInfo->stream->hLog, "Capture event (WaveRTPolled): pos = %4.1lf%%, framesRead=%u", (pos * 100.0 / pCapture->hostBufferSize), frameCount));
- ++pInfo->captureHead;
- --pInfo->pending;
- }
- return paNoError;
-}
-
-static PaError PaPinCaptureSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex)
-{
- pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet = 0;
- ++pInfo->pending;
- return paNoError;
-}
-
-static PaError PaPinCaptureSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex)
-{
- pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet = 0;
- ++pInfo->pending;
- return paNoError;
-}
-
-static PaError PaPinRenderEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex)
-{
- unsigned long pos;
- unsigned realOutBuf;
- PaWinWdmIOInfo* pRender = &pInfo->stream->render;
- const unsigned halfOutputBuffer = pRender->hostBufferSize >> 1;
- PaWinWdmPin* pin = pInfo->stream->render.pPin;
- PaIOPacket* ioPacket = &pInfo->renderPackets[pInfo->renderHead & cPacketsArrayMask];
-
- /* Get hold of current DAC position */
- pin->fnAudioPosition(pin, &pos);
- /* Compensate for HW FIFO to get to last read buffer position */
- pos += pin->hwLatency;
- /* Wrap it */
- pos %= pRender->hostBufferSize;
- /* And align it, not sure its really needed though */
- pos &= ~(pRender->bytesPerFrame - 1);
- /* Then realOutBuf will point to "other" half of double buffer */
- realOutBuf = pos < halfOutputBuffer ? 1U : 0U;
-
- if (pInfo->priming)
- {
- realOutBuf = pInfo->renderHead & 0x1;
- }
- ioPacket->packet = pInfo->stream->render.packets + realOutBuf;
- ioPacket->startByte = realOutBuf * halfOutputBuffer;
- ioPacket->lengthBytes = halfOutputBuffer;
-
- PA_HP_TRACE((pInfo->stream->hLog, "Render event (WaveRT) : idx=%u head=%u (pos = %4.1lf%%)", realOutBuf, pInfo->renderHead, (pos * 100.0 / pRender->hostBufferSize) ));
-
- ++pInfo->renderHead;
- --pInfo->pending;
- return paNoError;
-}
-
-static PaError PaPinRenderEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex)
-{
- unsigned long pos;
- unsigned realOutBuf;
- unsigned bytesToWrite;
-
- PaWinWdmIOInfo* pRender = &pInfo->stream->render;
- const unsigned halfOutputBuffer = pRender->hostBufferSize >> 1;
- PaWinWdmPin* pin = pInfo->stream->render.pPin;
- PaIOPacket* ioPacket = &pInfo->renderPackets[pInfo->renderHead & cPacketsArrayMask];
-
- /* Get hold of current DAC position */
- pin->fnAudioPosition(pin, &pos);
- /* Compensate for HW FIFO to get to last read buffer position */
- pos += pin->hwLatency;
- /* Wrap it */
- pos %= pRender->hostBufferSize;
- /* And align it, not sure its really needed though */
- pos &= ~(pRender->bytesPerFrame - 1);
-
- if (pInfo->priming)
- {
- realOutBuf = pInfo->renderHead & 0x1;
- ioPacket->packet = pInfo->stream->render.packets + realOutBuf;
- ioPacket->startByte = realOutBuf * halfOutputBuffer;
- ioPacket->lengthBytes = halfOutputBuffer;
- ++pInfo->renderHead;
- --pInfo->pending;
- }
- else
- {
- bytesToWrite = (pRender->hostBufferSize + pos - pRender->lastPosition) % pRender->hostBufferSize;
- ++pRender->pollCntr;
- if (bytesToWrite >= halfOutputBuffer)
- {
- realOutBuf = (pos < halfOutputBuffer) ? 1U : 0U;
- ioPacket->packet = pInfo->stream->render.packets + realOutBuf;
- pRender->lastPosition = realOutBuf ? 0U : halfOutputBuffer;
- ioPacket->startByte = realOutBuf * halfOutputBuffer;
- ioPacket->lengthBytes = halfOutputBuffer;
- ++pInfo->renderHead;
- --pInfo->pending;
- PA_HP_TRACE((pInfo->stream->hLog, "Render event (WaveRTPolled) : idx=%u head=%u (pos = %4.1lf%%, cnt=%u)", realOutBuf, pInfo->renderHead, (pos * 100.0 / pRender->hostBufferSize), pRender->pollCntr));
- pRender->pollCntr = 0;
- }
- }
- return paNoError;
-}
-
-static PaError PaPinRenderSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex)
-{
- PaWinWdmPin* pin = pInfo->stream->render.pPin;
- pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet = 0;
- /* Call barrier (if needed) */
- pin->fnMemBarrier();
- PA_HP_TRACE((pInfo->stream->hLog, "Render submit (WaveRT) : submit=%u", pInfo->renderTail));
- ++pInfo->pending;
- if (pInfo->priming)
- {
- --pInfo->priming;
- if (pInfo->priming)
- {
- PA_HP_TRACE((pInfo->stream->hLog, "Setting WaveRT event for priming (2)"));
- SetEvent(pInfo->stream->render.events[0]);
- }
- }
- return paNoError;
-}
-
-static PaError PaPinRenderSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex)
-{
- PaWinWdmPin* pin = pInfo->stream->render.pPin;
- pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet = 0;
- /* Call barrier (if needed) */
- pin->fnMemBarrier();
- PA_HP_TRACE((pInfo->stream->hLog, "Render submit (WaveRTPolled) : submit=%u", pInfo->renderTail));
- ++pInfo->pending;
- if (pInfo->priming)
- {
- --pInfo->priming;
- if (pInfo->priming)
- {
- PA_HP_TRACE((pInfo->stream->hLog, "Setting WaveRT event for priming (2)"));
- SetEvent(pInfo->stream->render.events[0]);
- }
- }
- return paNoError;
-}
diff --git a/portaudio/src/hostapi/wdmks/readme.txt b/portaudio/src/hostapi/wdmks/readme.txt
deleted file mode 100644
index 611acc7..0000000
--- a/portaudio/src/hostapi/wdmks/readme.txt
+++ /dev/null
@@ -1,85 +0,0 @@
-Notes about WDM-KS host API
----------------------------
-
-Status history
---------------
-16th January 2011:
-Added support for WaveRT device API (Vista and later) for even lesser
-latency support.
-
-10th November 2005:
-Made following changes:
- * OpenStream: Try all PaSampleFormats internally if the the chosen
- format is not supported natively. This fixed several problems
- with soundcards that did not take kindly to using 24-bit 3-byte formats.
- * OpenStream: Make the minimum framesPerHostIBuffer (and framesPerHostOBuffer)
- the default frameSize for the playback/recording pin.
- * ProcessingThread: Added a switch to only call PaUtil_EndBufferProcessing
- if the total input frames equals the total output frames
-
-5th September 2004:
-This is the first public version of the code. It should be considered
-an alpha release with zero guarantee not to crash on any particular
-system. So far it has only been tested in the author's development
-environment, which means a Win2k/SP2 PIII laptop with integrated
-SoundMAX driver and USB Tascam US-428 compiled with both MinGW
-(GCC 3.3) and MSVC++6 using the MS DirectX 9 SDK.
-It has been most widely tested with the MinGW build, with most of the
-test programs (particularly paqa_devs and paqa_errs) passing.
-There are some notable failures: patest_out_underflow and both of the
-blocking I/O tests (as blocking I/O is not implemented).
-At this point the code needs to be tested with a much wider variety
-of configurations and feedback provided from testers regarding
-both working and failing cases.
-
-What is the WDM-KS host API?
-----------------------------
-PortAudio for Windows currently has 3 functional host implementations.
-MME uses the oldest Windows audio API which does not offer good
-play/record latency.
-DirectX improves this, but still imposes a penalty
-of 10s of milliseconds due to the system mixing of streams from
-multiple applications.
-ASIO offers very good latency, but requires special drivers which are
-not always available for cheaper audio hardware. Also, when ASIO
-drivers are available, they are not always so robust because they
-bypass all of the standardised Windows device driver architecture
-and hit the hardware their own way.
-Alternatively there are a couple of free (but closed source) ASIO
-implementations which connect to the lower level Windows
-"Kernel Streaming" API, but again these require special installation
-by the user, and can be limited in functionality or difficult to use.
-
-This is where the PortAudio "WDM-KS" host implementation comes in.
-It directly connects PortAudio to the same Kernel Streaming API which
-those ASIO bridges use. This avoids the mixing penalty of DirectX,
-giving at least as good latency as any ASIO driver, but it has the
-advantage of working with ANY Windows audio hardware which is available
-through the normal MME/DirectX routes without the user requiring
-any additional device drivers to be installed, and allowing all
-device selection to be done through the normal PortAudio API.
-
-Note that in general you should only be using this host API if your
-application has a real requirement for very low latency audio (<20ms),
-either because you are generating sounds in real-time based upon
-user input, or you a processing recorded audio in real time.
-
-The only thing to be aware of is that using the KS interface will
-block that device from being used by the rest of system through
-the higher level APIs, or conversely, if the system is using
-a device, the KS API will not be able to use it. MS recommend that
-you should keep the device open only when your application has focus.
-In PortAudio terms, this means having a stream Open on a WDMKS device.
-
-Usage
------
-To add the WDMKS backend to your program which is already using
-PortAudio, you must define PA_USE_WDMKS=1 in your build file,
-and include the pa_win_wdmks\pa_win_wdmks.c into your build.
-The file should compile in both C and C++.
-You will need a DirectX SDK installed on your system for the
-ks.h and ksmedia.h header files.
-You will need to link to the system "setupapi" library.
-Note that if you use MinGW, you will get more warnings from
-the DX header files when using GCC(C), and still a few warnings
-with G++(CPP).