To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

The primary repository for this project is hosted at https://github.com/sonic-visualiser/sv-dependency-builds .
This repository is a read-only copy which is updated automatically every hour.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / src / portaudio_20161030_catalina_patch / src / hostapi / wdmks / pa_win_wdmks.c @ 162:d43aab368df9

History | View | Annotate | Download (233 KB)

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 <string.h> /* strlen() */
71
#include <assert.h>
72
#include <wchar.h>  /* iswspace() */
73

    
74
#include "pa_util.h"
75
#include "pa_allocation.h"
76
#include "pa_hostapi.h"
77
#include "pa_stream.h"
78
#include "pa_cpuload.h"
79
#include "pa_process.h"
80
#include "portaudio.h"
81
#include "pa_debugprint.h"
82
#include "pa_memorybarrier.h"
83
#include "pa_ringbuffer.h"
84
#include "pa_trace.h"
85
#include "pa_win_waveformat.h"
86

    
87
#include "pa_win_wdmks.h"
88

    
89
#ifndef DRV_QUERYDEVICEINTERFACE
90
#define DRV_QUERYDEVICEINTERFACE     (DRV_RESERVED + 12)
91
#endif
92
#ifndef DRV_QUERYDEVICEINTERFACESIZE
93
#define DRV_QUERYDEVICEINTERFACESIZE (DRV_RESERVED + 13)
94
#endif
95

    
96
#include <windows.h>
97
#ifndef __GNUC__ /* Fix for ticket #257: MinGW-w64: Inclusion of <winioctl.h> triggers multiple redefinition errors. */
98
#include <winioctl.h>
99
#endif
100
#include <process.h>
101

    
102
#include <math.h>
103

    
104
#ifdef _MSC_VER
105
#define snprintf _snprintf
106
#define vsnprintf _vsnprintf
107
#endif
108

    
109
/* The PA_HP_TRACE macro is used in RT parts, so it can be switched off without affecting
110
the rest of the debug tracing */
111
#if 1
112
#define PA_HP_TRACE(x)  PaUtil_AddHighSpeedLogMessage x ;
113
#else
114
#define PA_HP_TRACE(x)
115
#endif
116

    
117
/* A define that selects whether the resulting pin names are chosen from pin category
118
instead of the available pin names, who sometimes can be quite cheesy, like "Volume control".
119
Default is to use the pin category.
120
*/
121
#ifndef PA_WDMKS_USE_CATEGORY_FOR_PIN_NAMES
122
#define PA_WDMKS_USE_CATEGORY_FOR_PIN_NAMES  1
123
#endif
124

    
125
#ifdef __GNUC__
126
#undef PA_LOGE_
127
#define PA_LOGE_ PA_DEBUG(("%s {\n",__FUNCTION__))
128
#undef PA_LOGL_
129
#define PA_LOGL_ PA_DEBUG(("} %s\n",__FUNCTION__))
130
/* These defines are set in order to allow the WIndows DirectX
131
* headers to compile with a GCC compiler such as MinGW
132
* NOTE: The headers may generate a few warning in GCC, but
133
* they should compile */
134
#define _INC_MMSYSTEM
135
#define _INC_MMREG
136
#define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */
137
#define DEFINE_GUID_THUNK(name,guid) DEFINE_GUID(name,guid)
138
#define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK( n, STATIC_##n )
139
#if !defined( DEFINE_WAVEFORMATEX_GUID )
140
#define DEFINE_WAVEFORMATEX_GUID(x) (USHORT)(x), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
141
#endif
142
#define  WAVE_FORMAT_ADPCM      0x0002
143
#define  WAVE_FORMAT_IEEE_FLOAT 0x0003
144
#define  WAVE_FORMAT_ALAW       0x0006
145
#define  WAVE_FORMAT_MULAW      0x0007
146
#define  WAVE_FORMAT_MPEG       0x0050
147
#define  WAVE_FORMAT_DRM        0x0009
148
#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}}
149
#define DYNAMIC_GUID(data) DYNAMIC_GUID_THUNK(data)
150
#endif
151

    
152
/* use CreateThread for CYGWIN/Windows Mobile, _beginthreadex for all others */
153
#if !defined(__CYGWIN__) && !defined(_WIN32_WCE)
154
#define CREATE_THREAD_FUNCTION (HANDLE)_beginthreadex
155
#define PA_THREAD_FUNC static unsigned WINAPI
156
#else
157
#define CREATE_THREAD_FUNCTION CreateThread
158
#define PA_THREAD_FUNC static DWORD WINAPI
159
#endif
160

    
161
#ifdef _MSC_VER
162
#define NOMMIDS
163
#define DYNAMIC_GUID(data) {data}
164
#define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */
165
#undef DEFINE_GUID
166
#define DEFINE_GUID(n,data) EXTERN_C const GUID n = {data}
167
#define DEFINE_GUID_THUNK(n,data) DEFINE_GUID(n,data)
168
#define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK(n, STATIC_##n)
169
#endif
170

    
171
#include <setupapi.h>
172

    
173
#ifndef EXTERN_C
174
#define EXTERN_C extern
175
#endif
176

    
177
#if defined(__GNUC__)
178

    
179
/* For MinGW we reference mingw-include files supplied with WASAPI */
180
#define WINBOOL BOOL
181

    
182
#include "../wasapi/mingw-include/ks.h"
183
#include "../wasapi/mingw-include/ksmedia.h"
184

    
185
#else
186

    
187
#include <mmreg.h>
188
#include <ks.h>
189

    
190
/* Note that Windows SDK V6.0A or later is needed for WaveRT specific structs to be present in
191
   ksmedia.h. Also make sure that the SDK include path is before other include paths (that may contain
192
   an "old" ksmedia.h), so the proper ksmedia.h is used */
193
#include <ksmedia.h>
194

    
195
#endif
196

    
197
#include <assert.h>
198
#include <stdio.h>
199

    
200
/* These next definitions allow the use of the KSUSER DLL */
201
typedef /*KSDDKAPI*/ DWORD WINAPI KSCREATEPIN(HANDLE, PKSPIN_CONNECT, ACCESS_MASK, PHANDLE);
202
extern HMODULE      DllKsUser;
203
extern KSCREATEPIN* FunctionKsCreatePin;
204

    
205
/* These definitions allows the use of AVRT.DLL on Vista and later OSs */
206
typedef enum _PA_AVRT_PRIORITY
207
{
208
    PA_AVRT_PRIORITY_LOW = -1,
209
    PA_AVRT_PRIORITY_NORMAL,
210
    PA_AVRT_PRIORITY_HIGH,
211
    PA_AVRT_PRIORITY_CRITICAL
212
} PA_AVRT_PRIORITY, *PPA_AVRT_PRIORITY;
213

    
214
typedef struct
215
{
216
    HINSTANCE hInstance;
217

    
218
    HANDLE  (WINAPI *AvSetMmThreadCharacteristics) (LPCSTR, LPDWORD);
219
    BOOL    (WINAPI *AvRevertMmThreadCharacteristics) (HANDLE);
220
    BOOL    (WINAPI *AvSetMmThreadPriority) (HANDLE, PA_AVRT_PRIORITY);
221
} PaWinWDMKSAvRtEntryPoints;
222

    
223
static PaWinWDMKSAvRtEntryPoints paWinWDMKSAvRtEntryPoints = {0};
224

    
225
/* An unspecified channel count (-1) is not treated correctly, so we replace it with
226
* an arbitrarily large number */ 
227
#define MAXIMUM_NUMBER_OF_CHANNELS 256
228

    
229
/* Forward definition to break circular type reference between pin and filter */
230
struct __PaWinWdmFilter;
231
typedef struct __PaWinWdmFilter PaWinWdmFilter;
232

    
233
struct __PaWinWdmPin;
234
typedef struct __PaWinWdmPin PaWinWdmPin;
235

    
236
struct __PaWinWdmStream;
237
typedef struct __PaWinWdmStream PaWinWdmStream;
238

    
239
/* Function prototype for getting audio position */
240
typedef PaError (*FunctionGetPinAudioPosition)(PaWinWdmPin*, unsigned long*);
241

    
242
/* Function prototype for memory barrier */
243
typedef void (*FunctionMemoryBarrier)(void);
244

    
245
struct __PaProcessThreadInfo;
246
typedef struct __PaProcessThreadInfo PaProcessThreadInfo;
247

    
248
typedef PaError (*FunctionPinHandler)(PaProcessThreadInfo* pInfo, unsigned eventIndex);
249

    
250
typedef enum __PaStreamStartEnum
251
{
252
    StreamStart_kOk,
253
    StreamStart_kFailed,
254
    StreamStart_kCnt
255
} PaStreamStartEnum;
256

    
257
/* Multiplexed input structure.
258
*  Very often several physical inputs are multiplexed through a MUX node (represented in the topology filter) */
259
typedef struct __PaWinWdmMuxedInput
260
{
261
    wchar_t                     friendlyName[MAX_PATH];
262
    ULONG                       muxPinId;
263
    ULONG                       muxNodeId;
264
    ULONG                       endpointPinId;
265
} PaWinWdmMuxedInput;
266

    
267
/* The Pin structure
268
* A pin is an input or output node, e.g. for audio flow */
269
struct __PaWinWdmPin
270
{
271
    HANDLE                      handle;
272
    PaWinWdmMuxedInput**        inputs;
273
    unsigned                    inputCount;
274
    wchar_t                     friendlyName[MAX_PATH];
275

    
276
    PaWinWdmFilter*             parentFilter;
277
    PaWDMKSSubType              pinKsSubType;
278
    unsigned long               pinId;
279
    unsigned long               endpointPinId;  /* For output pins */
280
    KSPIN_CONNECT*              pinConnect;
281
    unsigned long               pinConnectSize;
282
    KSDATAFORMAT_WAVEFORMATEX*  ksDataFormatWfx;
283
    KSPIN_COMMUNICATION         communication;
284
    KSDATARANGE*                dataRanges;
285
    KSMULTIPLE_ITEM*            dataRangesItem;
286
    KSPIN_DATAFLOW              dataFlow;
287
    KSPIN_CINSTANCES            instances;
288
    unsigned long               frameSize;
289
    int                         maxChannels;
290
    unsigned long               formats;
291
    int                         defaultSampleRate;
292
    ULONG                       *positionRegister;  /* WaveRT */
293
    ULONG                       hwLatency;          /* WaveRT */
294
    FunctionMemoryBarrier       fnMemBarrier;       /* WaveRT */
295
    FunctionGetPinAudioPosition fnAudioPosition;    /* WaveRT */
296
    FunctionPinHandler          fnEventHandler;
297
    FunctionPinHandler          fnSubmitHandler;
298
};
299

    
300
/* The Filter structure
301
* A filter has a number of pins and a "friendly name" */
302
struct __PaWinWdmFilter
303
{
304
    HANDLE         handle;
305
    PaWinWDMKSDeviceInfo    devInfo;  /* This will hold information that is exposed in PaDeviceInfo */
306

    
307
    DWORD            deviceNode;
308
    int            pinCount;
309
    PaWinWdmPin**  pins;
310
    PaWinWdmFilter*  topologyFilter;
311
    wchar_t          friendlyName[MAX_PATH];
312
    int              validPinCount;
313
    int            usageCount;
314
    KSMULTIPLE_ITEM* connections;
315
    KSMULTIPLE_ITEM* nodes;
316
    int              filterRefCount;
317
};
318

    
319

    
320
typedef struct __PaWinWdmDeviceInfo
321
{
322
    PaDeviceInfo    inheritedDeviceInfo;
323
    char            compositeName[MAX_PATH];   /* Composite name consists of pin name + device name in utf8 */
324
    PaWinWdmFilter* filter;
325
    unsigned long   pin;
326
    int             muxPosition;    /* Used only for input devices */
327
    int             endpointPinId;
328
}
329
PaWinWdmDeviceInfo;
330

    
331
/* PaWinWdmHostApiRepresentation - host api datastructure specific to this implementation */
332
typedef struct __PaWinWdmHostApiRepresentation
333
{
334
    PaUtilHostApiRepresentation  inheritedHostApiRep;
335
    PaUtilStreamInterface        callbackStreamInterface;
336
    PaUtilStreamInterface        blockingStreamInterface;
337

    
338
    PaUtilAllocationGroup*       allocations;
339
    int                          deviceCount;
340
}
341
PaWinWdmHostApiRepresentation;
342

    
343
typedef struct __DATAPACKET
344
{
345
    KSSTREAM_HEADER  Header;
346
    OVERLAPPED       Signal;
347
} DATAPACKET;
348

    
349
typedef struct __PaIOPacket
350
{
351
    DATAPACKET*     packet;
352
    unsigned        startByte;
353
    unsigned        lengthBytes;
354
} PaIOPacket;
355

    
356
typedef struct __PaWinWdmIOInfo
357
{
358
    PaWinWdmPin*        pPin;
359
    char*               hostBuffer;
360
    unsigned            hostBufferSize;
361
    unsigned            framesPerBuffer;
362
    unsigned            bytesPerFrame;
363
    unsigned            bytesPerSample;
364
    unsigned            noOfPackets;    /* Only used in WaveCyclic */
365
    HANDLE              *events;        /* noOfPackets handles (WaveCyclic) 1 (WaveRT) */
366
    DATAPACKET          *packets;       /* noOfPackets packets (WaveCyclic) 2 (WaveRT) */
367
    /* WaveRT polled mode */
368
    unsigned            lastPosition; 
369
    unsigned            pollCntr;
370
} PaWinWdmIOInfo;
371

    
372
/* PaWinWdmStream - a stream data structure specifically for this implementation */
373
struct __PaWinWdmStream
374
{
375
    PaUtilStreamRepresentation  streamRepresentation;
376
    PaWDMKSSpecificStreamInfo   hostApiStreamInfo;    /* This holds info that is exposed through PaStreamInfo */
377
    PaUtilCpuLoadMeasurer       cpuLoadMeasurer;
378
    PaUtilBufferProcessor       bufferProcessor;
379

    
380
#if PA_TRACE_REALTIME_EVENTS
381
    LogHandle                   hLog;
382
#endif
383

    
384
    PaUtilAllocationGroup*      allocGroup;
385
    PaWinWdmIOInfo              capture;
386
    PaWinWdmIOInfo              render;
387
    int                         streamStarted;
388
    int                         streamActive;
389
    int                         streamStop;
390
    int                         streamAbort;
391
    int                         oldProcessPriority;
392
    HANDLE                      streamThread;
393
    HANDLE                      eventAbort;
394
    HANDLE                      eventStreamStart[StreamStart_kCnt];        /* 0 = OK, 1 = Failed */
395
    PaError                     threadResult;
396
    PaStreamFlags               streamFlags;
397

    
398
    /* Capture ring buffer */
399
    PaUtilRingBuffer            ringBuffer;
400
    char*                       ringBufferData;
401

    
402
    /* These values handle the case where the user wants to use fewer
403
    * channels than the device has */
404
    int                         userInputChannels;
405
    int                         deviceInputChannels;
406
    int                         userOutputChannels;
407
    int                         deviceOutputChannels;
408
};
409

    
410
/* Gather all processing variables in a struct */
411
struct __PaProcessThreadInfo 
412
{
413
    PaWinWdmStream              *stream;
414
    PaStreamCallbackTimeInfo    ti;
415
    PaStreamCallbackFlags       underover;
416
    int                         cbResult;
417
    volatile int                pending;
418
    volatile int                priming;
419
    volatile int                pinsStarted;
420
    unsigned long               timeout;
421
    unsigned                    captureHead;
422
    unsigned                    captureTail;
423
    unsigned                    renderHead;
424
    unsigned                    renderTail;
425
    PaIOPacket                  capturePackets[4];
426
    PaIOPacket                  renderPackets[4];
427
};
428

    
429
/* Used for transferring device infos during scanning / rescanning */
430
typedef struct __PaWinWDMScanDeviceInfosResults
431
{ 
432
    PaDeviceInfo **deviceInfos;
433
    PaDeviceIndex defaultInputDevice;
434
    PaDeviceIndex defaultOutputDevice;
435
} PaWinWDMScanDeviceInfosResults;
436

    
437
static const unsigned cPacketsArrayMask = 3;
438

    
439
HMODULE      DllKsUser = NULL;
440
KSCREATEPIN* FunctionKsCreatePin = NULL;
441

    
442
/* prototypes for functions declared in this file */
443

    
444
#ifdef __cplusplus
445
extern "C"
446
{
447
#endif /* __cplusplus */
448

    
449
    PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
450

    
451
#ifdef __cplusplus
452
}
453
#endif /* __cplusplus */
454

    
455
/* Low level I/O functions */
456
static PaError WdmSyncIoctl(HANDLE handle,
457
                            unsigned long ioctlNumber,
458
                            void* inBuffer,
459
                            unsigned long inBufferCount,
460
                            void* outBuffer,
461
                            unsigned long outBufferCount,
462
                            unsigned long* bytesReturned);
463

    
464
static PaError WdmGetPropertySimple(HANDLE handle,
465
                                    const GUID* const guidPropertySet,
466
                                    unsigned long property,
467
                                    void* value,
468
                                    unsigned long valueCount);
469

    
470
static PaError WdmSetPropertySimple(HANDLE handle,
471
                                    const GUID* const guidPropertySet,
472
                                    unsigned long property,
473
                                    void* value,
474
                                    unsigned long valueCount,
475
                                    void* instance,
476
                                    unsigned long instanceCount);
477

    
478
static PaError WdmGetPinPropertySimple(HANDLE  handle,
479
                                       unsigned long pinId,
480
                                       const GUID* const guidPropertySet,
481
                                       unsigned long property,
482
                                       void* value,
483
                                       unsigned long valueCount,
484
                                       unsigned long* byteCount);
485

    
486
static PaError WdmGetPinPropertyMulti(HANDLE  handle,
487
                                      unsigned long pinId,
488
                                      const GUID* const guidPropertySet,
489
                                      unsigned long property,
490
                                      KSMULTIPLE_ITEM** ksMultipleItem);
491

    
492
static PaError WdmGetPropertyMulti(HANDLE handle,
493
                                   const GUID* const guidPropertySet,
494
                                   unsigned long property,
495
                                   KSMULTIPLE_ITEM** ksMultipleItem);
496

    
497
static PaError WdmSetMuxNodeProperty(HANDLE handle,
498
                                     ULONG nodeId,
499
                                     ULONG pinId);
500

    
501

    
502
/** Pin management functions */
503
static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, PaError* error);
504
static void PinFree(PaWinWdmPin* pin);
505
static void PinClose(PaWinWdmPin* pin);
506
static PaError PinInstantiate(PaWinWdmPin* pin);
507
/*static PaError PinGetState(PaWinWdmPin* pin, KSSTATE* state); NOT USED */
508
static PaError PinSetState(PaWinWdmPin* pin, KSSTATE state);
509
static PaError PinSetFormat(PaWinWdmPin* pin, const WAVEFORMATEX* format);
510
static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format);
511
/* WaveRT support */
512
static PaError PinQueryNotificationSupport(PaWinWdmPin* pPin, BOOL* pbResult);
513
static PaError PinGetBuffer(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier);
514
static PaError PinRegisterPositionRegister(PaWinWdmPin* pPin);
515
static PaError PinRegisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle);
516
static PaError PinUnregisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle);
517
static PaError PinGetHwLatency(PaWinWdmPin* pPin, ULONG* pFifoSize, ULONG* pChipsetDelay, ULONG* pCodecDelay);
518
static PaError PinGetAudioPositionMemoryMapped(PaWinWdmPin* pPin, ULONG* pPosition);
519
static PaError PinGetAudioPositionViaIOCTLRead(PaWinWdmPin* pPin, ULONG* pPosition);
520
static PaError PinGetAudioPositionViaIOCTLWrite(PaWinWdmPin* pPin, ULONG* pPosition);
521

    
522
/* Filter management functions */
523
static PaWinWdmFilter* FilterNew(PaWDMKSType type, DWORD devNode, const wchar_t* filterName, const wchar_t* friendlyName, PaError* error);
524
static PaError FilterInitializePins(PaWinWdmFilter* filter);
525
static void FilterFree(PaWinWdmFilter* filter);
526
static void FilterAddRef(PaWinWdmFilter* filter);
527
static PaWinWdmPin* FilterCreatePin(
528
                                    PaWinWdmFilter* filter,
529
                                    int pinId,
530
                                    const WAVEFORMATEX* wfex,
531
                                    PaError* error);
532
static PaError FilterUse(PaWinWdmFilter* filter);
533
static void FilterRelease(PaWinWdmFilter* filter);
534

    
535
/* Hot plug functions */
536
static BOOL IsDeviceTheSame(const PaWinWdmDeviceInfo* pDev1,
537
                            const PaWinWdmDeviceInfo* pDev2);
538

    
539
/* Interface functions */
540
static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
541
static PaError IsFormatSupported(
542
struct PaUtilHostApiRepresentation *hostApi,
543
    const PaStreamParameters *inputParameters,
544
    const PaStreamParameters *outputParameters,
545
    double sampleRate );
546

    
547
static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void **newDeviceInfos, int *newDeviceCount );
548
static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *deviceInfos, int deviceCount );
549
static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *deviceInfos, int deviceCount );
550

    
551
static PaError OpenStream(
552
struct PaUtilHostApiRepresentation *hostApi,
553
    PaStream** s,
554
    const PaStreamParameters *inputParameters,
555
    const PaStreamParameters *outputParameters,
556
    double sampleRate,
557
    unsigned long framesPerBuffer,
558
    PaStreamFlags streamFlags,
559
    PaStreamCallback *streamCallback,
560
    void *userData );
561
static PaError CloseStream( PaStream* stream );
562
static PaError StartStream( PaStream *stream );
563
static PaError StopStream( PaStream *stream );
564
static PaError AbortStream( PaStream *stream );
565
static PaError IsStreamStopped( PaStream *s );
566
static PaError IsStreamActive( PaStream *stream );
567
static PaTime GetStreamTime( PaStream *stream );
568
static double GetStreamCpuLoad( PaStream* stream );
569
static PaError ReadStream(
570
                          PaStream* stream,
571
                          void *buffer,
572
                          unsigned long frames );
573
static PaError WriteStream(
574
                           PaStream* stream,
575
                           const void *buffer,
576
                           unsigned long frames );
577
static signed long GetStreamReadAvailable( PaStream* stream );
578
static signed long GetStreamWriteAvailable( PaStream* stream );
579

    
580
/* Utility functions */
581
static unsigned long GetWfexSize(const WAVEFORMATEX* wfex);
582
static PaWinWdmFilter** BuildFilterList(int* filterCount, int* noOfPaDevices, PaError* result);
583
static BOOL PinWrite(HANDLE h, DATAPACKET* p);
584
static BOOL PinRead(HANDLE h, DATAPACKET* p);
585
static void DuplicateFirstChannelInt16(void* buffer, int channels, int samples);
586
static void DuplicateFirstChannelInt24(void* buffer, int channels, int samples);
587
PA_THREAD_FUNC ProcessingThread(void*);
588

    
589
/* Pin handler functions */
590
static PaError PaPinCaptureEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex);
591
static PaError PaPinCaptureSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex);
592

    
593
static PaError PaPinRenderEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex);
594
static PaError PaPinRenderSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex);
595

    
596
static PaError PaPinCaptureEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex);
597
static PaError PaPinCaptureEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex);
598
static PaError PaPinCaptureSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex);
599
static PaError PaPinCaptureSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex);
600

    
601
static PaError PaPinRenderEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex);
602
static PaError PaPinRenderEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex);
603
static PaError PaPinRenderSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex);
604
static PaError PaPinRenderSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex);
605

    
606
/* Function bodies */
607

    
608
#if defined(_DEBUG) && defined(PA_ENABLE_DEBUG_OUTPUT)
609
#define PA_WDMKS_SET_TREF
610
static PaTime tRef = 0;
611

    
612
static void PaWinWdmDebugPrintf(const char* fmt, ...)
613
{
614
    va_list list;
615
    char buffer[1024];
616
    PaTime t = PaUtil_GetTime() - tRef;
617
    va_start(list, fmt);
618
    _vsnprintf(buffer, 1023, fmt, list);
619
    va_end(list);
620
    PaUtil_DebugPrint("%6.3lf: %s", t, buffer);
621
}
622

    
623
#ifdef PA_DEBUG
624
#undef PA_DEBUG
625
#define PA_DEBUG(x)    PaWinWdmDebugPrintf x ;
626
#endif
627
#endif
628

    
629
static BOOL IsDeviceTheSame(const PaWinWdmDeviceInfo* pDev1,
630
                            const PaWinWdmDeviceInfo* pDev2)
631
{
632
    if (pDev1 == NULL || pDev2 == NULL)
633
        return FALSE;
634

    
635
    if (pDev1 == pDev2)
636
        return TRUE;
637

    
638
    if (strcmp(pDev1->compositeName, pDev2->compositeName) == 0)
639
        return TRUE;
640

    
641
    return FALSE;
642
}
643

    
644
static BOOL IsEarlierThanVista()
645
{
646
/*
647
NOTE: GetVersionEx() is deprecated as of Windows 8.1 and can not be used to reliably detect
648
versions of Windows higher than Windows 8 (due to manifest requirements for reporting higher versions).
649
Microsoft recommends switching to VerifyVersionInfo (available on Win 2k and later), however GetVersionEx
650
is is faster, for now we just disable the deprecation warning.
651
See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx
652
See: http://www.codeproject.com/Articles/678606/Part-Overcoming-Windows-s-deprecation-of-GetVe
653
*/
654
#pragma warning (disable : 4996) /* use of GetVersionEx */
655

    
656
    OSVERSIONINFO osvi;
657
    osvi.dwOSVersionInfoSize = sizeof(osvi);
658
    if (GetVersionEx(&osvi) && osvi.dwMajorVersion<6)
659
    {
660
        return TRUE;
661
    }
662
    return FALSE;
663

    
664
#pragma warning (default : 4996)
665
}
666

    
667

    
668

    
669
static void MemoryBarrierDummy(void)
670
{
671
    /* Do nothing */
672
}
673

    
674
static void MemoryBarrierRead(void)
675
{
676
    PaUtil_ReadMemoryBarrier();
677
}
678

    
679
static void MemoryBarrierWrite(void)
680
{
681
    PaUtil_WriteMemoryBarrier();
682
}
683

    
684
static unsigned long GetWfexSize(const WAVEFORMATEX* wfex)
685
{
686
    if( wfex->wFormatTag == WAVE_FORMAT_PCM )
687
    {
688
        return sizeof( WAVEFORMATEX );
689
    }
690
    else
691
    {
692
        return (sizeof( WAVEFORMATEX ) + wfex->cbSize);
693
    }
694
}
695

    
696
static void PaWinWDM_SetLastErrorInfo(long errCode, const char* fmt, ...)
697
{
698
    va_list list;
699
    char buffer[1024];
700
    va_start(list, fmt);
701
    _vsnprintf(buffer, 1023, fmt, list);
702
    va_end(list);
703
    PaUtil_SetLastHostErrorInfo(paWDMKS, errCode, buffer);
704
}
705

    
706
/*
707
Low level pin/filter access functions
708
*/
709
static PaError WdmSyncIoctl(
710
                            HANDLE handle,
711
                            unsigned long ioctlNumber,
712
                            void* inBuffer,
713
                            unsigned long inBufferCount,
714
                            void* outBuffer,
715
                            unsigned long outBufferCount,
716
                            unsigned long* bytesReturned)
717
{
718
    PaError result = paNoError;
719
    unsigned long dummyBytesReturned = 0;
720
    BOOL bRes;
721

    
722
    if( !bytesReturned )
723
    {
724
        /* Use a dummy as the caller hasn't supplied one */
725
        bytesReturned = &dummyBytesReturned;
726
    }
727

    
728
    bRes = DeviceIoControl(handle, ioctlNumber, inBuffer, inBufferCount, outBuffer, outBufferCount, bytesReturned, NULL);
729
    if (!bRes)
730
    {
731
        unsigned long error = GetLastError();
732
        if ( !(((error == ERROR_INSUFFICIENT_BUFFER ) || ( error == ERROR_MORE_DATA )) && 
733
            ( ioctlNumber == IOCTL_KS_PROPERTY ) &&
734
            ( outBufferCount == 0 ) ) ) 
735
        {
736
            KSPROPERTY* ksProperty = (KSPROPERTY*)inBuffer;
737

    
738
            PaWinWDM_SetLastErrorInfo(result, "WdmSyncIoctl: DeviceIoControl GLE = 0x%08X (prop_set = {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}, prop_id = %u)",
739
                error,
740
                ksProperty->Set.Data1, ksProperty->Set.Data2, ksProperty->Set.Data3,
741
                ksProperty->Set.Data4[0], ksProperty->Set.Data4[1],
742
                ksProperty->Set.Data4[2], ksProperty->Set.Data4[3],
743
                ksProperty->Set.Data4[4], ksProperty->Set.Data4[5],
744
                ksProperty->Set.Data4[6], ksProperty->Set.Data4[7],
745
                ksProperty->Id
746
                );
747
            result = paUnanticipatedHostError;
748
        }
749
    }
750
    return result;
751
}
752

    
753
static PaError WdmGetPropertySimple(HANDLE handle,
754
                                    const GUID* const guidPropertySet,
755
                                    unsigned long property,
756
                                    void* value,
757
                                    unsigned long valueCount)
758
{
759
    PaError result;
760
    KSPROPERTY ksProperty;
761

    
762
    ksProperty.Set = *guidPropertySet;
763
    ksProperty.Id = property;
764
    ksProperty.Flags = KSPROPERTY_TYPE_GET;
765

    
766
    result = WdmSyncIoctl(
767
        handle,
768
        IOCTL_KS_PROPERTY,
769
        &ksProperty,
770
        sizeof(KSPROPERTY),
771
        value,
772
        valueCount,
773
        NULL);
774

    
775
    return result;
776
}
777

    
778
static PaError WdmSetPropertySimple(
779
                                    HANDLE handle,
780
                                    const GUID* const guidPropertySet,
781
                                    unsigned long property,
782
                                    void* value,
783
                                    unsigned long valueCount,
784
                                    void* instance,
785
                                    unsigned long instanceCount)
786
{
787
    PaError result;
788
    KSPROPERTY* ksProperty;
789
    unsigned long propertyCount  = 0;
790

    
791
    propertyCount = sizeof(KSPROPERTY) + instanceCount;
792
    ksProperty = (KSPROPERTY*)_alloca( propertyCount );
793
    if( !ksProperty )
794
    {
795
        return paInsufficientMemory;
796
    }
797

    
798
    ksProperty->Set = *guidPropertySet;
799
    ksProperty->Id = property;
800
    ksProperty->Flags = KSPROPERTY_TYPE_SET;
801

    
802
    if( instance )
803
    {
804
        memcpy((void*)((char*)ksProperty + sizeof(KSPROPERTY)), instance, instanceCount);
805
    }
806

    
807
    result = WdmSyncIoctl(
808
        handle,
809
        IOCTL_KS_PROPERTY,
810
        ksProperty,
811
        propertyCount,
812
        value,
813
        valueCount,
814
        NULL);
815

    
816
    return result;
817
}
818

    
819
static PaError WdmGetPinPropertySimple(
820
                                       HANDLE  handle,
821
                                       unsigned long pinId,
822
                                       const GUID* const guidPropertySet,
823
                                       unsigned long property,
824
                                       void* value,
825
                                       unsigned long valueCount,
826
                                       unsigned long *byteCount)
827
{
828
    PaError result;
829

    
830
    KSP_PIN ksPProp;
831
    ksPProp.Property.Set = *guidPropertySet;
832
    ksPProp.Property.Id = property;
833
    ksPProp.Property.Flags = KSPROPERTY_TYPE_GET;
834
    ksPProp.PinId = pinId;
835
    ksPProp.Reserved = 0;
836

    
837
    result = WdmSyncIoctl(
838
        handle,
839
        IOCTL_KS_PROPERTY,
840
        &ksPProp,
841
        sizeof(KSP_PIN),
842
        value,
843
        valueCount,
844
        byteCount);
845

    
846
    return result;
847
}
848

    
849
static PaError WdmGetPinPropertyMulti(
850
                                      HANDLE handle,
851
                                      unsigned long pinId,
852
                                      const GUID* const guidPropertySet,
853
                                      unsigned long property,
854
                                      KSMULTIPLE_ITEM** ksMultipleItem)
855
{
856
    PaError result;
857
    unsigned long multipleItemSize = 0;
858
    KSP_PIN ksPProp;
859

    
860
    ksPProp.Property.Set = *guidPropertySet;
861
    ksPProp.Property.Id = property;
862
    ksPProp.Property.Flags = KSPROPERTY_TYPE_GET;
863
    ksPProp.PinId = pinId;
864
    ksPProp.Reserved = 0;
865

    
866
    result = WdmSyncIoctl(
867
        handle,
868
        IOCTL_KS_PROPERTY,
869
        &ksPProp.Property,
870
        sizeof(KSP_PIN),
871
        NULL,
872
        0,
873
        &multipleItemSize);
874
    if( result != paNoError )
875
    {
876
        return result;
877
    }
878

    
879
    *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize );
880
    if( !*ksMultipleItem )
881
    {
882
        return paInsufficientMemory;
883
    }
884

    
885
    result = WdmSyncIoctl(
886
        handle,
887
        IOCTL_KS_PROPERTY,
888
        &ksPProp,
889
        sizeof(KSP_PIN),
890
        (void*)*ksMultipleItem,
891
        multipleItemSize,
892
        NULL);
893

    
894
    if( result != paNoError )
895
    {
896
        PaUtil_FreeMemory( ksMultipleItem );
897
    }
898

    
899
    return result;
900
}
901

    
902
static PaError WdmGetPropertyMulti(HANDLE handle,
903
                                   const GUID* const guidPropertySet,
904
                                   unsigned long property,
905
                                   KSMULTIPLE_ITEM** ksMultipleItem)
906
{
907
    PaError result;
908
    unsigned long multipleItemSize = 0;
909
    KSPROPERTY ksProp;
910

    
911
    ksProp.Set = *guidPropertySet;
912
    ksProp.Id = property;
913
    ksProp.Flags = KSPROPERTY_TYPE_GET;
914

    
915
    result = WdmSyncIoctl(
916
        handle,
917
        IOCTL_KS_PROPERTY,
918
        &ksProp,
919
        sizeof(KSPROPERTY),
920
        NULL,
921
        0,
922
        &multipleItemSize);
923
    if( result != paNoError )
924
    {
925
        return result;
926
    }
927

    
928
    *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize );
929
    if( !*ksMultipleItem )
930
    {
931
        return paInsufficientMemory;
932
    }
933

    
934
    result = WdmSyncIoctl(
935
        handle,
936
        IOCTL_KS_PROPERTY,
937
        &ksProp,
938
        sizeof(KSPROPERTY),
939
        (void*)*ksMultipleItem,
940
        multipleItemSize,
941
        NULL);
942

    
943
    if( result != paNoError )
944
    {
945
        PaUtil_FreeMemory( ksMultipleItem );
946
    }
947

    
948
    return result;
949
}
950

    
951
static PaError WdmSetMuxNodeProperty(HANDLE handle,
952
                                     ULONG nodeId,
953
                                     ULONG pinId)
954
{
955
    PaError result = paNoError;
956
    KSNODEPROPERTY prop;
957
    prop.Property.Set = KSPROPSETID_Audio;
958
    prop.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE;
959
    prop.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY;
960
    prop.NodeId = nodeId;
961
    prop.Reserved = 0;
962

    
963
    result = WdmSyncIoctl(handle, IOCTL_KS_PROPERTY, &prop, sizeof(KSNODEPROPERTY), &pinId, sizeof(ULONG), NULL);
964

    
965
    return result;
966
}
967

    
968
/* Used when traversing topology for outputs */
969
static const KSTOPOLOGY_CONNECTION* GetConnectionTo(const KSTOPOLOGY_CONNECTION* pFrom, PaWinWdmFilter* filter, int muxIdx)
970
{
971
    unsigned i;
972
    const KSTOPOLOGY_CONNECTION* retval = NULL;
973
    const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
974
    (void)muxIdx;
975
    PA_DEBUG(("GetConnectionTo: Checking %u connections... (pFrom = %p)", filter->connections->Count, pFrom));
976
    for (i = 0; i < filter->connections->Count; ++i)
977
    {
978
        const KSTOPOLOGY_CONNECTION* pConn = connections + i;
979
        if (pConn == pFrom)
980
            continue;
981

    
982
        if (pConn->FromNode == pFrom->ToNode)
983
        {
984
            retval = pConn;
985
            break;
986
        }
987
    }
988
    PA_DEBUG(("GetConnectionTo: Returning %p\n", retval));
989
    return retval;
990
}
991

    
992
/* Used when traversing topology for inputs */
993
static const KSTOPOLOGY_CONNECTION* GetConnectionFrom(const KSTOPOLOGY_CONNECTION* pTo, PaWinWdmFilter* filter, int muxIdx)
994
{
995
    unsigned i;
996
    const KSTOPOLOGY_CONNECTION* retval = NULL;
997
    const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
998
    int muxCntr = 0;
999
    PA_DEBUG(("GetConnectionFrom: Checking %u connections... (pTo = %p)\n", filter->connections->Count, pTo));
1000
    for (i = 0; i < filter->connections->Count; ++i)
1001
    {
1002
        const KSTOPOLOGY_CONNECTION* pConn = connections + i;
1003
        if (pConn == pTo)
1004
            continue;
1005

    
1006
        if (pConn->ToNode == pTo->FromNode)
1007
        {
1008
            if (muxIdx >= 0)
1009
            {
1010
                if (muxCntr < muxIdx)
1011
                {
1012
                    ++muxCntr;
1013
                    continue;
1014
                }
1015
            }
1016
            retval = pConn;
1017
            break;
1018
        }
1019
    }
1020
    PA_DEBUG(("GetConnectionFrom: Returning %p\n", retval));
1021
    return retval;
1022
}
1023

    
1024
static ULONG GetNumberOfConnectionsTo(const KSTOPOLOGY_CONNECTION* pTo, PaWinWdmFilter* filter)
1025
{
1026
    ULONG retval = 0;
1027
    unsigned i;
1028
    const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
1029
    PA_DEBUG(("GetNumberOfConnectionsTo: Checking %u connections...\n", filter->connections->Count));
1030
    for (i = 0; i < filter->connections->Count; ++i)
1031
    {
1032
        const KSTOPOLOGY_CONNECTION* pConn = connections + i;
1033
        if (pConn->ToNode == pTo->FromNode &&
1034
            (pTo->FromNode != KSFILTER_NODE || pConn->ToNodePin == pTo->FromNodePin))
1035
        {
1036
            ++retval;
1037
        }
1038
    }
1039
    PA_DEBUG(("GetNumberOfConnectionsTo: Returning %d\n", retval));
1040
    return retval;
1041
}
1042

    
1043
typedef const KSTOPOLOGY_CONNECTION *(*TFnGetConnection)(const KSTOPOLOGY_CONNECTION*, PaWinWdmFilter*, int);
1044

    
1045
static const KSTOPOLOGY_CONNECTION* FindStartConnectionFrom(ULONG startPin, PaWinWdmFilter* filter)
1046
{
1047
    unsigned i;
1048
    const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
1049
    PA_DEBUG(("FindStartConnectionFrom: Startpin %u, Checking %u connections...\n", startPin, filter->connections->Count));
1050
    for (i = 0; i < filter->connections->Count; ++i)
1051
    {
1052
        const KSTOPOLOGY_CONNECTION* pConn = connections + i;
1053
        if (pConn->ToNode == KSFILTER_NODE && pConn->ToNodePin == startPin)
1054
        {
1055
            PA_DEBUG(("FindStartConnectionFrom: returning %p\n", pConn));
1056
            return pConn;
1057
        }
1058
    }
1059

    
1060
    PA_DEBUG(("FindStartConnectionFrom: returning NULL\n"));
1061
    assert(FALSE);
1062
    return 0;
1063
}
1064

    
1065
static const KSTOPOLOGY_CONNECTION* FindStartConnectionTo(ULONG startPin, PaWinWdmFilter* filter)
1066
{
1067
    unsigned i;
1068
    const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
1069
    PA_DEBUG(("FindStartConnectionTo: Startpin %u, Checking %u connections...\n", startPin, filter->connections->Count));
1070
    for (i = 0; i < filter->connections->Count; ++i)
1071
    {
1072
        const KSTOPOLOGY_CONNECTION* pConn = connections + i;
1073
        if (pConn->FromNode == KSFILTER_NODE && pConn->FromNodePin == startPin)
1074
        {
1075
            PA_DEBUG(("FindStartConnectionTo: returning %p\n", pConn));
1076
            return pConn;
1077
        }
1078
    }
1079

    
1080
    PA_DEBUG(("FindStartConnectionTo: returning NULL\n"));
1081
    assert(FALSE);
1082
    return 0;
1083
}
1084

    
1085
static ULONG GetConnectedPin(ULONG startPin, BOOL forward, PaWinWdmFilter* filter, int muxPosition, ULONG *muxInputPinId, ULONG *muxNodeId)
1086
{
1087
    int limit=1000;
1088
    const KSTOPOLOGY_CONNECTION *conn = NULL; 
1089
    TFnGetConnection fnGetConnection = forward ? GetConnectionTo : GetConnectionFrom ;
1090
    PA_LOGE_;
1091
    while (1)
1092
    {
1093
        limit--;
1094
        if (limit == 0) {
1095
           PA_DEBUG(("GetConnectedPin: LOOP LIMIT REACHED\n"));
1096
           break;
1097
        }
1098

    
1099
        if (conn == NULL)
1100
        {
1101
            conn = forward ? FindStartConnectionTo(startPin, filter) : FindStartConnectionFrom(startPin, filter);
1102
        }
1103
        else
1104
        {
1105
            conn = fnGetConnection(conn, filter, -1);
1106
        }
1107

    
1108
        /* Handling case of erroneous connection list */
1109
        if (conn == NULL)
1110
        {
1111
            break;
1112
        }
1113

    
1114
        if (forward ? conn->ToNode == KSFILTER_NODE : conn->FromNode == KSFILTER_NODE)
1115
        {
1116
            return forward ? conn->ToNodePin : conn->FromNodePin;
1117
        }
1118
        else
1119
        {
1120
            PA_DEBUG(("GetConnectedPin: count=%d, forward=%d, muxPosition=%d\n", filter->nodes->Count, forward, muxPosition));
1121
            if (filter->nodes->Count > 0 && !forward && muxPosition >= 0)
1122
            {
1123
                const GUID* nodes = (const GUID*)(filter->nodes + 1);
1124
                if (IsEqualGUID(&nodes[conn->FromNode], &KSNODETYPE_MUX))
1125
                {
1126
                    ULONG nConn = GetNumberOfConnectionsTo(conn, filter);
1127
                    conn = fnGetConnection(conn, filter, muxPosition);
1128
                    if (conn == NULL)
1129
                    {
1130
                        break;
1131
                    }
1132
                    if (muxInputPinId != 0)
1133
                    {
1134
                        *muxInputPinId = conn->ToNodePin;
1135
                    }
1136
                    if (muxNodeId != 0)
1137
                    {
1138
                        *muxNodeId = conn->ToNode;
1139
                    }
1140
                }
1141
            }
1142
        }
1143
    }
1144
    PA_LOGL_;
1145
    return KSFILTER_NODE;
1146
}
1147

    
1148
static void DumpConnectionsAndNodes(PaWinWdmFilter* filter)
1149
{
1150
    unsigned i;
1151
    const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1);
1152
    const GUID* nodes = (const GUID*)(filter->nodes + 1);
1153

    
1154
    PA_LOGE_;
1155
    PA_DEBUG(("DumpConnectionsAndNodes: connections=%d, nodes=%d\n", filter->connections->Count, filter->nodes->Count));
1156

    
1157
    for (i=0; i < filter->connections->Count; ++i)
1158
    {
1159
        const KSTOPOLOGY_CONNECTION* pConn = connections + i;
1160
        PA_DEBUG(("  Connection: %u - FromNode=%u,FromPin=%u -> ToNode=%u,ToPin=%u\n", 
1161
            i,
1162
            pConn->FromNode, pConn->FromNodePin,
1163
            pConn->ToNode, pConn->ToNodePin
1164
            ));
1165
    }
1166

    
1167
    for (i=0; i < filter->nodes->Count; ++i)
1168
    {
1169
        const GUID* pConn = nodes + i;
1170
        PA_DEBUG(("  Node: %d - {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
1171
            i,
1172
            pConn->Data1, pConn->Data2, pConn->Data3,
1173
            pConn->Data4[0], pConn->Data4[1],
1174
            pConn->Data4[2], pConn->Data4[3],
1175
            pConn->Data4[4], pConn->Data4[5],
1176
            pConn->Data4[6], pConn->Data4[7]
1177
        ));
1178
    }
1179
    PA_LOGL_;
1180

    
1181
}
1182

    
1183
typedef struct __PaUsbTerminalGUIDToName 
1184
{
1185
    USHORT     usbGUID;
1186
    wchar_t    name[64];
1187
} PaUsbTerminalGUIDToName;
1188

    
1189
static const PaUsbTerminalGUIDToName kNames[] =
1190
{
1191
    /* Types copied from: http://msdn.microsoft.com/en-us/library/ff537742(v=vs.85).aspx */
1192
    /* Input terminal types */
1193
    { 0x0201, L"Microphone" },
1194
    { 0x0202, L"Desktop Microphone" },
1195
    { 0x0203, L"Personal Microphone" },
1196
    { 0x0204, L"Omni Directional Microphone" },
1197
    { 0x0205, L"Microphone Array" },
1198
    { 0x0206, L"Processing Microphone Array" },
1199
    /* Output terminal types */
1200
    { 0x0301, L"Speakers" },
1201
    { 0x0302, L"Headphones" },
1202
    { 0x0303, L"Head Mounted Display Audio" },
1203
    { 0x0304, L"Desktop Speaker" },
1204
    { 0x0305, L"Room Speaker" },
1205
    { 0x0306, L"Communication Speaker" },
1206
    { 0x0307, L"LFE Speakers" },
1207
    /* External terminal types */
1208
    { 0x0601, L"Analog" },
1209
    { 0x0602, L"Digital" },
1210
    { 0x0603, L"Line" },
1211
    { 0x0604, L"Audio" },
1212
    { 0x0605, L"SPDIF" },
1213
};
1214

    
1215
static const unsigned kNamesCnt = sizeof(kNames)/sizeof(PaUsbTerminalGUIDToName);
1216

    
1217
static int PaUsbTerminalGUIDToNameCmp(const void* lhs, const void* rhs)
1218
{
1219
    const PaUsbTerminalGUIDToName* pL = (const PaUsbTerminalGUIDToName*)lhs;
1220
    const PaUsbTerminalGUIDToName* pR = (const PaUsbTerminalGUIDToName*)rhs;
1221
    return ((int)(pL->usbGUID) - (int)(pR->usbGUID));
1222
}
1223

    
1224
static PaError GetNameFromCategory(const GUID* pGUID, BOOL input, wchar_t* name, unsigned length)
1225
{
1226
    PaError result = paUnanticipatedHostError;
1227
    USHORT usbTerminalGUID = (USHORT)(pGUID->Data1 - 0xDFF219E0);
1228

    
1229
    PA_LOGE_;
1230
    if (input && usbTerminalGUID >= 0x301 && usbTerminalGUID < 0x400)
1231
    {
1232
        /* Output terminal name for an input !? Set it to Line! */
1233
        usbTerminalGUID = 0x603;
1234
    }
1235
    if (!input && usbTerminalGUID >= 0x201 && usbTerminalGUID < 0x300)
1236
    {
1237
        /* Input terminal name for an output !? Set it to Line! */
1238
        usbTerminalGUID = 0x603;
1239
    }
1240
    if (usbTerminalGUID >= 0x201 && usbTerminalGUID < 0x713)
1241
    {
1242
        PaUsbTerminalGUIDToName s = { usbTerminalGUID };
1243
        const PaUsbTerminalGUIDToName* ptr = bsearch(
1244
            &s,
1245
            kNames,
1246
            kNamesCnt,
1247
            sizeof(PaUsbTerminalGUIDToName),
1248
            PaUsbTerminalGUIDToNameCmp
1249
            );
1250
        if (ptr != 0)
1251
        {
1252
            PA_DEBUG(("GetNameFromCategory: USB GUID %04X -> '%S'\n", usbTerminalGUID, ptr->name));
1253

    
1254
            if (name != NULL && length > 0)
1255
            {
1256
                int n = _snwprintf(name, length, L"%s", ptr->name);
1257
                if (usbTerminalGUID >= 0x601 && usbTerminalGUID < 0x700)
1258
                {
1259
                    _snwprintf(name + n, length - n, L" %s", (input ? L"In":L"Out"));
1260
                }
1261
            }
1262
            result = paNoError;
1263
        }
1264
    }
1265
    else
1266
    {
1267
        PaWinWDM_SetLastErrorInfo(result, "GetNameFromCategory: usbTerminalGUID = %04X ", usbTerminalGUID);
1268
    }
1269
    PA_LOGL_;
1270
    return result;
1271
}
1272

    
1273
static BOOL IsFrequencyWithinRange(const KSDATARANGE_AUDIO* range, int frequency)
1274
{
1275
    if (frequency < (int)range->MinimumSampleFrequency)
1276
        return FALSE;
1277
    if (frequency > (int)range->MaximumSampleFrequency)
1278
        return FALSE;
1279
    return TRUE;
1280
}
1281

    
1282
static BOOL IsBitsWithinRange(const KSDATARANGE_AUDIO* range, int noOfBits)
1283
{
1284
    if (noOfBits < (int)range->MinimumBitsPerSample)
1285
        return FALSE;
1286
    if (noOfBits > (int)range->MaximumBitsPerSample)
1287
        return FALSE;
1288
    return TRUE;
1289
}
1290

    
1291
/* Note: Somewhat different order compared to WMME implementation, as we want to focus on fidelity first */
1292
static const int defaultSampleRateSearchOrder[] =
1293
{ 44100, 48000, 88200, 96000, 192000, 32000, 24000, 22050, 16000, 12000, 11025, 9600, 8000 };
1294
static const int defaultSampleRateSearchOrderCount = sizeof(defaultSampleRateSearchOrder)/sizeof(defaultSampleRateSearchOrder[0]);
1295

    
1296
static int DefaultSampleFrequencyIndex(const KSDATARANGE_AUDIO* range)
1297
{
1298
    int i;
1299

    
1300
    for(i=0; i < defaultSampleRateSearchOrderCount; ++i)
1301
    {
1302
        int currentFrequency = defaultSampleRateSearchOrder[i];
1303

    
1304
        if (IsFrequencyWithinRange(range, currentFrequency))
1305
        {
1306
            return i;
1307
        }
1308
    }
1309

    
1310
    return -1;
1311
}
1312

    
1313
/*
1314
Create a new pin object belonging to a filter
1315
The pin object holds all the configuration information about the pin
1316
before it is opened, and then the handle of the pin after is opened
1317
*/
1318
static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, PaError* error)
1319
{
1320
    PaWinWdmPin* pin;
1321
    PaError result;
1322
    unsigned long i;
1323
    KSMULTIPLE_ITEM* item = NULL;
1324
    KSIDENTIFIER* identifier;
1325
    KSDATARANGE* dataRange;
1326
    const ULONG streamingId = (parentFilter->devInfo.streamingType == Type_kWaveRT) ? KSINTERFACE_STANDARD_LOOPED_STREAMING : KSINTERFACE_STANDARD_STREAMING;
1327
    int defaultSampleRateIndex = defaultSampleRateSearchOrderCount;
1328

    
1329
    PA_LOGE_;
1330
    PA_DEBUG(("PinNew: Creating pin %d:\n",pinId));
1331

    
1332
    /* Allocate the new PIN object */
1333
    pin = (PaWinWdmPin*)PaUtil_AllocateMemory( sizeof(PaWinWdmPin) );
1334
    if( !pin )
1335
    {
1336
        result = paInsufficientMemory;
1337
        goto error;
1338
    }
1339

    
1340
    /* Zero the pin object */
1341
    /* memset( (void*)pin, 0, sizeof(PaWinWdmPin) ); */
1342

    
1343
    pin->parentFilter = parentFilter;
1344
    pin->pinId = pinId;
1345

    
1346
    /* Allocate a connect structure */
1347
    pin->pinConnectSize = sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX);
1348
    pin->pinConnect = (KSPIN_CONNECT*)PaUtil_AllocateMemory( pin->pinConnectSize );
1349
    if( !pin->pinConnect )
1350
    {
1351
        result = paInsufficientMemory;
1352
        goto error;
1353
    }
1354

    
1355
    /* Configure the connect structure with default values */
1356
    pin->pinConnect->Interface.Set               = KSINTERFACESETID_Standard;
1357
    pin->pinConnect->Interface.Id                = streamingId;
1358
    pin->pinConnect->Interface.Flags             = 0;
1359
    pin->pinConnect->Medium.Set                  = KSMEDIUMSETID_Standard;
1360
    pin->pinConnect->Medium.Id                   = KSMEDIUM_TYPE_ANYINSTANCE;
1361
    pin->pinConnect->Medium.Flags                = 0;
1362
    pin->pinConnect->PinId                       = pinId;
1363
    pin->pinConnect->PinToHandle                 = NULL;
1364
    pin->pinConnect->Priority.PriorityClass      = KSPRIORITY_NORMAL;
1365
    pin->pinConnect->Priority.PrioritySubClass   = 1;
1366
    pin->ksDataFormatWfx = (KSDATAFORMAT_WAVEFORMATEX*)(pin->pinConnect + 1);
1367
    pin->ksDataFormatWfx->DataFormat.FormatSize  = sizeof(KSDATAFORMAT_WAVEFORMATEX);
1368
    pin->ksDataFormatWfx->DataFormat.Flags       = 0;
1369
    pin->ksDataFormatWfx->DataFormat.Reserved    = 0;
1370
    pin->ksDataFormatWfx->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
1371
    pin->ksDataFormatWfx->DataFormat.SubFormat   = KSDATAFORMAT_SUBTYPE_PCM;
1372
    pin->ksDataFormatWfx->DataFormat.Specifier   = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
1373

    
1374
    pin->frameSize = 0; /* Unknown until we instantiate pin */
1375

    
1376
    /* Get the COMMUNICATION property */
1377
    result = WdmGetPinPropertySimple(
1378
        parentFilter->handle,
1379
        pinId,
1380
        &KSPROPSETID_Pin,
1381
        KSPROPERTY_PIN_COMMUNICATION,
1382
        &pin->communication,
1383
        sizeof(KSPIN_COMMUNICATION),
1384
        NULL);
1385
    if( result != paNoError )
1386
        goto error;
1387

    
1388
    if( /*(pin->communication != KSPIN_COMMUNICATION_SOURCE) &&*/
1389
        (pin->communication != KSPIN_COMMUNICATION_SINK) &&
1390
        (pin->communication != KSPIN_COMMUNICATION_BOTH) )
1391
    {
1392
        PA_DEBUG(("PinNew: Not source/sink\n"));
1393
        result = paInvalidDevice;
1394
        goto error;
1395
    }
1396

    
1397
    /* Get dataflow information */
1398
    result = WdmGetPinPropertySimple(
1399
        parentFilter->handle,
1400
        pinId,
1401
        &KSPROPSETID_Pin,
1402
        KSPROPERTY_PIN_DATAFLOW,
1403
        &pin->dataFlow,
1404
        sizeof(KSPIN_DATAFLOW),
1405
        NULL);
1406

    
1407
    if( result != paNoError )
1408
        goto error;
1409

    
1410
    /* Get the INTERFACE property list */
1411
    result = WdmGetPinPropertyMulti(
1412
        parentFilter->handle,
1413
        pinId,
1414
        &KSPROPSETID_Pin,
1415
        KSPROPERTY_PIN_INTERFACES,
1416
        &item);
1417

    
1418
    if( result != paNoError )
1419
        goto error;
1420

    
1421
    identifier = (KSIDENTIFIER*)(item+1);
1422

    
1423
    /* Check that at least one interface is STANDARD_STREAMING */
1424
    result = paUnanticipatedHostError;
1425
    for( i = 0; i < item->Count; i++ )
1426
    {
1427
        if( IsEqualGUID(&identifier[i].Set, &KSINTERFACESETID_Standard) && ( identifier[i].Id == streamingId ) )
1428
        {
1429
            result = paNoError;
1430
            break;
1431
        }
1432
    }
1433

    
1434
    if( result != paNoError )
1435
    {
1436
        PA_DEBUG(("PinNew: No %s streaming\n", streamingId==KSINTERFACE_STANDARD_LOOPED_STREAMING?"looped":"standard"));
1437
        goto error;
1438
    }
1439

    
1440
    /* Don't need interfaces any more */
1441
    PaUtil_FreeMemory( item );
1442
    item = NULL;
1443

    
1444
    /* Get the MEDIUM properties list */
1445
    result = WdmGetPinPropertyMulti(
1446
        parentFilter->handle,
1447
        pinId,
1448
        &KSPROPSETID_Pin,
1449
        KSPROPERTY_PIN_MEDIUMS,
1450
        &item);
1451

    
1452
    if( result != paNoError )
1453
        goto error;
1454

    
1455
    identifier = (KSIDENTIFIER*)(item+1); /* Not actually necessary... */
1456

    
1457
    /* Check that at least one medium is STANDARD_DEVIO */
1458
    result = paUnanticipatedHostError;
1459
    for( i = 0; i < item->Count; i++ )
1460
    {
1461
        if( IsEqualGUID(&identifier[i].Set, &KSMEDIUMSETID_Standard) && ( identifier[i].Id == KSMEDIUM_STANDARD_DEVIO ) )
1462
        {
1463
            result = paNoError;
1464
            break;
1465
        }
1466
    }
1467

    
1468
    if( result != paNoError )
1469
    {
1470
        PA_DEBUG(("No standard devio\n"));
1471
        goto error;
1472
    }
1473
    /* Don't need mediums any more */
1474
    PaUtil_FreeMemory( item );
1475
    item = NULL;
1476

    
1477
    /* Get DATARANGES */
1478
    result = WdmGetPinPropertyMulti(
1479
        parentFilter->handle,
1480
        pinId,
1481
        &KSPROPSETID_Pin,
1482
        KSPROPERTY_PIN_DATARANGES,
1483
        &pin->dataRangesItem);
1484

    
1485
    if( result != paNoError )
1486
        goto error;
1487

    
1488
    pin->dataRanges = (KSDATARANGE*)(pin->dataRangesItem +1);
1489

    
1490
    /* Check that at least one datarange supports audio */
1491
    result = paUnanticipatedHostError;
1492
    dataRange = pin->dataRanges;
1493
    pin->maxChannels = 0;
1494
    pin->defaultSampleRate = 0;
1495
    pin->formats = 0;
1496
    PA_DEBUG(("PinNew: Checking %u no of dataranges...\n", pin->dataRangesItem->Count));
1497
    for( i = 0; i < pin->dataRangesItem->Count; i++)
1498
    {
1499
        PA_DEBUG(("PinNew: DR major format %x\n",*(unsigned long*)(&(dataRange->MajorFormat))));
1500
        /* Check that subformat is WAVEFORMATEX, PCM or WILDCARD */
1501
        if( IS_VALID_WAVEFORMATEX_GUID(&dataRange->SubFormat) ||
1502
            IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) ||
1503
            IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) ||
1504
            IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_WILDCARD) ||
1505
            IsEqualGUID(&dataRange->MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) )
1506
        {
1507
            int defaultIndex;
1508
            result = paNoError;
1509
            /* Record the maximum possible channels with this pin */
1510
            if( ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels == (ULONG) -1 )
1511
            {
1512
                pin->maxChannels = MAXIMUM_NUMBER_OF_CHANNELS;
1513
            }
1514
            else if( (int) ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels > pin->maxChannels )
1515
            {
1516
                pin->maxChannels = (int) ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels;
1517
            }
1518
            PA_DEBUG(("PinNew: MaxChannel: %d\n",pin->maxChannels));
1519

    
1520
            /* Record the formats (bit depths) that are supported */
1521
            if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 8) )
1522
            {
1523
                pin->formats |= paInt8;
1524
                PA_DEBUG(("PinNew: Format PCM 8 bit supported\n"));
1525
            }
1526
            if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 16) )
1527
            {
1528
                pin->formats |= paInt16;
1529
                PA_DEBUG(("PinNew: Format PCM 16 bit supported\n"));
1530
            }
1531
            if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 24) )
1532
            {
1533
                pin->formats |= paInt24;
1534
                PA_DEBUG(("PinNew: Format PCM 24 bit supported\n"));
1535
            }
1536
            if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 32) )
1537
            {
1538
                if (IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
1539
                {
1540
                    pin->formats |= paFloat32;
1541
                    PA_DEBUG(("PinNew: Format IEEE float 32 bit supported\n"));
1542
                }
1543
                else
1544
                {
1545
                    pin->formats |= paInt32;
1546
                    PA_DEBUG(("PinNew: Format PCM 32 bit supported\n"));
1547
                }
1548
            }
1549

    
1550
            defaultIndex = DefaultSampleFrequencyIndex((KSDATARANGE_AUDIO*)dataRange);
1551
            if (defaultIndex >= 0 && defaultIndex < defaultSampleRateIndex)
1552
            {
1553
                defaultSampleRateIndex = defaultIndex;
1554
            }
1555
        }
1556
        dataRange = (KSDATARANGE*)( ((char*)dataRange) + dataRange->FormatSize);
1557
    }
1558

    
1559
    if( result != paNoError )
1560
        goto error;
1561

    
1562
    /* If none of the frequencies searched for are present, there's something seriously wrong */
1563
    if (defaultSampleRateIndex == defaultSampleRateSearchOrderCount)
1564
    {
1565
        PA_DEBUG(("PinNew: No default sample rate found, skipping pin!\n"));
1566
        PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "PinNew: No default sample rate found");
1567
        result = paUnanticipatedHostError;
1568
        goto error;
1569
    }
1570

    
1571
    /* Set the default sample rate */
1572
    pin->defaultSampleRate = defaultSampleRateSearchOrder[defaultSampleRateIndex];
1573
    PA_DEBUG(("PinNew: Default sample rate = %d Hz\n", pin->defaultSampleRate));
1574

    
1575
    /* Get instance information */
1576
    result = WdmGetPinPropertySimple(
1577
        parentFilter->handle,
1578
        pinId,
1579
        &KSPROPSETID_Pin,
1580
        KSPROPERTY_PIN_CINSTANCES,
1581
        &pin->instances,
1582
        sizeof(KSPIN_CINSTANCES),
1583
        NULL);
1584

    
1585
    if( result != paNoError )
1586
        goto error;
1587

    
1588
    /* If WaveRT, check if pin supports notification mode */
1589
    if (parentFilter->devInfo.streamingType == Type_kWaveRT)
1590
    {
1591
        BOOL bSupportsNotification = FALSE;
1592
        if (PinQueryNotificationSupport(pin, &bSupportsNotification) == paNoError)
1593
        {
1594
            pin->pinKsSubType = bSupportsNotification ? SubType_kNotification : SubType_kPolled;
1595
        }
1596
    }
1597

    
1598
    /* Query pin name (which means we need to traverse to non IRP pin, via physical connection to topology filter pin, through
1599
    its nodes to the endpoint pin, and get that ones name... phew...) */
1600
    PA_DEBUG(("PinNew: Finding topology pin...\n"));
1601

    
1602
    {
1603
        ULONG topoPinId = GetConnectedPin(pinId, (pin->dataFlow == KSPIN_DATAFLOW_IN), parentFilter, -1, NULL, NULL);
1604
        const wchar_t kInputName[] = L"Input";
1605
        const wchar_t kOutputName[] = L"Output";
1606

    
1607
        if (topoPinId != KSFILTER_NODE)
1608
        {
1609
            /* Get physical connection for topo pin */
1610
            unsigned long cbBytes = 0;
1611
            PA_DEBUG(("PinNew: Getting physical connection...\n"));
1612
            result = WdmGetPinPropertySimple(parentFilter->handle,
1613
                topoPinId,
1614
                &KSPROPSETID_Pin,
1615
                KSPROPERTY_PIN_PHYSICALCONNECTION,
1616
                0,
1617
                0,
1618
                &cbBytes
1619
                );
1620

    
1621
            if (result != paNoError)
1622
            {
1623
                /* No physical connection -> there is no topology filter! So we get the name of the pin! */
1624
                PA_DEBUG(("PinNew: No physical connection! Getting the pin name\n"));
1625
                result = WdmGetPinPropertySimple(parentFilter->handle,
1626
                    topoPinId,
1627
                    &KSPROPSETID_Pin,
1628
                    KSPROPERTY_PIN_NAME,
1629
                    pin->friendlyName,
1630
                    MAX_PATH,
1631
                    NULL);
1632
                if (result != paNoError)
1633
                {
1634
                    GUID category = {0};
1635

    
1636
                    /* Get pin category information */
1637
                    result = WdmGetPinPropertySimple(parentFilter->handle,
1638
                        topoPinId,
1639
                        &KSPROPSETID_Pin,
1640
                        KSPROPERTY_PIN_CATEGORY,
1641
                        &category,
1642
                        sizeof(GUID),
1643
                        NULL);
1644

    
1645
                    if (result == paNoError)
1646
                    {
1647
                        result = GetNameFromCategory(&category, (pin->dataFlow == KSPIN_DATAFLOW_OUT), pin->friendlyName, MAX_PATH);
1648
                    }
1649
                }
1650

    
1651
                /* Make sure pin gets a name here... */
1652
                if (wcslen(pin->friendlyName) == 0)
1653
                {
1654
                    wcscpy(pin->friendlyName, (pin->dataFlow == KSPIN_DATAFLOW_IN) ? kOutputName : kInputName);
1655
#ifdef UNICODE
1656
                    PA_DEBUG(("PinNew: Setting pin friendly name to '%s'\n", pin->friendlyName));
1657
#else
1658
                    PA_DEBUG(("PinNew: Setting pin friendly name to '%S'\n", pin->friendlyName));
1659
#endif
1660
                }
1661

    
1662
                /* This is then == the endpoint pin */
1663
                pin->endpointPinId = (pin->dataFlow == KSPIN_DATAFLOW_IN) ? pinId : topoPinId;
1664
            }
1665
            else
1666
            {
1667
                KSPIN_PHYSICALCONNECTION* pc = (KSPIN_PHYSICALCONNECTION*)PaUtil_AllocateMemory(cbBytes + 2);
1668
                ULONG pcPin;
1669
                wchar_t symbLinkName[MAX_PATH];
1670
                PA_DEBUG(("PinNew: Physical connection found!\n"));
1671
                if (pc == NULL)
1672
                {
1673
                    result = paInsufficientMemory;
1674
                    goto error;
1675
                }
1676
                result = WdmGetPinPropertySimple(parentFilter->handle,
1677
                    topoPinId,
1678
                    &KSPROPSETID_Pin,
1679
                    KSPROPERTY_PIN_PHYSICALCONNECTION,
1680
                    pc,
1681
                    cbBytes,
1682
                    NULL
1683
                    );
1684

    
1685
                pcPin = pc->Pin;
1686
                wcsncpy(symbLinkName, pc->SymbolicLinkName, MAX_PATH);
1687
                PaUtil_FreeMemory( pc );
1688

    
1689
                if (result != paNoError)
1690
                {
1691
                    /* Shouldn't happen, but fail if it does */
1692
                    PA_DEBUG(("PinNew: failed to retrieve physical connection!\n"));
1693
                    goto error;
1694
                }
1695

    
1696
                if (symbLinkName[1] == TEXT('?'))
1697
                {
1698
                    symbLinkName[1] = TEXT('\\');
1699
                }
1700

    
1701
                if (pin->parentFilter->topologyFilter == NULL)
1702
                {
1703
                    PA_DEBUG(("PinNew: Creating topology filter '%S'\n", symbLinkName));
1704

    
1705
                    pin->parentFilter->topologyFilter = FilterNew(Type_kNotUsed, 0, symbLinkName, L"", &result);
1706
                    if (pin->parentFilter->topologyFilter == NULL)
1707
                    {
1708
                        PA_DEBUG(("PinNew: Failed creating topology filter\n"));
1709
                        result = paUnanticipatedHostError;
1710
                        PaWinWDM_SetLastErrorInfo(result, "Failed to create topology filter '%S'", symbLinkName);
1711
                        goto error;
1712
                    }
1713

    
1714
                    /* Copy info so we have it in device info */
1715
                    wcsncpy(pin->parentFilter->devInfo.topologyPath, symbLinkName, MAX_PATH);
1716
                }
1717
                else
1718
                {
1719
                    /* Must be the same */
1720
                    assert(wcscmp(symbLinkName, pin->parentFilter->topologyFilter->devInfo.filterPath) == 0);
1721
                }
1722

    
1723
                PA_DEBUG(("PinNew: Opening topology filter..."));
1724

    
1725
                result = FilterUse(pin->parentFilter->topologyFilter);
1726
                if (result == paNoError)
1727
                {
1728
                    unsigned long endpointPinId;
1729

    
1730
                    if (pin->dataFlow == KSPIN_DATAFLOW_IN)
1731
                    {
1732
                        /* The "endpointPinId" is what WASAPI looks at for pin names */
1733
                        GUID category = {0};
1734

    
1735
                        PA_DEBUG(("PinNew: Checking for output endpoint pin id...\n"));
1736

    
1737
                        endpointPinId = GetConnectedPin(pcPin, TRUE, pin->parentFilter->topologyFilter, -1, NULL, NULL);
1738

    
1739
                        if (endpointPinId == KSFILTER_NODE)
1740
                        {
1741
                            result = paUnanticipatedHostError;
1742
                            PaWinWDM_SetLastErrorInfo(result, "Failed to get endpoint pin ID on topology filter!");
1743
                            goto error;
1744
                        }
1745

    
1746
                        PA_DEBUG(("PinNew: Found endpoint pin id %u\n", endpointPinId));
1747

    
1748
                        /* Get pin category information */
1749
                        result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
1750
                            endpointPinId,
1751
                            &KSPROPSETID_Pin,
1752
                            KSPROPERTY_PIN_CATEGORY,
1753
                            &category,
1754
                            sizeof(GUID),
1755
                            NULL);
1756

    
1757
                        if (result == paNoError)
1758
                        {
1759
#if !PA_WDMKS_USE_CATEGORY_FOR_PIN_NAMES
1760
                            wchar_t pinName[MAX_PATH];
1761

    
1762
                            PA_DEBUG(("PinNew: Getting pin name property..."));
1763

    
1764
                            /* Ok, try pin name also, and favor that if available */
1765
                            result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
1766
                                endpointPinId,
1767
                                &KSPROPSETID_Pin,
1768
                                KSPROPERTY_PIN_NAME,
1769
                                pinName,
1770
                                MAX_PATH,
1771
                                NULL);
1772

    
1773
                            if (result == paNoError && wcslen(pinName)>0)
1774
                            {
1775
                                wcsncpy(pin->friendlyName, pinName, MAX_PATH);
1776
                            }
1777
                            else
1778
#endif
1779
                            {
1780
                                result = GetNameFromCategory(&category, (pin->dataFlow == KSPIN_DATAFLOW_OUT), pin->friendlyName, MAX_PATH);
1781
                            }
1782
                        }
1783

    
1784
                        /* Make sure we get a name for the pin */
1785
                        if (wcslen(pin->friendlyName) == 0)
1786
                        {
1787
                            wcscpy(pin->friendlyName, kOutputName);
1788
                        }
1789
#ifdef UNICODE
1790
                        PA_DEBUG(("PinNew: Pin name '%s'\n", pin->friendlyName));
1791
#else
1792
                        PA_DEBUG(("PinNew: Pin name '%S'\n", pin->friendlyName));
1793
#endif                                
1794

    
1795
                        /* Set endpoint pin ID (this is the topology INPUT pin, since portmixer will always traverse the
1796
                        filter in audio streaming direction, see http://msdn.microsoft.com/en-us/library/windows/hardware/ff536331(v=vs.85).aspx
1797
                        for more information)
1798
                        */
1799
                        pin->endpointPinId = pcPin;
1800
                    }
1801
                    else
1802
                    {
1803
                        unsigned muxCount = 0;
1804
                        int muxPos = 0;
1805
                        /* Max 64 multiplexer inputs... sanity check :) */
1806
                        for (i = 0; i < 64; ++i)
1807
                        {
1808
                            ULONG muxNodeIdTest = (unsigned)-1;
1809
                            PA_DEBUG(("PinNew: Checking for input endpoint pin id (%d)...\n", i));
1810

    
1811
                            endpointPinId = GetConnectedPin(pcPin,
1812
                                FALSE,
1813
                                pin->parentFilter->topologyFilter,
1814
                                (int)i,
1815
                                NULL,
1816
                                &muxNodeIdTest);
1817

    
1818
                            if (endpointPinId == KSFILTER_NODE)
1819
                            {
1820
                                /* We're done */
1821
                                PA_DEBUG(("PinNew: Done with inputs.\n", endpointPinId));
1822
                                break;
1823
                            }
1824
                            else
1825
                            {
1826
                                /* The "endpointPinId" is what WASAPI looks at for pin names */
1827
                                GUID category = {0};
1828

    
1829
                                PA_DEBUG(("PinNew: Found endpoint pin id %u\n", endpointPinId));
1830

    
1831
                                /* Get pin category information */
1832
                                result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
1833
                                    endpointPinId,
1834
                                    &KSPROPSETID_Pin,
1835
                                    KSPROPERTY_PIN_CATEGORY,
1836
                                    &category,
1837
                                    sizeof(GUID),
1838
                                    NULL);
1839

    
1840
                                if (result == paNoError)
1841
                                {
1842
                                    if (muxNodeIdTest == (unsigned)-1)
1843
                                    {
1844
                                        /* Ok, try pin name, and favor that if available */
1845
                                        result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
1846
                                            endpointPinId,
1847
                                            &KSPROPSETID_Pin,
1848
                                            KSPROPERTY_PIN_NAME,
1849
                                            pin->friendlyName,
1850
                                            MAX_PATH,
1851
                                            NULL);
1852

    
1853
                                        if (result != paNoError)
1854
                                        {
1855
                                            result = GetNameFromCategory(&category, TRUE, pin->friendlyName, MAX_PATH);
1856
                                        }
1857
                                        break;
1858
                                    }
1859
                                    else
1860
                                    {
1861
                                        result = GetNameFromCategory(&category, TRUE, NULL, 0);
1862

    
1863
                                        if (result == paNoError)
1864
                                        {
1865
                                            ++muxCount;
1866
                                        }
1867
                                    }
1868
                                }
1869
                                else
1870
                                {
1871
                                    PA_DEBUG(("PinNew: Failed to get pin category"));
1872
                                }
1873
                            }
1874
                        }
1875

    
1876
                        if (muxCount == 0)
1877
                        {
1878
                            pin->endpointPinId = endpointPinId;
1879
                            /* Make sure we get a name for the pin */
1880
                            if (wcslen(pin->friendlyName) == 0)
1881
                            {
1882
                                wcscpy(pin->friendlyName, kInputName);
1883
                            }
1884
#ifdef UNICODE
1885
                            PA_DEBUG(("PinNew: Input friendly name '%s'\n", pin->friendlyName));
1886
#else
1887
                            PA_DEBUG(("PinNew: Input friendly name '%S'\n", pin->friendlyName));
1888
#endif
1889
                        }
1890
                        else // muxCount > 0
1891
                        {
1892
                            PA_DEBUG(("PinNew: Setting up %u inputs\n", muxCount));
1893

    
1894
                            /* Now we redo the operation once known how many multiplexer positions there are */
1895
                            pin->inputs = (PaWinWdmMuxedInput**)PaUtil_AllocateMemory(muxCount * sizeof(PaWinWdmMuxedInput*));
1896
                            if (pin->inputs == NULL)
1897
                            {
1898
                                FilterRelease(pin->parentFilter->topologyFilter);
1899
                                result = paInsufficientMemory;
1900
                                goto error;
1901
                            }
1902
                            pin->inputCount = muxCount;
1903

    
1904
                            for (i = 0; i < muxCount; ++muxPos)
1905
                            {
1906
                                PA_DEBUG(("PinNew: Setting up input %u...\n", i));
1907

    
1908
                                if (pin->inputs[i] == NULL)
1909
                                {
1910
                                    pin->inputs[i] = (PaWinWdmMuxedInput*)PaUtil_AllocateMemory(sizeof(PaWinWdmMuxedInput));
1911
                                    if (pin->inputs[i] == NULL)
1912
                                    {
1913
                                        FilterRelease(pin->parentFilter->topologyFilter);
1914
                                        result = paInsufficientMemory;
1915
                                        goto error;
1916
                                    }
1917
                                }
1918

    
1919
                                endpointPinId = GetConnectedPin(pcPin,
1920
                                    FALSE,
1921
                                    pin->parentFilter->topologyFilter,
1922
                                    muxPos,
1923
                                    &pin->inputs[i]->muxPinId, 
1924
                                    &pin->inputs[i]->muxNodeId);
1925

    
1926
                                if (endpointPinId != KSFILTER_NODE)
1927
                                {
1928
                                    /* The "endpointPinId" is what WASAPI looks at for pin names */
1929
                                    GUID category = {0};
1930

    
1931
                                    /* Set input endpoint ID */
1932
                                    pin->inputs[i]->endpointPinId = endpointPinId;
1933

    
1934
                                    /* Get pin category information */
1935
                                    result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
1936
                                        endpointPinId,
1937
                                        &KSPROPSETID_Pin,
1938
                                        KSPROPERTY_PIN_CATEGORY,
1939
                                        &category,
1940
                                        sizeof(GUID),
1941
                                        NULL);
1942

    
1943
                                    if (result == paNoError)
1944
                                    {
1945
                                        /* Try pin name first, and if that is not defined, use category instead */
1946
                                        result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle,
1947
                                            endpointPinId,
1948
                                            &KSPROPSETID_Pin,
1949
                                            KSPROPERTY_PIN_NAME,
1950
                                            pin->inputs[i]->friendlyName,
1951
                                            MAX_PATH,
1952
                                            NULL);
1953

    
1954
                                        if (result != paNoError)
1955
                                        {
1956
                                            result = GetNameFromCategory(&category, TRUE, pin->inputs[i]->friendlyName, MAX_PATH);
1957
                                            if (result != paNoError)
1958
                                            {
1959
                                                /* Only specify name, let name hash in ScanDeviceInfos fix postfix enumerators */
1960
                                                wcscpy(pin->inputs[i]->friendlyName, kInputName);
1961
                                            }
1962
                                        }
1963
#ifdef UNICODE
1964
                                        PA_DEBUG(("PinNew: Input (%u) friendly name '%s'\n", i, pin->inputs[i]->friendlyName));
1965
#else
1966
                                        PA_DEBUG(("PinNew: Input (%u) friendly name '%S'\n", i, pin->inputs[i]->friendlyName));
1967
#endif
1968
                                        ++i;
1969
                                    }
1970
                                }
1971
                                else
1972
                                {
1973
                                    /* Should never come here! */
1974
                                    assert(FALSE);
1975
                                }
1976
                            }
1977
                        }
1978
                    }
1979
                }
1980
            }
1981
        }
1982
        else
1983
        {
1984
            PA_DEBUG(("PinNew: No topology pin id found. Bad...\n"));
1985
            /* No TOPO pin id ??? This is bad. Ok, so we just say it is an input or output... */
1986
            wcscpy(pin->friendlyName, (pin->dataFlow == KSPIN_DATAFLOW_IN) ? kOutputName : kInputName);
1987
        }
1988
    }
1989

    
1990
    /* Release topology filter if it has been used */
1991
    if (pin->parentFilter->topologyFilter && pin->parentFilter->topologyFilter->handle != NULL)
1992
    {
1993
        PA_DEBUG(("PinNew: Releasing topology filter...\n"));
1994
        FilterRelease(pin->parentFilter->topologyFilter);
1995
    }
1996

    
1997
    /* Success */
1998
    *error = paNoError;
1999
    PA_DEBUG(("Pin created successfully\n"));
2000
    PA_LOGL_;
2001
    return pin;
2002

    
2003
error:
2004
    PA_DEBUG(("PinNew: Error %d\n", result));
2005
    /*
2006
    Error cleanup
2007
    */
2008

    
2009
    if (pin->parentFilter->topologyFilter && pin->parentFilter->topologyFilter->handle != NULL)
2010
    {
2011
        FilterRelease(pin->parentFilter->topologyFilter);
2012
    }
2013

    
2014
    PaUtil_FreeMemory( item );
2015
    PinFree(pin);
2016

    
2017
    *error = result;
2018
    PA_LOGL_;
2019
    return NULL;
2020
}
2021

    
2022
/*
2023
Safely free all resources associated with the pin
2024
*/
2025
static void PinFree(PaWinWdmPin* pin)
2026
{
2027
    unsigned i;
2028
    PA_LOGE_;
2029
    if( pin )
2030
    {
2031
        PinClose(pin);
2032
        if( pin->pinConnect )
2033
        {
2034
            PaUtil_FreeMemory( pin->pinConnect );
2035
        }
2036
        if( pin->dataRangesItem )
2037
        {
2038
            PaUtil_FreeMemory( pin->dataRangesItem );
2039
        }
2040
        if( pin->inputs )
2041
        {
2042
            for (i = 0; i < pin->inputCount; ++i)
2043
            {
2044
                PaUtil_FreeMemory( pin->inputs[i] );
2045
            }
2046
            PaUtil_FreeMemory( pin->inputs );
2047
        }
2048
        PaUtil_FreeMemory( pin );
2049
    }
2050
    PA_LOGL_;
2051
}
2052

    
2053
/*
2054
If the pin handle is open, close it
2055
*/
2056
static void PinClose(PaWinWdmPin* pin)
2057
{
2058
    PA_LOGE_;
2059
    if( pin == NULL )
2060
    {
2061
        PA_DEBUG(("Closing NULL pin!"));
2062
        PA_LOGL_;
2063
        return;
2064
    }
2065
    if( pin->handle != NULL )
2066
    {
2067
        PinSetState( pin, KSSTATE_PAUSE );
2068
        PinSetState( pin, KSSTATE_STOP );
2069
        CloseHandle( pin->handle );
2070
        pin->handle = NULL;
2071
        FilterRelease(pin->parentFilter);
2072
    }
2073
    PA_LOGL_;
2074
}
2075

    
2076
/*
2077
Set the state of this (instantiated) pin
2078
*/
2079
static PaError PinSetState(PaWinWdmPin* pin, KSSTATE state)
2080
{
2081
    PaError result = paNoError;
2082
    KSPROPERTY prop;
2083

    
2084
    PA_LOGE_;
2085
    prop.Set = KSPROPSETID_Connection;
2086
    prop.Id  = KSPROPERTY_CONNECTION_STATE;
2087
    prop.Flags = KSPROPERTY_TYPE_SET;
2088

    
2089
    if( pin == NULL )
2090
        return paInternalError;
2091
    if( pin->handle == NULL )
2092
        return paInternalError;
2093

    
2094
    result = WdmSyncIoctl(pin->handle, IOCTL_KS_PROPERTY, &prop, sizeof(KSPROPERTY), &state, sizeof(KSSTATE), NULL);
2095

    
2096
    PA_LOGL_;
2097
    return result;
2098
}
2099

    
2100
static PaError PinInstantiate(PaWinWdmPin* pin)
2101
{
2102
    PaError result;
2103
    unsigned long createResult;
2104
    KSALLOCATOR_FRAMING ksaf;
2105
    KSALLOCATOR_FRAMING_EX ksafex;
2106

    
2107
    PA_LOGE_;
2108

    
2109
    if( pin == NULL )
2110
        return paInternalError;
2111
    if(!pin->pinConnect)
2112
        return paInternalError;
2113

    
2114
    FilterUse(pin->parentFilter);
2115

    
2116
    createResult = FunctionKsCreatePin(
2117
        pin->parentFilter->handle,
2118
        pin->pinConnect,
2119
        GENERIC_WRITE | GENERIC_READ,
2120
        &pin->handle
2121
        );
2122

    
2123
    PA_DEBUG(("Pin create result = 0x%08x\n",createResult));
2124
    if( createResult != ERROR_SUCCESS )
2125
    {
2126
        FilterRelease(pin->parentFilter);
2127
        pin->handle = NULL;
2128
        switch (createResult)
2129
        {
2130
        case ERROR_INVALID_PARAMETER:
2131
            /* First case when pin actually don't support the format */
2132
            return paSampleFormatNotSupported;
2133
        case ERROR_BAD_COMMAND:
2134
            /* Case when pin is occupied (by another application) */
2135
            return paDeviceUnavailable;
2136
        default:
2137
            /* All other cases */
2138
            return paInvalidDevice;
2139
        }
2140
    }
2141

    
2142
    if (pin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
2143
    {
2144
        /* Framing size query only valid for WaveCyclic devices */
2145
        result = WdmGetPropertySimple(
2146
            pin->handle,
2147
            &KSPROPSETID_Connection,
2148
            KSPROPERTY_CONNECTION_ALLOCATORFRAMING,
2149
            &ksaf,
2150
            sizeof(ksaf));
2151

    
2152
        if( result != paNoError )
2153
        {
2154
            result = WdmGetPropertySimple(
2155
                pin->handle,
2156
                &KSPROPSETID_Connection,
2157
                KSPROPERTY_CONNECTION_ALLOCATORFRAMING_EX,
2158
                &ksafex,
2159
                sizeof(ksafex));
2160
            if( result == paNoError )
2161
            {
2162
                pin->frameSize = ksafex.FramingItem[0].FramingRange.Range.MinFrameSize;
2163
            }
2164
        }
2165
        else
2166
        {
2167
            pin->frameSize = ksaf.FrameSize;
2168
        }
2169
    }
2170

    
2171
    PA_LOGL_;
2172

    
2173
    return paNoError;
2174
}
2175

    
2176
static PaError PinSetFormat(PaWinWdmPin* pin, const WAVEFORMATEX* format)
2177
{
2178
    unsigned long size;
2179
    void* newConnect;
2180

    
2181
    PA_LOGE_;
2182

    
2183
    if( pin == NULL )
2184
        return paInternalError;
2185
    if( format == NULL )
2186
        return paInternalError;
2187

    
2188
    size = GetWfexSize(format) + sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX) - sizeof(WAVEFORMATEX);
2189

    
2190
    if( pin->pinConnectSize != size )
2191
    {
2192
        newConnect = PaUtil_AllocateMemory( size );
2193
        if( newConnect == NULL )
2194
            return paInsufficientMemory;
2195
        memcpy( newConnect, (void*)pin->pinConnect, min(pin->pinConnectSize,size) );
2196
        PaUtil_FreeMemory( pin->pinConnect );
2197
        pin->pinConnect = (KSPIN_CONNECT*)newConnect;
2198
        pin->pinConnectSize = size;
2199
        pin->ksDataFormatWfx = (KSDATAFORMAT_WAVEFORMATEX*)((KSPIN_CONNECT*)newConnect + 1);
2200
        pin->ksDataFormatWfx->DataFormat.FormatSize = size - sizeof(KSPIN_CONNECT);
2201
    }
2202

    
2203
    memcpy( (void*)&(pin->ksDataFormatWfx->WaveFormatEx), format, GetWfexSize(format) );
2204
    pin->ksDataFormatWfx->DataFormat.SampleSize = (unsigned short)(format->nChannels * (format->wBitsPerSample / 8));
2205

    
2206
    PA_LOGL_;
2207

    
2208
    return paNoError;
2209
}
2210

    
2211
static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format)
2212
{
2213
    KSDATARANGE_AUDIO* dataRange;
2214
    unsigned long count;
2215
    GUID guid = DYNAMIC_GUID( DEFINE_WAVEFORMATEX_GUID(format->wFormatTag) );
2216
    PaError result = paInvalidDevice;
2217
    const WAVEFORMATEXTENSIBLE* pFormatExt = (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE) ? (const WAVEFORMATEXTENSIBLE*)format : 0;
2218

    
2219
    PA_LOGE_;
2220

    
2221
    if( pFormatExt != 0 )
2222
    {
2223
        guid = pFormatExt->SubFormat;
2224
    }
2225
    dataRange = (KSDATARANGE_AUDIO*)pin->dataRanges;
2226
    for(count = 0;
2227
        count<pin->dataRangesItem->Count;
2228
        count++, 
2229
        dataRange = (KSDATARANGE_AUDIO*)( ((char*)dataRange) + dataRange->DataRange.FormatSize)) /* Need to update dataRange here, due to 'continue' !! */
2230
    {
2231
        /* Check major format*/
2232
        if (!(IsEqualGUID(&(dataRange->DataRange.MajorFormat), &KSDATAFORMAT_TYPE_AUDIO) ||
2233
            IsEqualGUID(&(dataRange->DataRange.MajorFormat), &KSDATAFORMAT_TYPE_WILDCARD)))
2234
        {
2235
            continue;
2236
        }
2237

    
2238
        /* This is an audio or wildcard datarange... */
2239
        if (! (IsEqualGUID(&(dataRange->DataRange.SubFormat), &KSDATAFORMAT_SUBTYPE_WILDCARD) ||
2240
            IsEqualGUID(&(dataRange->DataRange.SubFormat), &KSDATAFORMAT_SUBTYPE_PCM) ||
2241
            IsEqualGUID(&(dataRange->DataRange.SubFormat), &guid) ))
2242
        {
2243
            continue;
2244
        }
2245

    
2246
        /* Check specifier... */
2247
        if (! (IsEqualGUID(&(dataRange->DataRange.Specifier), &KSDATAFORMAT_SPECIFIER_WILDCARD) ||
2248
            IsEqualGUID(&(dataRange->DataRange.Specifier), &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)) )
2249
        {
2250
            continue;
2251
        }
2252

    
2253
        PA_DEBUG(("Pin:%x, DataRange:%d\n",(void*)pin,count));
2254
        PA_DEBUG(("\tFormatSize:%d, SampleSize:%d\n",dataRange->DataRange.FormatSize,dataRange->DataRange.SampleSize));
2255
        PA_DEBUG(("\tMaxChannels:%d\n",dataRange->MaximumChannels));
2256
        PA_DEBUG(("\tBits:%d-%d\n",dataRange->MinimumBitsPerSample,dataRange->MaximumBitsPerSample));
2257
        PA_DEBUG(("\tSampleRate:%d-%d\n",dataRange->MinimumSampleFrequency,dataRange->MaximumSampleFrequency));
2258

    
2259
        if( dataRange->MaximumChannels != (ULONG)-1 && 
2260
            dataRange->MaximumChannels < format->nChannels )
2261
        {
2262
            result = paInvalidChannelCount;
2263
            continue;
2264
        }
2265

    
2266
        if (pFormatExt != 0)
2267
        {
2268
            if (!IsBitsWithinRange(dataRange, pFormatExt->Samples.wValidBitsPerSample))
2269
            {
2270
                result = paSampleFormatNotSupported;
2271
                continue;
2272
            }
2273
        }
2274
        else
2275
        {
2276
            if (!IsBitsWithinRange(dataRange, format->wBitsPerSample))
2277
            {
2278
                result = paSampleFormatNotSupported;
2279
                continue;
2280
            }
2281
        }
2282

    
2283
        if (!IsFrequencyWithinRange(dataRange, format->nSamplesPerSec))
2284
        {
2285
            result = paInvalidSampleRate;
2286
            continue;
2287
        }
2288

    
2289
        /* Success! */
2290
        result = paNoError;
2291
        break;
2292
    }
2293

    
2294
    PA_LOGL_;
2295
    return result;
2296
}
2297

    
2298
static PaError PinQueryNotificationSupport(PaWinWdmPin* pPin, BOOL* pbResult)
2299
{
2300
    PaError result = paNoError;
2301
    KSPROPERTY propIn;
2302

    
2303
    PA_LOGE_;
2304

    
2305
    propIn.Set = KSPROPSETID_RtAudio;
2306
    propIn.Id = 8; /* = KSPROPERTY_RTAUDIO_QUERY_NOTIFICATION_SUPPORT */
2307
    propIn.Flags = KSPROPERTY_TYPE_GET;
2308

    
2309
    result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
2310
        &propIn,
2311
        sizeof(KSPROPERTY),
2312
        pbResult,
2313
        sizeof(BOOL),
2314
        NULL);
2315

    
2316
    if (result != paNoError) 
2317
    {
2318
        PA_DEBUG(("Failed PinQueryNotificationSupport\n"));
2319
    }
2320

    
2321
    PA_LOGL_;
2322
    return result;
2323
}
2324

    
2325
static PaError PinGetBufferWithNotification(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier)
2326
{
2327
    PaError result = paNoError;
2328
    KSRTAUDIO_BUFFER_PROPERTY_WITH_NOTIFICATION propIn;
2329
    KSRTAUDIO_BUFFER propOut;
2330

    
2331
    PA_LOGE_;
2332

    
2333
    propIn.BaseAddress = 0;
2334
    propIn.NotificationCount = 2;
2335
    propIn.RequestedBufferSize = *pRequestedBufSize;
2336
    propIn.Property.Set = KSPROPSETID_RtAudio;
2337
    propIn.Property.Id = KSPROPERTY_RTAUDIO_BUFFER_WITH_NOTIFICATION;
2338
    propIn.Property.Flags = KSPROPERTY_TYPE_GET;
2339

    
2340
    result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
2341
        &propIn,
2342
        sizeof(KSRTAUDIO_BUFFER_PROPERTY_WITH_NOTIFICATION),
2343
        &propOut,
2344
        sizeof(KSRTAUDIO_BUFFER),
2345
        NULL);
2346

    
2347
    if (result == paNoError) 
2348
    {
2349
        *pBuffer = propOut.BufferAddress;
2350
        *pRequestedBufSize = propOut.ActualBufferSize;
2351
        *pbCallMemBarrier = propOut.CallMemoryBarrier;
2352
    }
2353
    else 
2354
    {
2355
        PA_DEBUG(("Failed to get buffer with notification\n"));
2356
    }
2357

    
2358
    PA_LOGL_;
2359
    return result;
2360
}
2361

    
2362
static PaError PinGetBufferWithoutNotification(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier)
2363
{
2364
    PaError result = paNoError;
2365
    KSRTAUDIO_BUFFER_PROPERTY propIn;
2366
    KSRTAUDIO_BUFFER propOut;
2367

    
2368
    PA_LOGE_;
2369

    
2370
    propIn.BaseAddress = NULL;
2371
    propIn.RequestedBufferSize = *pRequestedBufSize;
2372
    propIn.Property.Set = KSPROPSETID_RtAudio;
2373
    propIn.Property.Id = KSPROPERTY_RTAUDIO_BUFFER;
2374
    propIn.Property.Flags = KSPROPERTY_TYPE_GET;
2375

    
2376
    result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
2377
        &propIn,
2378
        sizeof(KSRTAUDIO_BUFFER_PROPERTY),
2379
        &propOut,
2380
        sizeof(KSRTAUDIO_BUFFER),
2381
        NULL);
2382

    
2383
    if (result == paNoError)
2384
    {
2385
        *pBuffer = propOut.BufferAddress;
2386
        *pRequestedBufSize = propOut.ActualBufferSize;
2387
        *pbCallMemBarrier = propOut.CallMemoryBarrier;
2388
    }
2389
    else 
2390
    {
2391
        PA_DEBUG(("Failed to get buffer without notification\n"));
2392
    }
2393

    
2394
    PA_LOGL_;
2395
    return result;
2396
}
2397

    
2398
/* greatest common divisor - PGCD in French */
2399
static unsigned long PaWinWDMGCD( unsigned long a, unsigned long b )
2400
{
2401
    return (b==0) ? a : PaWinWDMGCD( b, a%b);
2402
}
2403

    
2404

    
2405
/* This function will handle getting the cyclic buffer from a WaveRT driver. Certain WaveRT drivers needs to have
2406
requested buffer size on multiples of 128 bytes:
2407

2408
*/
2409
static PaError PinGetBuffer(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier)
2410
{
2411
    PaError result = paNoError;
2412
    int limit = 1000;
2413
    PA_LOGE_;
2414

    
2415
    while (1)
2416
    {
2417
        limit--;
2418
        if (limit == 0) {
2419
           PA_DEBUG(("PinGetBuffer: LOOP LIMIT REACHED\n"));
2420
           break;
2421
        }
2422

    
2423
        if (pPin->pinKsSubType != SubType_kPolled)
2424
        {
2425
            /* In case of unknown (or notification), we try both modes */
2426
            result = PinGetBufferWithNotification(pPin, pBuffer, pRequestedBufSize, pbCallMemBarrier);
2427
            if (result == paNoError)
2428
            {
2429
                PA_DEBUG(("PinGetBuffer: SubType_kNotification\n"));
2430
                pPin->pinKsSubType = SubType_kNotification;
2431
                break;
2432
            }
2433
        }
2434

    
2435
        result = PinGetBufferWithoutNotification(pPin, pBuffer, pRequestedBufSize, pbCallMemBarrier);
2436
        if (result == paNoError)
2437
        {
2438
            PA_DEBUG(("PinGetBuffer: SubType_kPolled\n"));
2439
            pPin->pinKsSubType = SubType_kPolled;
2440
            break;
2441
        }
2442

    
2443
        /* Check if requested size is on a 128 byte boundary */
2444
        if (((*pRequestedBufSize) % 128UL) == 0)
2445
        {
2446
            PA_DEBUG(("Buffer size on 128 byte boundary, still fails :(\n"));
2447
            /* Ok, can't do much more */
2448
            break;
2449
        }
2450
        else
2451
        {
2452
            /* Compute LCM so we know which sizes are on a 128 byte boundary */
2453
            const unsigned gcd = PaWinWDMGCD(128UL, pPin->ksDataFormatWfx->WaveFormatEx.nBlockAlign);
2454
            const unsigned lcm = (128UL * pPin->ksDataFormatWfx->WaveFormatEx.nBlockAlign) / gcd;
2455
            DWORD dwOldSize = *pRequestedBufSize;
2456

    
2457
            /* Align size to (next larger) LCM byte boundary, and then we try again. Note that LCM is not necessarily a
2458
            power of 2. */
2459
            *pRequestedBufSize = ((*pRequestedBufSize + lcm - 1) / lcm) * lcm;
2460

    
2461
            PA_DEBUG(("Adjusting buffer size from %u to %u bytes (128 byte boundary, LCM=%u)\n", dwOldSize, *pRequestedBufSize, lcm));
2462
        }
2463
    }
2464

    
2465
    PA_LOGL_;
2466

    
2467
    return result;
2468
}
2469

    
2470
static PaError PinRegisterPositionRegister(PaWinWdmPin* pPin) 
2471
{
2472
    PaError result = paNoError;
2473
    KSRTAUDIO_HWREGISTER_PROPERTY propIn;
2474
    KSRTAUDIO_HWREGISTER propOut;
2475

    
2476
    PA_LOGE_;
2477

    
2478
    propIn.BaseAddress = NULL;
2479
    propIn.Property.Set = KSPROPSETID_RtAudio;
2480
    propIn.Property.Id = KSPROPERTY_RTAUDIO_POSITIONREGISTER;
2481
    propIn.Property.Flags = KSPROPERTY_TYPE_SET;
2482

    
2483
    result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
2484
        &propIn,
2485
        sizeof(KSRTAUDIO_HWREGISTER_PROPERTY),
2486
        &propOut,
2487
        sizeof(KSRTAUDIO_HWREGISTER),
2488
        NULL);
2489

    
2490
    if (result == paNoError) 
2491
    {
2492
        pPin->positionRegister = (ULONG*)propOut.Register;
2493
    }
2494
    else
2495
    {
2496
        PA_DEBUG(("Failed to register position register\n"));
2497
    }
2498

    
2499
    PA_LOGL_;
2500

    
2501
    return result;
2502
}
2503

    
2504
static PaError PinRegisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle) 
2505
{
2506
    PaError result = paNoError;
2507
    KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY prop;
2508

    
2509
    PA_LOGE_;
2510

    
2511
    prop.NotificationEvent = handle;
2512
    prop.Property.Set = KSPROPSETID_RtAudio;
2513
    prop.Property.Id = KSPROPERTY_RTAUDIO_REGISTER_NOTIFICATION_EVENT;
2514
    prop.Property.Flags = KSPROPERTY_TYPE_SET;
2515

    
2516
    result = WdmSyncIoctl(pPin->handle,
2517
        IOCTL_KS_PROPERTY,
2518
        &prop,
2519
        sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY),
2520
        &prop,
2521
        sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY),
2522
        NULL);
2523

    
2524
    if (result != paNoError) {
2525
        PA_DEBUG(("Failed to register notification handle 0x%08X\n", handle));
2526
    }
2527

    
2528
    PA_LOGL_;
2529

    
2530
    return result;
2531
}
2532

    
2533
static PaError PinUnregisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle) 
2534
{
2535
    PaError result = paNoError;
2536
    KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY prop;
2537

    
2538
    PA_LOGE_;
2539

    
2540
    if (handle != NULL)
2541
    {
2542
        prop.NotificationEvent = handle;
2543
        prop.Property.Set = KSPROPSETID_RtAudio;
2544
        prop.Property.Id = KSPROPERTY_RTAUDIO_UNREGISTER_NOTIFICATION_EVENT;
2545
        prop.Property.Flags = KSPROPERTY_TYPE_SET;
2546

    
2547
        result = WdmSyncIoctl(pPin->handle,
2548
            IOCTL_KS_PROPERTY,
2549
            &prop,
2550
            sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY),
2551
            &prop,
2552
            sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY),
2553
            NULL);
2554

    
2555
        if (result != paNoError) {
2556
            PA_DEBUG(("Failed to unregister notification handle 0x%08X\n", handle));
2557
        }
2558
    }
2559
    PA_LOGL_;
2560

    
2561
    return result;
2562
}
2563

    
2564
static PaError PinGetHwLatency(PaWinWdmPin* pPin, ULONG* pFifoSize, ULONG* pChipsetDelay, ULONG* pCodecDelay)
2565
{
2566
    PaError result = paNoError;
2567
    KSPROPERTY propIn;
2568
    KSRTAUDIO_HWLATENCY propOut;
2569

    
2570
    PA_LOGE_;
2571

    
2572
    propIn.Set = KSPROPSETID_RtAudio;
2573
    propIn.Id = KSPROPERTY_RTAUDIO_HWLATENCY;
2574
    propIn.Flags = KSPROPERTY_TYPE_GET;
2575

    
2576
    result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY,
2577
        &propIn,
2578
        sizeof(KSPROPERTY),
2579
        &propOut,
2580
        sizeof(KSRTAUDIO_HWLATENCY),
2581
        NULL);
2582

    
2583
    if (result == paNoError)
2584
    {
2585
        *pFifoSize = propOut.FifoSize;
2586
        *pChipsetDelay = propOut.ChipsetDelay;
2587
        *pCodecDelay = propOut.CodecDelay;
2588
    }
2589
    else
2590
    {
2591
        PA_DEBUG(("Failed to retrieve hardware FIFO size!\n"));
2592
    }
2593

    
2594
    PA_LOGL_;
2595

    
2596
    return result;
2597
}
2598

    
2599
/* This one is used for WaveRT */
2600
static PaError PinGetAudioPositionMemoryMapped(PaWinWdmPin* pPin, ULONG* pPosition)
2601
{
2602
    *pPosition = (*pPin->positionRegister);
2603
    return paNoError;
2604
}
2605

    
2606
/* This one also, but in case the driver hasn't implemented memory mapped access to the position register */
2607
static PaError PinGetAudioPositionViaIOCTLRead(PaWinWdmPin* pPin, ULONG* pPosition)
2608
{
2609
    PaError result = paNoError;
2610
    KSPROPERTY propIn;
2611
    KSAUDIO_POSITION propOut;
2612

    
2613
    PA_LOGE_;
2614

    
2615
    propIn.Set = KSPROPSETID_Audio;
2616
    propIn.Id = KSPROPERTY_AUDIO_POSITION;
2617
    propIn.Flags = KSPROPERTY_TYPE_GET;
2618

    
2619
    result = WdmSyncIoctl(pPin->handle,
2620
        IOCTL_KS_PROPERTY,
2621
        &propIn, sizeof(KSPROPERTY),
2622
        &propOut, sizeof(KSAUDIO_POSITION),
2623
        NULL);
2624

    
2625
    if (result == paNoError)
2626
    {
2627
        *pPosition = (ULONG)(propOut.PlayOffset);
2628
    }
2629
    else
2630
    {
2631
        PA_DEBUG(("Failed to get audio play position!\n"));
2632
    }
2633

    
2634
    PA_LOGL_;
2635

    
2636
    return result;
2637

    
2638
}
2639

    
2640
/* This one also, but in case the driver hasn't implemented memory mapped access to the position register */
2641
static PaError PinGetAudioPositionViaIOCTLWrite(PaWinWdmPin* pPin, ULONG* pPosition)
2642
{
2643
    PaError result = paNoError;
2644
    KSPROPERTY propIn;
2645
    KSAUDIO_POSITION propOut;
2646

    
2647
    PA_LOGE_;
2648

    
2649
    propIn.Set = KSPROPSETID_Audio;
2650
    propIn.Id = KSPROPERTY_AUDIO_POSITION;
2651
    propIn.Flags = KSPROPERTY_TYPE_GET;
2652

    
2653
    result = WdmSyncIoctl(pPin->handle,
2654
        IOCTL_KS_PROPERTY,
2655
        &propIn, sizeof(KSPROPERTY),
2656
        &propOut, sizeof(KSAUDIO_POSITION),
2657
        NULL);
2658

    
2659
    if (result == paNoError)
2660
    {
2661
        *pPosition = (ULONG)(propOut.WriteOffset);
2662
    }
2663
    else
2664
    {
2665
        PA_DEBUG(("Failed to get audio write position!\n"));
2666
    }
2667

    
2668
    PA_LOGL_;
2669

    
2670
    return result;
2671

    
2672
}
2673

    
2674
/***********************************************************************************************/
2675

    
2676
/**
2677
* Create a new filter object. 
2678
*/
2679
static PaWinWdmFilter* FilterNew( PaWDMKSType type, DWORD devNode, const wchar_t* filterName, const wchar_t* friendlyName, PaError* error )
2680
{
2681
    PaWinWdmFilter* filter = 0;
2682
    PaError result;
2683

    
2684
    /* Allocate the new filter object */
2685
    filter = (PaWinWdmFilter*)PaUtil_AllocateMemory( sizeof(PaWinWdmFilter) );
2686
    if( !filter )
2687
    {
2688
        result = paInsufficientMemory;
2689
        goto error;
2690
    }
2691

    
2692
    PA_DEBUG(("FilterNew: Creating filter '%S'\n", friendlyName));
2693

    
2694
    /* Set type flag */
2695
    filter->devInfo.streamingType = type;
2696

    
2697
    /* Store device node */
2698
    filter->deviceNode = devNode;
2699

    
2700
    /* Zero the filter object - done by AllocateMemory */
2701
    /* memset( (void*)filter, 0, sizeof(PaWinWdmFilter) ); */
2702

    
2703
    /* Copy the filter name */
2704
    wcsncpy(filter->devInfo.filterPath, filterName, MAX_PATH);
2705

    
2706
    /* Copy the friendly name */
2707
    wcsncpy(filter->friendlyName, friendlyName, MAX_PATH);
2708

    
2709
    PA_DEBUG(("FilterNew: Opening filter...\n", friendlyName));
2710

    
2711
    /* Open the filter handle */
2712
    result = FilterUse(filter);
2713
    if( result != paNoError )
2714
    {
2715
        goto error;
2716
    }
2717

    
2718
    /* Get pin count */
2719
    result = WdmGetPinPropertySimple
2720
        (
2721
        filter->handle,
2722
        0,
2723
        &KSPROPSETID_Pin,
2724
        KSPROPERTY_PIN_CTYPES,
2725
        &filter->pinCount,
2726
        sizeof(filter->pinCount),
2727
        NULL);
2728

    
2729
    if( result != paNoError)
2730
    {
2731
        goto error;
2732
    }
2733

    
2734
    /* Get connections & nodes for filter */
2735
    result = WdmGetPropertyMulti(
2736
        filter->handle,
2737
        &KSPROPSETID_Topology,
2738
        KSPROPERTY_TOPOLOGY_CONNECTIONS,
2739
        &filter->connections);
2740

    
2741
    if( result != paNoError)
2742
    {
2743
        goto error;
2744
    }
2745

    
2746
    result = WdmGetPropertyMulti(
2747
        filter->handle,
2748
        &KSPROPSETID_Topology,
2749
        KSPROPERTY_TOPOLOGY_NODES,
2750
        &filter->nodes);
2751

    
2752
    if( result != paNoError)
2753
    {
2754
        goto error;
2755
    }
2756

    
2757
    /* For debugging purposes */
2758
    DumpConnectionsAndNodes(filter);
2759

    
2760
    /* Get product GUID (it might not be supported) */
2761
    {
2762
        KSCOMPONENTID compId;
2763
        if (WdmGetPropertySimple(filter->handle, &KSPROPSETID_General, KSPROPERTY_GENERAL_COMPONENTID, &compId, sizeof(KSCOMPONENTID)) == paNoError)
2764
        {
2765
            filter->devInfo.deviceProductGuid = compId.Product;
2766
        }
2767
    }
2768

    
2769
    /* This section is not executed for topology filters */
2770
    if (type != Type_kNotUsed)
2771
    {
2772
        /* Initialize the pins */
2773
        result = FilterInitializePins(filter);
2774

    
2775
        if( result != paNoError)
2776
        {
2777
            goto error;
2778
        }
2779
    }
2780

    
2781
    /* Close the filter handle for now
2782
    * It will be opened later when needed */
2783
    FilterRelease(filter);
2784

    
2785
    *error = paNoError;
2786
    return filter;
2787

    
2788
error:
2789
    PA_DEBUG(("FilterNew: Error %d\n", result));
2790
    /*
2791
    Error cleanup
2792
    */
2793
    FilterFree(filter);
2794

    
2795
    *error = result;
2796
    return NULL;
2797
}
2798

    
2799
/**
2800
* Add reference to filter
2801
*/
2802
static void FilterAddRef( PaWinWdmFilter* filter )
2803
{
2804
    if (filter != 0)
2805
    {
2806
        filter->filterRefCount++;
2807
    }
2808
}
2809

    
2810

    
2811
/**
2812
* Initialize the pins of the filter. This is separated from FilterNew because this might fail if there is another
2813
* process using the pin(s).
2814
*/
2815
PaError FilterInitializePins( PaWinWdmFilter* filter )
2816
{
2817
    PaError result = paNoError;
2818
    int pinId;
2819

    
2820
    if (filter->devInfo.streamingType == Type_kNotUsed)
2821
        return paNoError;
2822

    
2823
    if (filter->pins != NULL)
2824
        return paNoError;   
2825

    
2826
    /* Allocate pointer array to hold the pins */
2827
    filter->pins = (PaWinWdmPin**)PaUtil_AllocateMemory( sizeof(PaWinWdmPin*) * filter->pinCount );
2828
    if( !filter->pins )
2829
    {
2830
        result = paInsufficientMemory;
2831
        goto error;
2832
    }
2833

    
2834
    /* Create all the pins we can */
2835
    for(pinId = 0; pinId < filter->pinCount; pinId++)
2836
    {
2837
        /* Create the pin with this Id */
2838
        PaWinWdmPin* newPin;
2839
        newPin = PinNew(filter, pinId, &result);
2840
        if( result == paInsufficientMemory )
2841
            goto error;
2842
        if( newPin != NULL )
2843
        {
2844
            filter->pins[pinId] = newPin;
2845
            ++filter->validPinCount;
2846
        }
2847
    }
2848

    
2849
    if (filter->validPinCount == 0)
2850
    {
2851
        result = paDeviceUnavailable;
2852
        goto error;
2853
    }
2854

    
2855
    return paNoError;
2856

    
2857
error:
2858

    
2859
    if (filter->pins)
2860
    {
2861
        for (pinId = 0; pinId < filter->pinCount; ++pinId)
2862
        {
2863
            if (filter->pins[pinId])
2864
            {
2865
                PinFree(filter->pins[pinId]);
2866
                filter->pins[pinId] = 0;
2867
            }
2868
        }
2869
        PaUtil_FreeMemory( filter->pins );
2870
        filter->pins = 0;
2871
    }
2872

    
2873
    return result;
2874
}
2875

    
2876

    
2877
/**
2878
* Free a previously created filter
2879
*/
2880
static void FilterFree(PaWinWdmFilter* filter)
2881
{
2882
    PA_LOGL_;
2883
    if( filter )
2884
    {
2885
        if (--filter->filterRefCount > 0)
2886
        {
2887
            /* Ok, a stream has a ref count to this filter */
2888
            return;
2889
        }
2890

    
2891
        if ( filter->topologyFilter )
2892
        {
2893
            FilterFree(filter->topologyFilter);
2894
            filter->topologyFilter = 0;
2895
        }
2896
        if ( filter->pins )
2897
        {
2898
            int pinId;
2899
            for( pinId = 0; pinId < filter->pinCount; pinId++ )
2900
                PinFree(filter->pins[pinId]);
2901
            PaUtil_FreeMemory( filter->pins );
2902
            filter->pins = 0;
2903
        }
2904
        if( filter->connections )
2905
        {
2906
            PaUtil_FreeMemory(filter->connections);
2907
            filter->connections = 0;
2908
        }
2909
        if( filter->nodes )
2910
        {
2911
            PaUtil_FreeMemory(filter->nodes);
2912
            filter->nodes = 0;
2913
        }
2914
        if( filter->handle )
2915
            CloseHandle( filter->handle );
2916
        PaUtil_FreeMemory( filter );
2917
    }
2918
    PA_LOGE_;
2919
}
2920

    
2921
/**
2922
* Reopen the filter handle if necessary so it can be used
2923
**/
2924
static PaError FilterUse(PaWinWdmFilter* filter)
2925
{
2926
    assert( filter );
2927

    
2928
    PA_LOGE_;
2929
    if( filter->handle == NULL )
2930
    {
2931
        /* Open the filter */
2932
        filter->handle = CreateFileW(
2933
            filter->devInfo.filterPath,
2934
            GENERIC_READ | GENERIC_WRITE,
2935
            0,
2936
            NULL,
2937
            OPEN_EXISTING,
2938
            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
2939
            NULL);
2940

    
2941
        if( filter->handle == NULL )
2942
        {
2943
            return paDeviceUnavailable;
2944
        }
2945
    }
2946
    filter->usageCount++;
2947
    PA_LOGL_;
2948
    return paNoError;
2949
}
2950

    
2951
/**
2952
* Release the filter handle if nobody is using it
2953
**/
2954
static void FilterRelease(PaWinWdmFilter* filter)
2955
{
2956
    assert( filter );
2957
    assert( filter->usageCount > 0 );
2958

    
2959
    PA_LOGE_;
2960
    /* Check first topology filter, if used */
2961
    if (filter->topologyFilter != NULL && filter->topologyFilter->handle != NULL)
2962
    {
2963
        FilterRelease(filter->topologyFilter);
2964
    }
2965

    
2966
    filter->usageCount--;
2967
    if( filter->usageCount == 0 )
2968
    {
2969
        if( filter->handle != NULL )
2970
        {
2971
            CloseHandle( filter->handle );
2972
            filter->handle = NULL;
2973
        }
2974
    }
2975
    PA_LOGL_;
2976
}
2977

    
2978
/**
2979
* Create a render or playback pin using the supplied format
2980
**/
2981
static PaWinWdmPin* FilterCreatePin(PaWinWdmFilter* filter,
2982
                                    int pinId,
2983
                                    const WAVEFORMATEX* wfex,
2984
                                    PaError* error)
2985
{
2986
    PaError result = paNoError;
2987
    PaWinWdmPin* pin = NULL;
2988
    assert( filter );
2989
    assert( pinId < filter->pinCount );
2990
    pin = filter->pins[pinId];
2991
    assert( pin );
2992
    result = PinSetFormat(pin,wfex);
2993
    if( result == paNoError )
2994
    {
2995
        result = PinInstantiate(pin);
2996
    }
2997
    *error = result;
2998
    return result == paNoError ? pin : 0;
2999
}
3000

    
3001
static const wchar_t kUsbPrefix[] = L"\\\\?\\USB";
3002

    
3003
static BOOL IsUSBDevice(const wchar_t* devicePath)
3004
{
3005
    /* Alex Lessard pointed out that different devices might present the device path with
3006
       lower case letters. */
3007
    return (_wcsnicmp(devicePath, kUsbPrefix, sizeof(kUsbPrefix)/sizeof(kUsbPrefix[0]) ) == 0);
3008
}
3009

    
3010
/* This should make it more language tolerant, I hope... */
3011
static const wchar_t kUsbNamePrefix[] = L"USB Audio";
3012

    
3013
static BOOL IsNameUSBAudioDevice(const wchar_t* friendlyName)
3014
{
3015
    return (_wcsnicmp(friendlyName, kUsbNamePrefix, sizeof(kUsbNamePrefix)/sizeof(kUsbNamePrefix[0])) == 0);
3016
}
3017

    
3018
typedef enum _tag_EAlias
3019
{
3020
    Alias_kRender   = (1<<0),
3021
    Alias_kCapture  = (1<<1),
3022
    Alias_kRealtime = (1<<2),
3023
} EAlias;
3024

    
3025
/* Trim whitespace from string */
3026
static void TrimString(wchar_t* str, size_t length)
3027
{
3028
    wchar_t* s = str;
3029
    wchar_t* e = 0;
3030

    
3031
    /* Find start of string */
3032
    while (iswspace(*s)) ++s;
3033
    e=s+min(length,wcslen(s))-1;
3034

    
3035
    /* Find end of string */
3036
    while(e>s && iswspace(*e)) --e;
3037
    ++e;
3038

    
3039
    length = e - s;
3040
    memmove(str, s, length * sizeof(wchar_t));
3041
    str[length] = 0;
3042
}
3043

    
3044
/**
3045
* Build the list of available filters
3046
* Use the SetupDi API to enumerate all devices in the KSCATEGORY_AUDIO which 
3047
* have a KSCATEGORY_RENDER or KSCATEGORY_CAPTURE alias. For each of these 
3048
* devices initialise a PaWinWdmFilter structure by calling our NewFilter() 
3049
* function. We enumerate devices twice, once to count how many there are, 
3050
* and once to initialize the PaWinWdmFilter structures.
3051
*
3052
* Vista and later: Also check KSCATEGORY_REALTIME for WaveRT devices.
3053
*/
3054
//PaError BuildFilterList( PaWinWdmHostApiRepresentation* wdmHostApi, int* noOfPaDevices )
3055
PaWinWdmFilter** BuildFilterList( int* pFilterCount, int* pNoOfPaDevices, PaError* pResult )
3056
{
3057
    PaWinWdmFilter** ppFilters = NULL;
3058
    HDEVINFO handle = NULL;
3059
    int device;
3060
    int invalidDevices;
3061
    int slot;
3062
    SP_DEVICE_INTERFACE_DATA interfaceData;
3063
    SP_DEVICE_INTERFACE_DATA aliasData;
3064
    SP_DEVINFO_DATA devInfoData;
3065
    int noError;
3066
    const int sizeInterface = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR));
3067
    unsigned char interfaceDetailsArray[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR))];
3068
    SP_DEVICE_INTERFACE_DETAIL_DATA_W* devInterfaceDetails = (SP_DEVICE_INTERFACE_DETAIL_DATA_W*)interfaceDetailsArray;
3069
    const GUID* category = (const GUID*)&KSCATEGORY_AUDIO;
3070
    const GUID* alias_render = (const GUID*)&KSCATEGORY_RENDER;
3071
    const GUID* alias_capture = (const GUID*)&KSCATEGORY_CAPTURE;
3072
    const GUID* category_realtime = (const GUID*)&KSCATEGORY_REALTIME;
3073
    DWORD aliasFlags;
3074
    PaWDMKSType streamingType;
3075
    int filterCount = 0;
3076
    int noOfPaDevices = 0;
3077

    
3078
    PA_LOGE_;
3079

    
3080
    assert(pFilterCount != NULL);
3081
    assert(pNoOfPaDevices != NULL);
3082
    assert(pResult != NULL);
3083

    
3084
    devInterfaceDetails->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
3085
    *pFilterCount = 0;
3086
    *pNoOfPaDevices = 0;
3087

    
3088
    /* Open a handle to search for devices (filters) */
3089
    handle = SetupDiGetClassDevs(category,NULL,NULL,DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
3090
    if( handle == INVALID_HANDLE_VALUE )
3091
    {
3092
        *pResult = paUnanticipatedHostError;
3093
        return NULL;
3094
    }
3095
    PA_DEBUG(("Setup called\n"));
3096

    
3097
    /* First let's count the number of devices so we can allocate a list */
3098
    invalidDevices = 0;
3099
    for( device = 0;;device++ )
3100
    {
3101
        interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
3102
        interfaceData.Reserved = 0;
3103
        aliasData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
3104
        aliasData.Reserved = 0;
3105
        noError = SetupDiEnumDeviceInterfaces(handle,NULL,category,device,&interfaceData);
3106
        PA_DEBUG(("Enum called\n"));
3107
        if( !noError )
3108
            break; /* No more devices */
3109

    
3110
        /* Check this one has the render or capture alias */
3111
        aliasFlags = 0;
3112
        noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_render,&aliasData);
3113
        PA_DEBUG(("noError = %d\n",noError));
3114
        if(noError)
3115
        {
3116
            if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
3117
            {
3118
                PA_DEBUG(("Device %d has render alias\n",device));
3119
                aliasFlags |= Alias_kRender; /* Has render alias */
3120
            }
3121
            else
3122
            {
3123
                PA_DEBUG(("Device %d has no render alias\n",device));
3124
            }
3125
        }
3126
        noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_capture,&aliasData);
3127
        if(noError)
3128
        {
3129
            if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
3130
            {
3131
                PA_DEBUG(("Device %d has capture alias\n",device));
3132
                aliasFlags |= Alias_kCapture; /* Has capture alias */
3133
            }
3134
            else
3135
            {
3136
                PA_DEBUG(("Device %d has no capture alias\n",device));
3137
            }
3138
        }
3139
        if(!aliasFlags)
3140
            invalidDevices++; /* This was not a valid capture or render audio device */
3141
    }
3142
    /* Remember how many there are */
3143
    filterCount = device-invalidDevices;
3144

    
3145
    PA_DEBUG(("Interfaces found: %d\n",device-invalidDevices));
3146

    
3147
    /* Now allocate the list of pointers to devices */
3148
    ppFilters  = (PaWinWdmFilter**)PaUtil_AllocateMemory( sizeof(PaWinWdmFilter*) * filterCount);
3149
    if( ppFilters == 0 )
3150
    {
3151
        if(handle != NULL)
3152
            SetupDiDestroyDeviceInfoList(handle);
3153
        *pResult = paInsufficientMemory;
3154
        return NULL;
3155
    }
3156

    
3157
    /* Now create filter objects for each interface found */
3158
    slot = 0;
3159
    for( device = 0;;device++ )
3160
    {
3161
        interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
3162
        interfaceData.Reserved = 0;
3163
        aliasData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
3164
        aliasData.Reserved = 0;
3165
        devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
3166
        devInfoData.Reserved = 0;
3167
        streamingType = Type_kWaveCyclic;
3168

    
3169
        noError = SetupDiEnumDeviceInterfaces(handle,NULL,category,device,&interfaceData);
3170
        if( !noError )
3171
            break; /* No more devices */
3172

    
3173
        /* Check this one has the render or capture alias */
3174
        aliasFlags = 0;
3175
        noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_render,&aliasData);
3176
        if(noError)
3177
        {
3178
            if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
3179
            {
3180
                PA_DEBUG(("Device %d has render alias\n",device));
3181
                aliasFlags |= Alias_kRender; /* Has render alias */
3182
            }
3183
        }
3184
        noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_capture,&aliasData);
3185
        if(noError)
3186
        {
3187
            if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
3188
            {
3189
                PA_DEBUG(("Device %d has capture alias\n",device));
3190
                aliasFlags |= Alias_kCapture; /* Has capture alias */
3191
            }
3192
        }
3193
        if(!aliasFlags)
3194
        {
3195
            continue; /* This was not a valid capture or render audio device */
3196
        }
3197
        else
3198
        {
3199
            /* Check if filter is WaveRT, if not it is a WaveCyclic */
3200
            noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,category_realtime,&aliasData);
3201
            if (noError)
3202
            {
3203
                PA_DEBUG(("Device %d has realtime alias\n",device));
3204
                aliasFlags |= Alias_kRealtime;
3205
                streamingType = Type_kWaveRT;
3206
            }
3207
        }
3208

    
3209
        noError = SetupDiGetDeviceInterfaceDetailW(handle,&interfaceData,devInterfaceDetails,sizeInterface,NULL,&devInfoData);
3210
        if( noError )
3211
        {
3212
            DWORD type;
3213
            WCHAR friendlyName[MAX_PATH] = {0};
3214
            DWORD sizeFriendlyName;
3215
            PaWinWdmFilter* newFilter = 0;
3216

    
3217
            PaError result = paNoError;
3218
            /* Try to get the "friendly name" for this interface */
3219
            sizeFriendlyName = sizeof(friendlyName);
3220

    
3221
            if (IsEarlierThanVista() && IsUSBDevice(devInterfaceDetails->DevicePath))
3222
            {
3223
                /* XP and USB audio device needs to look elsewhere, otherwise it'll only be a "USB Audio Device". Not
3224
                very literate. */
3225
                if (!SetupDiGetDeviceRegistryPropertyW(handle,
3226
                    &devInfoData,
3227
                    SPDRP_LOCATION_INFORMATION, 
3228
                    &type,
3229
                    (BYTE*)friendlyName,
3230
                    sizeof(friendlyName),
3231
                    NULL))
3232
                {
3233
                    friendlyName[0] = 0;
3234
                }
3235
            }
3236

    
3237
            if (friendlyName[0] == 0 || IsNameUSBAudioDevice(friendlyName))
3238
            {
3239
                /* Fix contributed by Ben Allison
3240
                * Removed KEY_SET_VALUE from flags on following call
3241
                * as its causes failure when running without admin rights
3242
                * and it was not required */
3243
                HKEY hkey=SetupDiOpenDeviceInterfaceRegKey(handle,&interfaceData,0,KEY_QUERY_VALUE);
3244
                if(hkey!=INVALID_HANDLE_VALUE)
3245
                {
3246
                    noError = RegQueryValueExW(hkey,L"FriendlyName",0,&type,(BYTE*)friendlyName,&sizeFriendlyName);
3247
                    if( noError == ERROR_SUCCESS )
3248
                    {
3249
                        PA_DEBUG(("Interface %d, Name: %s\n",device,friendlyName));
3250
                        RegCloseKey(hkey);
3251
                    }
3252
                    else
3253
                    {
3254
                        friendlyName[0] = 0;
3255
                    }
3256
                }
3257
            }
3258

    
3259
            TrimString(friendlyName, sizeFriendlyName);
3260

    
3261
            newFilter = FilterNew(streamingType, 
3262
                devInfoData.DevInst,
3263
                devInterfaceDetails->DevicePath,
3264
                friendlyName,
3265
                &result);
3266

    
3267
            if( result == paNoError )
3268
            {
3269
                int pin;
3270
                unsigned filterIOs = 0;
3271

    
3272
                /* Increment number of "devices" */
3273
                for (pin = 0; pin < newFilter->pinCount; ++pin)
3274
                {
3275
                    PaWinWdmPin* pPin = newFilter->pins[pin];
3276
                    if (pPin == NULL)
3277
                        continue;
3278

    
3279
                    filterIOs += max(1, pPin->inputCount);
3280
                }
3281

    
3282
                noOfPaDevices += filterIOs;
3283

    
3284
                PA_DEBUG(("Filter (%s) created with %d valid pins (total I/Os: %u)\n", ((newFilter->devInfo.streamingType==Type_kWaveRT)?"WaveRT":"WaveCyclic"), newFilter->validPinCount, filterIOs));
3285

    
3286
                assert(slot < filterCount);
3287

    
3288
                ppFilters[slot] = newFilter;
3289

    
3290
                slot++;
3291
            }
3292
            else
3293
            {
3294
                PA_DEBUG(("Filter NOT created\n"));
3295
                /* As there are now less filters than we initially thought
3296
                * we must reduce the count by one */
3297
                filterCount--;
3298
            }
3299
        }
3300
    }
3301

    
3302
    /* Clean up */
3303
    if(handle != NULL)
3304
        SetupDiDestroyDeviceInfoList(handle);
3305

    
3306
    *pFilterCount = filterCount;
3307
    *pNoOfPaDevices = noOfPaDevices;
3308

    
3309
    return ppFilters;
3310
}
3311

    
3312
typedef struct PaNameHashIndex
3313
{
3314
    unsigned index;
3315
    unsigned count;
3316
    ULONG    hash;
3317
    struct PaNameHashIndex *next;
3318
} PaNameHashIndex;
3319

    
3320
typedef struct PaNameHashObject
3321
{
3322
    PaNameHashIndex* list;
3323
    PaUtilAllocationGroup* allocGroup;
3324
} PaNameHashObject;
3325

    
3326
static ULONG GetNameHash(const wchar_t* str, const BOOL input)
3327
{
3328
    /* This is to make sure that a name that exists as both input & output won't get the same hash value */
3329
    const ULONG fnv_prime = (input ? 0x811C9DD7 : 0x811FEB0B);
3330
    ULONG hash = 0;
3331
    for(; *str != 0; str++)
3332
    {
3333
        hash *= fnv_prime;
3334
        hash ^= (*str);
3335
    }
3336
    assert(hash != 0);
3337
    return hash;
3338
}
3339

    
3340
static PaError CreateHashEntry(PaNameHashObject* obj, const wchar_t* name, const BOOL input)
3341
{
3342
    ULONG hash = GetNameHash(name, input); 
3343
    PaNameHashIndex * pLast = NULL;
3344
    PaNameHashIndex * p = obj->list;
3345
    while (p != 0)
3346
    {
3347
        if (p->hash == hash)
3348
        {
3349
            break;
3350
        }
3351
        pLast = p;
3352
        p = p->next;
3353
    }
3354
    if (p == NULL)
3355
    {
3356
        p = (PaNameHashIndex*)PaUtil_GroupAllocateMemory(obj->allocGroup, sizeof(PaNameHashIndex));
3357
        if (p == NULL)
3358
        {
3359
            return paInsufficientMemory;
3360
        }
3361
        p->hash = hash;
3362
        p->count = 1;
3363
        if (pLast != 0)
3364
        {
3365
            assert(pLast->next == 0);
3366
            pLast->next = p;
3367
        }
3368
        if (obj->list == 0)
3369
        {
3370
            obj->list = p;
3371
        }
3372
    }
3373
    else
3374
    {
3375
        ++p->count;
3376
    }
3377
    return paNoError;
3378
}
3379

    
3380
static PaError InitNameHashObject(PaNameHashObject* obj, PaWinWdmFilter* pFilter)
3381
{
3382
    int i;
3383

    
3384
    obj->allocGroup = PaUtil_CreateAllocationGroup();
3385
    if (obj->allocGroup == NULL)
3386
    {
3387
        return paInsufficientMemory;
3388
    }
3389

    
3390
    for (i = 0; i < pFilter->pinCount; ++i)
3391
    {
3392
        unsigned m;
3393
        PaWinWdmPin* pin = pFilter->pins[i];
3394

    
3395
        if (pin == NULL)
3396
            continue;
3397

    
3398
        for (m = 0; m < max(1, pin->inputCount); ++m)
3399
        {
3400
            const BOOL isInput = (pin->dataFlow == KSPIN_DATAFLOW_OUT);
3401
            const wchar_t* name = (pin->inputs == NULL) ? pin->friendlyName : pin->inputs[m]->friendlyName;
3402

    
3403
            PaError result = CreateHashEntry(obj, name, isInput);
3404

    
3405
            if (result != paNoError)
3406
            {
3407
                return result;
3408
            }
3409
        }
3410
    }
3411
    return paNoError;
3412
}
3413

    
3414
static void DeinitNameHashObject(PaNameHashObject* obj)
3415
{
3416
    assert(obj != 0);
3417
    PaUtil_FreeAllAllocations(obj->allocGroup);
3418
    PaUtil_DestroyAllocationGroup(obj->allocGroup);
3419
    memset(obj, 0, sizeof(PaNameHashObject));
3420
}
3421

    
3422
static unsigned GetNameIndex(PaNameHashObject* obj, const wchar_t* name, const BOOL input)
3423
{
3424
    ULONG hash = GetNameHash(name, input); 
3425
    PaNameHashIndex* p = obj->list;
3426
    while (p != NULL)
3427
    {
3428
        if (p->hash == hash)
3429
        {
3430
            if (p->count > 1)
3431
            {
3432
                return (++p->index);
3433
            }
3434
            else
3435
            {
3436
                return 0;
3437
            }
3438
        }
3439

    
3440
        p = p->next;
3441
    }
3442
    // Should never get here!!
3443
    assert(FALSE);
3444
    return 0;
3445
}
3446

    
3447
static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex, void **scanResults, int *newDeviceCount )
3448
{
3449
    PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
3450
    PaError result = paNoError;
3451
    PaWinWdmFilter** ppFilters = 0;
3452
    PaWinWDMScanDeviceInfosResults *outArgument = 0;
3453
    int filterCount = 0;
3454
    int totalDeviceCount = 0;
3455
    int idxDevice = 0;
3456
    DWORD defaultInDevPathSize = 0;
3457
    DWORD defaultOutDevPathSize = 0;
3458
    wchar_t* defaultInDevPath = 0;
3459
    wchar_t* defaultOutDevPath = 0;
3460

    
3461
    ppFilters = BuildFilterList( &filterCount, &totalDeviceCount, &result );
3462
    if( result != paNoError )
3463
    {
3464
        goto error;
3465
    }
3466

    
3467
    // Get hold of default device paths for capture & playback
3468
    if( waveInMessage(0, DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&defaultInDevPathSize, 0 ) == MMSYSERR_NOERROR )
3469
    {
3470
        defaultInDevPath = (wchar_t *)PaUtil_AllocateMemory((defaultInDevPathSize + 1) * sizeof(wchar_t));
3471
        waveInMessage(0, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)defaultInDevPath, defaultInDevPathSize);
3472
    }
3473
    if( waveOutMessage(0, DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&defaultOutDevPathSize, 0 ) == MMSYSERR_NOERROR )
3474
    {
3475
        defaultOutDevPath = (wchar_t *)PaUtil_AllocateMemory((defaultOutDevPathSize + 1) * sizeof(wchar_t));
3476
        waveOutMessage(0, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)defaultOutDevPath, defaultOutDevPathSize);
3477
    }
3478

    
3479
    if( totalDeviceCount > 0 )
3480
    {
3481
        PaWinWdmDeviceInfo *deviceInfoArray = 0;
3482
        int idxFilter;
3483
        int i;
3484
        unsigned devIsDefaultIn = 0, devIsDefaultOut = 0;
3485

    
3486
        /* Allocate the out param for all the info we need */
3487
        outArgument = (PaWinWDMScanDeviceInfosResults *) PaUtil_GroupAllocateMemory(
3488
            wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults) );
3489
        if( !outArgument )
3490
        {
3491
            result = paInsufficientMemory;
3492
            goto error;
3493
        }
3494

    
3495
        outArgument->defaultInputDevice  = paNoDevice;
3496
        outArgument->defaultOutputDevice = paNoDevice;
3497

    
3498
        outArgument->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
3499
            wdmHostApi->allocations, sizeof(PaDeviceInfo*) * totalDeviceCount );
3500
        if( !outArgument->deviceInfos )
3501
        {
3502
            result = paInsufficientMemory;
3503
            goto error;
3504
        }
3505

    
3506
        /* allocate all device info structs in a contiguous block */
3507
        deviceInfoArray = (PaWinWdmDeviceInfo*)PaUtil_GroupAllocateMemory(
3508
            wdmHostApi->allocations, sizeof(PaWinWdmDeviceInfo) * totalDeviceCount );
3509
        if( !deviceInfoArray )
3510
        {
3511
            result = paInsufficientMemory;
3512
            goto error;
3513
        }
3514

    
3515
        /* Make sure all items in array */
3516
        for( i = 0 ; i < totalDeviceCount; ++i )
3517
        {
3518
            PaDeviceInfo *deviceInfo  = &deviceInfoArray[i].inheritedDeviceInfo;
3519
            deviceInfo->structVersion = 2;
3520
            deviceInfo->hostApi       = hostApiIndex;
3521
            deviceInfo->name          = 0;
3522
            outArgument->deviceInfos[ i ] = deviceInfo;
3523
        }
3524

    
3525
        idxDevice = 0;
3526
        for (idxFilter = 0; idxFilter < filterCount; ++idxFilter)
3527
        {
3528
            PaNameHashObject nameHash = {0};
3529
            PaWinWdmFilter* pFilter = ppFilters[idxFilter];
3530
            if( pFilter == NULL )
3531
                continue;
3532

    
3533
            if (InitNameHashObject(&nameHash, pFilter) != paNoError)
3534
            {
3535
                DeinitNameHashObject(&nameHash);
3536
                continue;
3537
            }
3538

    
3539
            devIsDefaultIn = (defaultInDevPath && (_wcsicmp(pFilter->devInfo.filterPath, defaultInDevPath) == 0));
3540
            devIsDefaultOut = (defaultOutDevPath && (_wcsicmp(pFilter->devInfo.filterPath, defaultOutDevPath) == 0));
3541

    
3542
            for (i = 0; i < pFilter->pinCount; ++i)
3543
            {
3544
                unsigned m;
3545
                ULONG nameIndex = 0;
3546
                ULONG nameIndexHash = 0;
3547
                PaWinWdmPin* pin = pFilter->pins[i];
3548

    
3549
                if (pin == NULL)
3550
                    continue;
3551

    
3552
                for (m = 0; m < max(1, pin->inputCount); ++m)
3553
                {
3554
                    PaWinWdmDeviceInfo *wdmDeviceInfo = (PaWinWdmDeviceInfo *)outArgument->deviceInfos[idxDevice];
3555
                    PaDeviceInfo *deviceInfo = &wdmDeviceInfo->inheritedDeviceInfo;
3556
                    wchar_t localCompositeName[MAX_PATH];
3557
                    unsigned nameIndex = 0;
3558
                    const BOOL isInput = (pin->dataFlow == KSPIN_DATAFLOW_OUT);
3559

    
3560
                    wdmDeviceInfo->filter = pFilter;
3561

    
3562
                    deviceInfo->structVersion = 2;
3563
                    deviceInfo->hostApi = hostApiIndex;
3564
                    deviceInfo->name = wdmDeviceInfo->compositeName;
3565
                    /* deviceInfo->hostApiSpecificDeviceInfo = &pFilter->devInfo; */
3566

    
3567
                    wdmDeviceInfo->pin = pin->pinId;
3568

    
3569
                    /* Get the name of the "device" */
3570
                    if (pin->inputs == NULL)
3571
                    {
3572
                        wcsncpy(localCompositeName, pin->friendlyName, MAX_PATH);
3573
                        wdmDeviceInfo->muxPosition = -1;
3574
                        wdmDeviceInfo->endpointPinId = pin->endpointPinId;
3575
                    }
3576
                    else
3577
                    {
3578
                        PaWinWdmMuxedInput* input = pin->inputs[m];
3579
                        wcsncpy(localCompositeName, input->friendlyName, MAX_PATH);
3580
                        wdmDeviceInfo->muxPosition = (int)m;
3581
                        wdmDeviceInfo->endpointPinId = input->endpointPinId;
3582
                    }
3583

    
3584
                    {
3585
                        /* Get base length */
3586
                        size_t n = wcslen(localCompositeName);
3587

    
3588
                        /* Check if there are more entries with same name (which might very well be the case), if there
3589
                        are, the name will be postfixed with an index. */
3590
                        nameIndex = GetNameIndex(&nameHash, localCompositeName, isInput);
3591
                        if (nameIndex > 0)
3592
                        {
3593
                            /* This name has multiple instances, so we post fix with a number */
3594
                            n += _snwprintf(localCompositeName + n, MAX_PATH - n, L" %u", nameIndex);
3595
                        }
3596
                        /* Postfix with filter name */
3597
                        _snwprintf(localCompositeName + n, MAX_PATH - n, L" (%s)", pFilter->friendlyName);
3598
                    }
3599

    
3600
                    /* Convert wide char string to utf-8 */
3601
                    WideCharToMultiByte(CP_UTF8, 0, localCompositeName, -1, wdmDeviceInfo->compositeName, MAX_PATH, NULL, NULL);
3602

    
3603
                    /* NB! WDM/KS has no concept of a full-duplex device, each pin is either an input or an output */
3604
                    if (isInput)
3605
                    {
3606
                        /* INPUT ! */
3607
                        deviceInfo->maxInputChannels  = pin->maxChannels;
3608
                        deviceInfo->maxOutputChannels = 0;
3609

    
3610
                        /* RoBi NB: Due to the fact that input audio endpoints in Vista (& later OSs) can be the same device, but with
3611
                           different input mux settings, there might be a discrepancy between the default input device chosen, and
3612
                           that which will be used by Portaudio. Not much to do about that unfortunately.
3613
                        */
3614
                        if ((defaultInDevPath == 0 || devIsDefaultIn) &&
3615
                             outArgument->defaultInputDevice == paNoDevice)
3616
                        {
3617
                            outArgument->defaultInputDevice = idxDevice;
3618
                        }
3619
                    }
3620
                    else
3621
                    {
3622
                        /* OUTPUT ! */
3623
                        deviceInfo->maxInputChannels  = 0;
3624
                        deviceInfo->maxOutputChannels = pin->maxChannels;
3625

    
3626
                        if ((defaultOutDevPath == 0 || devIsDefaultOut) &&
3627
                            outArgument->defaultOutputDevice == paNoDevice)
3628
                        {
3629
                            outArgument->defaultOutputDevice = idxDevice;
3630
                        }
3631
                    }
3632

    
3633
                    /* These low values are not very useful because
3634
                    * a) The lowest latency we end up with can depend on many factors such
3635
                    *    as the device buffer sizes/granularities, sample rate, channels and format
3636
                    * b) We cannot know the device buffer sizes until we try to open/use it at
3637
                    *    a particular setting
3638
                    * So: we give 512x48000Hz frames as the default low input latency
3639
                    **/
3640
                    switch (pFilter->devInfo.streamingType)
3641
                    {
3642
                    case Type_kWaveCyclic:
3643
                        if (IsEarlierThanVista())
3644
                        {
3645
                            /* XP doesn't tolerate low latency, unless the Process Priority Class is set to REALTIME_PRIORITY_CLASS 
3646
                            through SetPriorityClass, then 10 ms is quite feasible. However, one should then bear in mind that ALL of
3647
                            the process is running in REALTIME_PRIORITY_CLASS, which might not be appropriate for an application with
3648
                            a GUI . In this case it is advisable to separate the audio engine in another process and use IPC to communicate
3649
                            with it. */
3650
                            deviceInfo->defaultLowInputLatency = 0.02;
3651
                            deviceInfo->defaultLowOutputLatency = 0.02;
3652
                        }
3653
                        else
3654
                        {
3655
                            /* This is a conservative estimate. Most WaveCyclic drivers will limit the available latency, but f.i. my Edirol
3656
                            PCR-A30 can reach 3 ms latency easily... */
3657
                            deviceInfo->defaultLowInputLatency = 0.01;
3658
                            deviceInfo->defaultLowOutputLatency = 0.01;
3659
                        }
3660
                        deviceInfo->defaultHighInputLatency = (4096.0/48000.0);
3661
                        deviceInfo->defaultHighOutputLatency = (4096.0/48000.0);
3662
                        deviceInfo->defaultSampleRate = (double)(pin->defaultSampleRate);
3663
                        break;
3664
                    case Type_kWaveRT:
3665
                        /* This is also a conservative estimate, based on WaveRT polled mode. In polled mode, the latency will be dictated
3666
                        by the buffer size given by the driver. */
3667
                        deviceInfo->defaultLowInputLatency = 0.01;
3668
                        deviceInfo->defaultLowOutputLatency = 0.01;
3669
                        deviceInfo->defaultHighInputLatency = 0.04;
3670
                        deviceInfo->defaultHighOutputLatency = 0.04;
3671
                        deviceInfo->defaultSampleRate = (double)(pin->defaultSampleRate);
3672
                        break;
3673
                    default:
3674
                        assert(0);
3675
                        break;
3676
                    }
3677

    
3678
                    /* Add reference to filter */
3679
                    FilterAddRef(wdmDeviceInfo->filter);
3680

    
3681
                    assert(idxDevice < totalDeviceCount);
3682
                    ++idxDevice;
3683
                }
3684
            }
3685

    
3686
            /* If no one has add ref'd the filter, drop it */
3687
            if (pFilter->filterRefCount == 0)
3688
            {
3689
                FilterFree(pFilter);
3690
            }
3691

    
3692
            /* Deinitialize name hash object */
3693
            DeinitNameHashObject(&nameHash);
3694
        }
3695
    }
3696

    
3697
    *scanResults = outArgument;
3698
    *newDeviceCount = idxDevice;
3699
    return result;
3700

    
3701
error:
3702
    result = DisposeDeviceInfos(hostApi, outArgument, totalDeviceCount);
3703

    
3704
    return result;
3705
}
3706

    
3707
static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *scanResults, int deviceCount )
3708
{
3709
    PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
3710

    
3711
    hostApi->info.deviceCount = 0;
3712
    hostApi->info.defaultInputDevice = paNoDevice;
3713
    hostApi->info.defaultOutputDevice = paNoDevice;
3714

    
3715
    /* Free any old memory which might be in the device info */
3716
    if( hostApi->deviceInfos )
3717
    {
3718
        PaWinWDMScanDeviceInfosResults* localScanResults = (PaWinWDMScanDeviceInfosResults*)PaUtil_GroupAllocateMemory(
3719
            wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults));
3720
        localScanResults->deviceInfos = hostApi->deviceInfos;
3721

    
3722
        DisposeDeviceInfos(hostApi, &localScanResults, hostApi->info.deviceCount);
3723

    
3724
        hostApi->deviceInfos = NULL;
3725
    }
3726

    
3727
    if( scanResults != NULL )
3728
    {
3729
        PaWinWDMScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinWDMScanDeviceInfosResults * ) scanResults;
3730

    
3731
        if( deviceCount > 0 )
3732
        {
3733
            /* use the array allocated in ScanDeviceInfos() as our deviceInfos */
3734
            hostApi->deviceInfos = scanDeviceInfosResults->deviceInfos;
3735

    
3736
            hostApi->info.defaultInputDevice = scanDeviceInfosResults->defaultInputDevice;
3737
            hostApi->info.defaultOutputDevice = scanDeviceInfosResults->defaultOutputDevice;
3738

    
3739
            hostApi->info.deviceCount = deviceCount;
3740
        }
3741

    
3742
        PaUtil_GroupFreeMemory( wdmHostApi->allocations, scanDeviceInfosResults );
3743
    }
3744

    
3745
    return paNoError;
3746

    
3747
}
3748

    
3749
static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *scanResults, int deviceCount )
3750
{
3751
    PaWinWdmHostApiRepresentation *winDsHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
3752

    
3753
    if( scanResults != NULL )
3754
    {
3755
        PaWinWDMScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinWDMScanDeviceInfosResults * ) scanResults;
3756

    
3757
        if( scanDeviceInfosResults->deviceInfos )
3758
        {
3759
            int i;
3760
            for (i = 0; i < deviceCount; ++i)
3761
            {
3762
                PaWinWdmDeviceInfo* pDevice = (PaWinWdmDeviceInfo*)scanDeviceInfosResults->deviceInfos[i];
3763
                if (pDevice->filter != 0)
3764
                {
3765
                    FilterFree(pDevice->filter);
3766
                }
3767
            }
3768

    
3769
            PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults->deviceInfos[0] ); /* all device info structs are allocated in a block so we can destroy them here */
3770
            PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults->deviceInfos );
3771
        }
3772

    
3773
        PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults );
3774
    }
3775

    
3776
    return paNoError;
3777

    
3778
}
3779

    
3780
PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
3781
{
3782
    PaError result = paNoError;
3783
    int deviceCount = 0;
3784
    void *scanResults = 0;
3785
    PaWinWdmHostApiRepresentation *wdmHostApi = NULL;
3786

    
3787
    PA_LOGE_;
3788

    
3789
#ifdef PA_WDMKS_SET_TREF
3790
    tRef = PaUtil_GetTime();
3791
#endif
3792

    
3793
    /*
3794
    Attempt to load the KSUSER.DLL without which we cannot create pins
3795
    We will unload this on termination
3796
    */
3797
    if(DllKsUser == NULL)
3798
    {
3799
        DllKsUser = LoadLibrary(TEXT("ksuser.dll"));
3800
        if(DllKsUser == NULL)
3801
            goto error;
3802
    }
3803
    FunctionKsCreatePin = (KSCREATEPIN*)GetProcAddress(DllKsUser, "KsCreatePin");
3804
    if(FunctionKsCreatePin == NULL)
3805
        goto error;
3806

    
3807
    /* Attempt to load AVRT.DLL, if we can't, then we'll just use time critical prio instead... */
3808
    if(paWinWDMKSAvRtEntryPoints.hInstance == NULL)
3809
    {
3810
        paWinWDMKSAvRtEntryPoints.hInstance = LoadLibrary(TEXT("avrt.dll"));
3811
        if (paWinWDMKSAvRtEntryPoints.hInstance != NULL)
3812
        {
3813
            paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics =
3814
                (HANDLE(WINAPI*)(LPCSTR,LPDWORD))GetProcAddress(paWinWDMKSAvRtEntryPoints.hInstance,"AvSetMmThreadCharacteristicsA");
3815
            paWinWDMKSAvRtEntryPoints.AvRevertMmThreadCharacteristics =
3816
                (BOOL(WINAPI*)(HANDLE))GetProcAddress(paWinWDMKSAvRtEntryPoints.hInstance, "AvRevertMmThreadCharacteristics");
3817
            paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority =
3818
                (BOOL(WINAPI*)(HANDLE,PA_AVRT_PRIORITY))GetProcAddress(paWinWDMKSAvRtEntryPoints.hInstance, "AvSetMmThreadPriority");
3819
        }
3820
    }
3821

    
3822
    wdmHostApi = (PaWinWdmHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinWdmHostApiRepresentation) );
3823
    if( !wdmHostApi )
3824
    {
3825
        result = paInsufficientMemory;
3826
        goto error;
3827
    }
3828

    
3829
    wdmHostApi->allocations = PaUtil_CreateAllocationGroup();
3830
    if( !wdmHostApi->allocations )
3831
    {
3832
        result = paInsufficientMemory;
3833
        goto error;
3834
    }
3835

    
3836
    *hostApi = &wdmHostApi->inheritedHostApiRep;
3837
    (*hostApi)->info.structVersion = 1;
3838
    (*hostApi)->info.type = paWDMKS;
3839
    (*hostApi)->info.name = "Windows WDM-KS";
3840

    
3841
    /* these are all updated by CommitDeviceInfos() */
3842
    (*hostApi)->info.deviceCount = 0;
3843
    (*hostApi)->info.defaultInputDevice = paNoDevice;
3844
    (*hostApi)->info.defaultOutputDevice = paNoDevice;
3845
    (*hostApi)->deviceInfos = 0;
3846

    
3847
    result = ScanDeviceInfos(&wdmHostApi->inheritedHostApiRep, hostApiIndex, &scanResults, &deviceCount);
3848
    if (result != paNoError)
3849
    {
3850
        goto error;
3851
    }
3852

    
3853
    CommitDeviceInfos(&wdmHostApi->inheritedHostApiRep, hostApiIndex, scanResults, deviceCount);
3854

    
3855
    (*hostApi)->Terminate = Terminate;
3856
    (*hostApi)->OpenStream = OpenStream;
3857
    (*hostApi)->IsFormatSupported = IsFormatSupported;
3858
    /* In preparation for hotplug
3859
    (*hostApi)->ScanDeviceInfos = ScanDeviceInfos;
3860
    (*hostApi)->CommitDeviceInfos = CommitDeviceInfos;
3861
    (*hostApi)->DisposeDeviceInfos = DisposeDeviceInfos;
3862
    */
3863
    PaUtil_InitializeStreamInterface( &wdmHostApi->callbackStreamInterface, CloseStream, StartStream,
3864
        StopStream, AbortStream, IsStreamStopped, IsStreamActive,
3865
        GetStreamTime, GetStreamCpuLoad,
3866
        PaUtil_DummyRead, PaUtil_DummyWrite,
3867
        PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
3868

    
3869
    PaUtil_InitializeStreamInterface( &wdmHostApi->blockingStreamInterface, CloseStream, StartStream,
3870
        StopStream, AbortStream, IsStreamStopped, IsStreamActive,
3871
        GetStreamTime, PaUtil_DummyGetCpuLoad,
3872
        ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
3873

    
3874
    PA_LOGL_;
3875
    return result;
3876

    
3877
error:
3878
    Terminate( (PaUtilHostApiRepresentation*)wdmHostApi );
3879

    
3880
    PA_LOGL_;
3881
    return result;
3882
}
3883

    
3884

    
3885
static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
3886
{
3887
    PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
3888
    PA_LOGE_;
3889

    
3890
    /* Do not unload the libraries */
3891
    if( DllKsUser != NULL )
3892
    {
3893
        FreeLibrary( DllKsUser );
3894
        DllKsUser = NULL;
3895
    }
3896

    
3897
    if( paWinWDMKSAvRtEntryPoints.hInstance != NULL )
3898
    {
3899
        FreeLibrary( paWinWDMKSAvRtEntryPoints.hInstance );
3900
        paWinWDMKSAvRtEntryPoints.hInstance = NULL;
3901
    }
3902

    
3903
    if( wdmHostApi)
3904
    {
3905
        PaWinWDMScanDeviceInfosResults* localScanResults = (PaWinWDMScanDeviceInfosResults*)PaUtil_GroupAllocateMemory(
3906
            wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults));
3907
        localScanResults->deviceInfos = hostApi->deviceInfos;
3908
        DisposeDeviceInfos(hostApi, localScanResults, hostApi->info.deviceCount);
3909

    
3910
        if( wdmHostApi->allocations )
3911
        {
3912
            PaUtil_FreeAllAllocations( wdmHostApi->allocations );
3913
            PaUtil_DestroyAllocationGroup( wdmHostApi->allocations );
3914
        }
3915
        PaUtil_FreeMemory( wdmHostApi );
3916
    }
3917
    PA_LOGL_;
3918
}
3919

    
3920
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
3921
                                 const PaStreamParameters *inputParameters,
3922
                                 const PaStreamParameters *outputParameters,
3923
                                 double sampleRate )
3924
{
3925
    int inputChannelCount, outputChannelCount;
3926
    PaSampleFormat inputSampleFormat, outputSampleFormat;
3927
    PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
3928
    PaWinWdmFilter* pFilter;
3929
    int result = paFormatIsSupported;
3930
    WAVEFORMATEXTENSIBLE wfx;
3931
    PaWinWaveFormatChannelMask channelMask;
3932

    
3933
    PA_LOGE_;
3934

    
3935
    if( inputParameters )
3936
    {
3937
        PaWinWdmDeviceInfo* pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device];
3938
        PaWinWdmPin* pin;
3939
        unsigned fmt;
3940
        unsigned long testFormat = 0;
3941
        unsigned validBits = 0;
3942

    
3943
        inputChannelCount = inputParameters->channelCount;
3944
        inputSampleFormat = inputParameters->sampleFormat;
3945

    
3946
        /* all standard sample formats are supported by the buffer adapter,
3947
        this implementation doesn't support any custom sample formats */
3948
        if( inputSampleFormat & paCustomFormat )
3949
        {
3950
            PaWinWDM_SetLastErrorInfo(paSampleFormatNotSupported, "IsFormatSupported: Custom input format not supported");
3951
            return paSampleFormatNotSupported;
3952
        }
3953

    
3954
        /* unless alternate device specification is supported, reject the use of
3955
        paUseHostApiSpecificDeviceSpecification */
3956

    
3957
        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
3958
        {
3959
            PaWinWDM_SetLastErrorInfo(paInvalidDevice, "IsFormatSupported: paUseHostApiSpecificDeviceSpecification not supported");
3960
            return paInvalidDevice;
3961
        }
3962

    
3963
        /* check that input device can support inputChannelCount */
3964
        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
3965
        {
3966
            PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "IsFormatSupported: Invalid input channel count");
3967
            return paInvalidChannelCount;
3968
        }
3969

    
3970
        /* validate inputStreamInfo */
3971
        if( inputParameters->hostApiSpecificStreamInfo )
3972
        {
3973
            PaWinWDM_SetLastErrorInfo(paIncompatibleHostApiSpecificStreamInfo, "Host API stream info not supported");
3974
            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
3975
        }
3976

    
3977
        pFilter = pDeviceInfo->filter;
3978
        pin = pFilter->pins[pDeviceInfo->pin];
3979

    
3980
        /* Find out the testing format */
3981
        for (fmt = paFloat32; fmt <= paUInt8; fmt <<= 1)
3982
        {
3983
            if ((fmt & pin->formats) != 0)
3984
            {
3985
                /* Found a matching format! */
3986
                testFormat = fmt;
3987
                break;
3988
            }
3989
        }
3990
        if (testFormat == 0)
3991
        {
3992
            PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(capture) failed: no testformat found!");
3993
            return paUnanticipatedHostError;
3994
        }
3995

    
3996
        /* Due to special considerations, WaveRT devices with paInt24 should be tested with paInt32 and
3997
        valid bits = 24 (instead of 24 bit samples) */
3998
        if (pFilter->devInfo.streamingType == Type_kWaveRT && testFormat == paInt24)
3999
        {
4000
            PA_DEBUG(("IsFormatSupported (capture): WaveRT overriding testFormat paInt24 with paInt32 (24 valid bits)"));
4001
            testFormat = paInt32;
4002
            validBits = 24;
4003
        }
4004

    
4005
        /* Check that the input format is supported */
4006
        channelMask = PaWin_DefaultChannelMask(inputChannelCount);
4007
        PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
4008
            inputChannelCount, 
4009
            testFormat,
4010
            PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
4011
            sampleRate,
4012
            channelMask );
4013
        if (validBits != 0)
4014
        {
4015
            wfx.Samples.wValidBitsPerSample = validBits;
4016
        }
4017

    
4018
        result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx);
4019
        if( result != paNoError )
4020
        {
4021
            /* Try a WAVE_FORMAT_PCM instead */
4022
            PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
4023
                inputChannelCount, 
4024
                testFormat,
4025
                PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
4026
                sampleRate);
4027

    
4028
            if (validBits != 0)
4029
            {
4030
                wfx.Samples.wValidBitsPerSample = validBits;
4031
            }
4032

    
4033
            result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx);
4034
            if( result != paNoError )
4035
            {
4036
                PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(capture) failed: sr=%u,ch=%u,bits=%u", wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample);
4037
                return result;
4038
            }
4039
        }
4040
    }
4041
    else
4042
    {
4043
        inputChannelCount = 0;
4044
    }
4045

    
4046
    if( outputParameters )
4047
    {
4048
        PaWinWdmDeviceInfo* pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device];
4049
        PaWinWdmPin* pin;
4050
        unsigned fmt;
4051
        unsigned long testFormat = 0;
4052
        unsigned validBits = 0;
4053

    
4054
        outputChannelCount = outputParameters->channelCount;
4055
        outputSampleFormat = outputParameters->sampleFormat;
4056

    
4057
        /* all standard sample formats are supported by the buffer adapter,
4058
        this implementation doesn't support any custom sample formats */
4059
        if( outputSampleFormat & paCustomFormat )
4060
        {
4061
            PaWinWDM_SetLastErrorInfo(paSampleFormatNotSupported, "IsFormatSupported: Custom output format not supported");
4062
            return paSampleFormatNotSupported;
4063
        }
4064

    
4065
        /* unless alternate device specification is supported, reject the use of
4066
        paUseHostApiSpecificDeviceSpecification */
4067

    
4068
        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
4069
        {
4070
            PaWinWDM_SetLastErrorInfo(paInvalidDevice, "IsFormatSupported: paUseHostApiSpecificDeviceSpecification not supported");
4071
            return paInvalidDevice;
4072
        }
4073

    
4074
        /* check that output device can support outputChannelCount */
4075
        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
4076
        {
4077
            PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "Invalid output channel count");
4078
            return paInvalidChannelCount;
4079
        }
4080

    
4081
        /* validate outputStreamInfo */
4082
        if( outputParameters->hostApiSpecificStreamInfo )
4083
        {
4084
            PaWinWDM_SetLastErrorInfo(paIncompatibleHostApiSpecificStreamInfo, "Host API stream info not supported");
4085
            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
4086
        }
4087

    
4088
        pFilter = pDeviceInfo->filter;
4089
        pin = pFilter->pins[pDeviceInfo->pin];
4090

    
4091
        /* Find out the testing format */
4092
        for (fmt = paFloat32; fmt <= paUInt8; fmt <<= 1)
4093
        {
4094
            if ((fmt & pin->formats) != 0)
4095
            {
4096
                /* Found a matching format! */
4097
                testFormat = fmt;
4098
                break;
4099
            }
4100
        }
4101
        if (testFormat == 0)
4102
        {
4103
            PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(render) failed: no testformat found!");
4104
            return paUnanticipatedHostError;
4105
        }
4106

    
4107
        /* Due to special considerations, WaveRT devices with paInt24 should be tested with paInt32 and
4108
        valid bits = 24 (instead of 24 bit samples) */
4109
        if (pFilter->devInfo.streamingType == Type_kWaveRT && testFormat == paInt24)
4110
        {
4111
            PA_DEBUG(("IsFormatSupported (render): WaveRT overriding testFormat paInt24 with paInt32 (24 valid bits)"));
4112
            testFormat = paInt32;
4113
            validBits = 24;
4114
        }
4115

    
4116
        /* Check that the output format is supported */
4117
        channelMask = PaWin_DefaultChannelMask(outputChannelCount);
4118
        PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
4119
            outputChannelCount, 
4120
            testFormat,
4121
            PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
4122
            sampleRate,
4123
            channelMask );
4124

    
4125
        if (validBits != 0)
4126
        {
4127
            wfx.Samples.wValidBitsPerSample = validBits;
4128
        }
4129

    
4130
        result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx);
4131
        if( result != paNoError )
4132
        {
4133
            /* Try a WAVE_FORMAT_PCM instead */
4134
            PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
4135
                outputChannelCount, 
4136
                testFormat,
4137
                PaWin_SampleFormatToLinearWaveFormatTag(testFormat),
4138
                sampleRate);
4139

    
4140
            if (validBits != 0)
4141
            {
4142
                wfx.Samples.wValidBitsPerSample = validBits;
4143
            }
4144

    
4145
            result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx);
4146
            if( result != paNoError )
4147
            {
4148
                PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(render) failed: %u,%u,%u", wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample);
4149
                return result;
4150
            }
4151
        }
4152

    
4153
    }
4154
    else
4155
    {
4156
        outputChannelCount = 0;
4157
    }
4158

    
4159
    /*
4160
    IMPLEMENT ME:
4161

4162
    - if a full duplex stream is requested, check that the combination
4163
    of input and output parameters is supported if necessary
4164

4165
    - check that the device supports sampleRate
4166

4167
    Because the buffer adapter handles conversion between all standard
4168
    sample formats, the following checks are only required if paCustomFormat
4169
    is implemented, or under some other unusual conditions.
4170

4171
    - check that input device can support inputSampleFormat, or that
4172
    we have the capability to convert from inputSampleFormat to
4173
    a native format
4174

4175
    - check that output device can support outputSampleFormat, or that
4176
    we have the capability to convert from outputSampleFormat to
4177
    a native format
4178
    */
4179
    if((inputChannelCount == 0)&&(outputChannelCount == 0))
4180
    {
4181
        PaWinWDM_SetLastErrorInfo(paSampleFormatNotSupported, "No input or output channels defined");
4182
        result = paSampleFormatNotSupported; /* Not right error */
4183
    }
4184

    
4185
    PA_LOGL_;
4186
    return result;
4187
}
4188

    
4189
static void ResetStreamEvents(PaWinWdmStream* stream) 
4190
{
4191
    unsigned i;
4192
    ResetEvent(stream->eventAbort);
4193
    ResetEvent(stream->eventStreamStart[StreamStart_kOk]);
4194
    ResetEvent(stream->eventStreamStart[StreamStart_kFailed]);
4195

    
4196
    for (i=0; i<stream->capture.noOfPackets; ++i)
4197
    {
4198
        if (stream->capture.events && stream->capture.events[i])
4199
        {
4200
            ResetEvent(stream->capture.events[i]);
4201
        }
4202
    }
4203

    
4204
    for (i=0; i<stream->render.noOfPackets; ++i)
4205
    {
4206
        if (stream->render.events && stream->render.events[i])
4207
        {
4208
            ResetEvent(stream->render.events[i]);
4209
        }
4210
    }
4211
}
4212

    
4213
static void CloseStreamEvents(PaWinWdmStream* stream) 
4214
{
4215
    unsigned i;
4216
    PaWinWdmIOInfo* ios[2] = { &stream->capture, &stream->render };
4217

    
4218
    if (stream->eventAbort)
4219
    {
4220
        CloseHandle(stream->eventAbort);
4221
        stream->eventAbort = 0;
4222
    }
4223
    if (stream->eventStreamStart[StreamStart_kOk])
4224
    {
4225
        CloseHandle(stream->eventStreamStart[StreamStart_kOk]);
4226
    }
4227
    if (stream->eventStreamStart[StreamStart_kFailed])
4228
    {
4229
        CloseHandle(stream->eventStreamStart[StreamStart_kFailed]);
4230
    }
4231

    
4232
    for (i = 0; i < 2; ++i)
4233
    {
4234
        unsigned j;
4235
        /* Unregister notification handles for WaveRT */
4236
        if (ios[i]->pPin && ios[i]->pPin->parentFilter->devInfo.streamingType == Type_kWaveRT &&
4237
            ios[i]->pPin->pinKsSubType == SubType_kNotification &&
4238
            ios[i]->events != 0)
4239
        {
4240
            PinUnregisterNotificationHandle(ios[i]->pPin, ios[i]->events[0]);
4241
        }
4242

    
4243
        for (j=0; j < ios[i]->noOfPackets; ++j)
4244
        {
4245
            if (ios[i]->events && ios[i]->events[j])
4246
            {
4247
                CloseHandle(ios[i]->events[j]);
4248
                ios[i]->events[j] = 0;
4249
            }
4250
        }
4251
    }
4252
}
4253

    
4254
static unsigned NextPowerOf2(unsigned val)
4255
{
4256
    val--;
4257
    val = (val >> 1) | val;
4258
    val = (val >> 2) | val;
4259
    val = (val >> 4) | val;
4260
    val = (val >> 8) | val;
4261
    val = (val >> 16) | val;
4262
    return ++val;
4263
}
4264

    
4265
static PaError ValidateSpecificStreamParameters(
4266
    const PaStreamParameters *streamParameters,
4267
    const PaWinWDMKSInfo *streamInfo,
4268
    unsigned isInput)
4269
{
4270
    if( streamInfo )
4271
    {
4272
        if( streamInfo->size != sizeof( PaWinWDMKSInfo )
4273
            || streamInfo->version != 1 )
4274
        {
4275
            PA_DEBUG(("Stream parameters: size or version not correct"));
4276
            return paIncompatibleHostApiSpecificStreamInfo;
4277
        }
4278

    
4279
        if (!!(streamInfo->flags & ~(paWinWDMKSOverrideFramesize | paWinWDMKSUseGivenChannelMask)))
4280
        {
4281
            PA_DEBUG(("Stream parameters: non supported flags set"));
4282
            return paIncompatibleHostApiSpecificStreamInfo;
4283
        }
4284

    
4285
        if (streamInfo->noOfPackets != 0 &&
4286
            (streamInfo->noOfPackets < 2 || streamInfo->noOfPackets > 8))
4287
        {
4288
            PA_DEBUG(("Stream parameters: noOfPackets %u out of range [2,8]", streamInfo->noOfPackets));
4289
            return paIncompatibleHostApiSpecificStreamInfo;
4290
        }
4291

    
4292
        if (streamInfo->flags & paWinWDMKSUseGivenChannelMask)
4293
        {
4294
            if (isInput)
4295
            {
4296
                PA_DEBUG(("Stream parameters: Channels mask setting not supported for input stream"));
4297
                return paIncompatibleHostApiSpecificStreamInfo;
4298
            }
4299

    
4300
            if (streamInfo->channelMask & PAWIN_SPEAKER_RESERVED)
4301
            {
4302
                PA_DEBUG(("Stream parameters: Given channels mask 0x%08X not supported", streamInfo->channelMask));
4303
                return paIncompatibleHostApiSpecificStreamInfo;
4304
            }
4305
        }
4306

    
4307
    }
4308

    
4309
    return paNoError;
4310
}
4311

    
4312

    
4313

    
4314

    
4315
/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
4316

    
4317
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
4318
                          PaStream** s,
4319
                          const PaStreamParameters *inputParameters,
4320
                          const PaStreamParameters *outputParameters,
4321
                          double sampleRate,
4322
                          unsigned long framesPerUserBuffer,
4323
                          PaStreamFlags streamFlags,
4324
                          PaStreamCallback *streamCallback,
4325
                          void *userData )
4326
{
4327
    PaError result = paNoError;
4328
    PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
4329
    PaWinWdmStream *stream = 0;
4330
    /* unsigned long framesPerHostBuffer; these may not be equivalent for all implementations */
4331
    PaSampleFormat inputSampleFormat, outputSampleFormat;
4332
    PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
4333
    int userInputChannels,userOutputChannels;
4334
    WAVEFORMATEXTENSIBLE wfx;
4335

    
4336
    PA_LOGE_;
4337
    PA_DEBUG(("OpenStream:sampleRate = %f\n",sampleRate));
4338
    PA_DEBUG(("OpenStream:framesPerBuffer = %lu\n",framesPerUserBuffer));
4339

    
4340
    if( inputParameters )
4341
    {
4342
        userInputChannels = inputParameters->channelCount;
4343
        inputSampleFormat = inputParameters->sampleFormat;
4344

    
4345
        /* unless alternate device specification is supported, reject the use of
4346
        paUseHostApiSpecificDeviceSpecification */
4347

    
4348
        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
4349
        {
4350
            PaWinWDM_SetLastErrorInfo(paInvalidDevice, "paUseHostApiSpecificDeviceSpecification(in) not supported");
4351
            return paInvalidDevice;
4352
        }
4353

    
4354
        /* check that input device can support stream->userInputChannels */
4355
        if( userInputChannels > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
4356
        {
4357
            PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "Invalid input channel count");
4358
            return paInvalidChannelCount;
4359
        }
4360

    
4361
        /* validate inputStreamInfo */
4362
        result = ValidateSpecificStreamParameters(inputParameters, inputParameters->hostApiSpecificStreamInfo, 1 );
4363
        if(result != paNoError)
4364
        {
4365
            PaWinWDM_SetLastErrorInfo(result, "Host API stream info not supported (in)");
4366
            return result; /* this implementation doesn't use custom stream info */
4367
        }
4368
    }
4369
    else
4370
    {
4371
        userInputChannels = 0;
4372
        inputSampleFormat = hostInputSampleFormat = paInt16; /* Supress 'uninitialised var' warnings. */
4373
    }
4374

    
4375
    if( outputParameters )
4376
    {
4377
        userOutputChannels = outputParameters->channelCount;
4378
        outputSampleFormat = outputParameters->sampleFormat;
4379

    
4380
        /* unless alternate device specification is supported, reject the use of
4381
        paUseHostApiSpecificDeviceSpecification */
4382

    
4383
        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
4384
        {
4385
            PaWinWDM_SetLastErrorInfo(paInvalidDevice, "paUseHostApiSpecificDeviceSpecification(out) not supported");
4386
            return paInvalidDevice;
4387
        }
4388

    
4389
        /* check that output device can support stream->userInputChannels */
4390
        if( userOutputChannels > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
4391
        {
4392
            PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "Invalid output channel count");
4393
            return paInvalidChannelCount;
4394
        }
4395

    
4396
        /* validate outputStreamInfo */
4397
        result = ValidateSpecificStreamParameters( outputParameters, outputParameters->hostApiSpecificStreamInfo, 0 );
4398
        if (result != paNoError)
4399
        {
4400
            PaWinWDM_SetLastErrorInfo(result, "Host API stream info not supported (out)");
4401
            return result; /* this implementation doesn't use custom stream info */
4402
        }
4403
    }
4404
    else
4405
    {
4406
        userOutputChannels = 0;
4407
        outputSampleFormat = hostOutputSampleFormat = paInt16; /* Supress 'uninitialized var' warnings. */
4408
    }
4409

    
4410
    /* validate platform specific flags */
4411
    if( (streamFlags & paPlatformSpecificFlags) != 0 )
4412
    {
4413
        PaWinWDM_SetLastErrorInfo(paInvalidFlag, "Invalid flag supplied");
4414
        return paInvalidFlag; /* unexpected platform specific flag */
4415
    }
4416

    
4417
    stream = (PaWinWdmStream*)PaUtil_AllocateMemory( sizeof(PaWinWdmStream) );
4418
    if( !stream )
4419
    {
4420
        result = paInsufficientMemory;
4421
        goto error;
4422
    }
4423

    
4424
    /* Create allocation group */
4425
    stream->allocGroup = PaUtil_CreateAllocationGroup();
4426
    if( !stream->allocGroup )
4427
    {
4428
        result = paInsufficientMemory;
4429
        goto error;
4430
    }
4431

    
4432
    /* Zero the stream object */
4433
    /* memset((void*)stream,0,sizeof(PaWinWdmStream)); */
4434

    
4435
    if( streamCallback )
4436
    {
4437
        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
4438
            &wdmHostApi->callbackStreamInterface, streamCallback, userData );
4439
    }
4440
    else
4441
    {
4442
        /* PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
4443
        &wdmHostApi->blockingStreamInterface, streamCallback, userData ); */
4444

    
4445
        /* We don't support the blocking API yet */
4446
        PA_DEBUG(("Blocking API not supported yet!\n"));
4447
        PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Blocking API not supported yet");
4448
        result = paUnanticipatedHostError;
4449
        goto error;
4450
    }
4451

    
4452
    PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
4453

    
4454
    /* Instantiate the input pin if necessary */
4455
    if(userInputChannels > 0)
4456
    {
4457
        PaWinWdmFilter* pFilter;
4458
        PaWinWdmDeviceInfo* pDeviceInfo;
4459
        PaWinWdmPin* pPin;
4460
        unsigned validBitsPerSample = 0;
4461
        PaWinWaveFormatChannelMask channelMask = PaWin_DefaultChannelMask( userInputChannels );
4462

    
4463
        result = paSampleFormatNotSupported;
4464
        pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device];
4465
        pFilter = pDeviceInfo->filter;
4466
        pPin = pFilter->pins[pDeviceInfo->pin];
4467

    
4468
        stream->userInputChannels = userInputChannels;
4469

    
4470
        hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( pPin->formats, inputSampleFormat );
4471
        if (hostInputSampleFormat == paSampleFormatNotSupported)
4472
        {
4473
            result = paUnanticipatedHostError;
4474
            PaWinWDM_SetLastErrorInfo(result, "PU_SCAF(%X,%X) failed (input)", pPin->formats, inputSampleFormat);
4475
            goto error;
4476
        }
4477
        else if (pFilter->devInfo.streamingType == Type_kWaveRT && hostInputSampleFormat == paInt24)
4478
        {
4479
            /* For WaveRT, we choose 32 bit format instead of paInt24, since we MIGHT need to align buffer on a
4480
            128 byte boundary (see PinGetBuffer) */
4481
            hostInputSampleFormat = paInt32;
4482
            /* But we'll tell the driver that it's 24 bit in 32 bit container */
4483
            validBitsPerSample = 24;
4484
        }
4485

    
4486
        while (hostInputSampleFormat <= paUInt8)
4487
        {
4488
            unsigned channelsToProbe = stream->userInputChannels;
4489
            /* Some or all KS devices can only handle the exact number of channels
4490
            * they specify. But PortAudio clients expect to be able to
4491
            * at least specify mono I/O on a multi-channel device
4492
            * If this is the case, then we will do the channel mapping internally
4493
            * The following loop tests this case
4494
            **/
4495
            while (1)
4496
            {
4497
                PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
4498
                    channelsToProbe, 
4499
                    hostInputSampleFormat,
4500
                    PaWin_SampleFormatToLinearWaveFormatTag(hostInputSampleFormat),
4501
                    sampleRate,
4502
                    channelMask );
4503
                stream->capture.bytesPerFrame = wfx.Format.nBlockAlign;
4504
                if (validBitsPerSample != 0)
4505
                {
4506
                    wfx.Samples.wValidBitsPerSample = validBitsPerSample;
4507
                }
4508
                stream->capture.pPin = FilterCreatePin(pFilter, pPin->pinId, (WAVEFORMATEX*)&wfx, &result);
4509
                stream->deviceInputChannels = channelsToProbe;
4510

    
4511
                if( result != paNoError && result != paDeviceUnavailable )
4512
                {
4513
                    /* Try a WAVE_FORMAT_PCM instead */
4514
                    PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
4515
                        channelsToProbe, 
4516
                        hostInputSampleFormat,
4517
                        PaWin_SampleFormatToLinearWaveFormatTag(hostInputSampleFormat),
4518
                        sampleRate);
4519
                    if (validBitsPerSample != 0)
4520
                    {
4521
                        wfx.Samples.wValidBitsPerSample = validBitsPerSample;
4522
                    }
4523
                    stream->capture.pPin = FilterCreatePin(pFilter, pPin->pinId, (const WAVEFORMATEX*)&wfx, &result);
4524
                }
4525

    
4526
                if (result == paDeviceUnavailable) goto occupied;
4527

    
4528
                if (result == paNoError)
4529
                {
4530
                    /* We're done */
4531
                    break;
4532
                }
4533

    
4534
                if (channelsToProbe < (unsigned)pPin->maxChannels)
4535
                {
4536
                    /* Go to next multiple of 2 */
4537
                    channelsToProbe = min((((channelsToProbe>>1)+1)<<1), (unsigned)pPin->maxChannels);
4538
                    continue;
4539
                }
4540

    
4541
                break;
4542
            }
4543

    
4544
            if (result == paNoError)
4545
            {
4546
                /* We're done */
4547
                break;
4548
            }
4549

    
4550
            /* Go to next format in line with lower resolution */
4551
            hostInputSampleFormat <<= 1;
4552
        }
4553

    
4554
        if(stream->capture.pPin == NULL)
4555
        {
4556
            PaWinWDM_SetLastErrorInfo(result, "Failed to create capture pin: sr=%u,ch=%u,bits=%u,align=%u",
4557
                wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample, wfx.Format.nBlockAlign);
4558
            goto error;
4559
        }
4560

    
4561
        /* Select correct mux input on MUX node of topology filter */
4562
        if (pDeviceInfo->muxPosition >= 0)
4563
        {
4564
            assert(pPin->parentFilter->topologyFilter != NULL);
4565

    
4566
            result = FilterUse(pPin->parentFilter->topologyFilter);
4567
            if (result != paNoError)
4568
            {
4569
                PaWinWDM_SetLastErrorInfo(result, "Failed to open topology filter");
4570
                goto error;
4571
            }
4572

    
4573
            result = WdmSetMuxNodeProperty(pPin->parentFilter->topologyFilter->handle,
4574
                pPin->inputs[pDeviceInfo->muxPosition]->muxNodeId,
4575
                pPin->inputs[pDeviceInfo->muxPosition]->muxPinId);
4576

    
4577
            FilterRelease(pPin->parentFilter->topologyFilter);
4578

    
4579
            if(result != paNoError)
4580
            {
4581
                PaWinWDM_SetLastErrorInfo(result, "Failed to set topology mux node");
4582
                goto error;
4583
            }
4584
        }
4585

    
4586
        stream->capture.bytesPerSample = stream->capture.bytesPerFrame / stream->deviceInputChannels;
4587
        stream->capture.pPin->frameSize /= stream->capture.bytesPerFrame;
4588
        PA_DEBUG(("Capture pin frames: %d\n",stream->capture.pPin->frameSize));
4589
    }
4590
    else
4591
    {
4592
        stream->capture.pPin = NULL;
4593
        stream->capture.bytesPerFrame = 0;
4594
    }
4595

    
4596
    /* Instantiate the output pin if necessary */
4597
    if(userOutputChannels > 0)
4598
    {
4599
        PaWinWdmFilter* pFilter;
4600
        PaWinWdmDeviceInfo* pDeviceInfo;
4601
        PaWinWdmPin* pPin;
4602
        PaWinWDMKSInfo* pInfo = (PaWinWDMKSInfo*)(outputParameters->hostApiSpecificStreamInfo);
4603
        unsigned validBitsPerSample = 0;
4604
        PaWinWaveFormatChannelMask channelMask = PaWin_DefaultChannelMask( userOutputChannels );
4605
        if (pInfo && (pInfo->flags & paWinWDMKSUseGivenChannelMask))
4606
        {
4607
            PA_DEBUG(("Using channelMask 0x%08X instead of default 0x%08X\n",
4608
                pInfo->channelMask,
4609
                channelMask));
4610
            channelMask = pInfo->channelMask;
4611
        }
4612

    
4613
        result = paSampleFormatNotSupported;
4614
        pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device];
4615
        pFilter = pDeviceInfo->filter;
4616
        pPin = pFilter->pins[pDeviceInfo->pin];
4617

    
4618
        stream->userOutputChannels = userOutputChannels;
4619

    
4620
        hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( pPin->formats, outputSampleFormat );
4621
        if (hostOutputSampleFormat == paSampleFormatNotSupported)
4622
        {
4623
            result = paUnanticipatedHostError;
4624
            PaWinWDM_SetLastErrorInfo(result, "PU_SCAF(%X,%X) failed (output)", pPin->formats, hostOutputSampleFormat);
4625
            goto error;
4626
        }
4627
        else if (pFilter->devInfo.streamingType == Type_kWaveRT && hostOutputSampleFormat == paInt24)
4628
        {
4629
            /* For WaveRT, we choose 32 bit format instead of paInt24, since we MIGHT need to align buffer on a
4630
            128 byte boundary (see PinGetBuffer) */
4631
            hostOutputSampleFormat = paInt32;
4632
            /* But we'll tell the driver that it's 24 bit in 32 bit container */
4633
            validBitsPerSample = 24;
4634
        }
4635

    
4636
        while (hostOutputSampleFormat <= paUInt8)
4637
        {
4638
            unsigned channelsToProbe = stream->userOutputChannels;
4639
            /* Some or all KS devices can only handle the exact number of channels
4640
            * they specify. But PortAudio clients expect to be able to
4641
            * at least specify mono I/O on a multi-channel device
4642
            * If this is the case, then we will do the channel mapping internally
4643
            * The following loop tests this case
4644
            **/
4645
            while (1)
4646
            {
4647
                PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx,
4648
                    channelsToProbe, 
4649
                    hostOutputSampleFormat,
4650
                    PaWin_SampleFormatToLinearWaveFormatTag(hostOutputSampleFormat),
4651
                    sampleRate,
4652
                    channelMask );
4653
                stream->render.bytesPerFrame = wfx.Format.nBlockAlign;
4654
                if (validBitsPerSample != 0)
4655
                {
4656
                    wfx.Samples.wValidBitsPerSample = validBitsPerSample;
4657
                }
4658
                stream->render.pPin = FilterCreatePin(pFilter, pPin->pinId, (WAVEFORMATEX*)&wfx, &result);
4659
                stream->deviceOutputChannels = channelsToProbe;
4660

    
4661
                if( result != paNoError && result != paDeviceUnavailable )
4662
                {
4663
                    PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx,
4664
                        channelsToProbe, 
4665
                        hostOutputSampleFormat,
4666
                        PaWin_SampleFormatToLinearWaveFormatTag(hostOutputSampleFormat),
4667
                        sampleRate);
4668
                    if (validBitsPerSample != 0)
4669
                    {
4670
                        wfx.Samples.wValidBitsPerSample = validBitsPerSample;
4671
                    }
4672
                    stream->render.pPin = FilterCreatePin(pFilter, pPin->pinId, (const WAVEFORMATEX*)&wfx, &result);
4673
                }
4674

    
4675
                if (result == paDeviceUnavailable) goto occupied;
4676

    
4677
                if (result == paNoError)
4678
                {
4679
                    /* We're done */
4680
                    break;
4681
                }
4682

    
4683
                if (channelsToProbe < (unsigned)pPin->maxChannels)
4684
                {
4685
                    /* Go to next multiple of 2 */
4686
                    channelsToProbe = min((((channelsToProbe>>1)+1)<<1), (unsigned)pPin->maxChannels);
4687
                    continue;
4688
                }
4689

    
4690
                break;
4691
            };
4692

    
4693
            if (result == paNoError)
4694
            {
4695
                /* We're done */
4696
                break;
4697
            }
4698

    
4699
            /* Go to next format in line with lower resolution */
4700
            hostOutputSampleFormat <<= 1;
4701
        }
4702

    
4703
        if(stream->render.pPin == NULL)
4704
        {
4705
            PaWinWDM_SetLastErrorInfo(result, "Failed to create render pin: sr=%u,ch=%u,bits=%u,align=%u",
4706
                wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample, wfx.Format.nBlockAlign);
4707
            goto error;
4708
        }
4709

    
4710
        stream->render.bytesPerSample = stream->render.bytesPerFrame / stream->deviceOutputChannels;
4711
        stream->render.pPin->frameSize /= stream->render.bytesPerFrame;
4712
        PA_DEBUG(("Render pin frames: %d\n",stream->render.pPin->frameSize));
4713
    }
4714
    else
4715
    {
4716
        stream->render.pPin = NULL;
4717
        stream->render.bytesPerFrame = 0;
4718
    }
4719

    
4720
    /* Calculate the framesPerHostXxxxBuffer size based upon the suggested latency values */
4721
    /* Record the buffer length */
4722
    if(inputParameters)
4723
    {
4724
        /* Calculate the frames from the user's value - add a bit to round up */
4725
        stream->capture.framesPerBuffer = (unsigned long)((inputParameters->suggestedLatency*sampleRate)+0.0001);
4726
        if(stream->capture.framesPerBuffer > (unsigned long)sampleRate)
4727
        { /* Upper limit is 1 second */
4728
            stream->capture.framesPerBuffer = (unsigned long)sampleRate;
4729
        }
4730
        else if(stream->capture.framesPerBuffer < stream->capture.pPin->frameSize)
4731
        {
4732
            stream->capture.framesPerBuffer = stream->capture.pPin->frameSize;
4733
        }
4734
        PA_DEBUG(("Input frames chosen:%ld\n",stream->capture.framesPerBuffer));
4735

    
4736
        /* Setup number of packets to use */
4737
        stream->capture.noOfPackets = 2;
4738

    
4739
        if (inputParameters->hostApiSpecificStreamInfo)
4740
        {
4741
            PaWinWDMKSInfo* pInfo = (PaWinWDMKSInfo*)inputParameters->hostApiSpecificStreamInfo;
4742

    
4743
            if (stream->capture.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic &&
4744
                pInfo->noOfPackets != 0)
4745
            {
4746
                stream->capture.noOfPackets = pInfo->noOfPackets;
4747
            }
4748
        }
4749
    }
4750

    
4751
    if(outputParameters)
4752
    {
4753
        /* Calculate the frames from the user's value - add a bit to round up */
4754
        stream->render.framesPerBuffer = (unsigned long)((outputParameters->suggestedLatency*sampleRate)+0.0001);
4755
        if(stream->render.framesPerBuffer > (unsigned long)sampleRate)
4756
        { /* Upper limit is 1 second */
4757
            stream->render.framesPerBuffer = (unsigned long)sampleRate;
4758
        }
4759
        else if(stream->render.framesPerBuffer < stream->render.pPin->frameSize)
4760
        {
4761
            stream->render.framesPerBuffer = stream->render.pPin->frameSize;
4762
        }
4763
        PA_DEBUG(("Output frames chosen:%ld\n",stream->render.framesPerBuffer));
4764

    
4765
        /* Setup number of packets to use */
4766
        stream->render.noOfPackets = 2;
4767

    
4768
        if (outputParameters->hostApiSpecificStreamInfo)
4769
        {
4770
            PaWinWDMKSInfo* pInfo = (PaWinWDMKSInfo*)outputParameters->hostApiSpecificStreamInfo;
4771

    
4772
            if (stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic &&
4773
                pInfo->noOfPackets != 0)
4774
            {
4775
                stream->render.noOfPackets = pInfo->noOfPackets;
4776
            }
4777
        }
4778
    }
4779

    
4780
    /* Host buffer size is bound to the largest of the input and output frame sizes */
4781
    result =  PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
4782
        stream->userInputChannels, inputSampleFormat, hostInputSampleFormat,
4783
        stream->userOutputChannels, outputSampleFormat, hostOutputSampleFormat,
4784
        sampleRate, streamFlags, framesPerUserBuffer,
4785
        max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer), 
4786
        paUtilBoundedHostBufferSize,
4787
        streamCallback, userData );
4788
    if( result != paNoError )
4789
    {
4790
        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",
4791
            stream->userInputChannels, inputSampleFormat, hostInputSampleFormat,
4792
            stream->userOutputChannels, outputSampleFormat, hostOutputSampleFormat,
4793
            sampleRate, streamFlags, framesPerUserBuffer,
4794
            max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer));
4795
        goto error;
4796
    }
4797

    
4798
    /* Allocate/get all the buffers for host I/O */
4799
    if (stream->userInputChannels > 0)
4800
    {
4801
        stream->streamRepresentation.streamInfo.inputLatency = stream->capture.framesPerBuffer / sampleRate;
4802

    
4803
        switch (stream->capture.pPin->parentFilter->devInfo.streamingType)
4804
        {
4805
        case Type_kWaveCyclic:
4806
            {
4807
                unsigned size = stream->capture.noOfPackets * stream->capture.framesPerBuffer * stream->capture.bytesPerFrame;
4808
                /* Allocate input host buffer */
4809
                stream->capture.hostBuffer = (char*)PaUtil_GroupAllocateMemory(stream->allocGroup, size);
4810
                PA_DEBUG(("Input buffer allocated (size = %u)\n", size));
4811
                if( !stream->capture.hostBuffer )
4812
                {
4813
                    PA_DEBUG(("Cannot allocate host input buffer!\n"));
4814
                    PaWinWDM_SetLastErrorInfo(paInsufficientMemory, "Failed to allocate input buffer");
4815
                    result = paInsufficientMemory;
4816
                    goto error;
4817
                }
4818
                stream->capture.hostBufferSize = size;
4819
                PA_DEBUG(("Input buffer start = %p (size=%u)\n",stream->capture.hostBuffer, stream->capture.hostBufferSize));
4820
                stream->capture.pPin->fnEventHandler = PaPinCaptureEventHandler_WaveCyclic;
4821
                stream->capture.pPin->fnSubmitHandler = PaPinCaptureSubmitHandler_WaveCyclic;
4822
            }
4823
            break;
4824
        case Type_kWaveRT:
4825
            {
4826
                const DWORD dwTotalSize = 2 * stream->capture.framesPerBuffer * stream->capture.bytesPerFrame;
4827
                DWORD dwRequestedSize = dwTotalSize;
4828
                BOOL bCallMemoryBarrier = FALSE;
4829
                ULONG hwFifoLatency = 0;
4830
                ULONG dummy;
4831
                result = PinGetBuffer(stream->capture.pPin, (void**)&stream->capture.hostBuffer, &dwRequestedSize, &bCallMemoryBarrier);
4832
                if (!result) 
4833
                {
4834
                    PA_DEBUG(("Input buffer start = %p, size = %u\n", stream->capture.hostBuffer, dwRequestedSize));
4835
                    if (dwRequestedSize != dwTotalSize)
4836
                    {
4837
                        PA_DEBUG(("Buffer length changed by driver from %u to %u !\n", dwTotalSize, dwRequestedSize));
4838
                        /* Recalculate to what the driver has given us */
4839
                        stream->capture.framesPerBuffer = dwRequestedSize / (2 * stream->capture.bytesPerFrame);
4840
                    }
4841
                    stream->capture.hostBufferSize = dwRequestedSize;
4842

    
4843
                    if (stream->capture.pPin->pinKsSubType == SubType_kPolled)
4844
                    {
4845
                        stream->capture.pPin->fnEventHandler = PaPinCaptureEventHandler_WaveRTPolled;
4846
                        stream->capture.pPin->fnSubmitHandler = PaPinCaptureSubmitHandler_WaveRTPolled;
4847
                    }
4848
                    else
4849
                    {
4850
                        stream->capture.pPin->fnEventHandler = PaPinCaptureEventHandler_WaveRTEvent;
4851
                        stream->capture.pPin->fnSubmitHandler = PaPinCaptureSubmitHandler_WaveRTEvent;
4852
                    }
4853

    
4854
                    stream->capture.pPin->fnMemBarrier = bCallMemoryBarrier ? MemoryBarrierRead : MemoryBarrierDummy;
4855
                }
4856
                else 
4857
                {
4858
                    PA_DEBUG(("Failed to get input buffer (WaveRT)\n"));
4859
                    PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to get input buffer (WaveRT)");
4860
                    result = paUnanticipatedHostError;
4861
                    goto error;
4862
                }
4863

    
4864
                /* Get latency */
4865
                result = PinGetHwLatency(stream->capture.pPin, &hwFifoLatency, &dummy, &dummy);
4866
                if (result == paNoError)
4867
                {
4868
                    stream->capture.pPin->hwLatency = hwFifoLatency;
4869

    
4870
                    /* Add HW latency into total input latency */
4871
                    stream->streamRepresentation.streamInfo.inputLatency += ((hwFifoLatency / stream->capture.bytesPerFrame) / sampleRate);
4872
                }
4873
                else
4874
                {
4875
                    PA_DEBUG(("Failed to get size of FIFO hardware buffer (is set to zero)\n"));
4876
                    stream->capture.pPin->hwLatency = 0;
4877
                }
4878
            }
4879
            break;
4880
        default:
4881
            /* Undefined wave type!! */
4882
            assert(0);
4883
            result = paInternalError;
4884
            PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType);
4885
            goto error;
4886
        }
4887
    }
4888
    else 
4889
    {
4890
        stream->capture.hostBuffer = 0;
4891
    }
4892

    
4893
    if (stream->userOutputChannels > 0)
4894
    {
4895
        stream->streamRepresentation.streamInfo.outputLatency = stream->render.framesPerBuffer / sampleRate;
4896

    
4897
        switch (stream->render.pPin->parentFilter->devInfo.streamingType)
4898
        {
4899
        case Type_kWaveCyclic:
4900
            {
4901
                unsigned size = stream->render.noOfPackets * stream->render.framesPerBuffer * stream->render.bytesPerFrame;
4902
                /* Allocate output device buffer */
4903
                stream->render.hostBuffer = (char*)PaUtil_GroupAllocateMemory(stream->allocGroup, size);
4904
                PA_DEBUG(("Output buffer allocated (size = %u)\n", size));
4905
                if( !stream->render.hostBuffer )
4906
                {
4907
                    PA_DEBUG(("Cannot allocate host output buffer!\n"));
4908
                    PaWinWDM_SetLastErrorInfo(paInsufficientMemory, "Failed to allocate output buffer");
4909
                    result = paInsufficientMemory;
4910
                    goto error;
4911
                }
4912
                stream->render.hostBufferSize = size;
4913
                PA_DEBUG(("Output buffer start = %p (size=%u)\n",stream->render.hostBuffer, stream->render.hostBufferSize));
4914

    
4915
                stream->render.pPin->fnEventHandler = PaPinRenderEventHandler_WaveCyclic;
4916
                stream->render.pPin->fnSubmitHandler = PaPinRenderSubmitHandler_WaveCyclic;
4917
            }
4918
            break;
4919
        case Type_kWaveRT:
4920
            {
4921
                const DWORD dwTotalSize = 2 * stream->render.framesPerBuffer * stream->render.bytesPerFrame;
4922
                DWORD dwRequestedSize = dwTotalSize;
4923
                BOOL bCallMemoryBarrier = FALSE;
4924
                ULONG hwFifoLatency = 0;
4925
                ULONG dummy;
4926
                result = PinGetBuffer(stream->render.pPin, (void**)&stream->render.hostBuffer, &dwRequestedSize, &bCallMemoryBarrier);
4927
                if (!result) 
4928
                {
4929
                    PA_DEBUG(("Output buffer start = %p, size = %u, membarrier = %u\n", stream->render.hostBuffer, dwRequestedSize, bCallMemoryBarrier));
4930
                    if (dwRequestedSize != dwTotalSize)
4931
                    {
4932
                        PA_DEBUG(("Buffer length changed by driver from %u to %u !\n", dwTotalSize, dwRequestedSize));
4933
                        /* Recalculate to what the driver has given us */
4934
                        stream->render.framesPerBuffer = dwRequestedSize / (2 * stream->render.bytesPerFrame);
4935
                    }
4936
                    stream->render.hostBufferSize = dwRequestedSize;
4937

    
4938
                    if (stream->render.pPin->pinKsSubType == SubType_kPolled)
4939
                    {
4940
                        stream->render.pPin->fnEventHandler = PaPinRenderEventHandler_WaveRTPolled;
4941
                        stream->render.pPin->fnSubmitHandler = PaPinRenderSubmitHandler_WaveRTPolled;
4942
                    }
4943
                    else
4944
                    {
4945
                        stream->render.pPin->fnEventHandler = PaPinRenderEventHandler_WaveRTEvent;
4946
                        stream->render.pPin->fnSubmitHandler = PaPinRenderSubmitHandler_WaveRTEvent;
4947
                    }
4948

    
4949
                    stream->render.pPin->fnMemBarrier = bCallMemoryBarrier ? MemoryBarrierWrite : MemoryBarrierDummy;
4950
                }
4951
                else 
4952
                {
4953
                    PA_DEBUG(("Failed to get output buffer (with notification)\n"));
4954
                    PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to get output buffer (with notification)");
4955
                    result = paUnanticipatedHostError;
4956
                    goto error;
4957
                }
4958

    
4959
                /* Get latency */
4960
                result = PinGetHwLatency(stream->render.pPin, &hwFifoLatency, &dummy, &dummy);
4961
                if (result == paNoError)
4962
                {
4963
                    stream->render.pPin->hwLatency = hwFifoLatency;
4964

    
4965
                    /* Add HW latency into total output latency */
4966
                    stream->streamRepresentation.streamInfo.outputLatency += ((hwFifoLatency / stream->render.bytesPerFrame) / sampleRate);
4967
                }
4968
                else
4969
                {
4970
                    PA_DEBUG(("Failed to get size of FIFO hardware buffer (is set to zero)\n"));
4971
                    stream->render.pPin->hwLatency = 0;
4972
                }
4973
            }
4974
            break;
4975
        default:
4976
            /* Undefined wave type!! */
4977
            assert(0);
4978
            result = paInternalError;
4979
            PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType);
4980
            goto error;
4981
        }
4982
    }
4983
    else 
4984
    {
4985
        stream->render.hostBuffer = 0;
4986
    }
4987

    
4988
    stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
4989

    
4990
    PA_DEBUG(("BytesPerInputFrame = %d\n",stream->capture.bytesPerFrame));
4991
    PA_DEBUG(("BytesPerOutputFrame = %d\n",stream->render.bytesPerFrame));
4992

    
4993
    /* memset(stream->hostBuffer,0,size); */
4994

    
4995
    /* Abort */
4996
    stream->eventAbort          = CreateEvent(NULL, TRUE, FALSE, NULL);
4997
    if (stream->eventAbort == 0)
4998
    {
4999
        result = paInsufficientMemory;
5000
        goto error;
5001
    }
5002
    stream->eventStreamStart[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
5003
    if (stream->eventStreamStart[0] == 0)
5004
    {
5005
        result = paInsufficientMemory;
5006
        goto error;
5007
    }
5008
    stream->eventStreamStart[1] = CreateEvent(NULL, TRUE, FALSE, NULL);
5009
    if (stream->eventStreamStart[1] == 0)
5010
    {
5011
        result = paInsufficientMemory;
5012
        goto error;
5013
    }
5014

    
5015
    if(stream->userInputChannels > 0)
5016
    {
5017
        const unsigned bufferSizeInBytes = stream->capture.framesPerBuffer * stream->capture.bytesPerFrame;
5018
        const unsigned ringBufferFrameSize = NextPowerOf2( 1024 + 2 * max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer) );
5019

    
5020
        stream->capture.events = (HANDLE*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->capture.noOfPackets * sizeof(HANDLE));
5021
        if (stream->capture.events == NULL)
5022
        {
5023
            result = paInsufficientMemory;
5024
            goto error;
5025
        }
5026

    
5027
        stream->capture.packets = (DATAPACKET*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->capture.noOfPackets * sizeof(DATAPACKET));
5028
        if (stream->capture.packets == NULL)
5029
        {
5030
            result = paInsufficientMemory;
5031
            goto error;
5032
        }
5033

    
5034
        switch(stream->capture.pPin->parentFilter->devInfo.streamingType)
5035
        {
5036
        case Type_kWaveCyclic:
5037
            {
5038
                /* WaveCyclic case */
5039
                unsigned i;
5040
                for (i = 0; i < stream->capture.noOfPackets; ++i)
5041
                {
5042
                    /* Set up the packets */
5043
                    DATAPACKET *p = stream->capture.packets + i;
5044

    
5045
                    /* Record event */
5046
                    stream->capture.events[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
5047

    
5048
                    p->Signal.hEvent = stream->capture.events[i];
5049
                    p->Header.Data = stream->capture.hostBuffer + (i*bufferSizeInBytes);
5050
                    p->Header.FrameExtent = bufferSizeInBytes;
5051
                    p->Header.DataUsed = 0;
5052
                    p->Header.Size = sizeof(p->Header);
5053
                    p->Header.PresentationTime.Numerator = 1;
5054
                    p->Header.PresentationTime.Denominator = 1;
5055
                }
5056
            }
5057
            break;
5058
        case Type_kWaveRT:
5059
            {
5060
                /* Set up the "packets" */
5061
                DATAPACKET *p = stream->capture.packets + 0;
5062

    
5063
                /* Record event: WaveRT has a single event for 2 notification per buffer */
5064
                stream->capture.events[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
5065

    
5066
                p->Header.Data = stream->capture.hostBuffer;
5067
                p->Header.FrameExtent = bufferSizeInBytes;
5068
                p->Header.DataUsed = 0;
5069
                p->Header.Size = sizeof(p->Header);
5070
                p->Header.PresentationTime.Numerator = 1;
5071
                p->Header.PresentationTime.Denominator = 1;
5072

    
5073
                ++p;
5074
                p->Header.Data = stream->capture.hostBuffer + bufferSizeInBytes;
5075
                p->Header.FrameExtent = bufferSizeInBytes;
5076
                p->Header.DataUsed = 0;
5077
                p->Header.Size = sizeof(p->Header);
5078
                p->Header.PresentationTime.Numerator = 1;
5079
                p->Header.PresentationTime.Denominator = 1;
5080

    
5081
                if (stream->capture.pPin->pinKsSubType == SubType_kNotification)
5082
                {
5083
                    result = PinRegisterNotificationHandle(stream->capture.pPin, stream->capture.events[0]);
5084

    
5085
                    if (result != paNoError)
5086
                    {
5087
                        PA_DEBUG(("Failed to register capture notification handle\n"));
5088
                        PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to register capture notification handle");
5089
                        result = paUnanticipatedHostError;
5090
                        goto error;
5091
                    }
5092
                }
5093

    
5094
                result = PinRegisterPositionRegister(stream->capture.pPin);
5095

    
5096
                if (result != paNoError)
5097
                {
5098
                    unsigned long pos = 0xdeadc0de;
5099
                    PA_DEBUG(("Failed to register capture position register, using PinGetAudioPositionViaIOCTLWrite\n"));
5100
                    stream->capture.pPin->fnAudioPosition = PinGetAudioPositionViaIOCTLWrite;
5101
                    /* Test position function */
5102
                    result = (stream->capture.pPin->fnAudioPosition)(stream->capture.pPin, &pos);
5103
                    if (result != paNoError || pos != 0x0)
5104
                    {
5105
                        PA_DEBUG(("Failed to read capture position register (IOCTL)\n"));
5106
                        PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to read capture position register (IOCTL)");
5107
                        result = paUnanticipatedHostError;
5108
                        goto error;
5109
                    }                
5110
                }
5111
                else
5112
                {
5113
                    stream->capture.pPin->fnAudioPosition = PinGetAudioPositionMemoryMapped;
5114
                }
5115
            }
5116
            break;
5117
        default:
5118
            /* Undefined wave type!! */
5119
            assert(0);
5120
            result = paInternalError;
5121
            PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType);
5122
            goto error;
5123
        }
5124

    
5125
        /* Setup the input ring buffer here */
5126
        stream->ringBufferData = (char*)PaUtil_GroupAllocateMemory(stream->allocGroup, ringBufferFrameSize * stream->capture.bytesPerFrame);
5127
        if (stream->ringBufferData == NULL)
5128
        {
5129
            result = paInsufficientMemory;
5130
            goto error;
5131
        }
5132
        PaUtil_InitializeRingBuffer(&stream->ringBuffer, stream->capture.bytesPerFrame, ringBufferFrameSize, stream->ringBufferData);
5133
    }
5134
    if(stream->userOutputChannels > 0)
5135
    {
5136
        const unsigned bufferSizeInBytes = stream->render.framesPerBuffer * stream->render.bytesPerFrame;
5137

    
5138
        stream->render.events = (HANDLE*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->render.noOfPackets * sizeof(HANDLE));
5139
        if (stream->render.events == NULL)
5140
        {
5141
            result = paInsufficientMemory;
5142
            goto error;
5143
        }
5144

    
5145
        stream->render.packets = (DATAPACKET*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->render.noOfPackets * sizeof(DATAPACKET));
5146
        if (stream->render.packets == NULL)
5147
        {
5148
            result = paInsufficientMemory;
5149
            goto error;
5150
        }
5151

    
5152
        switch(stream->render.pPin->parentFilter->devInfo.streamingType)
5153
        {
5154
        case Type_kWaveCyclic:
5155
            {
5156
                /* WaveCyclic case */
5157
                unsigned i;
5158
                for (i = 0; i < stream->render.noOfPackets; ++i)
5159
                {
5160
                    /* Set up the packets */
5161
                    DATAPACKET *p = stream->render.packets + i;
5162

    
5163
                    /* Playback event */
5164
                    stream->render.events[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
5165

    
5166
                    /* In this case, we just use the packets as ptr to the device buffer */
5167
                    p->Signal.hEvent = stream->render.events[i];
5168
                    p->Header.Data = stream->render.hostBuffer + (i*bufferSizeInBytes);
5169
                    p->Header.FrameExtent = bufferSizeInBytes;
5170
                    p->Header.DataUsed = bufferSizeInBytes;
5171
                    p->Header.Size = sizeof(p->Header);
5172
                    p->Header.PresentationTime.Numerator = 1;
5173
                    p->Header.PresentationTime.Denominator = 1;
5174
                }
5175
            }
5176
            break;
5177
        case Type_kWaveRT:
5178
            {
5179
                /* WaveRT case */
5180

    
5181
                /* Set up the "packets" */
5182
                DATAPACKET *p = stream->render.packets;
5183

    
5184
                /* The only playback event */
5185
                stream->render.events[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
5186

    
5187
                /* In this case, we just use the packets as ptr to the device buffer */
5188
                p->Header.Data = stream->render.hostBuffer;
5189
                p->Header.FrameExtent = stream->render.framesPerBuffer*stream->render.bytesPerFrame;
5190
                p->Header.DataUsed = stream->render.framesPerBuffer*stream->render.bytesPerFrame;
5191
                p->Header.Size = sizeof(p->Header);
5192
                p->Header.PresentationTime.Numerator = 1;
5193
                p->Header.PresentationTime.Denominator = 1;
5194

    
5195
                ++p;
5196
                p->Header.Data = stream->render.hostBuffer + stream->render.framesPerBuffer*stream->render.bytesPerFrame;
5197
                p->Header.FrameExtent = stream->render.framesPerBuffer*stream->render.bytesPerFrame;
5198
                p->Header.DataUsed = stream->render.framesPerBuffer*stream->render.bytesPerFrame;
5199
                p->Header.Size = sizeof(p->Header);
5200
                p->Header.PresentationTime.Numerator = 1;
5201
                p->Header.PresentationTime.Denominator = 1;
5202

    
5203
                if (stream->render.pPin->pinKsSubType == SubType_kNotification)
5204
                {
5205
                    result = PinRegisterNotificationHandle(stream->render.pPin, stream->render.events[0]);
5206

    
5207
                    if (result != paNoError)
5208
                    {
5209
                        PA_DEBUG(("Failed to register rendering notification handle\n"));
5210
                        PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to register rendering notification handle");
5211
                        result = paUnanticipatedHostError;
5212
                        goto error;
5213
                    }
5214
                }
5215

    
5216
                result = PinRegisterPositionRegister(stream->render.pPin);
5217

    
5218
                if (result != paNoError)
5219
                {
5220
                    unsigned long pos = 0xdeadc0de;
5221
                    PA_DEBUG(("Failed to register rendering position register, using PinGetAudioPositionViaIOCTLRead\n"));
5222
                    stream->render.pPin->fnAudioPosition = PinGetAudioPositionViaIOCTLRead;
5223
                    /* Test position function */
5224
                    result = (stream->render.pPin->fnAudioPosition)(stream->render.pPin, &pos);
5225
                    if (result != paNoError || pos != 0x0)
5226
                    {
5227
                        PA_DEBUG(("Failed to read render position register (IOCTL)\n"));
5228
                        PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to read render position register (IOCTL)");
5229
                        result = paUnanticipatedHostError;
5230
                        goto error;
5231
                    }
5232
                }
5233
                else
5234
                {
5235
                    stream->render.pPin->fnAudioPosition = PinGetAudioPositionMemoryMapped;
5236
                }
5237
            }
5238
            break;
5239
        default:
5240
            /* Undefined wave type!! */
5241
            assert(0);
5242
            result = paInternalError;
5243
            PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType);
5244
            goto error;
5245
        }
5246
    }
5247

    
5248
    stream->streamStarted = 0;
5249
    stream->streamActive = 0;
5250
    stream->streamStop = 0;
5251
    stream->streamAbort = 0;
5252
    stream->streamFlags = streamFlags;
5253
    stream->oldProcessPriority = REALTIME_PRIORITY_CLASS;
5254

    
5255
    /* Increase ref count on filters in use, so that a CommitDeviceInfos won't delete them */
5256
    if (stream->capture.pPin != 0)
5257
    {
5258
        FilterAddRef(stream->capture.pPin->parentFilter);
5259
    }
5260
    if (stream->render.pPin != 0)
5261
    {
5262
        FilterAddRef(stream->render.pPin->parentFilter);
5263
    }
5264

    
5265
    /* Ok, now update our host API specific stream info */
5266
    if (stream->userInputChannels)
5267
    {
5268
        PaWinWdmDeviceInfo *pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device];
5269

    
5270
        stream->hostApiStreamInfo.input.device = Pa_HostApiDeviceIndexToDeviceIndex(Pa_HostApiTypeIdToHostApiIndex(paWDMKS), inputParameters->device);
5271
        stream->hostApiStreamInfo.input.channels = stream->deviceInputChannels;
5272
        stream->hostApiStreamInfo.input.muxNodeId = -1;
5273
        if (stream->capture.pPin->inputs)
5274
        {
5275
            stream->hostApiStreamInfo.input.muxNodeId = stream->capture.pPin->inputs[pDeviceInfo->muxPosition]->muxNodeId;
5276
        }
5277
        stream->hostApiStreamInfo.input.endpointPinId = pDeviceInfo->endpointPinId;
5278
        stream->hostApiStreamInfo.input.framesPerHostBuffer = stream->capture.framesPerBuffer;
5279
        stream->hostApiStreamInfo.input.streamingSubType = stream->capture.pPin->pinKsSubType;
5280
    }
5281
    else
5282
    {
5283
        stream->hostApiStreamInfo.input.device = paNoDevice;
5284
    }
5285
    if (stream->userOutputChannels)
5286
    {
5287
        stream->hostApiStreamInfo.output.device = Pa_HostApiDeviceIndexToDeviceIndex(Pa_HostApiTypeIdToHostApiIndex(paWDMKS), outputParameters->device);
5288
        stream->hostApiStreamInfo.output.channels = stream->deviceOutputChannels;
5289
        stream->hostApiStreamInfo.output.framesPerHostBuffer = stream->render.framesPerBuffer;
5290
        stream->hostApiStreamInfo.output.endpointPinId = stream->render.pPin->endpointPinId;
5291
        stream->hostApiStreamInfo.output.streamingSubType = stream->render.pPin->pinKsSubType;
5292
    }
5293
    else
5294
    {
5295
        stream->hostApiStreamInfo.output.device = paNoDevice;
5296
    }
5297
    /*stream->streamRepresentation.streamInfo.hostApiTypeId = paWDMKS;
5298
    stream->streamRepresentation.streamInfo.hostApiSpecificStreamInfo = &stream->hostApiStreamInfo;*/
5299
    stream->streamRepresentation.streamInfo.structVersion = 2;
5300

    
5301
    *s = (PaStream*)stream;
5302

    
5303
    PA_LOGL_;
5304
    return result;
5305

    
5306
occupied:
5307
    /* Ok, someone else is hogging the pin, bail out */
5308
    assert (result == paDeviceUnavailable);
5309
    PaWinWDM_SetLastErrorInfo(result, "Device is occupied");
5310

    
5311
error:
5312
    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
5313

    
5314
    CloseStreamEvents(stream);
5315

    
5316
    if (stream->allocGroup)
5317
    {
5318
        PaUtil_FreeAllAllocations(stream->allocGroup);
5319
        PaUtil_DestroyAllocationGroup(stream->allocGroup);
5320
        stream->allocGroup = 0;
5321
    }
5322

    
5323
    if(stream->render.pPin)
5324
        PinClose(stream->render.pPin);
5325
    if(stream->capture.pPin)
5326
        PinClose(stream->capture.pPin);
5327

    
5328
    PaUtil_FreeMemory( stream );
5329

    
5330
    PA_LOGL_;
5331
    return result;
5332
}
5333

    
5334
/*
5335
When CloseStream() is called, the multi-api layer ensures that
5336
the stream has already been stopped or aborted.
5337
*/
5338
static PaError CloseStream( PaStream* s )
5339
{
5340
    PaError result = paNoError;
5341
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
5342

    
5343
    PA_LOGE_;
5344

    
5345
    assert(!stream->streamStarted);
5346
    assert(!stream->streamActive);
5347

    
5348
    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
5349
    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
5350

    
5351
    CloseStreamEvents(stream);
5352

    
5353
    if (stream->allocGroup)
5354
    {
5355
        PaUtil_FreeAllAllocations(stream->allocGroup);
5356
        PaUtil_DestroyAllocationGroup(stream->allocGroup);
5357
        stream->allocGroup = 0;
5358
    }
5359

    
5360
    if(stream->render.pPin)
5361
    {
5362
        PinClose(stream->render.pPin);
5363
    }
5364
    if(stream->capture.pPin)
5365
    {
5366
        PinClose(stream->capture.pPin);
5367
    }
5368

    
5369
    if (stream->render.pPin)
5370
    {
5371
        FilterFree(stream->render.pPin->parentFilter);
5372
    }
5373
    if (stream->capture.pPin)
5374
    {
5375
        FilterFree(stream->capture.pPin->parentFilter);
5376
    }
5377

    
5378
    PaUtil_FreeMemory( stream );
5379

    
5380
    PA_LOGL_;
5381
    return result;
5382
}
5383

    
5384
/*
5385
Write the supplied packet to the pin
5386
Asynchronous
5387
Should return paNoError on success
5388
*/
5389
static PaError PinWrite(HANDLE h, DATAPACKET* p)
5390
{
5391
    PaError result = paNoError;
5392
    unsigned long cbReturned = 0;
5393
    BOOL fRes = DeviceIoControl(h,
5394
        IOCTL_KS_WRITE_STREAM,
5395
        NULL,
5396
        0,
5397
        &p->Header,
5398
        p->Header.Size,
5399
        &cbReturned,
5400
        &p->Signal);
5401
    if (!fRes)
5402
    {
5403
        unsigned long error = GetLastError();
5404
        if (error != ERROR_IO_PENDING)
5405
        {
5406
            result = paInternalError;
5407
        }
5408
    }
5409
    return result;
5410
}
5411

    
5412
/*
5413
Read to the supplied packet from the pin
5414
Asynchronous
5415
Should return paNoError on success
5416
*/
5417
static PaError PinRead(HANDLE h, DATAPACKET* p)
5418
{
5419
    PaError result = paNoError;
5420
    unsigned long cbReturned = 0;
5421
    BOOL fRes = DeviceIoControl(h,
5422
        IOCTL_KS_READ_STREAM,
5423
        NULL,
5424
        0,
5425
        &p->Header,
5426
        p->Header.Size,
5427
        &cbReturned,
5428
        &p->Signal);
5429
    if (!fRes)
5430
    {
5431
        unsigned long error = GetLastError();
5432
        if (error != ERROR_IO_PENDING)
5433
        {
5434
            result = paInternalError;
5435
        }
5436
    }
5437
    return result;
5438
}
5439

    
5440
/*
5441
Copy the first interleaved channel of 16 bit data to the other channels
5442
*/
5443
static void DuplicateFirstChannelInt16(void* buffer, int channels, int samples)
5444
{
5445
    unsigned short* data = (unsigned short*)buffer;
5446
    int channel;
5447
    unsigned short sourceSample;
5448
    while( samples-- )
5449
    {
5450
        sourceSample = *data++;
5451
        channel = channels-1;
5452
        while( channel-- )
5453
        {
5454
            *data++ = sourceSample;
5455
        }
5456
    }
5457
}
5458

    
5459
/*
5460
Copy the first interleaved channel of 24 bit data to the other channels
5461
*/
5462
static void DuplicateFirstChannelInt24(void* buffer, int channels, int samples)
5463
{
5464
    unsigned char* data = (unsigned char*)buffer;
5465
    int channel;
5466
    unsigned char sourceSample[3];
5467
    while( samples-- )
5468
    {
5469
        sourceSample[0] = data[0];
5470
        sourceSample[1] = data[1];
5471
        sourceSample[2] = data[2];
5472
        data += 3;
5473
        channel = channels-1;
5474
        while( channel-- )
5475
        {
5476
            data[0] = sourceSample[0];
5477
            data[1] = sourceSample[1];
5478
            data[2] = sourceSample[2];
5479
            data += 3;
5480
        }
5481
    }
5482
}
5483

    
5484
/*
5485
Copy the first interleaved channel of 32 bit data to the other channels
5486
*/
5487
static void DuplicateFirstChannelInt32(void* buffer, int channels, int samples)
5488
{
5489
    unsigned long* data = (unsigned long*)buffer;
5490
    int channel;
5491
    unsigned long sourceSample;
5492
    while( samples-- )
5493
    {
5494
        sourceSample = *data++;
5495
        channel = channels-1;
5496
        while( channel-- )
5497
        {
5498
            *data++ = sourceSample;
5499
        }
5500
    }
5501
}
5502

    
5503
/*
5504
Increase the priority of the calling thread to RT 
5505
*/
5506
static HANDLE BumpThreadPriority() 
5507
{
5508
    HANDLE hThread = GetCurrentThread();
5509
    DWORD dwTask = 0;
5510
    HANDLE hAVRT = NULL;
5511

    
5512
    /* If we have access to AVRT.DLL (Vista and later), use it */
5513
    if (paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics != NULL) 
5514
    {
5515
        hAVRT = paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics("Pro Audio", &dwTask);
5516
        if (hAVRT != NULL && hAVRT != INVALID_HANDLE_VALUE) 
5517
        {
5518
            BOOL bret = paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority(hAVRT, PA_AVRT_PRIORITY_CRITICAL);
5519
            if (!bret)
5520
            {
5521
                PA_DEBUG(("Set mm thread prio to critical failed!\n"));
5522
            }
5523
            else
5524
            {
5525
                return hAVRT;
5526
            }
5527
        }
5528
        else
5529
        {
5530
            PA_DEBUG(("Set mm thread characteristic to 'Pro Audio' failed, reverting to SetThreadPriority\n"));
5531
        }
5532
    }
5533

    
5534
    /* For XP and earlier, or if AvSetMmThreadCharacteristics fails (MMCSS disabled ?) */
5535
    if (timeBeginPeriod(1) != TIMERR_NOERROR) {
5536
        PA_DEBUG(("timeBeginPeriod(1) failed!\n"));
5537
    }
5538

    
5539
    if (!SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL)) {
5540
        PA_DEBUG(("SetThreadPriority failed!\n"));
5541
    }
5542

    
5543
    return hAVRT;
5544
}
5545

    
5546
/*
5547
Decrease the priority of the calling thread to normal
5548
*/
5549
static void DropThreadPriority(HANDLE hAVRT)
5550
{
5551
    HANDLE hThread = GetCurrentThread();
5552

    
5553
    if (hAVRT != NULL) 
5554
    {
5555
        paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority(hAVRT, PA_AVRT_PRIORITY_NORMAL);
5556
        paWinWDMKSAvRtEntryPoints.AvRevertMmThreadCharacteristics(hAVRT);
5557
        return;
5558
    }
5559

    
5560
    SetThreadPriority(hThread, THREAD_PRIORITY_NORMAL);
5561
    timeEndPeriod(1);
5562
}
5563

    
5564
static PaError PreparePinForStart(PaWinWdmPin* pin)
5565
{
5566
    PaError result;
5567
    result = PinSetState(pin, KSSTATE_ACQUIRE);
5568
    if (result != paNoError)
5569
    {
5570
        goto error;
5571
    }
5572
    result = PinSetState(pin, KSSTATE_PAUSE);
5573
    if (result != paNoError)
5574
    {
5575
        goto error;
5576
    }
5577
    return result;
5578

    
5579
error:
5580
    PinSetState(pin, KSSTATE_STOP);
5581
    return result;
5582
}
5583

    
5584
static PaError PreparePinsForStart(PaProcessThreadInfo* pInfo)
5585
{
5586
    PaError result = paNoError;
5587
    /* Submit buffers */
5588
    if (pInfo->stream->capture.pPin)
5589
    {
5590
        if ((result = PreparePinForStart(pInfo->stream->capture.pPin)) != paNoError)
5591
        {
5592
            goto error;
5593
        }
5594

    
5595
        if (pInfo->stream->capture.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
5596
        {
5597
            unsigned i;
5598
            for(i=0; i < pInfo->stream->capture.noOfPackets; ++i)
5599
            {
5600
                if ((result = PinRead(pInfo->stream->capture.pPin->handle, pInfo->stream->capture.packets + i)) != paNoError)
5601
                {
5602
                    goto error;
5603
                }
5604
                ++pInfo->pending;
5605
            }
5606
        }
5607
        else
5608
        {
5609
            pInfo->pending = 2;
5610
        }
5611
    }
5612

    
5613
    if(pInfo->stream->render.pPin)
5614
    {
5615
        if ((result = PreparePinForStart(pInfo->stream->render.pPin)) != paNoError)
5616
        {
5617
            goto error;
5618
        }
5619

    
5620
        pInfo->priming += pInfo->stream->render.noOfPackets;
5621
        ++pInfo->pending;
5622
        SetEvent(pInfo->stream->render.events[0]);
5623
        if (pInfo->stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic) 
5624
        {
5625
            unsigned i;
5626
            for(i=1; i < pInfo->stream->render.noOfPackets; ++i)
5627
            {
5628
                SetEvent(pInfo->stream->render.events[i]);
5629
                ++pInfo->pending;
5630
            }
5631
        }
5632
    }
5633

    
5634
error:
5635
    PA_DEBUG(("PreparePinsForStart = %d\n", result));
5636
    return result;
5637
}
5638

    
5639
static PaError StartPin(PaWinWdmPin* pin)
5640
{
5641
    return PinSetState(pin, KSSTATE_RUN);
5642
}
5643

    
5644
static PaError StartPins(PaProcessThreadInfo* pInfo)
5645
{
5646
    PaError result = paNoError;
5647
    /* Start the pins as synced as possible */
5648
    if (pInfo->stream->capture.pPin)
5649
    {
5650
        result = StartPin(pInfo->stream->capture.pPin);
5651
    }
5652
    if(pInfo->stream->render.pPin)
5653
    {
5654
        result = StartPin(pInfo->stream->render.pPin);
5655
    }
5656
    PA_DEBUG(("StartPins = %d\n", result));
5657
    return result;
5658
}
5659

    
5660

    
5661
static PaError StopPin(PaWinWdmPin* pin)
5662
{
5663
    PinSetState(pin, KSSTATE_PAUSE);
5664
    PinSetState(pin, KSSTATE_STOP);
5665
    return paNoError;
5666
}
5667

    
5668

    
5669
static PaError StopPins(PaProcessThreadInfo* pInfo)
5670
{
5671
    PaError result = paNoError;
5672
    if(pInfo->stream->render.pPin)
5673
    {
5674
        StopPin(pInfo->stream->render.pPin);
5675
    }
5676
    if(pInfo->stream->capture.pPin)
5677
    {
5678
        StopPin(pInfo->stream->capture.pPin);
5679
    }
5680
    return result;
5681
}
5682

    
5683
typedef void (*TSetInputFrameCount)(PaUtilBufferProcessor*, unsigned long);
5684
typedef void (*TSetInputChannel)(PaUtilBufferProcessor*, unsigned int, void *, unsigned int);
5685
static const TSetInputFrameCount fnSetInputFrameCount[2] = { PaUtil_SetInputFrameCount, PaUtil_Set2ndInputFrameCount };
5686
static const TSetInputChannel fnSetInputChannel[2] = { PaUtil_SetInputChannel, PaUtil_Set2ndInputChannel };
5687

    
5688
static PaError PaDoProcessing(PaProcessThreadInfo* pInfo)
5689
{
5690
    PaError result = paNoError;
5691
    int i, framesProcessed = 0, doChannelCopy = 0;
5692
    ring_buffer_size_t inputFramesAvailable = PaUtil_GetRingBufferReadAvailable(&pInfo->stream->ringBuffer);
5693

    
5694
    /* Do necessary buffer processing (which will invoke user callback if necessary) */
5695
    if (pInfo->cbResult == paContinue &&
5696
        (pInfo->renderHead != pInfo->renderTail || inputFramesAvailable))
5697
    {
5698
        unsigned processFullDuplex = pInfo->stream->capture.pPin && pInfo->stream->render.pPin && (!pInfo->priming);
5699

    
5700
        PA_HP_TRACE((pInfo->stream->hLog, "DoProcessing: InputFrames=%u", inputFramesAvailable));
5701

    
5702
        PaUtil_BeginCpuLoadMeasurement( &pInfo->stream->cpuLoadMeasurer );
5703

    
5704
        pInfo->ti.currentTime = PaUtil_GetTime();
5705

    
5706
        PaUtil_BeginBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->ti, pInfo->underover);
5707
        pInfo->underover = 0; /* Reset the (under|over)flow status */
5708

    
5709
        if (pInfo->renderTail != pInfo->renderHead)
5710
        {
5711
            DATAPACKET* packet = pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet;
5712

    
5713
            assert(packet != 0);
5714
            assert(packet->Header.Data != 0);
5715

    
5716
            PaUtil_SetOutputFrameCount(&pInfo->stream->bufferProcessor, pInfo->stream->render.framesPerBuffer);
5717

    
5718
            for(i=0;i<pInfo->stream->userOutputChannels;i++)
5719
            {
5720
                /* Only write the user output channels. Leave the rest blank */
5721
                PaUtil_SetOutputChannel(&pInfo->stream->bufferProcessor,
5722
                    i,
5723
                    ((unsigned char*)(packet->Header.Data))+(i*pInfo->stream->render.bytesPerSample),
5724
                    pInfo->stream->deviceOutputChannels);
5725
            }
5726

    
5727
            /* We will do a copy to the other channels after the data has been written */
5728
            doChannelCopy = ( pInfo->stream->userOutputChannels == 1 );
5729
        }
5730

    
5731
        if (inputFramesAvailable && (!pInfo->stream->userOutputChannels || inputFramesAvailable >= (int)pInfo->stream->render.framesPerBuffer))
5732
        {
5733
            unsigned wrapCntr = 0;
5734
            void* data[2] = {0};
5735
            ring_buffer_size_t size[2] = {0};
5736

    
5737
            /* If full-duplex, we just extract output buffer number of frames */
5738
            if (pInfo->stream->userOutputChannels)
5739
            {
5740
                inputFramesAvailable = min(inputFramesAvailable, (int)pInfo->stream->render.framesPerBuffer);
5741
            }
5742

    
5743
            inputFramesAvailable = PaUtil_GetRingBufferReadRegions(&pInfo->stream->ringBuffer,
5744
                inputFramesAvailable,
5745
                &data[0],
5746
                &size[0],
5747
                &data[1],
5748
                &size[1]);
5749

    
5750
            for (wrapCntr = 0; wrapCntr < 2; ++wrapCntr)
5751
            {
5752
                if (size[wrapCntr] == 0)
5753
                    break;
5754

    
5755
                fnSetInputFrameCount[wrapCntr](&pInfo->stream->bufferProcessor, size[wrapCntr]);
5756
                for(i=0;i<pInfo->stream->userInputChannels;i++)
5757
                {
5758
                    /* Only read as many channels as the user wants */
5759
                    fnSetInputChannel[wrapCntr](&pInfo->stream->bufferProcessor,
5760
                        i,
5761
                        ((unsigned char*)(data[wrapCntr]))+(i*pInfo->stream->capture.bytesPerSample),
5762
                        pInfo->stream->deviceInputChannels);
5763
                }
5764
            }
5765
        }
5766
        else
5767
        {
5768
            /* We haven't consumed anything from the ring buffer... */
5769
            inputFramesAvailable = 0;
5770
            /* If we have full-duplex, this is at startup, so mark no-input! */
5771
            if (pInfo->stream->userOutputChannels>0 && pInfo->stream->userInputChannels>0)
5772
            {
5773
                PA_HP_TRACE((pInfo->stream->hLog, "Input startup, marking no input."));
5774
                PaUtil_SetNoInput(&pInfo->stream->bufferProcessor);
5775
            }
5776
        }
5777

    
5778
        if (processFullDuplex) /* full duplex */
5779
        {
5780
            /* Only call the EndBufferProcessing function when the total input frames == total output frames */
5781
            const unsigned long totalInputFrameCount = pInfo->stream->bufferProcessor.hostInputFrameCount[0] + pInfo->stream->bufferProcessor.hostInputFrameCount[1];
5782
            const unsigned long totalOutputFrameCount = pInfo->stream->bufferProcessor.hostOutputFrameCount[0] + pInfo->stream->bufferProcessor.hostOutputFrameCount[1];
5783

    
5784
            if(totalInputFrameCount == totalOutputFrameCount && totalOutputFrameCount != 0)
5785
            {
5786
                framesProcessed = PaUtil_EndBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->cbResult);
5787
            }
5788
            else
5789
            {
5790
                framesProcessed = 0;
5791
            }
5792
        }
5793
        else 
5794
        {
5795
            framesProcessed = PaUtil_EndBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->cbResult);
5796
        }
5797

    
5798
        PA_HP_TRACE((pInfo->stream->hLog, "Frames processed: %u %s", framesProcessed, (pInfo->priming ? "(priming)":"")));
5799

    
5800
        if( doChannelCopy )
5801
        {
5802
            DATAPACKET* packet = pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet;
5803
            /* Copy the first output channel to the other channels */
5804
            switch (pInfo->stream->render.bytesPerSample)
5805
            {
5806
            case 2:
5807
                DuplicateFirstChannelInt16(packet->Header.Data, pInfo->stream->deviceOutputChannels, pInfo->stream->render.framesPerBuffer);
5808
                break;
5809
            case 3:
5810
                DuplicateFirstChannelInt24(packet->Header.Data, pInfo->stream->deviceOutputChannels, pInfo->stream->render.framesPerBuffer);
5811
                break;
5812
            case 4:
5813
                DuplicateFirstChannelInt32(packet->Header.Data, pInfo->stream->deviceOutputChannels, pInfo->stream->render.framesPerBuffer);
5814
                break;
5815
            default:
5816
                assert(0); /* Unsupported format! */
5817
                break;
5818
            }
5819
        }
5820
        PaUtil_EndCpuLoadMeasurement( &pInfo->stream->cpuLoadMeasurer, framesProcessed );
5821

    
5822
        if (inputFramesAvailable)
5823
        {
5824
            PaUtil_AdvanceRingBufferReadIndex(&pInfo->stream->ringBuffer, inputFramesAvailable);
5825
        }
5826

    
5827
        if (pInfo->renderTail != pInfo->renderHead)
5828
        {
5829
            if (!pInfo->stream->streamStop)
5830
            {
5831
                result = pInfo->stream->render.pPin->fnSubmitHandler(pInfo, pInfo->renderTail);
5832
                if (result != paNoError)
5833
                {
5834
                    PA_HP_TRACE((pInfo->stream->hLog, "Capture submit handler failed with result %d", result));
5835
                    return result;
5836
                }
5837
            }
5838
            pInfo->renderTail++;
5839
            if (!pInfo->pinsStarted && pInfo->priming == 0)
5840
            {
5841
                /* We start the pins here to allow "prime time" */
5842
                if ((result = StartPins(pInfo)) == paNoError)
5843
                {
5844
                    PA_HP_TRACE((pInfo->stream->hLog, "Starting pins!"));
5845
                    pInfo->pinsStarted = 1;
5846
                }
5847
            }
5848
        }
5849
    }
5850

    
5851
    return result;
5852
}
5853

    
5854
static VOID CALLBACK TimerAPCWaveRTPolledMode(
5855
    LPVOID lpArgToCompletionRoutine,
5856
    DWORD dwTimerLowValue,
5857
    DWORD dwTimerHighValue)
5858
{
5859
    HANDLE* pHandles = (HANDLE*)lpArgToCompletionRoutine;
5860
    if (pHandles[0]) SetEvent(pHandles[0]);
5861
    if (pHandles[1]) SetEvent(pHandles[1]);
5862
}
5863

    
5864
static DWORD GetCurrentTimeInMillisecs()
5865
{
5866
    return timeGetTime();
5867
}
5868

    
5869
PA_THREAD_FUNC ProcessingThread(void* pParam)
5870
{
5871
    PaError result = paNoError;
5872
    HANDLE hAVRT = NULL;
5873
    HANDLE hTimer = NULL;
5874
    HANDLE *handleArray = NULL;
5875
    HANDLE timerEventHandles[2] = {0};
5876
    unsigned noOfHandles = 0;
5877
    unsigned captureEvents = 0;
5878
    unsigned renderEvents = 0;
5879
    unsigned timerPeriod = 0;
5880
    DWORD timeStamp[2] = {0};
5881

    
5882
    PaProcessThreadInfo info;
5883
    memset(&info, 0, sizeof(PaProcessThreadInfo));
5884
    info.stream = (PaWinWdmStream*)pParam;
5885

    
5886
    info.stream->threadResult = paNoError;
5887

    
5888
    PA_LOGE_;
5889

    
5890
    info.ti.inputBufferAdcTime = 0.0;
5891
    info.ti.currentTime = 0.0;
5892
    info.ti.outputBufferDacTime = 0.0;
5893

    
5894
    PA_DEBUG(("In  buffer len: %.3f ms\n",(2000*info.stream->capture.framesPerBuffer) / info.stream->streamRepresentation.streamInfo.sampleRate));
5895
    PA_DEBUG(("Out buffer len: %.3f ms\n",(2000*info.stream->render.framesPerBuffer) / info.stream->streamRepresentation.streamInfo.sampleRate));
5896
    info.timeout = (DWORD)max(
5897
        (2000*info.stream->render.framesPerBuffer/info.stream->streamRepresentation.streamInfo.sampleRate + 0.5),
5898
        (2000*info.stream->capture.framesPerBuffer/info.stream->streamRepresentation.streamInfo.sampleRate + 0.5));
5899
    info.timeout = max(info.timeout*8, 100);
5900
    timerPeriod = info.timeout;
5901
    PA_DEBUG(("Timeout = %ld ms\n",info.timeout));
5902

    
5903
    /* Allocate handle array */
5904
    handleArray = (HANDLE*)PaUtil_AllocateMemory((info.stream->capture.noOfPackets + info.stream->render.noOfPackets + 1) * sizeof(HANDLE));
5905

    
5906
    /* Setup handle array for WFMO */
5907
    if (info.stream->capture.pPin != 0)
5908
    {
5909
        handleArray[noOfHandles++] = info.stream->capture.events[0];
5910
        if (info.stream->capture.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
5911
        {
5912
            unsigned i;
5913
            for(i=1; i < info.stream->capture.noOfPackets; ++i)
5914
            {
5915
                handleArray[noOfHandles++] = info.stream->capture.events[i];
5916
            }
5917
        }
5918
        captureEvents = noOfHandles;
5919
        renderEvents = noOfHandles;
5920
    }
5921

    
5922
    if (info.stream->render.pPin != 0)
5923
    {
5924
        handleArray[noOfHandles++] = info.stream->render.events[0];
5925
        if (info.stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic)
5926
        {
5927
            unsigned i;
5928
            for(i=1; i < info.stream->render.noOfPackets; ++i)
5929
            {
5930
                handleArray[noOfHandles++] = info.stream->render.events[i];
5931
            }
5932
        }
5933
        renderEvents = noOfHandles;
5934
    }
5935
    handleArray[noOfHandles++] = info.stream->eventAbort;
5936
    assert(noOfHandles <= (info.stream->capture.noOfPackets + info.stream->render.noOfPackets + 1));
5937

    
5938
    /* Prepare render and capture pins */
5939
    if ((result = PreparePinsForStart(&info)) != paNoError) 
5940
    {
5941
        PA_DEBUG(("Failed to prepare device(s)!\n"));
5942
        goto error;
5943
    }
5944

    
5945
    /* Init high speed logger */
5946
    if (PaUtil_InitializeHighSpeedLog(&info.stream->hLog, 1000000) != paNoError)
5947
    {
5948
        PA_DEBUG(("Failed to init high speed logger!\n"));
5949
        goto error;
5950
    }
5951

    
5952
    /* Heighten priority here */
5953
    hAVRT = BumpThreadPriority();
5954

    
5955
    /* If input only, we start the pins immediately */
5956
    if (info.stream->render.pPin == 0)
5957
    {
5958
        if ((result = StartPins(&info)) != paNoError)
5959
        {
5960
            PA_DEBUG(("Failed to start device(s)!\n"));
5961
            goto error;
5962
        }
5963
        info.pinsStarted = 1;
5964
    }
5965

    
5966
    /* Handle WaveRT polled mode */
5967
    {
5968
        const unsigned fs = (unsigned)info.stream->streamRepresentation.streamInfo.sampleRate;
5969
        if (info.stream->capture.pPin != 0 && info.stream->capture.pPin->pinKsSubType == SubType_kPolled)
5970
        {
5971
            timerEventHandles[0] = info.stream->capture.events[0];
5972
            timerPeriod = min(timerPeriod, (1000*info.stream->capture.framesPerBuffer)/fs);
5973
        }
5974

    
5975
        if (info.stream->render.pPin != 0 && info.stream->render.pPin->pinKsSubType == SubType_kPolled)
5976
        {
5977
            timerEventHandles[1] = info.stream->render.events[0];
5978
            timerPeriod = min(timerPeriod, (1000*info.stream->render.framesPerBuffer)/fs);
5979
        }
5980

    
5981
        if (timerEventHandles[0] || timerEventHandles[1])
5982
        {
5983
            LARGE_INTEGER dueTime = {0};
5984

    
5985
            timerPeriod=max(timerPeriod/5,1);
5986
            PA_DEBUG(("Timer event handles=0x%04X,0x%04X period=%u ms", timerEventHandles[0], timerEventHandles[1], timerPeriod));
5987
            hTimer = CreateWaitableTimer(0, FALSE, NULL);
5988
            if (hTimer == NULL)
5989
            {
5990
                result = paUnanticipatedHostError;
5991
                goto error;
5992
            }
5993
            /* invoke first timeout immediately */
5994
            if (!SetWaitableTimer(hTimer, &dueTime, timerPeriod, TimerAPCWaveRTPolledMode, timerEventHandles, FALSE))
5995
            {
5996
                result = paUnanticipatedHostError;
5997
                goto error;
5998
            }
5999
            PA_DEBUG(("Waitable timer started, period = %u ms\n", timerPeriod));
6000
        }
6001
    }
6002

    
6003
    /* Mark stream as active */
6004
    info.stream->streamActive = 1;
6005
    info.stream->threadResult = paNoError;
6006

    
6007
    /* Up and running... */
6008
    SetEvent(info.stream->eventStreamStart[StreamStart_kOk]);
6009

    
6010
    /* Take timestamp here */
6011
    timeStamp[0] = timeStamp[1] = GetCurrentTimeInMillisecs();
6012

    
6013
    while(!info.stream->streamAbort)
6014
    {
6015
        unsigned doProcessing = 1;
6016
        unsigned wait = WaitForMultipleObjects(noOfHandles, handleArray, FALSE, 0);
6017
        unsigned eventSignalled = wait - WAIT_OBJECT_0;
6018
        DWORD dwCurrentTime = 0;
6019

    
6020
        if (wait == WAIT_FAILED) 
6021
        {
6022
            PA_DEBUG(("Wait failed = %ld! \n",wait));
6023
            break;
6024
        }
6025
        if (wait == WAIT_TIMEOUT)
6026
        {
6027
            wait = WaitForMultipleObjectsEx(noOfHandles, handleArray, FALSE, 50, TRUE);
6028
            eventSignalled = wait - WAIT_OBJECT_0;
6029
        }
6030
        else
6031
        {
6032
            if (eventSignalled < captureEvents)
6033
            {
6034
                if (PaUtil_GetRingBufferWriteAvailable(&info.stream->ringBuffer) == 0)
6035
                {
6036
                    PA_HP_TRACE((info.stream->hLog, "!!!!! Input overflow !!!!!"));
6037
                    info.underover |= paInputOverflow;
6038
                }
6039
            }
6040
            else if (eventSignalled < renderEvents)
6041
            {
6042
                if (!info.priming && info.renderHead - info.renderTail > 1)
6043
                {
6044
                    PA_HP_TRACE((info.stream->hLog, "!!!!! Output underflow !!!!!"));
6045
                    info.underover |= paOutputUnderflow;
6046
                }
6047
            }
6048
        }
6049

    
6050
        /* Get event time */
6051
        dwCurrentTime = GetCurrentTimeInMillisecs();
6052

    
6053
        /* Since we can mix capture/render devices between WaveCyclic, WaveRT polled and WaveRT notification (3x3 combinations), 
6054
        we can't rely on the timeout of WFMO to check for device timeouts, we need to keep tally. */
6055
        if (info.stream->capture.pPin && (dwCurrentTime - timeStamp[0]) >= info.timeout)
6056
        {
6057
            PA_DEBUG(("Timeout for capture device (%u ms)!", info.timeout, (dwCurrentTime - timeStamp[0])));
6058
            result = paTimedOut;
6059
            break;
6060
        }
6061
        if (info.stream->render.pPin && (dwCurrentTime - timeStamp[1]) >= info.timeout)
6062
        {
6063
            PA_DEBUG(("Timeout for render device (%u ms)!", info.timeout, (dwCurrentTime - timeStamp[1])));
6064
            result = paTimedOut;
6065
            break;
6066
        }
6067

    
6068
        if (wait == WAIT_IO_COMPLETION)
6069
        {
6070
            /* Waitable timer has fired! */
6071
            PA_HP_TRACE((info.stream->hLog, "WAIT_IO_COMPLETION"));
6072
            continue;
6073
        }
6074

    
6075
        if (wait == WAIT_TIMEOUT)
6076
        {
6077
            continue;
6078
        }
6079
        else
6080
        {
6081
            if (eventSignalled < captureEvents)
6082
            {
6083
                if (info.stream->capture.pPin->fnEventHandler(&info, eventSignalled) == paNoError)
6084
                {
6085
                    timeStamp[0] = dwCurrentTime;
6086

    
6087
                    /* Since we use the ring buffer, we can submit the buffers directly */
6088
                    if (!info.stream->streamStop)
6089
                    {
6090
                        result = info.stream->capture.pPin->fnSubmitHandler(&info, info.captureTail);
6091
                        if (result != paNoError)
6092
                        {
6093
                            PA_HP_TRACE((info.stream->hLog, "Capture submit handler failed with result %d", result));
6094
                            break;
6095
                        }
6096
                    }
6097
                    ++info.captureTail;
6098
                    /* If full-duplex, let _only_ render event trigger processing. We still need the stream stop
6099
                    handling working, so let that be processed anyways... */
6100
                    if (info.stream->userOutputChannels > 0)
6101
                    {
6102
                        doProcessing = 0;
6103
                    }
6104
                }
6105
            }
6106
            else if (eventSignalled < renderEvents)
6107
            {
6108
                timeStamp[1] = dwCurrentTime;
6109
                eventSignalled -= captureEvents;
6110
                info.stream->render.pPin->fnEventHandler(&info, eventSignalled);
6111
            }
6112
            else
6113
            {
6114
                assert(info.stream->streamAbort);
6115
                PA_HP_TRACE((info.stream->hLog, "Stream abort!"));
6116
                continue;
6117
            }
6118
        }
6119

    
6120
        /* Handle processing */
6121
        if (doProcessing)
6122
        {
6123
            result = PaDoProcessing(&info);
6124
            if (result != paNoError)
6125
            {
6126
                PA_HP_TRACE((info.stream->hLog, "PaDoProcessing failed!"));
6127
                break;
6128
            }
6129
        }
6130

    
6131
        if(info.stream->streamStop && info.cbResult != paComplete)
6132
        {
6133
            PA_HP_TRACE((info.stream->hLog, "Stream stop! pending=%d",info.pending));
6134
            info.cbResult = paComplete; /* Stop, but play remaining buffers */
6135
        }
6136

    
6137
        if(info.pending<=0)
6138
        {
6139
            PA_HP_TRACE((info.stream->hLog, "pending==0 finished..."));
6140
            break;
6141
        }
6142
        if((!info.stream->render.pPin)&&(info.cbResult!=paContinue))
6143
        {
6144
            PA_HP_TRACE((info.stream->hLog, "record only cbResult=%d...",info.cbResult));
6145
            break;
6146
        }
6147
    }
6148

    
6149
    PA_DEBUG(("Finished processing loop\n"));
6150

    
6151
    info.stream->threadResult = result;
6152
    goto bailout;
6153

    
6154
error:
6155
    PA_DEBUG(("Error starting processing thread\n"));
6156
    /* Set the "error" event together with result */
6157
    info.stream->threadResult = result;
6158
    SetEvent(info.stream->eventStreamStart[StreamStart_kFailed]);
6159

    
6160
bailout:
6161
    if (hTimer)
6162
    {
6163
        PA_DEBUG(("Waitable timer stopped\n", timerPeriod));
6164
        CancelWaitableTimer(hTimer);
6165
        CloseHandle(hTimer);
6166
        hTimer = 0;
6167
    }
6168

    
6169
    if (info.pinsStarted)
6170
    {
6171
        StopPins(&info);
6172
    }
6173

    
6174
    /* Lower prio here */
6175
    DropThreadPriority(hAVRT);
6176

    
6177
    if (handleArray != NULL)
6178
    {
6179
        PaUtil_FreeMemory(handleArray);
6180
    }
6181

    
6182
#if PA_TRACE_REALTIME_EVENTS
6183
    if (info.stream->hLog)
6184
    {
6185
        PA_DEBUG(("Dumping highspeed trace...\n"));
6186
        PaUtil_DumpHighSpeedLog(info.stream->hLog, "hp_trace.log");
6187
        PaUtil_DiscardHighSpeedLog(info.stream->hLog);
6188
        info.stream->hLog = 0;
6189
    }
6190
#endif
6191
    info.stream->streamActive = 0;
6192

    
6193
    if((!info.stream->streamStop)&&(!info.stream->streamAbort))
6194
    {
6195
        /* Invoke the user stream finished callback */
6196
        /* Only do it from here if not being stopped/aborted by user */
6197
        if( info.stream->streamRepresentation.streamFinishedCallback != 0 )
6198
            info.stream->streamRepresentation.streamFinishedCallback( info.stream->streamRepresentation.userData );
6199
    }
6200
    info.stream->streamStop = 0;
6201
    info.stream->streamAbort = 0;
6202

    
6203
    PA_LOGL_;
6204
    return 0;
6205
}
6206

    
6207

    
6208
static PaError StartStream( PaStream *s )
6209
{
6210
    PaError result = paNoError;
6211
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
6212

    
6213
    PA_LOGE_;
6214

    
6215
    if (stream->streamThread != NULL)
6216
    {
6217
        return paStreamIsNotStopped;
6218
    }
6219

    
6220
    stream->streamStop = 0;
6221
    stream->streamAbort = 0;
6222

    
6223
    ResetStreamEvents(stream);
6224

    
6225
    PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
6226

    
6227
    stream->oldProcessPriority = GetPriorityClass(GetCurrentProcess());
6228
    /* Uncomment the following line to enable dynamic boosting of the process
6229
    * priority to real time for best low latency support
6230
    * Disabled by default because RT processes can easily block the OS */
6231
    /*ret = SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS);
6232
    PA_DEBUG(("Class ret = %d;",ret));*/
6233

    
6234
    stream->streamThread = CREATE_THREAD_FUNCTION (NULL, 0, ProcessingThread, stream, CREATE_SUSPENDED, NULL);
6235
    if(stream->streamThread == NULL)
6236
    {
6237
        result = paInsufficientMemory;
6238
        goto end;
6239
    }
6240
    ResumeThread(stream->streamThread);
6241

    
6242
    switch (WaitForMultipleObjects(2, stream->eventStreamStart, FALSE, 5000))
6243
    {
6244
    case WAIT_OBJECT_0 + StreamStart_kOk:
6245
        PA_DEBUG(("Processing thread started!\n"));
6246
        result = paNoError;
6247
        /* streamActive is set in processing thread */
6248
        stream->streamStarted = 1;
6249
        break;
6250
    case WAIT_OBJECT_0 + StreamStart_kFailed:
6251
        PA_DEBUG(("Processing thread start failed! (result=%d)\n", stream->threadResult));
6252
        result = stream->threadResult;
6253
        /* Wait for the stream to really exit */
6254
        WaitForSingleObject(stream->streamThread, 200);
6255
        CloseHandle(stream->streamThread);
6256
        stream->streamThread = 0;
6257
        break;
6258
    case WAIT_TIMEOUT:
6259
    default:
6260
        result = paTimedOut;
6261
        PaWinWDM_SetLastErrorInfo(result, "Failed to start processing thread (timeout)!");
6262
        break;
6263
    }
6264

    
6265
end:
6266
    PA_LOGL_;
6267
    return result;
6268
}
6269

    
6270

    
6271
static PaError StopStream( PaStream *s )
6272
{
6273
    PaError result = paNoError;
6274
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
6275
    BOOL doCb = FALSE;
6276

    
6277
    PA_LOGE_;
6278

    
6279
    if(stream->streamActive)
6280
    {
6281
        DWORD dwExitCode;
6282
        doCb = TRUE;
6283
        stream->streamStop = 1;
6284
        if (GetExitCodeThread(stream->streamThread, &dwExitCode) && dwExitCode == STILL_ACTIVE)
6285
        {
6286
            if (WaitForSingleObject(stream->streamThread, INFINITE) != WAIT_OBJECT_0)
6287
            {
6288
                PA_DEBUG(("StopStream: stream thread terminated\n"));
6289
                TerminateThread(stream->streamThread, -1);
6290
                result = paTimedOut;
6291
            }
6292
        }
6293
        else
6294
        {
6295
            PA_DEBUG(("StopStream: GECT says not active, but streamActive is not false ??"));
6296
            result = paUnanticipatedHostError;
6297
            PaWinWDM_SetLastErrorInfo(result, "StopStream: GECT says not active, but streamActive = %d", stream->streamActive);
6298
        }
6299
    }
6300
    else
6301
    {
6302
        if (stream->threadResult != paNoError)
6303
        {
6304
            PA_DEBUG(("StopStream: Stream not active (%d)\n", stream->threadResult));
6305
            result = stream->threadResult;
6306
            stream->threadResult = paNoError;
6307
        }
6308
    }
6309

    
6310
    if (stream->streamThread != NULL)
6311
    {
6312
        CloseHandle(stream->streamThread);
6313
        stream->streamThread = 0;
6314
    }
6315
    stream->streamStarted = 0;
6316
    stream->streamActive = 0;
6317

    
6318
    if(doCb)
6319
    {
6320
        /* Do user callback now after all state has been reset */
6321
        /* This means it should be safe for the called function */
6322
        /* to invoke e.g. StartStream */
6323
        if( stream->streamRepresentation.streamFinishedCallback != 0 )
6324
            stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
6325
    }
6326

    
6327
    PA_LOGL_;
6328
    return result;
6329
}
6330

    
6331
static PaError AbortStream( PaStream *s )
6332
{
6333
    PaError result = paNoError;
6334
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
6335
    int doCb = 0;
6336

    
6337
    PA_LOGE_;
6338

    
6339
    if(stream->streamActive)
6340
    {
6341
        doCb = 1;
6342
        stream->streamAbort = 1;
6343
        SetEvent(stream->eventAbort); /* Signal immediately */
6344
        if (WaitForSingleObject(stream->streamThread, 10000) != WAIT_OBJECT_0)
6345
        {
6346
            TerminateThread(stream->streamThread, -1);
6347
            result = paTimedOut;
6348

    
6349
            PA_DEBUG(("AbortStream: stream thread terminated\n"));
6350
        }
6351
        assert(!stream->streamActive);
6352
    }
6353
    CloseHandle(stream->streamThread);
6354
    stream->streamThread = NULL;
6355
    stream->streamStarted = 0;
6356

    
6357
    if(doCb)
6358
    {
6359
        /* Do user callback now after all state has been reset */
6360
        /* This means it should be safe for the called function */
6361
        /* to invoke e.g. StartStream */
6362
        if( stream->streamRepresentation.streamFinishedCallback != 0 )
6363
            stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
6364
    }
6365

    
6366
    stream->streamActive = 0;
6367
    stream->streamStarted = 0;
6368

    
6369
    PA_LOGL_;
6370
    return result;
6371
}
6372

    
6373

    
6374
static PaError IsStreamStopped( PaStream *s )
6375
{
6376
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
6377
    int result = 0;
6378

    
6379
    PA_LOGE_;
6380

    
6381
    if(!stream->streamStarted)
6382
        result = 1;
6383

    
6384
    PA_LOGL_;
6385
    return result;
6386
}
6387

    
6388

    
6389
static PaError IsStreamActive( PaStream *s )
6390
{
6391
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
6392
    int result = 0;
6393

    
6394
    PA_LOGE_;
6395

    
6396
    if(stream->streamActive)
6397
        result = 1;
6398

    
6399
    PA_LOGL_;
6400
    return result;
6401
}
6402

    
6403

    
6404
static PaTime GetStreamTime( PaStream* s )
6405
{
6406
    PA_LOGE_;
6407
    PA_LOGL_;
6408
    (void)s;
6409
    return PaUtil_GetTime();
6410
}
6411

    
6412

    
6413
static double GetStreamCpuLoad( PaStream* s )
6414
{
6415
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
6416
    double result;
6417
    PA_LOGE_;
6418
    result = PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
6419
    PA_LOGL_;
6420
    return result;
6421
}
6422

    
6423

    
6424
/*
6425
As separate stream interfaces are used for blocking and callback
6426
streams, the following functions can be guaranteed to only be called
6427
for blocking streams.
6428
*/
6429

    
6430
static PaError ReadStream( PaStream* s,
6431
                          void *buffer,
6432
                          unsigned long frames )
6433
{
6434
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
6435

    
6436
    PA_LOGE_;
6437

    
6438
    /* suppress unused variable warnings */
6439
    (void) buffer;
6440
    (void) frames;
6441
    (void) stream;
6442

    
6443
    /* IMPLEMENT ME, see portaudio.h for required behavior*/
6444
    PA_LOGL_;
6445
    return paInternalError;
6446
}
6447

    
6448

    
6449
static PaError WriteStream( PaStream* s,
6450
                           const void *buffer,
6451
                           unsigned long frames )
6452
{
6453
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
6454

    
6455
    PA_LOGE_;
6456

    
6457
    /* suppress unused variable warnings */
6458
    (void) buffer;
6459
    (void) frames;
6460
    (void) stream;
6461

    
6462
    /* IMPLEMENT ME, see portaudio.h for required behavior*/
6463
    PA_LOGL_;
6464
    return paInternalError;
6465
}
6466

    
6467

    
6468
static signed long GetStreamReadAvailable( PaStream* s )
6469
{
6470
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
6471

    
6472
    PA_LOGE_;
6473

    
6474
    /* suppress unused variable warnings */
6475
    (void) stream;
6476

    
6477
    /* IMPLEMENT ME, see portaudio.h for required behavior*/
6478
    PA_LOGL_;
6479
    return 0;
6480
}
6481

    
6482

    
6483
static signed long GetStreamWriteAvailable( PaStream* s )
6484
{
6485
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
6486

    
6487
    PA_LOGE_;
6488
    /* suppress unused variable warnings */
6489
    (void) stream;
6490

    
6491
    /* IMPLEMENT ME, see portaudio.h for required behavior*/
6492
    PA_LOGL_;
6493
    return 0;
6494
}
6495

    
6496
/***************************************************************************************/
6497
/* Event and submit handlers for WaveCyclic                                            */
6498
/***************************************************************************************/
6499

    
6500
static PaError PaPinCaptureEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6501
{
6502
    PaError result = paNoError;
6503
    ring_buffer_size_t frameCount;
6504
    DATAPACKET* packet = pInfo->stream->capture.packets + eventIndex;
6505

    
6506
    assert( eventIndex < pInfo->stream->capture.noOfPackets );
6507

    
6508
    if (packet->Header.DataUsed == 0)
6509
    {
6510
        PA_HP_TRACE((pInfo->stream->hLog, ">>> Capture bogus event (no data): idx=%u", eventIndex));
6511

    
6512
        /* 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 
6513
           on startup of streaming, where it erroneously sets the event without the corresponding buffer being filled (DataUsed == 0) */
6514
        ResetEvent(packet->Signal.hEvent);
6515

    
6516
        result = -1;    /* Only need this to be NOT paNoError */
6517
    }
6518
    else
6519
    {
6520
        pInfo->capturePackets[pInfo->captureHead & cPacketsArrayMask].packet = packet;
6521

    
6522
        frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer, packet->Header.Data, pInfo->stream->capture.framesPerBuffer);
6523

    
6524
        PA_HP_TRACE((pInfo->stream->hLog, ">>> Capture event: idx=%u (frames=%u)", eventIndex, frameCount));
6525
        ++pInfo->captureHead;
6526
    }
6527

    
6528
    --pInfo->pending; /* This needs to be done in either case */
6529
    return result;
6530
}
6531

    
6532
static PaError PaPinCaptureSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6533
{
6534
    PaError result = paNoError;
6535
    DATAPACKET* packet = pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet;
6536
    pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet = 0;
6537
    assert(packet != 0);
6538
    PA_HP_TRACE((pInfo->stream->hLog, "Capture submit: %u", eventIndex));
6539
    packet->Header.DataUsed = 0; /* Reset for reuse */
6540
    ResetEvent(packet->Signal.hEvent);
6541
    result = PinRead(pInfo->stream->capture.pPin->handle, packet);
6542
    ++pInfo->pending;
6543
    return result;
6544
}
6545

    
6546
static PaError PaPinRenderEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6547
{
6548
    assert( eventIndex < pInfo->stream->render.noOfPackets );
6549

    
6550
    pInfo->renderPackets[pInfo->renderHead & cPacketsArrayMask].packet = pInfo->stream->render.packets + eventIndex;
6551
    PA_HP_TRACE((pInfo->stream->hLog, "<<< Render event : idx=%u head=%u", eventIndex, pInfo->renderHead));
6552
    ++pInfo->renderHead;
6553
    --pInfo->pending;
6554
    return paNoError;
6555
}
6556

    
6557
static PaError PaPinRenderSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6558
{
6559
    PaError result = paNoError;
6560
    DATAPACKET* packet = pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet;
6561
    pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet = 0;
6562
    assert(packet != 0);
6563

    
6564
    PA_HP_TRACE((pInfo->stream->hLog, "Render submit : %u idx=%u", pInfo->renderTail, (unsigned)(packet - pInfo->stream->render.packets)));
6565
    ResetEvent(packet->Signal.hEvent);
6566
    result = PinWrite(pInfo->stream->render.pPin->handle, packet);
6567
    /* Reset event, just in case we have an analogous situation to capture (see PaPinCaptureSubmitHandler_WaveCyclic) */
6568
    ++pInfo->pending;
6569
    if (pInfo->priming)
6570
    {
6571
        --pInfo->priming;
6572
    }
6573
    return result;
6574
}
6575

    
6576
/***************************************************************************************/
6577
/* Event and submit handlers for WaveRT                                                */
6578
/***************************************************************************************/
6579

    
6580
static PaError PaPinCaptureEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6581
{
6582
    unsigned long pos;
6583
    unsigned realInBuf;
6584
    unsigned frameCount;
6585
    PaWinWdmIOInfo* pCapture = &pInfo->stream->capture;
6586
    const unsigned halfInputBuffer = pCapture->hostBufferSize >> 1;
6587
    PaWinWdmPin* pin = pCapture->pPin;
6588
    DATAPACKET* packet = 0;
6589

    
6590
    /* Get hold of current ADC position */
6591
    pin->fnAudioPosition(pin, &pos);
6592
    /* Wrap it (robi: why not use hw latency compensation here ?? because pos then gets _way_ off from
6593
    where it should be, i.e. at beginning or half buffer position. Why? No idea.)  */
6594

    
6595
    pos %= pCapture->hostBufferSize;
6596
    /* Then realInBuf will point to "other" half of double buffer */
6597
    realInBuf = pos < halfInputBuffer ? 1U : 0U;
6598

    
6599
    packet = pInfo->stream->capture.packets + realInBuf;
6600

    
6601
    /* Call barrier (or dummy) */
6602
    pin->fnMemBarrier();
6603

    
6604
    /* Put it in queue */
6605
    frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer, packet->Header.Data, pCapture->framesPerBuffer);
6606

    
6607
    pInfo->capturePackets[pInfo->captureHead & cPacketsArrayMask].packet = packet;
6608

    
6609
    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));
6610

    
6611
    ++pInfo->captureHead;
6612
    --pInfo->pending;
6613

    
6614
    return paNoError;
6615
}
6616

    
6617
static PaError PaPinCaptureEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6618
{
6619
    unsigned long pos;
6620
    unsigned bytesToRead;
6621
    PaWinWdmIOInfo* pCapture = &pInfo->stream->capture;
6622
    const unsigned halfInputBuffer = pCapture->hostBufferSize>>1;
6623
    PaWinWdmPin* pin = pInfo->stream->capture.pPin;
6624

    
6625
    /* Get hold of current ADC position */
6626
    pin->fnAudioPosition(pin, &pos);
6627
    /* Wrap it (robi: why not use hw latency compensation here ?? because pos then gets _way_ off from
6628
    where it should be, i.e. at beginning or half buffer position. Why? No idea.)  */
6629
    /* Compensate for HW FIFO to get to last read buffer position */
6630
    pos += pin->hwLatency;
6631
    pos %= pCapture->hostBufferSize;
6632
    /* Need to align position on frame boundary */
6633
    pos &= ~(pCapture->bytesPerFrame - 1);
6634

    
6635
    /* Call barrier (or dummy) */
6636
    pin->fnMemBarrier();
6637

    
6638
    /* Put it in "queue" */
6639
    bytesToRead = (pCapture->hostBufferSize + pos - pCapture->lastPosition) % pCapture->hostBufferSize;
6640
    if (bytesToRead > 0)
6641
    {
6642
        unsigned frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer,
6643
            pCapture->hostBuffer + pCapture->lastPosition,
6644
            bytesToRead / pCapture->bytesPerFrame);
6645

    
6646
        pCapture->lastPosition = (pCapture->lastPosition + frameCount * pCapture->bytesPerFrame) % pCapture->hostBufferSize;
6647

    
6648
        PA_HP_TRACE((pInfo->stream->hLog, "Capture event (WaveRTPolled): pos = %4.1lf%%, framesRead=%u", (pos * 100.0 / pCapture->hostBufferSize), frameCount));
6649
        ++pInfo->captureHead;
6650
        --pInfo->pending;
6651
    }
6652
    return paNoError;
6653
}
6654

    
6655
static PaError PaPinCaptureSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6656
{
6657
    pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet = 0;
6658
    ++pInfo->pending;
6659
    return paNoError;
6660
}
6661

    
6662
static PaError PaPinCaptureSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6663
{
6664
    pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet = 0;
6665
    ++pInfo->pending;
6666
    return paNoError;
6667
}
6668

    
6669
static PaError PaPinRenderEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6670
{
6671
    unsigned long pos;
6672
    unsigned realOutBuf;
6673
    PaWinWdmIOInfo* pRender = &pInfo->stream->render;
6674
    const unsigned halfOutputBuffer = pRender->hostBufferSize >> 1;
6675
    PaWinWdmPin* pin = pInfo->stream->render.pPin;
6676
    PaIOPacket* ioPacket = &pInfo->renderPackets[pInfo->renderHead & cPacketsArrayMask];
6677

    
6678
    /* Get hold of current DAC position */
6679
    pin->fnAudioPosition(pin, &pos);
6680
    /* Compensate for HW FIFO to get to last read buffer position */
6681
    pos += pin->hwLatency;
6682
    /* Wrap it */
6683
    pos %= pRender->hostBufferSize;
6684
    /* And align it, not sure its really needed though */
6685
    pos &= ~(pRender->bytesPerFrame - 1);
6686
    /* Then realOutBuf will point to "other" half of double buffer */
6687
    realOutBuf = pos < halfOutputBuffer ? 1U : 0U;
6688

    
6689
    if (pInfo->priming)
6690
    {
6691
        realOutBuf = pInfo->renderHead & 0x1;
6692
    }
6693
    ioPacket->packet = pInfo->stream->render.packets + realOutBuf;
6694
    ioPacket->startByte = realOutBuf * halfOutputBuffer;
6695
    ioPacket->lengthBytes = halfOutputBuffer;
6696

    
6697
    PA_HP_TRACE((pInfo->stream->hLog, "Render event (WaveRT) : idx=%u head=%u (pos = %4.1lf%%)", realOutBuf, pInfo->renderHead, (pos * 100.0 / pRender->hostBufferSize) ));
6698

    
6699
    ++pInfo->renderHead;
6700
    --pInfo->pending;
6701
    return paNoError;
6702
}
6703

    
6704
static PaError PaPinRenderEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6705
{
6706
    unsigned long pos;
6707
    unsigned realOutBuf;
6708
    unsigned bytesToWrite;
6709

    
6710
    PaWinWdmIOInfo* pRender = &pInfo->stream->render;
6711
    const unsigned halfOutputBuffer = pRender->hostBufferSize >> 1;
6712
    PaWinWdmPin* pin = pInfo->stream->render.pPin;
6713
    PaIOPacket* ioPacket = &pInfo->renderPackets[pInfo->renderHead & cPacketsArrayMask];
6714

    
6715
    /* Get hold of current DAC position */
6716
    pin->fnAudioPosition(pin, &pos);
6717
    /* Compensate for HW FIFO to get to last read buffer position */
6718
    pos += pin->hwLatency;
6719
    /* Wrap it */
6720
    pos %= pRender->hostBufferSize;
6721
    /* And align it, not sure its really needed though */
6722
    pos &= ~(pRender->bytesPerFrame - 1);
6723

    
6724
    if (pInfo->priming)
6725
    {
6726
        realOutBuf = pInfo->renderHead & 0x1;
6727
        ioPacket->packet = pInfo->stream->render.packets + realOutBuf;
6728
        ioPacket->startByte = realOutBuf * halfOutputBuffer;
6729
        ioPacket->lengthBytes = halfOutputBuffer;
6730
        ++pInfo->renderHead;
6731
        --pInfo->pending;
6732
    }
6733
    else
6734
    {
6735
        bytesToWrite = (pRender->hostBufferSize + pos - pRender->lastPosition) % pRender->hostBufferSize;
6736
        ++pRender->pollCntr;
6737
        if (bytesToWrite >= halfOutputBuffer)
6738
        {
6739
            realOutBuf = (pos < halfOutputBuffer) ? 1U : 0U;
6740
            ioPacket->packet = pInfo->stream->render.packets + realOutBuf;
6741
            pRender->lastPosition = realOutBuf ? 0U : halfOutputBuffer;
6742
            ioPacket->startByte = realOutBuf * halfOutputBuffer;
6743
            ioPacket->lengthBytes = halfOutputBuffer;
6744
            ++pInfo->renderHead;
6745
            --pInfo->pending;
6746
            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));
6747
            pRender->pollCntr = 0;
6748
        }
6749
    }
6750
    return paNoError;
6751
}
6752

    
6753
static PaError PaPinRenderSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6754
{
6755
    PaWinWdmPin* pin = pInfo->stream->render.pPin;
6756
    pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet = 0;
6757
    /* Call barrier (if needed) */
6758
    pin->fnMemBarrier();
6759
    PA_HP_TRACE((pInfo->stream->hLog, "Render submit (WaveRT) : submit=%u", pInfo->renderTail));
6760
    ++pInfo->pending;
6761
    if (pInfo->priming)
6762
    {
6763
        --pInfo->priming;
6764
        if (pInfo->priming)
6765
        {
6766
            PA_HP_TRACE((pInfo->stream->hLog, "Setting WaveRT event for priming (2)"));
6767
            SetEvent(pInfo->stream->render.events[0]);
6768
        }
6769
    }
6770
    return paNoError;
6771
}
6772

    
6773
static PaError PaPinRenderSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex)
6774
{
6775
    PaWinWdmPin* pin = pInfo->stream->render.pPin;
6776
    pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet = 0;
6777
    /* Call barrier (if needed) */
6778
    pin->fnMemBarrier();
6779
    PA_HP_TRACE((pInfo->stream->hLog, "Render submit (WaveRTPolled) : submit=%u", pInfo->renderTail));
6780
    ++pInfo->pending;
6781
    if (pInfo->priming)
6782
    {
6783
        --pInfo->priming;
6784
        if (pInfo->priming)
6785
        {
6786
            PA_HP_TRACE((pInfo->stream->hLog, "Setting WaveRT event for priming (2)"));
6787
            SetEvent(pInfo->stream->render.events[0]);
6788
        }
6789
    }
6790
    return paNoError;
6791
}