~registry/dolphin-emu/triforce

« back to all changes in this revision

Viewing changes to Externals/portaudio/src/hostapi/wdmks/pa_win_wdmks.c

  • Committer: Sérgio Benjamim
  • Date: 2015-02-13 05:54:40 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20150213055440-ey2rt3sjpy27km78
Dolphin Triforce branch from code.google, commit b957980 (4.0-315).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: pa_win_wdmks.c 1606 2011-02-17 15:56:04Z rob_bielik $
 
3
 * PortAudio Windows WDM-KS interface
 
4
 *
 
5
 * Author: Andrew Baldwin
 
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)
 
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
/* Debugging/tracing support */
 
56
 
 
57
#define PA_LOGE_
 
58
#define PA_LOGL_
 
59
 
 
60
#ifdef __GNUC__
 
61
    #include <initguid.h>
 
62
    #define _WIN32_WINNT 0x0501
 
63
    #define WINVER 0x0501
 
64
#endif
 
65
 
 
66
#include <string.h> /* strlen() */
 
67
#include <assert.h>
 
68
 
 
69
#include "pa_util.h"
 
70
#include "pa_allocation.h"
 
71
#include "pa_hostapi.h"
 
72
#include "pa_stream.h"
 
73
#include "pa_cpuload.h"
 
74
#include "pa_process.h"
 
75
#include "portaudio.h"
 
76
#include "pa_debugprint.h"
 
77
 
 
78
#include <windows.h>
 
79
#include <winioctl.h>
 
80
#include <process.h>
 
81
 
 
82
#ifdef __GNUC__
 
83
    #undef PA_LOGE_
 
84
    #define PA_LOGE_ PA_DEBUG(("%s {\n",__FUNCTION__))
 
85
    #undef PA_LOGL_
 
86
    #define PA_LOGL_ PA_DEBUG(("} %s\n",__FUNCTION__))
 
87
    /* These defines are set in order to allow the WIndows DirectX
 
88
     * headers to compile with a GCC compiler such as MinGW
 
89
     * NOTE: The headers may generate a few warning in GCC, but
 
90
     * they should compile */
 
91
    #define _INC_MMSYSTEM
 
92
    #define _INC_MMREG
 
93
    #define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */
 
94
    #define DEFINE_GUID_THUNK(name,guid) DEFINE_GUID(name,guid)
 
95
    #define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK( n, STATIC_##n )
 
96
    #if !defined( DEFINE_WAVEFORMATEX_GUID )
 
97
        #define DEFINE_WAVEFORMATEX_GUID(x) (USHORT)(x), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
 
98
    #endif
 
99
    #define  WAVE_FORMAT_ADPCM      0x0002
 
100
    #define  WAVE_FORMAT_IEEE_FLOAT 0x0003
 
101
    #define  WAVE_FORMAT_ALAW       0x0006
 
102
    #define  WAVE_FORMAT_MULAW      0x0007
 
103
    #define  WAVE_FORMAT_MPEG       0x0050
 
104
    #define  WAVE_FORMAT_DRM        0x0009
 
105
    #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}}
 
106
    #define DYNAMIC_GUID(data) DYNAMIC_GUID_THUNK(data)
 
107
#endif
 
108
 
 
109
#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */
 
110
#pragma comment( lib, "setupapi.lib" )
 
111
#endif
 
112
 
 
113
/* use CreateThread for CYGWIN, _beginthreadex for all others */
 
114
#ifndef __CYGWIN__
 
115
#define CREATE_THREAD (HANDLE)_beginthreadex( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId )
 
116
#else
 
117
#define CREATE_THREAD CreateThread( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId )
 
118
#endif
 
119
 
 
120
/* use ExitThread for CYGWIN, _endthreadex for all others */
 
121
#ifndef __CYGWIN__
 
122
#define EXIT_THREAD _endthreadex(0)
 
123
#else
 
124
#define EXIT_THREAD ExitThread(0)
 
125
#endif
 
126
 
 
127
#ifdef _MSC_VER
 
128
    #define NOMMIDS
 
129
    #define DYNAMIC_GUID(data) {data}
 
130
    #define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */
 
131
    #undef DEFINE_GUID
 
132
    #define DEFINE_GUID(n,data) EXTERN_C const GUID n = {data}
 
133
    #define DEFINE_GUID_THUNK(n,data) DEFINE_GUID(n,data)
 
134
    #define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK(n, STATIC_##n)
 
135
#endif
 
136
 
 
137
#include <mmreg.h>
 
138
#include <ks.h>
 
139
#include <ksmedia.h>
 
140
#include <tchar.h>
 
141
#include <assert.h>
 
142
#include <stdio.h>
 
143
 
 
144
/* These next definitions allow the use of the KSUSER DLL */
 
145
typedef KSDDKAPI DWORD WINAPI KSCREATEPIN(HANDLE, PKSPIN_CONNECT, ACCESS_MASK, PHANDLE);
 
146
extern HMODULE      DllKsUser;
 
147
extern KSCREATEPIN* FunctionKsCreatePin;
 
148
 
 
149
/* Forward definition to break circular type reference between pin and filter */
 
150
struct __PaWinWdmFilter;
 
151
typedef struct __PaWinWdmFilter PaWinWdmFilter;
 
152
 
 
153
/* The Pin structure
 
154
 * A pin is an input or output node, e.g. for audio flow */
 
155
typedef struct __PaWinWdmPin
 
156
{
 
157
    HANDLE                      handle;
 
158
    PaWinWdmFilter*             parentFilter;
 
159
    unsigned long               pinId;
 
160
    KSPIN_CONNECT*              pinConnect;
 
161
    unsigned long               pinConnectSize;
 
162
    KSDATAFORMAT_WAVEFORMATEX*  ksDataFormatWfx;
 
163
    KSPIN_COMMUNICATION         communication;
 
164
    KSDATARANGE*                dataRanges;
 
165
    KSMULTIPLE_ITEM*            dataRangesItem;
 
166
    KSPIN_DATAFLOW              dataFlow;
 
167
    KSPIN_CINSTANCES            instances;
 
168
    unsigned long               frameSize;
 
169
    int                         maxChannels;
 
170
    unsigned long               formats;
 
171
    int                         bestSampleRate;
 
172
}
 
173
PaWinWdmPin;
 
174
 
 
175
/* The Filter structure
 
176
 * A filter has a number of pins and a "friendly name" */
 
177
struct __PaWinWdmFilter
 
178
{
 
179
    HANDLE         handle;
 
180
    int            pinCount;
 
181
    PaWinWdmPin**  pins;
 
182
    TCHAR          filterName[MAX_PATH];
 
183
    TCHAR          friendlyName[MAX_PATH];
 
184
    int            maxInputChannels;
 
185
    int            maxOutputChannels;
 
186
    unsigned long  formats;
 
187
    int            usageCount;
 
188
    int            bestSampleRate;
 
189
};
 
190
 
 
191
/* PaWinWdmHostApiRepresentation - host api datastructure specific to this implementation */
 
192
typedef struct __PaWinWdmHostApiRepresentation
 
193
{
 
194
    PaUtilHostApiRepresentation  inheritedHostApiRep;
 
195
    PaUtilStreamInterface        callbackStreamInterface;
 
196
    PaUtilStreamInterface        blockingStreamInterface;
 
197
 
 
198
    PaUtilAllocationGroup*       allocations;
 
199
    PaWinWdmFilter**             filters;
 
200
    int                          filterCount;
 
201
}
 
202
PaWinWdmHostApiRepresentation;
 
203
 
 
204
typedef struct __PaWinWdmDeviceInfo
 
205
{
 
206
    PaDeviceInfo     inheritedDeviceInfo;
 
207
    PaWinWdmFilter*  filter;
 
208
}
 
209
PaWinWdmDeviceInfo;
 
210
 
 
211
typedef struct __DATAPACKET
 
212
{
 
213
    KSSTREAM_HEADER  Header;
 
214
    OVERLAPPED       Signal;
 
215
} DATAPACKET;
 
216
 
 
217
/* PaWinWdmStream - a stream data structure specifically for this implementation */
 
218
typedef struct __PaWinWdmStream
 
219
{
 
220
    PaUtilStreamRepresentation  streamRepresentation;
 
221
    PaUtilCpuLoadMeasurer       cpuLoadMeasurer;
 
222
    PaUtilBufferProcessor       bufferProcessor;
 
223
 
 
224
    PaWinWdmPin*                recordingPin;
 
225
    PaWinWdmPin*                playbackPin;
 
226
    char*                       hostBuffer;
 
227
    unsigned long               framesPerHostIBuffer;
 
228
    unsigned long               framesPerHostOBuffer;
 
229
    int                         bytesPerInputFrame;
 
230
    int                         bytesPerOutputFrame;
 
231
    int                         streamStarted;
 
232
    int                         streamActive;
 
233
    int                         streamStop;
 
234
    int                         streamAbort;
 
235
    int                         oldProcessPriority;
 
236
    HANDLE                      streamThread;
 
237
    HANDLE                      events[5];  /* 2 play + 2 record packets + abort events */
 
238
    DATAPACKET                  packets[4]; /* 2 play + 2 record */
 
239
    PaStreamFlags               streamFlags;
 
240
    /* These values handle the case where the user wants to use fewer
 
241
     * channels than the device has */
 
242
    int                         userInputChannels;
 
243
    int                         deviceInputChannels;
 
244
    int                         userOutputChannels;
 
245
    int                         deviceOutputChannels;
 
246
    int                         inputSampleSize;
 
247
    int                         outputSampleSize;
 
248
}
 
249
PaWinWdmStream;
 
250
 
 
251
#include <setupapi.h>
 
252
 
 
253
HMODULE      DllKsUser = NULL;
 
254
KSCREATEPIN* FunctionKsCreatePin = NULL;
 
255
 
 
256
/* prototypes for functions declared in this file */
 
257
 
 
258
#ifdef __cplusplus
 
259
extern "C"
 
260
{
 
261
#endif /* __cplusplus */
 
262
 
 
263
PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
 
264
 
 
265
#ifdef __cplusplus
 
266
}
 
267
#endif /* __cplusplus */
 
268
 
 
269
/* Low level I/O functions */
 
270
static PaError WdmSyncIoctl(HANDLE handle,
 
271
    unsigned long ioctlNumber,
 
272
    void* inBuffer,
 
273
    unsigned long inBufferCount,
 
274
    void* outBuffer,
 
275
    unsigned long outBufferCount,
 
276
    unsigned long* bytesReturned);
 
277
static PaError WdmGetPropertySimple(HANDLE handle,
 
278
    const GUID* const guidPropertySet,
 
279
    unsigned long property,
 
280
    void* value,
 
281
    unsigned long valueCount,
 
282
    void* instance,
 
283
    unsigned long instanceCount);
 
284
static PaError WdmSetPropertySimple(HANDLE handle,
 
285
    const GUID* const guidPropertySet,
 
286
    unsigned long property,
 
287
    void* value,
 
288
    unsigned long valueCount,
 
289
    void* instance,
 
290
    unsigned long instanceCount);
 
291
static PaError WdmGetPinPropertySimple(HANDLE  handle,
 
292
    unsigned long pinId,
 
293
    const GUID* const guidPropertySet,
 
294
    unsigned long property,
 
295
    void* value,
 
296
    unsigned long valueCount);
 
297
static PaError WdmGetPinPropertyMulti(HANDLE  handle,
 
298
    unsigned long pinId,
 
299
    const GUID* const guidPropertySet,
 
300
    unsigned long property,
 
301
    KSMULTIPLE_ITEM** ksMultipleItem);
 
302
 
 
303
/** Pin management functions */
 
304
static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, PaError* error);
 
305
static void PinFree(PaWinWdmPin* pin);
 
306
static void PinClose(PaWinWdmPin* pin);
 
307
static PaError PinInstantiate(PaWinWdmPin* pin);
 
308
/*static PaError PinGetState(PaWinWdmPin* pin, KSSTATE* state); NOT USED */
 
309
static PaError PinSetState(PaWinWdmPin* pin, KSSTATE state);
 
310
static PaError PinSetFormat(PaWinWdmPin* pin, const WAVEFORMATEX* format);
 
311
static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format);
 
312
 
 
313
/* Filter management functions */
 
314
static PaWinWdmFilter* FilterNew(
 
315
    TCHAR* filterName,
 
316
    TCHAR* friendlyName,
 
317
    PaError* error);
 
318
static void FilterFree(PaWinWdmFilter* filter);
 
319
static PaWinWdmPin* FilterCreateRenderPin(
 
320
    PaWinWdmFilter* filter,
 
321
    const WAVEFORMATEX* wfex,
 
322
    PaError* error);
 
323
static PaWinWdmPin* FilterFindViableRenderPin(
 
324
    PaWinWdmFilter* filter,
 
325
    const WAVEFORMATEX* wfex,
 
326
    PaError* error);
 
327
static PaError FilterCanCreateRenderPin(
 
328
    PaWinWdmFilter* filter,
 
329
    const WAVEFORMATEX* wfex);
 
330
static PaWinWdmPin* FilterCreateCapturePin(
 
331
    PaWinWdmFilter* filter,
 
332
    const WAVEFORMATEX* wfex,
 
333
    PaError* error);
 
334
static PaWinWdmPin* FilterFindViableCapturePin(
 
335
    PaWinWdmFilter* filter,
 
336
    const WAVEFORMATEX* wfex,
 
337
    PaError* error);
 
338
static PaError FilterCanCreateCapturePin(
 
339
    PaWinWdmFilter* filter,
 
340
    const WAVEFORMATEX* pwfx);
 
341
static PaError FilterUse(
 
342
    PaWinWdmFilter* filter);
 
343
static void FilterRelease(
 
344
    PaWinWdmFilter* filter);
 
345
 
 
346
/* Interface functions */
 
347
static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
 
348
static PaError IsFormatSupported(
 
349
    struct PaUtilHostApiRepresentation *hostApi,
 
350
    const PaStreamParameters *inputParameters,
 
351
    const PaStreamParameters *outputParameters,
 
352
    double sampleRate );
 
353
static PaError OpenStream(
 
354
    struct PaUtilHostApiRepresentation *hostApi,
 
355
    PaStream** s,
 
356
    const PaStreamParameters *inputParameters,
 
357
    const PaStreamParameters *outputParameters,
 
358
    double sampleRate,
 
359
    unsigned long framesPerBuffer,
 
360
    PaStreamFlags streamFlags,
 
361
    PaStreamCallback *streamCallback,
 
362
    void *userData );
 
363
static PaError CloseStream( PaStream* stream );
 
364
static PaError StartStream( PaStream *stream );
 
365
static PaError StopStream( PaStream *stream );
 
366
static PaError AbortStream( PaStream *stream );
 
367
static PaError IsStreamStopped( PaStream *s );
 
368
static PaError IsStreamActive( PaStream *stream );
 
369
static PaTime GetStreamTime( PaStream *stream );
 
370
static double GetStreamCpuLoad( PaStream* stream );
 
371
static PaError ReadStream(
 
372
    PaStream* stream,
 
373
    void *buffer,
 
374
    unsigned long frames );
 
375
static PaError WriteStream(
 
376
    PaStream* stream,
 
377
    const void *buffer,
 
378
    unsigned long frames );
 
379
static signed long GetStreamReadAvailable( PaStream* stream );
 
380
static signed long GetStreamWriteAvailable( PaStream* stream );
 
381
 
 
382
/* Utility functions */
 
383
static unsigned long GetWfexSize(const WAVEFORMATEX* wfex);
 
384
static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi);
 
385
static BOOL PinWrite(HANDLE h, DATAPACKET* p);
 
386
static BOOL PinRead(HANDLE h, DATAPACKET* p);
 
387
static void DuplicateFirstChannelInt16(void* buffer, int channels, int samples);
 
388
static void DuplicateFirstChannelInt24(void* buffer, int channels, int samples);
 
389
static DWORD WINAPI ProcessingThread(LPVOID pParam);
 
390
 
 
391
/* Function bodies */
 
392
 
 
393
static unsigned long GetWfexSize(const WAVEFORMATEX* wfex)
 
394
{
 
395
    if( wfex->wFormatTag == WAVE_FORMAT_PCM )
 
396
    {
 
397
        return sizeof( WAVEFORMATEX );
 
398
    }
 
399
    else
 
400
    {
 
401
        return (sizeof( WAVEFORMATEX ) + wfex->cbSize);
 
402
    }
 
403
}
 
404
 
 
405
/*
 
406
Low level pin/filter access functions
 
407
*/
 
408
static PaError WdmSyncIoctl(
 
409
    HANDLE handle,
 
410
    unsigned long ioctlNumber,
 
411
    void* inBuffer,
 
412
    unsigned long inBufferCount,
 
413
    void* outBuffer,
 
414
    unsigned long outBufferCount,
 
415
    unsigned long* bytesReturned)
 
416
{
 
417
    PaError result = paNoError;
 
418
    OVERLAPPED overlapped;
 
419
    int boolResult;
 
420
    unsigned long dummyBytesReturned;
 
421
    unsigned long error;
 
422
 
 
423
    if( !bytesReturned )
 
424
    {
 
425
        /* User a dummy as the caller hasn't supplied one */
 
426
        bytesReturned = &dummyBytesReturned;
 
427
    }
 
428
 
 
429
    FillMemory((void *)&overlapped,sizeof(overlapped),0);
 
430
    overlapped.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
 
431
    if( !overlapped.hEvent )
 
432
    {
 
433
          result = paInsufficientMemory;
 
434
        goto error;
 
435
    }
 
436
    overlapped.hEvent = (HANDLE)((DWORD_PTR)overlapped.hEvent | 0x1);
 
437
 
 
438
    boolResult = DeviceIoControl(handle, ioctlNumber, inBuffer, inBufferCount,
 
439
        outBuffer, outBufferCount, bytesReturned, &overlapped);
 
440
    if( !boolResult )
 
441
    {
 
442
        error = GetLastError();
 
443
        if( error == ERROR_IO_PENDING )
 
444
        {
 
445
            error = WaitForSingleObject(overlapped.hEvent,INFINITE);
 
446
            if( error != WAIT_OBJECT_0 )
 
447
            {
 
448
                result = paUnanticipatedHostError;
 
449
                goto error;
 
450
            }
 
451
        }
 
452
        else if((( error == ERROR_INSUFFICIENT_BUFFER ) ||
 
453
                  ( error == ERROR_MORE_DATA )) &&
 
454
                  ( ioctlNumber == IOCTL_KS_PROPERTY ) &&
 
455
                  ( outBufferCount == 0 ))
 
456
        {
 
457
            boolResult = TRUE;
 
458
        }
 
459
        else
 
460
        {
 
461
            result = paUnanticipatedHostError;
 
462
        }
 
463
    }
 
464
    if( !boolResult )
 
465
        *bytesReturned = 0;
 
466
 
 
467
error:
 
468
    if( overlapped.hEvent )
 
469
    {
 
470
            CloseHandle( overlapped.hEvent );
 
471
    }
 
472
    return result;
 
473
}
 
474
 
 
475
static PaError WdmGetPropertySimple(HANDLE handle,
 
476
    const GUID* const guidPropertySet,
 
477
    unsigned long property,
 
478
    void* value,
 
479
    unsigned long valueCount,
 
480
    void* instance,
 
481
    unsigned long instanceCount)
 
482
{
 
483
    PaError result;
 
484
    KSPROPERTY* ksProperty;
 
485
    unsigned long propertyCount;
 
486
 
 
487
    propertyCount = sizeof(KSPROPERTY) + instanceCount;
 
488
    ksProperty = (KSPROPERTY*)PaUtil_AllocateMemory( propertyCount );
 
489
    if( !ksProperty )
 
490
    {
 
491
        return paInsufficientMemory;
 
492
    }
 
493
 
 
494
    FillMemory((void*)ksProperty,sizeof(ksProperty),0);
 
495
    ksProperty->Set = *guidPropertySet;
 
496
    ksProperty->Id = property;
 
497
    ksProperty->Flags = KSPROPERTY_TYPE_GET;
 
498
 
 
499
    if( instance )
 
500
    {
 
501
        memcpy( (void*)(((char*)ksProperty)+sizeof(KSPROPERTY)), instance, instanceCount );
 
502
    }
 
503
 
 
504
    result = WdmSyncIoctl(
 
505
                handle,
 
506
                IOCTL_KS_PROPERTY,
 
507
                ksProperty,
 
508
                propertyCount,
 
509
                value,
 
510
                valueCount,
 
511
                NULL);
 
512
 
 
513
    PaUtil_FreeMemory( ksProperty );
 
514
    return result;
 
515
}
 
516
 
 
517
static PaError WdmSetPropertySimple(
 
518
    HANDLE handle,
 
519
    const GUID* const guidPropertySet,
 
520
    unsigned long property,
 
521
    void* value,
 
522
    unsigned long valueCount,
 
523
    void* instance,
 
524
    unsigned long instanceCount)
 
525
{
 
526
    PaError result;
 
527
    KSPROPERTY* ksProperty;
 
528
    unsigned long propertyCount  = 0;
 
529
 
 
530
    propertyCount = sizeof(KSPROPERTY) + instanceCount;
 
531
    ksProperty = (KSPROPERTY*)PaUtil_AllocateMemory( propertyCount );
 
532
    if( !ksProperty )
 
533
    {
 
534
        return paInsufficientMemory;
 
535
    }
 
536
 
 
537
    ksProperty->Set = *guidPropertySet;
 
538
    ksProperty->Id = property;
 
539
    ksProperty->Flags = KSPROPERTY_TYPE_SET;
 
540
 
 
541
    if( instance )
 
542
    {
 
543
        memcpy((void*)((char*)ksProperty + sizeof(KSPROPERTY)), instance, instanceCount);
 
544
    }
 
545
 
 
546
    result = WdmSyncIoctl(
 
547
                handle,
 
548
                IOCTL_KS_PROPERTY,
 
549
                ksProperty,
 
550
                propertyCount,
 
551
                value,
 
552
                valueCount,
 
553
                NULL);
 
554
 
 
555
    PaUtil_FreeMemory( ksProperty );
 
556
    return result;
 
557
}
 
558
 
 
559
static PaError WdmGetPinPropertySimple(
 
560
    HANDLE  handle,
 
561
    unsigned long pinId,
 
562
    const GUID* const guidPropertySet,
 
563
    unsigned long property,
 
564
    void* value,
 
565
    unsigned long valueCount)
 
566
{
 
567
    PaError result;
 
568
 
 
569
    KSP_PIN ksPProp;
 
570
    ksPProp.Property.Set = *guidPropertySet;
 
571
    ksPProp.Property.Id = property;
 
572
    ksPProp.Property.Flags = KSPROPERTY_TYPE_GET;
 
573
    ksPProp.PinId = pinId;
 
574
    ksPProp.Reserved = 0;
 
575
 
 
576
    result = WdmSyncIoctl(
 
577
                handle,
 
578
                IOCTL_KS_PROPERTY,
 
579
                &ksPProp,
 
580
                sizeof(KSP_PIN),
 
581
                value,
 
582
                valueCount,
 
583
                NULL);
 
584
 
 
585
    return result;
 
586
}
 
587
 
 
588
static PaError WdmGetPinPropertyMulti(
 
589
    HANDLE handle,
 
590
    unsigned long pinId,
 
591
    const GUID* const guidPropertySet,
 
592
    unsigned long property,
 
593
    KSMULTIPLE_ITEM** ksMultipleItem)
 
594
{
 
595
    PaError result;
 
596
    unsigned long multipleItemSize = 0;
 
597
    KSP_PIN ksPProp;
 
598
 
 
599
    ksPProp.Property.Set = *guidPropertySet;
 
600
    ksPProp.Property.Id = property;
 
601
    ksPProp.Property.Flags = KSPROPERTY_TYPE_GET;
 
602
    ksPProp.PinId = pinId;
 
603
    ksPProp.Reserved = 0;
 
604
 
 
605
    result = WdmSyncIoctl(
 
606
                handle,
 
607
                IOCTL_KS_PROPERTY,
 
608
                &ksPProp.Property,
 
609
                sizeof(KSP_PIN),
 
610
                NULL,
 
611
                0,
 
612
                &multipleItemSize);
 
613
    if( result != paNoError )
 
614
    {
 
615
        return result;
 
616
    }
 
617
 
 
618
    *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize );
 
619
    if( !*ksMultipleItem )
 
620
    {
 
621
        return paInsufficientMemory;
 
622
    }
 
623
 
 
624
    result = WdmSyncIoctl(
 
625
                handle,
 
626
                IOCTL_KS_PROPERTY,
 
627
                &ksPProp,
 
628
                sizeof(KSP_PIN),
 
629
                (void*)*ksMultipleItem,
 
630
                multipleItemSize,
 
631
                NULL);
 
632
 
 
633
    if( result != paNoError )
 
634
    {
 
635
        PaUtil_FreeMemory( ksMultipleItem );
 
636
    }
 
637
 
 
638
    return result;
 
639
}
 
640
 
 
641
 
 
642
/*
 
643
Create a new pin object belonging to a filter
 
644
The pin object holds all the configuration information about the pin
 
645
before it is opened, and then the handle of the pin after is opened
 
646
*/
 
647
static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, PaError* error)
 
648
{
 
649
    PaWinWdmPin* pin;
 
650
    PaError result;
 
651
    unsigned long i;
 
652
    KSMULTIPLE_ITEM* item = NULL;
 
653
    KSIDENTIFIER* identifier;
 
654
    KSDATARANGE* dataRange;
 
655
 
 
656
    PA_LOGE_;
 
657
    PA_DEBUG(("Creating pin %d:\n",pinId));
 
658
 
 
659
    /* Allocate the new PIN object */
 
660
    pin = (PaWinWdmPin*)PaUtil_AllocateMemory( sizeof(PaWinWdmPin) );
 
661
    if( !pin )
 
662
    {
 
663
        result = paInsufficientMemory;
 
664
        goto error;
 
665
    }
 
666
 
 
667
    /* Zero the pin object */
 
668
    /* memset( (void*)pin, 0, sizeof(PaWinWdmPin) ); */
 
669
 
 
670
    pin->parentFilter = parentFilter;
 
671
    pin->pinId = pinId;
 
672
 
 
673
    /* Allocate a connect structure */
 
674
    pin->pinConnectSize = sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX);
 
675
    pin->pinConnect = (KSPIN_CONNECT*)PaUtil_AllocateMemory( pin->pinConnectSize );
 
676
    if( !pin->pinConnect )
 
677
    {
 
678
        result = paInsufficientMemory;
 
679
        goto error;
 
680
    }
 
681
 
 
682
    /* Configure the connect structure with default values */
 
683
    pin->pinConnect->Interface.Set               = KSINTERFACESETID_Standard;
 
684
    pin->pinConnect->Interface.Id                = KSINTERFACE_STANDARD_STREAMING;
 
685
    pin->pinConnect->Interface.Flags             = 0;
 
686
    pin->pinConnect->Medium.Set                  = KSMEDIUMSETID_Standard;
 
687
    pin->pinConnect->Medium.Id                   = KSMEDIUM_TYPE_ANYINSTANCE;
 
688
    pin->pinConnect->Medium.Flags                = 0;
 
689
    pin->pinConnect->PinId                       = pinId;
 
690
    pin->pinConnect->PinToHandle                 = NULL;
 
691
    pin->pinConnect->Priority.PriorityClass      = KSPRIORITY_NORMAL;
 
692
    pin->pinConnect->Priority.PrioritySubClass   = 1;
 
693
    pin->ksDataFormatWfx = (KSDATAFORMAT_WAVEFORMATEX*)(pin->pinConnect + 1);
 
694
    pin->ksDataFormatWfx->DataFormat.FormatSize  = sizeof(KSDATAFORMAT_WAVEFORMATEX);
 
695
    pin->ksDataFormatWfx->DataFormat.Flags       = 0;
 
696
    pin->ksDataFormatWfx->DataFormat.Reserved    = 0;
 
697
    pin->ksDataFormatWfx->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
 
698
    pin->ksDataFormatWfx->DataFormat.SubFormat   = KSDATAFORMAT_SUBTYPE_PCM;
 
699
    pin->ksDataFormatWfx->DataFormat.Specifier   = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
 
700
 
 
701
    pin->frameSize = 0; /* Unknown until we instantiate pin */
 
702
 
 
703
    /* Get the COMMUNICATION property */
 
704
    result = WdmGetPinPropertySimple(
 
705
        parentFilter->handle,
 
706
        pinId,
 
707
        &KSPROPSETID_Pin,
 
708
        KSPROPERTY_PIN_COMMUNICATION,
 
709
        &pin->communication,
 
710
        sizeof(KSPIN_COMMUNICATION));
 
711
    if( result != paNoError )
 
712
        goto error;
 
713
 
 
714
    if( /*(pin->communication != KSPIN_COMMUNICATION_SOURCE) &&*/
 
715
         (pin->communication != KSPIN_COMMUNICATION_SINK) &&
 
716
         (pin->communication != KSPIN_COMMUNICATION_BOTH) )
 
717
    {
 
718
        PA_DEBUG(("Not source/sink\n"));
 
719
        result = paInvalidDevice;
 
720
        goto error;
 
721
    }
 
722
 
 
723
    /* Get dataflow information */
 
724
    result = WdmGetPinPropertySimple(
 
725
        parentFilter->handle,
 
726
        pinId,
 
727
        &KSPROPSETID_Pin,
 
728
        KSPROPERTY_PIN_DATAFLOW,
 
729
        &pin->dataFlow,
 
730
        sizeof(KSPIN_DATAFLOW));
 
731
 
 
732
    if( result != paNoError )
 
733
        goto error;
 
734
 
 
735
    /* Get the INTERFACE property list */
 
736
    result = WdmGetPinPropertyMulti(
 
737
        parentFilter->handle,
 
738
        pinId,
 
739
        &KSPROPSETID_Pin,
 
740
        KSPROPERTY_PIN_INTERFACES,
 
741
        &item);
 
742
 
 
743
    if( result != paNoError )
 
744
        goto error;
 
745
 
 
746
    identifier = (KSIDENTIFIER*)(item+1);
 
747
 
 
748
    /* Check that at least one interface is STANDARD_STREAMING */
 
749
    result = paUnanticipatedHostError;
 
750
    for( i = 0; i < item->Count; i++ )
 
751
    {
 
752
        if( !memcmp( (void*)&identifier[i].Set, (void*)&KSINTERFACESETID_Standard, sizeof( GUID ) ) &&
 
753
            ( identifier[i].Id == KSINTERFACE_STANDARD_STREAMING ) )
 
754
        {
 
755
            result = paNoError;
 
756
            break;
 
757
        }
 
758
    }
 
759
 
 
760
    if( result != paNoError )
 
761
    {
 
762
        PA_DEBUG(("No standard streaming\n"));
 
763
        goto error;
 
764
    }
 
765
 
 
766
    /* Don't need interfaces any more */
 
767
    PaUtil_FreeMemory( item );
 
768
    item = NULL;
 
769
 
 
770
    /* Get the MEDIUM properties list */
 
771
    result = WdmGetPinPropertyMulti(
 
772
        parentFilter->handle,
 
773
        pinId,
 
774
        &KSPROPSETID_Pin,
 
775
        KSPROPERTY_PIN_MEDIUMS,
 
776
        &item);
 
777
 
 
778
    if( result != paNoError )
 
779
        goto error;
 
780
 
 
781
    identifier = (KSIDENTIFIER*)(item+1); /* Not actually necessary... */
 
782
 
 
783
    /* Check that at least one medium is STANDARD_DEVIO */
 
784
    result = paUnanticipatedHostError;
 
785
    for( i = 0; i < item->Count; i++ )
 
786
    {
 
787
        if( !memcmp( (void*)&identifier[i].Set, (void*)&KSMEDIUMSETID_Standard, sizeof( GUID ) ) &&
 
788
           ( identifier[i].Id == KSMEDIUM_STANDARD_DEVIO ) )
 
789
        {
 
790
            result = paNoError;
 
791
            break;
 
792
        }
 
793
    }
 
794
 
 
795
    if( result != paNoError )
 
796
    {
 
797
        PA_DEBUG(("No standard devio\n"));
 
798
        goto error;
 
799
    }
 
800
    /* Don't need mediums any more */
 
801
    PaUtil_FreeMemory( item );
 
802
    item = NULL;
 
803
 
 
804
    /* Get DATARANGES */
 
805
    result = WdmGetPinPropertyMulti(
 
806
        parentFilter->handle,
 
807
        pinId,
 
808
        &KSPROPSETID_Pin,
 
809
        KSPROPERTY_PIN_DATARANGES,
 
810
        &pin->dataRangesItem);
 
811
 
 
812
    if( result != paNoError )
 
813
        goto error;
 
814
 
 
815
    pin->dataRanges = (KSDATARANGE*)(pin->dataRangesItem +1);
 
816
 
 
817
    /* Check that at least one datarange supports audio */
 
818
    result = paUnanticipatedHostError;
 
819
    dataRange = pin->dataRanges;
 
820
    pin->maxChannels = 0;
 
821
    pin->bestSampleRate = 0;
 
822
    pin->formats = 0;
 
823
    for( i = 0; i <pin->dataRangesItem->Count; i++)
 
824
    {
 
825
        PA_DEBUG(("DR major format %x\n",*(unsigned long*)(&(dataRange->MajorFormat))));
 
826
        /* Check that subformat is WAVEFORMATEX, PCM or WILDCARD */
 
827
        if( IS_VALID_WAVEFORMATEX_GUID(&dataRange->SubFormat) ||
 
828
            !memcmp((void*)&dataRange->SubFormat, (void*)&KSDATAFORMAT_SUBTYPE_PCM, sizeof ( GUID ) ) ||
 
829
            ( !memcmp((void*)&dataRange->SubFormat, (void*)&KSDATAFORMAT_SUBTYPE_WILDCARD, sizeof ( GUID ) ) &&
 
830
            ( !memcmp((void*)&dataRange->MajorFormat, (void*)&KSDATAFORMAT_TYPE_AUDIO, sizeof ( GUID ) ) ) ) )
 
831
        {
 
832
            result = paNoError;
 
833
            /* Record the maximum possible channels with this pin */
 
834
            PA_DEBUG(("MaxChannel: %d\n",pin->maxChannels));
 
835
            if( (int)((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels > pin->maxChannels )
 
836
            {
 
837
                pin->maxChannels = ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels;
 
838
                /*PA_DEBUG(("MaxChannel: %d\n",pin->maxChannels));*/
 
839
            }
 
840
            /* Record the formats (bit depths) that are supported */
 
841
            if( ((KSDATARANGE_AUDIO*)dataRange)->MinimumBitsPerSample <= 16 )
 
842
            {
 
843
                pin->formats |= paInt16;
 
844
                PA_DEBUG(("Format 16 bit supported\n"));
 
845
            }
 
846
            if( ((KSDATARANGE_AUDIO*)dataRange)->MaximumBitsPerSample >= 24 )
 
847
            {
 
848
                pin->formats |= paInt24;
 
849
                PA_DEBUG(("Format 24 bit supported\n"));
 
850
            }
 
851
            if( ( pin->bestSampleRate != 48000) &&
 
852
                (((KSDATARANGE_AUDIO*)dataRange)->MaximumSampleFrequency >= 48000) &&
 
853
                (((KSDATARANGE_AUDIO*)dataRange)->MinimumSampleFrequency <= 48000) )
 
854
            {
 
855
                pin->bestSampleRate = 48000;
 
856
                PA_DEBUG(("48kHz supported\n"));
 
857
            }
 
858
            else if(( pin->bestSampleRate != 48000) && ( pin->bestSampleRate != 44100 ) &&
 
859
                (((KSDATARANGE_AUDIO*)dataRange)->MaximumSampleFrequency >= 44100) &&
 
860
                (((KSDATARANGE_AUDIO*)dataRange)->MinimumSampleFrequency <= 44100) )
 
861
            {
 
862
                pin->bestSampleRate = 44100;
 
863
                PA_DEBUG(("44.1kHz supported\n"));
 
864
            }
 
865
            else
 
866
            {
 
867
                pin->bestSampleRate = ((KSDATARANGE_AUDIO*)dataRange)->MaximumSampleFrequency;
 
868
            }
 
869
        }
 
870
        dataRange = (KSDATARANGE*)( ((char*)dataRange) + dataRange->FormatSize);
 
871
    }
 
872
 
 
873
    if( result != paNoError )
 
874
        goto error;
 
875
 
 
876
    /* Get instance information */
 
877
    result = WdmGetPinPropertySimple(
 
878
        parentFilter->handle,
 
879
        pinId,
 
880
        &KSPROPSETID_Pin,
 
881
        KSPROPERTY_PIN_CINSTANCES,
 
882
        &pin->instances,
 
883
        sizeof(KSPIN_CINSTANCES));
 
884
 
 
885
    if( result != paNoError )
 
886
        goto error;
 
887
 
 
888
    /* Success */
 
889
    *error = paNoError;
 
890
    PA_DEBUG(("Pin created successfully\n"));
 
891
    PA_LOGL_;
 
892
    return pin;
 
893
 
 
894
error:
 
895
    /*
 
896
    Error cleanup
 
897
    */
 
898
    PaUtil_FreeMemory( item );
 
899
    if( pin )
 
900
    {
 
901
        PaUtil_FreeMemory( pin->pinConnect );
 
902
        PaUtil_FreeMemory( pin->dataRangesItem );
 
903
        PaUtil_FreeMemory( pin );
 
904
    }
 
905
    *error = result;
 
906
    PA_LOGL_;
 
907
    return NULL;
 
908
}
 
909
 
 
910
/*
 
911
Safely free all resources associated with the pin
 
912
*/
 
913
static void PinFree(PaWinWdmPin* pin)
 
914
{
 
915
    PA_LOGE_;
 
916
    if( pin )
 
917
    {
 
918
        PinClose(pin);
 
919
        if( pin->pinConnect )
 
920
        {
 
921
            PaUtil_FreeMemory( pin->pinConnect );
 
922
        }
 
923
        if( pin->dataRangesItem )
 
924
        {
 
925
            PaUtil_FreeMemory( pin->dataRangesItem );
 
926
        }
 
927
        PaUtil_FreeMemory( pin );
 
928
    }
 
929
    PA_LOGL_;
 
930
}
 
931
 
 
932
/*
 
933
If the pin handle is open, close it
 
934
*/
 
935
static void PinClose(PaWinWdmPin* pin)
 
936
{
 
937
    PA_LOGE_;
 
938
    if( pin == NULL )
 
939
    {
 
940
        PA_DEBUG(("Closing NULL pin!"));
 
941
        PA_LOGL_;
 
942
        return;
 
943
    }
 
944
    if( pin->handle != NULL )
 
945
    {
 
946
        PinSetState( pin, KSSTATE_PAUSE );
 
947
        PinSetState( pin, KSSTATE_STOP );
 
948
        CloseHandle( pin->handle );
 
949
        pin->handle = NULL;
 
950
        FilterRelease(pin->parentFilter);
 
951
    }
 
952
    PA_LOGL_;
 
953
}
 
954
 
 
955
/*
 
956
Set the state of this (instantiated) pin
 
957
*/
 
958
static PaError PinSetState(PaWinWdmPin* pin, KSSTATE state)
 
959
{
 
960
    PaError result;
 
961
 
 
962
    PA_LOGE_;
 
963
    if( pin == NULL )
 
964
        return paInternalError;
 
965
    if( pin->handle == NULL )
 
966
        return paInternalError;
 
967
 
 
968
    result = WdmSetPropertySimple(
 
969
        pin->handle,
 
970
        &KSPROPSETID_Connection,
 
971
        KSPROPERTY_CONNECTION_STATE,
 
972
        &state,
 
973
        sizeof(state),
 
974
        NULL,
 
975
        0);
 
976
    PA_LOGL_;
 
977
    return result;
 
978
}
 
979
 
 
980
static PaError PinInstantiate(PaWinWdmPin* pin)
 
981
{
 
982
    PaError result;
 
983
    unsigned long createResult;
 
984
    KSALLOCATOR_FRAMING ksaf;
 
985
    KSALLOCATOR_FRAMING_EX ksafex;
 
986
 
 
987
    PA_LOGE_;
 
988
 
 
989
    if( pin == NULL )
 
990
        return paInternalError;
 
991
    if(!pin->pinConnect)
 
992
        return paInternalError;
 
993
 
 
994
    FilterUse(pin->parentFilter);
 
995
 
 
996
    createResult = FunctionKsCreatePin(
 
997
        pin->parentFilter->handle,
 
998
        pin->pinConnect,
 
999
        GENERIC_WRITE | GENERIC_READ,
 
1000
        &pin->handle
 
1001
        );
 
1002
 
 
1003
    PA_DEBUG(("Pin create result = %x\n",createResult));
 
1004
    if( createResult != ERROR_SUCCESS )
 
1005
    {
 
1006
        FilterRelease(pin->parentFilter);
 
1007
        pin->handle = NULL;
 
1008
        return paInvalidDevice;
 
1009
    }
 
1010
 
 
1011
    result = WdmGetPropertySimple(
 
1012
        pin->handle,
 
1013
        &KSPROPSETID_Connection,
 
1014
        KSPROPERTY_CONNECTION_ALLOCATORFRAMING,
 
1015
        &ksaf,
 
1016
        sizeof(ksaf),
 
1017
        NULL,
 
1018
        0);
 
1019
 
 
1020
    if( result != paNoError )
 
1021
    {
 
1022
        result = WdmGetPropertySimple(
 
1023
            pin->handle,
 
1024
            &KSPROPSETID_Connection,
 
1025
            KSPROPERTY_CONNECTION_ALLOCATORFRAMING_EX,
 
1026
            &ksafex,
 
1027
            sizeof(ksafex),
 
1028
            NULL,
 
1029
            0);
 
1030
        if( result == paNoError )
 
1031
        {
 
1032
            pin->frameSize = ksafex.FramingItem[0].FramingRange.Range.MinFrameSize;
 
1033
        }
 
1034
    }
 
1035
    else
 
1036
    {
 
1037
        pin->frameSize = ksaf.FrameSize;
 
1038
    }
 
1039
 
 
1040
    PA_LOGL_;
 
1041
 
 
1042
    return paNoError;
 
1043
}
 
1044
 
 
1045
/* NOT USED
 
1046
static PaError PinGetState(PaWinWdmPin* pin, KSSTATE* state)
 
1047
{
 
1048
    PaError result;
 
1049
 
 
1050
    if( state == NULL )
 
1051
        return paInternalError;
 
1052
    if( pin == NULL )
 
1053
        return paInternalError;
 
1054
    if( pin->handle == NULL )
 
1055
        return paInternalError;
 
1056
 
 
1057
    result = WdmGetPropertySimple(
 
1058
        pin->handle,
 
1059
        KSPROPSETID_Connection,
 
1060
        KSPROPERTY_CONNECTION_STATE,
 
1061
        state,
 
1062
        sizeof(KSSTATE),
 
1063
        NULL,
 
1064
        0);
 
1065
 
 
1066
    return result;
 
1067
}
 
1068
*/
 
1069
static PaError PinSetFormat(PaWinWdmPin* pin, const WAVEFORMATEX* format)
 
1070
{
 
1071
    unsigned long size;
 
1072
    void* newConnect;
 
1073
 
 
1074
    PA_LOGE_;
 
1075
 
 
1076
    if( pin == NULL )
 
1077
        return paInternalError;
 
1078
    if( format == NULL )
 
1079
        return paInternalError;
 
1080
 
 
1081
    size = GetWfexSize(format) + sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX) - sizeof(WAVEFORMATEX);
 
1082
 
 
1083
    if( pin->pinConnectSize != size )
 
1084
    {
 
1085
        newConnect = PaUtil_AllocateMemory( size );
 
1086
        if( newConnect == NULL )
 
1087
            return paInsufficientMemory;
 
1088
        memcpy( newConnect, (void*)pin->pinConnect, min(pin->pinConnectSize,size) );
 
1089
        PaUtil_FreeMemory( pin->pinConnect );
 
1090
        pin->pinConnect = (KSPIN_CONNECT*)newConnect;
 
1091
        pin->pinConnectSize = size;
 
1092
        pin->ksDataFormatWfx = (KSDATAFORMAT_WAVEFORMATEX*)((KSPIN_CONNECT*)newConnect + 1);
 
1093
        pin->ksDataFormatWfx->DataFormat.FormatSize = size - sizeof(KSPIN_CONNECT);
 
1094
    }
 
1095
 
 
1096
    memcpy( (void*)&(pin->ksDataFormatWfx->WaveFormatEx), format, GetWfexSize(format) );
 
1097
    pin->ksDataFormatWfx->DataFormat.SampleSize = (unsigned short)(format->nChannels * (format->wBitsPerSample / 8));
 
1098
 
 
1099
    PA_LOGL_;
 
1100
 
 
1101
    return paNoError;
 
1102
}
 
1103
 
 
1104
static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format)
 
1105
{
 
1106
    KSDATARANGE_AUDIO* dataRange;
 
1107
    unsigned long count;
 
1108
    GUID guid = DYNAMIC_GUID( DEFINE_WAVEFORMATEX_GUID(format->wFormatTag) );
 
1109
    PaError result = paInvalidDevice;
 
1110
 
 
1111
    PA_LOGE_;
 
1112
 
 
1113
    if( format->wFormatTag == WAVE_FORMAT_EXTENSIBLE )
 
1114
    {
 
1115
        guid = ((WAVEFORMATEXTENSIBLE*)format)->SubFormat;
 
1116
    }
 
1117
    dataRange = (KSDATARANGE_AUDIO*)pin->dataRanges;
 
1118
    for(count = 0; count<pin->dataRangesItem->Count; count++)
 
1119
    {
 
1120
        if(( !memcmp(&(dataRange->DataRange.MajorFormat),&KSDATAFORMAT_TYPE_AUDIO,sizeof(GUID)) ) ||
 
1121
           ( !memcmp(&(dataRange->DataRange.MajorFormat),&KSDATAFORMAT_TYPE_WILDCARD,sizeof(GUID)) ))
 
1122
        {
 
1123
            /* This is an audio or wildcard datarange... */
 
1124
            if(( !memcmp(&(dataRange->DataRange.SubFormat),&KSDATAFORMAT_SUBTYPE_WILDCARD,sizeof(GUID)) ) ||
 
1125
                ( !memcmp(&(dataRange->DataRange.SubFormat),&guid,sizeof(GUID)) ))
 
1126
            {
 
1127
                if(( !memcmp(&(dataRange->DataRange.Specifier),&KSDATAFORMAT_SPECIFIER_WILDCARD,sizeof(GUID)) ) ||
 
1128
                  ( !memcmp(&(dataRange->DataRange.Specifier),&KSDATAFORMAT_SPECIFIER_WAVEFORMATEX,sizeof(GUID) )))
 
1129
                {
 
1130
 
 
1131
                    PA_DEBUG(("Pin:%x, DataRange:%d\n",(void*)pin,count));
 
1132
                    PA_DEBUG(("\tFormatSize:%d, SampleSize:%d\n",dataRange->DataRange.FormatSize,dataRange->DataRange.SampleSize));
 
1133
                    PA_DEBUG(("\tMaxChannels:%d\n",dataRange->MaximumChannels));
 
1134
                    PA_DEBUG(("\tBits:%d-%d\n",dataRange->MinimumBitsPerSample,dataRange->MaximumBitsPerSample));
 
1135
                    PA_DEBUG(("\tSampleRate:%d-%d\n",dataRange->MinimumSampleFrequency,dataRange->MaximumSampleFrequency));
 
1136
 
 
1137
                    if( dataRange->MaximumChannels < format->nChannels )
 
1138
                    {
 
1139
                        result = paInvalidChannelCount;
 
1140
                        continue;
 
1141
                    }
 
1142
                    if( dataRange->MinimumBitsPerSample > format->wBitsPerSample )
 
1143
                    {
 
1144
                        result = paSampleFormatNotSupported;
 
1145
                        continue;
 
1146
                    }
 
1147
                    if( dataRange->MaximumBitsPerSample < format->wBitsPerSample )
 
1148
                    {
 
1149
                        result = paSampleFormatNotSupported;
 
1150
                        continue;
 
1151
                    }
 
1152
                    if( dataRange->MinimumSampleFrequency > format->nSamplesPerSec )
 
1153
                    {
 
1154
                        result = paInvalidSampleRate;
 
1155
                        continue;
 
1156
                    }
 
1157
                    if( dataRange->MaximumSampleFrequency < format->nSamplesPerSec )
 
1158
                    {
 
1159
                        result = paInvalidSampleRate;
 
1160
                        continue;
 
1161
                    }
 
1162
                    /* Success! */
 
1163
                    PA_LOGL_;
 
1164
                    return paNoError;
 
1165
                }
 
1166
            }
 
1167
        }
 
1168
        dataRange = (KSDATARANGE_AUDIO*)( ((char*)dataRange) + dataRange->DataRange.FormatSize);
 
1169
    }
 
1170
 
 
1171
    PA_LOGL_;
 
1172
 
 
1173
    return result;
 
1174
}
 
1175
 
 
1176
/**
 
1177
 * Create a new filter object
 
1178
 */
 
1179
static PaWinWdmFilter* FilterNew(TCHAR* filterName, TCHAR* friendlyName, PaError* error)
 
1180
{
 
1181
    PaWinWdmFilter* filter;
 
1182
    PaError result;
 
1183
    int pinId;
 
1184
    int valid;
 
1185
 
 
1186
 
 
1187
    /* Allocate the new filter object */
 
1188
    filter = (PaWinWdmFilter*)PaUtil_AllocateMemory( sizeof(PaWinWdmFilter) );
 
1189
    if( !filter )
 
1190
    {
 
1191
        result = paInsufficientMemory;
 
1192
        goto error;
 
1193
    }
 
1194
 
 
1195
    /* Zero the filter object - done by AllocateMemory */
 
1196
    /* memset( (void*)filter, 0, sizeof(PaWinWdmFilter) ); */
 
1197
 
 
1198
    /* Copy the filter name */
 
1199
    _tcsncpy(filter->filterName, filterName, MAX_PATH);
 
1200
 
 
1201
    /* Copy the friendly name */
 
1202
    _tcsncpy(filter->friendlyName, friendlyName, MAX_PATH);
 
1203
 
 
1204
    /* Open the filter handle */
 
1205
    result = FilterUse(filter);
 
1206
    if( result != paNoError )
 
1207
    {
 
1208
        goto error;
 
1209
    }
 
1210
 
 
1211
    /* Get pin count */
 
1212
    result = WdmGetPinPropertySimple
 
1213
        (
 
1214
        filter->handle,
 
1215
        0,
 
1216
        &KSPROPSETID_Pin,
 
1217
        KSPROPERTY_PIN_CTYPES,
 
1218
        &filter->pinCount,
 
1219
        sizeof(filter->pinCount)
 
1220
        );
 
1221
 
 
1222
    if( result != paNoError)
 
1223
    {
 
1224
        goto error;
 
1225
    }
 
1226
 
 
1227
    /* Allocate pointer array to hold the pins */
 
1228
    filter->pins = (PaWinWdmPin**)PaUtil_AllocateMemory( sizeof(PaWinWdmPin*) * filter->pinCount );
 
1229
    if( !filter->pins )
 
1230
    {
 
1231
        result = paInsufficientMemory;
 
1232
        goto error;
 
1233
    }
 
1234
 
 
1235
    /* Create all the pins we can */
 
1236
    filter->maxInputChannels = 0;
 
1237
    filter->maxOutputChannels = 0;
 
1238
    filter->bestSampleRate = 0;
 
1239
 
 
1240
    valid = 0;
 
1241
    for(pinId = 0; pinId < filter->pinCount; pinId++)
 
1242
    {
 
1243
        /* Create the pin with this Id */
 
1244
        PaWinWdmPin* newPin;
 
1245
        newPin = PinNew(filter, pinId, &result);
 
1246
        if( result == paInsufficientMemory )
 
1247
            goto error;
 
1248
        if( newPin != NULL )
 
1249
        {
 
1250
            filter->pins[pinId] = newPin;
 
1251
            valid = 1;
 
1252
 
 
1253
            /* Get the max output channel count */
 
1254
            if(( newPin->dataFlow == KSPIN_DATAFLOW_IN ) &&
 
1255
                (( newPin->communication == KSPIN_COMMUNICATION_SINK) ||
 
1256
                 ( newPin->communication == KSPIN_COMMUNICATION_BOTH)))
 
1257
            {
 
1258
                if(newPin->maxChannels > filter->maxOutputChannels)
 
1259
                    filter->maxOutputChannels = newPin->maxChannels;
 
1260
                filter->formats |= newPin->formats;
 
1261
            }
 
1262
            /* Get the max input channel count */
 
1263
            if(( newPin->dataFlow == KSPIN_DATAFLOW_OUT ) &&
 
1264
                (( newPin->communication == KSPIN_COMMUNICATION_SINK) ||
 
1265
                 ( newPin->communication == KSPIN_COMMUNICATION_BOTH)))
 
1266
            {
 
1267
                if(newPin->maxChannels > filter->maxInputChannels)
 
1268
                    filter->maxInputChannels = newPin->maxChannels;
 
1269
                filter->formats |= newPin->formats;
 
1270
            }
 
1271
 
 
1272
            if(newPin->bestSampleRate > filter->bestSampleRate)
 
1273
            {
 
1274
                filter->bestSampleRate = newPin->bestSampleRate;
 
1275
            }
 
1276
        }
 
1277
    }
 
1278
 
 
1279
    if(( filter->maxInputChannels == 0) && ( filter->maxOutputChannels == 0))
 
1280
    {
 
1281
        /* No input or output... not valid */
 
1282
        valid = 0;
 
1283
    }
 
1284
 
 
1285
    if( !valid )
 
1286
    {
 
1287
        /* No valid pin was found on this filter so we destroy it */
 
1288
        result = paDeviceUnavailable;
 
1289
        goto error;
 
1290
    }
 
1291
 
 
1292
    /* Close the filter handle for now
 
1293
     * It will be opened later when needed */
 
1294
    FilterRelease(filter);
 
1295
 
 
1296
    *error = paNoError;
 
1297
    return filter;
 
1298
 
 
1299
error:
 
1300
    /*
 
1301
    Error cleanup
 
1302
    */
 
1303
    if( filter )
 
1304
    {
 
1305
        for( pinId = 0; pinId < filter->pinCount; pinId++ )
 
1306
            PinFree(filter->pins[pinId]);
 
1307
        PaUtil_FreeMemory( filter->pins );
 
1308
        if( filter->handle )
 
1309
            CloseHandle( filter->handle );
 
1310
        PaUtil_FreeMemory( filter );
 
1311
    }
 
1312
    *error = result;
 
1313
    return NULL;
 
1314
}
 
1315
 
 
1316
/**
 
1317
 * Free a previously created filter
 
1318
 */
 
1319
static void FilterFree(PaWinWdmFilter* filter)
 
1320
{
 
1321
    int pinId;
 
1322
    PA_LOGL_;
 
1323
    if( filter )
 
1324
    {
 
1325
        for( pinId = 0; pinId < filter->pinCount; pinId++ )
 
1326
            PinFree(filter->pins[pinId]);
 
1327
        PaUtil_FreeMemory( filter->pins );
 
1328
        if( filter->handle )
 
1329
            CloseHandle( filter->handle );
 
1330
        PaUtil_FreeMemory( filter );
 
1331
    }
 
1332
    PA_LOGE_;
 
1333
}
 
1334
 
 
1335
/**
 
1336
 * Reopen the filter handle if necessary so it can be used
 
1337
 **/
 
1338
static PaError FilterUse(PaWinWdmFilter* filter)
 
1339
{
 
1340
    assert( filter );
 
1341
 
 
1342
    PA_LOGE_;
 
1343
    if( filter->handle == NULL )
 
1344
    {
 
1345
        /* Open the filter */
 
1346
        filter->handle = CreateFile(
 
1347
            filter->filterName,
 
1348
            GENERIC_READ | GENERIC_WRITE,
 
1349
            0,
 
1350
            NULL,
 
1351
            OPEN_EXISTING,
 
1352
            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
 
1353
            NULL);
 
1354
 
 
1355
        if( filter->handle == NULL )
 
1356
        {
 
1357
            return paDeviceUnavailable;
 
1358
        }
 
1359
    }
 
1360
    filter->usageCount++;
 
1361
    PA_LOGL_;
 
1362
    return paNoError;
 
1363
}
 
1364
 
 
1365
/**
 
1366
 * Release the filter handle if nobody is using it
 
1367
 **/
 
1368
static void FilterRelease(PaWinWdmFilter* filter)
 
1369
{
 
1370
    assert( filter );
 
1371
    assert( filter->usageCount > 0 );
 
1372
 
 
1373
    PA_LOGE_;
 
1374
    filter->usageCount--;
 
1375
    if( filter->usageCount == 0 )
 
1376
    {
 
1377
        if( filter->handle != NULL )
 
1378
        {
 
1379
            CloseHandle( filter->handle );
 
1380
            filter->handle = NULL;
 
1381
        }
 
1382
    }
 
1383
    PA_LOGL_;
 
1384
}
 
1385
 
 
1386
/**
 
1387
 * Create a render (playback) Pin using the supplied format
 
1388
 **/
 
1389
static PaWinWdmPin* FilterCreateRenderPin(PaWinWdmFilter* filter,
 
1390
    const WAVEFORMATEX* wfex,
 
1391
    PaError* error)
 
1392
{
 
1393
    PaError result;
 
1394
    PaWinWdmPin* pin;
 
1395
 
 
1396
    assert( filter );
 
1397
 
 
1398
    pin = FilterFindViableRenderPin(filter,wfex,&result);
 
1399
    if(!pin)
 
1400
    {
 
1401
        goto error;
 
1402
    }
 
1403
    result = PinSetFormat(pin,wfex);
 
1404
    if( result != paNoError )
 
1405
    {
 
1406
        goto error;
 
1407
    }
 
1408
    result = PinInstantiate(pin);
 
1409
    if( result != paNoError )
 
1410
    {
 
1411
        goto error;
 
1412
    }
 
1413
 
 
1414
    *error = paNoError;
 
1415
    return pin;
 
1416
 
 
1417
error:
 
1418
    *error = result;
 
1419
    return NULL;
 
1420
}
 
1421
 
 
1422
/**
 
1423
 * Find a pin that supports the given format
 
1424
 **/
 
1425
static PaWinWdmPin* FilterFindViableRenderPin(PaWinWdmFilter* filter,
 
1426
    const WAVEFORMATEX* wfex,
 
1427
    PaError* error)
 
1428
{
 
1429
    int pinId;
 
1430
    PaWinWdmPin*  pin;
 
1431
    PaError result = paDeviceUnavailable;
 
1432
    *error = paNoError;
 
1433
 
 
1434
    assert( filter );
 
1435
 
 
1436
    for( pinId = 0; pinId<filter->pinCount; pinId++ )
 
1437
    {
 
1438
        pin = filter->pins[pinId];
 
1439
        if( pin != NULL )
 
1440
        {
 
1441
            if(( pin->dataFlow == KSPIN_DATAFLOW_IN ) &&
 
1442
                (( pin->communication == KSPIN_COMMUNICATION_SINK) ||
 
1443
                 ( pin->communication == KSPIN_COMMUNICATION_BOTH)))
 
1444
            {
 
1445
                result = PinIsFormatSupported( pin, wfex );
 
1446
                if( result == paNoError )
 
1447
                {
 
1448
                    return pin;
 
1449
                }
 
1450
            }
 
1451
        }
 
1452
    }
 
1453
 
 
1454
    *error = result;
 
1455
    return NULL;
 
1456
}
 
1457
 
 
1458
/**
 
1459
 * Check if there is a pin that should playback
 
1460
 * with the supplied format
 
1461
 **/
 
1462
static PaError FilterCanCreateRenderPin(PaWinWdmFilter* filter,
 
1463
    const WAVEFORMATEX* wfex)
 
1464
{
 
1465
    PaWinWdmPin* pin;
 
1466
    PaError result;
 
1467
 
 
1468
    assert ( filter );
 
1469
 
 
1470
    pin = FilterFindViableRenderPin(filter,wfex,&result);
 
1471
    /* result will be paNoError if pin found
 
1472
     * or else an error code indicating what is wrong with the format
 
1473
     **/
 
1474
    return result;
 
1475
}
 
1476
 
 
1477
/**
 
1478
 * Create a capture (record) Pin using the supplied format
 
1479
 **/
 
1480
static PaWinWdmPin* FilterCreateCapturePin(PaWinWdmFilter* filter,
 
1481
    const WAVEFORMATEX* wfex,
 
1482
    PaError* error)
 
1483
{
 
1484
    PaError result;
 
1485
    PaWinWdmPin* pin;
 
1486
 
 
1487
    assert( filter );
 
1488
 
 
1489
    pin = FilterFindViableCapturePin(filter,wfex,&result);
 
1490
    if(!pin)
 
1491
    {
 
1492
        goto error;
 
1493
    }
 
1494
 
 
1495
    result = PinSetFormat(pin,wfex);
 
1496
    if( result != paNoError )
 
1497
    {
 
1498
        goto error;
 
1499
    }
 
1500
 
 
1501
    result = PinInstantiate(pin);
 
1502
    if( result != paNoError )
 
1503
    {
 
1504
        goto error;
 
1505
    }
 
1506
 
 
1507
    *error = paNoError;
 
1508
    return pin;
 
1509
 
 
1510
error:
 
1511
    *error = result;
 
1512
    return NULL;
 
1513
}
 
1514
 
 
1515
/**
 
1516
 * Find a capture pin that supports the given format
 
1517
 **/
 
1518
static PaWinWdmPin* FilterFindViableCapturePin(PaWinWdmFilter* filter,
 
1519
    const WAVEFORMATEX* wfex,
 
1520
    PaError* error)
 
1521
{
 
1522
    int pinId;
 
1523
    PaWinWdmPin*  pin;
 
1524
    PaError result = paDeviceUnavailable;
 
1525
    *error = paNoError;
 
1526
 
 
1527
    assert( filter );
 
1528
 
 
1529
    for( pinId = 0; pinId<filter->pinCount; pinId++ )
 
1530
    {
 
1531
        pin = filter->pins[pinId];
 
1532
        if( pin != NULL )
 
1533
        {
 
1534
            if(( pin->dataFlow == KSPIN_DATAFLOW_OUT ) &&
 
1535
                (( pin->communication == KSPIN_COMMUNICATION_SINK) ||
 
1536
                 ( pin->communication == KSPIN_COMMUNICATION_BOTH)))
 
1537
            {
 
1538
                result = PinIsFormatSupported( pin, wfex );
 
1539
                if( result == paNoError )
 
1540
                {
 
1541
                    return pin;
 
1542
                }
 
1543
            }
 
1544
        }
 
1545
    }
 
1546
 
 
1547
    *error = result;
 
1548
    return NULL;
 
1549
}
 
1550
 
 
1551
/**
 
1552
 * Check if there is a pin that should playback
 
1553
 * with the supplied format
 
1554
 **/
 
1555
static PaError FilterCanCreateCapturePin(PaWinWdmFilter* filter,
 
1556
    const WAVEFORMATEX* wfex)
 
1557
{
 
1558
    PaWinWdmPin* pin;
 
1559
    PaError result;
 
1560
 
 
1561
    assert ( filter );
 
1562
 
 
1563
    pin = FilterFindViableCapturePin(filter,wfex,&result);
 
1564
    /* result will be paNoError if pin found
 
1565
     * or else an error code indicating what is wrong with the format
 
1566
     **/
 
1567
    return result;
 
1568
}
 
1569
 
 
1570
/**
 
1571
 * Build the list of available filters
 
1572
 * Use the SetupDi API to enumerate all devices in the KSCATEGORY_AUDIO which 
 
1573
 * have a KSCATEGORY_RENDER or KSCATEGORY_CAPTURE alias. For each of these 
 
1574
 * devices initialise a PaWinWdmFilter structure by calling our NewFilter() 
 
1575
 * function. We enumerate devices twice, once to count how many there are, 
 
1576
 * and once to initialize the PaWinWdmFilter structures.
 
1577
 */
 
1578
static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi)
 
1579
{
 
1580
    PaError result = paNoError;
 
1581
    HDEVINFO handle = NULL;
 
1582
    int device;
 
1583
    int invalidDevices;
 
1584
    int slot;
 
1585
    SP_DEVICE_INTERFACE_DATA interfaceData;
 
1586
    SP_DEVICE_INTERFACE_DATA aliasData;
 
1587
    SP_DEVINFO_DATA devInfoData;
 
1588
    int noError;
 
1589
    const int sizeInterface = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR));
 
1590
    unsigned char interfaceDetailsArray[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR))];
 
1591
    SP_DEVICE_INTERFACE_DETAIL_DATA* devInterfaceDetails = (SP_DEVICE_INTERFACE_DETAIL_DATA*)interfaceDetailsArray;
 
1592
    TCHAR friendlyName[MAX_PATH];
 
1593
    HKEY hkey;
 
1594
    DWORD sizeFriendlyName;
 
1595
    DWORD type;
 
1596
    PaWinWdmFilter* newFilter;
 
1597
    GUID* category = (GUID*)&KSCATEGORY_AUDIO;
 
1598
    GUID* alias_render = (GUID*)&KSCATEGORY_RENDER;
 
1599
    GUID* alias_capture = (GUID*)&KSCATEGORY_CAPTURE;
 
1600
    DWORD hasAlias;
 
1601
 
 
1602
    PA_LOGE_;
 
1603
 
 
1604
    devInterfaceDetails->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
 
1605
 
 
1606
    /* Open a handle to search for devices (filters) */
 
1607
    handle = SetupDiGetClassDevs(category,NULL,NULL,DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
 
1608
    if( handle == NULL )
 
1609
    {
 
1610
        return paUnanticipatedHostError;
 
1611
    }
 
1612
    PA_DEBUG(("Setup called\n"));
 
1613
 
 
1614
    /* First let's count the number of devices so we can allocate a list */
 
1615
    invalidDevices = 0;
 
1616
    for( device = 0;;device++ )
 
1617
    {
 
1618
        interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
 
1619
        interfaceData.Reserved = 0;
 
1620
        aliasData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
 
1621
        aliasData.Reserved = 0;
 
1622
        noError = SetupDiEnumDeviceInterfaces(handle,NULL,category,device,&interfaceData);
 
1623
        PA_DEBUG(("Enum called\n"));
 
1624
        if( !noError )
 
1625
            break; /* No more devices */
 
1626
 
 
1627
        /* Check this one has the render or capture alias */
 
1628
        hasAlias = 0;
 
1629
        noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_render,&aliasData);
 
1630
        PA_DEBUG(("noError = %d\n",noError));
 
1631
        if(noError)
 
1632
        {
 
1633
            if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
 
1634
            {
 
1635
                PA_DEBUG(("Device %d has render alias\n",device));
 
1636
                hasAlias |= 1; /* Has render alias */
 
1637
            }
 
1638
            else
 
1639
            {
 
1640
                PA_DEBUG(("Device %d has no render alias\n",device));
 
1641
            }
 
1642
        }
 
1643
        noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_capture,&aliasData);
 
1644
        if(noError)
 
1645
        {
 
1646
            if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
 
1647
            {
 
1648
                PA_DEBUG(("Device %d has capture alias\n",device));
 
1649
                hasAlias |= 2; /* Has capture alias */
 
1650
            }
 
1651
            else
 
1652
            {
 
1653
                PA_DEBUG(("Device %d has no capture alias\n",device));
 
1654
            }
 
1655
        }
 
1656
        if(!hasAlias)
 
1657
            invalidDevices++; /* This was not a valid capture or render audio device */
 
1658
 
 
1659
    }
 
1660
    /* Remember how many there are */
 
1661
    wdmHostApi->filterCount = device-invalidDevices;
 
1662
 
 
1663
    PA_DEBUG(("Interfaces found: %d\n",device-invalidDevices));
 
1664
 
 
1665
    /* Now allocate the list of pointers to devices */
 
1666
    wdmHostApi->filters  = (PaWinWdmFilter**)PaUtil_AllocateMemory( sizeof(PaWinWdmFilter*) * device );
 
1667
    if( !wdmHostApi->filters )
 
1668
    {
 
1669
        if(handle != NULL)
 
1670
            SetupDiDestroyDeviceInfoList(handle);
 
1671
        return paInsufficientMemory;
 
1672
    }
 
1673
 
 
1674
    /* Now create filter objects for each interface found */
 
1675
    slot = 0;
 
1676
    for( device = 0;;device++ )
 
1677
    {
 
1678
        interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
 
1679
        interfaceData.Reserved = 0;
 
1680
        aliasData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
 
1681
        aliasData.Reserved = 0;
 
1682
        devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
 
1683
        devInfoData.Reserved = 0;
 
1684
 
 
1685
        noError = SetupDiEnumDeviceInterfaces(handle,NULL,category,device,&interfaceData);
 
1686
        if( !noError )
 
1687
            break; /* No more devices */
 
1688
 
 
1689
        /* Check this one has the render or capture alias */
 
1690
        hasAlias = 0;
 
1691
        noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_render,&aliasData);
 
1692
        if(noError)
 
1693
        {
 
1694
            if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
 
1695
            {
 
1696
                PA_DEBUG(("Device %d has render alias\n",device));
 
1697
                hasAlias |= 1; /* Has render alias */
 
1698
            }
 
1699
        }
 
1700
        noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_capture,&aliasData);
 
1701
        if(noError)
 
1702
        {
 
1703
            if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
 
1704
            {
 
1705
                PA_DEBUG(("Device %d has capture alias\n",device));
 
1706
                hasAlias |= 2; /* Has capture alias */
 
1707
            }
 
1708
        }
 
1709
        if(!hasAlias)
 
1710
            continue; /* This was not a valid capture or render audio device */
 
1711
 
 
1712
        noError = SetupDiGetDeviceInterfaceDetail(handle,&interfaceData,devInterfaceDetails,sizeInterface,NULL,&devInfoData);
 
1713
        if( noError )
 
1714
        {
 
1715
            /* Try to get the "friendly name" for this interface */
 
1716
            sizeFriendlyName = sizeof(friendlyName);
 
1717
            /* Fix contributed by Ben Allison
 
1718
             * Removed KEY_SET_VALUE from flags on following call
 
1719
             * as its causes failure when running without admin rights
 
1720
             * and it was not required */
 
1721
            hkey=SetupDiOpenDeviceInterfaceRegKey(handle,&interfaceData,0,KEY_QUERY_VALUE);
 
1722
            if(hkey!=INVALID_HANDLE_VALUE)
 
1723
            {
 
1724
                noError = RegQueryValueEx(hkey,TEXT("FriendlyName"),0,&type,(BYTE*)friendlyName,&sizeFriendlyName);
 
1725
                if( noError == ERROR_SUCCESS )
 
1726
                {
 
1727
                    PA_DEBUG(("Interface %d, Name: %s\n",device,friendlyName));
 
1728
                    RegCloseKey(hkey);
 
1729
                }
 
1730
                else
 
1731
                {
 
1732
                    friendlyName[0] = 0;
 
1733
                }
 
1734
            }
 
1735
            newFilter = FilterNew(devInterfaceDetails->DevicePath,friendlyName,&result);
 
1736
            if( result == paNoError )
 
1737
            {
 
1738
                PA_DEBUG(("Filter created\n"));
 
1739
                wdmHostApi->filters[slot] = newFilter;
 
1740
                slot++;
 
1741
            }
 
1742
            else
 
1743
            {
 
1744
                PA_DEBUG(("Filter NOT created\n"));
 
1745
                /* As there are now less filters than we initially thought
 
1746
                 * we must reduce the count by one */
 
1747
                wdmHostApi->filterCount--;
 
1748
            }
 
1749
        }
 
1750
    }
 
1751
 
 
1752
    /* Clean up */
 
1753
    if(handle != NULL)
 
1754
        SetupDiDestroyDeviceInfoList(handle);
 
1755
 
 
1756
    return paNoError;
 
1757
}
 
1758
 
 
1759
PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
 
1760
{
 
1761
    PaError result = paNoError;
 
1762
    int i, deviceCount;
 
1763
    PaWinWdmHostApiRepresentation *wdmHostApi;
 
1764
    PaWinWdmDeviceInfo *deviceInfoArray;
 
1765
    PaWinWdmFilter* pFilter;
 
1766
    PaWinWdmDeviceInfo *wdmDeviceInfo;
 
1767
    PaDeviceInfo *deviceInfo;
 
1768
 
 
1769
    PA_LOGE_;
 
1770
 
 
1771
    /*
 
1772
    Attempt to load the KSUSER.DLL without which we cannot create pins
 
1773
    We will unload this on termination
 
1774
    */
 
1775
    if(DllKsUser == NULL)
 
1776
    {
 
1777
        DllKsUser = LoadLibrary(TEXT("ksuser.dll"));
 
1778
        if(DllKsUser == NULL)
 
1779
            goto error;
 
1780
    }
 
1781
 
 
1782
    FunctionKsCreatePin = (KSCREATEPIN*)GetProcAddress(DllKsUser, "KsCreatePin");
 
1783
    if(FunctionKsCreatePin == NULL)
 
1784
        goto error;
 
1785
 
 
1786
    wdmHostApi = (PaWinWdmHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinWdmHostApiRepresentation) );
 
1787
    if( !wdmHostApi )
 
1788
    {
 
1789
        result = paInsufficientMemory;
 
1790
        goto error;
 
1791
    }
 
1792
 
 
1793
    wdmHostApi->allocations = PaUtil_CreateAllocationGroup();
 
1794
    if( !wdmHostApi->allocations )
 
1795
    {
 
1796
        result = paInsufficientMemory;
 
1797
        goto error;
 
1798
    }
 
1799
 
 
1800
    result = BuildFilterList( wdmHostApi );
 
1801
    if( result != paNoError )
 
1802
    {
 
1803
        goto error;
 
1804
    }
 
1805
    deviceCount = wdmHostApi->filterCount;
 
1806
 
 
1807
    *hostApi = &wdmHostApi->inheritedHostApiRep;
 
1808
    (*hostApi)->info.structVersion = 1;
 
1809
    (*hostApi)->info.type = paWDMKS;
 
1810
    (*hostApi)->info.name = "Windows WDM-KS";
 
1811
    (*hostApi)->info.defaultInputDevice = paNoDevice;
 
1812
    (*hostApi)->info.defaultOutputDevice = paNoDevice;
 
1813
 
 
1814
    if( deviceCount > 0 )
 
1815
    {
 
1816
        (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
 
1817
               wdmHostApi->allocations, sizeof(PaWinWdmDeviceInfo*) * deviceCount );
 
1818
        if( !(*hostApi)->deviceInfos )
 
1819
        {
 
1820
            result = paInsufficientMemory;
 
1821
            goto error;
 
1822
        }
 
1823
 
 
1824
        /* allocate all device info structs in a contiguous block */
 
1825
        deviceInfoArray = (PaWinWdmDeviceInfo*)PaUtil_GroupAllocateMemory(
 
1826
                wdmHostApi->allocations, sizeof(PaWinWdmDeviceInfo) * deviceCount );
 
1827
        if( !deviceInfoArray )
 
1828
        {
 
1829
            result = paInsufficientMemory;
 
1830
            goto error;
 
1831
        }
 
1832
 
 
1833
        for( i=0; i < deviceCount; ++i )
 
1834
        {
 
1835
            wdmDeviceInfo = &deviceInfoArray[i];
 
1836
            deviceInfo = &wdmDeviceInfo->inheritedDeviceInfo;
 
1837
            pFilter = wdmHostApi->filters[i];
 
1838
            if( pFilter == NULL )
 
1839
                continue;
 
1840
            wdmDeviceInfo->filter = pFilter;
 
1841
            deviceInfo->structVersion = 2;
 
1842
            deviceInfo->hostApi = hostApiIndex;
 
1843
            deviceInfo->name = (char*)pFilter->friendlyName;
 
1844
            PA_DEBUG(("Device found name: %s\n",(char*)pFilter->friendlyName));
 
1845
            deviceInfo->maxInputChannels = pFilter->maxInputChannels;
 
1846
            if(deviceInfo->maxInputChannels > 0)
 
1847
            {
 
1848
                /* Set the default input device to the first device we find with
 
1849
                 * more than zero input channels
 
1850
                 **/
 
1851
                if((*hostApi)->info.defaultInputDevice == paNoDevice)
 
1852
                {
 
1853
                    (*hostApi)->info.defaultInputDevice = i;
 
1854
                }
 
1855
            }
 
1856
 
 
1857
            deviceInfo->maxOutputChannels = pFilter->maxOutputChannels;
 
1858
            if(deviceInfo->maxOutputChannels > 0)
 
1859
            {
 
1860
                /* Set the default output device to the first device we find with
 
1861
                 * more than zero output channels
 
1862
                 **/
 
1863
                if((*hostApi)->info.defaultOutputDevice == paNoDevice)
 
1864
                {
 
1865
                    (*hostApi)->info.defaultOutputDevice = i;
 
1866
                }
 
1867
            }
 
1868
 
 
1869
            /* These low values are not very useful because
 
1870
             * a) The lowest latency we end up with can depend on many factors such
 
1871
             *    as the device buffer sizes/granularities, sample rate, channels and format
 
1872
             * b) We cannot know the device buffer sizes until we try to open/use it at
 
1873
             *    a particular setting
 
1874
             * So: we give 512x48000Hz frames as the default low input latency
 
1875
             **/
 
1876
            deviceInfo->defaultLowInputLatency = (512.0/48000.0);
 
1877
            deviceInfo->defaultLowOutputLatency = (512.0/48000.0);
 
1878
            deviceInfo->defaultHighInputLatency = (4096.0/48000.0);
 
1879
            deviceInfo->defaultHighOutputLatency = (4096.0/48000.0);
 
1880
            deviceInfo->defaultSampleRate = (double)(pFilter->bestSampleRate);
 
1881
 
 
1882
            (*hostApi)->deviceInfos[i] = deviceInfo;
 
1883
        }
 
1884
    }
 
1885
 
 
1886
    (*hostApi)->info.deviceCount = deviceCount;
 
1887
 
 
1888
    (*hostApi)->Terminate = Terminate;
 
1889
    (*hostApi)->OpenStream = OpenStream;
 
1890
    (*hostApi)->IsFormatSupported = IsFormatSupported;
 
1891
 
 
1892
    PaUtil_InitializeStreamInterface( &wdmHostApi->callbackStreamInterface, CloseStream, StartStream,
 
1893
                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
 
1894
                                      GetStreamTime, GetStreamCpuLoad,
 
1895
                                      PaUtil_DummyRead, PaUtil_DummyWrite,
 
1896
                                      PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
 
1897
 
 
1898
    PaUtil_InitializeStreamInterface( &wdmHostApi->blockingStreamInterface, CloseStream, StartStream,
 
1899
                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
 
1900
                                      GetStreamTime, PaUtil_DummyGetCpuLoad,
 
1901
                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
 
1902
 
 
1903
    PA_LOGL_;
 
1904
    return result;
 
1905
 
 
1906
error:
 
1907
    if( DllKsUser != NULL )
 
1908
    {
 
1909
        FreeLibrary( DllKsUser );
 
1910
        DllKsUser = NULL;
 
1911
    }
 
1912
 
 
1913
    if( wdmHostApi )
 
1914
    {
 
1915
        PaUtil_FreeMemory( wdmHostApi->filters );
 
1916
        if( wdmHostApi->allocations )
 
1917
        {
 
1918
            PaUtil_FreeAllAllocations( wdmHostApi->allocations );
 
1919
            PaUtil_DestroyAllocationGroup( wdmHostApi->allocations );
 
1920
        }
 
1921
        PaUtil_FreeMemory( wdmHostApi );
 
1922
    }
 
1923
    PA_LOGL_;
 
1924
    return result;
 
1925
}
 
1926
 
 
1927
 
 
1928
static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
 
1929
{
 
1930
    PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
 
1931
    int i;
 
1932
    PA_LOGE_;
 
1933
 
 
1934
    if( wdmHostApi->filters )
 
1935
    {
 
1936
        for( i=0; i<wdmHostApi->filterCount; i++)
 
1937
        {
 
1938
            if( wdmHostApi->filters[i] != NULL )
 
1939
            {
 
1940
                FilterFree( wdmHostApi->filters[i] );
 
1941
                wdmHostApi->filters[i] = NULL;
 
1942
            }
 
1943
        }
 
1944
    }
 
1945
    PaUtil_FreeMemory( wdmHostApi->filters );
 
1946
    if( wdmHostApi->allocations )
 
1947
    {
 
1948
        PaUtil_FreeAllAllocations( wdmHostApi->allocations );
 
1949
        PaUtil_DestroyAllocationGroup( wdmHostApi->allocations );
 
1950
    }
 
1951
    PaUtil_FreeMemory( wdmHostApi );
 
1952
    PA_LOGL_;
 
1953
}
 
1954
 
 
1955
static void FillWFEXT( WAVEFORMATEXTENSIBLE* pwfext, PaSampleFormat sampleFormat, double sampleRate, int channelCount)
 
1956
{
 
1957
    PA_LOGE_;
 
1958
    PA_DEBUG(( "sampleFormat = %lx\n" , sampleFormat ));
 
1959
    PA_DEBUG(( "sampleRate = %f\n" , sampleRate ));
 
1960
    PA_DEBUG(( "chanelCount = %d\n", channelCount ));
 
1961
 
 
1962
    pwfext->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
 
1963
    pwfext->Format.nChannels = channelCount;
 
1964
    pwfext->Format.nSamplesPerSec = (int)sampleRate;
 
1965
    if(channelCount == 1)
 
1966
        pwfext->dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT;
 
1967
    else
 
1968
        pwfext->dwChannelMask = KSAUDIO_SPEAKER_STEREO;
 
1969
    if(sampleFormat == paFloat32)
 
1970
    {
 
1971
        pwfext->Format.nBlockAlign = channelCount * 4;
 
1972
        pwfext->Format.wBitsPerSample = 32;
 
1973
        pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
 
1974
        pwfext->Samples.wValidBitsPerSample = 32;
 
1975
        pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
 
1976
    }
 
1977
    else if(sampleFormat == paInt32)
 
1978
    {
 
1979
        pwfext->Format.nBlockAlign = channelCount * 4;
 
1980
        pwfext->Format.wBitsPerSample = 32;
 
1981
        pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
 
1982
        pwfext->Samples.wValidBitsPerSample = 32;
 
1983
        pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
 
1984
    }
 
1985
    else if(sampleFormat == paInt24)
 
1986
    {
 
1987
        pwfext->Format.nBlockAlign = channelCount * 3;
 
1988
        pwfext->Format.wBitsPerSample = 24;
 
1989
        pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
 
1990
        pwfext->Samples.wValidBitsPerSample = 24;
 
1991
        pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
 
1992
    }
 
1993
    else if(sampleFormat == paInt16)
 
1994
    {
 
1995
        pwfext->Format.nBlockAlign = channelCount * 2;
 
1996
        pwfext->Format.wBitsPerSample = 16;
 
1997
        pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
 
1998
        pwfext->Samples.wValidBitsPerSample = 16;
 
1999
        pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
 
2000
    }
 
2001
    pwfext->Format.nAvgBytesPerSec = pwfext->Format.nSamplesPerSec * pwfext->Format.nBlockAlign;
 
2002
 
 
2003
    PA_LOGL_;
 
2004
}
 
2005
 
 
2006
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
 
2007
                                  const PaStreamParameters *inputParameters,
 
2008
                                  const PaStreamParameters *outputParameters,
 
2009
                                  double sampleRate )
 
2010
{
 
2011
    int inputChannelCount, outputChannelCount;
 
2012
    PaSampleFormat inputSampleFormat, outputSampleFormat;
 
2013
    PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
 
2014
    PaWinWdmFilter* pFilter;
 
2015
    int result = paFormatIsSupported;
 
2016
    WAVEFORMATEXTENSIBLE wfx;
 
2017
 
 
2018
    PA_LOGE_;
 
2019
 
 
2020
    if( inputParameters )
 
2021
    {
 
2022
        inputChannelCount = inputParameters->channelCount;
 
2023
        inputSampleFormat = inputParameters->sampleFormat;
 
2024
 
 
2025
        /* all standard sample formats are supported by the buffer adapter,
 
2026
            this implementation doesn't support any custom sample formats */
 
2027
        if( inputSampleFormat & paCustomFormat )
 
2028
            return paSampleFormatNotSupported;
 
2029
 
 
2030
        /* unless alternate device specification is supported, reject the use of
 
2031
            paUseHostApiSpecificDeviceSpecification */
 
2032
 
 
2033
        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
 
2034
            return paInvalidDevice;
 
2035
 
 
2036
        /* check that input device can support inputChannelCount */
 
2037
        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
 
2038
            return paInvalidChannelCount;
 
2039
 
 
2040
        /* validate inputStreamInfo */
 
2041
        if( inputParameters->hostApiSpecificStreamInfo )
 
2042
            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
 
2043
 
 
2044
        /* Check that the input format is supported */
 
2045
        FillWFEXT(&wfx,paInt16,sampleRate,inputChannelCount);
 
2046
 
 
2047
        pFilter = wdmHostApi->filters[inputParameters->device];
 
2048
        result = FilterCanCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx);
 
2049
        if( result != paNoError )
 
2050
        {
 
2051
            /* Try a WAVE_FORMAT_PCM instead */
 
2052
            wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
 
2053
            wfx.Format.cbSize = 0;
 
2054
            wfx.Samples.wValidBitsPerSample = 0;
 
2055
            wfx.dwChannelMask = 0;
 
2056
            wfx.SubFormat = GUID_NULL;
 
2057
            result = FilterCanCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx);
 
2058
            if( result != paNoError )
 
2059
                 return result;
 
2060
        }
 
2061
    }
 
2062
    else
 
2063
    {
 
2064
        inputChannelCount = 0;
 
2065
    }
 
2066
 
 
2067
    if( outputParameters )
 
2068
    {
 
2069
        outputChannelCount = outputParameters->channelCount;
 
2070
        outputSampleFormat = outputParameters->sampleFormat;
 
2071
 
 
2072
        /* all standard sample formats are supported by the buffer adapter,
 
2073
            this implementation doesn't support any custom sample formats */
 
2074
        if( outputSampleFormat & paCustomFormat )
 
2075
            return paSampleFormatNotSupported;
 
2076
 
 
2077
        /* unless alternate device specification is supported, reject the use of
 
2078
            paUseHostApiSpecificDeviceSpecification */
 
2079
 
 
2080
        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
 
2081
            return paInvalidDevice;
 
2082
 
 
2083
        /* check that output device can support outputChannelCount */
 
2084
        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
 
2085
            return paInvalidChannelCount;
 
2086
 
 
2087
        /* validate outputStreamInfo */
 
2088
        if( outputParameters->hostApiSpecificStreamInfo )
 
2089
            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
 
2090
 
 
2091
        /* Check that the output format is supported */
 
2092
        FillWFEXT(&wfx,paInt16,sampleRate,outputChannelCount);
 
2093
 
 
2094
        pFilter = wdmHostApi->filters[outputParameters->device];
 
2095
        result = FilterCanCreateRenderPin(pFilter,(const WAVEFORMATEX*)&wfx);
 
2096
        if( result != paNoError )
 
2097
        {
 
2098
            /* Try a WAVE_FORMAT_PCM instead */
 
2099
            wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
 
2100
            wfx.Format.cbSize = 0;
 
2101
            wfx.Samples.wValidBitsPerSample = 0;
 
2102
            wfx.dwChannelMask = 0;
 
2103
            wfx.SubFormat = GUID_NULL;
 
2104
            result = FilterCanCreateRenderPin(pFilter,(const WAVEFORMATEX*)&wfx);
 
2105
            if( result != paNoError )
 
2106
                 return result;
 
2107
        }
 
2108
 
 
2109
    }
 
2110
    else
 
2111
    {
 
2112
        outputChannelCount = 0;
 
2113
    }
 
2114
 
 
2115
    /*
 
2116
        IMPLEMENT ME:
 
2117
 
 
2118
            - if a full duplex stream is requested, check that the combination
 
2119
                of input and output parameters is supported if necessary
 
2120
 
 
2121
            - check that the device supports sampleRate
 
2122
 
 
2123
        Because the buffer adapter handles conversion between all standard
 
2124
        sample formats, the following checks are only required if paCustomFormat
 
2125
        is implemented, or under some other unusual conditions.
 
2126
 
 
2127
            - check that input device can support inputSampleFormat, or that
 
2128
                we have the capability to convert from inputSampleFormat to
 
2129
                a native format
 
2130
 
 
2131
            - check that output device can support outputSampleFormat, or that
 
2132
                we have the capability to convert from outputSampleFormat to
 
2133
                a native format
 
2134
    */
 
2135
    if((inputChannelCount == 0)&&(outputChannelCount == 0))
 
2136
            result = paSampleFormatNotSupported; /* Not right error */
 
2137
 
 
2138
    PA_LOGL_;
 
2139
    return result;
 
2140
}
 
2141
 
 
2142
/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
 
2143
 
 
2144
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
 
2145
                           PaStream** s,
 
2146
                           const PaStreamParameters *inputParameters,
 
2147
                           const PaStreamParameters *outputParameters,
 
2148
                           double sampleRate,
 
2149
                           unsigned long framesPerBuffer,
 
2150
                           PaStreamFlags streamFlags,
 
2151
                           PaStreamCallback *streamCallback,
 
2152
                           void *userData )
 
2153
{
 
2154
    PaError result = paNoError;
 
2155
    PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
 
2156
    PaWinWdmStream *stream = 0;
 
2157
    /* unsigned long framesPerHostBuffer; these may not be equivalent for all implementations */
 
2158
    PaSampleFormat inputSampleFormat, outputSampleFormat;
 
2159
    PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
 
2160
    int userInputChannels,userOutputChannels;
 
2161
    int size;
 
2162
    PaWinWdmFilter* pFilter;
 
2163
    WAVEFORMATEXTENSIBLE wfx;
 
2164
 
 
2165
    PA_LOGE_;
 
2166
    PA_DEBUG(("OpenStream:sampleRate = %f\n",sampleRate));
 
2167
    PA_DEBUG(("OpenStream:framesPerBuffer = %lu\n",framesPerBuffer));
 
2168
 
 
2169
    if( inputParameters )
 
2170
    {
 
2171
        userInputChannels = inputParameters->channelCount;
 
2172
        inputSampleFormat = inputParameters->sampleFormat;
 
2173
 
 
2174
        /* unless alternate device specification is supported, reject the use of
 
2175
            paUseHostApiSpecificDeviceSpecification */
 
2176
 
 
2177
        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
 
2178
            return paInvalidDevice;
 
2179
 
 
2180
        /* check that input device can support stream->userInputChannels */
 
2181
        if( userInputChannels > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
 
2182
            return paInvalidChannelCount;
 
2183
 
 
2184
        /* validate inputStreamInfo */
 
2185
        if( inputParameters->hostApiSpecificStreamInfo )
 
2186
            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
 
2187
 
 
2188
    }
 
2189
    else
 
2190
    {
 
2191
        userInputChannels = 0;
 
2192
        inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */
 
2193
    }
 
2194
 
 
2195
    if( outputParameters )
 
2196
    {
 
2197
        userOutputChannels = outputParameters->channelCount;
 
2198
        outputSampleFormat = outputParameters->sampleFormat;
 
2199
 
 
2200
        /* unless alternate device specification is supported, reject the use of
 
2201
            paUseHostApiSpecificDeviceSpecification */
 
2202
 
 
2203
        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
 
2204
            return paInvalidDevice;
 
2205
 
 
2206
        /* check that output device can support stream->userInputChannels */
 
2207
        if( userOutputChannels > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
 
2208
            return paInvalidChannelCount;
 
2209
 
 
2210
        /* validate outputStreamInfo */
 
2211
        if( outputParameters->hostApiSpecificStreamInfo )
 
2212
            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
 
2213
 
 
2214
    }
 
2215
    else
 
2216
    {
 
2217
        userOutputChannels = 0;
 
2218
        outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */
 
2219
    }
 
2220
 
 
2221
    /* validate platform specific flags */
 
2222
    if( (streamFlags & paPlatformSpecificFlags) != 0 )
 
2223
        return paInvalidFlag; /* unexpected platform specific flag */
 
2224
 
 
2225
    stream = (PaWinWdmStream*)PaUtil_AllocateMemory( sizeof(PaWinWdmStream) );
 
2226
    if( !stream )
 
2227
    {
 
2228
        result = paInsufficientMemory;
 
2229
        goto error;
 
2230
    }
 
2231
    /* Zero the stream object */
 
2232
    /* memset((void*)stream,0,sizeof(PaWinWdmStream)); */
 
2233
 
 
2234
    if( streamCallback )
 
2235
    {
 
2236
        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
 
2237
                                               &wdmHostApi->callbackStreamInterface, streamCallback, userData );
 
2238
    }
 
2239
    else
 
2240
    {
 
2241
        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
 
2242
                                               &wdmHostApi->blockingStreamInterface, streamCallback, userData );
 
2243
    }
 
2244
 
 
2245
    PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
 
2246
 
 
2247
    /* Instantiate the input pin if necessary */
 
2248
    if(userInputChannels > 0)
 
2249
    {
 
2250
        result = paSampleFormatNotSupported;
 
2251
        pFilter = wdmHostApi->filters[inputParameters->device];
 
2252
        stream->userInputChannels = userInputChannels;
 
2253
 
 
2254
        if(((inputSampleFormat & ~paNonInterleaved) & pFilter->formats) != 0)
 
2255
        {   /* inputSampleFormat is supported, so try to use it */
 
2256
            hostInputSampleFormat = inputSampleFormat;
 
2257
            FillWFEXT(&wfx, hostInputSampleFormat, sampleRate, stream->userInputChannels);
 
2258
            stream->bytesPerInputFrame = wfx.Format.nBlockAlign;
 
2259
            stream->recordingPin = FilterCreateCapturePin(pFilter, (const WAVEFORMATEX*)&wfx, &result);
 
2260
            stream->deviceInputChannels = stream->userInputChannels;
 
2261
        }
 
2262
        
 
2263
        if(result != paNoError)
 
2264
        {   /* Search through all PaSampleFormats to find one that works */
 
2265
            hostInputSampleFormat = paFloat32;
 
2266
 
 
2267
            do {
 
2268
                FillWFEXT(&wfx, hostInputSampleFormat, sampleRate, stream->userInputChannels);
 
2269
                stream->bytesPerInputFrame = wfx.Format.nBlockAlign;
 
2270
                stream->recordingPin = FilterCreateCapturePin(pFilter, (const WAVEFORMATEX*)&wfx, &result);
 
2271
                stream->deviceInputChannels = stream->userInputChannels;
 
2272
                
 
2273
                if(stream->recordingPin == NULL) result = paSampleFormatNotSupported;
 
2274
                if(result != paNoError)    hostInputSampleFormat <<= 1;
 
2275
            }
 
2276
            while(result != paNoError && hostInputSampleFormat <= paUInt8);
 
2277
        }
 
2278
 
 
2279
        if(result != paNoError)
 
2280
        {    /* None of the PaSampleFormats worked.  Set the hostInputSampleFormat to the best fit
 
2281
             * and try a PCM format.
 
2282
             **/
 
2283
            hostInputSampleFormat =
 
2284
                PaUtil_SelectClosestAvailableFormat( pFilter->formats, inputSampleFormat );
 
2285
 
 
2286
            /* Try a WAVE_FORMAT_PCM instead */
 
2287
            wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
 
2288
            wfx.Format.cbSize = 0;
 
2289
            wfx.Samples.wValidBitsPerSample = 0;
 
2290
            wfx.dwChannelMask = 0;
 
2291
            wfx.SubFormat = GUID_NULL;
 
2292
            stream->recordingPin = FilterCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx,&result);
 
2293
            if(stream->recordingPin == NULL) result = paSampleFormatNotSupported;
 
2294
        }
 
2295
 
 
2296
        if( result != paNoError )
 
2297
        {
 
2298
            /* Some or all KS devices can only handle the exact number of channels
 
2299
             * they specify. But PortAudio clients expect to be able to
 
2300
             * at least specify mono I/O on a multi-channel device
 
2301
             * If this is the case, then we will do the channel mapping internally
 
2302
             **/
 
2303
            if( stream->userInputChannels < pFilter->maxInputChannels )
 
2304
            {
 
2305
                FillWFEXT(&wfx,hostInputSampleFormat,sampleRate,pFilter->maxInputChannels);
 
2306
                stream->bytesPerInputFrame = wfx.Format.nBlockAlign;
 
2307
                stream->recordingPin = FilterCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx,&result);
 
2308
                stream->deviceInputChannels = pFilter->maxInputChannels;
 
2309
 
 
2310
                if( result != paNoError )
 
2311
                {
 
2312
                    /* Try a WAVE_FORMAT_PCM instead */
 
2313
                    wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
 
2314
                    wfx.Format.cbSize = 0;
 
2315
                    wfx.Samples.wValidBitsPerSample = 0;
 
2316
                    wfx.dwChannelMask = 0;
 
2317
                    wfx.SubFormat = GUID_NULL;
 
2318
                    stream->recordingPin = FilterCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx,&result);
 
2319
                }
 
2320
            }
 
2321
        }
 
2322
 
 
2323
        if(stream->recordingPin == NULL)
 
2324
        {
 
2325
            goto error;
 
2326
        }
 
2327
 
 
2328
        switch(hostInputSampleFormat)
 
2329
        {
 
2330
            case paInt16: stream->inputSampleSize = 2; break;
 
2331
            case paInt24: stream->inputSampleSize = 3; break;
 
2332
            case paInt32:
 
2333
            case paFloat32:    stream->inputSampleSize = 4; break;
 
2334
        }
 
2335
 
 
2336
        stream->recordingPin->frameSize /= stream->bytesPerInputFrame;
 
2337
        PA_DEBUG(("Pin output frames: %d\n",stream->recordingPin->frameSize));
 
2338
    }
 
2339
    else
 
2340
    {
 
2341
        stream->recordingPin = NULL;
 
2342
        stream->bytesPerInputFrame = 0;
 
2343
    }
 
2344
 
 
2345
    /* Instantiate the output pin if necessary */
 
2346
    if(userOutputChannels > 0)
 
2347
    {
 
2348
        result = paSampleFormatNotSupported;
 
2349
        pFilter = wdmHostApi->filters[outputParameters->device];
 
2350
        stream->userOutputChannels = userOutputChannels;
 
2351
 
 
2352
        if(((outputSampleFormat & ~paNonInterleaved) & pFilter->formats) != 0)
 
2353
        {
 
2354
            hostOutputSampleFormat = outputSampleFormat;
 
2355
            FillWFEXT(&wfx,hostOutputSampleFormat,sampleRate,stream->userOutputChannels);
 
2356
            stream->bytesPerOutputFrame = wfx.Format.nBlockAlign;
 
2357
            stream->playbackPin = FilterCreateRenderPin(pFilter,(WAVEFORMATEX*)&wfx,&result);
 
2358
            stream->deviceOutputChannels = stream->userOutputChannels;
 
2359
        }
 
2360
 
 
2361
        if(result != paNoError)
 
2362
        {
 
2363
            hostOutputSampleFormat = paFloat32;
 
2364
 
 
2365
            do {
 
2366
                FillWFEXT(&wfx,hostOutputSampleFormat,sampleRate,stream->userOutputChannels);
 
2367
                stream->bytesPerOutputFrame = wfx.Format.nBlockAlign;
 
2368
                stream->playbackPin = FilterCreateRenderPin(pFilter,(WAVEFORMATEX*)&wfx,&result);
 
2369
                stream->deviceOutputChannels = stream->userOutputChannels;
 
2370
 
 
2371
                if(stream->playbackPin == NULL) result = paSampleFormatNotSupported;
 
2372
                if(result != paNoError)    hostOutputSampleFormat <<= 1;
 
2373
            }
 
2374
            while(result != paNoError && hostOutputSampleFormat <= paUInt8);
 
2375
        }
 
2376
 
 
2377
        if(result != paNoError)
 
2378
        {
 
2379
            hostOutputSampleFormat =
 
2380
                PaUtil_SelectClosestAvailableFormat( pFilter->formats, outputSampleFormat );
 
2381
       
 
2382
            /* Try a WAVE_FORMAT_PCM instead */
 
2383
            wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
 
2384
            wfx.Format.cbSize = 0;
 
2385
            wfx.Samples.wValidBitsPerSample = 0;
 
2386
            wfx.dwChannelMask = 0;
 
2387
            wfx.SubFormat = GUID_NULL;
 
2388
            stream->playbackPin = FilterCreateRenderPin(pFilter,(WAVEFORMATEX*)&wfx,&result);
 
2389
            if(stream->playbackPin == NULL) result = paSampleFormatNotSupported;
 
2390
        }
 
2391
            
 
2392
        if( result != paNoError )
 
2393
        {
 
2394
            /* Some or all KS devices can only handle the exact number of channels
 
2395
             * they specify. But PortAudio clients expect to be able to
 
2396
             * at least specify mono I/O on a multi-channel device
 
2397
             * If this is the case, then we will do the channel mapping internally
 
2398
             **/
 
2399
            if( stream->userOutputChannels < pFilter->maxOutputChannels )
 
2400
            {
 
2401
                FillWFEXT(&wfx,hostOutputSampleFormat,sampleRate,pFilter->maxOutputChannels);
 
2402
                stream->bytesPerOutputFrame = wfx.Format.nBlockAlign;
 
2403
                stream->playbackPin = FilterCreateRenderPin(pFilter,(const WAVEFORMATEX*)&wfx,&result);
 
2404
                stream->deviceOutputChannels = pFilter->maxOutputChannels;
 
2405
                if( result != paNoError )
 
2406
                {
 
2407
                    /* Try a WAVE_FORMAT_PCM instead */
 
2408
                    wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
 
2409
                    wfx.Format.cbSize = 0;
 
2410
                    wfx.Samples.wValidBitsPerSample = 0;
 
2411
                    wfx.dwChannelMask = 0;
 
2412
                    wfx.SubFormat = GUID_NULL;
 
2413
                    stream->playbackPin = FilterCreateRenderPin(pFilter,(const WAVEFORMATEX*)&wfx,&result);
 
2414
                }
 
2415
            }
 
2416
        }
 
2417
 
 
2418
        if(stream->playbackPin == NULL)
 
2419
        {
 
2420
            goto error;
 
2421
        }
 
2422
 
 
2423
        switch(hostOutputSampleFormat)
 
2424
        {
 
2425
            case paInt16: stream->outputSampleSize = 2; break;
 
2426
            case paInt24: stream->outputSampleSize = 3; break;
 
2427
            case paInt32:
 
2428
            case paFloat32: stream->outputSampleSize = 4; break;
 
2429
        }
 
2430
 
 
2431
        stream->playbackPin->frameSize /= stream->bytesPerOutputFrame;
 
2432
        PA_DEBUG(("Pin output frames: %d\n",stream->playbackPin->frameSize));
 
2433
    }
 
2434
    else
 
2435
    {
 
2436
        stream->playbackPin = NULL;
 
2437
        stream->bytesPerOutputFrame = 0;
 
2438
    }
 
2439
 
 
2440
    /* Calculate the framesPerHostXxxxBuffer size based upon the suggested latency values */
 
2441
 
 
2442
    /* Record the buffer length */
 
2443
    if(inputParameters)
 
2444
    {
 
2445
        /* Calculate the frames from the user's value - add a bit to round up */
 
2446
            stream->framesPerHostIBuffer = (unsigned long)((inputParameters->suggestedLatency*sampleRate)+0.0001);
 
2447
        if(stream->framesPerHostIBuffer > (unsigned long)sampleRate)
 
2448
        { /* Upper limit is 1 second */
 
2449
              stream->framesPerHostIBuffer = (unsigned long)sampleRate;
 
2450
        }
 
2451
        else if(stream->framesPerHostIBuffer < stream->recordingPin->frameSize)
 
2452
        {
 
2453
              stream->framesPerHostIBuffer = stream->recordingPin->frameSize;
 
2454
        }
 
2455
        PA_DEBUG(("Input frames chosen:%ld\n",stream->framesPerHostIBuffer));
 
2456
    }
 
2457
 
 
2458
    if(outputParameters)
 
2459
    {
 
2460
        /* Calculate the frames from the user's value - add a bit to round up */
 
2461
        stream->framesPerHostOBuffer = (unsigned long)((outputParameters->suggestedLatency*sampleRate)+0.0001);
 
2462
        if(stream->framesPerHostOBuffer > (unsigned long)sampleRate)
 
2463
        { /* Upper limit is 1 second */
 
2464
                  stream->framesPerHostOBuffer = (unsigned long)sampleRate;
 
2465
        }
 
2466
        else if(stream->framesPerHostOBuffer < stream->playbackPin->frameSize)
 
2467
        {
 
2468
              stream->framesPerHostOBuffer = stream->playbackPin->frameSize;
 
2469
        }
 
2470
        PA_DEBUG(("Output frames chosen:%ld\n",stream->framesPerHostOBuffer));
 
2471
    }
 
2472
 
 
2473
    /* Host buffer size is bounded to the largest of the input and output
 
2474
    frame sizes */
 
2475
 
 
2476
    result =  PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
 
2477
              stream->userInputChannels, inputSampleFormat, hostInputSampleFormat,
 
2478
              stream->userOutputChannels, outputSampleFormat, hostOutputSampleFormat,
 
2479
              sampleRate, streamFlags, framesPerBuffer,
 
2480
              max(stream->framesPerHostOBuffer,stream->framesPerHostIBuffer),
 
2481
              paUtilBoundedHostBufferSize,
 
2482
              streamCallback, userData );
 
2483
    if( result != paNoError )
 
2484
        goto error;
 
2485
 
 
2486
    stream->streamRepresentation.streamInfo.inputLatency =
 
2487
            ((double)stream->framesPerHostIBuffer) / sampleRate;
 
2488
    stream->streamRepresentation.streamInfo.outputLatency =
 
2489
            ((double)stream->framesPerHostOBuffer) / sampleRate;
 
2490
    stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
 
2491
 
 
2492
      PA_DEBUG(("BytesPerInputFrame = %d\n",stream->bytesPerInputFrame));
 
2493
      PA_DEBUG(("BytesPerOutputFrame = %d\n",stream->bytesPerOutputFrame));
 
2494
 
 
2495
    /* Allocate all the buffers for host I/O */
 
2496
    size = 2 * (stream->framesPerHostIBuffer*stream->bytesPerInputFrame +  stream->framesPerHostOBuffer*stream->bytesPerOutputFrame);
 
2497
    PA_DEBUG(("Buffer size = %d\n",size));
 
2498
    stream->hostBuffer = (char*)PaUtil_AllocateMemory(size);
 
2499
    PA_DEBUG(("Buffer allocated\n"));
 
2500
    if( !stream->hostBuffer )
 
2501
    {
 
2502
        PA_DEBUG(("Cannot allocate host buffer!\n"));
 
2503
        result = paInsufficientMemory;
 
2504
        goto error;
 
2505
    }
 
2506
    PA_DEBUG(("Buffer start = %p\n",stream->hostBuffer));
 
2507
    /* memset(stream->hostBuffer,0,size); */
 
2508
 
 
2509
    /* Set up the packets */
 
2510
    stream->events[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
 
2511
    ResetEvent(stream->events[0]); /* Record buffer 1 */
 
2512
    stream->events[1] = CreateEvent(NULL, FALSE, FALSE, NULL);
 
2513
    ResetEvent(stream->events[1]); /* Record buffer 2 */
 
2514
    stream->events[2] = CreateEvent(NULL, FALSE, FALSE, NULL);
 
2515
    ResetEvent(stream->events[2]); /* Play buffer 1 */
 
2516
    stream->events[3] = CreateEvent(NULL, FALSE, FALSE, NULL);
 
2517
    ResetEvent(stream->events[3]); /* Play buffer 2 */
 
2518
    stream->events[4] = CreateEvent(NULL, FALSE, FALSE, NULL);
 
2519
    ResetEvent(stream->events[4]); /* Abort event */
 
2520
    if(stream->userInputChannels > 0)
 
2521
    {
 
2522
        DATAPACKET *p = &(stream->packets[0]);
 
2523
        p->Signal.hEvent = stream->events[0];
 
2524
        p->Header.Data = stream->hostBuffer;
 
2525
        p->Header.FrameExtent = stream->framesPerHostIBuffer*stream->bytesPerInputFrame;
 
2526
        p->Header.DataUsed = 0;
 
2527
        p->Header.Size = sizeof(p->Header);
 
2528
        p->Header.PresentationTime.Numerator = 1;
 
2529
        p->Header.PresentationTime.Denominator = 1;
 
2530
 
 
2531
        p = &(stream->packets[1]);
 
2532
        p->Signal.hEvent = stream->events[1];
 
2533
        p->Header.Data = stream->hostBuffer + stream->framesPerHostIBuffer*stream->bytesPerInputFrame;
 
2534
        p->Header.FrameExtent = stream->framesPerHostIBuffer*stream->bytesPerInputFrame;
 
2535
        p->Header.DataUsed = 0;
 
2536
        p->Header.Size = sizeof(p->Header);
 
2537
        p->Header.PresentationTime.Numerator = 1;
 
2538
        p->Header.PresentationTime.Denominator = 1;
 
2539
    }
 
2540
    if(stream->userOutputChannels > 0)
 
2541
    {
 
2542
        DATAPACKET *p = &(stream->packets[2]);
 
2543
        p->Signal.hEvent = stream->events[2];
 
2544
        p->Header.Data = stream->hostBuffer + 2*stream->framesPerHostIBuffer*stream->bytesPerInputFrame;
 
2545
        p->Header.FrameExtent = stream->framesPerHostOBuffer*stream->bytesPerOutputFrame;
 
2546
        p->Header.DataUsed = stream->framesPerHostOBuffer*stream->bytesPerOutputFrame;
 
2547
        p->Header.Size = sizeof(p->Header);
 
2548
        p->Header.PresentationTime.Numerator = 1;
 
2549
        p->Header.PresentationTime.Denominator = 1;
 
2550
    
 
2551
        p = &(stream->packets[3]);
 
2552
        p->Signal.hEvent = stream->events[3];
 
2553
        p->Header.Data = stream->hostBuffer + 2*stream->framesPerHostIBuffer*stream->bytesPerInputFrame + stream->framesPerHostOBuffer*stream->bytesPerOutputFrame;
 
2554
        p->Header.FrameExtent = stream->framesPerHostOBuffer*stream->bytesPerOutputFrame;
 
2555
        p->Header.DataUsed = stream->framesPerHostOBuffer*stream->bytesPerOutputFrame;
 
2556
        p->Header.Size = sizeof(p->Header);
 
2557
        p->Header.PresentationTime.Numerator = 1;
 
2558
        p->Header.PresentationTime.Denominator = 1;
 
2559
    }
 
2560
 
 
2561
    stream->streamStarted = 0;
 
2562
    stream->streamActive = 0;
 
2563
    stream->streamStop = 0;
 
2564
    stream->streamAbort = 0;
 
2565
    stream->streamFlags = streamFlags;
 
2566
    stream->oldProcessPriority = REALTIME_PRIORITY_CLASS;
 
2567
 
 
2568
    *s = (PaStream*)stream;
 
2569
 
 
2570
    PA_LOGL_;
 
2571
    return result;
 
2572
 
 
2573
error:
 
2574
    size = 5;
 
2575
    while(size--)
 
2576
    {
 
2577
        if(stream->events[size] != NULL)
 
2578
        {
 
2579
            CloseHandle(stream->events[size]);
 
2580
            stream->events[size] = NULL;
 
2581
        }
 
2582
    }
 
2583
    if(stream->hostBuffer)
 
2584
        PaUtil_FreeMemory( stream->hostBuffer );
 
2585
 
 
2586
    if(stream->playbackPin)
 
2587
        PinClose(stream->playbackPin);
 
2588
    if(stream->recordingPin)
 
2589
        PinClose(stream->recordingPin);
 
2590
 
 
2591
    if( stream )
 
2592
        PaUtil_FreeMemory( stream );
 
2593
 
 
2594
    PA_LOGL_;
 
2595
    return result;
 
2596
}
 
2597
 
 
2598
/*
 
2599
    When CloseStream() is called, the multi-api layer ensures that
 
2600
    the stream has already been stopped or aborted.
 
2601
*/
 
2602
static PaError CloseStream( PaStream* s )
 
2603
{
 
2604
    PaError result = paNoError;
 
2605
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
 
2606
    int size;
 
2607
 
 
2608
    PA_LOGE_;
 
2609
 
 
2610
    assert(!stream->streamStarted);
 
2611
    assert(!stream->streamActive);
 
2612
 
 
2613
    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
 
2614
    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
 
2615
    size = 5;
 
2616
    while(size--)
 
2617
    {
 
2618
        if(stream->events[size] != NULL)
 
2619
        {
 
2620
            CloseHandle(stream->events[size]);
 
2621
            stream->events[size] = NULL;
 
2622
        }
 
2623
    }
 
2624
    if(stream->hostBuffer)
 
2625
        PaUtil_FreeMemory( stream->hostBuffer );
 
2626
 
 
2627
    if(stream->playbackPin)
 
2628
        PinClose(stream->playbackPin);
 
2629
    if(stream->recordingPin)
 
2630
        PinClose(stream->recordingPin);
 
2631
 
 
2632
    PaUtil_FreeMemory( stream );
 
2633
 
 
2634
    PA_LOGL_;
 
2635
    return result;
 
2636
}
 
2637
 
 
2638
/*
 
2639
Write the supplied packet to the pin
 
2640
Asynchronous
 
2641
Should return false on success
 
2642
*/
 
2643
static BOOL PinWrite(HANDLE h, DATAPACKET* p)
 
2644
{
 
2645
    unsigned long cbReturned = 0;
 
2646
    return DeviceIoControl(h,IOCTL_KS_WRITE_STREAM,NULL,0,
 
2647
                            &p->Header,p->Header.Size,&cbReturned,&p->Signal);
 
2648
}
 
2649
 
 
2650
/*
 
2651
Read to the supplied packet from the pin
 
2652
Asynchronous
 
2653
Should return false on success
 
2654
*/
 
2655
static BOOL PinRead(HANDLE h, DATAPACKET* p)
 
2656
{
 
2657
    unsigned long cbReturned = 0;
 
2658
    return DeviceIoControl(h,IOCTL_KS_READ_STREAM,NULL,0,
 
2659
                            &p->Header,p->Header.Size,&cbReturned,&p->Signal);
 
2660
}
 
2661
 
 
2662
/*
 
2663
Copy the first interleaved channel of 16 bit data to the other channels
 
2664
*/
 
2665
static void DuplicateFirstChannelInt16(void* buffer, int channels, int samples)
 
2666
{
 
2667
    unsigned short* data = (unsigned short*)buffer;
 
2668
    int channel;
 
2669
    unsigned short sourceSample;
 
2670
    while( samples-- )
 
2671
    {
 
2672
        sourceSample = *data++;
 
2673
        channel = channels-1;
 
2674
        while( channel-- )
 
2675
        {
 
2676
            *data++ = sourceSample;
 
2677
        }
 
2678
    }
 
2679
}
 
2680
 
 
2681
/*
 
2682
Copy the first interleaved channel of 24 bit data to the other channels
 
2683
*/
 
2684
static void DuplicateFirstChannelInt24(void* buffer, int channels, int samples)
 
2685
{
 
2686
    unsigned char* data = (unsigned char*)buffer;
 
2687
    int channel;
 
2688
    unsigned char sourceSample[3];
 
2689
    while( samples-- )
 
2690
    {
 
2691
        sourceSample[0] = data[0];
 
2692
        sourceSample[1] = data[1];
 
2693
        sourceSample[2] = data[2];
 
2694
        data += 3;
 
2695
        channel = channels-1;
 
2696
        while( channel-- )
 
2697
        {
 
2698
            data[0] = sourceSample[0];
 
2699
            data[1] = sourceSample[1];
 
2700
            data[2] = sourceSample[2];
 
2701
            data += 3;
 
2702
        }
 
2703
    }
 
2704
}
 
2705
 
 
2706
/*
 
2707
Copy the first interleaved channel of 32 bit data to the other channels
 
2708
*/
 
2709
static void DuplicateFirstChannelInt32(void* buffer, int channels, int samples)
 
2710
{
 
2711
    unsigned long* data = (unsigned long*)buffer;
 
2712
    int channel;
 
2713
    unsigned long sourceSample;
 
2714
    while( samples-- )
 
2715
    {
 
2716
        sourceSample = *data++;
 
2717
        channel = channels-1;
 
2718
        while( channel-- )
 
2719
        {
 
2720
            *data++ = sourceSample;
 
2721
        }
 
2722
    }
 
2723
}
 
2724
 
 
2725
static DWORD WINAPI ProcessingThread(LPVOID pParam)
 
2726
{
 
2727
    PaWinWdmStream *stream = (PaWinWdmStream*)pParam;
 
2728
    PaStreamCallbackTimeInfo ti;
 
2729
    int cbResult = paContinue;
 
2730
    int inbuf = 0;
 
2731
    int outbuf = 0;
 
2732
    int pending = 0;
 
2733
    PaError result;
 
2734
    unsigned long wait;
 
2735
    unsigned long eventSignaled;
 
2736
    int fillPlaybuf = 0;
 
2737
    int emptyRecordbuf = 0;
 
2738
    int framesProcessed;
 
2739
    unsigned long timeout;
 
2740
    int i;
 
2741
    int doChannelCopy;
 
2742
    int priming = 0;
 
2743
    PaStreamCallbackFlags underover = 0;
 
2744
 
 
2745
    PA_LOGE_;
 
2746
 
 
2747
    ti.inputBufferAdcTime = 0.0;
 
2748
    ti.currentTime = 0.0;
 
2749
    ti.outputBufferDacTime = 0.0;
 
2750
 
 
2751
    /* Get double buffering going */
 
2752
 
 
2753
    /* Submit buffers */
 
2754
    if(stream->playbackPin)
 
2755
    {
 
2756
        result = PinSetState(stream->playbackPin, KSSTATE_RUN);
 
2757
 
 
2758
        PA_DEBUG(("play state run = %d;",(int)result));
 
2759
        SetEvent(stream->events[outbuf+2]);
 
2760
        outbuf = (outbuf+1)&1;
 
2761
        SetEvent(stream->events[outbuf+2]);
 
2762
        outbuf = (outbuf+1)&1;
 
2763
        pending += 2;
 
2764
        priming += 4;
 
2765
    }
 
2766
    if(stream->recordingPin)
 
2767
    {
 
2768
        result = PinSetState(stream->recordingPin, KSSTATE_RUN);
 
2769
 
 
2770
        PA_DEBUG(("recording state run = %d;",(int)result));
 
2771
        PinRead(stream->recordingPin->handle,&stream->packets[inbuf]);
 
2772
        inbuf = (inbuf+1)&1; /* Increment and wrap */
 
2773
        PinRead(stream->recordingPin->handle,&stream->packets[inbuf]);
 
2774
        inbuf = (inbuf+1)&1; /* Increment and wrap */
 
2775
        /* FIXME - do error checking */
 
2776
        pending += 2;
 
2777
    }
 
2778
    PA_DEBUG(("Out buffer len:%f\n",(2000*stream->framesPerHostOBuffer) / stream->streamRepresentation.streamInfo.sampleRate));
 
2779
    PA_DEBUG(("In buffer len:%f\n",(2000*stream->framesPerHostIBuffer) / stream->streamRepresentation.streamInfo.sampleRate));
 
2780
    timeout = max(
 
2781
       ((2000*(DWORD)stream->framesPerHostOBuffer) / (DWORD)stream->streamRepresentation.streamInfo.sampleRate),
 
2782
       ((2000*(DWORD)stream->framesPerHostIBuffer) / (DWORD)stream->streamRepresentation.streamInfo.sampleRate));
 
2783
    timeout = max(timeout,1);
 
2784
    PA_DEBUG(("Timeout = %ld\n",timeout));
 
2785
 
 
2786
    while(!stream->streamAbort)
 
2787
    {
 
2788
        fillPlaybuf = 0;
 
2789
        emptyRecordbuf = 0;
 
2790
 
 
2791
        /* Wait for next input or output buffer to be finished with*/
 
2792
        assert(pending>0);
 
2793
 
 
2794
        if(stream->streamStop)
 
2795
        {
 
2796
            PA_DEBUG(("ss1:pending=%d ",pending));
 
2797
        }
 
2798
        wait = WaitForMultipleObjects(5, stream->events, FALSE, 0);
 
2799
        if( wait == WAIT_TIMEOUT )
 
2800
        {
 
2801
            /* No (under|over)flow has ocurred */
 
2802
            wait = WaitForMultipleObjects(5, stream->events, FALSE, timeout);
 
2803
            eventSignaled = wait - WAIT_OBJECT_0;
 
2804
        }
 
2805
        else
 
2806
        {
 
2807
            eventSignaled = wait - WAIT_OBJECT_0;
 
2808
            if( eventSignaled < 2 )
 
2809
            {
 
2810
                underover |= paInputOverflow;
 
2811
                PA_DEBUG(("Input overflow\n"));
 
2812
            }
 
2813
            else if(( eventSignaled < 4 )&&(!priming))
 
2814
            {
 
2815
                underover |= paOutputUnderflow;
 
2816
                PA_DEBUG(("Output underflow\n"));
 
2817
            }
 
2818
        }
 
2819
 
 
2820
        if(stream->streamStop)
 
2821
        {
 
2822
            PA_DEBUG(("ss2:wait=%ld",wait));
 
2823
        }
 
2824
        if(wait == WAIT_FAILED)
 
2825
        {
 
2826
            PA_DEBUG(("Wait fail = %ld! ",wait));
 
2827
            break;
 
2828
        }
 
2829
        if(wait == WAIT_TIMEOUT)
 
2830
        {
 
2831
            continue;
 
2832
        }
 
2833
 
 
2834
        if(eventSignaled < 2)
 
2835
        { /* Recording input buffer has been filled */
 
2836
            if(stream->playbackPin)
 
2837
            {
 
2838
                /* First check if also the next playback buffer has been signaled */
 
2839
                wait = WaitForSingleObject(stream->events[outbuf+2],0);
 
2840
                if(wait == WAIT_OBJECT_0)
 
2841
                {
 
2842
                    /* Yes, so do both buffers at same time */
 
2843
                    fillPlaybuf = 1;
 
2844
                    pending--;
 
2845
                    /* Was this an underflow situation? */
 
2846
                    if( underover )
 
2847
                        underover |= paOutputUnderflow; /* Yes! */
 
2848
                }
 
2849
            }
 
2850
            emptyRecordbuf = 1;
 
2851
            pending--;
 
2852
        }
 
2853
        else if(eventSignaled < 4)
 
2854
        { /* Playback output buffer has been emptied */
 
2855
            if(stream->recordingPin)
 
2856
            {
 
2857
                /* First check if also the next recording buffer has been signaled */
 
2858
                wait = WaitForSingleObject(stream->events[inbuf],0);
 
2859
                if(wait == WAIT_OBJECT_0)
 
2860
                { /* Yes, so do both buffers at same time */
 
2861
                    emptyRecordbuf = 1;
 
2862
                    pending--;
 
2863
                    /* Was this an overflow situation? */
 
2864
                    if( underover )
 
2865
                        underover |= paInputOverflow; /* Yes! */
 
2866
                }
 
2867
            }
 
2868
            fillPlaybuf = 1;
 
2869
            pending--;
 
2870
        }
 
2871
        else
 
2872
        {
 
2873
            /* Abort event! */
 
2874
            assert(stream->streamAbort); /* Should have been set */
 
2875
            PA_DEBUG(("ABORTING "));
 
2876
            break;
 
2877
        }
 
2878
        ResetEvent(stream->events[eventSignaled]);
 
2879
 
 
2880
        if(stream->streamStop)
 
2881
        {
 
2882
            PA_DEBUG(("Stream stop! pending=%d",pending));
 
2883
            cbResult = paComplete; /* Stop, but play remaining buffers */
 
2884
        }
 
2885
 
 
2886
        /* Do necessary buffer processing (which will invoke user callback if necessary */
 
2887
        doChannelCopy = 0;
 
2888
        if(cbResult==paContinue)
 
2889
        {
 
2890
            PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
 
2891
            if((stream->bufferProcessor.hostInputFrameCount[0] + stream->bufferProcessor.hostInputFrameCount[1]) ==
 
2892
                (stream->bufferProcessor.hostOutputFrameCount[0] + stream->bufferProcessor.hostOutputFrameCount[1]) )
 
2893
                PaUtil_BeginBufferProcessing(&stream->bufferProcessor,&ti,underover);
 
2894
            underover = 0; /* Reset the (under|over)flow status */
 
2895
            if(fillPlaybuf)
 
2896
            {
 
2897
                PaUtil_SetOutputFrameCount(&stream->bufferProcessor,0);
 
2898
                if( stream->userOutputChannels == 1 )
 
2899
                {
 
2900
                    /* Write the single user channel to the first interleaved block */
 
2901
                    PaUtil_SetOutputChannel(&stream->bufferProcessor,0,stream->packets[outbuf+2].Header.Data,stream->deviceOutputChannels);
 
2902
                    /* We will do a copy to the other channels after the data has been written */
 
2903
                    doChannelCopy = 1;
 
2904
                }
 
2905
                else
 
2906
                {
 
2907
                    for(i=0;i<stream->userOutputChannels;i++)
 
2908
                    {
 
2909
                        /* Only write the user output channels. Leave the rest blank */
 
2910
                        PaUtil_SetOutputChannel(&stream->bufferProcessor,i,((unsigned char*)(stream->packets[outbuf+2].Header.Data))+(i*stream->outputSampleSize),stream->deviceOutputChannels);
 
2911
                    }
 
2912
                }
 
2913
            }
 
2914
            if(emptyRecordbuf)
 
2915
            {
 
2916
                PaUtil_SetInputFrameCount(&stream->bufferProcessor,stream->packets[inbuf].Header.DataUsed/stream->bytesPerInputFrame);
 
2917
                for(i=0;i<stream->userInputChannels;i++)
 
2918
                {
 
2919
                    /* Only read as many channels as the user wants */
 
2920
                    PaUtil_SetInputChannel(&stream->bufferProcessor,i,((unsigned char*)(stream->packets[inbuf].Header.Data))+(i*stream->inputSampleSize),stream->deviceInputChannels);
 
2921
                }
 
2922
            }
 
2923
            
 
2924
            if (stream->recordingPin && stream->playbackPin) /* full duplex */
 
2925
            {
 
2926
                /* Only call the EndBufferProcessing function when the total input frames == total output frames */
 
2927
 
 
2928
                if((stream->bufferProcessor.hostInputFrameCount[0] + stream->bufferProcessor.hostInputFrameCount[1]) ==
 
2929
                        (stream->bufferProcessor.hostOutputFrameCount[0] + stream->bufferProcessor.hostOutputFrameCount[1]) )
 
2930
                {
 
2931
                    framesProcessed = PaUtil_EndBufferProcessing(&stream->bufferProcessor,&cbResult);
 
2932
                }
 
2933
                else
 
2934
                {
 
2935
                    framesProcessed = 0;
 
2936
                }
 
2937
            }
 
2938
            else 
 
2939
            {
 
2940
                framesProcessed = PaUtil_EndBufferProcessing(&stream->bufferProcessor,&cbResult);
 
2941
            }
 
2942
 
 
2943
            if( doChannelCopy )
 
2944
            {
 
2945
                /* Copy the first output channel to the other channels */
 
2946
                switch(stream->outputSampleSize)
 
2947
                {
 
2948
                    case 2:
 
2949
                        DuplicateFirstChannelInt16(stream->packets[outbuf+2].Header.Data,stream->deviceOutputChannels,stream->framesPerHostOBuffer);
 
2950
                        break;
 
2951
                    case 3:
 
2952
                        DuplicateFirstChannelInt24(stream->packets[outbuf+2].Header.Data,stream->deviceOutputChannels,stream->framesPerHostOBuffer);
 
2953
                        break;
 
2954
                    case 4:
 
2955
                        DuplicateFirstChannelInt32(stream->packets[outbuf+2].Header.Data,stream->deviceOutputChannels,stream->framesPerHostOBuffer);
 
2956
                        break;
 
2957
                    default:
 
2958
                        assert(0); /* Unsupported format! */
 
2959
                        break;
 
2960
                }
 
2961
            }
 
2962
            PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
 
2963
        }
 
2964
        else
 
2965
        {
 
2966
            fillPlaybuf = 0;
 
2967
            emptyRecordbuf = 0;
 
2968
        }
 
2969
            
 
2970
        /*
 
2971
        if(cbResult != paContinue)
 
2972
        {
 
2973
            PA_DEBUG(("cbResult=%d, pending=%d:",cbResult,pending));
 
2974
        }
 
2975
        */
 
2976
        /* Submit buffers */
 
2977
        if((fillPlaybuf)&&(cbResult!=paAbort))
 
2978
        {
 
2979
            if(!PinWrite(stream->playbackPin->handle,&stream->packets[outbuf+2]))
 
2980
                outbuf = (outbuf+1)&1; /* Increment and wrap */
 
2981
            pending++;
 
2982
            if( priming )
 
2983
                priming--; /* Have to prime twice */
 
2984
        }
 
2985
        if((emptyRecordbuf)&&(cbResult==paContinue))
 
2986
        {
 
2987
            stream->packets[inbuf].Header.DataUsed = 0; /* Reset for reuse */
 
2988
            PinRead(stream->recordingPin->handle,&stream->packets[inbuf]);
 
2989
            inbuf = (inbuf+1)&1; /* Increment and wrap */
 
2990
            pending++;
 
2991
        }
 
2992
        if(pending==0)
 
2993
        {
 
2994
            PA_DEBUG(("pending==0 finished...;"));
 
2995
            break;
 
2996
        }
 
2997
        if((!stream->playbackPin)&&(cbResult!=paContinue))
 
2998
        {
 
2999
            PA_DEBUG(("record only cbResult=%d...;",cbResult));
 
3000
            break;
 
3001
        }
 
3002
    }
 
3003
 
 
3004
    PA_DEBUG(("Finished thread"));
 
3005
 
 
3006
    /* Finished, either normally or aborted */
 
3007
    if(stream->playbackPin)
 
3008
    {
 
3009
        result = PinSetState(stream->playbackPin, KSSTATE_PAUSE);
 
3010
        result = PinSetState(stream->playbackPin, KSSTATE_STOP);
 
3011
    }
 
3012
    if(stream->recordingPin)
 
3013
    {
 
3014
        result = PinSetState(stream->recordingPin, KSSTATE_PAUSE);
 
3015
        result = PinSetState(stream->recordingPin, KSSTATE_STOP);
 
3016
    }
 
3017
 
 
3018
    stream->streamActive = 0;
 
3019
 
 
3020
    if((!stream->streamStop)&&(!stream->streamAbort))
 
3021
    {
 
3022
          /* Invoke the user stream finished callback */
 
3023
          /* Only do it from here if not being stopped/aborted by user */
 
3024
          if( stream->streamRepresentation.streamFinishedCallback != 0 )
 
3025
              stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
 
3026
    }
 
3027
    stream->streamStop = 0;
 
3028
    stream->streamAbort = 0;
 
3029
 
 
3030
    /* Reset process priority if necessary */
 
3031
    if(stream->oldProcessPriority != REALTIME_PRIORITY_CLASS)
 
3032
    {
 
3033
        SetPriorityClass(GetCurrentProcess(),stream->oldProcessPriority);
 
3034
        stream->oldProcessPriority = REALTIME_PRIORITY_CLASS;
 
3035
    }
 
3036
 
 
3037
    PA_LOGL_;
 
3038
    EXIT_THREAD;
 
3039
    return 0;
 
3040
}
 
3041
 
 
3042
static PaError StartStream( PaStream *s )
 
3043
{
 
3044
    PaError result = paNoError;
 
3045
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
 
3046
    DWORD dwID;
 
3047
    BOOL ret;
 
3048
    int size;
 
3049
 
 
3050
    PA_LOGE_;
 
3051
 
 
3052
    stream->streamStop = 0;
 
3053
    stream->streamAbort = 0;
 
3054
    size = 5;
 
3055
    while(size--)
 
3056
    {
 
3057
        if(stream->events[size] != NULL)
 
3058
        {
 
3059
            ResetEvent(stream->events[size]);
 
3060
        }
 
3061
    }
 
3062
 
 
3063
    PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
 
3064
 
 
3065
    stream->oldProcessPriority = GetPriorityClass(GetCurrentProcess());
 
3066
    /* Uncomment the following line to enable dynamic boosting of the process
 
3067
     * priority to real time for best low latency support
 
3068
     * Disabled by default because RT processes can easily block the OS */
 
3069
    /*ret = SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS);
 
3070
      PA_DEBUG(("Class ret = %d;",ret));*/
 
3071
 
 
3072
    stream->streamStarted = 1;
 
3073
    stream->streamThread = (HANDLE)_beginthreadex(NULL, 0, ProcessingThread, stream, 0, &dwID);
 
3074
    if(stream->streamThread == NULL)
 
3075
    {
 
3076
        stream->streamStarted = 0;
 
3077
        result = paInsufficientMemory;
 
3078
        goto end;
 
3079
    }
 
3080
    ret = SetThreadPriority(stream->streamThread,THREAD_PRIORITY_TIME_CRITICAL);
 
3081
    PA_DEBUG(("Priority ret = %d;",ret));
 
3082
    /* Make the stream active */
 
3083
    stream->streamActive = 1;
 
3084
 
 
3085
end:
 
3086
    PA_LOGL_;
 
3087
    return result;
 
3088
}
 
3089
 
 
3090
 
 
3091
static PaError StopStream( PaStream *s )
 
3092
{
 
3093
    PaError result = paNoError;
 
3094
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
 
3095
    int doCb = 0;
 
3096
 
 
3097
    PA_LOGE_;
 
3098
 
 
3099
    if(stream->streamActive)
 
3100
    {
 
3101
        doCb = 1;
 
3102
        stream->streamStop = 1;
 
3103
        while(stream->streamActive)
 
3104
        {
 
3105
            PA_DEBUG(("W."));
 
3106
            Sleep(10); /* Let thread sleep for 10 msec */
 
3107
        }
 
3108
    }
 
3109
 
 
3110
    PA_DEBUG(("Terminating thread"));
 
3111
    if(stream->streamStarted && stream->streamThread)
 
3112
    {
 
3113
        TerminateThread(stream->streamThread,0);
 
3114
        stream->streamThread = NULL;
 
3115
    }
 
3116
 
 
3117
    stream->streamStarted = 0;
 
3118
 
 
3119
    if(stream->oldProcessPriority != REALTIME_PRIORITY_CLASS)
 
3120
    {
 
3121
        SetPriorityClass(GetCurrentProcess(),stream->oldProcessPriority);
 
3122
        stream->oldProcessPriority = REALTIME_PRIORITY_CLASS;
 
3123
    }
 
3124
 
 
3125
    if(doCb)
 
3126
    {
 
3127
        /* Do user callback now after all state has been reset */
 
3128
        /* This means it should be safe for the called function */
 
3129
        /* to invoke e.g. StartStream */
 
3130
        if( stream->streamRepresentation.streamFinishedCallback != 0 )
 
3131
             stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
 
3132
    }
 
3133
 
 
3134
    PA_LOGL_;
 
3135
    return result;
 
3136
}
 
3137
 
 
3138
static PaError AbortStream( PaStream *s )
 
3139
{
 
3140
    PaError result = paNoError;
 
3141
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
 
3142
    int doCb = 0;
 
3143
 
 
3144
    PA_LOGE_;
 
3145
 
 
3146
    if(stream->streamActive)
 
3147
    {
 
3148
        doCb = 1;
 
3149
        stream->streamAbort = 1;
 
3150
        SetEvent(stream->events[4]); /* Signal immediately */
 
3151
        while(stream->streamActive)
 
3152
        {
 
3153
            Sleep(10);
 
3154
        }
 
3155
    }
 
3156
 
 
3157
    if(stream->streamStarted && stream->streamThread)
 
3158
    {
 
3159
        TerminateThread(stream->streamThread,0);
 
3160
        stream->streamThread = NULL;
 
3161
    }
 
3162
 
 
3163
    stream->streamStarted = 0;
 
3164
 
 
3165
    if(stream->oldProcessPriority != REALTIME_PRIORITY_CLASS)
 
3166
    {
 
3167
        SetPriorityClass(GetCurrentProcess(),stream->oldProcessPriority);
 
3168
        stream->oldProcessPriority = REALTIME_PRIORITY_CLASS;
 
3169
    }
 
3170
 
 
3171
    if(doCb)
 
3172
    {
 
3173
        /* Do user callback now after all state has been reset */
 
3174
        /* This means it should be safe for the called function */
 
3175
        /* to invoke e.g. StartStream */
 
3176
        if( stream->streamRepresentation.streamFinishedCallback != 0 )
 
3177
            stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
 
3178
    }
 
3179
 
 
3180
    stream->streamActive = 0;
 
3181
    stream->streamStarted = 0;
 
3182
 
 
3183
    PA_LOGL_;
 
3184
    return result;
 
3185
}
 
3186
 
 
3187
 
 
3188
static PaError IsStreamStopped( PaStream *s )
 
3189
{
 
3190
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
 
3191
    int result = 0;
 
3192
 
 
3193
    PA_LOGE_;
 
3194
 
 
3195
    if(!stream->streamStarted)
 
3196
        result = 1;
 
3197
 
 
3198
    PA_LOGL_;
 
3199
    return result;
 
3200
}
 
3201
 
 
3202
 
 
3203
static PaError IsStreamActive( PaStream *s )
 
3204
{
 
3205
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
 
3206
    int result = 0;
 
3207
 
 
3208
    PA_LOGE_;
 
3209
 
 
3210
    if(stream->streamActive)
 
3211
        result = 1;
 
3212
 
 
3213
    PA_LOGL_;
 
3214
    return result;
 
3215
}
 
3216
 
 
3217
 
 
3218
static PaTime GetStreamTime( PaStream* s )
 
3219
{
 
3220
    PA_LOGE_;
 
3221
    PA_LOGL_;
 
3222
    (void)s;
 
3223
    return PaUtil_GetTime();
 
3224
}
 
3225
 
 
3226
 
 
3227
static double GetStreamCpuLoad( PaStream* s )
 
3228
{
 
3229
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
 
3230
    double result;
 
3231
    PA_LOGE_;
 
3232
    result = PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
 
3233
    PA_LOGL_;
 
3234
    return result;
 
3235
}
 
3236
 
 
3237
 
 
3238
/*
 
3239
    As separate stream interfaces are used for blocking and callback
 
3240
    streams, the following functions can be guaranteed to only be called
 
3241
    for blocking streams.
 
3242
*/
 
3243
 
 
3244
static PaError ReadStream( PaStream* s,
 
3245
                           void *buffer,
 
3246
                           unsigned long frames )
 
3247
{
 
3248
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
 
3249
 
 
3250
    PA_LOGE_;
 
3251
 
 
3252
    /* suppress unused variable warnings */
 
3253
    (void) buffer;
 
3254
    (void) frames;
 
3255
    (void) stream;
 
3256
 
 
3257
    /* IMPLEMENT ME, see portaudio.h for required behavior*/
 
3258
    PA_LOGL_;
 
3259
    return paNoError;
 
3260
}
 
3261
 
 
3262
 
 
3263
static PaError WriteStream( PaStream* s,
 
3264
                            const void *buffer,
 
3265
                            unsigned long frames )
 
3266
{
 
3267
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
 
3268
 
 
3269
    PA_LOGE_;
 
3270
 
 
3271
    /* suppress unused variable warnings */
 
3272
    (void) buffer;
 
3273
    (void) frames;
 
3274
    (void) stream;
 
3275
 
 
3276
    /* IMPLEMENT ME, see portaudio.h for required behavior*/
 
3277
    PA_LOGL_;
 
3278
    return paNoError;
 
3279
}
 
3280
 
 
3281
 
 
3282
static signed long GetStreamReadAvailable( PaStream* s )
 
3283
{
 
3284
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
 
3285
 
 
3286
    PA_LOGE_;
 
3287
 
 
3288
    /* suppress unused variable warnings */
 
3289
    (void) stream;
 
3290
 
 
3291
    /* IMPLEMENT ME, see portaudio.h for required behavior*/
 
3292
    PA_LOGL_;
 
3293
    return 0;
 
3294
}
 
3295
 
 
3296
 
 
3297
static signed long GetStreamWriteAvailable( PaStream* s )
 
3298
{
 
3299
    PaWinWdmStream *stream = (PaWinWdmStream*)s;
 
3300
 
 
3301
    PA_LOGE_;
 
3302
    /* suppress unused variable warnings */
 
3303
    (void) stream;
 
3304
 
 
3305
    /* IMPLEMENT ME, see portaudio.h for required behavior*/
 
3306
    PA_LOGL_;
 
3307
    return 0;
 
3308
}
 
 
b'\\ No newline at end of file'