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

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

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'