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