OSDN Git Service

Merge UnkoTim215
[timidity41/timidity41.git] / portaudio / src / hostapi / wdmks / pa_win_wdmks.c
1 /*
2 * $Id$
3 * PortAudio Windows WDM-KS interface
4 *
5 * Author: Andrew Baldwin, Robert Bielik (WaveRT)
6 * Based on the Open Source API proposed by Ross Bencina
7 * Copyright (c) 1999-2004 Andrew Baldwin, Ross Bencina, Phil Burk
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining
10 * a copy of this software and associated documentation files
11 * (the "Software"), to deal in the Software without restriction,
12 * including without limitation the rights to use, copy, modify, merge,
13 * publish, distribute, sublicense, and/or sell copies of the Software,
14 * and to permit persons to whom the Software is furnished to do so,
15 * subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
24 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
25 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29 /*
30 * The text above constitutes the entire PortAudio license; however, 
31 * the PortAudio community also makes the following non-binding requests:
32 *
33 * Any person wishing to distribute modifications to the Software is
34 * requested to send the modifications to the original developer so that
35 * they can be incorporated into the canonical version. It is also 
36 * requested that these non-binding requests be included along with the 
37 * license above.
38 */
39
40 /** @file
41 @ingroup hostapi_src
42 @brief Portaudio WDM-KS host API.
43
44 @note This is the implementation of the Portaudio host API using the
45 Windows WDM/Kernel Streaming API in order to enable very low latency
46 playback and recording on all modern Windows platforms (e.g. 2K, XP, Vista, Win7)
47 Note: This API accesses the device drivers below the usual KMIXER
48 component which is normally used to enable multi-client mixing and
49 format conversion. That means that it will lock out all other users
50 of a device for the duration of active stream using those devices
51 */
52
53 #include <stdio.h>
54
55 #if (defined(_WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */
56 #pragma comment( lib, "setupapi.lib" )
57 #endif
58
59 /* Debugging/tracing support */
60
61 #define PA_LOGE_
62 #define PA_LOGL_
63
64 #ifdef __GNUC__
65 #include <initguid.h>
66 #define _WIN32_WINNT 0x0501
67 #define WINVER 0x0501
68 #endif
69
70 #include <stdlib.h>
71 #include <string.h> /* strlen() */
72 #include <assert.h>
73 #include <wchar.h>  /* iswspace() */
74
75 #include "pa_util.h"
76 #include "pa_allocation.h"
77 #include "pa_hostapi.h"
78 #include "pa_stream.h"
79 #include "pa_cpuload.h"
80 #include "pa_process.h"
81 #include "portaudio.h"
82 #include "pa_debugprint.h"
83 #include "pa_memorybarrier.h"
84 #include "pa_ringbuffer.h"
85 #include "pa_trace.h"
86 #include "pa_win_waveformat.h"
87
88 #include "pa_win_wdmks.h"
89
90 #ifndef DRV_QUERYDEVICEINTERFACE
91 #define DRV_QUERYDEVICEINTERFACE     (DRV_RESERVED + 12)
92 #endif
93 #ifndef DRV_QUERYDEVICEINTERFACESIZE
94 #define DRV_QUERYDEVICEINTERFACESIZE (DRV_RESERVED + 13)
95 #endif
96
97 #include <windows.h>
98 #include <mmsystem.h>
99 #ifndef __GNUC__ /* Fix for ticket #257: MinGW-w64: Inclusion of <winioctl.h> triggers multiple redefinition errors. */
100 #include <winioctl.h>
101 #endif
102 #include <process.h>
103
104 #include <math.h>
105
106 #ifdef _MSC_VER
107 #define snprintf _snprintf
108 #define vsnprintf _vsnprintf
109 #endif
110
111 /* The PA_HP_TRACE macro is used in RT parts, so it can be switched off without affecting
112 the rest of the debug tracing */
113 #if 1
114 #define PA_HP_TRACE(x)  PaUtil_AddHighSpeedLogMessage x ;
115 #else
116 #define PA_HP_TRACE(x)
117 #endif
118
119 /* A define that selects whether the resulting pin names are chosen from pin category
120 instead of the available pin names, who sometimes can be quite cheesy, like "Volume control".
121 Default is to use the pin category.
122 */
123 #ifndef PA_WDMKS_USE_CATEGORY_FOR_PIN_NAMES
124 #define PA_WDMKS_USE_CATEGORY_FOR_PIN_NAMES  1
125 #endif
126
127 #ifdef __GNUC__
128 #undef PA_LOGE_
129 #define PA_LOGE_ PA_DEBUG(("%s {\n",__FUNCTION__))
130 #undef PA_LOGL_
131 #define PA_LOGL_ PA_DEBUG(("} %s\n",__FUNCTION__))
132 /* These defines are set in order to allow the WIndows DirectX
133 * headers to compile with a GCC compiler such as MinGW
134 * NOTE: The headers may generate a few warning in GCC, but
135 * they should compile */
136 #define _INC_MMSYSTEM
137 #define _INC_MMREG
138 #define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */
139 #define DEFINE_GUID_THUNK(name,guid) DEFINE_GUID(name,guid)
140 #define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK( n, STATIC_##n )
141 #if !defined( DEFINE_WAVEFORMATEX_GUID )
142 #define DEFINE_WAVEFORMATEX_GUID(x) (USHORT)(x), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
143 #endif
144 #define  WAVE_FORMAT_ADPCM      0x0002
145 #define  WAVE_FORMAT_IEEE_FLOAT 0x0003
146 #define  WAVE_FORMAT_ALAW       0x0006
147 #define  WAVE_FORMAT_MULAW      0x0007
148 #define  WAVE_FORMAT_MPEG       0x0050
149 #define  WAVE_FORMAT_DRM        0x0009
150 #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}}
151 #define DYNAMIC_GUID(data) DYNAMIC_GUID_THUNK(data)
152 #endif
153
154 /* use CreateThread for CYGWIN/Windows Mobile, _beginthreadex for all others */
155 #if !defined(__CYGWIN__) && !defined(_WIN32_WCE)
156 #define CREATE_THREAD_FUNCTION (HANDLE)_beginthreadex
157 #define PA_THREAD_FUNC static unsigned WINAPI
158 #else
159 #define CREATE_THREAD_FUNCTION CreateThread
160 #define PA_THREAD_FUNC static DWORD WINAPI
161 #endif
162
163 #ifdef _MSC_VER
164 #define NOMMIDS
165 #define DYNAMIC_GUID(data) {data}
166 #define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */
167 #undef DEFINE_GUID
168 #define DEFINE_GUID(n,data) EXTERN_C const GUID n = {data}
169 #define DEFINE_GUID_THUNK(n,data) DEFINE_GUID(n,data)
170 #define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK(n, STATIC_##n)
171 #endif
172
173 #include <setupapi.h>
174 #include <winioctl.h>
175
176 #ifndef EXTERN_C
177 #define EXTERN_C extern
178 #endif
179
180 #if defined(__GNUC__)
181
182 /* For MinGW we reference mingw-include files supplied with WASAPI */
183 #define WINBOOL BOOL
184
185 #include "../wasapi/mingw-include/ks.h"
186 #include "../wasapi/mingw-include/ksmedia.h"
187
188 #else
189
190 #include <mmreg.h>
191 #include <ks.h>
192
193 /* Note that Windows SDK V6.0A or later is needed for WaveRT specific structs to be present in
194    ksmedia.h. Also make sure that the SDK include path is before other include paths (that may contain
195    an "old" ksmedia.h), so the proper ksmedia.h is used */
196 #include <ksmedia.h>
197
198 #endif
199
200 #include <assert.h>
201 #include <stdio.h>
202
203 /* These next definitions allow the use of the KSUSER DLL */
204 typedef /*KSDDKAPI*/ DWORD WINAPI KSCREATEPIN(HANDLE, PKSPIN_CONNECT, ACCESS_MASK, PHANDLE);
205 extern HMODULE      DllKsUser;
206 extern KSCREATEPIN* FunctionKsCreatePin;
207
208 /* These definitions allows the use of AVRT.DLL on Vista and later OSs */
209 typedef enum _PA_AVRT_PRIORITY
210 {
211     PA_AVRT_PRIORITY_LOW = -1,
212     PA_AVRT_PRIORITY_NORMAL,
213     PA_AVRT_PRIORITY_HIGH,
214     PA_AVRT_PRIORITY_CRITICAL
215 } PA_AVRT_PRIORITY, *PPA_AVRT_PRIORITY;
216
217 typedef struct
218 {
219     HINSTANCE hInstance;
220
221     HANDLE  (WINAPI *AvSetMmThreadCharacteristics) (LPCSTR, LPDWORD);
222     BOOL    (WINAPI *AvRevertMmThreadCharacteristics) (HANDLE);
223     BOOL    (WINAPI *AvSetMmThreadPriority) (HANDLE, PA_AVRT_PRIORITY);
224 } PaWinWDMKSAvRtEntryPoints;
225
226 static PaWinWDMKSAvRtEntryPoints paWinWDMKSAvRtEntryPoints = {0};
227
228 /* An unspecified channel count (-1) is not treated correctly, so we replace it with
229 * an arbitrarily large number */ 
230 #define MAXIMUM_NUMBER_OF_CHANNELS 256
231
232 /* Forward definition to break circular type reference between pin and filter */
233 struct __PaWinWdmFilter;
234 typedef struct __PaWinWdmFilter PaWinWdmFilter;
235
236 struct __PaWinWdmPin;
237 typedef struct __PaWinWdmPin PaWinWdmPin;
238
239 struct __PaWinWdmStream;
240 typedef struct __PaWinWdmStream PaWinWdmStream;
241
242 /* Function prototype for getting audio position */
243 typedef PaError (*FunctionGetPinAudioPosition)(PaWinWdmPin*, unsigned long*);
244
245 /* Function prototype for memory barrier */
246 typedef void (*FunctionMemoryBarrier)(void);
247
248 struct __PaProcessThreadInfo;
249 typedef struct __PaProcessThreadInfo PaProcessThreadInfo;
250
251 typedef PaError (*FunctionPinHandler)(PaProcessThreadInfo* pInfo, unsigned eventIndex);
252
253 typedef enum __PaStreamStartEnum
254 {
255     StreamStart_kOk,
256     StreamStart_kFailed,
257     StreamStart_kCnt
258 } PaStreamStartEnum;
259
260 /* Multiplexed input structure.
261 *  Very often several physical inputs are multiplexed through a MUX node (represented in the topology filter) */
262 typedef struct __PaWinWdmMuxedInput
263 {
264     wchar_t                     friendlyName[MAX_PATH];
265     ULONG                       muxPinId;
266     ULONG                       muxNodeId;
267     ULONG                       endpointPinId;
268 } PaWinWdmMuxedInput;
269
270 /* The Pin structure
271 * A pin is an input or output node, e.g. for audio flow */
272 struct __PaWinWdmPin
273 {
274     HANDLE                      handle;
275     PaWinWdmMuxedInput**        inputs;
276     unsigned                    inputCount;
277     wchar_t                     friendlyName[MAX_PATH];
278
279     PaWinWdmFilter*             parentFilter;
280     PaWDMKSSubType              pinKsSubType;
281     unsigned long               pinId;
282     unsigned long               endpointPinId;  /* For output pins */
283     KSPIN_CONNECT*              pinConnect;
284     unsigned long               pinConnectSize;
285     KSDATAFORMAT_WAVEFORMATEX*  ksDataFormatWfx;
286     KSPIN_COMMUNICATION         communication;
287     KSDATARANGE*                dataRanges;
288     KSMULTIPLE_ITEM*            dataRangesItem;
289     KSPIN_DATAFLOW              dataFlow;
290     KSPIN_CINSTANCES            instances;
291     unsigned long               frameSize;
292     int                         maxChannels;
293     unsigned long               formats;
294     int                         defaultSampleRate;
295     ULONG                       *positionRegister;  /* WaveRT */
296     ULONG                       hwLatency;          /* WaveRT */
297     FunctionMemoryBarrier       fnMemBarrier;       /* WaveRT */
298     FunctionGetPinAudioPosition fnAudioPosition;    /* WaveRT */
299     FunctionPinHandler          fnEventHandler;
300     FunctionPinHandler          fnSubmitHandler;
301 };
302
303 /* The Filter structure
304 * A filter has a number of pins and a "friendly name" */
305 struct __PaWinWdmFilter
306 {
307     HANDLE         handle;
308     PaWinWDMKSDeviceInfo    devInfo;  /* This will hold information that is exposed in PaDeviceInfo */
309
310     DWORD            deviceNode;
311     int            pinCount;
312     PaWinWdmPin**  pins;
313     PaWinWdmFilter*  topologyFilter;
314     wchar_t          friendlyName[MAX_PATH];
315     int              validPinCount;
316     int            usageCount;
317     KSMULTIPLE_ITEM* connections;
318     KSMULTIPLE_ITEM* nodes;
319     int              filterRefCount;
320 };
321
322
323 typedef struct __PaWinWdmDeviceInfo
324 {
325     PaDeviceInfo    inheritedDeviceInfo;
326     char            compositeName[MAX_PATH];   /* Composite name consists of pin name + device name in utf8 */
327     PaWinWdmFilter* filter;
328     unsigned long   pin;
329     int             muxPosition;    /* Used only for input devices */
330     int             endpointPinId;
331 }
332 PaWinWdmDeviceInfo;
333
334 /* PaWinWdmHostApiRepresentation - host api datastructure specific to this implementation */
335 typedef struct __PaWinWdmHostApiRepresentation
336 {
337     PaUtilHostApiRepresentation  inheritedHostApiRep;
338     PaUtilStreamInterface        callbackStreamInterface;
339     PaUtilStreamInterface        blockingStreamInterface;
340
341     PaUtilAllocationGroup*       allocations;
342     int                          deviceCount;
343 }
344 PaWinWdmHostApiRepresentation;
345
346 typedef struct __DATAPACKET
347 {
348     KSSTREAM_HEADER  Header;
349     OVERLAPPED       Signal;
350 } DATAPACKET;
351
352 typedef struct __PaIOPacket
353 {
354     DATAPACKET*     packet;
355     unsigned        startByte;
356     unsigned        lengthBytes;
357 } PaIOPacket;
358
359 typedef struct __PaWinWdmIOInfo
360 {
361     PaWinWdmPin*        pPin;
362     char*               hostBuffer;
363     unsigned            hostBufferSize;
364     unsigned            framesPerBuffer;
365     unsigned            bytesPerFrame;
366     unsigned            bytesPerSample;
367     unsigned            noOfPackets;    /* Only used in WaveCyclic */
368     HANDLE              *events;        /* noOfPackets handles (WaveCyclic) 1 (WaveRT) */
369     DATAPACKET          *packets;       /* noOfPackets packets (WaveCyclic) 2 (WaveRT) */
370     /* WaveRT polled mode */
371     unsigned            lastPosition; 
372     unsigned            pollCntr;
373 } PaWinWdmIOInfo;
374
375 /* PaWinWdmStream - a stream data structure specifically for this implementation */
376 struct __PaWinWdmStream
377 {
378     PaUtilStreamRepresentation  streamRepresentation;
379     PaWDMKSSpecificStreamInfo   hostApiStreamInfo;    /* This holds info that is exposed through PaStreamInfo */
380     PaUtilCpuLoadMeasurer       cpuLoadMeasurer;
381     PaUtilBufferProcessor       bufferProcessor;
382
383 #if PA_TRACE_REALTIME_EVENTS
384     LogHandle                   hLog;
385 #endif
386
387     PaUtilAllocationGroup*      allocGroup;
388     PaWinWdmIOInfo              capture;
389     PaWinWdmIOInfo              render;
390     int                         streamStarted;
391     int                         streamActive;
392     int                         streamStop;
393     int                         streamAbort;
394     int                         oldProcessPriority;
395     HANDLE                      streamThread;
396     HANDLE                      eventAbort;
397     HANDLE                      eventStreamStart[StreamStart_kCnt];        /* 0 = OK, 1 = Failed */
398     PaError                     threadResult;
399     PaStreamFlags               streamFlags;
400
401     /* Capture ring buffer */
402     PaUtilRingBuffer            ringBuffer;
403     char*                       ringBufferData;
404
405     /* These values handle the case where the user wants to use fewer
406     * channels than the device has */
407     int                         userInputChannels;
408     int                         deviceInputChannels;
409     int                         userOutputChannels;
410     int                         deviceOutputChannels;
411 };
412
413 /* Gather all processing variables in a struct */
414 struct __PaProcessThreadInfo 
415 {
416     PaWinWdmStream              *stream;
417     PaStreamCallbackTimeInfo    ti;
418     PaStreamCallbackFlags       underover;
419     int                         cbResult;
420     volatile int                pending;
421     volatile int                priming;
422     volatile int                pinsStarted;
423     unsigned long               timeout;
424     unsigned                    captureHead;
425     unsigned                    captureTail;
426     unsigned                    renderHead;
427     unsigned                    renderTail;
428     PaIOPacket                  capturePackets[4];
429     PaIOPacket                  renderPackets[4];
430 };
431
432 /* Used for transferring device infos during scanning / rescanning */
433 typedef struct __PaWinWDMScanDeviceInfosResults
434
435     PaDeviceInfo **deviceInfos;
436     PaDeviceIndex defaultInputDevice;
437     PaDeviceIndex defaultOutputDevice;
438 } PaWinWDMScanDeviceInfosResults;
439
440 static const unsigned cPacketsArrayMask = 3;
441
442 HMODULE      DllKsUser = NULL;
443 KSCREATEPIN* FunctionKsCreatePin = NULL;
444
445 /* prototypes for functions declared in this file */
446
447 #ifdef __cplusplus
448 extern "C"
449 {
450 #endif /* __cplusplus */
451
452     PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
453
454 #ifdef __cplusplus
455 }
456 #endif /* __cplusplus */
457
458 /* Low level I/O functions */
459 static PaError WdmSyncIoctl(HANDLE handle,
460                             unsigned long ioctlNumber,
461                             void* inBuffer,
462                             unsigned long inBufferCount,
463                             void* outBuffer,
464                             unsigned long outBufferCount,
465                             unsigned long* bytesReturned);
466
467 static PaError WdmGetPropertySimple(HANDLE handle,
468                                     const GUID* const guidPropertySet,
469                                     unsigned long property,
470                                     void* value,
471                                     unsigned long valueCount);
472
473 static PaError WdmSetPropertySimple(HANDLE handle,
474                                     const GUID* const guidPropertySet,
475                                     unsigned long property,
476                                     void* value,
477                                     unsigned long valueCount,
478                                     void* instance,
479                                     unsigned long instanceCount);
480
481 static PaError WdmGetPinPropertySimple(HANDLE  handle,
482                                        unsigned long pinId,
483                                        const GUID* const guidPropertySet,
484                                        unsigned long property,
485                                        void* value,
486                                        unsigned long valueCount,
487                                        unsigned long* byteCount);
488
489 static PaError WdmGetPinPropertyMulti(HANDLE  handle,
490                                       unsigned long pinId,
491                                       const GUID* const guidPropertySet,
492                                       unsigned long property,
493                                       KSMULTIPLE_ITEM** ksMultipleItem);
494
495 static PaError WdmGetPropertyMulti(HANDLE handle,
496                                    const GUID* const guidPropertySet,
497                                    unsigned long property,
498                                    KSMULTIPLE_ITEM** ksMultipleItem);
499
500 static PaError WdmSetMuxNodeProperty(HANDLE handle,
501                                      ULONG nodeId,
502                                      ULONG pinId);
503
504
505 /** Pin management functions */
506 static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, PaError* error);
507 static void PinFree(PaWinWdmPin* pin);
508 static void PinClose(PaWinWdmPin* pin);
509 static PaError PinInstantiate(PaWinWdmPin* pin);
510 /*static PaError PinGetState(PaWinWdmPin* pin, KSSTATE* state); NOT USED */
511 static PaError PinSetState(PaWinWdmPin* pin, KSSTATE state);
512 static PaError PinSetFormat(PaWinWdmPin* pin, const WAVEFORMATEX* format);
513 static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format);
514 /* WaveRT support */
515 static PaError PinQueryNotificationSupport(PaWinWdmPin* pPin, BOOL* pbResult);
516 static PaError PinGetBuffer(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier);
517 static PaError PinRegisterPositionRegister(PaWinWdmPin* pPin);
518 static PaError PinRegisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle);
519 static PaError PinUnregisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle);
520 static PaError PinGetHwLatency(PaWinWdmPin* pPin, ULONG* pFifoSize, ULONG* pChipsetDelay, ULONG* pCodecDelay);
521 static PaError PinGetAudioPositionMemoryMapped(PaWinWdmPin* pPin, ULONG* pPosition);
522 static PaError PinGetAudioPositionViaIOCTLRead(PaWinWdmPin* pPin, ULONG* pPosition);
523 static PaError PinGetAudioPositionViaIOCTLWrite(PaWinWdmPin* pPin, ULONG* pPosition);
524
525 /* Filter management functions */
526 static PaWinWdmFilter* FilterNew(PaWDMKSType type, DWORD devNode, const wchar_t* filterName, const wchar_t* friendlyName, PaError* error);
527 static PaError FilterInitializePins(PaWinWdmFilter* filter);
528 static void FilterFree(PaWinWdmFilter* filter);
529 static void FilterAddRef(PaWinWdmFilter* filter);
530 static PaWinWdmPin* FilterCreatePin(
531                                     PaWinWdmFilter* filter,
532                                     int pinId,
533                                     const WAVEFORMATEX* wfex,
534                                     PaError* error);
535 static PaError FilterUse(PaWinWdmFilter* filter);
536 static void FilterRelease(PaWinWdmFilter* filter);
537
538 /* Hot plug functions */
539 static BOOL IsDeviceTheSame(const PaWinWdmDeviceInfo* pDev1,
540                             const PaWinWdmDeviceInfo* pDev2);
541
542 /* Interface functions */
543 static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
544 static PaError IsFormatSupported(
545 struct PaUtilHostApiRepresentation *hostApi,
546     const PaStreamParameters *inputParameters,
547     const PaStreamParameters *outputParameters,
548     double sampleRate );
549
550 static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void **newDeviceInfos, int *newDeviceCount );
551 static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *deviceInfos, int deviceCount );
552 static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *deviceInfos, int deviceCount );
553
554 static PaError OpenStream(
555 struct PaUtilHostApiRepresentation *hostApi,
556     PaStream** s,
557     const PaStreamParameters *inputParameters,
558     const PaStreamParameters *outputParameters,
559     double sampleRate,
560     unsigned long framesPerBuffer,
561     PaStreamFlags streamFlags,
562     PaStreamCallback *streamCallback,
563     void *userData );
564 static PaError CloseStream( PaStream* stream );
565 static PaError StartStream( PaStream *stream );
566 static PaError StopStream( PaStream *stream );
567 static PaError AbortStream( PaStream *stream );
568 static PaError IsStreamStopped( PaStream *s );
569 static PaError IsStreamActive( PaStream *stream );
570 static PaTime GetStreamTime( PaStream *stream );
571 static double GetStreamCpuLoad( PaStream* stream );
572 static PaError ReadStream(
573                           PaStream* stream,
574                           void *buffer,
575                           unsigned long frames );
576 static PaError WriteStream(
577                            PaStream* stream,
578                            const void *buffer,
579                            unsigned long frames );
580 static signed long GetStreamReadAvailable( PaStream* stream );
581 static signed long GetStreamWriteAvailable( PaStream* stream );
582
583 /* Utility functions */
584 static unsigned long GetWfexSize(const WAVEFORMATEX* wfex);
585 static PaWinWdmFilter** BuildFilterList(int* filterCount, int* noOfPaDevices, PaError* result);
586 static BOOL PinWrite(HANDLE h, DATAPACKET* p);
587 static BOOL PinRead(HANDLE h, DATAPACKET* p);
588 static void DuplicateFirstChannelInt16(void* buffer, int channels, int samples);
589 static void DuplicateFirstChannelInt24(void* buffer, int channels, int samples);
590 PA_THREAD_FUNC ProcessingThread(void*);
591
592 /* Pin handler functions */
593 static PaError PaPinCaptureEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex);
594 static PaError PaPinCaptureSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex);
595
596 static PaError PaPinRenderEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex);
597 static PaError PaPinRenderSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex);
598
599 static PaError PaPinCaptureEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex);
600 static PaError PaPinCaptureEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex);
601 static PaError PaPinCaptureSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex);
602 static PaError PaPinCaptureSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex);
603
604 static PaError PaPinRenderEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex);
605 static PaError PaPinRenderEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex);
606 static PaError PaPinRenderSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex);
607 static PaError PaPinRenderSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex);
608
609 /* Function bodies */
610
611 #if defined(_DEBUG) && defined(PA_ENABLE_DEBUG_OUTPUT)
612 #define PA_WDMKS_SET_TREF
613 static PaTime tRef = 0;
614
615 static void PaWinWdmDebugPrintf(const char* fmt, ...)
616 {
617     va_list list;
618     char buffer[1024];
619     PaTime t = PaUtil_GetTime() - tRef;
620     va_start(list, fmt);
621     _vsnprintf(buffer, 1023, fmt, list);
622     va_end(list);
623     PaUtil_DebugPrint("%6.3lf: %s", t, buffer);
624 }
625
626 #ifdef PA_DEBUG
627 #undef PA_DEBUG
628 #define PA_DEBUG(x)    PaWinWdmDebugPrintf x ;
629 #endif
630 #endif
631
632 static BOOL IsDeviceTheSame(const PaWinWdmDeviceInfo* pDev1,
633                             const PaWinWdmDeviceInfo* pDev2)
634 {
635     if (pDev1 == NULL || pDev2 == NULL)
636         return FALSE;
637
638     if (pDev1 == pDev2)
639         return TRUE;
640
641     if (strcmp(pDev1->compositeName, pDev2->compositeName) == 0)
642         return TRUE;
643
644     return FALSE;
645 }
646
647 static BOOL IsEarlierThanVista()
648 {
649 /*
650 NOTE: GetVersionEx() is deprecated as of Windows 8.1 and can not be used to reliably detect
651 versions of Windows higher than Windows 8 (due to manifest requirements for reporting higher versions).
652 Microsoft recommends switching to VerifyVersionInfo (available on Win 2k and later), however GetVersionEx
653 is is faster, for now we just disable the deprecation warning.
654 See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx
655 See: http://www.codeproject.com/Articles/678606/Part-Overcoming-Windows-s-deprecation-of-GetVe
656 */
657 #pragma warning (disable : 4996) /* use of GetVersionEx */
658
659     OSVERSIONINFO osvi;
660     osvi.dwOSVersionInfoSize = sizeof(osvi);
661     if (GetVersionEx(&osvi) && osvi.dwMajorVersion<6)
662     {
663         return TRUE;
664     }
665     return FALSE;
666
667 #pragma warning (default : 4996)
668 }
669
670
671
672 static void MemoryBarrierDummy(void)
673 {
674     /* Do nothing */
675 }
676
677 static void MemoryBarrierRead(void)
678 {
679     PaUtil_ReadMemoryBarrier();
680 }
681
682 static void MemoryBarrierWrite(void)
683 {
684     PaUtil_WriteMemoryBarrier();
685 }
686
687 static unsigned long GetWfexSize(const WAVEFORMATEX* wfex)
688 {
689     if( wfex->wFormatTag == WAVE_FORMAT_PCM )
690     {
691         return sizeof( WAVEFORMATEX );
692     }
693     else
694     {
695         return (sizeof( WAVEFORMATEX ) + wfex->cbSize);
696     }
697 }
698
699 static void PaWinWDM_SetLastErrorInfo(long errCode, const char* fmt, ...)
700 {
701     va_list list;
702     char buffer[1024];
703     va_start(list, fmt);
704     _vsnprintf(buffer, 1023, fmt, list);
705     va_end(list);
706     PaUtil_SetLastHostErrorInfo(paWDMKS, errCode, buffer);
707 }
708
709 /*
710 Low level pin/filter access functions
711 */
712 static PaError WdmSyncIoctl(
713                             HANDLE handle,
714                             unsigned long ioctlNumber,
715                             void* inBuffer,
716                             unsigned long inBufferCount,
717                             void* outBuffer,
718                             unsigned long outBufferCount,
719                             unsigned long* bytesReturned)
720 {
721     PaError result = paNoError;
722     unsigned long dummyBytesReturned = 0;
723     BOOL bRes;
724
725     if( !bytesReturned )
726     {
727         /* Use a dummy as the caller hasn't supplied one */
728         bytesReturned = &dummyBytesReturned;
729     }
730
731     bRes = DeviceIoControl(handle, ioctlNumber, inBuffer, inBufferCount, outBuffer, outBufferCount, bytesReturned, NULL);
732     if (!bRes)
733     {
734         unsigned long error = GetLastError();
735         if ( !(((error == ERROR_INSUFFICIENT_BUFFER ) || ( error == ERROR_MORE_DATA )) && 
736             ( ioctlNumber == IOCTL_KS_PROPERTY ) &&
737             ( outBufferCount == 0 ) ) ) 
738         {
739             KSPROPERTY* ksProperty = (KSPROPERTY*)inBuffer;
740
741             PaWinWDM_SetLastErrorInfo(result, "WdmSyncIoctl: DeviceIoControl GLE = 0x%08X (prop_set = {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}, prop_id = %u)",
742                 error,
743                 ksProperty->Set.Data1, ksProperty->Set.Data2, ksProperty->Set.Data3,
744                 ksProperty->Set.Data4[0], ksProperty->Set.Data4[1],
745                 ksProperty->Set.Data4[2], ksProperty->Set.Data4[3],
746                 ksProperty->Set.Data4[4], ksProperty->Set.Data4[5],
747                 ksProperty->Set.Data4[6], ksProperty->Set.Data4[7],
748                 ksProperty->Id
749                 );
750             result = paUnanticipatedHostError;
751         }
752     }
753     return result;
754 }
755
756 static PaError WdmGetPropertySimple(HANDLE handle,
757                                     const GUID* const guidPropertySet,
758                                     unsigned long property,
759                                     void* value,
760                                     unsigned long valueCount)
761 {
762     PaError result;
763     KSPROPERTY ksProperty;
764
765     ksProperty.Set = *guidPropertySet;
766     ksProperty.Id = property;
767     ksProperty.Flags = KSPROPERTY_TYPE_GET;
768
769     result = WdmSyncIoctl(
770         handle,
771         IOCTL_KS_PROPERTY,
772         &ksProperty,
773         sizeof(KSPROPERTY),
774         value,
775         valueCount,
776         NULL);
777
778     return result;
779 }
780
781 static PaError WdmSetPropertySimple(
782                                     HANDLE handle,
783                                     const GUID* const guidPropertySet,
784                                     unsigned long property,
785                                     void* value,
786                                     unsigned long valueCount,
787                                     void* instance,
788                                     unsigned long instanceCount)
789 {
790     PaError result;
791     KSPROPERTY* ksProperty;
792     unsigned long propertyCount  = 0;
793
794     propertyCount = sizeof(KSPROPERTY) + instanceCount;
795     ksProperty = (KSPROPERTY*)_alloca( propertyCount );
796     if( !ksProperty )
797     {
798         return paInsufficientMemory;
799     }
800
801     ksProperty->Set = *guidPropertySet;
802     ksProperty->Id = property;
803     ksProperty->Flags = KSPROPERTY_TYPE_SET;
804
805     if( instance )
806     {
807         memcpy((void*)((char*)ksProperty + sizeof(KSPROPERTY)), instance, instanceCount);
808     }
809
810     result = WdmSyncIoctl(
811         handle,
812         IOCTL_KS_PROPERTY,
813         ksProperty,
814         propertyCount,
815         value,
816         valueCount,
817         NULL);
818
819     return result;
820 }
821
822 static PaError WdmGetPinPropertySimple(
823                                        HANDLE  handle,
824                                        unsigned long pinId,
825                                        const GUID* const guidPropertySet,
826                                        unsigned long property,
827                                        void* value,
828                                        unsigned long valueCount,
829                                        unsigned long *byteCount)
830 {
831     PaError result;
832
833     KSP_PIN ksPProp;
834     ksPProp.Property.Set = *guidPropertySet;
835     ksPProp.Property.Id = property;
836     ksPProp.Property.Flags = KSPROPERTY_TYPE_GET;
837     ksPProp.PinId = pinId;
838     ksPProp.Reserved = 0;
839
840     result = WdmSyncIoctl(
841         handle,
842         IOCTL_KS_PROPERTY,
843         &ksPProp,
844         sizeof(KSP_PIN),
845         value,
846         valueCount,
847         byteCount);
848
849     return result;
850 }
851
852 static PaError WdmGetPinPropertyMulti(
853                                       HANDLE handle,
854                                       unsigned long pinId,
855                                       const GUID* const guidPropertySet,
856                                       unsigned long property,
857                                       KSMULTIPLE_ITEM** ksMultipleItem)
858 {
859     PaError result;
860     unsigned long multipleItemSize = 0;
861     KSP_PIN ksPProp;
862
863     ksPProp.Property.Set = *guidPropertySet;
864     ksPProp.Property.Id = property;
865     ksPProp.Property.Flags = KSPROPERTY_TYPE_GET;
866     ksPProp.PinId = pinId;
867     ksPProp.Reserved = 0;
868
869     result = WdmSyncIoctl(
870         handle,
871         IOCTL_KS_PROPERTY,
872         &ksPProp.Property,
873         sizeof(KSP_PIN),
874         NULL,
875         0,
876         &multipleItemSize);
877     if( result != paNoError )
878     {
879         return result;
880     }
881
882     *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize );
883     if( !*ksMultipleItem )
884     {
885         return paInsufficientMemory;
886     }
887
888     result = WdmSyncIoctl(
889         handle,
890         IOCTL_KS_PROPERTY,
891         &ksPProp,
892         sizeof(KSP_PIN),
893         (void*)*ksMultipleItem,
894         multipleItemSize,
895         NULL);
896
897     if( result != paNoError )
898     {
899         PaUtil_FreeMemory( ksMultipleItem );
900     }
901
902     return result;
903 }
904
905 static PaError WdmGetPropertyMulti(HANDLE handle,
906                                    const GUID* const guidPropertySet,
907                                    unsigned long property,
908                                    KSMULTIPLE_ITEM** ksMultipleItem)
909 {
910     PaError result;
911     unsigned long multipleItemSize = 0;
912     KSPROPERTY ksProp;
913
914     ksProp.Set = *guidPropertySet;
915     ksProp.Id = property;
916     ksProp.Flags = KSPROPERTY_TYPE_GET;
917
918     result = WdmSyncIoctl(
919         handle,
920         IOCTL_KS_PROPERTY,
921         &ksProp,
922         sizeof(KSPROPERTY),
923         NULL,
924         0,
925         &multipleItemSize);
926     if( result != paNoError )
927     {
928         return result;
929     }
930
931     *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize );
932     if( !*ksMultipleItem )
933     {
934         return paInsufficientMemory;
935     }
936
937     result = WdmSyncIoctl(
938         handle,
939         IOCTL_KS_PROPERTY,
940         &ksProp,
941         sizeof(KSPROPERTY),
942         (void*)*ksMultipleItem,
943         multipleItemSize,
944         NULL);
945
946     if( result != paNoError )
947     {
948         PaUtil_FreeMemory( ksMultipleItem );
949     }
950
951     return result;
952 }
953
954 static PaError WdmSetMuxNodeProperty(HANDLE handle,
955                                      ULONG nodeId,
956                                      ULONG pinId)
957 {
958     PaError result = paNoError;
959     KSNODEPROPERTY prop;
960     prop.Property.Set = KSPROPSETID_Audio;
961     prop.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE;
962     prop.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY;
963     prop.NodeId = nodeId;
964     prop.Reserved = 0;
965
966     result = WdmSyncIoctl(handle, IOCTL_KS_PROPERTY, &prop, sizeof(KSNODEPROPERTY), &pinId, sizeof(ULONG), NULL);
967
968     return result;
969 }
970
971 /* Used when traversing topology for outputs */
972 static const KSTOPOLOGY_CONNECTION* GetConnectionTo(const KSTOPOLOGY_CONNECTION* pFrom, PaWinWdmFilter* filter, int muxIdx)
973 {
974     unsigned i;
975     const KSTOPOLOGY_CONNECTION* retval = NULL;
976     const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
977     (void)muxIdx;
978     PA_DEBUG(("GetConnectionTo: Checking %u connections... (pFrom = %p)", filter->connections->Count, pFrom));
979     for (i = 0; i < filter->connections->Count; ++i)
980     {
981         const KSTOPOLOGY_CONNECTION* pConn = connections + i;
982         if (pConn == pFrom)
983             continue;
984
985         if (pConn->FromNode == pFrom->ToNode)
986         {
987             retval = pConn;
988             break;
989         }
990     }
991     PA_DEBUG(("GetConnectionTo: Returning %p\n", retval));
992     return retval;
993 }
994
995 /* Used when traversing topology for inputs */
996 static const KSTOPOLOGY_CONNECTION* GetConnectionFrom(const KSTOPOLOGY_CONNECTION* pTo, PaWinWdmFilter* filter, int muxIdx)
997 {
998     unsigned i;
999     const KSTOPOLOGY_CONNECTION* retval = NULL;
1000     const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
1001     int muxCntr = 0;
1002     PA_DEBUG(("GetConnectionFrom: Checking %u connections... (pTo = %p)\n", filter->connections->Count, pTo));
1003     for (i = 0; i < filter->connections->Count; ++i)
1004     {
1005         const KSTOPOLOGY_CONNECTION* pConn = connections + i;
1006         if (pConn == pTo)
1007             continue;
1008
1009         if (pConn->ToNode == pTo->FromNode)
1010         {
1011             if (muxIdx >= 0)
1012             {
1013                 if (muxCntr < muxIdx)
1014                 {
1015                     ++muxCntr;
1016                     continue;
1017                 }
1018             }
1019             retval = pConn;
1020             break;
1021         }
1022     }
1023     PA_DEBUG(("GetConnectionFrom: Returning %p\n", retval));
1024     return retval;
1025 }
1026
1027 static ULONG GetNumberOfConnectionsTo(const KSTOPOLOGY_CONNECTION* pTo, PaWinWdmFilter* filter)
1028 {
1029     ULONG retval = 0;
1030     unsigned i;
1031     const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
1032     PA_DEBUG(("GetNumberOfConnectionsTo: Checking %u connections...\n", filter->connections->Count));
1033     for (i = 0; i < filter->connections->Count; ++i)
1034     {
1035         const KSTOPOLOGY_CONNECTION* pConn = connections + i;
1036         if (pConn->ToNode == pTo->FromNode &&
1037             (pTo->FromNode != KSFILTER_NODE || pConn->ToNodePin == pTo->FromNodePin))
1038         {
1039             ++retval;
1040         }
1041     }
1042     PA_DEBUG(("GetNumberOfConnectionsTo: Returning %d\n", retval));
1043     return retval;
1044 }
1045
1046 typedef const KSTOPOLOGY_CONNECTION *(*TFnGetConnection)(const KSTOPOLOGY_CONNECTION*, PaWinWdmFilter*, int);
1047
1048 static const KSTOPOLOGY_CONNECTION* FindStartConnectionFrom(ULONG startPin, PaWinWdmFilter* filter)
1049 {
1050     unsigned i;
1051     const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
1052     PA_DEBUG(("FindStartConnectionFrom: Startpin %u, Checking %u connections...\n", startPin, filter->connections->Count));
1053     for (i = 0; i < filter->connections->Count; ++i)
1054     {
1055         const KSTOPOLOGY_CONNECTION* pConn = connections + i;
1056         if (pConn->ToNode == KSFILTER_NODE && pConn->ToNodePin == startPin)
1057         {
1058             PA_DEBUG(("FindStartConnectionFrom: returning %p\n", pConn));
1059             return pConn;
1060         }
1061     }
1062
1063     PA_DEBUG(("FindStartConnectionFrom: returning NULL\n"));
1064     assert(FALSE);
1065     return 0;
1066 }
1067
1068 static const KSTOPOLOGY_CONNECTION* FindStartConnectionTo(ULONG startPin, PaWinWdmFilter* filter)
1069 {
1070     unsigned i;
1071     const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
1072     PA_DEBUG(("FindStartConnectionTo: Startpin %u, Checking %u connections...\n", startPin, filter->connections->Count));
1073     for (i = 0; i < filter->connections->Count; ++i)
1074     {
1075         const KSTOPOLOGY_CONNECTION* pConn = connections + i;
1076         if (pConn->FromNode == KSFILTER_NODE && pConn->FromNodePin == startPin)
1077         {
1078             PA_DEBUG(("FindStartConnectionTo: returning %p\n", pConn));
1079             return pConn;
1080         }
1081     }
1082
1083     PA_DEBUG(("FindStartConnectionTo: returning NULL\n"));
1084     assert(FALSE);
1085     return 0;
1086 }
1087
1088 static ULONG GetConnectedPin(ULONG startPin, BOOL forward, PaWinWdmFilter* filter, int muxPosition, ULONG *muxInputPinId, ULONG *muxNodeId)
1089 {
1090     int limit=1000;
1091     const KSTOPOLOGY_CONNECTION *conn = NULL; 
1092     TFnGetConnection fnGetConnection = forward ? GetConnectionTo : GetConnectionFrom ;
1093     PA_LOGE_;
1094     while (1)
1095     {
1096         limit--;
1097         if (limit == 0) {
1098            PA_DEBUG(("GetConnectedPin: LOOP LIMIT REACHED\n"));
1099            break;
1100         }
1101
1102         if (conn == NULL)
1103         {
1104             conn = forward ? FindStartConnectionTo(startPin, filter) : FindStartConnectionFrom(startPin, filter);
1105         }
1106         else
1107         {
1108             conn = fnGetConnection(conn, filter, -1);
1109         }
1110
1111         /* Handling case of erroneous connection list */
1112         if (conn == NULL)
1113         {
1114             break;
1115         }
1116
1117         if (forward ? conn->ToNode == KSFILTER_NODE : conn->FromNode == KSFILTER_NODE)
1118         {
1119             return forward ? conn->ToNodePin : conn->FromNodePin;
1120         }
1121         else
1122         {
1123             PA_DEBUG(("GetConnectedPin: count=%d, forward=%d, muxPosition=%d\n", filter->nodes->Count, forward, muxPosition));
1124             if (filter->nodes->Count > 0 && !forward && muxPosition >= 0)
1125             {
1126                 const GUID* nodes = (const GUID*)(filter->nodes + 1);
1127                 if (IsEqualGUID(&nodes[conn->FromNode], &KSNODETYPE_MUX))
1128                 {
1129                     ULONG nConn = GetNumberOfConnectionsTo(conn, filter);
1130                     conn = fnGetConnection(conn, filter, muxPosition);
1131                     if (conn == NULL)
1132                     {
1133                         break;
1134                     }
1135                     if (muxInputPinId != 0)
1136                     {
1137                         *muxInputPinId = conn->ToNodePin;
1138                     }
1139                     if (muxNodeId != 0)
1140                     {
1141                         *muxNodeId = conn->ToNode;
1142                     }
1143                 }
1144             }
1145         }
1146     }
1147     PA_LOGL_;
1148     return KSFILTER_NODE;
1149 }
1150
1151 static void DumpConnectionsAndNodes(PaWinWdmFilter* filter)
1152 {
1153     unsigned i;
1154     const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
1155     const GUID* nodes = (const GUID*)(filter->nodes + 1);
1156
1157     PA_LOGE_;
1158     PA_DEBUG(("DumpConnectionsAndNodes: connections=%d, nodes=%d\n", filter->connections->Count, filter->nodes->Count));
1159
1160     for (i=0; i < filter->connections->Count; ++i)
1161     {
1162         const KSTOPOLOGY_CONNECTION* pConn = connections + i;
1163         PA_DEBUG(("  Connection: %u - FromNode=%u,FromPin=%u -> ToNode=%u,ToPin=%u\n", 
1164             i,
1165             pConn->FromNode, pConn->FromNodePin,
1166             pConn->ToNode, pConn->ToNodePin
1167             ));
1168     }
1169
1170     for (i=0; i < filter->nodes->Count; ++i)
1171     {
1172         const GUID* pConn = nodes + i;
1173         PA_DEBUG(("  Node: %d - {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
1174             i,
1175             pConn->Data1, pConn->Data2, pConn->Data3,
1176             pConn->Data4[0], pConn->Data4[1],
1177             pConn->Data4[2], pConn->Data4[3],
1178             pConn->Data4[4], pConn->Data4[5],
1179             pConn->Data4[6], pConn->Data4[7]
1180         ));
1181     }
1182     PA_LOGL_;
1183
1184 }
1185
1186 typedef struct __PaUsbTerminalGUIDToName 
1187 {
1188     USHORT     usbGUID;
1189     wchar_t    name[64];
1190 } PaUsbTerminalGUIDToName;
1191
1192 static const PaUsbTerminalGUIDToName kNames[] =
1193 {
1194     /* Types copied from: http://msdn.microsoft.com/en-us/library/ff537742(v=vs.85).aspx */
1195     /* Input terminal types */
1196     { 0x0201, L"Microphone" },
1197     { 0x0202, L"Desktop Microphone" },
1198     { 0x0203, L"Personal Microphone" },
1199     { 0x0204, L"Omni Directional Microphone" },
1200     { 0x0205, L"Microphone Array" },
1201     { 0x0206, L"Processing Microphone Array" },
1202     /* Output terminal types */
1203     { 0x0301, L"Speakers" },
1204     { 0x0302, L"Headphones" },
1205     { 0x0303, L"Head Mounted Display Audio" },
1206     { 0x0304, L"Desktop Speaker" },
1207     { 0x0305, L"Room Speaker" },
1208     { 0x0306, L"Communication Speaker" },
1209     { 0x0307, L"LFE Speakers" },
1210     /* External terminal types */
1211     { 0x0601, L"Analog" },
1212     { 0x0602, L"Digital" },
1213     { 0x0603, L"Line" },
1214     { 0x0604, L"Audio" },
1215     { 0x0605, L"SPDIF" },
1216 };
1217
1218 static const unsigned kNamesCnt = sizeof(kNames)/sizeof(PaUsbTerminalGUIDToName);
1219
1220 static int PaUsbTerminalGUIDToNameCmp(const void* lhs, const void* rhs)
1221 {
1222     const PaUsbTerminalGUIDToName* pL = (const PaUsbTerminalGUIDToName*)lhs;
1223     const PaUsbTerminalGUIDToName* pR = (const PaUsbTerminalGUIDToName*)rhs;
1224     return ((int)(pL->usbGUID) - (int)(pR->usbGUID));
1225 }
1226
1227 static PaError GetNameFromCategory(const GUID* pGUID, BOOL input, wchar_t* name, unsigned length)
1228 {
1229     PaError result = paUnanticipatedHostError;
1230     USHORT usbTerminalGUID = (USHORT)(pGUID->Data1 - 0xDFF219E0);
1231
1232     PA_LOGE_;
1233     if (input && usbTerminalGUID >= 0x301 && usbTerminalGUID < 0x400)
1234     {
1235         /* Output terminal name for an input !? Set it to Line! */
1236         usbTerminalGUID = 0x603;
1237     }
1238     if (!input && usbTerminalGUID >= 0x201 && usbTerminalGUID < 0x300)
1239     {
1240         /* Input terminal name for an output !? Set it to Line! */
1241         usbTerminalGUID = 0x603;
1242     }
1243     if (usbTerminalGUID >= 0x201 && usbTerminalGUID < 0x713)
1244     {
1245         PaUsbTerminalGUIDToName s = { usbTerminalGUID };
1246         const PaUsbTerminalGUIDToName* ptr = bsearch(
1247             &s,
1248             kNames,
1249             kNamesCnt,
1250             sizeof(PaUsbTerminalGUIDToName),
1251             PaUsbTerminalGUIDToNameCmp
1252             );
1253         if (ptr != 0)
1254         {
1255             PA_DEBUG(("GetNameFromCategory: USB GUID %04X -> '%S'\n", usbTerminalGUID, ptr->name));
1256
1257             if (name != NULL && length > 0)
1258             {
1259                 int n = _snwprintf(name, length, L"%s", ptr->name);
1260                 if (usbTerminalGUID >= 0x601 && usbTerminalGUID < 0x700)
1261                 {
1262                     _snwprintf(name + n, length - n, L" %s", (input ? L"In":L"Out"));
1263                 }
1264             }
1265             result = paNoError;
1266         }
1267     }
1268     else
1269     {
1270         PaWinWDM_SetLastErrorInfo(result, "GetNameFromCategory: usbTerminalGUID = %04X ", usbTerminalGUID);
1271     }
1272     PA_LOGL_;
1273     return result;
1274 }
1275
1276 static BOOL IsFrequencyWithinRange(const KSDATARANGE_AUDIO* range, int frequency)
1277 {
1278     if (frequency < (int)range->MinimumSampleFrequency)
1279         return FALSE;
1280     if (frequency > (int)range->MaximumSampleFrequency)
1281         return FALSE;
1282     return TRUE;
1283 }
1284
1285 static BOOL IsBitsWithinRange(const KSDATARANGE_AUDIO* range, int noOfBits)
1286 {
1287     if (noOfBits < (int)range->MinimumBitsPerSample)
1288         return FALSE;
1289     if (noOfBits > (int)range->MaximumBitsPerSample)
1290         return FALSE;
1291     return TRUE;
1292 }
1293
1294 /* Note: Somewhat different order compared to WMME implementation, as we want to focus on fidelity first */
1295 static const int defaultSampleRateSearchOrder[] =
1296 { 44100, 48000, 88200, 96000, 192000, 32000, 24000, 22050, 16000, 12000, 11025, 9600, 8000 };
1297 static const int defaultSampleRateSearchOrderCount = sizeof(defaultSampleRateSearchOrder)/sizeof(defaultSampleRateSearchOrder[0]);
1298
1299 static int DefaultSampleFrequencyIndex(const KSDATARANGE_AUDIO* range)
1300 {
1301     int i;
1302
1303     for(i=0; i < defaultSampleRateSearchOrderCount; ++i)
1304     {
1305         int currentFrequency = defaultSampleRateSearchOrder[i];
1306
1307         if (IsFrequencyWithinRange(range, currentFrequency))
1308         {
1309             return i;
1310         }
1311     }
1312
1313     return -1;
1314 }
1315
1316 /*
1317 Create a new pin object belonging to a filter
1318 The pin object holds all the configuration information about the pin
1319 before it is opened, and then the handle of the pin after is opened
1320 */
1321 static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, PaError* error)
1322 {
1323     PaWinWdmPin* pin;
1324     PaError result;
1325     unsigned long i;
1326     KSMULTIPLE_ITEM* item = NULL;
1327     KSIDENTIFIER* identifier;
1328     KSDATARANGE* dataRange;
1329     const ULONG streamingId = (parentFilter->devInfo.streamingType == Type_kWaveRT) ? KSINTERFACE_STANDARD_LOOPED_STREAMING : KSINTERFACE_STANDARD_STREAMING;
1330     int defaultSampleRateIndex = defaultSampleRateSearchOrderCount;
1331
1332     PA_LOGE_;
1333     PA_DEBUG(("PinNew: Creating pin %d:\n",pinId));
1334
1335     /* Allocate the new PIN object */
1336     pin = (PaWinWdmPin*)PaUtil_AllocateMemory( sizeof(PaWinWdmPin) );
1337     if( !pin )
1338     {
1339         result = paInsufficientMemory;
1340         goto error;
1341     }
1342
1343     /* Zero the pin object */
1344     /* memset( (void*)pin, 0, sizeof(PaWinWdmPin) ); */
1345
1346     pin->parentFilter = parentFilter;
1347     pin->pinId = pinId;
1348
1349     /* Allocate a connect structure */
1350     pin->pinConnectSize = sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX);
1351     pin->pinConnect = (KSPIN_CONNECT*)PaUtil_AllocateMemory( pin->pinConnectSize );
1352     if( !pin->pinConnect )
1353     {
1354         result = paInsufficientMemory;
1355         goto error;
1356     }
1357
1358     /* Configure the connect structure with default values */
1359     pin->pinConnect->Interface.Set               = KSINTERFACESETID_Standard;
1360     pin->pinConnect->Interface.Id                = streamingId;
1361     pin->pinConnect->Interface.Flags             = 0;
1362     pin->pinConnect->Medium.Set                  = KSMEDIUMSETID_Standard;
1363     pin->pinConnect->Medium.Id                   = KSMEDIUM_TYPE_ANYINSTANCE;
1364     pin->pinConnect->Medium.Flags                = 0;
1365     pin->pinConnect->PinId                       = pinId;
1366     pin->pinConnect->PinToHandle                 = NULL;
1367     pin->pinConnect->Priority.PriorityClass      = KSPRIORITY_NORMAL;
1368     pin->pinConnect->Priority.PrioritySubClass   = 1;
1369     pin->ksDataFormatWfx = (KSDATAFORMAT_WAVEFORMATEX*)(pin->pinConnect + 1);
1370     pin->ksDataFormatWfx->DataFormat.FormatSize  = sizeof(KSDATAFORMAT_WAVEFORMATEX);
1371     pin->ksDataFormatWfx->DataFormat.Flags       = 0;
1372     pin->ksDataFormatWfx->DataFormat.Reserved    = 0;
1373     pin->ksDataFormatWfx->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
1374     pin->ksDataFormatWfx->DataFormat.SubFormat   = KSDATAFORMAT_SUBTYPE_PCM;
1375     pin->ksDataFormatWfx->DataFormat.Specifier   = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
1376
1377     pin->frameSize = 0; /* Unknown until we instantiate pin */
1378
1379     /* Get the COMMUNICATION property */
1380     result = WdmGetPinPropertySimple(
1381         parentFilter->handle,
1382         pinId,
1383         &KSPROPSETID_Pin,
1384         KSPROPERTY_PIN_COMMUNICATION,
1385         &pin->communication,
1386         sizeof(KSPIN_COMMUNICATION),
1387         NULL);
1388     if( result != paNoError )
1389         goto error;
1390
1391     if( /*(pin->communication != KSPIN_COMMUNICATION_SOURCE) &&*/
1392         (pin->communication != KSPIN_COMMUNICATION_SINK) &&
1393         (pin->communication != KSPIN_COMMUNICATION_BOTH) )
1394     {
1395         PA_DEBUG(("PinNew: Not source/sink\n"));
1396         result = paInvalidDevice;
1397         goto error;
1398     }
1399
1400     /* Get dataflow information */
1401     result = WdmGetPinPropertySimple(
1402         parentFilter->handle,
1403         pinId,
1404         &KSPROPSETID_Pin,
1405         KSPROPERTY_PIN_DATAFLOW,
1406         &pin->dataFlow,
1407         sizeof(KSPIN_DATAFLOW),
1408         NULL);
1409
1410     if( result != paNoError )
1411         goto error;
1412
1413     /* Get the INTERFACE property list */
1414     result = WdmGetPinPropertyMulti(
1415         parentFilter->handle,
1416         pinId,
1417         &KSPROPSETID_Pin,
1418         KSPROPERTY_PIN_INTERFACES,
1419         &item);
1420
1421     if( result != paNoError )
1422         goto error;
1423
1424     identifier = (KSIDENTIFIER*)(item+1);
1425
1426     /* Check that at least one interface is STANDARD_STREAMING */
1427     result = paUnanticipatedHostError;
1428     for( i = 0; i < item->Count; i++ )
1429     {
1430         if( IsEqualGUID(&identifier[i].Set, &KSINTERFACESETID_Standard) && ( identifier[i].Id == streamingId ) )
1431         {
1432             result = paNoError;
1433             break;
1434         }
1435     }
1436
1437     if( result != paNoError )
1438     {
1439         PA_DEBUG(("PinNew: No %s streaming\n", streamingId==KSINTERFACE_STANDARD_LOOPED_STREAMING?"looped":"standard"));
1440         goto error;
1441     }
1442
1443     /* Don't need interfaces any more */
1444     PaUtil_FreeMemory( item );
1445     item = NULL;
1446
1447     /* Get the MEDIUM properties list */
1448     result = WdmGetPinPropertyMulti(
1449         parentFilter->handle,
1450         pinId,
1451         &KSPROPSETID_Pin,
1452         KSPROPERTY_PIN_MEDIUMS,
1453         &item);
1454
1455     if( result != paNoError )
1456         goto error;
1457
1458     identifier = (KSIDENTIFIER*)(item+1); /* Not actually necessary... */
1459
1460     /* Check that at least one medium is STANDARD_DEVIO */
1461     result = paUnanticipatedHostError;
1462     for( i = 0; i < item->Count; i++ )
1463     {
1464         if( IsEqualGUID(&identifier[i].Set, &KSMEDIUMSETID_Standard) && ( identifier[i].Id == KSMEDIUM_STANDARD_DEVIO ) )
1465         {
1466             result = paNoError;
1467             break;
1468         }
1469     }
1470
1471     if( result != paNoError )
1472     {
1473         PA_DEBUG(("No standard devio\n"));
1474         goto error;
1475     }
1476     /* Don't need mediums any more */
1477     PaUtil_FreeMemory( item );
1478     item = NULL;
1479
1480     /* Get DATARANGES */
1481     result = WdmGetPinPropertyMulti(
1482         parentFilter->handle,
1483         pinId,
1484         &KSPROPSETID_Pin,
1485         KSPROPERTY_PIN_DATARANGES,
1486         &pin->dataRangesItem);
1487
1488     if( result != paNoError )
1489         goto error;
1490
1491     pin->dataRanges = (KSDATARANGE*)(pin->dataRangesItem +1);
1492
1493     /* Check that at least one datarange supports audio */
1494     result = paUnanticipatedHostError;
1495     dataRange = pin->dataRanges;
1496     pin->maxChannels = 0;
1497     pin->defaultSampleRate = 0;
1498     pin->formats = 0;
1499     PA_DEBUG(("PinNew: Checking %u no of dataranges...\n", pin->dataRangesItem->Count));
1500     for( i = 0; i < pin->dataRangesItem->Count; i++)
1501     {
1502         PA_DEBUG(("PinNew: DR major format %x\n",*(unsigned long*)(&(dataRange->MajorFormat))));
1503         /* Check that subformat is WAVEFORMATEX, PCM or WILDCARD */
1504         if( IS_VALID_WAVEFORMATEX_GUID(&dataRange->SubFormat) ||
1505             IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) ||
1506             IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) ||
1507             IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_WILDCARD) ||
1508             IsEqualGUID(&dataRange->MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) )
1509         {
1510             int defaultIndex;
1511             result = paNoError;
1512             /* Record the maximum possible channels with this pin */
1513             if( ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels == (ULONG) -1 )
1514             {
1515                 pin->maxChannels = MAXIMUM_NUMBER_OF_CHANNELS;
1516             }
1517             else if( (int) ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels > pin->maxChannels )
1518             {
1519                 pin->maxChannels = (int) ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels;
1520             }
1521             PA_DEBUG(("PinNew: MaxChannel: %d\n",pin->maxChannels));
1522
1523             /* Record the formats (bit depths) that are supported */
1524             if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 8) )
1525             {
1526                 pin->formats |= paInt8;
1527                 PA_DEBUG(("PinNew: Format PCM 8 bit supported\n"));
1528             }
1529             if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 16) )
1530             {
1531                 pin->formats |= paInt16;
1532                 PA_DEBUG(("PinNew: Format PCM 16 bit supported\n"));
1533             }
1534             if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 24) )
1535             {
1536                 pin->formats |= paInt24;
1537                 PA_DEBUG(("PinNew: Format PCM 24 bit supported\n"));
1538             }
1539             if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 32) )
1540             {
1541                 if (IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
1542                 {
1543                     pin->formats |= paFloat32;
1544                     PA_DEBUG(("PinNew: Format IEEE float 32 bit supported\n"));
1545                 }
1546                 else
1547                 {
1548                     pin->formats |= paInt32;
1549                     PA_DEBUG(("PinNew: Format PCM 32 bit supported\n"));
1550                 }
1551             }
1552
1553             defaultIndex = DefaultSampleFrequencyIndex((KSDATARANGE_AUDIO*)dataRange);
1554             if (defaultIndex >= 0 && defaultIndex < defaultSampleRateIndex)
1555             {
1556                 defaultSampleRateIndex = defaultIndex;
1557             }
1558         }
1559         dataRange = (KSDATARANGE*)( ((char*)dataRange) + dataRange->FormatSize);
1560     }
1561
1562     if( result != paNoError )
1563         goto error;
1564
1565     /* If none of the frequencies searched for are present, there's something seriously wrong */
1566     if (defaultSampleRateIndex == defaultSampleRateSearchOrderCount)
1567     {
1568         PA_DEBUG(("PinNew: No default sample rate found, skipping pin!\n"));
1569         PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "PinNew: No default sample rate found");
1570         result = paUnanticipatedHostError;
1571         goto error;
1572     }
1573
1574     /* Set the default sample rate */
1575     pin->defaultSampleRate = defaultSampleRateSearchOrder[defaultSampleRateIndex];
1576     PA_DEBUG(("PinNew: Default sample rate = %d Hz\n", pin->defaultSampleRate));
1577
1578     /* Get instance information */
1579     result = WdmGetPinPropertySimple(
1580         parentFilter->handle,
1581         pinId,
1582         &KSPROPSETID_Pin,
1583         KSPROPERTY_PIN_CINSTANCES,
1584         &pin->instances,
1585         sizeof(KSPIN_CINSTANCES),
1586         NULL);
1587
1588     if( result != paNoError )
1589         goto error;
1590
1591     /* If WaveRT, check if pin supports notification mode */
1592     if (parentFilter->devInfo.streamingType == Type_kWaveRT)
1593     {
1594         BOOL bSupportsNotification = FALSE;
1595         if (PinQueryNotificationSupport(pin, &bSupportsNotification) == paNoError)
1596         {
1597             pin->pinKsSubType = bSupportsNotification ? SubType_kNotification : SubType_kPolled;
1598         }
1599     }
1600
1601     /* Query pin name (which means we need to traverse to non IRP pin, via physical connection to topology filter pin, through
1602     its nodes to the endpoint pin, and get that ones name... phew...) */
1603     PA_DEBUG(("PinNew: Finding topology pin...\n"));
1604
1605     {
1606         ULONG topoPinId = GetConnectedPin(pinId, (pin->dataFlow == KSPIN_DATAFLOW_IN), parentFilter, -1, NULL, NULL);
1607         const wchar_t kInputName[] = L"Input";
1608         const wchar_t kOutputName[] = L"Output";
1609
1610         if (topoPinId != KSFILTER_NODE)
1611         {
1612             /* Get physical connection for topo pin */
1613             unsigned long cbBytes = 0;
1614             PA_DEBUG(("PinNew: Getting physical connection...\n"));
1615             result = WdmGetPinPropertySimple(parentFilter->handle,
1616                 topoPinId,
1617                 &KSPROPSETID_Pin,
1618                 KSPROPERTY_PIN_PHYSICALCONNECTION,
1619                 0,
1620                 0,
1621                 &cbBytes
1622                 );
1623
1624             if (result != paNoError)
1625             {
1626                 /* No physical connection -> there is no topology filter! So we get the name of the pin! */
1627                 PA_DEBUG(("PinNew: No physical connection! Getting the pin name\n"));
1628                 result = WdmGetPinPropertySimple(parentFilter->handle,
1629                     topoPinId,
1630                     &KSPROPSETID_Pin,
1631                     KSPROPERTY_PIN_NAME,
1632                     pin->friendlyName,
1633                     MAX_PATH,
1634                     NULL);
1635                 if (result != paNoError)
1636                 {
1637                     GUID category = {0};
1638
1639                     /* Get pin category information */
1640                     result = WdmGetPinPropertySimple(parentFilter->handle,
1641                         topoPinId,
1642                         &KSPROPSETID_Pin,
1643                         KSPROPERTY_PIN_CATEGORY,
1644                         &category,
1645                         sizeof(GUID),
1646                         NULL);
1647
1648                     if (result == paNoError)
1649                     {
1650                         result = GetNameFromCategory(&category, (pin->dataFlow == KSPIN_DATAFLOW_OUT), pin->friendlyName, MAX_PATH);
1651                     }
1652                 }
1653
1654                 /* Make sure pin gets a name here... */
1655                 if (wcslen(pin->friendlyName) == 0)
1656                 {
1657                     wcscpy(pin->friendlyName, (pin->dataFlow == KSPIN_DATAFLOW_IN) ? kOutputName : kInputName);
1658 #ifdef UNICODE
1659                     PA_DEBUG(("PinNew: Setting pin friendly name to '%s'\n", pin->friendlyName));
1660 #else
1661                     PA_DEBUG(("PinNew: Setting pin friendly name to '%S'\n", pin->friendlyName));
1662 #endif
1663                 }
1664
1665                 /* This is then == the endpoint pin */
1666                 pin->endpointPinId = (pin->dataFlow == KSPIN_DATAFLOW_IN) ? pinId : topoPinId;
1667             }
1668             else
1669             {
1670                 KSPIN_PHYSICALCONNECTION* pc = (KSPIN_PHYSICALCONNECTION*)PaUtil_AllocateMemory(cbBytes + 2);
1671                 ULONG pcPin;
1672                 wchar_t symbLinkName[MAX_PATH];
1673                 PA_DEBUG(("PinNew: Physical connection found!\n"));
1674                 if (pc == NULL)
1675                 {
1676                     result = paInsufficientMemory;
1677                     goto error;
1678                 }
1679                 result = WdmGetPinPropertySimple(parentFilter->handle,
1680                     topoPinId,
1681                     &KSPROPSETID_Pin,
1682                     KSPROPERTY_PIN_PHYSICALCONNECTION,
1683                     pc,
1684                     cbBytes,
1685                     NULL
1686                     );
1687
1688                 pcPin = pc->Pin;
1689                 wcsncpy(symbLinkName, pc->SymbolicLinkName, MAX_PATH);
1690                 PaUtil_FreeMemory( pc );
1691
1692                 if (result != paNoError)
1693                 {
1694                     /* Shouldn't happen, but fail if it does */
1695                     PA_DEBUG(("PinNew: failed to retrieve physical connection!\n"));
1696                     goto error;
1697                 }
1698
1699                 if (symbLinkName[1] == TEXT('?'))
1700                 {
1701                     symbLinkName[1] = TEXT('\\');
1702                 }
1703
1704                 if (pin->parentFilter->topologyFilter == NULL)
1705                 {
1706                     PA_DEBUG(("PinNew: Creating topology filter '%S'\n", symbLinkName));
1707
1708                     pin->parentFilter->topologyFilter = FilterNew(Type_kNotUsed, 0, symbLinkName, L"", &result);
1709                     if (pin->parentFilter->topologyFilter == NULL)
1710                     {
1711                         PA_DEBUG(("PinNew: Failed creating topology filter\n"));
1712                         result = paUnanticipatedHostError;
1713                         PaWinWDM_SetLastErrorInfo(result, "Failed to create topology filter '%S'", symbLinkName);
1714                         goto error;
1715                     }
1716
1717                     /* Copy info so we have it in device info */
1718                     wcsncpy(pin->parentFilter->devInfo.topologyPath, symbLinkName, MAX_PATH);
1719                 }
1720                 else
1721                 {
1722                     /* Must be the same */
1723                     assert(wcscmp(symbLinkName, pin->parentFilter->topologyFilter->devInfo.filterPath) == 0);
1724                 }
1725
1726                 PA_DEBUG(("PinNew: Opening topology filter..."));
1727
1728                 result = FilterUse(pin->parentFilter->topologyFilter);
1729                 if (result == paNoError)
1730                 {
1731                     unsigned long endpointPinId;
1732
1733                     if (pin->dataFlow == KSPIN_DATAFLOW_IN)
1734                     {
1735                         /* The "endpointPinId" is what WASAPI looks at for pin names */
1736                         GUID category = {0};
1737
1738                         PA_DEBUG(("PinNew: Checking for output endpoint pin id...\n"));
1739
1740                         endpointPinId = GetConnectedPin(pcPin, TRUE, pin->parentFilter->topologyFilter, -1, NULL, NULL);
1741
1742                         if (endpointPinId == KSFILTER_NODE)
1743                         {
1744                             result = paUnanticipatedHostError;
1745                             PaWinWDM_SetLastErrorInfo(result, "Failed to get endpoint pin ID on topology filter!");
1746                             goto error;
1747                         }
1748
1749                         PA_DEBUG(("PinNew: Found endpoint pin id %u\n", endpointPinId));
1750
1751                         /* Get pin category information */
1752                         result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
1753                             endpointPinId,
1754                             &KSPROPSETID_Pin,
1755                             KSPROPERTY_PIN_CATEGORY,
1756                             &category,
1757                             sizeof(GUID),
1758                             NULL);
1759
1760                         if (result == paNoError)
1761                         {
1762 #if !PA_WDMKS_USE_CATEGORY_FOR_PIN_NAMES
1763                             wchar_t pinName[MAX_PATH];
1764
1765                             PA_DEBUG(("PinNew: Getting pin name property..."));
1766
1767                             /* Ok, try pin name also, and favor that if available */
1768                             result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
1769                                 endpointPinId,
1770                                 &KSPROPSETID_Pin,
1771                                 KSPROPERTY_PIN_NAME,
1772                                 pinName,
1773                                 MAX_PATH,
1774                                 NULL);
1775
1776                             if (result == paNoError && wcslen(pinName)>0)
1777                             {
1778                                 wcsncpy(pin->friendlyName, pinName, MAX_PATH);
1779                             }
1780                             else
1781 #endif
1782                             {
1783                                 result = GetNameFromCategory(&category, (pin->dataFlow == KSPIN_DATAFLOW_OUT), pin->friendlyName, MAX_PATH);
1784                             }
1785                         }
1786
1787                         /* Make sure we get a name for the pin */
1788                         if (wcslen(pin->friendlyName) == 0)
1789                         {
1790                             wcscpy(pin->friendlyName, kOutputName);
1791                         }
1792 #ifdef UNICODE
1793                         PA_DEBUG(("PinNew: Pin name '%s'\n", pin->friendlyName));
1794 #else
1795                         PA_DEBUG(("PinNew: Pin name '%S'\n", pin->friendlyName));
1796 #endif                                
1797
1798                         /* Set endpoint pin ID (this is the topology INPUT pin, since portmixer will always traverse the
1799                         filter in audio streaming direction, see http://msdn.microsoft.com/en-us/library/windows/hardware/ff536331(v=vs.85).aspx
1800                         for more information)
1801                         */
1802                         pin->endpointPinId = pcPin;
1803                     }
1804                     else
1805                     {
1806                         unsigned muxCount = 0;
1807                         int muxPos = 0;
1808                         /* Max 64 multiplexer inputs... sanity check :) */
1809                         for (i = 0; i < 64; ++i)
1810                         {
1811                             ULONG muxNodeIdTest = (unsigned)-1;
1812                             PA_DEBUG(("PinNew: Checking for input endpoint pin id (%d)...\n", i));
1813
1814                             endpointPinId = GetConnectedPin(pcPin,
1815                                 FALSE,
1816                                 pin->parentFilter->topologyFilter,
1817                                 (int)i,
1818                                 NULL,
1819                                 &muxNodeIdTest);
1820
1821                             if (endpointPinId == KSFILTER_NODE)
1822                             {
1823                                 /* We're done */
1824                                 PA_DEBUG(("PinNew: Done with inputs.\n", endpointPinId));
1825                                 break;
1826                             }
1827                             else
1828                             {
1829                                 /* The "endpointPinId" is what WASAPI looks at for pin names */
1830                                 GUID category = {0};
1831
1832                                 PA_DEBUG(("PinNew: Found endpoint pin id %u\n", endpointPinId));
1833
1834                                 /* Get pin category information */
1835                                 result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
1836                                     endpointPinId,
1837                                     &KSPROPSETID_Pin,
1838                                     KSPROPERTY_PIN_CATEGORY,
1839                                     &category,
1840                                     sizeof(GUID),
1841                                     NULL);
1842
1843                                 if (result == paNoError)
1844                                 {
1845                                     if (muxNodeIdTest == (unsigned)-1)
1846                                     {
1847                                         /* Ok, try pin name, and favor that if available */
1848                                         result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
1849                                             endpointPinId,
1850                                             &KSPROPSETID_Pin,
1851                                             KSPROPERTY_PIN_NAME,
1852                                             pin->friendlyName,
1853                                             MAX_PATH,
1854                                             NULL);
1855
1856                                         if (result != paNoError)
1857                                         {
1858                                             result = GetNameFromCategory(&category, TRUE, pin->friendlyName, MAX_PATH);
1859                                         }
1860                                         break;
1861                                     }
1862                                     else
1863                                     {
1864                                         result = GetNameFromCategory(&category, TRUE, NULL, 0);
1865
1866                                         if (result == paNoError)
1867                                         {
1868                                             ++muxCount;
1869                                         }
1870                                     }
1871                                 }
1872                                 else
1873                                 {
1874                                     PA_DEBUG(("PinNew: Failed to get pin category"));
1875                                 }
1876                             }
1877                         }
1878
1879                         if (muxCount == 0)
1880                         {
1881                             pin->endpointPinId = endpointPinId;
1882                             /* Make sure we get a name for the pin */
1883                             if (wcslen(pin->friendlyName) == 0)
1884                             {
1885                                 wcscpy(pin->friendlyName, kInputName);
1886                             }
1887 #ifdef UNICODE
1888                             PA_DEBUG(("PinNew: Input friendly name '%s'\n", pin->friendlyName));
1889 #else
1890                             PA_DEBUG(("PinNew: Input friendly name '%S'\n", pin->friendlyName));
1891 #endif
1892                         }
1893                         else // muxCount > 0
1894                         {
1895                             PA_DEBUG(("PinNew: Setting up %u inputs\n", muxCount));
1896
1897                             /* Now we redo the operation once known how many multiplexer positions there are */
1898                             pin->inputs = (PaWinWdmMuxedInput**)PaUtil_AllocateMemory(muxCount * sizeof(PaWinWdmMuxedInput*));
1899                             if (pin->inputs == NULL)
1900                             {
1901                                 FilterRelease(pin->parentFilter->topologyFilter);
1902                                 result = paInsufficientMemory;
1903                                 goto error;
1904                             }
1905                             pin->inputCount = muxCount;
1906
1907                             for (i = 0; i < muxCount; ++muxPos)
1908                             {
1909                                 PA_DEBUG(("PinNew: Setting up input %u...\n", i));
1910
1911                                 if (pin->inputs[i] == NULL)
1912                                 {
1913                                     pin->inputs[i] = (PaWinWdmMuxedInput*)PaUtil_AllocateMemory(sizeof(PaWinWdmMuxedInput));
1914                                     if (pin->inputs[i] == NULL)
1915                                     {
1916                                         FilterRelease(pin->parentFilter->topologyFilter);
1917                                         result = paInsufficientMemory;
1918                                         goto error;
1919                                     }
1920                                 }
1921
1922                                 endpointPinId = GetConnectedPin(pcPin,
1923                                     FALSE,
1924                                     pin->parentFilter->topologyFilter,
1925                                     muxPos,
1926                                     &pin->inputs[i]->muxPinId, 
1927                                     &pin->inputs[i]->muxNodeId);
1928
1929                                 if (endpointPinId != KSFILTER_NODE)
1930                                 {
1931                                     /* The "endpointPinId" is what WASAPI looks at for pin names */
1932                                     GUID category = {0};
1933
1934                                     /* Set input endpoint ID */
1935                                     pin->inputs[i]->endpointPinId = endpointPinId;
1936
1937                                     /* Get pin category information */
1938                                     result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
1939                                         endpointPinId,
1940                                         &KSPROPSETID_Pin,
1941                                         KSPROPERTY_PIN_CATEGORY,
1942                                         &category,
1943                                         sizeof(GUID),
1944                                         NULL);
1945
1946                                     if (result == paNoError)
1947                                     {
1948                                         /* Try pin name first, and if that is not defined, use category instead */
1949                                         result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
1950                                             endpointPinId,
1951                                             &KSPROPSETID_Pin,
1952                                             KSPROPERTY_PIN_NAME,
1953                                             pin->inputs[i]->friendlyName,
1954                                             MAX_PATH,
1955                                             NULL);
1956
1957                                         if (result != paNoError)
1958                                         {
1959                                             result = GetNameFromCategory(&category, TRUE, pin->inputs[i]->friendlyName, MAX_PATH);
1960                                             if (result != paNoError)
1961                                             {
1962                                                 /* Only specify name, let name hash in ScanDeviceInfos fix postfix enumerators */
1963                                                 wcscpy(pin->inputs[i]->friendlyName, kInputName);
1964                                             }
1965                                         }
1966 #ifdef UNICODE
1967                                         PA_DEBUG(("PinNew: Input (%u) friendly name '%s'\n", i, pin->inputs[i]->friendlyName));
1968 #else
1969                                         PA_DEBUG(("PinNew: Input (%u) friendly name '%S'\n", i, pin->inputs[i]->friendlyName));
1970 #endif
1971                                         ++i;
1972                                     }
1973                                 }
1974                                 else
1975                                 {
1976                                     /* Should never come here! */
1977                                     assert(FALSE);
1978                                 }
1979                             }
1980                         }
1981                     }
1982                 }
1983             }
1984         }
1985         else
1986         {
1987             PA_DEBUG(("PinNew: No topology pin id found. Bad...\n"));
1988             /* No TOPO pin id ??? This is bad. Ok, so we just say it is an input or output... */
1989             wcscpy(pin->friendlyName, (pin->dataFlow == KSPIN_DATAFLOW_IN) ? kOutputName : kInputName);
1990         }
1991     }
1992
1993     /* Release topology filter if it has been used */
1994     if (pin->parentFilter->topologyFilter && pin->parentFilter->topologyFilter->handle != NULL)
1995     {
1996         PA_DEBUG(("PinNew: Releasing topology filter...\n"));
1997         FilterRelease(pin->parentFilter->topologyFilter);
1998     }
1999
2000     /* Success */
2001     *error = paNoError;
2002     PA_DEBUG(("Pin created successfully\n"));
2003     PA_LOGL_;
2004     return pin;
2005
2006 error:
2007     PA_DEBUG(("PinNew: Error %d\n", result));
2008     /*
2009     Error cleanup
2010     */
2011
2012     if (pin->parentFilter->topologyFilter && pin->parentFilter->topologyFilter->handle != NULL)
2013     {
2014         FilterRelease(pin->parentFilter->topologyFilter);
2015     }
2016
2017     PaUtil_FreeMemory( item );
2018     PinFree(pin);
2019
2020     *error = result;
2021     PA_LOGL_;
2022     return NULL;
2023 }
2024
2025 /*
2026 Safely free all resources associated with the pin
2027 */
2028 static void PinFree(PaWinWdmPin* pin)
2029 {
2030     unsigned i;
2031     PA_LOGE_;
2032     if( pin )
2033     {
2034         PinClose(pin);
2035         if( pin->pinConnect )
2036         {
2037             PaUtil_FreeMemory( pin->pinConnect );
2038         }
2039         if( pin->dataRangesItem )
2040         {
2041             PaUtil_FreeMemory( pin->dataRangesItem );
2042         }
2043         if( pin->inputs )
2044         {
2045             for (i = 0; i < pin->inputCount; ++i)
2046             {
2047                 PaUtil_FreeMemory( pin->inputs[i] );
2048             }
2049             PaUtil_FreeMemory( pin->inputs );
2050         }
2051         PaUtil_FreeMemory( pin );
2052     }
2053     PA_LOGL_;
2054 }
2055
2056 /*
2057 If the pin handle is open, close it
2058 */
2059 static void PinClose(PaWinWdmPin* pin)
2060 {
2061     PA_LOGE_;
2062     if( pin == NULL )
2063     {
2064         PA_DEBUG(("Closing NULL pin!"));
2065         PA_LOGL_;
2066         return;
2067     }
2068     if( pin->handle != NULL )
2069     {
2070         PinSetState( pin, KSSTATE_PAUSE );
2071         PinSetState( pin, KSSTATE_STOP );
2072         CloseHandle( pin->handle );
2073         pin->handle = NULL;
2074         FilterRelease(pin->parentFilter);
2075     }
2076     PA_LOGL_;
2077 }
2078
2079 /*
2080 Set the state of this (instantiated) pin
2081 */
2082 static PaError PinSetState(PaWinWdmPin* pin, KSSTATE state)
2083 {
2084     PaError result = paNoError;
2085     KSPROPERTY prop;
2086
2087     PA_LOGE_;
2088     prop.Set = KSPROPSETID_Connection;
2089     prop.Id  = KSPROPERTY_CONNECTION_STATE;
2090     prop.Flags = KSPROPERTY_TYPE_SET;
2091
2092     if( pin == NULL )
2093         return paInternalError;
2094     if( pin->handle == NULL )
2095         return paInternalError;
2096
2097     result = WdmSyncIoctl(pin->handle, IOCTL_KS_PROPERTY, &prop, sizeof(KSPROPERTY), &state, sizeof(KSSTATE), NULL);
2098
2099     PA_LOGL_;
2100     return result;
2101 }
2102
2103 static PaError PinInstantiate(PaWinWdmPin* pin)
2104 {
2105     PaError result;
2106     unsigned long createResult;
2107     KSALLOCATOR_FRAMING ksaf;
2108     KSALLOCATOR_FRAMING_EX ksafex;
2109
2110     PA_LOGE_;
2111
2112     if( pin == NULL )
2113         return paInternalError;
2114     if(!pin->pinConnect)
2115         return paInternalError;
2116
2117     FilterUse(pin->parentFilter);
2118
2119     createResult = FunctionKsCreatePin(
2120         pin->parentFilter->handle,
2121         pin->pinConnect,
2122         GENERIC_WRITE | GENERIC_READ,
2123         &pin->handle
2124         );
2125
2126     PA_DEBUG(("Pin create result = 0x%08x\n",createResult));
2127     if( createResult != ERROR_SUCCESS )
2128     {
2129         FilterRelease(pin->parentFilter);
2130         pin->handle = NULL;
2131         switch (createResult)
2132         {
2133         case ERROR_INVALID_PARAMETER:
2134             /* First case when pin actually don't support the format */
2135             return paSampleFormatNotSupported;
2136         case ERROR_BAD_COMMAND:
2137             /* Case when pin is occupied (by another application) */
2138             return paDeviceUnavailable;
2139         default:
2140             /* All other cases */
2141             return paInvalidDevice;
2142         }
2143     }
2144
2145     if (pin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
2146     {
2147         /* Framing size query only valid for WaveCyclic devices */
2148         result = WdmGetPropertySimple(
2149             pin->handle,
2150             &KSPROPSETID_Connection,
2151             KSPROPERTY_CONNECTION_ALLOCATORFRAMING,
2152             &ksaf,
2153             sizeof(ksaf));
2154
2155         if( result != paNoError )
2156         {
2157             result = WdmGetPropertySimple(
2158                 pin->handle,
2159                 &KSPROPSETID_Connection,
2160                 KSPROPERTY_CONNECTION_ALLOCATORFRAMING_EX,
2161                 &ksafex,
2162                 sizeof(ksafex));
2163             if( result == paNoError )
2164             {
2165                 pin->frameSize = ksafex.FramingItem[0].FramingRange.Range.MinFrameSize;
2166             }
2167         }
2168         else
2169         {
2170             pin->frameSize = ksaf.FrameSize;
2171         }
2172     }
2173
2174     PA_LOGL_;
2175
2176     return paNoError;
2177 }
2178
2179 static PaError PinSetFormat(PaWinWdmPin* pin, const WAVEFORMATEX* format)
2180 {
2181     unsigned long size;
2182     void* newConnect;
2183
2184     PA_LOGE_;
2185
2186     if( pin == NULL )
2187         return paInternalError;
2188     if( format == NULL )
2189         return paInternalError;
2190
2191     size = GetWfexSize(format) + sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX) - sizeof(WAVEFORMATEX);
2192
2193     if( pin->pinConnectSize != size )
2194     {
2195         newConnect = PaUtil_AllocateMemory( size );
2196         if( newConnect == NULL )
2197             return paInsufficientMemory;
2198         memcpy( newConnect, (void*)pin->pinConnect, min(pin->pinConnectSize,size) );
2199         PaUtil_FreeMemory( pin->pinConnect );
2200         pin->pinConnect = (KSPIN_CONNECT*)newConnect;
2201         pin->pinConnectSize = size;
2202         pin->ksDataFormatWfx = (KSDATAFORMAT_WAVEFORMATEX*)((KSPIN_CONNECT*)newConnect + 1);
2203         pin->ksDataFormatWfx->DataFormat.FormatSize = size - sizeof(KSPIN_CONNECT);
2204     }
2205
2206     memcpy( (void*)&(pin->ksDataFormatWfx->WaveFormatEx), format, GetWfexSize(format) );
2207     pin->ksDataFormatWfx->DataFormat.SampleSize = (unsigned short)(format->nChannels * (format->wBitsPerSample / 8));
2208
2209     PA_LOGL_;
2210
2211     return paNoError;
2212 }
2213
2214 static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format)
2215 {
2216     KSDATARANGE_AUDIO* dataRange;
2217     unsigned long count;
2218     GUID guid = DYNAMIC_GUID( DEFINE_WAVEFORMATEX_GUID(format->wFormatTag) );
2219     PaError result = paInvalidDevice;
2220     const WAVEFORMATEXTENSIBLE* pFormatExt = (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE) ? (const WAVEFORMATEXTENSIBLE*)format : 0;
2221
2222     PA_LOGE_;
2223
2224     if( pFormatExt != 0 )
2225     {
2226         guid = pFormatExt->SubFormat;
2227     }
2228     dataRange = (KSDATARANGE_AUDIO*)pin->dataRanges;
2229     for(count = 0;
2230         count<pin->dataRangesItem->Count;
2231         count++, 
2232         dataRange = (KSDATARANGE_AUDIO*)( ((char*)dataRange) + dataRange->DataRange.FormatSize)) /* Need to update dataRange here, due to 'continue' !! */
2233     {
2234         /* Check major format*/
2235         if (!(IsEqualGUID(&(dataRange->DataRange.MajorFormat), &KSDATAFORMAT_TYPE_AUDIO) ||
2236             IsEqualGUID(&(dataRange->DataRange.MajorFormat), &KSDATAFORMAT_TYPE_WILDCARD)))
2237         {
2238             continue;
2239         }
2240
2241         /* This is an audio or wildcard datarange... */
2242         if (! (IsEqualGUID(&(dataRange->DataRange.SubFormat), &KSDATAFORMAT_SUBTYPE_WILDCARD) ||
2243             IsEqualGUID(&(dataRange->DataRange.SubFormat), &KSDATAFORMAT_SUBTYPE_PCM) ||
2244             IsEqualGUID(&(dataRange->DataRange.SubFormat), &guid) ))
2245         {
2246             continue;
2247         }
2248
2249         /* Check specifier... */
2250         if (! (IsEqualGUID(&(dataRange->DataRange.Specifier), &KSDATAFORMAT_SPECIFIER_WILDCARD) ||
2251             IsEqualGUID(&(dataRange->DataRange.Specifier), &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)) )
2252         {
2253             continue;
2254         }
2255
2256         PA_DEBUG(("Pin:%x, DataRange:%d\n",(void*)pin,count));
2257         PA_DEBUG(("\tFormatSize:%d, SampleSize:%d\n",dataRange->DataRange.FormatSize,dataRange->DataRange.SampleSize));
2258         PA_DEBUG(("\tMaxChannels:%d\n",dataRange->MaximumChannels));
2259         PA_DEBUG(("\tBits:%d-%d\n",dataRange->MinimumBitsPerSample,dataRange->MaximumBitsPerSample));
2260         PA_DEBUG(("\tSampleRate:%d-%d\n",dataRange->MinimumSampleFrequency,dataRange->MaximumSampleFrequency));
2261
2262         if( dataRange->MaximumChannels != (ULONG)-1 && 
2263             dataRange->MaximumChannels < format->nChannels )
2264         {
2265             result = paInvalidChannelCount;
2266             continue;
2267         }
2268
2269         if (pFormatExt != 0)
2270         {
2271             if (!IsBitsWithinRange(dataRange, pFormatExt->Samples.wValidBitsPerSample))
2272             {
2273                 result = paSampleFormatNotSupported;
2274                 continue;
2275             }
2276         }
2277         else
2278         {
2279             if (!IsBitsWithinRange(dataRange, format->wBitsPerSample))
2280             {
2281                 result = paSampleFormatNotSupported;
2282                 continue;
2283             }
2284         }
2285
2286         if (!IsFrequencyWithinRange(dataRange, format->nSamplesPerSec))
2287         {
2288             result = paInvalidSampleRate;
2289             continue;
2290         }
2291
2292         /* Success! */
2293         result = paNoError;
2294         break;
2295     }
2296
2297     PA_LOGL_;
2298     return result;
2299 }
2300
2301 static PaError PinQueryNotificationSupport(PaWinWdmPin* pPin, BOOL* pbResult)
2302 {
2303     PaError result = paNoError;
2304     KSPROPERTY propIn;
2305
2306     PA_LOGE_;
2307
2308     propIn.Set = KSPROPSETID_RtAudio;
2309     propIn.Id = 8; /* = KSPROPERTY_RTAUDIO_QUERY_NOTIFICATION_SUPPORT */
2310     propIn.Flags = KSPROPERTY_TYPE_GET;
2311
2312     result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
2313         &propIn,
2314         sizeof(KSPROPERTY),
2315         pbResult,
2316         sizeof(BOOL),
2317         NULL);
2318
2319     if (result != paNoError) 
2320     {
2321         PA_DEBUG(("Failed PinQueryNotificationSupport\n"));
2322     }
2323
2324     PA_LOGL_;
2325     return result;
2326 }
2327
2328 static PaError PinGetBufferWithNotification(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier)
2329 {
2330     PaError result = paNoError;
2331     KSRTAUDIO_BUFFER_PROPERTY_WITH_NOTIFICATION propIn;
2332     KSRTAUDIO_BUFFER propOut;
2333
2334     PA_LOGE_;
2335
2336     propIn.BaseAddress = 0;
2337     propIn.NotificationCount = 2;
2338     propIn.RequestedBufferSize = *pRequestedBufSize;
2339     propIn.Property.Set = KSPROPSETID_RtAudio;
2340     propIn.Property.Id = KSPROPERTY_RTAUDIO_BUFFER_WITH_NOTIFICATION;
2341     propIn.Property.Flags = KSPROPERTY_TYPE_GET;
2342
2343     result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
2344         &propIn,
2345         sizeof(KSRTAUDIO_BUFFER_PROPERTY_WITH_NOTIFICATION),
2346         &propOut,
2347         sizeof(KSRTAUDIO_BUFFER),
2348         NULL);
2349
2350     if (result == paNoError) 
2351     {
2352         *pBuffer = propOut.BufferAddress;
2353         *pRequestedBufSize = propOut.ActualBufferSize;
2354         *pbCallMemBarrier = propOut.CallMemoryBarrier;
2355     }
2356     else 
2357     {
2358         PA_DEBUG(("Failed to get buffer with notification\n"));
2359     }
2360
2361     PA_LOGL_;
2362     return result;
2363 }
2364
2365 static PaError PinGetBufferWithoutNotification(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier)
2366 {
2367     PaError result = paNoError;
2368     KSRTAUDIO_BUFFER_PROPERTY propIn;
2369     KSRTAUDIO_BUFFER propOut;
2370
2371     PA_LOGE_;
2372
2373     propIn.BaseAddress = NULL;
2374     propIn.RequestedBufferSize = *pRequestedBufSize;
2375     propIn.Property.Set = KSPROPSETID_RtAudio;
2376     propIn.Property.Id = KSPROPERTY_RTAUDIO_BUFFER;
2377     propIn.Property.Flags = KSPROPERTY_TYPE_GET;
2378
2379     result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
2380         &propIn,
2381         sizeof(KSRTAUDIO_BUFFER_PROPERTY),
2382         &propOut,
2383         sizeof(KSRTAUDIO_BUFFER),
2384         NULL);
2385
2386     if (result == paNoError)
2387     {
2388         *pBuffer = propOut.BufferAddress;
2389         *pRequestedBufSize = propOut.ActualBufferSize;
2390         *pbCallMemBarrier = propOut.CallMemoryBarrier;
2391     }
2392     else 
2393     {
2394         PA_DEBUG(("Failed to get buffer without notification\n"));
2395     }
2396
2397     PA_LOGL_;
2398     return result;
2399 }
2400
2401 /* greatest common divisor - PGCD in French */
2402 static unsigned long PaWinWDMGCD( unsigned long a, unsigned long b )
2403 {
2404     return (b==0) ? a : PaWinWDMGCD( b, a%b);
2405 }
2406
2407
2408 /* This function will handle getting the cyclic buffer from a WaveRT driver. Certain WaveRT drivers needs to have
2409 requested buffer size on multiples of 128 bytes:
2410
2411 */
2412 static PaError PinGetBuffer(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier)
2413 {
2414     PaError result = paNoError;
2415     int limit = 1000;
2416     PA_LOGE_;
2417
2418     while (1)
2419     {
2420         limit--;
2421         if (limit == 0) {
2422            PA_DEBUG(("PinGetBuffer: LOOP LIMIT REACHED\n"));
2423            break;
2424         }
2425
2426         if (pPin->pinKsSubType != SubType_kPolled)
2427         {
2428             /* In case of unknown (or notification), we try both modes */
2429             result = PinGetBufferWithNotification(pPin, pBuffer, pRequestedBufSize, pbCallMemBarrier);
2430             if (result == paNoError)
2431             {
2432                 PA_DEBUG(("PinGetBuffer: SubType_kNotification\n"));
2433                 pPin->pinKsSubType = SubType_kNotification;
2434                 break;
2435             }
2436         }
2437
2438         result = PinGetBufferWithoutNotification(pPin, pBuffer, pRequestedBufSize, pbCallMemBarrier);
2439         if (result == paNoError)
2440         {
2441             PA_DEBUG(("PinGetBuffer: SubType_kPolled\n"));
2442             pPin->pinKsSubType = SubType_kPolled;
2443             break;
2444         }
2445
2446         /* Check if requested size is on a 128 byte boundary */
2447         if (((*pRequestedBufSize) % 128UL) == 0)
2448         {
2449             PA_DEBUG(("Buffer size on 128 byte boundary, still fails :(\n"));
2450             /* Ok, can't do much more */
2451             break;
2452         }
2453         else
2454         {
2455             /* Compute LCM so we know which sizes are on a 128 byte boundary */
2456             const unsigned gcd = PaWinWDMGCD(128UL, pPin->ksDataFormatWfx->WaveFormatEx.nBlockAlign);
2457             const unsigned lcm = (128UL * pPin->ksDataFormatWfx->WaveFormatEx.nBlockAlign) / gcd;
2458             DWORD dwOldSize = *pRequestedBufSize;
2459
2460             /* Align size to (next larger) LCM byte boundary, and then we try again. Note that LCM is not necessarily a
2461             power of 2. */
2462             *pRequestedBufSize = ((*pRequestedBufSize + lcm - 1) / lcm) * lcm;
2463
2464             PA_DEBUG(("Adjusting buffer size from %u to %u bytes (128 byte boundary, LCM=%u)\n", dwOldSize, *pRequestedBufSize, lcm));
2465         }
2466     }
2467
2468     PA_LOGL_;
2469
2470     return result;
2471 }
2472
2473 static PaError PinRegisterPositionRegister(PaWinWdmPin* pPin) 
2474 {
2475     PaError result = paNoError;
2476     KSRTAUDIO_HWREGISTER_PROPERTY propIn;
2477     KSRTAUDIO_HWREGISTER propOut;
2478
2479     PA_LOGE_;
2480
2481     propIn.BaseAddress = NULL;
2482     propIn.Property.Set = KSPROPSETID_RtAudio;
2483     propIn.Property.Id = KSPROPERTY_RTAUDIO_POSITIONREGISTER;
2484     propIn.Property.Flags = KSPROPERTY_TYPE_SET;
2485
2486     result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
2487         &propIn,
2488         sizeof(KSRTAUDIO_HWREGISTER_PROPERTY),
2489         &propOut,
2490         sizeof(KSRTAUDIO_HWREGISTER),
2491         NULL);
2492
2493     if (result == paNoError) 
2494     {
2495         pPin->positionRegister = (ULONG*)propOut.Register;
2496     }
2497     else
2498     {
2499         PA_DEBUG(("Failed to register position register\n"));
2500     }
2501
2502     PA_LOGL_;
2503
2504     return result;
2505 }
2506
2507 static PaError PinRegisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle) 
2508 {
2509     PaError result = paNoError;
2510     KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY prop;
2511
2512     PA_LOGE_;
2513
2514     prop.NotificationEvent = handle;
2515     prop.Property.Set = KSPROPSETID_RtAudio;
2516     prop.Property.Id = KSPROPERTY_RTAUDIO_REGISTER_NOTIFICATION_EVENT;
2517     prop.Property.Flags = KSPROPERTY_TYPE_SET;
2518
2519     result = WdmSyncIoctl(pPin->handle,
2520         IOCTL_KS_PROPERTY,
2521         &prop,
2522         sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY),
2523         &prop,
2524         sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY),
2525         NULL);
2526
2527     if (result != paNoError) {
2528         PA_DEBUG(("Failed to register notification handle 0x%08X\n", handle));
2529     }
2530
2531     PA_LOGL_;
2532
2533     return result;
2534 }
2535
2536 static PaError PinUnregisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle) 
2537 {
2538     PaError result = paNoError;
2539     KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY prop;
2540
2541     PA_LOGE_;
2542
2543     if (handle != NULL)
2544     {
2545         prop.NotificationEvent = handle;
2546         prop.Property.Set = KSPROPSETID_RtAudio;
2547         prop.Property.Id = KSPROPERTY_RTAUDIO_UNREGISTER_NOTIFICATION_EVENT;
2548         prop.Property.Flags = KSPROPERTY_TYPE_SET;
2549
2550         result = WdmSyncIoctl(pPin->handle,
2551             IOCTL_KS_PROPERTY,
2552             &prop,
2553             sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY),
2554             &prop,
2555             sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY),
2556             NULL);
2557
2558         if (result != paNoError) {
2559             PA_DEBUG(("Failed to unregister notification handle 0x%08X\n", handle));
2560         }
2561     }
2562     PA_LOGL_;
2563
2564     return result;
2565 }
2566
2567 static PaError PinGetHwLatency(PaWinWdmPin* pPin, ULONG* pFifoSize, ULONG* pChipsetDelay, ULONG* pCodecDelay)
2568 {
2569     PaError result = paNoError;
2570     KSPROPERTY propIn;
2571     KSRTAUDIO_HWLATENCY propOut;
2572
2573     PA_LOGE_;
2574
2575     propIn.Set = KSPROPSETID_RtAudio;
2576     propIn.Id = KSPROPERTY_RTAUDIO_HWLATENCY;
2577     propIn.Flags = KSPROPERTY_TYPE_GET;
2578
2579     result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
2580         &propIn,
2581         sizeof(KSPROPERTY),
2582         &propOut,
2583         sizeof(KSRTAUDIO_HWLATENCY),
2584         NULL);
2585
2586     if (result == paNoError)
2587     {
2588         *pFifoSize = propOut.FifoSize;
2589         *pChipsetDelay = propOut.ChipsetDelay;
2590         *pCodecDelay = propOut.CodecDelay;
2591     }
2592     else
2593     {
2594         PA_DEBUG(("Failed to retrieve hardware FIFO size!\n"));
2595     }
2596
2597     PA_LOGL_;
2598
2599     return result;
2600 }
2601
2602 /* This one is used for WaveRT */
2603 static PaError PinGetAudioPositionMemoryMapped(PaWinWdmPin* pPin, ULONG* pPosition)
2604 {
2605     *pPosition = (*pPin->positionRegister);
2606     return paNoError;
2607 }
2608
2609 /* This one also, but in case the driver hasn't implemented memory mapped access to the position register */
2610 static PaError PinGetAudioPositionViaIOCTLRead(PaWinWdmPin* pPin, ULONG* pPosition)
2611 {
2612     PaError result = paNoError;
2613     KSPROPERTY propIn;
2614     KSAUDIO_POSITION propOut;
2615
2616     PA_LOGE_;
2617
2618     propIn.Set = KSPROPSETID_Audio;
2619     propIn.Id = KSPROPERTY_AUDIO_POSITION;
2620     propIn.Flags = KSPROPERTY_TYPE_GET;
2621
2622     result = WdmSyncIoctl(pPin->handle,
2623         IOCTL_KS_PROPERTY,
2624         &propIn, sizeof(KSPROPERTY),
2625         &propOut, sizeof(KSAUDIO_POSITION),
2626         NULL);
2627
2628     if (result == paNoError)
2629     {
2630         *pPosition = (ULONG)(propOut.PlayOffset);
2631     }
2632     else
2633     {
2634         PA_DEBUG(("Failed to get audio play position!\n"));
2635     }
2636
2637     PA_LOGL_;
2638
2639     return result;
2640
2641 }
2642
2643 /* This one also, but in case the driver hasn't implemented memory mapped access to the position register */
2644 static PaError PinGetAudioPositionViaIOCTLWrite(PaWinWdmPin* pPin, ULONG* pPosition)
2645 {
2646     PaError result = paNoError;
2647     KSPROPERTY propIn;
2648     KSAUDIO_POSITION propOut;
2649
2650     PA_LOGE_;
2651
2652     propIn.Set = KSPROPSETID_Audio;
2653     propIn.Id = KSPROPERTY_AUDIO_POSITION;
2654     propIn.Flags = KSPROPERTY_TYPE_GET;
2655
2656     result = WdmSyncIoctl(pPin->handle,
2657         IOCTL_KS_PROPERTY,
2658         &propIn, sizeof(KSPROPERTY),
2659         &propOut, sizeof(KSAUDIO_POSITION),
2660         NULL);
2661
2662     if (result == paNoError)
2663     {
2664         *pPosition = (ULONG)(propOut.WriteOffset);
2665     }
2666     else
2667     {
2668         PA_DEBUG(("Failed to get audio write position!\n"));
2669     }
2670
2671     PA_LOGL_;
2672
2673     return result;
2674
2675 }
2676
2677 /***********************************************************************************************/
2678
2679 /**
2680 * Create a new filter object. 
2681 */
2682 static PaWinWdmFilter* FilterNew( PaWDMKSType type, DWORD devNode, const wchar_t* filterName, const wchar_t* friendlyName, PaError* error )
2683 {
2684     PaWinWdmFilter* filter = 0;
2685     PaError result;
2686
2687     /* Allocate the new filter object */
2688     filter = (PaWinWdmFilter*)PaUtil_AllocateMemory( sizeof(PaWinWdmFilter) );
2689     if( !filter )
2690     {
2691         result = paInsufficientMemory;
2692         goto error;
2693     }
2694
2695     PA_DEBUG(("FilterNew: Creating filter '%S'\n", friendlyName));
2696
2697     /* Set type flag */
2698     filter->devInfo.streamingType = type;
2699
2700     /* Store device node */
2701     filter->deviceNode = devNode;
2702
2703     /* Zero the filter object - done by AllocateMemory */
2704     /* memset( (void*)filter, 0, sizeof(PaWinWdmFilter) ); */
2705
2706     /* Copy the filter name */
2707     wcsncpy(filter->devInfo.filterPath, filterName, MAX_PATH);
2708
2709     /* Copy the friendly name */
2710     wcsncpy(filter->friendlyName, friendlyName, MAX_PATH);
2711
2712     PA_DEBUG(("FilterNew: Opening filter...\n", friendlyName));
2713
2714     /* Open the filter handle */
2715     result = FilterUse(filter);
2716     if( result != paNoError )
2717     {
2718         goto error;
2719     }
2720
2721     /* Get pin count */
2722     result = WdmGetPinPropertySimple
2723         (
2724         filter->handle,
2725         0,
2726         &KSPROPSETID_Pin,
2727         KSPROPERTY_PIN_CTYPES,
2728         &filter->pinCount,
2729         sizeof(filter->pinCount),
2730         NULL);
2731
2732     if( result != paNoError)
2733     {
2734         goto error;
2735     }
2736
2737     /* Get connections & nodes for filter */
2738     result = WdmGetPropertyMulti(
2739         filter->handle,
2740         &KSPROPSETID_Topology,
2741         KSPROPERTY_TOPOLOGY_CONNECTIONS,
2742         &filter->connections);
2743
2744     if( result != paNoError)
2745     {
2746         goto error;
2747     }
2748
2749     result = WdmGetPropertyMulti(
2750         filter->handle,
2751         &KSPROPSETID_Topology,
2752         KSPROPERTY_TOPOLOGY_NODES,
2753         &filter->nodes);
2754
2755     if( result != paNoError)
2756     {
2757         goto error;
2758     }
2759
2760     /* For debugging purposes */
2761     DumpConnectionsAndNodes(filter);
2762
2763     /* Get product GUID (it might not be supported) */
2764     {
2765         KSCOMPONENTID compId;
2766         if (WdmGetPropertySimple(filter->handle, &KSPROPSETID_General, KSPROPERTY_GENERAL_COMPONENTID, &compId, sizeof(KSCOMPONENTID)) == paNoError)
2767         {
2768             filter->devInfo.deviceProductGuid = compId.Product;
2769         }
2770     }
2771
2772     /* This section is not executed for topology filters */
2773     if (type != Type_kNotUsed)
2774     {
2775         /* Initialize the pins */
2776         result = FilterInitializePins(filter);
2777
2778         if( result != paNoError)
2779         {
2780             goto error;
2781         }
2782     }
2783
2784     /* Close the filter handle for now
2785     * It will be opened later when needed */
2786     FilterRelease(filter);
2787
2788     *error = paNoError;
2789     return filter;
2790
2791 error:
2792     PA_DEBUG(("FilterNew: Error %d\n", result));
2793     /*
2794     Error cleanup
2795     */
2796     FilterFree(filter);
2797
2798     *error = result;
2799     return NULL;
2800 }
2801
2802 /**
2803 * Add reference to filter
2804 */
2805 static void FilterAddRef( PaWinWdmFilter* filter )
2806 {
2807     if (filter != 0)
2808     {
2809         filter->filterRefCount++;
2810     }
2811 }
2812
2813
2814 /**
2815 * Initialize the pins of the filter. This is separated from FilterNew because this might fail if there is another
2816 * process using the pin(s).
2817 */
2818 PaError FilterInitializePins( PaWinWdmFilter* filter )
2819 {
2820     PaError result = paNoError;
2821     int pinId;
2822
2823     if (filter->devInfo.streamingType == Type_kNotUsed)
2824         return paNoError;
2825
2826     if (filter->pins != NULL)
2827         return paNoError;   
2828
2829     /* Allocate pointer array to hold the pins */
2830     filter->pins = (PaWinWdmPin**)PaUtil_AllocateMemory( sizeof(PaWinWdmPin*) * filter->pinCount );
2831     if( !filter->pins )
2832     {
2833         result = paInsufficientMemory;
2834         goto error;
2835     }
2836
2837     /* Create all the pins we can */
2838     for(pinId = 0; pinId < filter->pinCount; pinId++)
2839     {
2840         /* Create the pin with this Id */
2841         PaWinWdmPin* newPin;
2842         newPin = PinNew(filter, pinId, &result);
2843         if( result == paInsufficientMemory )
2844             goto error;
2845         if( newPin != NULL )
2846         {
2847             filter->pins[pinId] = newPin;
2848             ++filter->validPinCount;
2849         }
2850     }
2851
2852     if (filter->validPinCount == 0)
2853     {
2854         result = paDeviceUnavailable;
2855         goto error;
2856     }
2857
2858     return paNoError;
2859
2860 error:
2861
2862     if (filter->pins)
2863     {
2864         for (pinId = 0; pinId < filter->pinCount; ++pinId)
2865         {
2866             if (filter->pins[pinId])
2867             {
2868                 PinFree(filter->pins[pinId]);
2869                 filter->pins[pinId] = 0;
2870             }
2871         }
2872         PaUtil_FreeMemory( filter->pins );
2873         filter->pins = 0;
2874     }
2875
2876     return result;
2877 }
2878
2879
2880 /**
2881 * Free a previously created filter
2882 */
2883 static void FilterFree(PaWinWdmFilter* filter)
2884 {
2885     PA_LOGL_;
2886     if( filter )
2887     {
2888         if (--filter->filterRefCount > 0)
2889         {
2890             /* Ok, a stream has a ref count to this filter */
2891             return;
2892         }
2893
2894         if ( filter->topologyFilter )
2895         {
2896             FilterFree(filter->topologyFilter);
2897             filter->topologyFilter = 0;
2898         }
2899         if ( filter->pins )
2900         {
2901             int pinId;
2902             for( pinId = 0; pinId < filter->pinCount; pinId++ )
2903                 PinFree(filter->pins[pinId]);
2904             PaUtil_FreeMemory( filter->pins );
2905             filter->pins = 0;
2906         }
2907         if( filter->connections )
2908         {
2909             PaUtil_FreeMemory(filter->connections);
2910             filter->connections = 0;
2911         }
2912         if( filter->nodes )
2913         {
2914             PaUtil_FreeMemory(filter->nodes);
2915             filter->nodes = 0;
2916         }
2917         if( filter->handle )
2918             CloseHandle( filter->handle );
2919         PaUtil_FreeMemory( filter );
2920     }
2921     PA_LOGE_;
2922 }
2923
2924 /**
2925 * Reopen the filter handle if necessary so it can be used
2926 **/
2927 static PaError FilterUse(PaWinWdmFilter* filter)
2928 {
2929     assert( filter );
2930
2931     PA_LOGE_;
2932     if( filter->handle == NULL )
2933     {
2934         /* Open the filter */
2935         filter->handle = CreateFileW(
2936             filter->devInfo.filterPath,
2937             GENERIC_READ | GENERIC_WRITE,
2938             0,
2939             NULL,
2940             OPEN_EXISTING,
2941             FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
2942             NULL);
2943
2944         if( filter->handle == NULL )
2945         {
2946             return paDeviceUnavailable;
2947         }
2948     }
2949     filter->usageCount++;
2950     PA_LOGL_;
2951     return paNoError;
2952 }
2953
2954 /**
2955 * Release the filter handle if nobody is using it
2956 **/
2957 static void FilterRelease(PaWinWdmFilter* filter)
2958 {
2959     assert( filter );
2960     assert( filter->usageCount > 0 );
2961
2962     PA_LOGE_;
2963     /* Check first topology filter, if used */
2964     if (filter->topologyFilter != NULL && filter->topologyFilter->handle != NULL)
2965     {
2966         FilterRelease(filter->topologyFilter);
2967     }
2968
2969     filter->usageCount--;
2970     if( filter->usageCount == 0 )
2971     {
2972         if( filter->handle != NULL )
2973         {
2974             CloseHandle( filter->handle );
2975             filter->handle = NULL;
2976         }
2977     }
2978     PA_LOGL_;
2979 }
2980
2981 /**
2982 * Create a render or playback pin using the supplied format
2983 **/
2984 static PaWinWdmPin* FilterCreatePin(PaWinWdmFilter* filter,
2985                                     int pinId,
2986                                     const WAVEFORMATEX* wfex,
2987                                     PaError* error)
2988 {
2989     PaError result = paNoError;
2990     PaWinWdmPin* pin = NULL;
2991     assert( filter );
2992     assert( pinId < filter->pinCount );
2993     pin = filter->pins[pinId];
2994     assert( pin );
2995     result = PinSetFormat(pin,wfex);
2996     if( result == paNoError )
2997     {
2998         result = PinInstantiate(pin);
2999     }
3000     *error = result;
3001     return result == paNoError ? pin : 0;
3002 }
3003
3004 static const wchar_t kUsbPrefix[] = L"\\\\?\\USB";
3005
3006 static BOOL IsUSBDevice(const wchar_t* devicePath)
3007 {
3008     /* Alex Lessard pointed out that different devices might present the device path with
3009        lower case letters. */
3010     return (_wcsnicmp(devicePath, kUsbPrefix, sizeof(kUsbPrefix)/sizeof(kUsbPrefix[0]) ) == 0);
3011 }
3012
3013 /* This should make it more language tolerant, I hope... */
3014 static const wchar_t kUsbNamePrefix[] = L"USB Audio";
3015
3016 static BOOL IsNameUSBAudioDevice(const wchar_t* friendlyName)
3017 {
3018     return (_wcsnicmp(friendlyName, kUsbNamePrefix, sizeof(kUsbNamePrefix)/sizeof(kUsbNamePrefix[0])) == 0);
3019 }
3020
3021 typedef enum _tag_EAlias
3022 {
3023     Alias_kRender   = (1<<0),
3024     Alias_kCapture  = (1<<1),
3025     Alias_kRealtime = (1<<2),
3026 } EAlias;
3027
3028 /* Trim whitespace from string */
3029 static void TrimString(wchar_t* str, size_t length)
3030 {
3031     wchar_t* s = str;
3032     wchar_t* e = 0;
3033
3034     /* Find start of string */
3035     while (iswspace(*s)) ++s;
3036     e=s+min(length,wcslen(s))-1;
3037
3038     /* Find end of string */
3039     while(e>s && iswspace(*e)) --e;
3040     ++e;
3041
3042     length = e - s;
3043     memmove(str, s, length * sizeof(wchar_t));
3044     str[length] = 0;
3045 }
3046
3047 /**
3048 * Build the list of available filters
3049 * Use the SetupDi API to enumerate all devices in the KSCATEGORY_AUDIO which 
3050 * have a KSCATEGORY_RENDER or KSCATEGORY_CAPTURE alias. For each of these 
3051 * devices initialise a PaWinWdmFilter structure by calling our NewFilter() 
3052 * function. We enumerate devices twice, once to count how many there are, 
3053 * and once to initialize the PaWinWdmFilter structures.
3054 *
3055 * Vista and later: Also check KSCATEGORY_REALTIME for WaveRT devices.
3056 */
3057 //PaError BuildFilterList( PaWinWdmHostApiRepresentation* wdmHostApi, int* noOfPaDevices )
3058 PaWinWdmFilter** BuildFilterList( int* pFilterCount, int* pNoOfPaDevices, PaError* pResult )
3059 {
3060     PaWinWdmFilter** ppFilters = NULL;
3061     HDEVINFO handle = NULL;
3062     int device;
3063     int invalidDevices;
3064     int slot;
3065     SP_DEVICE_INTERFACE_DATA interfaceData;
3066     SP_DEVICE_INTERFACE_DATA aliasData;
3067     SP_DEVINFO_DATA devInfoData;
3068     int noError;
3069     const int sizeInterface = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR));
3070     unsigned char interfaceDetailsArray[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR))];
3071     SP_DEVICE_INTERFACE_DETAIL_DATA_W* devInterfaceDetails = (SP_DEVICE_INTERFACE_DETAIL_DATA_W*)interfaceDetailsArray;
3072     const GUID* category = (const GUID*)&KSCATEGORY_AUDIO;
3073     const GUID* alias_render = (const GUID*)&KSCATEGORY_RENDER;
3074     const GUID* alias_capture = (const GUID*)&KSCATEGORY_CAPTURE;
3075     const GUID* category_realtime = (const GUID*)&KSCATEGORY_REALTIME;
3076     DWORD aliasFlags;
3077     PaWDMKSType streamingType;
3078     int filterCount = 0;
3079     int noOfPaDevices = 0;
3080
3081     PA_LOGE_;
3082
3083     assert(pFilterCount != NULL);
3084     assert(pNoOfPaDevices != NULL);
3085     assert(pResult != NULL);
3086
3087     devInterfaceDetails->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
3088     *pFilterCount = 0;
3089     *pNoOfPaDevices = 0;
3090
3091     /* Open a handle to search for devices (filters) */
3092     handle = SetupDiGetClassDevs(category,NULL,NULL,DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
3093     if( handle == INVALID_HANDLE_VALUE )
3094     {
3095         *pResult = paUnanticipatedHostError;
3096         return NULL;
3097     }
3098     PA_DEBUG(("Setup called\n"));
3099
3100     /* First let's count the number of devices so we can allocate a list */
3101     invalidDevices = 0;
3102     for( device = 0;;device++ )
3103     {
3104         interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
3105         interfaceData.Reserved = 0;
3106         aliasData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
3107         aliasData.Reserved = 0;
3108         noError = SetupDiEnumDeviceInterfaces(handle,NULL,category,device,&interfaceData);
3109         PA_DEBUG(("Enum called\n"));
3110         if( !noError )
3111             break; /* No more devices */
3112
3113         /* Check this one has the render or capture alias */
3114         aliasFlags = 0;
3115         noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_render,&aliasData);
3116         PA_DEBUG(("noError = %d\n",noError));
3117         if(noError)
3118         {
3119             if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
3120             {
3121                 PA_DEBUG(("Device %d has render alias\n",device));
3122                 aliasFlags |= Alias_kRender; /* Has render alias */
3123             }
3124             else
3125             {
3126                 PA_DEBUG(("Device %d has no render alias\n",device));
3127             }
3128         }
3129         noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_capture,&aliasData);
3130         if(noError)
3131         {
3132             if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
3133             {
3134                 PA_DEBUG(("Device %d has capture alias\n",device));
3135                 aliasFlags |= Alias_kCapture; /* Has capture alias */
3136             }
3137             else
3138             {
3139                 PA_DEBUG(("Device %d has no capture alias\n",device));
3140             }
3141         }
3142         if(!aliasFlags)
3143             invalidDevices++; /* This was not a valid capture or render audio device */
3144     }
3145     /* Remember how many there are */
3146     filterCount = device-invalidDevices;
3147
3148     PA_DEBUG(("Interfaces found: %d\n",device-invalidDevices));
3149
3150     /* Now allocate the list of pointers to devices */
3151     ppFilters  = (PaWinWdmFilter**)PaUtil_AllocateMemory( sizeof(PaWinWdmFilter*) * filterCount);
3152     if( ppFilters == 0 )
3153     {
3154         if(handle != NULL)
3155             SetupDiDestroyDeviceInfoList(handle);
3156         *pResult = paInsufficientMemory;
3157         return NULL;
3158     }
3159
3160     /* Now create filter objects for each interface found */
3161     slot = 0;
3162     for( device = 0;;device++ )
3163     {
3164         interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
3165         interfaceData.Reserved = 0;
3166         aliasData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
3167         aliasData.Reserved = 0;
3168         devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
3169         devInfoData.Reserved = 0;
3170         streamingType = Type_kWaveCyclic;
3171
3172         noError = SetupDiEnumDeviceInterfaces(handle,NULL,category,device,&interfaceData);
3173         if( !noError )
3174             break; /* No more devices */
3175
3176         /* Check this one has the render or capture alias */
3177         aliasFlags = 0;
3178         noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_render,&aliasData);
3179         if(noError)
3180         {
3181             if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
3182             {
3183                 PA_DEBUG(("Device %d has render alias\n",device));
3184                 aliasFlags |= Alias_kRender; /* Has render alias */
3185             }
3186         }
3187         noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_capture,&aliasData);
3188         if(noError)
3189         {
3190             if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
3191             {
3192                 PA_DEBUG(("Device %d has capture alias\n",device));
3193                 aliasFlags |= Alias_kCapture; /* Has capture alias */
3194             }
3195         }
3196         if(!aliasFlags)
3197         {
3198             continue; /* This was not a valid capture or render audio device */
3199         }
3200         else
3201         {
3202             /* Check if filter is WaveRT, if not it is a WaveCyclic */
3203             noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,category_realtime,&aliasData);
3204             if (noError)
3205             {
3206                 PA_DEBUG(("Device %d has realtime alias\n",device));
3207                 aliasFlags |= Alias_kRealtime;
3208                 streamingType = Type_kWaveRT;
3209             }
3210         }
3211
3212         noError = SetupDiGetDeviceInterfaceDetailW(handle,&interfaceData,devInterfaceDetails,sizeInterface,NULL,&devInfoData);
3213         if( noError )
3214         {
3215             DWORD type;
3216             WCHAR friendlyName[MAX_PATH] = {0};
3217             DWORD sizeFriendlyName;
3218             PaWinWdmFilter* newFilter = 0;
3219
3220             PaError result = paNoError;
3221             /* Try to get the "friendly name" for this interface */
3222             sizeFriendlyName = sizeof(friendlyName);
3223
3224             if (IsEarlierThanVista() && IsUSBDevice(devInterfaceDetails->DevicePath))
3225             {
3226                 /* XP and USB audio device needs to look elsewhere, otherwise it'll only be a "USB Audio Device". Not
3227                 very literate. */
3228                 if (!SetupDiGetDeviceRegistryPropertyW(handle,
3229                     &devInfoData,
3230                     SPDRP_LOCATION_INFORMATION, 
3231                     &type,
3232                     (BYTE*)friendlyName,
3233                     sizeof(friendlyName),
3234                     NULL))
3235                 {
3236                     friendlyName[0] = 0;
3237                 }
3238             }
3239
3240             if (friendlyName[0] == 0 || IsNameUSBAudioDevice(friendlyName))
3241             {
3242                 /* Fix contributed by Ben Allison
3243                 * Removed KEY_SET_VALUE from flags on following call
3244                 * as its causes failure when running without admin rights
3245                 * and it was not required */
3246                 HKEY hkey=SetupDiOpenDeviceInterfaceRegKey(handle,&interfaceData,0,KEY_QUERY_VALUE);
3247                 if(hkey!=INVALID_HANDLE_VALUE)
3248                 {
3249                     noError = RegQueryValueExW(hkey,L"FriendlyName",0,&type,(BYTE*)friendlyName,&sizeFriendlyName);
3250                     if( noError == ERROR_SUCCESS )
3251                     {
3252                         PA_DEBUG(("Interface %d, Name: %s\n",device,friendlyName));
3253                         RegCloseKey(hkey);
3254                     }
3255                     else
3256                     {
3257                         friendlyName[0] = 0;
3258                     }
3259                 }
3260             }
3261
3262             TrimString(friendlyName, sizeFriendlyName);
3263
3264             newFilter = FilterNew(streamingType, 
3265                 devInfoData.DevInst,
3266                 devInterfaceDetails->DevicePath,
3267                 friendlyName,
3268                 &result);
3269
3270             if( result == paNoError )
3271             {
3272                 int pin;
3273                 unsigned filterIOs = 0;
3274
3275                 /* Increment number of "devices" */
3276                 for (pin = 0; pin < newFilter->pinCount; ++pin)
3277                 {
3278                     PaWinWdmPin* pPin = newFilter->pins[pin];
3279                     if (pPin == NULL)
3280                         continue;
3281
3282                     filterIOs += max(1, pPin->inputCount);
3283                 }
3284
3285                 noOfPaDevices += filterIOs;
3286
3287                 PA_DEBUG(("Filter (%s) created with %d valid pins (total I/Os: %u)\n", ((newFilter->devInfo.streamingType==Type_kWaveRT)?"WaveRT":"WaveCyclic"), newFilter->validPinCount, filterIOs));
3288
3289                 assert(slot < filterCount);
3290
3291                 ppFilters[slot] = newFilter;
3292
3293                 slot++;
3294             }
3295             else
3296             {
3297                 PA_DEBUG(("Filter NOT created\n"));
3298                 /* As there are now less filters than we initially thought
3299                 * we must reduce the count by one */
3300                 filterCount--;
3301             }
3302         }
3303     }
3304
3305     /* Clean up */
3306     if(handle != NULL)
3307         SetupDiDestroyDeviceInfoList(handle);
3308
3309     *pFilterCount = filterCount;
3310     *pNoOfPaDevices = noOfPaDevices;
3311
3312     return ppFilters;
3313 }
3314
3315 typedef struct PaNameHashIndex
3316 {
3317     unsigned index;
3318     unsigned count;
3319     ULONG    hash;
3320     struct PaNameHashIndex *next;
3321 } PaNameHashIndex;
3322
3323 typedef struct PaNameHashObject
3324 {
3325     PaNameHashIndex* list;
3326     PaUtilAllocationGroup* allocGroup;
3327 } PaNameHashObject;
3328
3329 static ULONG GetNameHash(const wchar_t* str, const BOOL input)
3330 {
3331     /* This is to make sure that a name that exists as both input & output won't get the same hash value */
3332     const ULONG fnv_prime = (input ? 0x811C9DD7 : 0x811FEB0B);
3333     ULONG hash = 0;
3334     for(; *str != 0; str++)
3335     {
3336         hash *= fnv_prime;
3337         hash ^= (*str);
3338     }
3339     assert(hash != 0);
3340     return hash;
3341 }
3342
3343 static PaError CreateHashEntry(PaNameHashObject* obj, const wchar_t* name, const BOOL input)
3344 {
3345     ULONG hash = GetNameHash(name, input); 
3346     PaNameHashIndex * pLast = NULL;
3347     PaNameHashIndex * p = obj->list;
3348     while (p != 0)
3349     {
3350         if (p->hash == hash)
3351         {
3352             break;
3353         }
3354         pLast = p;
3355         p = p->next;
3356     }
3357     if (p == NULL)
3358     {
3359         p = (PaNameHashIndex*)PaUtil_GroupAllocateMemory(obj->allocGroup, sizeof(PaNameHashIndex));
3360         if (p == NULL)
3361         {
3362             return paInsufficientMemory;
3363         }
3364         p->hash = hash;
3365         p->count = 1;
3366         if (pLast != 0)
3367         {
3368             assert(pLast->next == 0);
3369             pLast->next = p;
3370         }
3371         if (obj->list == 0)
3372         {
3373             obj->list = p;
3374         }
3375     }
3376     else
3377     {
3378         ++p->count;
3379     }
3380     return paNoError;
3381 }
3382
3383 static PaError InitNameHashObject(PaNameHashObject* obj, PaWinWdmFilter* pFilter)
3384 {
3385     int i;
3386
3387     obj->allocGroup = PaUtil_CreateAllocationGroup();
3388     if (obj->allocGroup == NULL)
3389     {
3390         return paInsufficientMemory;
3391     }
3392
3393     for (i = 0; i < pFilter->pinCount; ++i)
3394     {
3395         unsigned m;
3396         PaWinWdmPin* pin = pFilter->pins[i];
3397
3398         if (pin == NULL)
3399             continue;
3400
3401         for (m = 0; m < max(1, pin->inputCount); ++m)
3402         {
3403             const BOOL isInput = (pin->dataFlow == KSPIN_DATAFLOW_OUT);
3404             const wchar_t* name = (pin->inputs == NULL) ? pin->friendlyName : pin->inputs[m]->friendlyName;
3405
3406             PaError result = CreateHashEntry(obj, name, isInput);
3407
3408             if (result != paNoError)
3409             {
3410                 return result;
3411             }
3412         }
3413     }
3414     return paNoError;
3415 }
3416
3417 static void DeinitNameHashObject(PaNameHashObject* obj)
3418 {
3419     assert(obj != 0);
3420     PaUtil_FreeAllAllocations(obj->allocGroup);
3421     PaUtil_DestroyAllocationGroup(obj->allocGroup);
3422     memset(obj, 0, sizeof(PaNameHashObject));
3423 }
3424
3425 static unsigned GetNameIndex(PaNameHashObject* obj, const wchar_t* name, const BOOL input)
3426 {
3427     ULONG hash = GetNameHash(name, input); 
3428     PaNameHashIndex* p = obj->list;
3429     while (p != NULL)
3430     {
3431         if (p->hash == hash)
3432         {
3433             if (p->count > 1)
3434             {
3435                 return (++p->index);
3436             }
3437             else
3438             {
3439                 return 0;
3440             }
3441         }
3442
3443         p = p->next;
3444     }
3445     // Should never get here!!
3446     assert(FALSE);
3447     return 0;
3448 }
3449
3450 static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex, void **scanResults, int *newDeviceCount )
3451 {
3452     PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
3453     PaError result = paNoError;
3454     PaWinWdmFilter** ppFilters = 0;
3455     PaWinWDMScanDeviceInfosResults *outArgument = 0;
3456     int filterCount = 0;
3457     int totalDeviceCount = 0;
3458     int idxDevice = 0;
3459     DWORD defaultInDevPathSize = 0;
3460     DWORD defaultOutDevPathSize = 0;
3461     wchar_t* defaultInDevPath = 0;
3462     wchar_t* defaultOutDevPath = 0;
3463
3464     ppFilters = BuildFilterList( &filterCount, &totalDeviceCount, &result );
3465     if( result != paNoError )
3466     {
3467         goto error;
3468     }
3469
3470     // Get hold of default device paths for capture & playback
3471     if( waveInMessage(0, DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&defaultInDevPathSize, 0 ) == MMSYSERR_NOERROR )
3472     {
3473         defaultInDevPath = (wchar_t *)PaUtil_AllocateMemory((defaultInDevPathSize + 1) * sizeof(wchar_t));
3474         waveInMessage(0, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)defaultInDevPath, defaultInDevPathSize);
3475     }
3476     if( waveOutMessage(0, DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&defaultOutDevPathSize, 0 ) == MMSYSERR_NOERROR )
3477     {
3478         defaultOutDevPath = (wchar_t *)PaUtil_AllocateMemory((defaultOutDevPathSize + 1) * sizeof(wchar_t));
3479         waveOutMessage(0, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)defaultOutDevPath, defaultOutDevPathSize);
3480     }
3481
3482     if( totalDeviceCount > 0 )
3483     {
3484         PaWinWdmDeviceInfo *deviceInfoArray = 0;
3485         int idxFilter;
3486         int i;
3487         unsigned devIsDefaultIn = 0, devIsDefaultOut = 0;
3488
3489         /* Allocate the out param for all the info we need */
3490         outArgument = (PaWinWDMScanDeviceInfosResults *) PaUtil_GroupAllocateMemory(
3491             wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults) );
3492         if( !outArgument )
3493         {
3494             result = paInsufficientMemory;
3495             goto error;
3496         }
3497
3498         outArgument->defaultInputDevice  = paNoDevice;
3499         outArgument->defaultOutputDevice = paNoDevice;
3500
3501         outArgument->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
3502             wdmHostApi->allocations, sizeof(PaDeviceInfo*) * totalDeviceCount );
3503         if( !outArgument->deviceInfos )
3504         {
3505             result = paInsufficientMemory;
3506             goto error;
3507         }
3508
3509         /* allocate all device info structs in a contiguous block */
3510         deviceInfoArray = (PaWinWdmDeviceInfo*)PaUtil_GroupAllocateMemory(
3511             wdmHostApi->allocations, sizeof(PaWinWdmDeviceInfo) * totalDeviceCount );
3512         if( !deviceInfoArray )
3513         {
3514             result = paInsufficientMemory;
3515             goto error;
3516         }
3517
3518         /* Make sure all items in array */
3519         for( i = 0 ; i < totalDeviceCount; ++i )
3520         {
3521             PaDeviceInfo *deviceInfo  = &deviceInfoArray[i].inheritedDeviceInfo;
3522             deviceInfo->structVersion = 2;
3523             deviceInfo->hostApi       = hostApiIndex;
3524             deviceInfo->name          = 0;
3525             outArgument->deviceInfos[ i ] = deviceInfo;
3526         }
3527
3528         idxDevice = 0;
3529         for (idxFilter = 0; idxFilter < filterCount; ++idxFilter)
3530         {
3531             PaNameHashObject nameHash = {0};
3532             PaWinWdmFilter* pFilter = ppFilters[idxFilter];
3533             if( pFilter == NULL )
3534                 continue;
3535
3536             if (InitNameHashObject(&nameHash, pFilter) != paNoError)
3537             {
3538                 DeinitNameHashObject(&nameHash);
3539                 continue;
3540             }
3541
3542             devIsDefaultIn = (defaultInDevPath && (_wcsicmp(pFilter->devInfo.filterPath, defaultInDevPath) == 0));
3543             devIsDefaultOut = (defaultOutDevPath && (_wcsicmp(pFilter->devInfo.filterPath, defaultOutDevPath) == 0));
3544
3545             for (i = 0; i < pFilter->pinCount; ++i)
3546             {
3547                 unsigned m;
3548                 ULONG nameIndex = 0;
3549                 ULONG nameIndexHash = 0;
3550                 PaWinWdmPin* pin = pFilter->pins[i];
3551
3552                 if (pin == NULL)
3553                     continue;
3554
3555                 for (m = 0; m < max(1, pin->inputCount); ++m)
3556                 {
3557                     PaWinWdmDeviceInfo *wdmDeviceInfo = (PaWinWdmDeviceInfo *)outArgument->deviceInfos[idxDevice];
3558                     PaDeviceInfo *deviceInfo = &wdmDeviceInfo->inheritedDeviceInfo;
3559                     wchar_t localCompositeName[MAX_PATH];
3560                     unsigned nameIndex = 0;
3561                     const BOOL isInput = (pin->dataFlow == KSPIN_DATAFLOW_OUT);
3562
3563                     wdmDeviceInfo->filter = pFilter;
3564
3565                     deviceInfo->structVersion = 2;
3566                     deviceInfo->hostApi = hostApiIndex;
3567                     deviceInfo->name = wdmDeviceInfo->compositeName;
3568                     /* deviceInfo->hostApiSpecificDeviceInfo = &pFilter->devInfo; */
3569
3570                     wdmDeviceInfo->pin = pin->pinId;
3571
3572                     /* Get the name of the "device" */
3573                     if (pin->inputs == NULL)
3574                     {
3575                         wcsncpy(localCompositeName, pin->friendlyName, MAX_PATH);
3576                         wdmDeviceInfo->muxPosition = -1;
3577                         wdmDeviceInfo->endpointPinId = pin->endpointPinId;
3578                     }
3579                     else
3580                     {
3581                         PaWinWdmMuxedInput* input = pin->inputs[m];
3582                         wcsncpy(localCompositeName, input->friendlyName, MAX_PATH);
3583                         wdmDeviceInfo->muxPosition = (int)m;
3584                         wdmDeviceInfo->endpointPinId = input->endpointPinId;
3585                     }
3586
3587                     {
3588                         /* Get base length */
3589                         size_t n = wcslen(localCompositeName);
3590
3591                         /* Check if there are more entries with same name (which might very well be the case), if there
3592                         are, the name will be postfixed with an index. */
3593                         nameIndex = GetNameIndex(&nameHash, localCompositeName, isInput);
3594                         if (nameIndex > 0)
3595                         {
3596                             /* This name has multiple instances, so we post fix with a number */
3597                             n += _snwprintf(localCompositeName + n, MAX_PATH - n, L" %u", nameIndex);
3598                         }
3599                         /* Postfix with filter name */
3600                         _snwprintf(localCompositeName + n, MAX_PATH - n, L" (%s)", pFilter->friendlyName);
3601                     }
3602
3603                     /* Convert wide char string to utf-8 */
3604                     WideCharToMultiByte(CP_UTF8, 0, localCompositeName, -1, wdmDeviceInfo->compositeName, MAX_PATH, NULL, NULL);
3605
3606                     /* NB! WDM/KS has no concept of a full-duplex device, each pin is either an input or an output */
3607                     if (isInput)
3608                     {
3609                         /* INPUT ! */
3610                         deviceInfo->maxInputChannels  = pin->maxChannels;
3611                         deviceInfo->maxOutputChannels = 0;
3612
3613                         /* RoBi NB: Due to the fact that input audio endpoints in Vista (& later OSs) can be the same device, but with
3614                            different input mux settings, there might be a discrepancy between the default input device chosen, and
3615                            that which will be used by Portaudio. Not much to do about that unfortunately.
3616                         */
3617                         if ((defaultInDevPath == 0 || devIsDefaultIn) &&
3618                              outArgument->defaultInputDevice == paNoDevice)
3619                         {
3620                             outArgument->defaultInputDevice = idxDevice;
3621                         }
3622                     }
3623                     else
3624                     {
3625                         /* OUTPUT ! */
3626                         deviceInfo->maxInputChannels  = 0;
3627                         deviceInfo->maxOutputChannels = pin->maxChannels;
3628
3629                         if ((defaultOutDevPath == 0 || devIsDefaultOut) &&
3630                             outArgument->defaultOutputDevice == paNoDevice)
3631                         {
3632                             outArgument->defaultOutputDevice = idxDevice;
3633                         }
3634                     }
3635
3636                     /* These low values are not very useful because
3637                     * a) The lowest latency we end up with can depend on many factors such
3638                     *    as the device buffer sizes/granularities, sample rate, channels and format
3639                     * b) We cannot know the device buffer sizes until we try to open/use it at
3640                     *    a particular setting
3641                     * So: we give 512x48000Hz frames as the default low input latency
3642                     **/
3643                     switch (pFilter->devInfo.streamingType)
3644                     {
3645                     case Type_kWaveCyclic:
3646                         if (IsEarlierThanVista())
3647                         {
3648                             /* XP doesn't tolerate low latency, unless the Process Priority Class is set to REALTIME_PRIORITY_CLASS 
3649                             through SetPriorityClass, then 10 ms is quite feasible. However, one should then bear in mind that ALL of
3650                             the process is running in REALTIME_PRIORITY_CLASS, which might not be appropriate for an application with
3651                             a GUI . In this case it is advisable to separate the audio engine in another process and use IPC to communicate
3652                             with it. */
3653                             deviceInfo->defaultLowInputLatency = 0.02;
3654                             deviceInfo->defaultLowOutputLatency = 0.02;
3655                         }
3656                         else
3657                         {
3658                             /* This is a conservative estimate. Most WaveCyclic drivers will limit the available latency, but f.i. my Edirol
3659                             PCR-A30 can reach 3 ms latency easily... */
3660                             deviceInfo->defaultLowInputLatency = 0.01;
3661                             deviceInfo->defaultLowOutputLatency = 0.01;
3662                         }
3663                         deviceInfo->defaultHighInputLatency = (4096.0/48000.0);
3664                         deviceInfo->defaultHighOutputLatency = (4096.0/48000.0);
3665                         deviceInfo->defaultSampleRate = (double)(pin->defaultSampleRate);
3666                         break;
3667                     case Type_kWaveRT:
3668                         /* This is also a conservative estimate, based on WaveRT polled mode. In polled mode, the latency will be dictated
3669                         by the buffer size given by the driver. */
3670                         deviceInfo->defaultLowInputLatency = 0.01;
3671                         deviceInfo->defaultLowOutputLatency = 0.01;
3672                         deviceInfo->defaultHighInputLatency = 0.04;
3673                         deviceInfo->defaultHighOutputLatency = 0.04;
3674                         deviceInfo->defaultSampleRate = (double)(pin->defaultSampleRate);
3675                         break;
3676                     default:
3677                         assert(0);
3678                         break;
3679                     }
3680
3681                     /* Add reference to filter */
3682                     FilterAddRef(wdmDeviceInfo->filter);
3683
3684                     assert(idxDevice < totalDeviceCount);
3685                     ++idxDevice;
3686                 }
3687             }
3688
3689             /* If no one has add ref'd the filter, drop it */
3690             if (pFilter->filterRefCount == 0)
3691             {
3692                 FilterFree(pFilter);
3693             }
3694
3695             /* Deinitialize name hash object */
3696             DeinitNameHashObject(&nameHash);
3697         }
3698     }
3699
3700     *scanResults = outArgument;
3701     *newDeviceCount = idxDevice;
3702     return result;
3703
3704 error:
3705     result = DisposeDeviceInfos(hostApi, outArgument, totalDeviceCount);
3706
3707     return result;
3708 }
3709
3710 static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *scanResults, int deviceCount )
3711 {
3712     PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
3713
3714     hostApi->info.deviceCount = 0;
3715     hostApi->info.defaultInputDevice = paNoDevice;
3716     hostApi->info.defaultOutputDevice = paNoDevice;
3717
3718     /* Free any old memory which might be in the device info */
3719     if( hostApi->deviceInfos )
3720     {
3721         PaWinWDMScanDeviceInfosResults* localScanResults = (PaWinWDMScanDeviceInfosResults*)PaUtil_GroupAllocateMemory(
3722             wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults));
3723         localScanResults->deviceInfos = hostApi->deviceInfos;
3724
3725         DisposeDeviceInfos(hostApi, &localScanResults, hostApi->info.deviceCount);
3726
3727         hostApi->deviceInfos = NULL;
3728     }
3729
3730     if( scanResults != NULL )
3731     {
3732         PaWinWDMScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinWDMScanDeviceInfosResults * ) scanResults;
3733
3734         if( deviceCount > 0 )
3735         {
3736             /* use the array allocated in ScanDeviceInfos() as our deviceInfos */
3737             hostApi->deviceInfos = scanDeviceInfosResults->deviceInfos;
3738
3739             hostApi->info.defaultInputDevice = scanDeviceInfosResults->defaultInputDevice;
3740             hostApi->info.defaultOutputDevice = scanDeviceInfosResults->defaultOutputDevice;
3741
3742             hostApi->info.deviceCount = deviceCount;
3743         }
3744
3745         PaUtil_GroupFreeMemory( wdmHostApi->allocations, scanDeviceInfosResults );
3746     }
3747
3748     return paNoError;
3749
3750 }
3751
3752 static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *scanResults, int deviceCount )
3753 {
3754     PaWinWdmHostApiRepresentation *winDsHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
3755
3756     if( scanResults != NULL )
3757     {
3758         PaWinWDMScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinWDMScanDeviceInfosResults * ) scanResults;
3759
3760         if( scanDeviceInfosResults->deviceInfos )
3761         {
3762             int i;
3763             for (i = 0; i < deviceCount; ++i)
3764             {
3765                 PaWinWdmDeviceInfo* pDevice = (PaWinWdmDeviceInfo*)scanDeviceInfosResults->deviceInfos[i];
3766                 if (pDevice->filter != 0)
3767                 {
3768                     FilterFree(pDevice->filter);
3769                 }
3770             }
3771
3772             PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults->deviceInfos[0] ); /* all device info structs are allocated in a block so we can destroy them here */
3773             PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults->deviceInfos );
3774         }
3775
3776         PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults );
3777     }
3778
3779     return paNoError;
3780
3781 }
3782
3783 PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
3784 {
3785     PaError result = paNoError;
3786     int deviceCount = 0;
3787     void *scanResults = 0;
3788     PaWinWdmHostApiRepresentation *wdmHostApi = NULL;
3789
3790     PA_LOGE_;
3791
3792 #ifdef PA_WDMKS_SET_TREF
3793     tRef = PaUtil_GetTime();
3794 #endif
3795
3796     /*
3797     Attempt to load the KSUSER.DLL without which we cannot create pins
3798     We will unload this on termination
3799     */
3800     if(DllKsUser == NULL)
3801     {
3802         DllKsUser = LoadLibrary(TEXT("ksuser.dll"));
3803         if(DllKsUser == NULL)
3804             goto error;
3805     }
3806     FunctionKsCreatePin = (KSCREATEPIN*)GetProcAddress(DllKsUser, "KsCreatePin");
3807     if(FunctionKsCreatePin == NULL)
3808         goto error;
3809
3810     /* Attempt to load AVRT.DLL, if we can't, then we'll just use time critical prio instead... */
3811     if(paWinWDMKSAvRtEntryPoints.hInstance == NULL)
3812     {
3813         paWinWDMKSAvRtEntryPoints.hInstance = LoadLibrary(TEXT("avrt.dll"));
3814         if (paWinWDMKSAvRtEntryPoints.hInstance != NULL)
3815         {
3816             paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics =
3817                 (HANDLE(WINAPI*)(LPCSTR,LPDWORD))GetProcAddress(paWinWDMKSAvRtEntryPoints.hInstance,"AvSetMmThreadCharacteristicsA");
3818             paWinWDMKSAvRtEntryPoints.AvRevertMmThreadCharacteristics =
3819                 (BOOL(WINAPI*)(HANDLE))GetProcAddress(paWinWDMKSAvRtEntryPoints.hInstance, "AvRevertMmThreadCharacteristics");
3820             paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority =
3821                 (BOOL(WINAPI*)(HANDLE,PA_AVRT_PRIORITY))GetProcAddress(paWinWDMKSAvRtEntryPoints.hInstance, "AvSetMmThreadPriority");
3822         }
3823     }
3824
3825     wdmHostApi = (PaWinWdmHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinWdmHostApiRepresentation) );
3826     if( !wdmHostApi )
3827     {
3828         result = paInsufficientMemory;
3829         goto error;
3830     }
3831
3832     wdmHostApi->allocations = PaUtil_CreateAllocationGroup();
3833     if( !wdmHostApi->allocations )
3834     {
3835         result = paInsufficientMemory;
3836         goto error;
3837     }
3838
3839     *hostApi = &wdmHostApi->inheritedHostApiRep;
3840     (*hostApi)->info.structVersion = 1;
3841     (*hostApi)->info.type = paWDMKS;
3842     (*hostApi)->info.name = "Windows WDM-KS";
3843
3844     /* these are all updated by CommitDeviceInfos() */
3845     (*hostApi)->info.deviceCount = 0;
3846     (*hostApi)->info.defaultInputDevice = paNoDevice;
3847     (*hostApi)->info.defaultOutputDevice = paNoDevice;
3848     (*hostApi)->deviceInfos = 0;
3849
3850     result = ScanDeviceInfos(&wdmHostApi->inheritedHostApiRep, hostApiIndex, &scanResults, &deviceCount);
3851     if (result != paNoError)
3852     {
3853         goto error;
3854     }
3855
3856     CommitDeviceInfos(&wdmHostApi->inheritedHostApiRep, hostApiIndex, scanResults, deviceCount);
3857
3858     (*hostApi)->Terminate = Terminate;
3859     (*hostApi)->OpenStream = OpenStream;
3860     (*hostApi)->IsFormatSupported = IsFormatSupported;
3861     /* In preparation for hotplug
3862     (*hostApi)->ScanDeviceInfos = ScanDeviceInfos;
3863     (*hostApi)->CommitDeviceInfos = CommitDeviceInfos;
3864     (*hostApi)->DisposeDeviceInfos = DisposeDeviceInfos;
3865     */
3866     PaUtil_InitializeStreamInterface( &wdmHostApi->callbackStreamInterface, CloseStream, StartStream,
3867         StopStream, AbortStream, IsStreamStopped, IsStreamActive,
3868         GetStreamTime, GetStreamCpuLoad,
3869         PaUtil_DummyRead, PaUtil_DummyWrite,
3870         PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
3871
3872     PaUtil_InitializeStreamInterface( &wdmHostApi->blockingStreamInterface, CloseStream, StartStream,
3873         StopStream, AbortStream, IsStreamStopped, IsStreamActive,
3874         GetStreamTime, PaUtil_DummyGetCpuLoad,
3875         ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
3876
3877     PA_LOGL_;
3878     return result;
3879
3880 error:
3881     Terminate( (PaUtilHostApiRepresentation*)wdmHostApi );
3882
3883     PA_LOGL_;
3884     return result;
3885 }
3886
3887
3888 static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
3889 {
3890     PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
3891     PA_LOGE_;
3892
3893     /* Do not unload the libraries */
3894     if( DllKsUser != NULL )
3895     {
3896         FreeLibrary( DllKsUser );
3897         DllKsUser = NULL;
3898     }
3899
3900     if( paWinWDMKSAvRtEntryPoints.hInstance != NULL )
3901     {
3902         FreeLibrary( paWinWDMKSAvRtEntryPoints.hInstance );
3903         paWinWDMKSAvRtEntryPoints.hInstance = NULL;
3904     }
3905
3906     if( wdmHostApi)
3907     {
3908         PaWinWDMScanDeviceInfosResults* localScanResults = (PaWinWDMScanDeviceInfosResults*)PaUtil_GroupAllocateMemory(
3909             wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults));
3910         localScanResults->deviceInfos = hostApi->deviceInfos;
3911         DisposeDeviceInfos(hostApi, localScanResults, hostApi->info.deviceCount);
3912
3913         if( wdmHostApi->allocations )
3914         {
3915             PaUtil_FreeAllAllocations( wdmHostApi->allocations );
3916             PaUtil_DestroyAllocationGroup( wdmHostApi->allocations );
3917         }
3918         PaUtil_FreeMemory( wdmHostApi );
3919     }
3920     PA_LOGL_;
3921 }
3922
3923 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
3924                                  const PaStreamParameters *inputParameters,
3925                                  const PaStreamParameters *outputParameters,
3926                                  double sampleRate )
3927 {
3928     int inputChannelCount, outputChannelCount;
3929     PaSampleFormat inputSampleFormat, outputSampleFormat;
3930     PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
3931     PaWinWdmFilter* pFilter;
3932     int result = paFormatIsSupported;
3933     WAVEFORMATEXTENSIBLE wfx;
3934     PaWinWaveFormatChannelMask channelMask;
3935
3936     PA_LOGE_;
3937
3938     if( inputParameters )
3939     {
3940         PaWinWdmDeviceInfo* pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device];
3941         PaWinWdmPin* pin;
3942         unsigned fmt;
3943         unsigned long testFormat = 0;
3944         unsigned validBits = 0;
3945
3946         inputChannelCount = inputParameters->channelCount;
3947         inputSampleFormat = inputParameters->sampleFormat;
3948
3949         /* all standard sample formats are supported by the buffer adapter,
3950         this implementation doesn't support any custom sample formats */
3951         if( inputSampleFormat & paCustomFormat )
3952         {
3953             PaWinWDM_SetLastErrorInfo(paSampleFormatNotSupported, "IsFormatSupported: Custom input format not supported");
3954             return paSampleFormatNotSupported;
3955         }
3956
3957         /* unless alternate device specification is supported, reject the use of
3958         paUseHostApiSpecificDeviceSpecification */
3959
3960         if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
3961         {
3962             PaWinWDM_SetLastErrorInfo(paInvalidDevice, "IsFormatSupported: paUseHostApiSpecificDeviceSpecification not supported");
3963             return paInvalidDevice;
3964         }
3965
3966         /* check that input device can support inputChannelCount */
3967         if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
3968         {
3969             PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "IsFormatSupported: Invalid input channel count");
3970             return paInvalidChannelCount;
3971         }
3972
3973         /* validate inputStreamInfo */
3974         if( inputParameters->hostApiSpecificStreamInfo )
3975         {
3976             PaWinWDM_SetLastErrorInfo(paIncompatibleHostApiSpecificStreamInfo, "Host API stream info not supported");
3977             return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
3978         }
3979
3980         pFilter = pDeviceInfo->filter;
3981         pin = pFilter->pins[pDeviceInfo->pin];
3982
3983         /* Find out the testing format */
3984         for (fmt = paFloat32; fmt <= paUInt8; fmt <<= 1)
3985         {
3986             if ((fmt & pin->formats) != 0)
3987             {
3988                 /* Found a matching format! */
3989                 testFormat = fmt;
3990                 break;
3991             }
3992         }
3993         if (testFormat == 0)
3994         {
3995             PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(capture) failed: no testformat found!");
3996             return paUnanticipatedHostError;
3997         }
3998
3999         /* Due to special considerations, WaveRT devices with paInt24 should be tested with paInt32 and
4000         valid bits = 24 (instead of 24 bit samples) */
4001         if (pFilter->devInfo.streamingType == Type_kWaveRT && testFormat == paInt24)
4002         {
4003             PA_DEBUG(("IsFormatSupported (capture): WaveRT overriding testFormat paInt24 with paInt32 (24 valid bits)"));
4004             testFormat = paInt32;
4005             validBits = 24;
4006         }
4007
4008         /* Check that the input format is supported */
4009         channelMask = PaWin_DefaultChannelMask(inputChannelCount);
4010         PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
4011             inputChannelCount, 
4012             testFormat,
4013             PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
4014             sampleRate,
4015             channelMask );
4016         if (validBits != 0)
4017         {
4018             wfx.Samples.wValidBitsPerSample = validBits;
4019         }
4020
4021         result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx);
4022         if( result != paNoError )
4023         {
4024             /* Try a WAVE_FORMAT_PCM instead */
4025             PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
4026                 inputChannelCount, 
4027                 testFormat,
4028                 PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
4029                 sampleRate);
4030
4031             if (validBits != 0)
4032             {
4033                 wfx.Samples.wValidBitsPerSample = validBits;
4034             }
4035
4036             result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx);
4037             if( result != paNoError )
4038             {
4039                 PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(capture) failed: sr=%u,ch=%u,bits=%u", wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample);
4040                 return result;
4041             }
4042         }
4043     }
4044     else
4045     {
4046         inputChannelCount = 0;
4047     }
4048
4049     if( outputParameters )
4050     {
4051         PaWinWdmDeviceInfo* pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device];
4052         PaWinWdmPin* pin;
4053         unsigned fmt;
4054         unsigned long testFormat = 0;
4055         unsigned validBits = 0;
4056
4057         outputChannelCount = outputParameters->channelCount;
4058         outputSampleFormat = outputParameters->sampleFormat;
4059
4060         /* all standard sample formats are supported by the buffer adapter,
4061         this implementation doesn't support any custom sample formats */
4062         if( outputSampleFormat & paCustomFormat )
4063         {
4064             PaWinWDM_SetLastErrorInfo(paSampleFormatNotSupported, "IsFormatSupported: Custom output format not supported");
4065             return paSampleFormatNotSupported;
4066         }
4067
4068         /* unless alternate device specification is supported, reject the use of
4069         paUseHostApiSpecificDeviceSpecification */
4070
4071         if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
4072         {
4073             PaWinWDM_SetLastErrorInfo(paInvalidDevice, "IsFormatSupported: paUseHostApiSpecificDeviceSpecification not supported");
4074             return paInvalidDevice;
4075         }
4076
4077         /* check that output device can support outputChannelCount */
4078         if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
4079         {
4080             PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "Invalid output channel count");
4081             return paInvalidChannelCount;
4082         }
4083
4084         /* validate outputStreamInfo */
4085         if( outputParameters->hostApiSpecificStreamInfo )
4086         {
4087             PaWinWDM_SetLastErrorInfo(paIncompatibleHostApiSpecificStreamInfo, "Host API stream info not supported");
4088             return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
4089         }
4090
4091         pFilter = pDeviceInfo->filter;
4092         pin = pFilter->pins[pDeviceInfo->pin];
4093
4094         /* Find out the testing format */
4095         for (fmt = paFloat32; fmt <= paUInt8; fmt <<= 1)
4096         {
4097             if ((fmt & pin->formats) != 0)
4098             {
4099                 /* Found a matching format! */
4100                 testFormat = fmt;
4101                 break;
4102             }
4103         }
4104         if (testFormat == 0)
4105         {
4106             PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(render) failed: no testformat found!");
4107             return paUnanticipatedHostError;
4108         }
4109
4110         /* Due to special considerations, WaveRT devices with paInt24 should be tested with paInt32 and
4111         valid bits = 24 (instead of 24 bit samples) */
4112         if (pFilter->devInfo.streamingType == Type_kWaveRT && testFormat == paInt24)
4113         {
4114             PA_DEBUG(("IsFormatSupported (render): WaveRT overriding testFormat paInt24 with paInt32 (24 valid bits)"));
4115             testFormat = paInt32;
4116             validBits = 24;
4117         }
4118
4119         /* Check that the output format is supported */
4120         channelMask = PaWin_DefaultChannelMask(outputChannelCount);
4121         PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
4122             outputChannelCount, 
4123             testFormat,
4124             PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
4125             sampleRate,
4126             channelMask );
4127
4128         if (validBits != 0)
4129         {
4130             wfx.Samples.wValidBitsPerSample = validBits;
4131         }
4132
4133         result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx);
4134         if( result != paNoError )
4135         {
4136             /* Try a WAVE_FORMAT_PCM instead */
4137             PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
4138                 outputChannelCount, 
4139                 testFormat,
4140                 PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
4141                 sampleRate);
4142
4143             if (validBits != 0)
4144             {
4145                 wfx.Samples.wValidBitsPerSample = validBits;
4146             }
4147
4148             result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx);
4149             if( result != paNoError )
4150             {
4151                 PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(render) failed: %u,%u,%u", wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample);
4152                 return result;
4153             }
4154         }
4155
4156     }
4157     else
4158     {
4159         outputChannelCount = 0;
4160     }
4161
4162     /*
4163     IMPLEMENT ME:
4164
4165     - if a full duplex stream is requested, check that the combination
4166     of input and output parameters is supported if necessary
4167
4168     - check that the device supports sampleRate
4169
4170     Because the buffer adapter handles conversion between all standard
4171     sample formats, the following checks are only required if paCustomFormat
4172     is implemented, or under some other unusual conditions.
4173
4174     - check that input device can support inputSampleFormat, or that
4175     we have the capability to convert from inputSampleFormat to
4176     a native format
4177
4178     - check that output device can support outputSampleFormat, or that
4179     we have the capability to convert from outputSampleFormat to
4180     a native format
4181     */
4182     if((inputChannelCount == 0)&&(outputChannelCount == 0))
4183     {
4184         PaWinWDM_SetLastErrorInfo(paSampleFormatNotSupported, "No input or output channels defined");
4185         result = paSampleFormatNotSupported; /* Not right error */
4186     }
4187
4188     PA_LOGL_;
4189     return result;
4190 }
4191
4192 static void ResetStreamEvents(PaWinWdmStream* stream) 
4193 {
4194     unsigned i;
4195     ResetEvent(stream->eventAbort);
4196     ResetEvent(stream->eventStreamStart[StreamStart_kOk]);
4197     ResetEvent(stream->eventStreamStart[StreamStart_kFailed]);
4198
4199     for (i=0; i<stream->capture.noOfPackets; ++i)
4200     {
4201         if (stream->capture.events && stream->capture.events[i])
4202         {
4203             ResetEvent(stream->capture.events[i]);
4204         }
4205     }
4206
4207     for (i=0; i<stream->render.noOfPackets; ++i)
4208     {
4209         if (stream->render.events && stream->render.events[i])
4210         {
4211             ResetEvent(stream->render.events[i]);
4212         }
4213     }
4214 }
4215
4216 static void CloseStreamEvents(PaWinWdmStream* stream) 
4217 {
4218     unsigned i;
4219     PaWinWdmIOInfo* ios[2] = { &stream->capture, &stream->render };
4220
4221     if (stream->eventAbort)
4222     {
4223         CloseHandle(stream->eventAbort);
4224         stream->eventAbort = 0;
4225     }
4226     if (stream->eventStreamStart[StreamStart_kOk])
4227     {
4228         CloseHandle(stream->eventStreamStart[StreamStart_kOk]);
4229     }
4230     if (stream->eventStreamStart[StreamStart_kFailed])
4231     {
4232         CloseHandle(stream->eventStreamStart[StreamStart_kFailed]);
4233     }
4234
4235     for (i = 0; i < 2; ++i)
4236     {
4237         unsigned j;
4238         /* Unregister notification handles for WaveRT */
4239         if (ios[i]->pPin && ios[i]->pPin->parentFilter->devInfo.streamingType == Type_kWaveRT &&
4240             ios[i]->pPin->pinKsSubType == SubType_kNotification &&
4241             ios[i]->events != 0)
4242         {
4243             PinUnregisterNotificationHandle(ios[i]->pPin, ios[i]->events[0]);
4244         }
4245
4246         for (j=0; j < ios[i]->noOfPackets; ++j)
4247         {
4248             if (ios[i]->events && ios[i]->events[j])
4249             {
4250                 CloseHandle(ios[i]->events[j]);
4251                 ios[i]->events[j] = 0;
4252             }
4253         }
4254     }
4255 }
4256
4257 static unsigned NextPowerOf2(unsigned val)
4258 {
4259     val--;
4260     val = (val >> 1) | val;
4261     val = (val >> 2) | val;
4262     val = (val >> 4) | val;
4263     val = (val >> 8) | val;
4264     val = (val >> 16) | val;
4265     return ++val;
4266 }
4267
4268 static PaError ValidateSpecificStreamParameters(
4269     const PaStreamParameters *streamParameters,
4270     const PaWinWDMKSInfo *streamInfo,
4271     unsigned isInput)
4272 {
4273     if( streamInfo )
4274     {
4275         if( streamInfo->size != sizeof( PaWinWDMKSInfo )
4276             || streamInfo->version != 1 )
4277         {
4278             PA_DEBUG(("Stream parameters: size or version not correct"));
4279             return paIncompatibleHostApiSpecificStreamInfo;
4280         }
4281
4282         if (!!(streamInfo->flags & ~(paWinWDMKSOverrideFramesize | paWinWDMKSUseGivenChannelMask)))
4283         {
4284             PA_DEBUG(("Stream parameters: non supported flags set"));
4285             return paIncompatibleHostApiSpecificStreamInfo;
4286         }
4287
4288         if (streamInfo->noOfPackets != 0 &&
4289             (streamInfo->noOfPackets < 2 || streamInfo->noOfPackets > 8))
4290         {
4291             PA_DEBUG(("Stream parameters: noOfPackets %u out of range [2,8]", streamInfo->noOfPackets));
4292             return paIncompatibleHostApiSpecificStreamInfo;
4293         }
4294
4295         if (streamInfo->flags & paWinWDMKSUseGivenChannelMask)
4296         {
4297             if (isInput)
4298             {
4299                 PA_DEBUG(("Stream parameters: Channels mask setting not supported for input stream"));
4300                 return paIncompatibleHostApiSpecificStreamInfo;
4301             }
4302
4303             if (streamInfo->channelMask & PAWIN_SPEAKER_RESERVED)
4304             {
4305                 PA_DEBUG(("Stream parameters: Given channels mask 0x%08X not supported", streamInfo->channelMask));
4306                 return paIncompatibleHostApiSpecificStreamInfo;
4307             }
4308         }
4309
4310     }
4311
4312     return paNoError;
4313 }
4314
4315
4316
4317
4318 /* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
4319
4320 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
4321                           PaStream** s,
4322                           const PaStreamParameters *inputParameters,
4323                           const PaStreamParameters *outputParameters,
4324                           double sampleRate,
4325                           unsigned long framesPerUserBuffer,
4326                           PaStreamFlags streamFlags,
4327                           PaStreamCallback *streamCallback,
4328                           void *userData )
4329 {
4330     PaError result = paNoError;
4331     PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
4332     PaWinWdmStream *stream = 0;
4333     /* unsigned long framesPerHostBuffer; these may not be equivalent for all implementations */
4334     PaSampleFormat inputSampleFormat, outputSampleFormat;
4335     PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
4336     int userInputChannels,userOutputChannels;
4337     WAVEFORMATEXTENSIBLE wfx;
4338
4339     PA_LOGE_;
4340     PA_DEBUG(("OpenStream:sampleRate = %f\n",sampleRate));
4341     PA_DEBUG(("OpenStream:framesPerBuffer = %lu\n",framesPerUserBuffer));
4342
4343     if( inputParameters )
4344     {
4345         userInputChannels = inputParameters->channelCount;
4346         inputSampleFormat = inputParameters->sampleFormat;
4347
4348         /* unless alternate device specification is supported, reject the use of
4349         paUseHostApiSpecificDeviceSpecification */
4350
4351         if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
4352         {
4353             PaWinWDM_SetLastErrorInfo(paInvalidDevice, "paUseHostApiSpecificDeviceSpecification(in) not supported");
4354             return paInvalidDevice;
4355         }
4356
4357         /* check that input device can support stream->userInputChannels */
4358         if( userInputChannels > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
4359         {
4360             PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "Invalid input channel count");
4361             return paInvalidChannelCount;
4362         }
4363
4364         /* validate inputStreamInfo */
4365         result = ValidateSpecificStreamParameters(inputParameters, inputParameters->hostApiSpecificStreamInfo, 1 );
4366         if(result != paNoError)
4367         {
4368             PaWinWDM_SetLastErrorInfo(result, "Host API stream info not supported (in)");
4369             return result; /* this implementation doesn't use custom stream info */
4370         }
4371     }
4372     else
4373     {
4374         userInputChannels = 0;
4375         inputSampleFormat = hostInputSampleFormat = paInt16; /* Supress 'uninitialised var' warnings. */
4376     }
4377
4378     if( outputParameters )
4379     {
4380         userOutputChannels = outputParameters->channelCount;
4381         outputSampleFormat = outputParameters->sampleFormat;
4382
4383         /* unless alternate device specification is supported, reject the use of
4384         paUseHostApiSpecificDeviceSpecification */
4385
4386         if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
4387         {
4388             PaWinWDM_SetLastErrorInfo(paInvalidDevice, "paUseHostApiSpecificDeviceSpecification(out) not supported");
4389             return paInvalidDevice;
4390         }
4391
4392         /* check that output device can support stream->userInputChannels */
4393         if( userOutputChannels > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
4394         {
4395             PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "Invalid output channel count");
4396             return paInvalidChannelCount;
4397         }
4398
4399         /* validate outputStreamInfo */
4400         result = ValidateSpecificStreamParameters( outputParameters, outputParameters->hostApiSpecificStreamInfo, 0 );
4401         if (result != paNoError)
4402         {
4403             PaWinWDM_SetLastErrorInfo(result, "Host API stream info not supported (out)");
4404             return result; /* this implementation doesn't use custom stream info */
4405         }
4406     }
4407     else
4408     {
4409         userOutputChannels = 0;
4410         outputSampleFormat = hostOutputSampleFormat = paInt16; /* Supress 'uninitialized var' warnings. */
4411     }
4412
4413     /* validate platform specific flags */
4414     if( (streamFlags & paPlatformSpecificFlags) != 0 )
4415     {
4416         PaWinWDM_SetLastErrorInfo(paInvalidFlag, "Invalid flag supplied");
4417         return paInvalidFlag; /* unexpected platform specific flag */
4418     }
4419
4420     stream = (PaWinWdmStream*)PaUtil_AllocateMemory( sizeof(PaWinWdmStream) );
4421     if( !stream )
4422     {
4423         result = paInsufficientMemory;
4424         goto error;
4425     }
4426
4427     /* Create allocation group */
4428     stream->allocGroup = PaUtil_CreateAllocationGroup();
4429     if( !stream->allocGroup )
4430     {
4431         result = paInsufficientMemory;
4432         goto error;
4433     }
4434
4435     /* Zero the stream object */
4436     /* memset((void*)stream,0,sizeof(PaWinWdmStream)); */
4437
4438     if( streamCallback )
4439     {
4440         PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
4441             &wdmHostApi->callbackStreamInterface, streamCallback, userData );
4442     }
4443     else
4444     {
4445         /* PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
4446         &wdmHostApi->blockingStreamInterface, streamCallback, userData ); */
4447
4448         /* We don't support the blocking API yet */
4449         PA_DEBUG(("Blocking API not supported yet!\n"));
4450         PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Blocking API not supported yet");
4451         result = paUnanticipatedHostError;
4452         goto error;
4453     }
4454
4455     PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
4456
4457     /* Instantiate the input pin if necessary */
4458     if(userInputChannels > 0)
4459     {
4460         PaWinWdmFilter* pFilter;
4461         PaWinWdmDeviceInfo* pDeviceInfo;
4462         PaWinWdmPin* pPin;
4463         unsigned validBitsPerSample = 0;
4464         PaWinWaveFormatChannelMask channelMask = PaWin_DefaultChannelMask( userInputChannels );
4465
4466         result = paSampleFormatNotSupported;
4467         pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device];
4468         pFilter = pDeviceInfo->filter;
4469         pPin = pFilter->pins[pDeviceInfo->pin];
4470
4471         stream->userInputChannels = userInputChannels;
4472
4473         hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( pPin->formats, inputSampleFormat );
4474         if (hostInputSampleFormat == paSampleFormatNotSupported)
4475         {
4476             result = paUnanticipatedHostError;
4477             PaWinWDM_SetLastErrorInfo(result, "PU_SCAF(%X,%X) failed (input)", pPin->formats, inputSampleFormat);
4478             goto error;
4479         }
4480         else if (pFilter->devInfo.streamingType == Type_kWaveRT && hostInputSampleFormat == paInt24)
4481         {
4482             /* For WaveRT, we choose 32 bit format instead of paInt24, since we MIGHT need to align buffer on a
4483             128 byte boundary (see PinGetBuffer) */
4484             hostInputSampleFormat = paInt32;
4485             /* But we'll tell the driver that it's 24 bit in 32 bit container */
4486             validBitsPerSample = 24;
4487         }
4488
4489         while (hostInputSampleFormat <= paUInt8)
4490         {
4491             unsigned channelsToProbe = stream->userInputChannels;
4492             /* Some or all KS devices can only handle the exact number of channels
4493             * they specify. But PortAudio clients expect to be able to
4494             * at least specify mono I/O on a multi-channel device
4495             * If this is the case, then we will do the channel mapping internally
4496             * The following loop tests this case
4497             **/
4498             while (1)
4499             {
4500                 PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
4501                     channelsToProbe, 
4502                     hostInputSampleFormat,
4503                     PaWin_SampleFormatToLinearWaveFormatTag(hostInputSampleFormat),
4504                     sampleRate,
4505                     channelMask );
4506                 stream->capture.bytesPerFrame = wfx.Format.nBlockAlign;
4507                 if (validBitsPerSample != 0)
4508                 {
4509                     wfx.Samples.wValidBitsPerSample = validBitsPerSample;
4510                 }
4511                 stream->capture.pPin = FilterCreatePin(pFilter, pPin->pinId, (WAVEFORMATEX*)&wfx, &result);
4512                 stream->deviceInputChannels = channelsToProbe;
4513
4514                 if( result != paNoError && result != paDeviceUnavailable )
4515                 {
4516                     /* Try a WAVE_FORMAT_PCM instead */
4517                     PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
4518                         channelsToProbe, 
4519                         hostInputSampleFormat,
4520                         PaWin_SampleFormatToLinearWaveFormatTag(hostInputSampleFormat),
4521                         sampleRate);
4522                     if (validBitsPerSample != 0)
4523                     {
4524                         wfx.Samples.wValidBitsPerSample = validBitsPerSample;
4525                     }
4526                     stream->capture.pPin = FilterCreatePin(pFilter, pPin->pinId, (const WAVEFORMATEX*)&wfx, &result);
4527                 }
4528
4529                 if (result == paDeviceUnavailable) goto occupied;
4530
4531                 if (result == paNoError)
4532                 {
4533                     /* We're done */
4534                     break;
4535                 }
4536
4537                 if (channelsToProbe < (unsigned)pPin->maxChannels)
4538                 {
4539                     /* Go to next multiple of 2 */
4540                     channelsToProbe = min((((channelsToProbe>>1)+1)<<1), (unsigned)pPin->maxChannels);
4541                     continue;
4542                 }
4543
4544                 break;
4545             }
4546
4547             if (result == paNoError)
4548             {
4549                 /* We're done */
4550                 break;
4551             }
4552
4553             /* Go to next format in line with lower resolution */
4554             hostInputSampleFormat <<= 1;
4555         }
4556
4557         if(stream->capture.pPin == NULL)
4558         {
4559             PaWinWDM_SetLastErrorInfo(result, "Failed to create capture pin: sr=%u,ch=%u,bits=%u,align=%u",
4560                 wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample, wfx.Format.nBlockAlign);
4561             goto error;
4562         }
4563
4564         /* Select correct mux input on MUX node of topology filter */
4565         if (pDeviceInfo->muxPosition >= 0)
4566         {
4567             assert(pPin->parentFilter->topologyFilter != NULL);
4568
4569             result = FilterUse(pPin->parentFilter->topologyFilter);
4570             if (result != paNoError)
4571             {
4572                 PaWinWDM_SetLastErrorInfo(result, "Failed to open topology filter");
4573                 goto error;
4574             }
4575
4576             result = WdmSetMuxNodeProperty(pPin->parentFilter->topologyFilter->handle,
4577                 pPin->inputs[pDeviceInfo->muxPosition]->muxNodeId,
4578                 pPin->inputs[pDeviceInfo->muxPosition]->muxPinId);
4579
4580             FilterRelease(pPin->parentFilter->topologyFilter);
4581
4582             if(result != paNoError)
4583             {
4584                 PaWinWDM_SetLastErrorInfo(result, "Failed to set topology mux node");
4585                 goto error;
4586             }
4587         }
4588
4589         stream->capture.bytesPerSample = stream->capture.bytesPerFrame / stream->deviceInputChannels;
4590         stream->capture.pPin->frameSize /= stream->capture.bytesPerFrame;
4591         PA_DEBUG(("Capture pin frames: %d\n",stream->capture.pPin->frameSize));
4592     }
4593     else
4594     {
4595         stream->capture.pPin = NULL;
4596         stream->capture.bytesPerFrame = 0;
4597     }
4598
4599     /* Instantiate the output pin if necessary */
4600     if(userOutputChannels > 0)
4601     {
4602         PaWinWdmFilter* pFilter;
4603         PaWinWdmDeviceInfo* pDeviceInfo;
4604         PaWinWdmPin* pPin;
4605         PaWinWDMKSInfo* pInfo = (PaWinWDMKSInfo*)(outputParameters->hostApiSpecificStreamInfo);
4606         unsigned validBitsPerSample = 0;
4607         PaWinWaveFormatChannelMask channelMask = PaWin_DefaultChannelMask( userOutputChannels );
4608         if (pInfo && (pInfo->flags & paWinWDMKSUseGivenChannelMask))
4609         {
4610             PA_DEBUG(("Using channelMask 0x%08X instead of default 0x%08X\n",
4611                 pInfo->channelMask,
4612                 channelMask));
4613             channelMask = pInfo->channelMask;
4614         }
4615
4616         result = paSampleFormatNotSupported;
4617         pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device];
4618         pFilter = pDeviceInfo->filter;
4619         pPin = pFilter->pins[pDeviceInfo->pin];
4620
4621         stream->userOutputChannels = userOutputChannels;
4622
4623         hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( pPin->formats, outputSampleFormat );
4624         if (hostOutputSampleFormat == paSampleFormatNotSupported)
4625         {
4626             result = paUnanticipatedHostError;
4627             PaWinWDM_SetLastErrorInfo(result, "PU_SCAF(%X,%X) failed (output)", pPin->formats, hostOutputSampleFormat);
4628             goto error;
4629         }
4630         else if (pFilter->devInfo.streamingType == Type_kWaveRT && hostOutputSampleFormat == paInt24)
4631         {
4632             /* For WaveRT, we choose 32 bit format instead of paInt24, since we MIGHT need to align buffer on a
4633             128 byte boundary (see PinGetBuffer) */
4634             hostOutputSampleFormat = paInt32;
4635             /* But we'll tell the driver that it's 24 bit in 32 bit container */
4636             validBitsPerSample = 24;
4637         }
4638
4639         while (hostOutputSampleFormat <= paUInt8)
4640         {
4641             unsigned channelsToProbe = stream->userOutputChannels;
4642             /* Some or all KS devices can only handle the exact number of channels
4643             * they specify. But PortAudio clients expect to be able to
4644             * at least specify mono I/O on a multi-channel device
4645             * If this is the case, then we will do the channel mapping internally
4646             * The following loop tests this case
4647             **/
4648             while (1)
4649             {
4650                 PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
4651                     channelsToProbe, 
4652                     hostOutputSampleFormat,
4653                     PaWin_SampleFormatToLinearWaveFormatTag(hostOutputSampleFormat),
4654                     sampleRate,
4655                     channelMask );
4656                 stream->render.bytesPerFrame = wfx.Format.nBlockAlign;
4657                 if (validBitsPerSample != 0)
4658                 {
4659                     wfx.Samples.wValidBitsPerSample = validBitsPerSample;
4660                 }
4661                 stream->render.pPin = FilterCreatePin(pFilter, pPin->pinId, (WAVEFORMATEX*)&wfx, &result);
4662                 stream->deviceOutputChannels = channelsToProbe;
4663
4664                 if( result != paNoError && result != paDeviceUnavailable )
4665                 {
4666                     PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
4667                         channelsToProbe, 
4668                         hostOutputSampleFormat,
4669                         PaWin_SampleFormatToLinearWaveFormatTag(hostOutputSampleFormat),
4670                         sampleRate);
4671                     if (validBitsPerSample != 0)
4672                     {
4673                         wfx.Samples.wValidBitsPerSample = validBitsPerSample;
4674                     }
4675                     stream->render.pPin = FilterCreatePin(pFilter, pPin->pinId, (const WAVEFORMATEX*)&wfx, &result);
4676                 }
4677
4678                 if (result == paDeviceUnavailable) goto occupied;
4679
4680                 if (result == paNoError)
4681                 {
4682                     /* We're done */
4683                     break;
4684                 }
4685
4686                 if (channelsToProbe < (unsigned)pPin->maxChannels)
4687                 {
4688                     /* Go to next multiple of 2 */
4689                     channelsToProbe = min((((channelsToProbe>>1)+1)<<1), (unsigned)pPin->maxChannels);
4690                     continue;
4691                 }
4692
4693                 break;
4694             };
4695
4696             if (result == paNoError)
4697             {
4698                 /* We're done */
4699                 break;
4700             }
4701
4702             /* Go to next format in line with lower resolution */
4703             hostOutputSampleFormat <<= 1;
4704         }
4705
4706         if(stream->render.pPin == NULL)
4707         {
4708             PaWinWDM_SetLastErrorInfo(result, "Failed to create render pin: sr=%u,ch=%u,bits=%u,align=%u",
4709                 wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample, wfx.Format.nBlockAlign);
4710             goto error;
4711         }
4712
4713         stream->render.bytesPerSample = stream->render.bytesPerFrame / stream->deviceOutputChannels;
4714         stream->render.pPin->frameSize /= stream->render.bytesPerFrame;
4715         PA_DEBUG(("Render pin frames: %d\n",stream->render.pPin->frameSize));
4716     }
4717     else
4718     {
4719         stream->render.pPin = NULL;
4720         stream->render.bytesPerFrame = 0;
4721     }
4722
4723     /* Calculate the framesPerHostXxxxBuffer size based upon the suggested latency values */
4724     /* Record the buffer length */
4725     if(inputParameters)
4726     {
4727         /* Calculate the frames from the user's value - add a bit to round up */
4728         stream->capture.framesPerBuffer = (unsigned long)((inputParameters->suggestedLatency*sampleRate)+0.0001);
4729         if(stream->capture.framesPerBuffer > (unsigned long)sampleRate)
4730         { /* Upper limit is 1 second */
4731             stream->capture.framesPerBuffer = (unsigned long)sampleRate;
4732         }
4733         else if(stream->capture.framesPerBuffer < stream->capture.pPin->frameSize)
4734         {
4735             stream->capture.framesPerBuffer = stream->capture.pPin->frameSize;
4736         }
4737         PA_DEBUG(("Input frames chosen:%ld\n",stream->capture.framesPerBuffer));
4738
4739         /* Setup number of packets to use */
4740         stream->capture.noOfPackets = 2;
4741
4742         if (inputParameters->hostApiSpecificStreamInfo)
4743         {
4744             PaWinWDMKSInfo* pInfo = (PaWinWDMKSInfo*)inputParameters->hostApiSpecificStreamInfo;
4745
4746             if (stream->capture.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic &&
4747                 pInfo->noOfPackets != 0)
4748             {
4749                 stream->capture.noOfPackets = pInfo->noOfPackets;
4750             }
4751         }
4752     }
4753
4754     if(outputParameters)
4755     {
4756         /* Calculate the frames from the user's value - add a bit to round up */
4757         stream->render.framesPerBuffer = (unsigned long)((outputParameters->suggestedLatency*sampleRate)+0.0001);
4758         if(stream->render.framesPerBuffer > (unsigned long)sampleRate)
4759         { /* Upper limit is 1 second */
4760             stream->render.framesPerBuffer = (unsigned long)sampleRate;
4761         }
4762         else if(stream->render.framesPerBuffer < stream->render.pPin->frameSize)
4763         {
4764             stream->render.framesPerBuffer = stream->render.pPin->frameSize;
4765         }
4766         PA_DEBUG(("Output frames chosen:%ld\n",stream->render.framesPerBuffer));
4767
4768         /* Setup number of packets to use */
4769         stream->render.noOfPackets = 2;
4770
4771         if (outputParameters->hostApiSpecificStreamInfo)
4772         {
4773             PaWinWDMKSInfo* pInfo = (PaWinWDMKSInfo*)outputParameters->hostApiSpecificStreamInfo;
4774
4775             if (stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic &&
4776                 pInfo->noOfPackets != 0)
4777             {
4778                 stream->render.noOfPackets = pInfo->noOfPackets;
4779             }
4780         }
4781     }
4782
4783     /* Host buffer size is bound to the largest of the input and output frame sizes */
4784     result =  PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
4785         stream->userInputChannels, inputSampleFormat, hostInputSampleFormat,
4786         stream->userOutputChannels, outputSampleFormat, hostOutputSampleFormat,
4787         sampleRate, streamFlags, framesPerUserBuffer,
4788         max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer), 
4789         paUtilBoundedHostBufferSize,
4790         streamCallback, userData );
4791     if( result != paNoError )
4792     {
4793         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",
4794             stream->userInputChannels, inputSampleFormat, hostInputSampleFormat,
4795             stream->userOutputChannels, outputSampleFormat, hostOutputSampleFormat,
4796             sampleRate, streamFlags, framesPerUserBuffer,
4797             max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer));
4798         goto error;
4799     }
4800
4801     /* Allocate/get all the buffers for host I/O */
4802     if (stream->userInputChannels > 0)
4803     {
4804         stream->streamRepresentation.streamInfo.inputLatency = stream->capture.framesPerBuffer / sampleRate;
4805
4806         switch (stream->capture.pPin->parentFilter->devInfo.streamingType)
4807         {
4808         case Type_kWaveCyclic:
4809             {
4810                 unsigned size = stream->capture.noOfPackets * stream->capture.framesPerBuffer * stream->capture.bytesPerFrame;
4811                 /* Allocate input host buffer */
4812                 stream->capture.hostBuffer = (char*)PaUtil_GroupAllocateMemory(stream->allocGroup, size);
4813                 PA_DEBUG(("Input buffer allocated (size = %u)\n", size));
4814                 if( !stream->capture.hostBuffer )
4815                 {
4816                     PA_DEBUG(("Cannot allocate host input buffer!\n"));
4817                     PaWinWDM_SetLastErrorInfo(paInsufficientMemory, "Failed to allocate input buffer");
4818                     result = paInsufficientMemory;
4819                     goto error;
4820                 }
4821                 stream->capture.hostBufferSize = size;
4822                 PA_DEBUG(("Input buffer start = %p (size=%u)\n",stream->capture.hostBuffer, stream->capture.hostBufferSize));
4823                 stream->capture.pPin->fnEventHandler = PaPinCaptureEventHandler_WaveCyclic;
4824                 stream->capture.pPin->fnSubmitHandler = PaPinCaptureSubmitHandler_WaveCyclic;
4825             }
4826             break;
4827         case Type_kWaveRT:
4828             {
4829                 const DWORD dwTotalSize = 2 * stream->capture.framesPerBuffer * stream->capture.bytesPerFrame;
4830                 DWORD dwRequestedSize = dwTotalSize;
4831                 BOOL bCallMemoryBarrier = FALSE;
4832                 ULONG hwFifoLatency = 0;
4833                 ULONG dummy;
4834                 result = PinGetBuffer(stream->capture.pPin, (void**)&stream->capture.hostBuffer, &dwRequestedSize, &bCallMemoryBarrier);
4835                 if (!result) 
4836                 {
4837                     PA_DEBUG(("Input buffer start = %p, size = %u\n", stream->capture.hostBuffer, dwRequestedSize));
4838                     if (dwRequestedSize != dwTotalSize)
4839                     {
4840                         PA_DEBUG(("Buffer length changed by driver from %u to %u !\n", dwTotalSize, dwRequestedSize));
4841                         /* Recalculate to what the driver has given us */
4842                         stream->capture.framesPerBuffer = dwRequestedSize / (2 * stream->capture.bytesPerFrame);
4843                     }
4844                     stream->capture.hostBufferSize = dwRequestedSize;
4845
4846                     if (stream->capture.pPin->pinKsSubType == SubType_kPolled)
4847                     {
4848                         stream->capture.pPin->fnEventHandler = PaPinCaptureEventHandler_WaveRTPolled;
4849                         stream->capture.pPin->fnSubmitHandler = PaPinCaptureSubmitHandler_WaveRTPolled;
4850                     }
4851                     else
4852                     {
4853                         stream->capture.pPin->fnEventHandler = PaPinCaptureEventHandler_WaveRTEvent;
4854                         stream->capture.pPin->fnSubmitHandler = PaPinCaptureSubmitHandler_WaveRTEvent;
4855                     }
4856
4857                     stream->capture.pPin->fnMemBarrier = bCallMemoryBarrier ? MemoryBarrierRead : MemoryBarrierDummy;
4858                 }
4859                 else 
4860                 {
4861                     PA_DEBUG(("Failed to get input buffer (WaveRT)\n"));
4862                     PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to get input buffer (WaveRT)");
4863                     result = paUnanticipatedHostError;
4864                     goto error;
4865                 }
4866
4867                 /* Get latency */
4868                 result = PinGetHwLatency(stream->capture.pPin, &hwFifoLatency, &dummy, &dummy);
4869                 if (result == paNoError)
4870                 {
4871                     stream->capture.pPin->hwLatency = hwFifoLatency;
4872
4873                     /* Add HW latency into total input latency */
4874                     stream->streamRepresentation.streamInfo.inputLatency += ((hwFifoLatency / stream->capture.bytesPerFrame) / sampleRate);
4875                 }
4876                 else
4877                 {
4878                     PA_DEBUG(("Failed to get size of FIFO hardware buffer (is set to zero)\n"));
4879                     stream->capture.pPin->hwLatency = 0;
4880                 }
4881             }
4882             break;
4883         default:
4884             /* Undefined wave type!! */
4885             assert(0);
4886             result = paInternalError;
4887             PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType);
4888             goto error;
4889         }
4890     }
4891     else 
4892     {
4893         stream->capture.hostBuffer = 0;
4894     }
4895
4896     if (stream->userOutputChannels > 0)
4897     {
4898         stream->streamRepresentation.streamInfo.outputLatency = stream->render.framesPerBuffer / sampleRate;
4899
4900         switch (stream->render.pPin->parentFilter->devInfo.streamingType)
4901         {
4902         case Type_kWaveCyclic:
4903             {
4904                 unsigned size = stream->render.noOfPackets * stream->render.framesPerBuffer * stream->render.bytesPerFrame;
4905                 /* Allocate output device buffer */
4906                 stream->render.hostBuffer = (char*)PaUtil_GroupAllocateMemory(stream->allocGroup, size);
4907                 PA_DEBUG(("Output buffer allocated (size = %u)\n", size));
4908                 if( !stream->render.hostBuffer )
4909                 {
4910                     PA_DEBUG(("Cannot allocate host output buffer!\n"));
4911                     PaWinWDM_SetLastErrorInfo(paInsufficientMemory, "Failed to allocate output buffer");
4912                     result = paInsufficientMemory;
4913                     goto error;
4914                 }
4915                 stream->render.hostBufferSize = size;
4916                 PA_DEBUG(("Output buffer start = %p (size=%u)\n",stream->render.hostBuffer, stream->render.hostBufferSize));
4917
4918                 stream->render.pPin->fnEventHandler = PaPinRenderEventHandler_WaveCyclic;
4919                 stream->render.pPin->fnSubmitHandler = PaPinRenderSubmitHandler_WaveCyclic;
4920             }
4921             break;
4922         case Type_kWaveRT:
4923             {
4924                 const DWORD dwTotalSize = 2 * stream->render.framesPerBuffer * stream->render.bytesPerFrame;
4925                 DWORD dwRequestedSize = dwTotalSize;
4926                 BOOL bCallMemoryBarrier = FALSE;
4927                 ULONG hwFifoLatency = 0;
4928                 ULONG dummy;
4929                 result = PinGetBuffer(stream->render.pPin, (void**)&stream->render.hostBuffer, &dwRequestedSize, &bCallMemoryBarrier);
4930                 if (!result) 
4931                 {
4932                     PA_DEBUG(("Output buffer start = %p, size = %u, membarrier = %u\n", stream->render.hostBuffer, dwRequestedSize, bCallMemoryBarrier));
4933                     if (dwRequestedSize != dwTotalSize)
4934                     {
4935                         PA_DEBUG(("Buffer length changed by driver from %u to %u !\n", dwTotalSize, dwRequestedSize));
4936                         /* Recalculate to what the driver has given us */
4937                         stream->render.framesPerBuffer = dwRequestedSize / (2 * stream->render.bytesPerFrame);
4938                     }
4939                     stream->render.hostBufferSize = dwRequestedSize;
4940
4941                     if (stream->render.pPin->pinKsSubType == SubType_kPolled)
4942                     {
4943                         stream->render.pPin->fnEventHandler = PaPinRenderEventHandler_WaveRTPolled;
4944                         stream->render.pPin->fnSubmitHandler = PaPinRenderSubmitHandler_WaveRTPolled;
4945                     }
4946                     else
4947                     {
4948                         stream->render.pPin->fnEventHandler = PaPinRenderEventHandler_WaveRTEvent;
4949                         stream->render.pPin->fnSubmitHandler = PaPinRenderSubmitHandler_WaveRTEvent;
4950                     }
4951
4952                     stream->render.pPin->fnMemBarrier = bCallMemoryBarrier ? MemoryBarrierWrite : MemoryBarrierDummy;
4953                 }
4954                 else 
4955                 {
4956                     PA_DEBUG(("Failed to get output buffer (with notification)\n"));
4957                     PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to get output buffer (with notification)");
4958                     result = paUnanticipatedHostError;
4959                     goto error;
4960                 }
4961
4962                 /* Get latency */
4963                 result = PinGetHwLatency(stream->render.pPin, &hwFifoLatency, &dummy, &dummy);
4964                 if (result == paNoError)
4965                 {
4966                     stream->render.pPin->hwLatency = hwFifoLatency;
4967
4968                     /* Add HW latency into total output latency */
4969                     stream->streamRepresentation.streamInfo.outputLatency += ((hwFifoLatency / stream->render.bytesPerFrame) / sampleRate);
4970                 }
4971                 else
4972                 {
4973                     PA_DEBUG(("Failed to get size of FIFO hardware buffer (is set to zero)\n"));
4974                     stream->render.pPin->hwLatency = 0;
4975                 }
4976             }
4977             break;
4978         default:
4979             /* Undefined wave type!! */
4980             assert(0);
4981             result = paInternalError;
4982             PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType);
4983             goto error;
4984         }
4985     }
4986     else 
4987     {
4988         stream->render.hostBuffer = 0;
4989     }
4990
4991     stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
4992
4993     PA_DEBUG(("BytesPerInputFrame = %d\n",stream->capture.bytesPerFrame));
4994     PA_DEBUG(("BytesPerOutputFrame = %d\n",stream->render.bytesPerFrame));
4995
4996     /* memset(stream->hostBuffer,0,size); */
4997
4998     /* Abort */
4999     stream->eventAbort          = CreateEvent(NULL, TRUE, FALSE, NULL);
5000     if (stream->eventAbort == 0)
5001     {
5002         result = paInsufficientMemory;
5003         goto error;
5004     }
5005     stream->eventStreamStart[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
5006     if (stream->eventStreamStart[0] == 0)
5007     {
5008         result = paInsufficientMemory;
5009         goto error;
5010     }
5011     stream->eventStreamStart[1] = CreateEvent(NULL, TRUE, FALSE, NULL);
5012     if (stream->eventStreamStart[1] == 0)
5013     {
5014         result = paInsufficientMemory;
5015         goto error;
5016     }
5017
5018     if(stream->userInputChannels > 0)
5019     {
5020         const unsigned bufferSizeInBytes = stream->capture.framesPerBuffer * stream->capture.bytesPerFrame;
5021         const unsigned ringBufferFrameSize = NextPowerOf2( 1024 + 2 * max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer) );
5022
5023         stream->capture.events = (HANDLE*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->capture.noOfPackets * sizeof(HANDLE));
5024         if (stream->capture.events == NULL)
5025         {
5026             result = paInsufficientMemory;
5027             goto error;
5028         }
5029
5030         stream->capture.packets = (DATAPACKET*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->capture.noOfPackets * sizeof(DATAPACKET));
5031         if (stream->capture.packets == NULL)
5032         {
5033             result = paInsufficientMemory;
5034             goto error;
5035         }
5036
5037         switch(stream->capture.pPin->parentFilter->devInfo.streamingType)
5038         {
5039         case Type_kWaveCyclic:
5040             {
5041                 /* WaveCyclic case */
5042                 unsigned i;
5043                 for (i = 0; i < stream->capture.noOfPackets; ++i)
5044                 {
5045                     /* Set up the packets */
5046                     DATAPACKET *p = stream->capture.packets + i;
5047
5048                     /* Record event */
5049                     stream->capture.events[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
5050
5051                     p->Signal.hEvent = stream->capture.events[i];
5052                     p->Header.Data = stream->capture.hostBuffer + (i*bufferSizeInBytes);
5053                     p->Header.FrameExtent = bufferSizeInBytes;
5054                     p->Header.DataUsed = 0;
5055                     p->Header.Size = sizeof(p->Header);
5056                     p->Header.PresentationTime.Numerator = 1;
5057                     p->Header.PresentationTime.Denominator = 1;
5058                 }
5059             }
5060             break;
5061         case Type_kWaveRT:
5062             {
5063                 /* Set up the "packets" */
5064                 DATAPACKET *p = stream->capture.packets + 0;
5065
5066                 /* Record event: WaveRT has a single event for 2 notification per buffer */
5067                 stream->capture.events[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
5068
5069                 p->Header.Data = stream->capture.hostBuffer;
5070                 p->Header.FrameExtent = bufferSizeInBytes;
5071                 p->Header.DataUsed = 0;
5072                 p->Header.Size = sizeof(p->Header);
5073                 p->Header.PresentationTime.Numerator = 1;
5074                 p->Header.PresentationTime.Denominator = 1;
5075
5076                 ++p;
5077                 p->Header.Data = stream->capture.hostBuffer + bufferSizeInBytes;
5078                 p->Header.FrameExtent = bufferSizeInBytes;
5079                 p->Header.DataUsed = 0;
5080                 p->Header.Size = sizeof(p->Header);
5081                 p->Header.PresentationTime.Numerator = 1;
5082                 p->Header.PresentationTime.Denominator = 1;
5083
5084                 if (stream->capture.pPin->pinKsSubType == SubType_kNotification)
5085                 {
5086                     result = PinRegisterNotificationHandle(stream->capture.pPin, stream->capture.events[0]);
5087
5088                     if (result != paNoError)
5089                     {
5090                         PA_DEBUG(("Failed to register capture notification handle\n"));
5091                         PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to register capture notification handle");
5092                         result = paUnanticipatedHostError;
5093                         goto error;
5094                     }
5095                 }
5096
5097                 result = PinRegisterPositionRegister(stream->capture.pPin);
5098
5099                 if (result != paNoError)
5100                 {
5101                     unsigned long pos = 0xdeadc0de;
5102                     PA_DEBUG(("Failed to register capture position register, using PinGetAudioPositionViaIOCTLWrite\n"));
5103                     stream->capture.pPin->fnAudioPosition = PinGetAudioPositionViaIOCTLWrite;
5104                     /* Test position function */
5105                     result = (stream->capture.pPin->fnAudioPosition)(stream->capture.pPin, &pos);
5106                     if (result != paNoError || pos != 0x0)
5107                     {
5108                         PA_DEBUG(("Failed to read capture position register (IOCTL)\n"));
5109                         PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to read capture position register (IOCTL)");
5110                         result = paUnanticipatedHostError;
5111                         goto error;
5112                     }                
5113                 }
5114                 else
5115                 {
5116                     stream->capture.pPin->fnAudioPosition = PinGetAudioPositionMemoryMapped;
5117                 }
5118             }
5119             break;
5120         default:
5121             /* Undefined wave type!! */
5122             assert(0);
5123             result = paInternalError;
5124             PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType);
5125             goto error;
5126         }
5127
5128         /* Setup the input ring buffer here */
5129         stream->ringBufferData = (char*)PaUtil_GroupAllocateMemory(stream->allocGroup, ringBufferFrameSize * stream->capture.bytesPerFrame);
5130         if (stream->ringBufferData == NULL)
5131         {
5132             result = paInsufficientMemory;
5133             goto error;
5134         }
5135         PaUtil_InitializeRingBuffer(&stream->ringBuffer, stream->capture.bytesPerFrame, ringBufferFrameSize, stream->ringBufferData);
5136     }
5137     if(stream->userOutputChannels > 0)
5138     {
5139         const unsigned bufferSizeInBytes = stream->render.framesPerBuffer * stream->render.bytesPerFrame;
5140
5141         stream->render.events = (HANDLE*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->render.noOfPackets * sizeof(HANDLE));
5142         if (stream->render.events == NULL)
5143         {
5144             result = paInsufficientMemory;
5145             goto error;
5146         }
5147
5148         stream->render.packets = (DATAPACKET*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->render.noOfPackets * sizeof(DATAPACKET));
5149         if (stream->render.packets == NULL)
5150         {
5151             result = paInsufficientMemory;
5152             goto error;
5153         }
5154
5155         switch(stream->render.pPin->parentFilter->devInfo.streamingType)
5156         {
5157         case Type_kWaveCyclic:
5158             {
5159                 /* WaveCyclic case */
5160                 unsigned i;
5161                 for (i = 0; i < stream->render.noOfPackets; ++i)
5162                 {
5163                     /* Set up the packets */
5164                     DATAPACKET *p = stream->render.packets + i;
5165
5166                     /* Playback event */
5167                     stream->render.events[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
5168
5169                     /* In this case, we just use the packets as ptr to the device buffer */
5170                     p->Signal.hEvent = stream->render.events[i];
5171                     p->Header.Data = stream->render.hostBuffer + (i*bufferSizeInBytes);
5172                     p->Header.FrameExtent = bufferSizeInBytes;
5173                     p->Header.DataUsed = bufferSizeInBytes;
5174                     p->Header.Size = sizeof(p->Header);
5175                     p->Header.PresentationTime.Numerator = 1;
5176                     p->Header.PresentationTime.Denominator = 1;
5177                 }
5178             }
5179             break;
5180         case Type_kWaveRT:
5181             {
5182                 /* WaveRT case */
5183
5184                 /* Set up the "packets" */
5185                 DATAPACKET *p = stream->render.packets;
5186
5187                 /* The only playback event */
5188                 stream->render.events[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
5189
5190                 /* In this case, we just use the packets as ptr to the device buffer */
5191                 p->Header.Data = stream->render.hostBuffer;
5192                 p->Header.FrameExtent = stream->render.framesPerBuffer*stream->render.bytesPerFrame;
5193                 p->Header.DataUsed = stream->render.framesPerBuffer*stream->render.bytesPerFrame;
5194                 p->Header.Size = sizeof(p->Header);
5195                 p->Header.PresentationTime.Numerator = 1;
5196                 p->Header.PresentationTime.Denominator = 1;
5197
5198                 ++p;
5199                 p->Header.Data = stream->render.hostBuffer + stream->render.framesPerBuffer*stream->render.bytesPerFrame;
5200                 p->Header.FrameExtent = stream->render.framesPerBuffer*stream->render.bytesPerFrame;
5201                 p->Header.DataUsed = stream->render.framesPerBuffer*stream->render.bytesPerFrame;
5202                 p->Header.Size = sizeof(p->Header);
5203                 p->Header.PresentationTime.Numerator = 1;
5204                 p->Header.PresentationTime.Denominator = 1;
5205
5206                 if (stream->render.pPin->pinKsSubType == SubType_kNotification)
5207                 {
5208                     result = PinRegisterNotificationHandle(stream->render.pPin, stream->render.events[0]);
5209
5210                     if (result != paNoError)
5211                     {
5212                         PA_DEBUG(("Failed to register rendering notification handle\n"));
5213                         PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to register rendering notification handle");
5214                         result = paUnanticipatedHostError;
5215                         goto error;
5216                     }
5217                 }
5218
5219                 result = PinRegisterPositionRegister(stream->render.pPin);
5220
5221                 if (result != paNoError)
5222                 {
5223                     unsigned long pos = 0xdeadc0de;
5224                     PA_DEBUG(("Failed to register rendering position register, using PinGetAudioPositionViaIOCTLRead\n"));
5225                     stream->render.pPin->fnAudioPosition = PinGetAudioPositionViaIOCTLRead;
5226                     /* Test position function */
5227                     result = (stream->render.pPin->fnAudioPosition)(stream->render.pPin, &pos);
5228                     if (result != paNoError || pos != 0x0)
5229                     {
5230                         PA_DEBUG(("Failed to read render position register (IOCTL)\n"));
5231                         PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to read render position register (IOCTL)");
5232                         result = paUnanticipatedHostError;
5233                         goto error;
5234                     }
5235                 }
5236                 else
5237                 {
5238                     stream->render.pPin->fnAudioPosition = PinGetAudioPositionMemoryMapped;
5239                 }
5240             }
5241             break;
5242         default:
5243             /* Undefined wave type!! */
5244             assert(0);
5245             result = paInternalError;
5246             PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType);
5247             goto error;
5248         }
5249     }
5250
5251     stream->streamStarted = 0;
5252     stream->streamActive = 0;
5253     stream->streamStop = 0;
5254     stream->streamAbort = 0;
5255     stream->streamFlags = streamFlags;
5256     stream->oldProcessPriority = REALTIME_PRIORITY_CLASS;
5257
5258     /* Increase ref count on filters in use, so that a CommitDeviceInfos won't delete them */
5259     if (stream->capture.pPin != 0)
5260     {
5261         FilterAddRef(stream->capture.pPin->parentFilter);
5262     }
5263     if (stream->render.pPin != 0)
5264     {
5265         FilterAddRef(stream->render.pPin->parentFilter);
5266     }
5267
5268     /* Ok, now update our host API specific stream info */
5269     if (stream->userInputChannels)
5270     {
5271         PaWinWdmDeviceInfo *pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device];
5272
5273         stream->hostApiStreamInfo.input.device = Pa_HostApiDeviceIndexToDeviceIndex(Pa_HostApiTypeIdToHostApiIndex(paWDMKS), inputParameters->device);
5274         stream->hostApiStreamInfo.input.channels = stream->deviceInputChannels;
5275         stream->hostApiStreamInfo.input.muxNodeId = -1;
5276         if (stream->capture.pPin->inputs)
5277         {
5278             stream->hostApiStreamInfo.input.muxNodeId = stream->capture.pPin->inputs[pDeviceInfo->muxPosition]->muxNodeId;
5279         }
5280         stream->hostApiStreamInfo.input.endpointPinId = pDeviceInfo->endpointPinId;
5281         stream->hostApiStreamInfo.input.framesPerHostBuffer = stream->capture.framesPerBuffer;
5282         stream->hostApiStreamInfo.input.streamingSubType = stream->capture.pPin->pinKsSubType;
5283     }
5284     else
5285     {
5286         stream->hostApiStreamInfo.input.device = paNoDevice;
5287     }
5288     if (stream->userOutputChannels)
5289     {
5290         stream->hostApiStreamInfo.output.device = Pa_HostApiDeviceIndexToDeviceIndex(Pa_HostApiTypeIdToHostApiIndex(paWDMKS), outputParameters->device);
5291         stream->hostApiStreamInfo.output.channels = stream->deviceOutputChannels;
5292         stream->hostApiStreamInfo.output.framesPerHostBuffer = stream->render.framesPerBuffer;
5293         stream->hostApiStreamInfo.output.endpointPinId = stream->render.pPin->endpointPinId;
5294         stream->hostApiStreamInfo.output.streamingSubType = stream->render.pPin->pinKsSubType;
5295     }
5296     else
5297     {
5298         stream->hostApiStreamInfo.output.device = paNoDevice;
5299     }
5300     /*stream->streamRepresentation.streamInfo.hostApiTypeId = paWDMKS;
5301     stream->streamRepresentation.streamInfo.hostApiSpecificStreamInfo = &stream->hostApiStreamInfo;*/
5302     stream->streamRepresentation.streamInfo.structVersion = 2;
5303
5304     *s = (PaStream*)stream;
5305
5306     PA_LOGL_;
5307     return result;
5308
5309 occupied:
5310     /* Ok, someone else is hogging the pin, bail out */
5311     assert (result == paDeviceUnavailable);
5312     PaWinWDM_SetLastErrorInfo(result, "Device is occupied");
5313
5314 error:
5315     PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
5316
5317     CloseStreamEvents(stream);
5318
5319     if (stream->allocGroup)
5320     {
5321         PaUtil_FreeAllAllocations(stream->allocGroup);
5322         PaUtil_DestroyAllocationGroup(stream->allocGroup);
5323         stream->allocGroup = 0;
5324     }
5325
5326     if(stream->render.pPin)
5327         PinClose(stream->render.pPin);
5328     if(stream->capture.pPin)
5329         PinClose(stream->capture.pPin);
5330
5331     PaUtil_FreeMemory( stream );
5332
5333     PA_LOGL_;
5334     return result;
5335 }
5336
5337 /*
5338 When CloseStream() is called, the multi-api layer ensures that
5339 the stream has already been stopped or aborted.
5340 */
5341 static PaError CloseStream( PaStream* s )
5342 {
5343     PaError result = paNoError;
5344     PaWinWdmStream *stream = (PaWinWdmStream*)s;
5345
5346     PA_LOGE_;
5347
5348     assert(!stream->streamStarted);
5349     assert(!stream->streamActive);
5350
5351     PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
5352     PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
5353
5354     CloseStreamEvents(stream);
5355
5356     if (stream->allocGroup)
5357     {
5358         PaUtil_FreeAllAllocations(stream->allocGroup);
5359         PaUtil_DestroyAllocationGroup(stream->allocGroup);
5360         stream->allocGroup = 0;
5361     }
5362
5363     if(stream->render.pPin)
5364     {
5365         PinClose(stream->render.pPin);
5366     }
5367     if(stream->capture.pPin)
5368     {
5369         PinClose(stream->capture.pPin);
5370     }
5371
5372     if (stream->render.pPin)
5373     {
5374         FilterFree(stream->render.pPin->parentFilter);
5375     }
5376     if (stream->capture.pPin)
5377     {
5378         FilterFree(stream->capture.pPin->parentFilter);
5379     }
5380
5381     PaUtil_FreeMemory( stream );
5382
5383     PA_LOGL_;
5384     return result;
5385 }
5386
5387 /*
5388 Write the supplied packet to the pin
5389 Asynchronous
5390 Should return paNoError on success
5391 */
5392 static PaError PinWrite(HANDLE h, DATAPACKET* p)
5393 {
5394     PaError result = paNoError;
5395     unsigned long cbReturned = 0;
5396     BOOL fRes = DeviceIoControl(h,
5397         IOCTL_KS_WRITE_STREAM,
5398         NULL,
5399         0,
5400         &p->Header,
5401         p->Header.Size,
5402         &cbReturned,
5403         &p->Signal);
5404     if (!fRes)
5405     {
5406         unsigned long error = GetLastError();
5407         if (error != ERROR_IO_PENDING)
5408         {
5409             result = paInternalError;
5410         }
5411     }
5412     return result;
5413 }
5414
5415 /*
5416 Read to the supplied packet from the pin
5417 Asynchronous
5418 Should return paNoError on success
5419 */
5420 static PaError PinRead(HANDLE h, DATAPACKET* p)
5421 {
5422     PaError result = paNoError;
5423     unsigned long cbReturned = 0;
5424     BOOL fRes = DeviceIoControl(h,
5425         IOCTL_KS_READ_STREAM,
5426         NULL,
5427         0,
5428         &p->Header,
5429         p->Header.Size,
5430         &cbReturned,
5431         &p->Signal);
5432     if (!fRes)
5433     {
5434         unsigned long error = GetLastError();
5435         if (error != ERROR_IO_PENDING)
5436         {
5437             result = paInternalError;
5438         }
5439     }
5440     return result;
5441 }
5442
5443 /*
5444 Copy the first interleaved channel of 16 bit data to the other channels
5445 */
5446 static void DuplicateFirstChannelInt16(void* buffer, int channels, int samples)
5447 {
5448     unsigned short* data = (unsigned short*)buffer;
5449     int channel;
5450     unsigned short sourceSample;
5451     while( samples-- )
5452     {
5453         sourceSample = *data++;
5454         channel = channels-1;
5455         while( channel-- )
5456         {
5457             *data++ = sourceSample;
5458         }
5459     }
5460 }
5461
5462 /*
5463 Copy the first interleaved channel of 24 bit data to the other channels
5464 */
5465 static void DuplicateFirstChannelInt24(void* buffer, int channels, int samples)
5466 {
5467     unsigned char* data = (unsigned char*)buffer;
5468     int channel;
5469     unsigned char sourceSample[3];
5470     while( samples-- )
5471     {
5472         sourceSample[0] = data[0];
5473         sourceSample[1] = data[1];
5474         sourceSample[2] = data[2];
5475         data += 3;
5476         channel = channels-1;
5477         while( channel-- )
5478         {
5479             data[0] = sourceSample[0];
5480             data[1] = sourceSample[1];
5481             data[2] = sourceSample[2];
5482             data += 3;
5483         }
5484     }
5485 }
5486
5487 /*
5488 Copy the first interleaved channel of 32 bit data to the other channels
5489 */
5490 static void DuplicateFirstChannelInt32(void* buffer, int channels, int samples)
5491 {
5492     unsigned long* data = (unsigned long*)buffer;
5493     int channel;
5494     unsigned long sourceSample;
5495     while( samples-- )
5496     {
5497         sourceSample = *data++;
5498         channel = channels-1;
5499         while( channel-- )
5500         {
5501             *data++ = sourceSample;
5502         }
5503     }
5504 }
5505
5506 /*
5507 Increase the priority of the calling thread to RT 
5508 */
5509 static HANDLE BumpThreadPriority() 
5510 {
5511     HANDLE hThread = GetCurrentThread();
5512     DWORD dwTask = 0;
5513     HANDLE hAVRT = NULL;
5514
5515     /* If we have access to AVRT.DLL (Vista and later), use it */
5516     if (paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics != NULL) 
5517     {
5518         hAVRT = paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics("Pro Audio", &dwTask);
5519         if (hAVRT != NULL && hAVRT != INVALID_HANDLE_VALUE) 
5520         {
5521             BOOL bret = paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority(hAVRT, PA_AVRT_PRIORITY_CRITICAL);
5522             if (!bret)
5523             {
5524                 PA_DEBUG(("Set mm thread prio to critical failed!\n"));
5525             }
5526             else
5527             {
5528                 return hAVRT;
5529             }
5530         }
5531         else
5532         {
5533             PA_DEBUG(("Set mm thread characteristic to 'Pro Audio' failed, reverting to SetThreadPriority\n"));
5534         }
5535     }
5536
5537     /* For XP and earlier, or if AvSetMmThreadCharacteristics fails (MMCSS disabled ?) */
5538     if (timeBeginPeriod(1) != TIMERR_NOERROR) {
5539         PA_DEBUG(("timeBeginPeriod(1) failed!\n"));
5540     }
5541
5542     if (!SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL)) {
5543         PA_DEBUG(("SetThreadPriority failed!\n"));
5544     }
5545
5546     return hAVRT;
5547 }
5548
5549 /*
5550 Decrease the priority of the calling thread to normal
5551 */
5552 static void DropThreadPriority(HANDLE hAVRT)
5553 {
5554     HANDLE hThread = GetCurrentThread();
5555
5556     if (hAVRT != NULL) 
5557     {
5558         paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority(hAVRT, PA_AVRT_PRIORITY_NORMAL);
5559         paWinWDMKSAvRtEntryPoints.AvRevertMmThreadCharacteristics(hAVRT);
5560         return;
5561     }
5562
5563     SetThreadPriority(hThread, THREAD_PRIORITY_NORMAL);
5564     timeEndPeriod(1);
5565 }
5566
5567 static PaError PreparePinForStart(PaWinWdmPin* pin)
5568 {
5569     PaError result;
5570     result = PinSetState(pin, KSSTATE_ACQUIRE);
5571     if (result != paNoError)
5572     {
5573         goto error;
5574     }
5575     result = PinSetState(pin, KSSTATE_PAUSE);
5576     if (result != paNoError)
5577     {
5578         goto error;
5579     }
5580     return result;
5581
5582 error:
5583     PinSetState(pin, KSSTATE_STOP);
5584     return result;
5585 }
5586
5587 static PaError PreparePinsForStart(PaProcessThreadInfo* pInfo)
5588 {
5589     PaError result = paNoError;
5590     /* Submit buffers */
5591     if (pInfo->stream->capture.pPin)
5592     {
5593         if ((result = PreparePinForStart(pInfo->stream->capture.pPin)) != paNoError)
5594         {
5595             goto error;
5596         }
5597
5598         if (pInfo->stream->capture.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
5599         {
5600             unsigned i;
5601             for(i=0; i < pInfo->stream->capture.noOfPackets; ++i)
5602             {
5603                 if ((result = PinRead(pInfo->stream->capture.pPin->handle, pInfo->stream->capture.packets + i)) != paNoError)
5604                 {
5605                     goto error;
5606                 }
5607                 ++pInfo->pending;
5608             }
5609         }
5610         else
5611         {
5612             pInfo->pending = 2;
5613         }
5614     }
5615
5616     if(pInfo->stream->render.pPin)
5617     {
5618         if ((result = PreparePinForStart(pInfo->stream->render.pPin)) != paNoError)
5619         {
5620             goto error;
5621         }
5622
5623         pInfo->priming += pInfo->stream->render.noOfPackets;
5624         ++pInfo->pending;
5625         SetEvent(pInfo->stream->render.events[0]);
5626         if (pInfo->stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic) 
5627         {
5628             unsigned i;
5629             for(i=1; i < pInfo->stream->render.noOfPackets; ++i)
5630             {
5631                 SetEvent(pInfo->stream->render.events[i]);
5632                 ++pInfo->pending;
5633             }
5634         }
5635     }
5636
5637 error:
5638     PA_DEBUG(("PreparePinsForStart = %d\n", result));
5639     return result;
5640 }
5641
5642 static PaError StartPin(PaWinWdmPin* pin)
5643 {
5644     return PinSetState(pin, KSSTATE_RUN);
5645 }
5646
5647 static PaError StartPins(PaProcessThreadInfo* pInfo)
5648 {
5649     PaError result = paNoError;
5650     /* Start the pins as synced as possible */
5651     if (pInfo->stream->capture.pPin)
5652     {
5653         result = StartPin(pInfo->stream->capture.pPin);
5654     }
5655     if(pInfo->stream->render.pPin)
5656     {
5657         result = StartPin(pInfo->stream->render.pPin);
5658     }
5659     PA_DEBUG(("StartPins = %d\n", result));
5660     return result;
5661 }
5662
5663
5664 static PaError StopPin(PaWinWdmPin* pin)
5665 {
5666     PinSetState(pin, KSSTATE_PAUSE);
5667     PinSetState(pin, KSSTATE_STOP);
5668     return paNoError;
5669 }
5670
5671
5672 static PaError StopPins(PaProcessThreadInfo* pInfo)
5673 {
5674     PaError result = paNoError;
5675     if(pInfo->stream->render.pPin)
5676     {
5677         StopPin(pInfo->stream->render.pPin);
5678     }
5679     if(pInfo->stream->capture.pPin)
5680     {
5681         StopPin(pInfo->stream->capture.pPin);
5682     }
5683     return result;
5684 }
5685
5686 typedef void (*TSetInputFrameCount)(PaUtilBufferProcessor*, unsigned long);
5687 typedef void (*TSetInputChannel)(PaUtilBufferProcessor*, unsigned int, void *, unsigned int);
5688 static const TSetInputFrameCount fnSetInputFrameCount[2] = { PaUtil_SetInputFrameCount, PaUtil_Set2ndInputFrameCount };
5689 static const TSetInputChannel fnSetInputChannel[2] = { PaUtil_SetInputChannel, PaUtil_Set2ndInputChannel };
5690
5691 static PaError PaDoProcessing(PaProcessThreadInfo* pInfo)
5692 {
5693     PaError result = paNoError;
5694     int i, framesProcessed = 0, doChannelCopy = 0;
5695     ring_buffer_size_t inputFramesAvailable = PaUtil_GetRingBufferReadAvailable(&pInfo->stream->ringBuffer);
5696
5697     /* Do necessary buffer processing (which will invoke user callback if necessary) */
5698     if (pInfo->cbResult == paContinue &&
5699         (pInfo->renderHead != pInfo->renderTail || inputFramesAvailable))
5700     {
5701         unsigned processFullDuplex = pInfo->stream->capture.pPin && pInfo->stream->render.pPin && (!pInfo->priming);
5702
5703         PA_HP_TRACE((pInfo->stream->hLog, "DoProcessing: InputFrames=%u", inputFramesAvailable));
5704
5705         PaUtil_BeginCpuLoadMeasurement( &pInfo->stream->cpuLoadMeasurer );
5706
5707         pInfo->ti.currentTime = PaUtil_GetTime();
5708
5709         PaUtil_BeginBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->ti, pInfo->underover);
5710         pInfo->underover = 0; /* Reset the (under|over)flow status */
5711
5712         if (pInfo->renderTail != pInfo->renderHead)
5713         {
5714             DATAPACKET* packet = pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet;
5715
5716             assert(packet != 0);
5717             assert(packet->Header.Data != 0);
5718
5719             PaUtil_SetOutputFrameCount(&pInfo->stream->bufferProcessor, pInfo->stream->render.framesPerBuffer);
5720
5721             for(i=0;i<pInfo->stream->userOutputChannels;i++)
5722             {
5723                 /* Only write the user output channels. Leave the rest blank */
5724                 PaUtil_SetOutputChannel(&pInfo->stream->bufferProcessor,
5725                     i,
5726                     ((unsigned char*)(packet->Header.Data))+(i*pInfo->stream->render.bytesPerSample),
5727                     pInfo->stream->deviceOutputChannels);
5728             }
5729
5730             /* We will do a copy to the other channels after the data has been written */
5731             doChannelCopy = ( pInfo->stream->userOutputChannels == 1 );
5732         }
5733
5734         if (inputFramesAvailable && (!pInfo->stream->userOutputChannels || inputFramesAvailable >= (int)pInfo->stream->render.framesPerBuffer))
5735         {
5736             unsigned wrapCntr = 0;
5737             void* data[2] = {0};
5738             ring_buffer_size_t size[2] = {0};
5739
5740             /* If full-duplex, we just extract output buffer number of frames */
5741             if (pInfo->stream->userOutputChannels)
5742             {
5743                 inputFramesAvailable = min(inputFramesAvailable, (int)pInfo->stream->render.framesPerBuffer);
5744             }
5745
5746             inputFramesAvailable = PaUtil_GetRingBufferReadRegions(&pInfo->stream->ringBuffer,
5747                 inputFramesAvailable,
5748                 &data[0],
5749                 &size[0],
5750                 &data[1],
5751                 &size[1]);
5752
5753             for (wrapCntr = 0; wrapCntr < 2; ++wrapCntr)
5754             {
5755                 if (size[wrapCntr] == 0)
5756                     break;
5757
5758                 fnSetInputFrameCount[wrapCntr](&pInfo->stream->bufferProcessor, size[wrapCntr]);
5759                 for(i=0;i<pInfo->stream->userInputChannels;i++)
5760                 {
5761                     /* Only read as many channels as the user wants */
5762                     fnSetInputChannel[wrapCntr](&pInfo->stream->bufferProcessor,
5763                         i,
5764                         ((unsigned char*)(data[wrapCntr]))+(i*pInfo->stream->capture.bytesPerSample),
5765                         pInfo->stream->deviceInputChannels);
5766                 }
5767             }
5768         }
5769         else
5770         {
5771             /* We haven't consumed anything from the ring buffer... */
5772             inputFramesAvailable = 0;
5773             /* If we have full-duplex, this is at startup, so mark no-input! */
5774             if (pInfo->stream->userOutputChannels>0 && pInfo->stream->userInputChannels>0)
5775             {
5776                 PA_HP_TRACE((pInfo->stream->hLog, "Input startup, marking no input."));
5777                 PaUtil_SetNoInput(&pInfo->stream->bufferProcessor);
5778             }
5779         }
5780
5781         if (processFullDuplex) /* full duplex */
5782         {
5783             /* Only call the EndBufferProcessing function when the total input frames == total output frames */
5784             const unsigned long totalInputFrameCount = pInfo->stream->bufferProcessor.hostInputFrameCount[0] + pInfo->stream->bufferProcessor.hostInputFrameCount[1];
5785             const unsigned long totalOutputFrameCount = pInfo->stream->bufferProcessor.hostOutputFrameCount[0] + pInfo->stream->bufferProcessor.hostOutputFrameCount[1];
5786
5787             if(totalInputFrameCount == totalOutputFrameCount && totalOutputFrameCount != 0)
5788             {
5789                 framesProcessed = PaUtil_EndBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->cbResult);
5790             }
5791             else
5792             {
5793                 framesProcessed = 0;
5794             }
5795         }
5796         else 
5797         {
5798             framesProcessed = PaUtil_EndBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->cbResult);
5799         }
5800
5801         PA_HP_TRACE((pInfo->stream->hLog, "Frames processed: %u %s", framesProcessed, (pInfo->priming ? "(priming)":"")));
5802
5803         if( doChannelCopy )
5804         {
5805             DATAPACKET* packet = pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet;
5806             /* Copy the first output channel to the other channels */
5807             switch (pInfo->stream->render.bytesPerSample)
5808             {
5809             case 2:
5810                 DuplicateFirstChannelInt16(packet->Header.Data, pInfo->stream->deviceOutputChannels, pInfo->stream->render.framesPerBuffer);
5811                 break;
5812             case 3:
5813                 DuplicateFirstChannelInt24(packet->Header.Data, pInfo->stream->deviceOutputChannels, pInfo->stream->render.framesPerBuffer);
5814                 break;
5815             case 4:
5816                 DuplicateFirstChannelInt32(packet->Header.Data, pInfo->stream->deviceOutputChannels, pInfo->stream->render.framesPerBuffer);
5817                 break;
5818             default:
5819                 assert(0); /* Unsupported format! */
5820                 break;
5821             }
5822         }
5823         PaUtil_EndCpuLoadMeasurement( &pInfo->stream->cpuLoadMeasurer, framesProcessed );
5824
5825         if (inputFramesAvailable)
5826         {
5827             PaUtil_AdvanceRingBufferReadIndex(&pInfo->stream->ringBuffer, inputFramesAvailable);
5828         }
5829
5830         if (pInfo->renderTail != pInfo->renderHead)
5831         {
5832             if (!pInfo->stream->streamStop)
5833             {
5834                 result = pInfo->stream->render.pPin->fnSubmitHandler(pInfo, pInfo->renderTail);
5835                 if (result != paNoError)
5836                 {
5837                     PA_HP_TRACE((pInfo->stream->hLog, "Capture submit handler failed with result %d", result));
5838                     return result;
5839                 }
5840             }
5841             pInfo->renderTail++;
5842             if (!pInfo->pinsStarted && pInfo->priming == 0)
5843             {
5844                 /* We start the pins here to allow "prime time" */
5845                 if ((result = StartPins(pInfo)) == paNoError)
5846                 {
5847                     PA_HP_TRACE((pInfo->stream->hLog, "Starting pins!"));
5848                     pInfo->pinsStarted = 1;
5849                 }
5850             }
5851         }
5852     }
5853
5854     return result;
5855 }
5856
5857 static VOID CALLBACK TimerAPCWaveRTPolledMode(
5858     LPVOID lpArgToCompletionRoutine,
5859     DWORD dwTimerLowValue,
5860     DWORD dwTimerHighValue)
5861 {
5862     HANDLE* pHandles = (HANDLE*)lpArgToCompletionRoutine;
5863     if (pHandles[0]) SetEvent(pHandles[0]);
5864     if (pHandles[1]) SetEvent(pHandles[1]);
5865 }
5866
5867 static DWORD GetCurrentTimeInMillisecs()
5868 {
5869     return timeGetTime();
5870 }
5871
5872 PA_THREAD_FUNC ProcessingThread(void* pParam)
5873 {
5874     PaError result = paNoError;
5875     HANDLE hAVRT = NULL;
5876     HANDLE hTimer = NULL;
5877     HANDLE *handleArray = NULL;
5878     HANDLE timerEventHandles[2] = {0};
5879     unsigned noOfHandles = 0;
5880     unsigned captureEvents = 0;
5881     unsigned renderEvents = 0;
5882     unsigned timerPeriod = 0;
5883     DWORD timeStamp[2] = {0};
5884
5885     PaProcessThreadInfo info;
5886     memset(&info, 0, sizeof(PaProcessThreadInfo));
5887     info.stream = (PaWinWdmStream*)pParam;
5888
5889     info.stream->threadResult = paNoError;
5890
5891     PA_LOGE_;
5892
5893     info.ti.inputBufferAdcTime = 0.0;
5894     info.ti.currentTime = 0.0;
5895     info.ti.outputBufferDacTime = 0.0;
5896
5897     PA_DEBUG(("In  buffer len: %.3f ms\n",(2000*info.stream->capture.framesPerBuffer) / info.stream->streamRepresentation.streamInfo.sampleRate));
5898     PA_DEBUG(("Out buffer len: %.3f ms\n",(2000*info.stream->render.framesPerBuffer) / info.stream->streamRepresentation.streamInfo.sampleRate));
5899     info.timeout = (DWORD)max(
5900         (2000*info.stream->render.framesPerBuffer/info.stream->streamRepresentation.streamInfo.sampleRate + 0.5),
5901         (2000*info.stream->capture.framesPerBuffer/info.stream->streamRepresentation.streamInfo.sampleRate + 0.5));
5902     info.timeout = max(info.timeout*8, 100);
5903     timerPeriod = info.timeout;
5904     PA_DEBUG(("Timeout = %ld ms\n",info.timeout));
5905
5906     /* Allocate handle array */
5907     handleArray = (HANDLE*)PaUtil_AllocateMemory((info.stream->capture.noOfPackets + info.stream->render.noOfPackets + 1) * sizeof(HANDLE));
5908
5909     /* Setup handle array for WFMO */
5910     if (info.stream->capture.pPin != 0)
5911     {
5912         handleArray[noOfHandles++] = info.stream->capture.events[0];
5913         if (info.stream->capture.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
5914         {
5915             unsigned i;
5916             for(i=1; i < info.stream->capture.noOfPackets; ++i)
5917             {
5918                 handleArray[noOfHandles++] = info.stream->capture.events[i];
5919             }
5920         }
5921         captureEvents = noOfHandles;
5922         renderEvents = noOfHandles;
5923     }
5924
5925     if (info.stream->render.pPin != 0)
5926     {
5927         handleArray[noOfHandles++] = info.stream->render.events[0];
5928         if (info.stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
5929         {
5930             unsigned i;
5931             for(i=1; i < info.stream->render.noOfPackets; ++i)
5932             {
5933                 handleArray[noOfHandles++] = info.stream->render.events[i];
5934             }
5935         }
5936         renderEvents = noOfHandles;
5937     }
5938     handleArray[noOfHandles++] = info.stream->eventAbort;
5939     assert(noOfHandles <= (info.stream->capture.noOfPackets + info.stream->render.noOfPackets + 1));
5940
5941     /* Prepare render and capture pins */
5942     if ((result = PreparePinsForStart(&info)) != paNoError) 
5943     {
5944         PA_DEBUG(("Failed to prepare device(s)!\n"));
5945         goto error;
5946     }
5947
5948     /* Init high speed logger */
5949     if (PaUtil_InitializeHighSpeedLog(&info.stream->hLog, 1000000) != paNoError)
5950     {
5951         PA_DEBUG(("Failed to init high speed logger!\n"));
5952         goto error;
5953     }
5954
5955     /* Heighten priority here */
5956     hAVRT = BumpThreadPriority();
5957
5958     /* If input only, we start the pins immediately */
5959     if (info.stream->render.pPin == 0)
5960     {
5961         if ((result = StartPins(&info)) != paNoError)
5962         {
5963             PA_DEBUG(("Failed to start device(s)!\n"));
5964             goto error;
5965         }
5966         info.pinsStarted = 1;
5967     }
5968
5969     /* Handle WaveRT polled mode */
5970     {
5971         const unsigned fs = (unsigned)info.stream->streamRepresentation.streamInfo.sampleRate;
5972         if (info.stream->capture.pPin != 0 && info.stream->capture.pPin->pinKsSubType == SubType_kPolled)
5973         {
5974             timerEventHandles[0] = info.stream->capture.events[0];
5975             timerPeriod = min(timerPeriod, (1000*info.stream->capture.framesPerBuffer)/fs);
5976         }
5977
5978         if (info.stream->render.pPin != 0 && info.stream->render.pPin->pinKsSubType == SubType_kPolled)
5979         {
5980             timerEventHandles[1] = info.stream->render.events[0];
5981             timerPeriod = min(timerPeriod, (1000*info.stream->render.framesPerBuffer)/fs);
5982         }
5983
5984         if (timerEventHandles[0] || timerEventHandles[1])
5985         {
5986             LARGE_INTEGER dueTime = {0};
5987
5988             timerPeriod=max(timerPeriod/5,1);
5989             PA_DEBUG(("Timer event handles=0x%04X,0x%04X period=%u ms", timerEventHandles[0], timerEventHandles[1], timerPeriod));
5990             hTimer = CreateWaitableTimer(0, FALSE, NULL);
5991             if (hTimer == NULL)
5992             {
5993                 result = paUnanticipatedHostError;
5994                 goto error;
5995             }
5996             /* invoke first timeout immediately */
5997             if (!SetWaitableTimer(hTimer, &dueTime, timerPeriod, TimerAPCWaveRTPolledMode, timerEventHandles, FALSE))
5998             {
5999                 result = paUnanticipatedHostError;
6000                 goto error;
6001             }
6002             PA_DEBUG(("Waitable timer started, period = %u ms\n", timerPeriod));
6003         }
6004     }
6005
6006     /* Mark stream as active */
6007     info.stream->streamActive = 1;
6008     info.stream->threadResult = paNoError;
6009
6010     /* Up and running... */
6011     SetEvent(info.stream->eventStreamStart[StreamStart_kOk]);
6012
6013     /* Take timestamp here */
6014     timeStamp[0] = timeStamp[1] = GetCurrentTimeInMillisecs();
6015
6016     while(!info.stream->streamAbort)
6017     {
6018         unsigned doProcessing = 1;
6019         unsigned wait = WaitForMultipleObjects(noOfHandles, handleArray, FALSE, 0);
6020         unsigned eventSignalled = wait - WAIT_OBJECT_0;
6021         DWORD dwCurrentTime = 0;
6022
6023         if (wait == WAIT_FAILED) 
6024         {
6025             PA_DEBUG(("Wait failed = %ld! \n",wait));
6026             break;
6027         }
6028         if (wait == WAIT_TIMEOUT)
6029         {
6030             wait = WaitForMultipleObjectsEx(noOfHandles, handleArray, FALSE, 50, TRUE);
6031             eventSignalled = wait - WAIT_OBJECT_0;
6032         }
6033         else
6034         {
6035             if (eventSignalled < captureEvents)
6036             {
6037                 if (PaUtil_GetRingBufferWriteAvailable(&info.stream->ringBuffer) == 0)
6038                 {
6039                     PA_HP_TRACE((info.stream->hLog, "!!!!! Input overflow !!!!!"));
6040                     info.underover |= paInputOverflow;
6041                 }
6042             }
6043             else if (eventSignalled < renderEvents)
6044             {
6045                 if (!info.priming && info.renderHead - info.renderTail > 1)
6046                 {
6047                     PA_HP_TRACE((info.stream->hLog, "!!!!! Output underflow !!!!!"));
6048                     info.underover |= paOutputUnderflow;
6049                 }
6050             }
6051         }
6052
6053         /* Get event time */
6054         dwCurrentTime = GetCurrentTimeInMillisecs();
6055
6056         /* Since we can mix capture/render devices between WaveCyclic, WaveRT polled and WaveRT notification (3x3 combinations), 
6057         we can't rely on the timeout of WFMO to check for device timeouts, we need to keep tally. */
6058         if (info.stream->capture.pPin && (dwCurrentTime - timeStamp[0]) >= info.timeout)
6059         {
6060             PA_DEBUG(("Timeout for capture device (%u ms)!", info.timeout, (dwCurrentTime - timeStamp[0])));
6061             result = paTimedOut;
6062             break;
6063         }
6064         if (info.stream->render.pPin && (dwCurrentTime - timeStamp[1]) >= info.timeout)
6065         {
6066             PA_DEBUG(("Timeout for render device (%u ms)!", info.timeout, (dwCurrentTime - timeStamp[1])));
6067             result = paTimedOut;
6068             break;
6069         }
6070
6071         if (wait == WAIT_IO_COMPLETION)
6072         {
6073             /* Waitable timer has fired! */
6074             PA_HP_TRACE((info.stream->hLog, "WAIT_IO_COMPLETION"));
6075             continue;
6076         }
6077
6078         if (wait == WAIT_TIMEOUT)
6079         {
6080             continue;
6081         }
6082         else
6083         {
6084             if (eventSignalled < captureEvents)
6085             {
6086                 if (info.stream->capture.pPin->fnEventHandler(&info, eventSignalled) == paNoError)
6087                 {
6088                     timeStamp[0] = dwCurrentTime;
6089
6090                     /* Since we use the ring buffer, we can submit the buffers directly */
6091                     if (!info.stream->streamStop)
6092                     {
6093                         result = info.stream->capture.pPin->fnSubmitHandler(&info, info.captureTail);
6094                         if (result != paNoError)
6095                         {
6096                             PA_HP_TRACE((info.stream->hLog, "Capture submit handler failed with result %d", result));
6097                             break;
6098                         }
6099                     }
6100                     ++info.captureTail;
6101                     /* If full-duplex, let _only_ render event trigger processing. We still need the stream stop
6102                     handling working, so let that be processed anyways... */
6103                     if (info.stream->userOutputChannels > 0)
6104                     {
6105                         doProcessing = 0;
6106                     }
6107                 }
6108             }
6109             else if (eventSignalled < renderEvents)
6110             {
6111                 timeStamp[1] = dwCurrentTime;
6112                 eventSignalled -= captureEvents;
6113                 info.stream->render.pPin->fnEventHandler(&info, eventSignalled);
6114             }
6115             else
6116             {
6117                 assert(info.stream->streamAbort);
6118                 PA_HP_TRACE((info.stream->hLog, "Stream abort!"));
6119                 continue;
6120             }
6121         }
6122
6123         /* Handle processing */
6124         if (doProcessing)
6125         {
6126             result = PaDoProcessing(&info);
6127             if (result != paNoError)
6128             {
6129                 PA_HP_TRACE((info.stream->hLog, "PaDoProcessing failed!"));
6130                 break;
6131             }
6132         }
6133
6134         if(info.stream->streamStop && info.cbResult != paComplete)
6135         {
6136             PA_HP_TRACE((info.stream->hLog, "Stream stop! pending=%d",info.pending));
6137             info.cbResult = paComplete; /* Stop, but play remaining buffers */
6138         }
6139
6140         if(info.pending<=0)
6141         {
6142             PA_HP_TRACE((info.stream->hLog, "pending==0 finished..."));
6143             break;
6144         }
6145         if((!info.stream->render.pPin)&&(info.cbResult!=paContinue))
6146         {
6147             PA_HP_TRACE((info.stream->hLog, "record only cbResult=%d...",info.cbResult));
6148             break;
6149         }
6150     }
6151
6152     PA_DEBUG(("Finished processing loop\n"));
6153
6154     info.stream->threadResult = result;
6155     goto bailout;
6156
6157 error:
6158     PA_DEBUG(("Error starting processing thread\n"));
6159     /* Set the "error" event together with result */
6160     info.stream->threadResult = result;
6161     SetEvent(info.stream->eventStreamStart[StreamStart_kFailed]);
6162
6163 bailout:
6164     if (hTimer)
6165     {
6166         PA_DEBUG(("Waitable timer stopped\n", timerPeriod));
6167         CancelWaitableTimer(hTimer);
6168         CloseHandle(hTimer);
6169         hTimer = 0;
6170     }
6171
6172     if (info.pinsStarted)
6173     {
6174         StopPins(&info);
6175     }
6176
6177     /* Lower prio here */
6178     DropThreadPriority(hAVRT);
6179
6180     if (handleArray != NULL)
6181     {
6182         PaUtil_FreeMemory(handleArray);
6183     }
6184
6185 #if PA_TRACE_REALTIME_EVENTS
6186     if (info.stream->hLog)
6187     {
6188         PA_DEBUG(("Dumping highspeed trace...\n"));
6189         PaUtil_DumpHighSpeedLog(info.stream->hLog, "hp_trace.log");
6190         PaUtil_DiscardHighSpeedLog(info.stream->hLog);
6191         info.stream->hLog = 0;
6192     }
6193 #endif
6194     info.stream->streamActive = 0;
6195
6196     if((!info.stream->streamStop)&&(!info.stream->streamAbort))
6197     {
6198         /* Invoke the user stream finished callback */
6199         /* Only do it from here if not being stopped/aborted by user */
6200         if( info.stream->streamRepresentation.streamFinishedCallback != 0 )
6201             info.stream->streamRepresentation.streamFinishedCallback( info.stream->streamRepresentation.userData );
6202     }
6203     info.stream->streamStop = 0;
6204     info.stream->streamAbort = 0;
6205
6206     PA_LOGL_;
6207     return 0;
6208 }
6209
6210
6211 static PaError StartStream( PaStream *s )
6212 {
6213     PaError result = paNoError;
6214     PaWinWdmStream *stream = (PaWinWdmStream*)s;
6215
6216     PA_LOGE_;
6217
6218     if (stream->streamThread != NULL)
6219     {
6220         return paStreamIsNotStopped;
6221     }
6222
6223     stream->streamStop = 0;
6224     stream->streamAbort = 0;
6225
6226     ResetStreamEvents(stream);
6227
6228     PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
6229
6230     stream->oldProcessPriority = GetPriorityClass(GetCurrentProcess());
6231     /* Uncomment the following line to enable dynamic boosting of the process
6232     * priority to real time for best low latency support
6233     * Disabled by default because RT processes can easily block the OS */
6234     /*ret = SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS);
6235     PA_DEBUG(("Class ret = %d;",ret));*/
6236
6237     stream->streamThread = CREATE_THREAD_FUNCTION (NULL, 0, ProcessingThread, stream, CREATE_SUSPENDED, NULL);
6238     if(stream->streamThread == NULL)
6239     {
6240         result = paInsufficientMemory;
6241         goto end;
6242     }
6243     ResumeThread(stream->streamThread);
6244
6245     switch (WaitForMultipleObjects(2, stream->eventStreamStart, FALSE, 5000))
6246     {
6247     case WAIT_OBJECT_0 + StreamStart_kOk:
6248         PA_DEBUG(("Processing thread started!\n"));
6249         result = paNoError;
6250         /* streamActive is set in processing thread */
6251         stream->streamStarted = 1;
6252         break;
6253     case WAIT_OBJECT_0 + StreamStart_kFailed:
6254         PA_DEBUG(("Processing thread start failed! (result=%d)\n", stream->threadResult));
6255         result = stream->threadResult;
6256         /* Wait for the stream to really exit */
6257         WaitForSingleObject(stream->streamThread, 200);
6258         CloseHandle(stream->streamThread);
6259         stream->streamThread = 0;
6260         break;
6261     case WAIT_TIMEOUT:
6262     default:
6263         result = paTimedOut;
6264         PaWinWDM_SetLastErrorInfo(result, "Failed to start processing thread (timeout)!");
6265         break;
6266     }
6267
6268 end:
6269     PA_LOGL_;
6270     return result;
6271 }
6272
6273
6274 static PaError StopStream( PaStream *s )
6275 {
6276     PaError result = paNoError;
6277     PaWinWdmStream *stream = (PaWinWdmStream*)s;
6278     BOOL doCb = FALSE;
6279
6280     PA_LOGE_;
6281
6282     if(stream->streamActive)
6283     {
6284         DWORD dwExitCode;
6285         doCb = TRUE;
6286         stream->streamStop = 1;
6287         if (GetExitCodeThread(stream->streamThread, &dwExitCode) && dwExitCode == STILL_ACTIVE)
6288         {
6289             if (WaitForSingleObject(stream->streamThread, INFINITE) != WAIT_OBJECT_0)
6290             {
6291                 PA_DEBUG(("StopStream: stream thread terminated\n"));
6292                 TerminateThread(stream->streamThread, -1);
6293                 result = paTimedOut;
6294             }
6295         }
6296         else
6297         {
6298             PA_DEBUG(("StopStream: GECT says not active, but streamActive is not false ??"));
6299             result = paUnanticipatedHostError;
6300             PaWinWDM_SetLastErrorInfo(result, "StopStream: GECT says not active, but streamActive = %d", stream->streamActive);
6301         }
6302     }
6303     else
6304     {
6305         if (stream->threadResult != paNoError)
6306         {
6307             PA_DEBUG(("StopStream: Stream not active (%d)\n", stream->threadResult));
6308             result = stream->threadResult;
6309             stream->threadResult = paNoError;
6310         }
6311     }
6312
6313     if (stream->streamThread != NULL)
6314     {
6315         CloseHandle(stream->streamThread);
6316         stream->streamThread = 0;
6317     }
6318     stream->streamStarted = 0;
6319     stream->streamActive = 0;
6320
6321     if(doCb)
6322     {
6323         /* Do user callback now after all state has been reset */
6324         /* This means it should be safe for the called function */
6325         /* to invoke e.g. StartStream */
6326         if( stream->streamRepresentation.streamFinishedCallback != 0 )
6327             stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
6328     }
6329
6330     PA_LOGL_;
6331     return result;
6332 }
6333
6334 static PaError AbortStream( PaStream *s )
6335 {
6336     PaError result = paNoError;
6337     PaWinWdmStream *stream = (PaWinWdmStream*)s;
6338     int doCb = 0;
6339
6340     PA_LOGE_;
6341
6342     if(stream->streamActive)
6343     {
6344         doCb = 1;
6345         stream->streamAbort = 1;
6346         SetEvent(stream->eventAbort); /* Signal immediately */
6347         if (WaitForSingleObject(stream->streamThread, 10000) != WAIT_OBJECT_0)
6348         {
6349             TerminateThread(stream->streamThread, -1);
6350             result = paTimedOut;
6351
6352             PA_DEBUG(("AbortStream: stream thread terminated\n"));
6353         }
6354         assert(!stream->streamActive);
6355     }
6356     CloseHandle(stream->streamThread);
6357     stream->streamThread = NULL;
6358     stream->streamStarted = 0;
6359
6360     if(doCb)
6361     {
6362         /* Do user callback now after all state has been reset */
6363         /* This means it should be safe for the called function */
6364         /* to invoke e.g. StartStream */
6365         if( stream->streamRepresentation.streamFinishedCallback != 0 )
6366             stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
6367     }
6368
6369     stream->streamActive = 0;
6370     stream->streamStarted = 0;
6371
6372     PA_LOGL_;
6373     return result;
6374 }
6375
6376
6377 static PaError IsStreamStopped( PaStream *s )
6378 {
6379     PaWinWdmStream *stream = (PaWinWdmStream*)s;
6380     int result = 0;
6381
6382     PA_LOGE_;
6383
6384     if(!stream->streamStarted)
6385         result = 1;
6386
6387     PA_LOGL_;
6388     return result;
6389 }
6390
6391
6392 static PaError IsStreamActive( PaStream *s )
6393 {
6394     PaWinWdmStream *stream = (PaWinWdmStream*)s;
6395     int result = 0;
6396
6397     PA_LOGE_;
6398
6399     if(stream->streamActive)
6400         result = 1;
6401
6402     PA_LOGL_;
6403     return result;
6404 }
6405
6406
6407 static PaTime GetStreamTime( PaStream* s )
6408 {
6409     PA_LOGE_;
6410     PA_LOGL_;
6411     (void)s;
6412     return PaUtil_GetTime();
6413 }
6414
6415
6416 static double GetStreamCpuLoad( PaStream* s )
6417 {
6418     PaWinWdmStream *stream = (PaWinWdmStream*)s;
6419     double result;
6420     PA_LOGE_;
6421     result = PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
6422     PA_LOGL_;
6423     return result;
6424 }
6425
6426
6427 /*
6428 As separate stream interfaces are used for blocking and callback
6429 streams, the following functions can be guaranteed to only be called
6430 for blocking streams.
6431 */
6432
6433 static PaError ReadStream( PaStream* s,
6434                           void *buffer,
6435                           unsigned long frames )
6436 {
6437     PaWinWdmStream *stream = (PaWinWdmStream*)s;
6438
6439     PA_LOGE_;
6440
6441     /* suppress unused variable warnings */
6442     (void) buffer;
6443     (void) frames;
6444     (void) stream;
6445
6446     /* IMPLEMENT ME, see portaudio.h for required behavior*/
6447     PA_LOGL_;
6448     return paInternalError;
6449 }
6450
6451
6452 static PaError WriteStream( PaStream* s,
6453                            const void *buffer,
6454                            unsigned long frames )
6455 {
6456     PaWinWdmStream *stream = (PaWinWdmStream*)s;
6457
6458     PA_LOGE_;
6459
6460     /* suppress unused variable warnings */
6461     (void) buffer;
6462     (void) frames;
6463     (void) stream;
6464
6465     /* IMPLEMENT ME, see portaudio.h for required behavior*/
6466     PA_LOGL_;
6467     return paInternalError;
6468 }
6469
6470
6471 static signed long GetStreamReadAvailable( PaStream* s )
6472 {
6473     PaWinWdmStream *stream = (PaWinWdmStream*)s;
6474
6475     PA_LOGE_;
6476
6477     /* suppress unused variable warnings */
6478     (void) stream;
6479
6480     /* IMPLEMENT ME, see portaudio.h for required behavior*/
6481     PA_LOGL_;
6482     return 0;
6483 }
6484
6485
6486 static signed long GetStreamWriteAvailable( PaStream* s )
6487 {
6488     PaWinWdmStream *stream = (PaWinWdmStream*)s;
6489
6490     PA_LOGE_;
6491     /* suppress unused variable warnings */
6492     (void) stream;
6493
6494     /* IMPLEMENT ME, see portaudio.h for required behavior*/
6495     PA_LOGL_;
6496     return 0;
6497 }
6498
6499 /***************************************************************************************/
6500 /* Event and submit handlers for WaveCyclic                                            */
6501 /***************************************************************************************/
6502
6503 static PaError PaPinCaptureEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6504 {
6505     PaError result = paNoError;
6506     ring_buffer_size_t frameCount;
6507     DATAPACKET* packet = pInfo->stream->capture.packets + eventIndex;
6508
6509     assert( eventIndex < pInfo->stream->capture.noOfPackets );
6510
6511     if (packet->Header.DataUsed == 0)
6512     {
6513         PA_HP_TRACE((pInfo->stream->hLog, ">>> Capture bogus event (no data): idx=%u", eventIndex));
6514
6515         /* 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 
6516            on startup of streaming, where it erroneously sets the event without the corresponding buffer being filled (DataUsed == 0) */
6517         ResetEvent(packet->Signal.hEvent);
6518
6519         result = -1;    /* Only need this to be NOT paNoError */
6520     }
6521     else
6522     {
6523         pInfo->capturePackets[pInfo->captureHead & cPacketsArrayMask].packet = packet;
6524
6525         frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer, packet->Header.Data, pInfo->stream->capture.framesPerBuffer);
6526
6527         PA_HP_TRACE((pInfo->stream->hLog, ">>> Capture event: idx=%u (frames=%u)", eventIndex, frameCount));
6528         ++pInfo->captureHead;
6529     }
6530
6531     --pInfo->pending; /* This needs to be done in either case */
6532     return result;
6533 }
6534
6535 static PaError PaPinCaptureSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6536 {
6537     PaError result = paNoError;
6538     DATAPACKET* packet = pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet;
6539     pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet = 0;
6540     assert(packet != 0);
6541     PA_HP_TRACE((pInfo->stream->hLog, "Capture submit: %u", eventIndex));
6542     packet->Header.DataUsed = 0; /* Reset for reuse */
6543     ResetEvent(packet->Signal.hEvent);
6544     result = PinRead(pInfo->stream->capture.pPin->handle, packet);
6545     ++pInfo->pending;
6546     return result;
6547 }
6548
6549 static PaError PaPinRenderEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6550 {
6551     assert( eventIndex < pInfo->stream->render.noOfPackets );
6552
6553     pInfo->renderPackets[pInfo->renderHead & cPacketsArrayMask].packet = pInfo->stream->render.packets + eventIndex;
6554     PA_HP_TRACE((pInfo->stream->hLog, "<<< Render event : idx=%u head=%u", eventIndex, pInfo->renderHead));
6555     ++pInfo->renderHead;
6556     --pInfo->pending;
6557     return paNoError;
6558 }
6559
6560 static PaError PaPinRenderSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6561 {
6562     PaError result = paNoError;
6563     DATAPACKET* packet = pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet;
6564     pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet = 0;
6565     assert(packet != 0);
6566
6567     PA_HP_TRACE((pInfo->stream->hLog, "Render submit : %u idx=%u", pInfo->renderTail, (unsigned)(packet - pInfo->stream->render.packets)));
6568     ResetEvent(packet->Signal.hEvent);
6569     result = PinWrite(pInfo->stream->render.pPin->handle, packet);
6570     /* Reset event, just in case we have an analogous situation to capture (see PaPinCaptureSubmitHandler_WaveCyclic) */
6571     ++pInfo->pending;
6572     if (pInfo->priming)
6573     {
6574         --pInfo->priming;
6575     }
6576     return result;
6577 }
6578
6579 /***************************************************************************************/
6580 /* Event and submit handlers for WaveRT                                                */
6581 /***************************************************************************************/
6582
6583 static PaError PaPinCaptureEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6584 {
6585     unsigned long pos;
6586     unsigned realInBuf;
6587     unsigned frameCount;
6588     PaWinWdmIOInfo* pCapture = &pInfo->stream->capture;
6589     const unsigned halfInputBuffer = pCapture->hostBufferSize >> 1;
6590     PaWinWdmPin* pin = pCapture->pPin;
6591     DATAPACKET* packet = 0;
6592
6593     /* Get hold of current ADC position */
6594     pin->fnAudioPosition(pin, &pos);
6595     /* Wrap it (robi: why not use hw latency compensation here ?? because pos then gets _way_ off from
6596     where it should be, i.e. at beginning or half buffer position. Why? No idea.)  */
6597
6598     pos %= pCapture->hostBufferSize;
6599     /* Then realInBuf will point to "other" half of double buffer */
6600     realInBuf = pos < halfInputBuffer ? 1U : 0U;
6601
6602     packet = pInfo->stream->capture.packets + realInBuf;
6603
6604     /* Call barrier (or dummy) */
6605     pin->fnMemBarrier();
6606
6607     /* Put it in queue */
6608     frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer, packet->Header.Data, pCapture->framesPerBuffer);
6609
6610     pInfo->capturePackets[pInfo->captureHead & cPacketsArrayMask].packet = packet;
6611
6612     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));
6613
6614     ++pInfo->captureHead;
6615     --pInfo->pending;
6616
6617     return paNoError;
6618 }
6619
6620 static PaError PaPinCaptureEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6621 {
6622     unsigned long pos;
6623     unsigned bytesToRead;
6624     PaWinWdmIOInfo* pCapture = &pInfo->stream->capture;
6625     const unsigned halfInputBuffer = pCapture->hostBufferSize>>1;
6626     PaWinWdmPin* pin = pInfo->stream->capture.pPin;
6627
6628     /* Get hold of current ADC position */
6629     pin->fnAudioPosition(pin, &pos);
6630     /* Wrap it (robi: why not use hw latency compensation here ?? because pos then gets _way_ off from
6631     where it should be, i.e. at beginning or half buffer position. Why? No idea.)  */
6632     /* Compensate for HW FIFO to get to last read buffer position */
6633     pos += pin->hwLatency;
6634     pos %= pCapture->hostBufferSize;
6635     /* Need to align position on frame boundary */
6636     pos &= ~(pCapture->bytesPerFrame - 1);
6637
6638     /* Call barrier (or dummy) */
6639     pin->fnMemBarrier();
6640
6641     /* Put it in "queue" */
6642     bytesToRead = (pCapture->hostBufferSize + pos - pCapture->lastPosition) % pCapture->hostBufferSize;
6643     if (bytesToRead > 0)
6644     {
6645         unsigned frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer,
6646             pCapture->hostBuffer + pCapture->lastPosition,
6647             bytesToRead / pCapture->bytesPerFrame);
6648
6649         pCapture->lastPosition = (pCapture->lastPosition + frameCount * pCapture->bytesPerFrame) % pCapture->hostBufferSize;
6650
6651         PA_HP_TRACE((pInfo->stream->hLog, "Capture event (WaveRTPolled): pos = %4.1lf%%, framesRead=%u", (pos * 100.0 / pCapture->hostBufferSize), frameCount));
6652         ++pInfo->captureHead;
6653         --pInfo->pending;
6654     }
6655     return paNoError;
6656 }
6657
6658 static PaError PaPinCaptureSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6659 {
6660     pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet = 0;
6661     ++pInfo->pending;
6662     return paNoError;
6663 }
6664
6665 static PaError PaPinCaptureSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6666 {
6667     pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet = 0;
6668     ++pInfo->pending;
6669     return paNoError;
6670 }
6671
6672 static PaError PaPinRenderEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6673 {
6674     unsigned long pos;
6675     unsigned realOutBuf;
6676     PaWinWdmIOInfo* pRender = &pInfo->stream->render;
6677     const unsigned halfOutputBuffer = pRender->hostBufferSize >> 1;
6678     PaWinWdmPin* pin = pInfo->stream->render.pPin;
6679     PaIOPacket* ioPacket = &pInfo->renderPackets[pInfo->renderHead & cPacketsArrayMask];
6680
6681     /* Get hold of current DAC position */
6682     pin->fnAudioPosition(pin, &pos);
6683     /* Compensate for HW FIFO to get to last read buffer position */
6684     pos += pin->hwLatency;
6685     /* Wrap it */
6686     pos %= pRender->hostBufferSize;
6687     /* And align it, not sure its really needed though */
6688     pos &= ~(pRender->bytesPerFrame - 1);
6689     /* Then realOutBuf will point to "other" half of double buffer */
6690     realOutBuf = pos < halfOutputBuffer ? 1U : 0U;
6691
6692     if (pInfo->priming)
6693     {
6694         realOutBuf = pInfo->renderHead & 0x1;
6695     }
6696     ioPacket->packet = pInfo->stream->render.packets + realOutBuf;
6697     ioPacket->startByte = realOutBuf * halfOutputBuffer;
6698     ioPacket->lengthBytes = halfOutputBuffer;
6699
6700     PA_HP_TRACE((pInfo->stream->hLog, "Render event (WaveRT) : idx=%u head=%u (pos = %4.1lf%%)", realOutBuf, pInfo->renderHead, (pos * 100.0 / pRender->hostBufferSize) ));
6701
6702     ++pInfo->renderHead;
6703     --pInfo->pending;
6704     return paNoError;
6705 }
6706
6707 static PaError PaPinRenderEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6708 {
6709     unsigned long pos;
6710     unsigned realOutBuf;
6711     unsigned bytesToWrite;
6712
6713     PaWinWdmIOInfo* pRender = &pInfo->stream->render;
6714     const unsigned halfOutputBuffer = pRender->hostBufferSize >> 1;
6715     PaWinWdmPin* pin = pInfo->stream->render.pPin;
6716     PaIOPacket* ioPacket = &pInfo->renderPackets[pInfo->renderHead & cPacketsArrayMask];
6717
6718     /* Get hold of current DAC position */
6719     pin->fnAudioPosition(pin, &pos);
6720     /* Compensate for HW FIFO to get to last read buffer position */
6721     pos += pin->hwLatency;
6722     /* Wrap it */
6723     pos %= pRender->hostBufferSize;
6724     /* And align it, not sure its really needed though */
6725     pos &= ~(pRender->bytesPerFrame - 1);
6726
6727     if (pInfo->priming)
6728     {
6729         realOutBuf = pInfo->renderHead & 0x1;
6730         ioPacket->packet = pInfo->stream->render.packets + realOutBuf;
6731         ioPacket->startByte = realOutBuf * halfOutputBuffer;
6732         ioPacket->lengthBytes = halfOutputBuffer;
6733         ++pInfo->renderHead;
6734         --pInfo->pending;
6735     }
6736     else
6737     {
6738         bytesToWrite = (pRender->hostBufferSize + pos - pRender->lastPosition) % pRender->hostBufferSize;
6739         ++pRender->pollCntr;
6740         if (bytesToWrite >= halfOutputBuffer)
6741         {
6742             realOutBuf = (pos < halfOutputBuffer) ? 1U : 0U;
6743             ioPacket->packet = pInfo->stream->render.packets + realOutBuf;
6744             pRender->lastPosition = realOutBuf ? 0U : halfOutputBuffer;
6745             ioPacket->startByte = realOutBuf * halfOutputBuffer;
6746             ioPacket->lengthBytes = halfOutputBuffer;
6747             ++pInfo->renderHead;
6748             --pInfo->pending;
6749             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));
6750             pRender->pollCntr = 0;
6751         }
6752     }
6753     return paNoError;
6754 }
6755
6756 static PaError PaPinRenderSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6757 {
6758     PaWinWdmPin* pin = pInfo->stream->render.pPin;
6759     pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet = 0;
6760     /* Call barrier (if needed) */
6761     pin->fnMemBarrier();
6762     PA_HP_TRACE((pInfo->stream->hLog, "Render submit (WaveRT) : submit=%u", pInfo->renderTail));
6763     ++pInfo->pending;
6764     if (pInfo->priming)
6765     {
6766         --pInfo->priming;
6767         if (pInfo->priming)
6768         {
6769             PA_HP_TRACE((pInfo->stream->hLog, "Setting WaveRT event for priming (2)"));
6770             SetEvent(pInfo->stream->render.events[0]);
6771         }
6772     }
6773     return paNoError;
6774 }
6775
6776 static PaError PaPinRenderSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6777 {
6778     PaWinWdmPin* pin = pInfo->stream->render.pPin;
6779     pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet = 0;
6780     /* Call barrier (if needed) */
6781     pin->fnMemBarrier();
6782     PA_HP_TRACE((pInfo->stream->hLog, "Render submit (WaveRTPolled) : submit=%u", pInfo->renderTail));
6783     ++pInfo->pending;
6784     if (pInfo->priming)
6785     {
6786         --pInfo->priming;
6787         if (pInfo->priming)
6788         {
6789             PA_HP_TRACE((pInfo->stream->hLog, "Setting WaveRT event for priming (2)"));
6790             SetEvent(pInfo->stream->render.events[0]);
6791         }
6792     }
6793     return paNoError;
6794 }