~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.2.1/third_party/portaudio/src/hostapi/wdmks/pa_win_wdmks.c

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-01-07 14:51:16 UTC
  • mfrom: (4.3.5 sid)
  • Revision ID: package-import@ubuntu.com-20150107145116-yxnafinf4lrdvrmx
Tags: 1.4.1-0.1ubuntu1
* Merge with Debian, remaining changes:
 - Drop soprano, nepomuk build-dep
* Drop ubuntu patches, now upstream

Show diffs side-by-side

added added

removed removed

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