1 /*
2  * Portable Audio I/O Library WASAPI implementation
3  * Copyright (c) 2006-2010 David Viens, Dmitry Kostjuchenko
4  *
5  * Based on the Open Source API proposed by Ross Bencina
6  * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining
9  * a copy of this software and associated documentation files
10  * (the "Software"), to deal in the Software without restriction,
11  * including without limitation the rights to use, copy, modify, merge,
12  * publish, distribute, sublicense, and/or sell copies of the Software,
13  * and to permit persons to whom the Software is furnished to do so,
14  * subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be
17  * included in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
24  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  */
27 
28 /*
29  * The text above constitutes the entire PortAudio license; however,
30  * the PortAudio community also makes the following non-binding requests:
31  *
32  * Any person wishing to distribute modifications to the Software is
33  * requested to send the modifications to the original developer so that
34  * they can be incorporated into the canonical version. It is also
35  * requested that these non-binding requests be included along with the
36  * license above.
37  */
38 
39 /** @file
40  @ingroup hostapi_src
41  @brief WASAPI implementation of support for a host API.
42  @note pa_wasapi currently requires minimum VC 2005, and the latest Vista SDK
43 */
44 
45 #include <windows.h>
46 #include <stdio.h>
47 #include <process.h>
48 #include <assert.h>
49 
50 // WinRT
51 #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
52 	#define PA_WINRT
53 	#define INITGUID
54 #endif
55 
56 // WASAPI
57 #include <mmreg.h>  // must be before other Wasapi headers
58 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
59 	#include <Avrt.h>
60 	#define COBJMACROS
61 	#include <Audioclient.h>
62 	#include <endpointvolume.h>
63 	#define INITGUID // Avoid additional linkage of static libs, excessive code will be optimized out by the compiler
64 	#include <mmdeviceapi.h>
65 	#include <functiondiscoverykeys.h>
66     #include <devicetopology.h>	// Used to get IKsJackDescription interface
67 	#undef INITGUID
68 #endif
69 #ifndef __MWERKS__
70 	#include <malloc.h>
71 	#include <memory.h>
72 #endif
73 
74 #include "pa_util.h"
75 #include "pa_allocation.h"
76 #include "pa_hostapi.h"
77 #include "pa_stream.h"
78 #include "pa_cpuload.h"
79 #include "pa_process.h"
80 #include "pa_win_wasapi.h"
81 #include "pa_debugprint.h"
82 #include "pa_ringbuffer.h"
83 #include "pa_win_coinitialize.h"
84 
85 #if !defined(NTDDI_VERSION)
86 
87     #undef WINVER
88     #undef _WIN32_WINNT
89     #define WINVER       0x0600 // VISTA
90 	#define _WIN32_WINNT WINVER
91 
92 	#ifndef _AVRT_ //<< fix MinGW dummy compile by defining missing type: AVRT_PRIORITY
93         typedef enum _AVRT_PRIORITY
94         {
95             AVRT_PRIORITY_LOW = -1,
96             AVRT_PRIORITY_NORMAL,
97             AVRT_PRIORITY_HIGH,
98             AVRT_PRIORITY_CRITICAL
99         } AVRT_PRIORITY, *PAVRT_PRIORITY;
100 	#endif
101 
102 	#include <basetyps.h> // << for IID/CLSID
103     #include <rpcsal.h>
104     #include <sal.h>
105 
106 	#ifndef __LPCGUID_DEFINED__
107 		#define __LPCGUID_DEFINED__
108 		typedef const GUID *LPCGUID;
109 	#endif
110 
111     #ifndef PROPERTYKEY_DEFINED
112         #define PROPERTYKEY_DEFINED
113         typedef struct _tagpropertykey
114         {
115             GUID fmtid;
116             DWORD pid;
117         } 	PROPERTYKEY;
118     #endif
119 
120     #ifdef __midl_proxy
121         #define __MIDL_CONST
122     #else
123         #define __MIDL_CONST const
124     #endif
125 
126     #ifdef WIN64
127         #include <wtypes.h>
128         typedef LONG NTSTATUS;
129         #define FASTCALL
130         #include <oleidl.h>
131         #include <objidl.h>
132      #else
133         typedef struct _BYTE_BLOB
134         {
135             unsigned long clSize;
136             unsigned char abData[ 1 ];
137         } 	BYTE_BLOB;
138         typedef /* [unique] */  __RPC_unique_pointer BYTE_BLOB *UP_BYTE_BLOB;
139         typedef LONGLONG REFERENCE_TIME;
140         #define NONAMELESSUNION
141     #endif
142 
143     #ifndef WAVE_FORMAT_IEEE_FLOAT
144         #define WAVE_FORMAT_IEEE_FLOAT 0x0003 // 32-bit floating-point
145     #endif
146 
147     #ifndef __MINGW_EXTENSION
148         #if defined(__GNUC__) || defined(__GNUG__)
149             #define __MINGW_EXTENSION __extension__
150         #else
151             #define __MINGW_EXTENSION
152         #endif
153     #endif
154 
155     #include <sdkddkver.h>
156     #include <propkeydef.h>
157     #define COBJMACROS
158     #define INITGUID // Avoid additional linkage of static libs, excessive code will be optimized out by the compiler
159     #include <audioclient.h>
160     #include <mmdeviceapi.h>
161     #include <endpointvolume.h>
162     #include <functiondiscoverykeys.h>
163 	#include <devicetopology.h>	// Used to get IKsJackDescription interface
164     #undef INITGUID
165 
166 #endif // NTDDI_VERSION
167 
168 // Missing declarations for WinRT
169 #ifdef PA_WINRT
170 
171 	#define DEVICE_STATE_ACTIVE 0x00000001
172 
173 	typedef	enum _EDataFlow
174 	{
175 		eRender					= 0,
176 		eCapture				= ( eRender + 1 ) ,
177 		eAll					= ( eCapture + 1 ) ,
178 		EDataFlow_enum_count	= ( eAll + 1 )
179 	}
180 	EDataFlow;
181 
182 	typedef enum _EndpointFormFactor
183 	{
184 		RemoteNetworkDevice			= 0,
185 		Speakers					= ( RemoteNetworkDevice + 1 ) ,
186 		LineLevel					= ( Speakers + 1 ) ,
187 		Headphones					= ( LineLevel + 1 ) ,
188 		Microphone					= ( Headphones + 1 ) ,
189 		Headset						= ( Microphone + 1 ) ,
190 		Handset						= ( Headset + 1 ) ,
191 		UnknownDigitalPassthrough	= ( Handset + 1 ) ,
192 		SPDIF						= ( UnknownDigitalPassthrough + 1 ) ,
193 		HDMI						= ( SPDIF + 1 ) ,
194 		UnknownFormFactor			= ( HDMI + 1 )
195 	}
196 	EndpointFormFactor;
197 
198 #endif
199 
200 #ifndef GUID_SECT
201     #define GUID_SECT
202 #endif
203 
204 #define __DEFINE_GUID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) static const GUID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
205 #define __DEFINE_IID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) static const IID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
206 #define __DEFINE_CLSID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) static const CLSID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
207 #define PA_DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
208     __DEFINE_CLSID(pa_CLSID_##className, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
209 #define PA_DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
210     __DEFINE_IID(pa_IID_##interfaceName, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
211 
212 // "1CB9AD4C-DBFA-4c32-B178-C2F568A703B2"
213 PA_DEFINE_IID(IAudioClient,         1cb9ad4c, dbfa, 4c32, b1, 78, c2, f5, 68, a7, 03, b2);
214 // "726778CD-F60A-4EDA-82DE-E47610CD78AA"
215 PA_DEFINE_IID(IAudioClient2,        726778cd, f60a, 4eda, 82, de, e4, 76, 10, cd, 78, aa);
216 // "1BE09788-6894-4089-8586-9A2A6C265AC5"
217 PA_DEFINE_IID(IMMEndpoint,          1be09788, 6894, 4089, 85, 86, 9a, 2a, 6c, 26, 5a, c5);
218 // "A95664D2-9614-4F35-A746-DE8DB63617E6"
219 PA_DEFINE_IID(IMMDeviceEnumerator,  a95664d2, 9614, 4f35, a7, 46, de, 8d, b6, 36, 17, e6);
220 // "BCDE0395-E52F-467C-8E3D-C4579291692E"
221 PA_DEFINE_CLSID(IMMDeviceEnumerator,bcde0395, e52f, 467c, 8e, 3d, c4, 57, 92, 91, 69, 2e);
222 // "F294ACFC-3146-4483-A7BF-ADDCA7C260E2"
223 PA_DEFINE_IID(IAudioRenderClient,   f294acfc, 3146, 4483, a7, bf, ad, dc, a7, c2, 60, e2);
224 // "C8ADBD64-E71E-48a0-A4DE-185C395CD317"
225 PA_DEFINE_IID(IAudioCaptureClient,  c8adbd64, e71e, 48a0, a4, de, 18, 5c, 39, 5c, d3, 17);
226 // *2A07407E-6497-4A18-9787-32F79BD0D98F*  Or this??
227 PA_DEFINE_IID(IDeviceTopology,      2A07407E, 6497, 4A18, 97, 87, 32, f7, 9b, d0, d9, 8f);
228 // *AE2DE0E4-5BCA-4F2D-AA46-5D13F8FDB3A9*
229 PA_DEFINE_IID(IPart,                AE2DE0E4, 5BCA, 4F2D, aa, 46, 5d, 13, f8, fd, b3, a9);
230 // *4509F757-2D46-4637-8E62-CE7DB944F57B*
231 PA_DEFINE_IID(IKsJackDescription,   4509F757, 2D46, 4637, 8e, 62, ce, 7d, b9, 44, f5, 7b);
232 
233 // Media formats:
234 __DEFINE_GUID(pa_KSDATAFORMAT_SUBTYPE_PCM,        0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
235 __DEFINE_GUID(pa_KSDATAFORMAT_SUBTYPE_ADPCM,      0x00000002, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
236 __DEFINE_GUID(pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
237 
238 #ifdef __IAudioClient2_INTERFACE_DEFINED__
239 typedef enum _pa_AUDCLNT_STREAMOPTIONS {
240 	pa_AUDCLNT_STREAMOPTIONS_NONE          = 0x00,
241 	pa_AUDCLNT_STREAMOPTIONS_RAW           = 0x01,
242 	pa_AUDCLNT_STREAMOPTIONS_MATCH_FORMAT  = 0x02
243 } pa_AUDCLNT_STREAMOPTIONS;
244 typedef struct _pa_AudioClientProperties {
245 	UINT32                   cbSize;
246 	BOOL                     bIsOffload;
247 	AUDIO_STREAM_CATEGORY    eCategory;
248 	pa_AUDCLNT_STREAMOPTIONS Options;
249 } pa_AudioClientProperties;
250 #define PA_AUDIOCLIENTPROPERTIES_SIZE_CATEGORY (sizeof(pa_AudioClientProperties) - sizeof(pa_AUDCLNT_STREAMOPTIONS))
251 #define PA_AUDIOCLIENTPROPERTIES_SIZE_OPTIONS   sizeof(pa_AudioClientProperties)
252 #endif // __IAudioClient2_INTERFACE_DEFINED__
253 
254 /* use CreateThread for CYGWIN/Windows Mobile, _beginthreadex for all others */
255 #if !defined(__CYGWIN__) && !defined(_WIN32_WCE)
256 	#define CREATE_THREAD(PROC) (HANDLE)_beginthreadex( NULL, 0, (PROC), stream, 0, &stream->dwThreadId )
257 	#define PA_THREAD_FUNC static unsigned WINAPI
258 	#define PA_THREAD_ID unsigned
259 #else
260 	#define CREATE_THREAD(PROC) CreateThread( NULL, 0, (PROC), stream, 0, &stream->dwThreadId )
261 	#define PA_THREAD_FUNC static DWORD WINAPI
262 	#define PA_THREAD_ID DWORD
263 #endif
264 
265 // Thread function forward decl.
266 PA_THREAD_FUNC ProcThreadEvent(void *param);
267 PA_THREAD_FUNC ProcThreadPoll(void *param);
268 
269 // Availabe from Windows 7
270 #ifndef AUDCLNT_E_BUFFER_ERROR
271 	#define AUDCLNT_E_BUFFER_ERROR AUDCLNT_ERR(0x018)
272 #endif
273 #ifndef AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED
274 	#define AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED AUDCLNT_ERR(0x019)
275 #endif
276 #ifndef AUDCLNT_E_INVALID_DEVICE_PERIOD
277 	#define AUDCLNT_E_INVALID_DEVICE_PERIOD AUDCLNT_ERR(0x020)
278 #endif
279 
280 #define MAX_STR_LEN 512
281 
282 enum { S_INPUT = 0, S_OUTPUT = 1, S_COUNT = 2, S_FULLDUPLEX = 0 };
283 
284 // Number of packets which compose single contignous buffer. With trial and error it was calculated
285 // that WASAPI Input sub-system uses 6 packets per whole buffer. Please provide more information
286 // or corrections if available.
287 enum { WASAPI_PACKETS_PER_INPUT_BUFFER = 6 };
288 
289 #define STATIC_ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
290 
291 #define PRINT(x) PA_DEBUG(x);
292 
293 #define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \
294     PaUtil_SetLastHostErrorInfo( paWASAPI, errorCode, errorText )
295 
296 #define PA_WASAPI__IS_FULLDUPLEX(STREAM) ((STREAM)->in.clientProc && (STREAM)->out.clientProc)
297 
298 #ifndef IF_FAILED_JUMP
299 #define IF_FAILED_JUMP(hr, label) if(FAILED(hr)) goto label;
300 #endif
301 
302 #ifndef IF_FAILED_INTERNAL_ERROR_JUMP
303 #define IF_FAILED_INTERNAL_ERROR_JUMP(hr, error, label) if(FAILED(hr)) { error = paInternalError; goto label; }
304 #endif
305 
306 #define SAFE_CLOSE(h) if ((h) != NULL) { CloseHandle((h)); (h) = NULL; }
307 #define SAFE_RELEASE(punk) if ((punk) != NULL) { (punk)->lpVtbl->Release((punk)); (punk) = NULL; }
308 
309 // Mixer function
310 typedef void (*MixMonoToStereoF) (void *__to, void *__from, UINT32 count);
311 
312 // AVRT is the new "multimedia schedulling stuff"
313 #ifndef PA_WINRT
314 typedef BOOL   (WINAPI *FAvRtCreateThreadOrderingGroup)  (PHANDLE,PLARGE_INTEGER,GUID*,PLARGE_INTEGER);
315 typedef BOOL   (WINAPI *FAvRtDeleteThreadOrderingGroup)  (HANDLE);
316 typedef BOOL   (WINAPI *FAvRtWaitOnThreadOrderingGroup)  (HANDLE);
317 typedef HANDLE (WINAPI *FAvSetMmThreadCharacteristics)   (LPCSTR,LPDWORD);
318 typedef BOOL   (WINAPI *FAvRevertMmThreadCharacteristics)(HANDLE);
319 typedef BOOL   (WINAPI *FAvSetMmThreadPriority)          (HANDLE,AVRT_PRIORITY);
320 static HMODULE hDInputDLL = 0;
321 FAvRtCreateThreadOrderingGroup   pAvRtCreateThreadOrderingGroup = NULL;
322 FAvRtDeleteThreadOrderingGroup   pAvRtDeleteThreadOrderingGroup = NULL;
323 FAvRtWaitOnThreadOrderingGroup   pAvRtWaitOnThreadOrderingGroup = NULL;
324 FAvSetMmThreadCharacteristics    pAvSetMmThreadCharacteristics = NULL;
325 FAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL;
326 FAvSetMmThreadPriority           pAvSetMmThreadPriority = NULL;
327 #endif
328 
329 #define _GetProc(fun, type, name)  {                                                        \
330                                         fun = (type) GetProcAddress(hDInputDLL,name);       \
331                                         if (fun == NULL) {                                  \
332                                             PRINT(("GetProcAddr failed for %s" ,name));     \
333                                             return FALSE;                                   \
334                                         }                                                   \
335                                     }                                                       \
336 
337 // ------------------------------------------------------------------------------------------
338 /* prototypes for functions declared in this file */
339 #ifdef __cplusplus
340 extern "C"
341 {
342 #endif /* __cplusplus */
343 PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
344 #ifdef __cplusplus
345 }
346 #endif /* __cplusplus */
347 // dummy entry point for other compilers and sdks
348 // currently built using RC1 SDK (5600)
349 //#if _MSC_VER < 1400
350 //PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
351 //{
352     //return paNoError;
353 //}
354 //#else
355 
356 // ------------------------------------------------------------------------------------------
357 static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
358 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
359                                   const PaStreamParameters *inputParameters,
360                                   const PaStreamParameters *outputParameters,
361                                   double sampleRate );
362 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
363                            PaStream** s,
364                            const PaStreamParameters *inputParameters,
365                            const PaStreamParameters *outputParameters,
366                            double sampleRate,
367                            unsigned long framesPerBuffer,
368                            PaStreamFlags streamFlags,
369                            PaStreamCallback *streamCallback,
370                            void *userData );
371 static PaError CloseStream( PaStream* stream );
372 static PaError StartStream( PaStream *stream );
373 static PaError StopStream( PaStream *stream );
374 static PaError AbortStream( PaStream *stream );
375 static PaError IsStreamStopped( PaStream *s );
376 static PaError IsStreamActive( PaStream *stream );
377 static PaTime GetStreamTime( PaStream *stream );
378 static double GetStreamCpuLoad( PaStream* stream );
379 static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
380 static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
381 static signed long GetStreamReadAvailable( PaStream* stream );
382 static signed long GetStreamWriteAvailable( PaStream* stream );
383 
384 // ------------------------------------------------------------------------------------------
385 /*
386  These are fields that can be gathered from IDevice and IAudioDevice PRIOR to Initialize, and
387  done in first pass i assume that neither of these will cause the Driver to "load", but again,
388  who knows how they implement their stuff
389  */
390 typedef struct PaWasapiDeviceInfo
391 {
392     // Device
393 #ifndef PA_WINRT
394     IMMDevice *device;
395 #endif
396 
397 	// from GetId
398     WCHAR szDeviceID[MAX_STR_LEN];
399 
400 	// from GetState
401     DWORD state;
402 
403     // Fields filled from IAudioDevice (_prior_ to Initialize)
404     // from GetDevicePeriod(
405     REFERENCE_TIME DefaultDevicePeriod;
406     REFERENCE_TIME MinimumDevicePeriod;
407 
408 	// Default format (setup through Control Panel by user)
409 	WAVEFORMATEXTENSIBLE DefaultFormat;
410 
411     // Fields filled from IMMEndpoint'sGetDataFlow
412     EDataFlow flow;
413 
414 	// Formfactor
415 	EndpointFormFactor formFactor;
416 }
417 PaWasapiDeviceInfo;
418 
419 // ------------------------------------------------------------------------------------------
420 /* PaWasapiHostApiRepresentation - host api datastructure specific to this implementation */
421 typedef struct
422 {
423     PaUtilHostApiRepresentation inheritedHostApiRep;
424     PaUtilStreamInterface       callbackStreamInterface;
425     PaUtilStreamInterface       blockingStreamInterface;
426 
427     PaUtilAllocationGroup      *allocations;
428 
429     /* implementation specific data goes here */
430 
431     PaWinUtilComInitializationResult comInitializationResult;
432 
433     //in case we later need the synch
434 #ifndef PA_WINRT
435     IMMDeviceEnumerator *enumerator;
436 #endif
437 
438     //this is the REAL number of devices, whether they are usefull to PA or not!
439     UINT32 deviceCount;
440 
441     WCHAR defaultRenderer [MAX_STR_LEN];
442     WCHAR defaultCapturer [MAX_STR_LEN];
443 
444     PaWasapiDeviceInfo *devInfo;
445 
446 	// Is true when WOW64 Vista/7 Workaround is needed
447 	BOOL useWOW64Workaround;
448 }
449 PaWasapiHostApiRepresentation;
450 
451 // ------------------------------------------------------------------------------------------
452 /* PaWasapiAudioClientParams - audio client parameters */
453 typedef struct PaWasapiAudioClientParams
454 {
455 	PaWasapiDeviceInfo *device_info;
456 	PaStreamParameters  stream_params;
457 	PaWasapiStreamInfo  wasapi_params;
458 	UINT32              frames_per_buffer;
459 	double              sample_rate;
460 	BOOL                blocking;
461 	BOOL                full_duplex;
462 	BOOL                wow64_workaround;
463 }
464 PaWasapiAudioClientParams;
465 
466 // ------------------------------------------------------------------------------------------
467 /* PaWasapiStream - a stream data structure specifically for this implementation */
468 typedef struct PaWasapiSubStream
469 {
470     IAudioClient        *clientParent;
471 #ifndef PA_WINRT
472 	IStream				*clientStream;
473 #endif
474 	IAudioClient		*clientProc;
475 
476     WAVEFORMATEXTENSIBLE wavex;
477     UINT32               bufferSize;
478     REFERENCE_TIME       deviceLatency;
479     REFERENCE_TIME       period;
480 	double				 latencySeconds;
481     UINT32				 framesPerHostCallback;
482 	AUDCLNT_SHAREMODE    shareMode;
483 	UINT32               streamFlags; // AUDCLNT_STREAMFLAGS_EVENTCALLBACK, ...
484 	UINT32               flags;
485 	PaWasapiAudioClientParams params; //!< parameters
486 
487 	// Buffers
488 	UINT32               buffers;			//!< number of buffers used (from host side)
489 	UINT32               framesPerBuffer;	//!< number of frames per 1 buffer
490 	BOOL                 userBufferAndHostMatch;
491 
492 	// Used for Mono >> Stereo workaround, if driver does not support it
493 	// (in Exclusive mode WASAPI usually refuses to operate with Mono (1-ch)
494 	void                *monoBuffer;	 //!< pointer to buffer
495 	UINT32               monoBufferSize; //!< buffer size in bytes
496 	MixMonoToStereoF     monoMixer;		 //!< pointer to mixer function
497 
498 	PaUtilRingBuffer    *tailBuffer;       //!< buffer with trailing sample for blocking mode operations (only for Input)
499 	void                *tailBufferMemory; //!< tail buffer memory region
500 }
501 PaWasapiSubStream;
502 
503 // ------------------------------------------------------------------------------------------
504 /* PaWasapiHostProcessor - redirects processing data */
505 typedef struct PaWasapiHostProcessor
506 {
507     PaWasapiHostProcessorCallback processor;
508     void *userData;
509 }
510 PaWasapiHostProcessor;
511 
512 // ------------------------------------------------------------------------------------------
513 typedef struct PaWasapiStream
514 {
515 	/* IMPLEMENT ME: rename this */
516     PaUtilStreamRepresentation streamRepresentation;
517     PaUtilCpuLoadMeasurer      cpuLoadMeasurer;
518     PaUtilBufferProcessor      bufferProcessor;
519 
520     // input
521 	PaWasapiSubStream          in;
522     IAudioCaptureClient       *captureClientParent;
523 #ifndef PA_WINRT
524 	IStream                   *captureClientStream;
525 #endif
526 	IAudioCaptureClient       *captureClient;
527     IAudioEndpointVolume      *inVol;
528 
529 	// output
530 	PaWasapiSubStream          out;
531     IAudioRenderClient        *renderClientParent;
532 #ifndef PA_WINRT
533 	IStream                   *renderClientStream;
534 #endif
535 	IAudioRenderClient        *renderClient;
536 	IAudioEndpointVolume      *outVol;
537 
538 	// event handles for event-driven processing mode
539 	HANDLE event[S_COUNT];
540 
541 	// buffer mode
542 	PaUtilHostBufferSizeMode bufferMode;
543 
544 	// must be volatile to avoid race condition on user query while
545 	// thread is being started
546     volatile BOOL running;
547 
548     PA_THREAD_ID dwThreadId;
549     HANDLE hThread;
550 	HANDLE hCloseRequest;
551 	HANDLE hThreadStart;        //!< signalled by thread on start
552 	HANDLE hThreadExit;         //!< signalled by thread on exit
553 	HANDLE hBlockingOpStreamRD;
554 	HANDLE hBlockingOpStreamWR;
555 
556     // Host callback Output overrider
557 	PaWasapiHostProcessor hostProcessOverrideOutput;
558 
559     // Host callback Input overrider
560 	PaWasapiHostProcessor hostProcessOverrideInput;
561 
562 	// Defines blocking/callback interface used
563 	BOOL bBlocking;
564 
565 	// Av Task (MM thread management)
566 	HANDLE hAvTask;
567 
568 	// Thread priority level
569 	PaWasapiThreadPriority nThreadPriority;
570 }
571 PaWasapiStream;
572 
573 // COM marshaling
574 static HRESULT MarshalSubStreamComPointers(PaWasapiSubStream *substream);
575 static HRESULT MarshalStreamComPointers(PaWasapiStream *stream);
576 static HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream);
577 static HRESULT UnmarshalStreamComPointers(PaWasapiStream *stream);
578 static void ReleaseUnmarshaledSubComPointers(PaWasapiSubStream *substream);
579 static void ReleaseUnmarshaledComPointers(PaWasapiStream *stream);
580 
581 // Local stream methods
582 static void _StreamOnStop(PaWasapiStream *stream);
583 static void _StreamFinish(PaWasapiStream *stream);
584 static void _StreamCleanup(PaWasapiStream *stream);
585 static HRESULT _PollGetOutputFramesAvailable(PaWasapiStream *stream, UINT32 *available);
586 static HRESULT _PollGetInputFramesAvailable(PaWasapiStream *stream, UINT32 *available);
587 static void *PaWasapi_ReallocateMemory(void *ptr, size_t size);
588 static void PaWasapi_FreeMemory(void *ptr);
589 
590 // Local statics
591 
592 // ------------------------------------------------------------------------------------------
593 #define LogHostError(HRES) __LogHostError(HRES, __FUNCTION__, __FILE__, __LINE__)
__LogHostError(HRESULT res,const char * func,const char * file,int line)594 static HRESULT __LogHostError(HRESULT res, const char *func, const char *file, int line)
595 {
596     const char *text = NULL;
597     switch (res)
598 	{
599 	case S_OK: return res;
600 	case E_POINTER                              :text ="E_POINTER"; break;
601 	case E_INVALIDARG                           :text ="E_INVALIDARG"; break;
602 
603 	case AUDCLNT_E_NOT_INITIALIZED              :text ="AUDCLNT_E_NOT_INITIALIZED"; break;
604 	case AUDCLNT_E_ALREADY_INITIALIZED          :text ="AUDCLNT_E_ALREADY_INITIALIZED"; break;
605 	case AUDCLNT_E_WRONG_ENDPOINT_TYPE          :text ="AUDCLNT_E_WRONG_ENDPOINT_TYPE"; break;
606 	case AUDCLNT_E_DEVICE_INVALIDATED           :text ="AUDCLNT_E_DEVICE_INVALIDATED"; break;
607 	case AUDCLNT_E_NOT_STOPPED                  :text ="AUDCLNT_E_NOT_STOPPED"; break;
608 	case AUDCLNT_E_BUFFER_TOO_LARGE             :text ="AUDCLNT_E_BUFFER_TOO_LARGE"; break;
609 	case AUDCLNT_E_OUT_OF_ORDER                 :text ="AUDCLNT_E_OUT_OF_ORDER"; break;
610 	case AUDCLNT_E_UNSUPPORTED_FORMAT           :text ="AUDCLNT_E_UNSUPPORTED_FORMAT"; break;
611 	case AUDCLNT_E_INVALID_SIZE                 :text ="AUDCLNT_E_INVALID_SIZE"; break;
612 	case AUDCLNT_E_DEVICE_IN_USE                :text ="AUDCLNT_E_DEVICE_IN_USE"; break;
613 	case AUDCLNT_E_BUFFER_OPERATION_PENDING     :text ="AUDCLNT_E_BUFFER_OPERATION_PENDING"; break;
614 	case AUDCLNT_E_THREAD_NOT_REGISTERED        :text ="AUDCLNT_E_THREAD_NOT_REGISTERED"; break;
615 	case AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED   :text ="AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED"; break;
616 	case AUDCLNT_E_ENDPOINT_CREATE_FAILED       :text ="AUDCLNT_E_ENDPOINT_CREATE_FAILED"; break;
617 	case AUDCLNT_E_SERVICE_NOT_RUNNING          :text ="AUDCLNT_E_SERVICE_NOT_RUNNING"; break;
618 	case AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED     :text ="AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED"; break;
619 	case AUDCLNT_E_EXCLUSIVE_MODE_ONLY          :text ="AUDCLNT_E_EXCLUSIVE_MODE_ONLY"; break;
620 	case AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL :text ="AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL"; break;
621 	case AUDCLNT_E_EVENTHANDLE_NOT_SET          :text ="AUDCLNT_E_EVENTHANDLE_NOT_SET"; break;
622 	case AUDCLNT_E_INCORRECT_BUFFER_SIZE        :text ="AUDCLNT_E_INCORRECT_BUFFER_SIZE"; break;
623 	case AUDCLNT_E_BUFFER_SIZE_ERROR            :text ="AUDCLNT_E_BUFFER_SIZE_ERROR"; break;
624 	case AUDCLNT_E_CPUUSAGE_EXCEEDED            :text ="AUDCLNT_E_CPUUSAGE_EXCEEDED"; break;
625 	case AUDCLNT_E_BUFFER_ERROR					:text ="AUDCLNT_E_BUFFER_ERROR"; break;
626 	case AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED		:text ="AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED"; break;
627 	case AUDCLNT_E_INVALID_DEVICE_PERIOD		:text ="AUDCLNT_E_INVALID_DEVICE_PERIOD"; break;
628 
629 	case AUDCLNT_S_BUFFER_EMPTY                 :text ="AUDCLNT_S_BUFFER_EMPTY"; break;
630 	case AUDCLNT_S_THREAD_ALREADY_REGISTERED    :text ="AUDCLNT_S_THREAD_ALREADY_REGISTERED"; break;
631 	case AUDCLNT_S_POSITION_STALLED				:text ="AUDCLNT_S_POSITION_STALLED"; break;
632 
633 	// other windows common errors:
634 	case CO_E_NOTINITIALIZED                    :text ="CO_E_NOTINITIALIZED: you must call CoInitialize() before Pa_OpenStream()"; break;
635 
636 	default:
637 		text = "UNKNOWN ERROR";
638     }
639 	PRINT(("WASAPI ERROR HRESULT: 0x%X : %s\n [FUNCTION: %s FILE: %s {LINE: %d}]\n", res, text, func, file, line));
640 	PA_SKELETON_SET_LAST_HOST_ERROR(res, text);
641 	return res;
642 }
643 
644 // ------------------------------------------------------------------------------------------
645 #define LogPaError(PAERR) __LogPaError(PAERR, __FUNCTION__, __FILE__, __LINE__)
__LogPaError(PaError err,const char * func,const char * file,int line)646 static PaError __LogPaError(PaError err, const char *func, const char *file, int line)
647 {
648 	if (err == paNoError)
649 		return err;
650 	PRINT(("WASAPI ERROR PAERROR: %i : %s\n [FUNCTION: %s FILE: %s {LINE: %d}]\n", err, Pa_GetErrorText(err), func, file, line));
651 	return err;
652 }
653 
654 // ------------------------------------------------------------------------------------------
655 /*! \class ThreadSleepScheduler
656            Allows to emulate thread sleep of less than 1 millisecond under Windows. Scheduler
657 		   calculates number of times the thread must run untill next sleep of 1 millisecond.
658 		   It does not make thread sleeping for real number of microseconds but rather controls
659 		   how many of imaginary microseconds the thread task can allow thread to sleep.
660 */
661 typedef struct ThreadIdleScheduler
662 {
663 	UINT32 m_idle_microseconds; //!< number of microseconds to sleep
664 	UINT32 m_next_sleep;        //!< next sleep round
665 	UINT32 m_i;					//!< current round iterator position
666 	UINT32 m_resolution;		//!< resolution in number of milliseconds
667 }
668 ThreadIdleScheduler;
669 //! Setup scheduler.
ThreadIdleScheduler_Setup(ThreadIdleScheduler * sched,UINT32 resolution,UINT32 microseconds)670 static void ThreadIdleScheduler_Setup(ThreadIdleScheduler *sched, UINT32 resolution, UINT32 microseconds)
671 {
672 	assert(microseconds != 0);
673 	assert(resolution != 0);
674 	assert((resolution * 1000) >= microseconds);
675 
676 	memset(sched, 0, sizeof(*sched));
677 
678 	sched->m_idle_microseconds = microseconds;
679 	sched->m_resolution        = resolution;
680 	sched->m_next_sleep        = (resolution * 1000) / microseconds;
681 }
682 //! Iterate and check if can sleep.
ThreadIdleScheduler_NextSleep(ThreadIdleScheduler * sched)683 static UINT32 ThreadIdleScheduler_NextSleep(ThreadIdleScheduler *sched)
684 {
685 	// advance and check if thread can sleep
686 	if (++ sched->m_i == sched->m_next_sleep)
687 	{
688 		sched->m_i = 0;
689 		return sched->m_resolution;
690 	}
691 	return 0;
692 }
693 
694 // ------------------------------------------------------------------------------------------
695 /*static double nano100ToMillis(REFERENCE_TIME ref)
696 {
697     //  1 nano = 0.000000001 seconds
698     //100 nano = 0.0000001   seconds
699     //100 nano = 0.0001   milliseconds
700     return ((double)ref)*0.0001;
701 }*/
702 
703 // ------------------------------------------------------------------------------------------
nano100ToSeconds(REFERENCE_TIME ref)704 static double nano100ToSeconds(REFERENCE_TIME ref)
705 {
706     //  1 nano = 0.000000001 seconds
707     //100 nano = 0.0000001   seconds
708     //100 nano = 0.0001   milliseconds
709     return ((double)ref)*0.0000001;
710 }
711 
712 // ------------------------------------------------------------------------------------------
713 /*static REFERENCE_TIME MillisTonano100(double ref)
714 {
715     //  1 nano = 0.000000001 seconds
716     //100 nano = 0.0000001   seconds
717     //100 nano = 0.0001   milliseconds
718     return (REFERENCE_TIME)(ref/0.0001);
719 }*/
720 
721 // ------------------------------------------------------------------------------------------
SecondsTonano100(double ref)722 static REFERENCE_TIME SecondsTonano100(double ref)
723 {
724     //  1 nano = 0.000000001 seconds
725     //100 nano = 0.0000001   seconds
726     //100 nano = 0.0001   milliseconds
727     return (REFERENCE_TIME)(ref/0.0000001);
728 }
729 
730 // ------------------------------------------------------------------------------------------
731 // Makes Hns period from frames and sample rate
MakeHnsPeriod(UINT32 nFrames,DWORD nSamplesPerSec)732 static REFERENCE_TIME MakeHnsPeriod(UINT32 nFrames, DWORD nSamplesPerSec)
733 {
734 	return (REFERENCE_TIME)((10000.0 * 1000 / nSamplesPerSec * nFrames) + 0.5);
735 }
736 
737 // ------------------------------------------------------------------------------------------
738 // Converts PaSampleFormat to bits per sample value
PaSampleFormatToBitsPerSample(PaSampleFormat format_id)739 static WORD PaSampleFormatToBitsPerSample(PaSampleFormat format_id)
740 {
741 	switch (format_id & ~paNonInterleaved)
742 	{
743 		case paFloat32:
744 		case paInt32: return 32;
745 		case paInt24: return 24;
746 		case paInt16: return 16;
747 		case paInt8:
748 		case paUInt8: return 8;
749 	}
750 	return 0;
751 }
752 
753 // ------------------------------------------------------------------------------------------
754 // Converts PaSampleFormat to bits per sample value
755 /*static WORD PaSampleFormatToBytesPerSample(PaSampleFormat format_id)
756 {
757 	return PaSampleFormatToBitsPerSample(format_id) >> 3; // 'bits/8'
758 }*/
759 
760 // ------------------------------------------------------------------------------------------
761 // Converts Hns period into number of frames
MakeFramesFromHns(REFERENCE_TIME hnsPeriod,UINT32 nSamplesPerSec)762 static UINT32 MakeFramesFromHns(REFERENCE_TIME hnsPeriod, UINT32 nSamplesPerSec)
763 {
764     UINT32 nFrames = (UINT32)(	// frames =
765         1.0 * hnsPeriod *		// hns *
766         nSamplesPerSec /		// (frames / s) /
767         1000 /					// (ms / s) /
768         10000					// (hns / s) /
769         + 0.5					// rounding
770     );
771 	return nFrames;
772 }
773 
774 // Aligning function type
775 typedef UINT32 (*ALIGN_FUNC) (UINT32 v, UINT32 align);
776 
777 // ------------------------------------------------------------------------------------------
778 // Aligns 'v' backwards
ALIGN_BWD(UINT32 v,UINT32 align)779 static UINT32 ALIGN_BWD(UINT32 v, UINT32 align)
780 {
781 	return ((v - (align ? v % align : 0)));
782 }
783 
784 // ------------------------------------------------------------------------------------------
785 // Aligns 'v' forward
ALIGN_FWD(UINT32 v,UINT32 align)786 static UINT32 ALIGN_FWD(UINT32 v, UINT32 align)
787 {
788 	UINT32 remainder = (align ? (v % align) : 0);
789 	if (remainder == 0)
790 		return v;
791 	return v + (align - remainder);
792 }
793 
794 // ------------------------------------------------------------------------------------------
795 // Get next value power of 2
ALIGN_NEXT_POW2(UINT32 v)796 UINT32 ALIGN_NEXT_POW2(UINT32 v)
797 {
798 	UINT32 v2 = 1;
799 	while (v > (v2 <<= 1)) { }
800 	v = v2;
801 	return v;
802 }
803 
804 // ------------------------------------------------------------------------------------------
805 // Aligns WASAPI buffer to 128 byte packet boundary. HD Audio will fail to play if buffer
806 // is misaligned. This problem was solved in Windows 7 were AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED
807 // is thrown although we must align for Vista anyway.
AlignFramesPerBuffer(UINT32 nFrames,UINT32 nSamplesPerSec,UINT32 nBlockAlign,ALIGN_FUNC pAlignFunc)808 static UINT32 AlignFramesPerBuffer(UINT32 nFrames, UINT32 nSamplesPerSec, UINT32 nBlockAlign,
809 								   ALIGN_FUNC pAlignFunc)
810 {
811 #define HDA_PACKET_SIZE (128)
812 
813 	long frame_bytes = nFrames * nBlockAlign;
814 	long packets;
815 	(void)nSamplesPerSec;
816 
817 	// align to packet size
818 	frame_bytes  = pAlignFunc(frame_bytes, HDA_PACKET_SIZE); // use ALIGN_FWD if bigger but safer period is more desired
819 
820 	// atlest 1 frame must be available
821 	if (frame_bytes < HDA_PACKET_SIZE)
822 		frame_bytes = HDA_PACKET_SIZE;
823 
824 	nFrames      = frame_bytes / nBlockAlign;
825 	packets      = frame_bytes / HDA_PACKET_SIZE;
826 
827 	frame_bytes = packets * HDA_PACKET_SIZE;
828 	nFrames     = frame_bytes / nBlockAlign;
829 
830 	return nFrames;
831 
832 #undef HDA_PACKET_SIZE
833 }
834 
835 // ------------------------------------------------------------------------------------------
GetFramesSleepTime(UINT32 nFrames,UINT32 nSamplesPerSec)836 static UINT32 GetFramesSleepTime(UINT32 nFrames, UINT32 nSamplesPerSec)
837 {
838 	REFERENCE_TIME nDuration;
839 	if (nSamplesPerSec == 0)
840 		return 0;
841 #define REFTIMES_PER_SEC  10000000
842 #define REFTIMES_PER_MILLISEC  10000
843 	// Calculate the actual duration of the allocated buffer.
844 	nDuration = (REFERENCE_TIME)((double)REFTIMES_PER_SEC * nFrames / nSamplesPerSec);
845 	return (UINT32)(nDuration/REFTIMES_PER_MILLISEC/2);
846 }
847 
848 // ------------------------------------------------------------------------------------------
GetFramesSleepTimeMicroseconds(UINT32 nFrames,UINT32 nSamplesPerSec)849 static UINT32 GetFramesSleepTimeMicroseconds(UINT32 nFrames, UINT32 nSamplesPerSec)
850 {
851 	REFERENCE_TIME nDuration;
852 	if (nSamplesPerSec == 0)
853 		return 0;
854 #define REFTIMES_PER_SEC  10000000
855 #define REFTIMES_PER_MILLISEC  10000
856 	// Calculate the actual duration of the allocated buffer.
857 	nDuration = (REFERENCE_TIME)((double)REFTIMES_PER_SEC * nFrames / nSamplesPerSec);
858 	return (UINT32)(nDuration/10/2);
859 }
860 
861 // ------------------------------------------------------------------------------------------
862 #ifndef PA_WINRT
SetupAVRT()863 static BOOL SetupAVRT()
864 {
865     hDInputDLL = LoadLibraryA("avrt.dll");
866     if (hDInputDLL == NULL)
867         return FALSE;
868 
869     _GetProc(pAvRtCreateThreadOrderingGroup,  FAvRtCreateThreadOrderingGroup,  "AvRtCreateThreadOrderingGroup");
870     _GetProc(pAvRtDeleteThreadOrderingGroup,  FAvRtDeleteThreadOrderingGroup,  "AvRtDeleteThreadOrderingGroup");
871     _GetProc(pAvRtWaitOnThreadOrderingGroup,  FAvRtWaitOnThreadOrderingGroup,  "AvRtWaitOnThreadOrderingGroup");
872     _GetProc(pAvSetMmThreadCharacteristics,   FAvSetMmThreadCharacteristics,   "AvSetMmThreadCharacteristicsA");
873 	_GetProc(pAvRevertMmThreadCharacteristics,FAvRevertMmThreadCharacteristics,"AvRevertMmThreadCharacteristics");
874     _GetProc(pAvSetMmThreadPriority,          FAvSetMmThreadPriority,          "AvSetMmThreadPriority");
875 
876 	return pAvRtCreateThreadOrderingGroup &&
877 		pAvRtDeleteThreadOrderingGroup &&
878 		pAvRtWaitOnThreadOrderingGroup &&
879 		pAvSetMmThreadCharacteristics &&
880 		pAvRevertMmThreadCharacteristics &&
881 		pAvSetMmThreadPriority;
882 }
883 #endif
884 
885 // ------------------------------------------------------------------------------------------
CloseAVRT()886 static void CloseAVRT()
887 {
888 #ifndef PA_WINRT
889 	if (hDInputDLL != NULL)
890 		FreeLibrary(hDInputDLL);
891 	hDInputDLL = NULL;
892 #endif
893 }
894 
895 // ------------------------------------------------------------------------------------------
IsWow64()896 static BOOL IsWow64()
897 {
898 #ifndef PA_WINRT
899 
900 	// http://msdn.microsoft.com/en-us/library/ms684139(VS.85).aspx
901 
902 	typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
903 	LPFN_ISWOW64PROCESS fnIsWow64Process;
904 
905     BOOL bIsWow64 = FALSE;
906 
907     // IsWow64Process is not available on all supported versions of Windows.
908     // Use GetModuleHandle to get a handle to the DLL that contains the function
909     // and GetProcAddress to get a pointer to the function if available.
910 
911     fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
912         GetModuleHandleA("kernel32"), "IsWow64Process");
913 
914     if (fnIsWow64Process == NULL)
915 		return FALSE;
916 
917     if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64))
918 		return FALSE;
919 
920     return bIsWow64;
921 
922 #else
923 
924 	return FALSE;
925 
926 #endif
927 }
928 
929 // ------------------------------------------------------------------------------------------
930 typedef enum EWindowsVersion
931 {
932 	WINDOWS_UNKNOWN = 0,
933 	WINDOWS_VISTA_SERVER2008,
934 	WINDOWS_7_SERVER2008R2,
935 	WINDOWS_8_SERVER2012,
936 	WINDOWS_8_1_SERVER2012R2,
937 	WINDOWS_10_SERVER2016,
938 	WINDOWS_FUTURE
939 }
940 EWindowsVersion;
941 // Alternative way for checking Windows version (allows to check version on Windows 8.1 and up)
942 #ifndef PA_WINRT
IsWindowsVersionOrGreater(WORD wMajorVersion,WORD wMinorVersion,WORD wServicePackMajor)943 static BOOL IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
944 {
945 	typedef ULONGLONG (NTAPI *LPFN_VERSETCONDITIONMASK)(ULONGLONG ConditionMask, DWORD TypeMask, BYTE Condition);
946 	typedef BOOL (WINAPI *LPFN_VERIFYVERSIONINFO)(LPOSVERSIONINFOEXA lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask);
947 
948 	LPFN_VERSETCONDITIONMASK fnVerSetConditionMask;
949 	LPFN_VERIFYVERSIONINFO fnVerifyVersionInfo;
950 	OSVERSIONINFOEXA osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 };
951 	DWORDLONG dwlConditionMask;
952 
953 	fnVerSetConditionMask = (LPFN_VERSETCONDITIONMASK)GetProcAddress(GetModuleHandleA("kernel32"), "VerSetConditionMask");
954 	fnVerifyVersionInfo = (LPFN_VERIFYVERSIONINFO)GetProcAddress(GetModuleHandleA("kernel32"), "VerifyVersionInfoA");
955 
956 	if ((fnVerSetConditionMask == NULL) || (fnVerifyVersionInfo == NULL))
957 		return FALSE;
958 
959 	dwlConditionMask = fnVerSetConditionMask(
960 		fnVerSetConditionMask(
961 			fnVerSetConditionMask(
962 				0, VER_MAJORVERSION,     VER_GREATER_EQUAL),
963 				   VER_MINORVERSION,     VER_GREATER_EQUAL),
964 				   VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
965 
966 	osvi.dwMajorVersion    = wMajorVersion;
967 	osvi.dwMinorVersion    = wMinorVersion;
968 	osvi.wServicePackMajor = wServicePackMajor;
969 
970 	return (fnVerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE);
971 }
972 #endif
973 // Get Windows version
GetWindowsVersion()974 static EWindowsVersion GetWindowsVersion()
975 {
976 #ifndef PA_WINRT
977 	static EWindowsVersion version = WINDOWS_UNKNOWN;
978 
979 	if (version == WINDOWS_UNKNOWN)
980 	{
981 		DWORD dwVersion = 0;
982 		DWORD dwMajorVersion = 0;
983 		DWORD dwMinorVersion = 0;
984 		DWORD dwBuild = 0;
985 
986 		typedef DWORD (WINAPI *LPFN_GETVERSION)(VOID);
987 		LPFN_GETVERSION fnGetVersion;
988 
989 		fnGetVersion = (LPFN_GETVERSION)GetProcAddress(GetModuleHandleA("kernel32"), "GetVersion");
990 		if (fnGetVersion != NULL)
991 		{
992 			PRINT(("WASAPI: getting Windows version with GetVersion()\n"));
993 
994 			dwVersion = fnGetVersion();
995 
996 			// Get the Windows version
997 			dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
998 			dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
999 
1000 			// Get the build number
1001 			if (dwVersion < 0x80000000)
1002 				dwBuild = (DWORD)(HIWORD(dwVersion));
1003 
1004 			switch (dwMajorVersion)
1005 			{
1006 			case 0:
1007 			case 1:
1008 			case 2:
1009 			case 3:
1010 			case 4:
1011 			case 5:
1012 				break; // skip lower
1013 			case 6:
1014 				switch (dwMinorVersion)
1015 				{
1016 				case 0:  version = WINDOWS_VISTA_SERVER2008;	break;
1017 				case 1:	 version = WINDOWS_7_SERVER2008R2;		break;
1018 				case 2:	 version = WINDOWS_8_SERVER2012;  		break;
1019 				case 3:	 version = WINDOWS_8_1_SERVER2012R2;	break;
1020 				default: version = WINDOWS_FUTURE;				break;
1021 				}
1022 				break;
1023 			case 10:
1024 				switch (dwMinorVersion)
1025 				{
1026 				case 0:	 version = WINDOWS_10_SERVER2016;		break;
1027 				default: version = WINDOWS_FUTURE;				break;
1028 				}
1029 				break;
1030 			default:
1031 				version = WINDOWS_FUTURE;
1032 				break;
1033 			}
1034 		}
1035 		else
1036 		{
1037 			PRINT(("WASAPI: getting Windows version with VerifyVersionInfo()\n"));
1038 
1039 			if (IsWindowsVersionOrGreater(10, 0, 0))
1040 				version = WINDOWS_10_SERVER2016;
1041 			else
1042 			if (IsWindowsVersionOrGreater(6, 3, 0))
1043 				version = WINDOWS_8_1_SERVER2012R2;
1044 			else
1045 			if (IsWindowsVersionOrGreater(6, 2, 0))
1046 				version = WINDOWS_8_SERVER2012;
1047 			else
1048 			if (IsWindowsVersionOrGreater(6, 1, 0))
1049 				version = WINDOWS_7_SERVER2008R2;
1050 			else
1051 			if (IsWindowsVersionOrGreater(6, 0, 0))
1052 				version = WINDOWS_VISTA_SERVER2008;
1053 			else
1054 				version = WINDOWS_FUTURE;
1055 		}
1056 
1057 		PRINT(("WASAPI: Windows version = %d\n", version));
1058 	}
1059 
1060 	return version;
1061 #else
1062 	return WINDOWS_8_SERVER2012;
1063 #endif
1064 }
1065 
1066 // ------------------------------------------------------------------------------------------
UseWOW64Workaround()1067 static BOOL UseWOW64Workaround()
1068 {
1069 	// note: WOW64 bug is common to Windows Vista x64, thus we fall back to safe Poll-driven
1070 	//       method. Windows 7 x64 seems has WOW64 bug fixed.
1071 
1072 	return (IsWow64() && (GetWindowsVersion() == WINDOWS_VISTA_SERVER2008));
1073 }
1074 
1075 // ------------------------------------------------------------------------------------------
GetAudioClientVersion()1076 static UINT32 GetAudioClientVersion()
1077 {
1078 	if (GetWindowsVersion() >= WINDOWS_10_SERVER2016)
1079 		return 3;
1080 	else
1081 	if (GetWindowsVersion() >= WINDOWS_8_SERVER2012)
1082 		return 2;
1083 
1084 	return 1;
1085 }
1086 
1087 // ------------------------------------------------------------------------------------------
GetAudioClientIID()1088 static const IID *GetAudioClientIID()
1089 {
1090 	static const IID *cli_iid = NULL;
1091 	if (cli_iid == NULL)
1092 	{
1093 		UINT32 cli_version = GetAudioClientVersion();
1094 		if (cli_version <= 1)
1095 		{
1096 			cli_iid = &pa_IID_IAudioClient;
1097 		}
1098 		else
1099 		{
1100 			switch (cli_version)
1101 			{
1102 			case 3:  cli_iid = &pa_IID_IAudioClient2; cli_version = 2; break; // use IAudioClient2 for Windows 10+ until IAudioClient3 functions are required
1103 			default: cli_iid = &pa_IID_IAudioClient2; cli_version = 2; break;
1104 			}
1105 		}
1106 
1107 		PRINT(("WASAPI: IAudioClient version = %d\n", cli_version));
1108 	}
1109 
1110 	return cli_iid;
1111 }
1112 
1113 // ------------------------------------------------------------------------------------------
1114 typedef enum EMixerDir { MIX_DIR__1TO2, MIX_DIR__2TO1, MIX_DIR__2TO1_L } EMixerDir;
1115 
1116 // ------------------------------------------------------------------------------------------
1117 #define _WASAPI_MONO_TO_STEREO_MIXER_1_TO_2(TYPE)\
1118 	TYPE * __restrict to   = __to;\
1119 	TYPE * __restrict from = __from;\
1120 	TYPE * __restrict end  = from + count;\
1121 	while (from != end)\
1122 	{\
1123 		*to ++ = *from;\
1124 		*to ++ = *from;\
1125 		++ from;\
1126 	}
1127 
1128 // ------------------------------------------------------------------------------------------
1129 #define _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_FLT32(TYPE)\
1130 	TYPE * __restrict to   = (TYPE *)__to;\
1131 	TYPE * __restrict from = (TYPE *)__from;\
1132 	TYPE * __restrict end  = to + count;\
1133 	while (to != end)\
1134 	{\
1135 		*to ++ = (TYPE)((float)(from[0] + from[1]) * 0.5f);\
1136 		from += 2;\
1137 	}
1138 
1139 // ------------------------------------------------------------------------------------------
1140 #define _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_INT32(TYPE)\
1141 	TYPE * __restrict to   = (TYPE *)__to;\
1142 	TYPE * __restrict from = (TYPE *)__from;\
1143 	TYPE * __restrict end  = to + count;\
1144 	while (to != end)\
1145 	{\
1146 		*to ++ = (TYPE)(((INT32)from[0] + (INT32)from[1]) >> 1);\
1147 		from += 2;\
1148 	}
1149 
1150 // ------------------------------------------------------------------------------------------
1151 #define _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_INT64(TYPE)\
1152 	TYPE * __restrict to   = (TYPE *)__to;\
1153 	TYPE * __restrict from = (TYPE *)__from;\
1154 	TYPE * __restrict end  = to + count;\
1155 	while (to != end)\
1156 	{\
1157 		*to ++ = (TYPE)(((INT64)from[0] + (INT64)from[1]) >> 1);\
1158 		from += 2;\
1159 	}
1160 
1161 // ------------------------------------------------------------------------------------------
1162 #define _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_L(TYPE)\
1163 	TYPE * __restrict to   = (TYPE *)__to;\
1164 	TYPE * __restrict from = (TYPE *)__from;\
1165 	TYPE * __restrict end  = to + count;\
1166 	while (to != end)\
1167 	{\
1168 		*to ++ = from[0];\
1169 		from += 2;\
1170 	}
1171 
1172 // ------------------------------------------------------------------------------------------
_MixMonoToStereo_1TO2_8(void * __to,void * __from,UINT32 count)1173 static void _MixMonoToStereo_1TO2_8(void *__to, void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_1_TO_2(BYTE); }
_MixMonoToStereo_1TO2_16(void * __to,void * __from,UINT32 count)1174 static void _MixMonoToStereo_1TO2_16(void *__to, void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_1_TO_2(short); }
_MixMonoToStereo_1TO2_24(void * __to,void * __from,UINT32 count)1175 static void _MixMonoToStereo_1TO2_24(void *__to, void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_1_TO_2(int); /* !!! int24 data is contained in 32-bit containers*/ }
_MixMonoToStereo_1TO2_32(void * __to,void * __from,UINT32 count)1176 static void _MixMonoToStereo_1TO2_32(void *__to, void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_1_TO_2(int); }
_MixMonoToStereo_1TO2_32f(void * __to,void * __from,UINT32 count)1177 static void _MixMonoToStereo_1TO2_32f(void *__to, void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_1_TO_2(float); }
1178 
1179 // ------------------------------------------------------------------------------------------
_MixMonoToStereo_2TO1_8(void * __to,void * __from,UINT32 count)1180 static void _MixMonoToStereo_2TO1_8(void *__to, void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_INT32(BYTE); }
_MixMonoToStereo_2TO1_16(void * __to,void * __from,UINT32 count)1181 static void _MixMonoToStereo_2TO1_16(void *__to, void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_INT32(short); }
_MixMonoToStereo_2TO1_24(void * __to,void * __from,UINT32 count)1182 static void _MixMonoToStereo_2TO1_24(void *__to, void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_INT32(int); /* !!! int24 data is contained in 32-bit containers*/ }
_MixMonoToStereo_2TO1_32(void * __to,void * __from,UINT32 count)1183 static void _MixMonoToStereo_2TO1_32(void *__to, void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_INT64(int); }
_MixMonoToStereo_2TO1_32f(void * __to,void * __from,UINT32 count)1184 static void _MixMonoToStereo_2TO1_32f(void *__to, void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_FLT32(float); }
1185 
1186 // ------------------------------------------------------------------------------------------
_MixMonoToStereo_2TO1_8_L(void * __to,void * __from,UINT32 count)1187 static void _MixMonoToStereo_2TO1_8_L(void *__to, void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_L(BYTE); }
_MixMonoToStereo_2TO1_16_L(void * __to,void * __from,UINT32 count)1188 static void _MixMonoToStereo_2TO1_16_L(void *__to, void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_L(short); }
_MixMonoToStereo_2TO1_24_L(void * __to,void * __from,UINT32 count)1189 static void _MixMonoToStereo_2TO1_24_L(void *__to, void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_L(int); /* !!! int24 data is contained in 32-bit containers*/ }
_MixMonoToStereo_2TO1_32_L(void * __to,void * __from,UINT32 count)1190 static void _MixMonoToStereo_2TO1_32_L(void *__to, void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_L(int); }
_MixMonoToStereo_2TO1_32f_L(void * __to,void * __from,UINT32 count)1191 static void _MixMonoToStereo_2TO1_32f_L(void *__to, void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_L(float); }
1192 
1193 // ------------------------------------------------------------------------------------------
_GetMonoToStereoMixer(PaSampleFormat format,EMixerDir dir)1194 static MixMonoToStereoF _GetMonoToStereoMixer(PaSampleFormat format, EMixerDir dir)
1195 {
1196 	switch (dir)
1197 	{
1198 	case MIX_DIR__1TO2:
1199 		switch (format & ~paNonInterleaved)
1200 		{
1201 		case paUInt8:	return _MixMonoToStereo_1TO2_8;
1202 		case paInt16:	return _MixMonoToStereo_1TO2_16;
1203 		case paInt24:	return _MixMonoToStereo_1TO2_24;
1204 		case paInt32:	return _MixMonoToStereo_1TO2_32;
1205 		case paFloat32: return _MixMonoToStereo_1TO2_32f;
1206 		}
1207 		break;
1208 
1209 	case MIX_DIR__2TO1:
1210 		switch (format & ~paNonInterleaved)
1211 		{
1212 		case paUInt8:	return _MixMonoToStereo_2TO1_8;
1213 		case paInt16:	return _MixMonoToStereo_2TO1_16;
1214 		case paInt24:	return _MixMonoToStereo_2TO1_24;
1215 		case paInt32:	return _MixMonoToStereo_2TO1_32;
1216 		case paFloat32: return _MixMonoToStereo_2TO1_32f;
1217 		}
1218 		break;
1219 
1220 	case MIX_DIR__2TO1_L:
1221 		switch (format & ~paNonInterleaved)
1222 		{
1223 		case paUInt8:	return _MixMonoToStereo_2TO1_8_L;
1224 		case paInt16:	return _MixMonoToStereo_2TO1_16_L;
1225 		case paInt24:	return _MixMonoToStereo_2TO1_24_L;
1226 		case paInt32:	return _MixMonoToStereo_2TO1_32_L;
1227 		case paFloat32: return _MixMonoToStereo_2TO1_32f_L;
1228 		}
1229 		break;
1230 	}
1231 
1232 	return NULL;
1233 }
1234 
1235 // ------------------------------------------------------------------------------------------
1236 #ifdef PA_WINRT
1237 typedef struct PaActivateAudioInterfaceCompletionHandler
1238 {
1239 	IActivateAudioInterfaceCompletionHandler parent;
1240 	volatile LONG refs;
1241 	volatile LONG done;
1242 	struct
1243 	{
1244 		const IID *iid;
1245 		void **obj;
1246 	}
1247 	in;
1248 	struct
1249 	{
1250 		HRESULT hr;
1251 	}
1252 	out;
1253 }
1254 PaActivateAudioInterfaceCompletionHandler;
1255 
HRESULT(STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_QueryInterface)1256 static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_QueryInterface)(
1257     IActivateAudioInterfaceCompletionHandler *This, REFIID riid, void **ppvObject)
1258 {
1259 	PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This;
1260 
1261 	// From MSDN:
1262 	// "The IAgileObject interface is a marker interface that indicates that an object
1263 	//  is free threaded and can be called from any apartment."
1264 	if (IsEqualIID(riid, &IID_IUnknown) ||
1265 		IsEqualIID(riid, &IID_IAgileObject))
1266 	{
1267 		IActivateAudioInterfaceCompletionHandler_AddRef((IActivateAudioInterfaceCompletionHandler *)handler);
1268 		(*ppvObject) = handler;
1269 		return S_OK;
1270 	}
1271 
1272 	return E_NOINTERFACE;
1273 }
1274 
ULONG(STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_AddRef)1275 static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_AddRef)(
1276     IActivateAudioInterfaceCompletionHandler *This)
1277 {
1278 	PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This;
1279 
1280 	return InterlockedIncrement(&handler->refs);
1281 }
1282 
ULONG(STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Release)1283 static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Release)(
1284     IActivateAudioInterfaceCompletionHandler *This)
1285 {
1286 	PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This;
1287 	ULONG refs;
1288 
1289 	if ((refs = InterlockedDecrement(&handler->refs)) == 0)
1290 	{
1291 		PaUtil_FreeMemory(handler->parent.lpVtbl);
1292 		PaUtil_FreeMemory(handler);
1293 	}
1294 
1295 	return refs;
1296 }
1297 
HRESULT(STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_ActivateCompleted)1298 static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_ActivateCompleted)(
1299     IActivateAudioInterfaceCompletionHandler *This, IActivateAudioInterfaceAsyncOperation *activateOperation)
1300 {
1301 	PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This;
1302 
1303     HRESULT hr = S_OK;
1304     HRESULT hrActivateResult = S_OK;
1305     IUnknown *punkAudioInterface = NULL;
1306 
1307     // Check for a successful activation result
1308     hr = IActivateAudioInterfaceAsyncOperation_GetActivateResult(activateOperation, &hrActivateResult, &punkAudioInterface);
1309     if (SUCCEEDED(hr) && SUCCEEDED(hrActivateResult))
1310     {
1311         // Get pointer to the requested audio interface
1312         IUnknown_QueryInterface(punkAudioInterface, handler->in.iid, handler->in.obj);
1313         if ((*handler->in.obj) == NULL)
1314             hrActivateResult = E_FAIL;
1315 	}
1316 	SAFE_RELEASE(punkAudioInterface);
1317 
1318 	if (SUCCEEDED(hr))
1319 		handler->out.hr = hrActivateResult;
1320 	else
1321 		handler->out.hr = hr;
1322 
1323 	// Got client object, stop busy waiting in ActivateAudioInterface
1324 	InterlockedExchange(&handler->done, TRUE);
1325 
1326 	return hr;
1327 }
1328 
CreateActivateAudioInterfaceCompletionHandler(const IID * iid,void ** obj)1329 static IActivateAudioInterfaceCompletionHandler *CreateActivateAudioInterfaceCompletionHandler(const IID *iid, void **obj)
1330 {
1331 	PaActivateAudioInterfaceCompletionHandler *handler = PaUtil_AllocateMemory(sizeof(PaActivateAudioInterfaceCompletionHandler));
1332 	ZeroMemory(handler, sizeof(*handler));
1333 	handler->parent.lpVtbl = PaUtil_AllocateMemory(sizeof(*handler->parent.lpVtbl));
1334 	handler->parent.lpVtbl->QueryInterface    = &PaActivateAudioInterfaceCompletionHandler_QueryInterface;
1335 	handler->parent.lpVtbl->AddRef            = &PaActivateAudioInterfaceCompletionHandler_AddRef;
1336 	handler->parent.lpVtbl->Release           = &PaActivateAudioInterfaceCompletionHandler_Release;
1337 	handler->parent.lpVtbl->ActivateCompleted = &PaActivateAudioInterfaceCompletionHandler_ActivateCompleted;
1338 	handler->refs = 1;
1339 	handler->in.iid = iid;
1340 	handler->in.obj = obj;
1341 	return (IActivateAudioInterfaceCompletionHandler *)handler;
1342 }
1343 #endif
1344 
1345 // ------------------------------------------------------------------------------------------
1346 #ifdef PA_WINRT
ActivateAudioInterface_WINRT(const PaWasapiDeviceInfo * deviceInfo,const IID * iid,void ** obj)1347 static HRESULT ActivateAudioInterface_WINRT(const PaWasapiDeviceInfo *deviceInfo, const IID *iid, void **obj)
1348 {
1349 #define PA_WASAPI_DEVICE_PATH_LEN 64
1350 
1351 	PaError result = paNoError;
1352 	HRESULT hr = S_OK;
1353 	IActivateAudioInterfaceAsyncOperation *asyncOp = NULL;
1354 	IActivateAudioInterfaceCompletionHandler *handler = CreateActivateAudioInterfaceCompletionHandler(iid, obj);
1355 	PaActivateAudioInterfaceCompletionHandler *handlerImpl = (PaActivateAudioInterfaceCompletionHandler *)handler;
1356 	OLECHAR devicePath[PA_WASAPI_DEVICE_PATH_LEN] = { 0 };
1357 
1358 	// Get device path in form L"{DEVICE_GUID}"
1359 	switch (deviceInfo->flow)
1360 	{
1361 	case eRender:
1362 		StringFromGUID2(&DEVINTERFACE_AUDIO_RENDER, devicePath, PA_WASAPI_DEVICE_PATH_LEN - 1);
1363 		break;
1364 	case eCapture:
1365 		StringFromGUID2(&DEVINTERFACE_AUDIO_CAPTURE, devicePath, PA_WASAPI_DEVICE_PATH_LEN - 1);
1366 		break;
1367 	default:
1368 		return S_FALSE;
1369 	}
1370 
1371 	// Async operation will call back to IActivateAudioInterfaceCompletionHandler::ActivateCompleted
1372 	// which must be an agile interface implementation
1373     hr = ActivateAudioInterfaceAsync(devicePath, iid, NULL, handler, &asyncOp);
1374     IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
1375 
1376 	// Wait in busy loop for async operation to complete
1377 	// Use Interlocked API here to ensure that ->done variable is read every time through the loop
1378 	while (SUCCEEDED(hr) && !InterlockedOr(&handlerImpl->done, 0))
1379 	{
1380 		Sleep(1);
1381 	}
1382 
1383 	hr = handlerImpl->out.hr;
1384 
1385 error:
1386 
1387 	SAFE_RELEASE(asyncOp);
1388 	SAFE_RELEASE(handler);
1389 
1390     return hr;
1391 
1392 #undef PA_WASAPI_DEVICE_PATH_LEN
1393 }
1394 #endif
1395 
1396 // ------------------------------------------------------------------------------------------
ActivateAudioInterface(const PaWasapiDeviceInfo * deviceInfo,IAudioClient ** client)1397 static HRESULT ActivateAudioInterface(const PaWasapiDeviceInfo *deviceInfo, IAudioClient **client)
1398 {
1399 #ifndef PA_WINRT
1400 	return IMMDevice_Activate(deviceInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void **)client);
1401 #else
1402 	return ActivateAudioInterface_WINRT(deviceInfo, GetAudioClientIID(), (void **)client);
1403 #endif
1404 }
1405 
1406 // ------------------------------------------------------------------------------------------
1407 #ifdef PA_WINRT
SignalObjectAndWait(HANDLE hObjectToSignal,HANDLE hObjectToWaitOn,DWORD dwMilliseconds,BOOL bAlertable)1408 static DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable)
1409 {
1410 	SetEvent(hObjectToSignal);
1411 	return WaitForSingleObjectEx(hObjectToWaitOn, dwMilliseconds, bAlertable);
1412 }
1413 #endif
1414 
1415 // ------------------------------------------------------------------------------------------
PaWasapi_Initialize(PaUtilHostApiRepresentation ** hostApi,PaHostApiIndex hostApiIndex)1416 PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
1417 {
1418     PaError result = paNoError;
1419     PaWasapiHostApiRepresentation *paWasapi;
1420     PaDeviceInfo *deviceInfoArray;
1421     HRESULT hr = S_OK;
1422 	UINT i;
1423 #ifndef PA_WINRT
1424     IMMDeviceCollection* pEndPoints = NULL;
1425 #else
1426 	WAVEFORMATEX *mixFormat;
1427 #endif
1428 
1429 #ifndef PA_WINRT
1430     if (!SetupAVRT())
1431 	{
1432         PRINT(("WASAPI: No AVRT! (not VISTA?)"));
1433         return paNoError;
1434     }
1435 #endif
1436 
1437     paWasapi = (PaWasapiHostApiRepresentation *)PaUtil_AllocateMemory( sizeof(PaWasapiHostApiRepresentation) );
1438     if (paWasapi == NULL)
1439 	{
1440         result = paInsufficientMemory;
1441         goto error;
1442     }
1443 
1444     memset( paWasapi, 0, sizeof(PaWasapiHostApiRepresentation) ); /* ensure all fields are zeroed. especially paWasapi->allocations */
1445 
1446     result = PaWinUtil_CoInitialize( paWASAPI, &paWasapi->comInitializationResult );
1447     if( result != paNoError )
1448     {
1449         goto error;
1450     }
1451 
1452     paWasapi->allocations = PaUtil_CreateAllocationGroup();
1453     if (paWasapi->allocations == NULL)
1454 	{
1455         result = paInsufficientMemory;
1456         goto error;
1457     }
1458 
1459     *hostApi                             = &paWasapi->inheritedHostApiRep;
1460     (*hostApi)->info.structVersion		 = 1;
1461     (*hostApi)->info.type				 = paWASAPI;
1462     (*hostApi)->info.name				 = "Windows WASAPI";
1463     (*hostApi)->info.deviceCount		 = 0;
1464     (*hostApi)->info.defaultInputDevice	 = paNoDevice;
1465     (*hostApi)->info.defaultOutputDevice = paNoDevice;
1466 
1467 #ifndef PA_WINRT
1468     paWasapi->enumerator = NULL;
1469     hr = CoCreateInstance(&pa_CLSID_IMMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER,
1470              &pa_IID_IMMDeviceEnumerator, (void **)&paWasapi->enumerator);
1471 
1472 	// We need to set the result to a value otherwise we will return paNoError
1473 	// [IF_FAILED_JUMP(hResult, error);]
1474 	IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
1475 
1476     // getting default device ids in the eMultimedia "role"
1477     {
1478         {
1479             IMMDevice *defaultRenderer = NULL;
1480             hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(paWasapi->enumerator, eRender, eMultimedia, &defaultRenderer);
1481             if (hr != S_OK)
1482 			{
1483 				if (hr != E_NOTFOUND) {
1484 					// We need to set the result to a value otherwise we will return paNoError
1485 					// [IF_FAILED_JUMP(hResult, error);]
1486 					IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
1487 				}
1488 			}
1489 			else
1490 			{
1491 				WCHAR *pszDeviceId = NULL;
1492 				hr = IMMDevice_GetId(defaultRenderer, &pszDeviceId);
1493 				// We need to set the result to a value otherwise we will return paNoError
1494 				// [IF_FAILED_JUMP(hResult, error);]
1495 				IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
1496 				wcsncpy(paWasapi->defaultRenderer, pszDeviceId, MAX_STR_LEN-1);
1497 				CoTaskMemFree(pszDeviceId);
1498 				IMMDevice_Release(defaultRenderer);
1499 			}
1500         }
1501 
1502         {
1503             IMMDevice *defaultCapturer = NULL;
1504             hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(paWasapi->enumerator, eCapture, eMultimedia, &defaultCapturer);
1505             if (hr != S_OK)
1506 			{
1507 				if (hr != E_NOTFOUND) {
1508 					// We need to set the result to a value otherwise we will return paNoError
1509 					// [IF_FAILED_JUMP(hResult, error);]
1510 					IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
1511 				}
1512 			}
1513 			else
1514 			{
1515 				WCHAR *pszDeviceId = NULL;
1516 				hr = IMMDevice_GetId(defaultCapturer, &pszDeviceId);
1517 				// We need to set the result to a value otherwise we will return paNoError
1518 				// [IF_FAILED_JUMP(hResult, error);]
1519 				IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
1520 				wcsncpy(paWasapi->defaultCapturer, pszDeviceId, MAX_STR_LEN-1);
1521 				CoTaskMemFree(pszDeviceId);
1522 				IMMDevice_Release(defaultCapturer);
1523 			}
1524         }
1525     }
1526 
1527     hr = IMMDeviceEnumerator_EnumAudioEndpoints(paWasapi->enumerator, eAll, DEVICE_STATE_ACTIVE, &pEndPoints);
1528 	// We need to set the result to a value otherwise we will return paNoError
1529 	// [IF_FAILED_JUMP(hResult, error);]
1530 	IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
1531 
1532     hr = IMMDeviceCollection_GetCount(pEndPoints, &paWasapi->deviceCount);
1533 	// We need to set the result to a value otherwise we will return paNoError
1534 	// [IF_FAILED_JUMP(hResult, error);]
1535 	IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
1536 
1537 #else
1538 	paWasapi->deviceCount = 2;
1539 #endif
1540 
1541     paWasapi->devInfo = (PaWasapiDeviceInfo *)PaUtil_AllocateMemory(sizeof(PaWasapiDeviceInfo) * paWasapi->deviceCount);
1542     if (paWasapi->devInfo == NULL)
1543 	{
1544         result = paInsufficientMemory;
1545         goto error;
1546     }
1547 	for (i = 0; i < paWasapi->deviceCount; ++i)
1548 		memset(&paWasapi->devInfo[i], 0, sizeof(PaWasapiDeviceInfo));
1549 
1550     if (paWasapi->deviceCount > 0)
1551     {
1552         (*hostApi)->deviceInfos = (PaDeviceInfo **)PaUtil_GroupAllocateMemory(
1553                 paWasapi->allocations, sizeof(PaDeviceInfo *) * paWasapi->deviceCount);
1554         if ((*hostApi)->deviceInfos == NULL)
1555 		{
1556             result = paInsufficientMemory;
1557             goto error;
1558         }
1559 
1560         /* allocate all device info structs in a contiguous block */
1561         deviceInfoArray = (PaDeviceInfo *)PaUtil_GroupAllocateMemory(
1562                 paWasapi->allocations, sizeof(PaDeviceInfo) * paWasapi->deviceCount);
1563         if (deviceInfoArray == NULL)
1564 		{
1565             result = paInsufficientMemory;
1566             goto error;
1567         }
1568 
1569         for (i = 0; i < paWasapi->deviceCount; ++i)
1570 		{
1571             PaDeviceInfo *deviceInfo  = &deviceInfoArray[i];
1572             deviceInfo->structVersion = 2;
1573             deviceInfo->hostApi       = hostApiIndex;
1574 
1575 			PA_DEBUG(("WASAPI: device idx: %02d\n", i));
1576 			PA_DEBUG(("WASAPI: ---------------\n"));
1577 
1578 		#ifndef PA_WINRT
1579             hr = IMMDeviceCollection_Item(pEndPoints, i, &paWasapi->devInfo[i].device);
1580 			// We need to set the result to a value otherwise we will return paNoError
1581 			// [IF_FAILED_JUMP(hResult, error);]
1582 			IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
1583 
1584             // getting ID
1585             {
1586                 WCHAR *pszDeviceId = NULL;
1587                 hr = IMMDevice_GetId(paWasapi->devInfo[i].device, &pszDeviceId);
1588 				// We need to set the result to a value otherwise we will return paNoError
1589 				// [IF_FAILED_JUMP(hr, error);]
1590 				IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
1591                 wcsncpy(paWasapi->devInfo[i].szDeviceID, pszDeviceId, MAX_STR_LEN-1);
1592                 CoTaskMemFree(pszDeviceId);
1593 
1594                 if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultCapturer) == 0)
1595 				{// we found the default input!
1596                     (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;
1597                 }
1598                 if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultRenderer) == 0)
1599 				{// we found the default output!
1600                     (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
1601                 }
1602             }
1603 
1604             hr = IMMDevice_GetState(paWasapi->devInfo[i].device, &paWasapi->devInfo[i].state);
1605 			// We need to set the result to a value otherwise we will return paNoError
1606 			// [IF_FAILED_JUMP(hResult, error);]
1607 			IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
1608 
1609             if (paWasapi->devInfo[i].state != DEVICE_STATE_ACTIVE)
1610 			{
1611                 PRINT(("WASAPI device: %d is not currently available (state:%d)\n", i, paWasapi->devInfo[i].state));
1612             }
1613 
1614             {
1615                 IPropertyStore *pProperty;
1616                 hr = IMMDevice_OpenPropertyStore(paWasapi->devInfo[i].device, STGM_READ, &pProperty);
1617 				// We need to set the result to a value otherwise we will return paNoError
1618 				// [IF_FAILED_JUMP(hResult, error);]
1619 				IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
1620 
1621                 // "Friendly" Name
1622                 {
1623 					char *deviceName;
1624                     PROPVARIANT value;
1625                     PropVariantInit(&value);
1626                     hr = IPropertyStore_GetValue(pProperty, &PKEY_Device_FriendlyName, &value);
1627 					// We need to set the result to a value otherwise we will return paNoError
1628 					// [IF_FAILED_JUMP(hResult, error);]
1629 					IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
1630                     deviceInfo->name = NULL;
1631                     deviceName = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, MAX_STR_LEN + 1);
1632                     if (deviceName == NULL)
1633 					{
1634                         result = paInsufficientMemory;
1635                         goto error;
1636                     }
1637 					if (value.pwszVal)
1638 						WideCharToMultiByte(CP_UTF8, 0, value.pwszVal, (int)wcslen(value.pwszVal), deviceName, MAX_STR_LEN - 1, 0, 0);
1639 					else
1640 						_snprintf(deviceName, MAX_STR_LEN - 1, "baddev%d", i);
1641                     deviceInfo->name = deviceName;
1642                     PropVariantClear(&value);
1643 					PA_DEBUG(("WASAPI:%d| name[%s]\n", i, deviceInfo->name));
1644                 }
1645 
1646                 // Default format
1647                 {
1648                     PROPVARIANT value;
1649                     PropVariantInit(&value);
1650                     hr = IPropertyStore_GetValue(pProperty, &PKEY_AudioEngine_DeviceFormat, &value);
1651 					// We need to set the result to a value otherwise we will return paNoError
1652 					// [IF_FAILED_JUMP(hResult, error);]
1653 					IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
1654 					memcpy(&paWasapi->devInfo[i].DefaultFormat, value.blob.pBlobData, min(sizeof(paWasapi->devInfo[i].DefaultFormat), value.blob.cbSize));
1655                     // cleanup
1656                     PropVariantClear(&value);
1657                 }
1658 
1659                 // Formfactor
1660                 {
1661                     PROPVARIANT value;
1662                     PropVariantInit(&value);
1663                     hr = IPropertyStore_GetValue(pProperty, &PKEY_AudioEndpoint_FormFactor, &value);
1664 					// We need to set the result to a value otherwise we will return paNoError
1665 					// [IF_FAILED_JUMP(hResult, error);]
1666 					IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
1667 					// set
1668 					#if defined(DUMMYUNIONNAME) && defined(NONAMELESSUNION)
1669 						// avoid breaking strict-aliasing rules in such line: (EndpointFormFactor)(*((UINT *)(((WORD *)&value.wReserved3)+1)));
1670 						UINT v;
1671 						memcpy(&v, (((WORD *)&value.wReserved3)+1), sizeof(v));
1672 						paWasapi->devInfo[i].formFactor = (EndpointFormFactor)v;
1673 					#else
1674 						paWasapi->devInfo[i].formFactor = (EndpointFormFactor)value.uintVal;
1675 					#endif
1676 					PA_DEBUG(("WASAPI:%d| form-factor[%d]\n", i, paWasapi->devInfo[i].formFactor));
1677                     // cleanup
1678                     PropVariantClear(&value);
1679                 }
1680 
1681 				SAFE_RELEASE(pProperty);
1682             }
1683 
1684             // Endpoint data
1685             {
1686                 IMMEndpoint *endpoint = NULL;
1687                 hr = IMMDevice_QueryInterface(paWasapi->devInfo[i].device, &pa_IID_IMMEndpoint, (void **)&endpoint);
1688                 if (SUCCEEDED(hr))
1689 				{
1690                     hr = IMMEndpoint_GetDataFlow(endpoint, &paWasapi->devInfo[i].flow);
1691                     SAFE_RELEASE(endpoint);
1692                 }
1693             }
1694 		#endif
1695 
1696             // Getting a temporary IAudioClient for more fields
1697             // we make sure NOT to call Initialize yet!
1698             {
1699 			#ifdef PA_WINRT
1700 				// Set flow as ActivateAudioInterface depends on it and selects corresponding
1701 				// direction for the Audio Client
1702 				paWasapi->devInfo[i].flow = (i == 0 ? eRender : eCapture);
1703 			#endif
1704 
1705 				// Create temp Audio Client instance to query additional details
1706                 IAudioClient *tmpClient = NULL;
1707                 hr = ActivateAudioInterface(&paWasapi->devInfo[i], &tmpClient);
1708 				// We need to set the result to a value otherwise we will return paNoError
1709 				// [IF_FAILED_JUMP(hResult, error);]
1710 				IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
1711 
1712 				// Get latency
1713                 hr = IAudioClient_GetDevicePeriod(tmpClient,
1714                     &paWasapi->devInfo[i].DefaultDevicePeriod,
1715                     &paWasapi->devInfo[i].MinimumDevicePeriod);
1716 				if (FAILED(hr))
1717 				{
1718 					PA_DEBUG(("WASAPI:%d| failed getting min/default periods by IAudioClient::GetDevicePeriod() with error[%08X], will use 30000/100000 hns\n", i, (UINT32)hr));
1719 
1720 					// assign WASAPI common values
1721 					paWasapi->devInfo[i].DefaultDevicePeriod = 100000;
1722 					paWasapi->devInfo[i].MinimumDevicePeriod = 30000;
1723 
1724 					// ignore error, let continue further without failing with paInternalError
1725 					hr = S_OK;
1726 				}
1727 
1728 			#ifdef PA_WINRT
1729 				// Get mix format which will treat as default device format
1730 				hr = IAudioClient_GetMixFormat(tmpClient, &mixFormat);
1731 				if (SUCCEEDED(hr))
1732 				{
1733 					// Default device
1734 					if (i == 0)
1735 						(*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
1736 					else
1737 						(*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;
1738 
1739 					// State
1740 					paWasapi->devInfo[i].state = DEVICE_STATE_ACTIVE;
1741 
1742 					// Default format
1743 					memcpy(&paWasapi->devInfo[i].DefaultFormat, mixFormat, min(sizeof(paWasapi->devInfo[i].DefaultFormat), sizeof(*mixFormat)));
1744 					CoTaskMemFree(mixFormat);
1745 
1746 					// Form-factor
1747 					paWasapi->devInfo[i].formFactor = UnknownFormFactor;
1748 
1749 					// Name
1750                     deviceInfo->name = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, MAX_STR_LEN + 1);
1751                     if (deviceInfo->name == NULL)
1752 					{
1753 						SAFE_RELEASE(tmpClient);
1754                         result = paInsufficientMemory;
1755                         goto error;
1756                     }
1757 					_snprintf((char *)deviceInfo->name, MAX_STR_LEN - 1, "WASAPI_%s:%d", (i == 0 ? "Output" : "Input"), i);
1758 					PA_DEBUG(("WASAPI:%d| name[%s]\n", i, deviceInfo->name));
1759 				}
1760 			#endif
1761 
1762 				// Release tmp client
1763 				SAFE_RELEASE(tmpClient);
1764 
1765 				if (hr != S_OK)
1766 				{
1767 					//davidv: this happened with my hardware, previously for that same device in DirectSound:
1768 					//Digital Output (Realtek AC'97 Audio)'s GUID: {0x38f2cf50,0x7b4c,0x4740,0x86,0xeb,0xd4,0x38,0x66,0xd8,0xc8, 0x9f}
1769 					//so something must be _really_ wrong with this device, TODO handle this better. We kind of need GetMixFormat
1770 					LogHostError(hr);
1771 					// We need to set the result to a value otherwise we will return paNoError
1772 					result = paInternalError;
1773 					goto error;
1774 				}
1775             }
1776 
1777             // we can now fill in portaudio device data
1778             deviceInfo->maxInputChannels  = 0;
1779             deviceInfo->maxOutputChannels = 0;
1780 			deviceInfo->defaultSampleRate = paWasapi->devInfo[i].DefaultFormat.Format.nSamplesPerSec;
1781             switch (paWasapi->devInfo[i].flow)
1782 			{
1783 			case eRender: {
1784                 deviceInfo->maxOutputChannels		 = paWasapi->devInfo[i].DefaultFormat.Format.nChannels;
1785                 deviceInfo->defaultHighOutputLatency = nano100ToSeconds(paWasapi->devInfo[i].DefaultDevicePeriod);
1786                 deviceInfo->defaultLowOutputLatency  = nano100ToSeconds(paWasapi->devInfo[i].MinimumDevicePeriod);
1787 				PA_DEBUG(("WASAPI:%d| def.SR[%d] max.CH[%d] latency{hi[%f] lo[%f]}\n", i, (UINT32)deviceInfo->defaultSampleRate,
1788 					deviceInfo->maxOutputChannels, (float)deviceInfo->defaultHighOutputLatency, (float)deviceInfo->defaultLowOutputLatency));
1789 				break;}
1790 			case eCapture: {
1791                 deviceInfo->maxInputChannels		= paWasapi->devInfo[i].DefaultFormat.Format.nChannels;
1792                 deviceInfo->defaultHighInputLatency = nano100ToSeconds(paWasapi->devInfo[i].DefaultDevicePeriod);
1793                 deviceInfo->defaultLowInputLatency  = nano100ToSeconds(paWasapi->devInfo[i].MinimumDevicePeriod);
1794 				PA_DEBUG(("WASAPI:%d| def.SR[%d] max.CH[%d] latency{hi[%f] lo[%f]}\n", i, (UINT32)deviceInfo->defaultSampleRate,
1795 					deviceInfo->maxInputChannels, (float)deviceInfo->defaultHighInputLatency, (float)deviceInfo->defaultLowInputLatency));
1796 				break; }
1797             default:
1798                 PRINT(("WASAPI:%d| bad Data Flow!\n", i));
1799 				// We need to set the result to a value otherwise we will return paNoError
1800 				result = paInternalError;
1801                 //continue; // do not skip from list, allow to initialize
1802 				 break;
1803             }
1804 
1805             (*hostApi)->deviceInfos[i] = deviceInfo;
1806             ++(*hostApi)->info.deviceCount;
1807         }
1808     }
1809 
1810     (*hostApi)->Terminate = Terminate;
1811     (*hostApi)->OpenStream = OpenStream;
1812     (*hostApi)->IsFormatSupported = IsFormatSupported;
1813 
1814     PaUtil_InitializeStreamInterface( &paWasapi->callbackStreamInterface, CloseStream, StartStream,
1815                                       StopStream, AbortStream, IsStreamStopped, IsStreamActive,
1816                                       GetStreamTime, GetStreamCpuLoad,
1817                                       PaUtil_DummyRead, PaUtil_DummyWrite,
1818                                       PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
1819 
1820     PaUtil_InitializeStreamInterface( &paWasapi->blockingStreamInterface, CloseStream, StartStream,
1821                                       StopStream, AbortStream, IsStreamStopped, IsStreamActive,
1822                                       GetStreamTime, PaUtil_DummyGetCpuLoad,
1823                                       ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
1824 
1825 
1826 	// findout if platform workaround is required
1827 	paWasapi->useWOW64Workaround = UseWOW64Workaround();
1828 
1829 #ifndef PA_WINRT
1830     SAFE_RELEASE(pEndPoints);
1831 #endif
1832 
1833 	PRINT(("WASAPI: initialized ok\n"));
1834 
1835     return paNoError;
1836 
1837 error:
1838 
1839 	PRINT(("WASAPI: failed %s error[%d|%s]\n", __FUNCTION__, result, Pa_GetErrorText(result)));
1840 
1841 #ifndef PA_WINRT
1842     SAFE_RELEASE(pEndPoints);
1843 #endif
1844 
1845 	Terminate((PaUtilHostApiRepresentation *)paWasapi);
1846 
1847 	// Safety if error was not set so that we do not think initialize was a success
1848 	if (result == paNoError) {
1849 		result = paInternalError;
1850 	}
1851 
1852     return result;
1853 }
1854 
1855 // ------------------------------------------------------------------------------------------
Terminate(PaUtilHostApiRepresentation * hostApi)1856 static void Terminate( PaUtilHostApiRepresentation *hostApi )
1857 {
1858 	UINT i;
1859     PaWasapiHostApiRepresentation *paWasapi = (PaWasapiHostApiRepresentation*)hostApi;
1860 	if (paWasapi == NULL)
1861 		return;
1862 
1863 	// Release IMMDeviceEnumerator
1864 #ifndef PA_WINRT
1865     SAFE_RELEASE(paWasapi->enumerator);
1866 #endif
1867 
1868 	// Release device info bound objects and device info itself
1869     for (i = 0; i < paWasapi->deviceCount; ++i)
1870 	{
1871         PaWasapiDeviceInfo *info = &paWasapi->devInfo[i];
1872 	#ifndef PA_WINRT
1873         SAFE_RELEASE(info->device);
1874 	#else
1875 		(void)info;
1876 	#endif
1877     }
1878     PaUtil_FreeMemory(paWasapi->devInfo);
1879 
1880     if (paWasapi->allocations)
1881 	{
1882         PaUtil_FreeAllAllocations(paWasapi->allocations);
1883         PaUtil_DestroyAllocationGroup(paWasapi->allocations);
1884     }
1885 
1886     PaWinUtil_CoUninitialize( paWASAPI, &paWasapi->comInitializationResult );
1887 
1888     PaUtil_FreeMemory(paWasapi);
1889 
1890 	// Close AVRT
1891 	CloseAVRT();
1892 }
1893 
1894 // ------------------------------------------------------------------------------------------
_GetHostApi(PaError * _error)1895 static PaWasapiHostApiRepresentation *_GetHostApi(PaError *_error)
1896 {
1897 	PaError error;
1898 
1899 	PaUtilHostApiRepresentation *pApi;
1900 	if ((error = PaUtil_GetHostApiRepresentation(&pApi, paWASAPI)) != paNoError)
1901 	{
1902 		if (_error != NULL)
1903 			(*_error) = error;
1904 
1905 		return NULL;
1906 	}
1907 	return (PaWasapiHostApiRepresentation *)pApi;
1908 }
1909 
1910 // ------------------------------------------------------------------------------------------
PaWasapi_GetDeviceDefaultFormat(void * pFormat,unsigned int nFormatSize,PaDeviceIndex nDevice)1911 int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int nFormatSize, PaDeviceIndex nDevice )
1912 {
1913 	PaError ret;
1914 	PaWasapiHostApiRepresentation *paWasapi;
1915 	UINT32 size;
1916 	PaDeviceIndex index;
1917 
1918 	if (pFormat == NULL)
1919 		return paBadBufferPtr;
1920 	if (nFormatSize <= 0)
1921 		return paBufferTooSmall;
1922 
1923 	// Get API
1924 	paWasapi = _GetHostApi(&ret);
1925 	if (paWasapi == NULL)
1926 		return ret;
1927 
1928 	// Get device index
1929 	ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, nDevice, &paWasapi->inheritedHostApiRep);
1930     if (ret != paNoError)
1931         return ret;
1932 
1933 	// Validate index
1934 	if ((UINT32)index >= paWasapi->deviceCount)
1935 		return paInvalidDevice;
1936 
1937 	size = min(nFormatSize, (UINT32)sizeof(paWasapi->devInfo[ index ].DefaultFormat));
1938 	memcpy(pFormat, &paWasapi->devInfo[ index ].DefaultFormat, size);
1939 
1940 	return size;
1941 }
1942 
1943 // ------------------------------------------------------------------------------------------
PaWasapi_GetDeviceRole(PaDeviceIndex nDevice)1944 int PaWasapi_GetDeviceRole( PaDeviceIndex nDevice )
1945 {
1946 	PaError ret;
1947 	PaDeviceIndex index;
1948 
1949 	// Get API
1950 	PaWasapiHostApiRepresentation *paWasapi = _GetHostApi(&ret);
1951 	if (paWasapi == NULL)
1952 		return paNotInitialized;
1953 
1954 	// Get device index
1955 	ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, nDevice, &paWasapi->inheritedHostApiRep);
1956     if (ret != paNoError)
1957         return ret;
1958 
1959 	// Validate index
1960 	if ((UINT32)index >= paWasapi->deviceCount)
1961 		return paInvalidDevice;
1962 
1963 	return paWasapi->devInfo[ index ].formFactor;
1964 }
1965 
1966 // ------------------------------------------------------------------------------------------
PaWasapi_GetFramesPerHostBuffer(PaStream * pStream,unsigned int * nInput,unsigned int * nOutput)1967 PaError PaWasapi_GetFramesPerHostBuffer( PaStream *pStream, unsigned int *nInput, unsigned int *nOutput )
1968 {
1969     PaWasapiStream *stream = (PaWasapiStream *)pStream;
1970 	if (stream == NULL)
1971 		return paBadStreamPtr;
1972 
1973 	if (nInput != NULL)
1974 		(*nInput) = stream->in.framesPerHostCallback;
1975 
1976 	if (nOutput != NULL)
1977 		(*nOutput) = stream->out.framesPerHostCallback;
1978 
1979 	return paNoError;
1980 }
1981 
1982 // ------------------------------------------------------------------------------------------
LogWAVEFORMATEXTENSIBLE(const WAVEFORMATEXTENSIBLE * in)1983 static void LogWAVEFORMATEXTENSIBLE(const WAVEFORMATEXTENSIBLE *in)
1984 {
1985     const WAVEFORMATEX *old = (WAVEFORMATEX *)in;
1986 	switch (old->wFormatTag)
1987 	{
1988 	case WAVE_FORMAT_EXTENSIBLE: {
1989 
1990 		PRINT(("wFormatTag     =WAVE_FORMAT_EXTENSIBLE\n"));
1991 
1992 		if (IsEqualGUID(&in->SubFormat, &pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
1993 		{
1994 			PRINT(("SubFormat      =KSDATAFORMAT_SUBTYPE_IEEE_FLOAT\n"));
1995 		}
1996 		else
1997 		if (IsEqualGUID(&in->SubFormat, &pa_KSDATAFORMAT_SUBTYPE_PCM))
1998 		{
1999 			PRINT(("SubFormat      =KSDATAFORMAT_SUBTYPE_PCM\n"));
2000 		}
2001 		else
2002 		{
2003 			PRINT(("SubFormat      =CUSTOM GUID{%d:%d:%d:%d%d%d%d%d%d%d%d}\n",
2004 										in->SubFormat.Data1,
2005 										in->SubFormat.Data2,
2006 										in->SubFormat.Data3,
2007 										(int)in->SubFormat.Data4[0],
2008 										(int)in->SubFormat.Data4[1],
2009 										(int)in->SubFormat.Data4[2],
2010 										(int)in->SubFormat.Data4[3],
2011 										(int)in->SubFormat.Data4[4],
2012 										(int)in->SubFormat.Data4[5],
2013 										(int)in->SubFormat.Data4[6],
2014 										(int)in->SubFormat.Data4[7]));
2015 		}
2016 		PRINT(("Samples.wValidBitsPerSample =%d\n",  in->Samples.wValidBitsPerSample));
2017 		PRINT(("dwChannelMask  =0x%X\n",in->dwChannelMask));
2018 
2019 		break; }
2020 
2021 	case WAVE_FORMAT_PCM:        PRINT(("wFormatTag     =WAVE_FORMAT_PCM\n")); break;
2022 	case WAVE_FORMAT_IEEE_FLOAT: PRINT(("wFormatTag     =WAVE_FORMAT_IEEE_FLOAT\n")); break;
2023 	default:
2024 		PRINT(("wFormatTag     =UNKNOWN(%d)\n",old->wFormatTag)); break;
2025 	}
2026 
2027 	PRINT(("nChannels      =%d\n",old->nChannels));
2028 	PRINT(("nSamplesPerSec =%d\n",old->nSamplesPerSec));
2029 	PRINT(("nAvgBytesPerSec=%d\n",old->nAvgBytesPerSec));
2030 	PRINT(("nBlockAlign    =%d\n",old->nBlockAlign));
2031 	PRINT(("wBitsPerSample =%d\n",old->wBitsPerSample));
2032 	PRINT(("cbSize         =%d\n",old->cbSize));
2033 }
2034 
2035 // ------------------------------------------------------------------------------------------
WaveToPaFormat(const WAVEFORMATEXTENSIBLE * in)2036 static PaSampleFormat WaveToPaFormat(const WAVEFORMATEXTENSIBLE *in)
2037 {
2038     const WAVEFORMATEX *old = (WAVEFORMATEX *)in;
2039 
2040     switch (old->wFormatTag)
2041 	{
2042     case WAVE_FORMAT_EXTENSIBLE: {
2043         if (IsEqualGUID(&in->SubFormat, &pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
2044 		{
2045             if (in->Samples.wValidBitsPerSample == 32)
2046                 return paFloat32;
2047         }
2048         else
2049 		if (IsEqualGUID(&in->SubFormat, &pa_KSDATAFORMAT_SUBTYPE_PCM))
2050 		{
2051             switch (old->wBitsPerSample)
2052 			{
2053                 case 32: return paInt32;
2054                 case 24: return paInt24;
2055                 case  8: return paUInt8;
2056                 case 16: return paInt16;
2057             }
2058         }
2059 		break; }
2060 
2061     case WAVE_FORMAT_IEEE_FLOAT:
2062 		return paFloat32;
2063 
2064     case WAVE_FORMAT_PCM: {
2065         switch (old->wBitsPerSample)
2066 		{
2067             case 32: return paInt32;
2068             case 24: return paInt24;
2069             case  8: return paUInt8;
2070             case 16: return paInt16;
2071         }
2072 		break; }
2073     }
2074 
2075     return paCustomFormat;
2076 }
2077 
2078 // ------------------------------------------------------------------------------------------
MakeWaveFormatFromParams(WAVEFORMATEXTENSIBLE * wavex,const PaStreamParameters * params,double sampleRate)2079 static PaError MakeWaveFormatFromParams(WAVEFORMATEXTENSIBLE *wavex, const PaStreamParameters *params,
2080 									double sampleRate)
2081 {
2082 	WORD bitsPerSample;
2083 	WAVEFORMATEX *old;
2084 	DWORD channelMask = 0;
2085 	PaWasapiStreamInfo *streamInfo = (PaWasapiStreamInfo *)params->hostApiSpecificStreamInfo;
2086 
2087 	// Get user assigned channel mask
2088 	if ((streamInfo != NULL) && (streamInfo->flags & paWinWasapiUseChannelMask))
2089 		channelMask = streamInfo->channelMask;
2090 
2091 	// Convert PaSampleFormat to bits per sample
2092 	if ((bitsPerSample = PaSampleFormatToBitsPerSample(params->sampleFormat)) == 0)
2093 		return paSampleFormatNotSupported;
2094 
2095     memset(wavex, 0, sizeof(*wavex));
2096 
2097     old					 = (WAVEFORMATEX *)wavex;
2098     old->nChannels       = (WORD)params->channelCount;
2099     old->nSamplesPerSec  = (DWORD)sampleRate;
2100 	if ((old->wBitsPerSample = bitsPerSample) > 16)
2101 	{
2102 		old->wBitsPerSample = 32; // 20 or 24 bits must go in 32 bit containers (ints)
2103 	}
2104     old->nBlockAlign     = (old->nChannels * (old->wBitsPerSample/8));
2105     old->nAvgBytesPerSec = (old->nSamplesPerSec * old->nBlockAlign);
2106 
2107     // WAVEFORMATEX
2108     if ((params->channelCount <= 2) && ((bitsPerSample == 16) || (bitsPerSample == 8)))
2109 	{
2110         old->cbSize		= 0;
2111         old->wFormatTag	= WAVE_FORMAT_PCM;
2112     }
2113     // WAVEFORMATEXTENSIBLE
2114     else
2115 	{
2116         old->wFormatTag = WAVE_FORMAT_EXTENSIBLE;
2117         old->cbSize		= sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
2118 
2119         if ((params->sampleFormat & ~paNonInterleaved) == paFloat32)
2120             wavex->SubFormat = pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
2121         else
2122             wavex->SubFormat = pa_KSDATAFORMAT_SUBTYPE_PCM;
2123 
2124         wavex->Samples.wValidBitsPerSample = bitsPerSample; //no extra padding!
2125 
2126 		// Set channel mask
2127 		if (channelMask != 0)
2128 		{
2129 			wavex->dwChannelMask = channelMask;
2130 		}
2131 		else
2132 		{
2133 			switch (params->channelCount)
2134 			{
2135 			case 1:  wavex->dwChannelMask = PAWIN_SPEAKER_MONO; break;
2136 			case 2:  wavex->dwChannelMask = PAWIN_SPEAKER_STEREO; break;
2137 			case 3:  wavex->dwChannelMask = PAWIN_SPEAKER_STEREO|SPEAKER_LOW_FREQUENCY; break;
2138 			case 4:  wavex->dwChannelMask = PAWIN_SPEAKER_QUAD; break;
2139 			case 5:  wavex->dwChannelMask = PAWIN_SPEAKER_QUAD|SPEAKER_LOW_FREQUENCY; break;
2140 #ifdef PAWIN_SPEAKER_5POINT1_SURROUND
2141 			case 6:  wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1_SURROUND; break;
2142 #else
2143 			case 6:  wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1; break;
2144 #endif
2145 #ifdef PAWIN_SPEAKER_5POINT1_SURROUND
2146 			case 7:  wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1_SURROUND|SPEAKER_BACK_CENTER; break;
2147 #else
2148 			case 7:  wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1|SPEAKER_BACK_CENTER; break;
2149 #endif
2150 #ifdef PAWIN_SPEAKER_7POINT1_SURROUND
2151 			case 8:  wavex->dwChannelMask = PAWIN_SPEAKER_7POINT1_SURROUND; break;
2152 #else
2153 			case 8:  wavex->dwChannelMask = PAWIN_SPEAKER_7POINT1; break;
2154 #endif
2155 
2156 			default: wavex->dwChannelMask = 0;
2157 			}
2158 		}
2159 	}
2160     return paNoError;
2161 }
2162 
2163 // ------------------------------------------------------------------------------------------
2164 /*static void wasapiFillWFEXT( WAVEFORMATEXTENSIBLE* pwfext, PaSampleFormat sampleFormat, double sampleRate, int channelCount)
2165 {
2166     PA_DEBUG(( "sampleFormat = %lx\n" , sampleFormat ));
2167     PA_DEBUG(( "sampleRate = %f\n" , sampleRate ));
2168     PA_DEBUG(( "chanelCount = %d\n", channelCount ));
2169 
2170     pwfext->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
2171     pwfext->Format.nChannels = (WORD)channelCount;
2172     pwfext->Format.nSamplesPerSec = (DWORD)sampleRate;
2173     if(channelCount == 1)
2174         pwfext->dwChannelMask = PAWIN_SPEAKER_DIRECTOUT;
2175     else
2176         pwfext->dwChannelMask = PAWIN_SPEAKER_STEREO;
2177     if(sampleFormat == paFloat32)
2178     {
2179         pwfext->Format.nBlockAlign = (WORD)(channelCount * 4);
2180         pwfext->Format.wBitsPerSample = 32;
2181         pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
2182         pwfext->Samples.wValidBitsPerSample = 32;
2183         pwfext->SubFormat = pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
2184     }
2185     else if(sampleFormat == paInt32)
2186     {
2187         pwfext->Format.nBlockAlign = (WORD)(channelCount * 4);
2188         pwfext->Format.wBitsPerSample = 32;
2189         pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
2190         pwfext->Samples.wValidBitsPerSample = 32;
2191         pwfext->SubFormat = pa_KSDATAFORMAT_SUBTYPE_PCM;
2192     }
2193     else if(sampleFormat == paInt24)
2194     {
2195         pwfext->Format.nBlockAlign = (WORD)(channelCount * 4);
2196         pwfext->Format.wBitsPerSample = 32; // 24-bit in 32-bit int container
2197         pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
2198         pwfext->Samples.wValidBitsPerSample = 24;
2199         pwfext->SubFormat = pa_KSDATAFORMAT_SUBTYPE_PCM;
2200     }
2201     else if(sampleFormat == paInt16)
2202     {
2203         pwfext->Format.nBlockAlign = (WORD)(channelCount * 2);
2204         pwfext->Format.wBitsPerSample = 16;
2205         pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
2206         pwfext->Samples.wValidBitsPerSample = 16;
2207         pwfext->SubFormat = pa_KSDATAFORMAT_SUBTYPE_PCM;
2208     }
2209     pwfext->Format.nAvgBytesPerSec = pwfext->Format.nSamplesPerSec * pwfext->Format.nBlockAlign;
2210 }*/
2211 
2212 // ------------------------------------------------------------------------------------------
GetClosestFormat(IAudioClient * myClient,double sampleRate,const PaStreamParameters * _params,AUDCLNT_SHAREMODE shareMode,WAVEFORMATEXTENSIBLE * outWavex,BOOL output)2213 static PaError GetClosestFormat(IAudioClient *myClient, double sampleRate,
2214 	const PaStreamParameters *_params, AUDCLNT_SHAREMODE shareMode, WAVEFORMATEXTENSIBLE *outWavex,
2215 	BOOL output)
2216 {
2217 	PaError answer                   = paInvalidSampleRate;
2218 	WAVEFORMATEX *sharedClosestMatch = NULL;
2219 	HRESULT hr                       = !S_OK;
2220 	PaStreamParameters params       = (*_params);
2221 	(void)output;
2222 
2223 	/* It was not noticed that 24-bit Input producing no output while device accepts this format.
2224 	   To fix this issue let's ask for 32-bits and let PA converters convert host 32-bit data
2225 	   to 24-bit for user-space. The bug concerns Vista, if Windows 7 supports 24-bits for Input
2226 	   please report to PortAudio developers to exclude Windows 7.
2227 	*/
2228 	/*if ((params.sampleFormat == paInt24) && (output == FALSE))
2229 		params.sampleFormat = paFloat32;*/ // <<< The silence was due to missing Int32_To_Int24_Dither implementation
2230 
2231     MakeWaveFormatFromParams(outWavex, &params, sampleRate);
2232 
2233 	hr = IAudioClient_IsFormatSupported(myClient, shareMode, &outWavex->Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));
2234 	if (hr == S_OK)
2235 		answer = paFormatIsSupported;
2236     else
2237 	if (sharedClosestMatch)
2238 	{
2239 		WORD bitsPerSample;
2240         WAVEFORMATEXTENSIBLE *ext = (WAVEFORMATEXTENSIBLE*)sharedClosestMatch;
2241 
2242 		GUID subf_guid = GUID_NULL;
2243 		if (sharedClosestMatch->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
2244 		{
2245 			memcpy(outWavex, sharedClosestMatch, sizeof(WAVEFORMATEXTENSIBLE));
2246 			subf_guid = ext->SubFormat;
2247 		}
2248 		else
2249 			memcpy(outWavex, sharedClosestMatch, sizeof(WAVEFORMATEX));
2250 
2251         CoTaskMemFree(sharedClosestMatch);
2252 
2253 		// Make supported by default
2254 		answer = paFormatIsSupported;
2255 
2256 		// Validate SampleRate
2257 		if ((DWORD)sampleRate != outWavex->Format.nSamplesPerSec)
2258 			return paInvalidSampleRate;
2259 
2260 		// Validate Channel count
2261 		if ((WORD)params.channelCount != outWavex->Format.nChannels)
2262 		{
2263 			// If mono, then driver does not support 1 channel, we use internal workaround
2264 			// of tiny software mixing functionality, e.g. we provide to user buffer 1 channel
2265 			// but then mix into 2 for device buffer
2266 			if ((params.channelCount == 1) && (outWavex->Format.nChannels == 2))
2267 				return paFormatIsSupported;
2268 			else
2269 				return paInvalidChannelCount;
2270 		}
2271 
2272 		// Validate Sample format
2273 		if ((bitsPerSample = PaSampleFormatToBitsPerSample(params.sampleFormat)) == 0)
2274 			return paSampleFormatNotSupported;
2275 
2276 		// Validate Sample format: bit size (WASAPI does not limit 'bit size')
2277 		//if (bitsPerSample != outWavex->Format.wBitsPerSample)
2278 		//	return paSampleFormatNotSupported;
2279 
2280 		// Validate Sample format: paFloat32 (WASAPI does not limit 'bit type')
2281 		//if ((params->sampleFormat == paFloat32) && (subf_guid != KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
2282 		//	return paSampleFormatNotSupported;
2283 
2284 		// Validate Sample format: paInt32 (WASAPI does not limit 'bit type')
2285 		//if ((params->sampleFormat == paInt32) && (subf_guid != KSDATAFORMAT_SUBTYPE_PCM))
2286 		//	return paSampleFormatNotSupported;
2287 	}
2288 	else
2289 	{
2290 		static const int BestToWorst[] = { paFloat32, paInt24, paInt16 };
2291 		int i;
2292 
2293 		// Try combination stereo and we will use built-in mono-stereo mixer then
2294 		if (params.channelCount == 1)
2295 		{
2296 			WAVEFORMATEXTENSIBLE stereo = { 0 };
2297 
2298 			PaStreamParameters stereo_params = params;
2299 			stereo_params.channelCount = 2;
2300 
2301 			MakeWaveFormatFromParams(&stereo, &stereo_params, sampleRate);
2302 
2303 			hr = IAudioClient_IsFormatSupported(myClient, shareMode, &stereo.Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));
2304 			if (hr == S_OK)
2305 			{
2306 				memcpy(outWavex, &stereo, sizeof(WAVEFORMATEXTENSIBLE));
2307 				CoTaskMemFree(sharedClosestMatch);
2308 				return (answer = paFormatIsSupported);
2309 			}
2310 
2311 			// Try selecting suitable sample type
2312 			for (i = 0; i < STATIC_ARRAY_SIZE(BestToWorst); ++i)
2313 			{
2314 				WAVEFORMATEXTENSIBLE sample = { 0 };
2315 
2316 				PaStreamParameters sample_params = stereo_params;
2317 				sample_params.sampleFormat = BestToWorst[i];
2318 
2319 				MakeWaveFormatFromParams(&sample, &sample_params, sampleRate);
2320 
2321 				hr = IAudioClient_IsFormatSupported(myClient, shareMode, &sample.Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));
2322 				if (hr == S_OK)
2323 				{
2324 					memcpy(outWavex, &sample, sizeof(WAVEFORMATEXTENSIBLE));
2325 					CoTaskMemFree(sharedClosestMatch);
2326 					return (answer = paFormatIsSupported);
2327 				}
2328 			}
2329 		}
2330 
2331 		// Try selecting suitable sample type
2332 		for (i = 0; i < STATIC_ARRAY_SIZE(BestToWorst); ++i)
2333 		{
2334 			WAVEFORMATEXTENSIBLE spfmt = { 0 };
2335 
2336 			PaStreamParameters spfmt_params = params;
2337 			spfmt_params.sampleFormat = BestToWorst[i];
2338 
2339 			MakeWaveFormatFromParams(&spfmt, &spfmt_params, sampleRate);
2340 
2341 			hr = IAudioClient_IsFormatSupported(myClient, shareMode, &spfmt.Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));
2342 			if (hr == S_OK)
2343 			{
2344 				memcpy(outWavex, &spfmt, sizeof(WAVEFORMATEXTENSIBLE));
2345 				CoTaskMemFree(sharedClosestMatch);
2346 				answer = paFormatIsSupported;
2347 				break;
2348 			}
2349 		}
2350 
2351 		// Nothing helped
2352 		LogHostError(hr);
2353 	}
2354 
2355 	return answer;
2356 }
2357 
2358 // ------------------------------------------------------------------------------------------
IsStreamParamsValid(struct PaUtilHostApiRepresentation * hostApi,const PaStreamParameters * inputParameters,const PaStreamParameters * outputParameters,double sampleRate)2359 static PaError IsStreamParamsValid(struct PaUtilHostApiRepresentation *hostApi,
2360                                    const  PaStreamParameters *inputParameters,
2361                                    const  PaStreamParameters *outputParameters,
2362                                    double sampleRate)
2363 {
2364 	if (hostApi == NULL)
2365 		return paHostApiNotFound;
2366 	if ((UINT32)sampleRate == 0)
2367 		return paInvalidSampleRate;
2368 
2369 	if (inputParameters != NULL)
2370     {
2371         /* all standard sample formats are supported by the buffer adapter,
2372             this implementation doesn't support any custom sample formats */
2373 		if (inputParameters->sampleFormat & paCustomFormat)
2374             return paSampleFormatNotSupported;
2375 
2376         /* unless alternate device specification is supported, reject the use of
2377             paUseHostApiSpecificDeviceSpecification */
2378         if (inputParameters->device == paUseHostApiSpecificDeviceSpecification)
2379             return paInvalidDevice;
2380 
2381         /* check that input device can support inputChannelCount */
2382         if (inputParameters->channelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels)
2383             return paInvalidChannelCount;
2384 
2385         /* validate inputStreamInfo */
2386         if (inputParameters->hostApiSpecificStreamInfo)
2387 		{
2388 			PaWasapiStreamInfo *inputStreamInfo = (PaWasapiStreamInfo *)inputParameters->hostApiSpecificStreamInfo;
2389 	        if ((inputStreamInfo->size != sizeof(PaWasapiStreamInfo)) ||
2390 	            (inputStreamInfo->version != 1) ||
2391                 (inputStreamInfo->hostApiType != paWASAPI))
2392 	        {
2393 	            return paIncompatibleHostApiSpecificStreamInfo;
2394 	        }
2395 		}
2396 
2397         return paNoError;
2398     }
2399 
2400     if (outputParameters != NULL)
2401     {
2402         /* all standard sample formats are supported by the buffer adapter,
2403             this implementation doesn't support any custom sample formats */
2404         if (outputParameters->sampleFormat & paCustomFormat)
2405             return paSampleFormatNotSupported;
2406 
2407         /* unless alternate device specification is supported, reject the use of
2408             paUseHostApiSpecificDeviceSpecification */
2409         if (outputParameters->device == paUseHostApiSpecificDeviceSpecification)
2410             return paInvalidDevice;
2411 
2412         /* check that output device can support outputChannelCount */
2413         if (outputParameters->channelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels)
2414             return paInvalidChannelCount;
2415 
2416         /* validate outputStreamInfo */
2417         if(outputParameters->hostApiSpecificStreamInfo)
2418         {
2419 			PaWasapiStreamInfo *outputStreamInfo = (PaWasapiStreamInfo *)outputParameters->hostApiSpecificStreamInfo;
2420 	        if ((outputStreamInfo->size != sizeof(PaWasapiStreamInfo)) ||
2421 	            (outputStreamInfo->version != 1) ||
2422                 (outputStreamInfo->hostApiType != paWASAPI))
2423 	        {
2424 	            return paIncompatibleHostApiSpecificStreamInfo;
2425 	        }
2426         }
2427 
2428 		return paNoError;
2429     }
2430 
2431 	return (inputParameters || outputParameters ? paNoError : paInternalError);
2432 }
2433 
2434 // ------------------------------------------------------------------------------------------
IsFormatSupported(struct PaUtilHostApiRepresentation * hostApi,const PaStreamParameters * inputParameters,const PaStreamParameters * outputParameters,double sampleRate)2435 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
2436                                   const  PaStreamParameters *inputParameters,
2437                                   const  PaStreamParameters *outputParameters,
2438                                   double sampleRate )
2439 {
2440 	IAudioClient *tmpClient = NULL;
2441 	PaWasapiHostApiRepresentation *paWasapi = (PaWasapiHostApiRepresentation*)hostApi;
2442 	PaWasapiStreamInfo *inputStreamInfo = NULL, *outputStreamInfo = NULL;
2443 
2444 	// Validate PaStreamParameters
2445 	PaError error;
2446 	if ((error = IsStreamParamsValid(hostApi, inputParameters, outputParameters, sampleRate)) != paNoError)
2447 		return error;
2448 
2449     if (inputParameters != NULL)
2450     {
2451 		WAVEFORMATEXTENSIBLE wavex;
2452 		HRESULT hr;
2453 		PaError answer;
2454 		AUDCLNT_SHAREMODE shareMode = AUDCLNT_SHAREMODE_SHARED;
2455 		inputStreamInfo = (PaWasapiStreamInfo *)inputParameters->hostApiSpecificStreamInfo;
2456 
2457 		if (inputStreamInfo && (inputStreamInfo->flags & paWinWasapiExclusive))
2458 			shareMode  = AUDCLNT_SHAREMODE_EXCLUSIVE;
2459 
2460 		hr = ActivateAudioInterface(&paWasapi->devInfo[inputParameters->device], &tmpClient);
2461 		if (hr != S_OK)
2462 		{
2463 			LogHostError(hr);
2464 			return paInvalidDevice;
2465 		}
2466 
2467 		answer = GetClosestFormat(tmpClient, sampleRate, inputParameters, shareMode, &wavex, FALSE);
2468 		SAFE_RELEASE(tmpClient);
2469 
2470 		if (answer != paFormatIsSupported)
2471 			return answer;
2472     }
2473 
2474     if (outputParameters != NULL)
2475     {
2476 		HRESULT hr;
2477 		WAVEFORMATEXTENSIBLE wavex;
2478 		PaError answer;
2479 		AUDCLNT_SHAREMODE shareMode = AUDCLNT_SHAREMODE_SHARED;
2480         outputStreamInfo = (PaWasapiStreamInfo *)outputParameters->hostApiSpecificStreamInfo;
2481 
2482 		if (outputStreamInfo && (outputStreamInfo->flags & paWinWasapiExclusive))
2483 			shareMode  = AUDCLNT_SHAREMODE_EXCLUSIVE;
2484 
2485 		hr = ActivateAudioInterface(&paWasapi->devInfo[outputParameters->device], &tmpClient);
2486 		if (hr != S_OK)
2487 		{
2488 			LogHostError(hr);
2489 			return paInvalidDevice;
2490 		}
2491 
2492 		answer = GetClosestFormat(tmpClient, sampleRate, outputParameters, shareMode, &wavex, TRUE);
2493 		SAFE_RELEASE(tmpClient);
2494 
2495 		if (answer != paFormatIsSupported)
2496 			return answer;
2497     }
2498 
2499     return paFormatIsSupported;
2500 }
2501 
2502 // ------------------------------------------------------------------------------------------
PaUtil_GetFramesPerHostBuffer(PaUint32 userFramesPerBuffer,PaTime suggestedLatency,double sampleRate,PaUint32 TimerJitterMs)2503 static PaUint32 PaUtil_GetFramesPerHostBuffer(PaUint32 userFramesPerBuffer, PaTime suggestedLatency, double sampleRate, PaUint32 TimerJitterMs)
2504 {
2505 	PaUint32 frames = userFramesPerBuffer + max( userFramesPerBuffer, (PaUint32)(suggestedLatency * sampleRate) );
2506     frames += (PaUint32)((sampleRate * 0.001) * TimerJitterMs);
2507 	return frames;
2508 }
2509 
2510 // ------------------------------------------------------------------------------------------
_RecalculateBuffersCount(PaWasapiSubStream * sub,UINT32 userFramesPerBuffer,UINT32 framesPerLatency,BOOL fullDuplex)2511 static void _RecalculateBuffersCount(PaWasapiSubStream *sub, UINT32 userFramesPerBuffer, UINT32 framesPerLatency, BOOL fullDuplex)
2512 {
2513 	// Count buffers (must be at least 1)
2514 	sub->buffers = (userFramesPerBuffer ? framesPerLatency / userFramesPerBuffer : 0);
2515 	if (sub->buffers == 0)
2516 		sub->buffers = 1;
2517 
2518 	// Determine amount of buffers used:
2519 	// - Full-duplex mode will lead to period difference, thus only 1.
2520 	// - Input mode, only 1, as WASAPI allows extraction of only 1 packet.
2521 	// - For Shared mode we use double buffering.
2522 	if ((sub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) || fullDuplex)
2523 	{
2524 		// Exclusive mode does not allow >1 buffers be used for Event interface, e.g. GetBuffer
2525 		// call must acquire max buffer size and it all must be processed.
2526 		if (sub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)
2527 			sub->userBufferAndHostMatch = 1;
2528 
2529 		// Use paUtilBoundedHostBufferSize because exclusive mode will starve and produce
2530 		// bad quality of audio
2531 		sub->buffers = 1;
2532 	}
2533 }
2534 
2535 // ------------------------------------------------------------------------------------------
_CalculateAlignedPeriod(PaWasapiSubStream * pSub,UINT32 * nFramesPerLatency,ALIGN_FUNC pAlignFunc)2536 static void _CalculateAlignedPeriod(PaWasapiSubStream *pSub, UINT32 *nFramesPerLatency,
2537 									ALIGN_FUNC pAlignFunc)
2538 {
2539 	// Align frames to HD Audio packet size of 128 bytes for Exclusive mode only.
2540 	// Not aligning on Windows Vista will cause Event timeout, although Windows 7 will
2541 	// return AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED error to realign buffer. Aligning is necessary
2542 	// for Exclusive mode only! when audio data is feeded directly to hardware.
2543 	if (pSub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)
2544 	{
2545 		(*nFramesPerLatency) = AlignFramesPerBuffer((*nFramesPerLatency),
2546 			pSub->wavex.Format.nSamplesPerSec, pSub->wavex.Format.nBlockAlign, pAlignFunc);
2547 	}
2548 
2549 	// Calculate period
2550 	pSub->period = MakeHnsPeriod((*nFramesPerLatency), pSub->wavex.Format.nSamplesPerSec);
2551 }
2552 
2553 // ------------------------------------------------------------------------------------------
CreateAudioClient(PaWasapiStream * pStream,PaWasapiSubStream * pSub,BOOL output,PaError * pa_error)2554 static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSub, BOOL output, PaError *pa_error)
2555 {
2556 	PaError error;
2557     HRESULT hr;
2558 
2559 	const PaWasapiDeviceInfo *pInfo  = pSub->params.device_info;
2560 	const PaStreamParameters *params = &pSub->params.stream_params;
2561 	UINT32 framesPerLatency          = pSub->params.frames_per_buffer;
2562 	double sampleRate                = pSub->params.sample_rate;
2563 	//BOOL blocking                    = pSub->params.blocking;
2564 	BOOL fullDuplex                  = pSub->params.full_duplex;
2565 
2566 	const UINT32 userFramesPerBuffer = framesPerLatency;
2567     IAudioClient *audioClient	     = NULL;
2568 
2569 	// Assume default failure due to some reason
2570 	(*pa_error) = paInvalidDevice;
2571 
2572 	// Validate parameters
2573     if (!pSub || !pInfo || !params)
2574 	{
2575 		(*pa_error) = paBadStreamPtr;
2576         return E_POINTER;
2577 	}
2578 	if ((UINT32)sampleRate == 0)
2579 	{
2580 		(*pa_error) = paInvalidSampleRate;
2581         return E_INVALIDARG;
2582 	}
2583 
2584     // Get the audio client
2585     hr = ActivateAudioInterface(pInfo, &audioClient);
2586 	if (hr != S_OK)
2587 	{
2588 		(*pa_error) = paInsufficientMemory;
2589 		LogHostError(hr);
2590 		goto done;
2591 	}
2592 
2593 	// Get closest format
2594 	if ((error = GetClosestFormat(audioClient, sampleRate, params, pSub->shareMode, &pSub->wavex, output)) != paFormatIsSupported)
2595 	{
2596 		(*pa_error) = error;
2597 		LogHostError(hr = AUDCLNT_E_UNSUPPORTED_FORMAT);
2598 		goto done; // fail, format not supported
2599 	}
2600 
2601 	// Check for Mono <<>> Stereo workaround
2602 	if ((params->channelCount == 1) && (pSub->wavex.Format.nChannels == 2))
2603 	{
2604 		/*if (blocking)
2605 		{
2606 			LogHostError(hr = AUDCLNT_E_UNSUPPORTED_FORMAT);
2607 			goto done; // fail, blocking mode not supported
2608 		}*/
2609 
2610 		// select mixer
2611 		pSub->monoMixer = _GetMonoToStereoMixer(WaveToPaFormat(&pSub->wavex), (pInfo->flow == eRender ? MIX_DIR__1TO2 : MIX_DIR__2TO1_L));
2612 		if (pSub->monoMixer == NULL)
2613 		{
2614 			(*pa_error) = paInvalidChannelCount;
2615 			LogHostError(hr = AUDCLNT_E_UNSUPPORTED_FORMAT);
2616 			goto done; // fail, no mixer for format
2617 		}
2618 	}
2619 
2620 #if 0
2621 	// Add suggestd latency
2622 	framesPerLatency += MakeFramesFromHns(SecondsTonano100(params->suggestedLatency), pSub->wavex.Format.nSamplesPerSec);
2623 #else
2624 	// Calculate host buffer size
2625 	if ((pSub->shareMode != AUDCLNT_SHAREMODE_EXCLUSIVE) &&
2626 		(!pSub->streamFlags || ((pSub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) == 0)))
2627 	{
2628 		framesPerLatency = PaUtil_GetFramesPerHostBuffer(userFramesPerBuffer,
2629 			params->suggestedLatency, pSub->wavex.Format.nSamplesPerSec, 0/*,
2630 			(pSub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK ? 0 : 1)*/);
2631 	}
2632 	else
2633 	{
2634 		REFERENCE_TIME overall;
2635 
2636 		// Work 1:1 with user buffer (only polling allows to use >1)
2637 		framesPerLatency += MakeFramesFromHns(SecondsTonano100(params->suggestedLatency), pSub->wavex.Format.nSamplesPerSec);
2638 
2639 		// Use Polling if overall latency is > 5ms as it allows to use 100% CPU in a callback,
2640 		// or user specified latency parameter
2641 		overall = MakeHnsPeriod(framesPerLatency, pSub->wavex.Format.nSamplesPerSec);
2642 		if ((overall >= (106667*2)/*21.33ms*/) || ((INT32)(params->suggestedLatency*100000.0) != 0/*0.01 msec granularity*/))
2643 		{
2644 			framesPerLatency = PaUtil_GetFramesPerHostBuffer(userFramesPerBuffer,
2645 				params->suggestedLatency, pSub->wavex.Format.nSamplesPerSec, 0/*,
2646 				(streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK ? 0 : 1)*/);
2647 
2648 			// Use Polling interface
2649 			pSub->streamFlags &= ~AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
2650 			PRINT(("WASAPI: CreateAudioClient: forcing POLL mode\n"));
2651 		}
2652 	}
2653 #endif
2654 
2655 	// For full-duplex output resize buffer to be the same as for input
2656 	if (output && fullDuplex)
2657 		framesPerLatency = pStream->in.framesPerHostCallback;
2658 
2659 	// Avoid 0 frames
2660 	if (framesPerLatency == 0)
2661 		framesPerLatency = MakeFramesFromHns(pInfo->DefaultDevicePeriod, pSub->wavex.Format.nSamplesPerSec);
2662 
2663 	// Exclusive Input stream renders data in 6 packets, we must set then the size of
2664 	// single packet, total buffer size, e.g. required latency will be PacketSize * 6
2665 	if (!output && (pSub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE))
2666 	{
2667 		// Do it only for Polling mode
2668 		if ((pSub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) == 0)
2669 		{
2670 			framesPerLatency /= WASAPI_PACKETS_PER_INPUT_BUFFER;
2671 		}
2672 	}
2673 
2674 	// Calculate aligned period
2675 	_CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_BWD);
2676 
2677 	/*! Enforce min/max period for device in Shared mode to avoid bad audio quality.
2678         Avoid doing so for Exclusive mode as alignment will suffer.
2679 	*/
2680 	if (pSub->shareMode == AUDCLNT_SHAREMODE_SHARED)
2681 	{
2682 		if (pSub->period < pInfo->DefaultDevicePeriod)
2683 		{
2684 			pSub->period = pInfo->DefaultDevicePeriod;
2685 			// Recalculate aligned period
2686 			framesPerLatency = MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec);
2687 			_CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_BWD);
2688 		}
2689 	}
2690 	else
2691 	{
2692 		if (pSub->period < pInfo->MinimumDevicePeriod)
2693 		{
2694 			pSub->period = pInfo->MinimumDevicePeriod;
2695 			// Recalculate aligned period
2696 			framesPerLatency = MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec);
2697 			_CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_FWD);
2698 		}
2699 	}
2700 
2701 	/*! Windows 7 does not allow to set latency lower than minimal device period and will
2702 	    return error: AUDCLNT_E_INVALID_DEVICE_PERIOD. Under Vista we enforce the same behavior
2703 	    manually for unified behavior on all platforms.
2704 	*/
2705 	{
2706 		/*!	AUDCLNT_E_BUFFER_SIZE_ERROR: Applies to Windows 7 and later.
2707 			Indicates that the buffer duration value requested by an exclusive-mode client is
2708 			out of range. The requested duration value for pull mode must not be greater than
2709 			500 milliseconds; for push mode the duration value must not be greater than 2 seconds.
2710 		*/
2711 		if (pSub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)
2712 		{
2713 			static const REFERENCE_TIME MAX_BUFFER_EVENT_DURATION = 500  * 10000;
2714 			static const REFERENCE_TIME MAX_BUFFER_POLL_DURATION  = 2000 * 10000;
2715 
2716 			if (pSub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)	// pull mode, max 500ms
2717 			{
2718 				if (pSub->period > MAX_BUFFER_EVENT_DURATION)
2719 				{
2720 					pSub->period = MAX_BUFFER_EVENT_DURATION;
2721 					// Recalculate aligned period
2722 					framesPerLatency = MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec);
2723 					_CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_BWD);
2724 				}
2725 			}
2726 			else														// push mode, max 2000ms
2727 			{
2728 				if (pSub->period > MAX_BUFFER_POLL_DURATION)
2729 				{
2730 					pSub->period = MAX_BUFFER_POLL_DURATION;
2731 					// Recalculate aligned period
2732 					framesPerLatency = MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec);
2733 					_CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_BWD);
2734 				}
2735 			}
2736 		}
2737 	}
2738 
2739 	// Set Raw mode (applicable only to IAudioClient2)
2740 #ifdef __IAudioClient2_INTERFACE_DEFINED__
2741 	if (GetAudioClientVersion() >= 2)
2742 	{
2743 		pa_AudioClientProperties audioProps = { 0 };
2744 		audioProps.cbSize     = sizeof(pa_AudioClientProperties);
2745 		audioProps.bIsOffload = FALSE;
2746 		audioProps.eCategory  = (AUDIO_STREAM_CATEGORY)pSub->params.wasapi_params.streamCategory;
2747 		switch (pSub->params.wasapi_params.streamOption)
2748 		{
2749 		case eStreamOptionRaw:
2750 			if (GetWindowsVersion() >= WINDOWS_8_1_SERVER2012R2)
2751 				audioProps.Options = pa_AUDCLNT_STREAMOPTIONS_RAW;
2752 			break;
2753 		case eStreamOptionMatchFormat:
2754 			if (GetWindowsVersion() >= WINDOWS_10_SERVER2016)
2755 				audioProps.Options = pa_AUDCLNT_STREAMOPTIONS_MATCH_FORMAT;
2756 			break;
2757 		}
2758 
2759 		hr = IAudioClient2_SetClientProperties((IAudioClient2 *)audioClient, (AudioClientProperties *)&audioProps);
2760 		if (hr != S_OK)
2761 		{
2762 			PRINT(("WASAPI: IAudioClient2_SetClientProperties(Category = %d, Options = %d) failed with error = %08X\n", audioProps.eCategory, audioProps.Options, (UINT32)hr));
2763 		}
2764 		else
2765 		{
2766 			PRINT(("WASAPI: IAudioClient2 set properties: IsOffload = %d, Category = %d, Options = %d\n", audioProps.bIsOffload, audioProps.eCategory, audioProps.Options));
2767 		}
2768 	}
2769 #endif
2770 
2771 	// Open the stream and associate it with an audio session
2772     hr = IAudioClient_Initialize(audioClient,
2773         pSub->shareMode,
2774         pSub->streamFlags,
2775 		pSub->period,
2776 		(pSub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE ? pSub->period : 0),
2777 		&pSub->wavex.Format,
2778         NULL);
2779 
2780 	/*! WASAPI is tricky on large device buffer, sometimes 2000ms can be allocated sometimes
2781 	    less. There is no known guaranteed level thus we make subsequent tries by decreasing
2782 		buffer by 100ms per try.
2783 	*/
2784 	while ((hr == E_OUTOFMEMORY) && (pSub->period > (100 * 10000)))
2785 	{
2786 		PRINT(("WASAPI: CreateAudioClient: decreasing buffer size to %d milliseconds\n", (pSub->period / 10000)));
2787 
2788 		// Decrease by 100ms and try again
2789 		pSub->period -= (100 * 10000);
2790 
2791 		// Recalculate aligned period
2792 		framesPerLatency = MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec);
2793 		_CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_BWD);
2794 
2795         // Release the previous allocations
2796         SAFE_RELEASE(audioClient);
2797 
2798         // Create a new audio client
2799         hr = ActivateAudioInterface(pInfo, &audioClient);
2800     	if (hr != S_OK)
2801 		{
2802 			(*pa_error) = paInsufficientMemory;
2803 			LogHostError(hr);
2804 			goto done;
2805 		}
2806 
2807 		// Open the stream and associate it with an audio session
2808 		hr = IAudioClient_Initialize(audioClient,
2809 			pSub->shareMode,
2810 			pSub->streamFlags,
2811 			pSub->period,
2812 			(pSub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE ? pSub->period : 0),
2813 			&pSub->wavex.Format,
2814 			NULL);
2815 	}
2816 
2817 	/*! WASAPI buffer size failure. Fallback to using default size.
2818 	*/
2819 	if (hr == AUDCLNT_E_BUFFER_SIZE_ERROR)
2820 	{
2821 		// Use default
2822 		pSub->period = pInfo->DefaultDevicePeriod;
2823 
2824 		PRINT(("WASAPI: CreateAudioClient: correcting buffer size to device default\n"));
2825 
2826         // Release the previous allocations
2827         SAFE_RELEASE(audioClient);
2828 
2829         // Create a new audio client
2830         hr = ActivateAudioInterface(pInfo, &audioClient);
2831     	if (hr != S_OK)
2832 		{
2833 			(*pa_error) = paInsufficientMemory;
2834 			LogHostError(hr);
2835 			goto done;
2836 		}
2837 
2838 		// Open the stream and associate it with an audio session
2839 		hr = IAudioClient_Initialize(audioClient,
2840 			pSub->shareMode,
2841 			pSub->streamFlags,
2842 			pSub->period,
2843 			(pSub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE ? pSub->period : 0),
2844 			&pSub->wavex.Format,
2845 			NULL);
2846 	}
2847 
2848     /*! If the requested buffer size is not aligned. Can be triggered by Windows 7 and up.
2849 	    Should not be be triggered ever as we do align buffers always with _CalculateAlignedPeriod.
2850 	*/
2851     if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED)
2852     {
2853 		UINT32 frames = 0;
2854 
2855         // Get the next aligned frame
2856         hr = IAudioClient_GetBufferSize(audioClient, &frames);
2857 		if (hr != S_OK)
2858 		{
2859 			(*pa_error) = paInvalidDevice;
2860 			LogHostError(hr);
2861 			goto done;
2862 		}
2863 
2864 		PRINT(("WASAPI: CreateAudioClient: aligning buffer size to % frames\n", frames));
2865 
2866         // Release the previous allocations
2867         SAFE_RELEASE(audioClient);
2868 
2869         // Create a new audio client
2870         hr = ActivateAudioInterface(pInfo, &audioClient);
2871     	if (hr != S_OK)
2872 		{
2873 			(*pa_error) = paInsufficientMemory;
2874 			LogHostError(hr);
2875 			goto done;
2876 		}
2877 
2878 		// Get closest format
2879 		if ((error = GetClosestFormat(audioClient, sampleRate, params, pSub->shareMode, &pSub->wavex, output)) != paFormatIsSupported)
2880 		{
2881 			(*pa_error) = error;
2882 			LogHostError(hr = AUDCLNT_E_UNSUPPORTED_FORMAT); // fail, format not supported
2883 			goto done;
2884 		}
2885 
2886 		// Check for Mono >> Stereo workaround
2887 		if ((params->channelCount == 1) && (pSub->wavex.Format.nChannels == 2))
2888 		{
2889 			/*if (blocking)
2890 			{
2891 				LogHostError(hr = AUDCLNT_E_UNSUPPORTED_FORMAT);
2892 				goto done; // fail, blocking mode not supported
2893 			}*/
2894 
2895 			// Select mixer
2896 			pSub->monoMixer = _GetMonoToStereoMixer(WaveToPaFormat(&pSub->wavex), (pInfo->flow == eRender ? MIX_DIR__1TO2 : MIX_DIR__2TO1_L));
2897 			if (pSub->monoMixer == NULL)
2898 			{
2899 				(*pa_error) = paInvalidChannelCount;
2900 				LogHostError(hr = AUDCLNT_E_UNSUPPORTED_FORMAT);
2901 				goto done; // fail, no mixer for format
2902 			}
2903 		}
2904 
2905 		// Calculate period
2906 		pSub->period = MakeHnsPeriod(frames, pSub->wavex.Format.nSamplesPerSec);
2907 
2908         // Open the stream and associate it with an audio session
2909         hr = IAudioClient_Initialize(audioClient,
2910             pSub->shareMode,
2911             pSub->streamFlags,
2912 			pSub->period,
2913 			(pSub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE ? pSub->period : 0),
2914             &pSub->wavex.Format,
2915             NULL);
2916     	if (hr != S_OK)
2917 		{
2918 			(*pa_error) = paInvalidDevice;
2919 			LogHostError(hr);
2920 			goto done;
2921 		}
2922     }
2923     else
2924 	if (hr != S_OK)
2925     {
2926 		(*pa_error) = paInvalidDevice;
2927 		LogHostError(hr);
2928 		goto done;
2929     }
2930 
2931     // Set client
2932 	pSub->clientParent = audioClient;
2933     IAudioClient_AddRef(pSub->clientParent);
2934 
2935 	// Recalculate buffers count
2936 	_RecalculateBuffersCount(pSub,
2937 		userFramesPerBuffer,
2938 		MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec),
2939 		fullDuplex);
2940 
2941 	// No error, client is succesfully created
2942 	(*pa_error) = paNoError;
2943 
2944 done:
2945 
2946     // Clean up
2947     SAFE_RELEASE(audioClient);
2948     return hr;
2949 }
2950 
2951 // ------------------------------------------------------------------------------------------
ActivateAudioClientOutput(PaWasapiStream * stream)2952 static PaError ActivateAudioClientOutput(PaWasapiStream *stream)
2953 {
2954 	HRESULT hr;
2955 	PaError result;
2956 
2957 	UINT32 maxBufferSize   = 0;
2958 	PaTime buffer_latency  = 0;
2959 	UINT32 framesPerBuffer = stream->out.params.frames_per_buffer;
2960 
2961 	// Create Audio client
2962 	hr = CreateAudioClient(stream, &stream->out, TRUE, &result);
2963     if (hr != S_OK)
2964 	{
2965 		LogPaError(result);
2966 		goto error;
2967     }
2968 	LogWAVEFORMATEXTENSIBLE(&stream->out.wavex);
2969 
2970 	// Activate volume
2971 	stream->outVol = NULL;
2972     /*hr = info->device->Activate(
2973         __uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL,
2974         (void**)&stream->outVol);
2975     if (hr != S_OK)
2976         return paInvalidDevice;*/
2977 
2978     // Get max possible buffer size to check if it is not less than that we request
2979     hr = IAudioClient_GetBufferSize(stream->out.clientParent, &maxBufferSize);
2980     if (hr != S_OK)
2981 	{
2982 		LogHostError(hr);
2983 		LogPaError(result = paInvalidDevice);
2984 		goto error;
2985 	}
2986 
2987     // Correct buffer to max size if it maxed out result of GetBufferSize
2988 	stream->out.bufferSize = maxBufferSize;
2989 
2990 	// Get interface latency (actually uneeded as we calculate latency from the size
2991 	// of maxBufferSize).
2992     hr = IAudioClient_GetStreamLatency(stream->out.clientParent, &stream->out.deviceLatency);
2993     if (hr != S_OK)
2994 	{
2995 		LogHostError(hr);
2996 		LogPaError(result = paInvalidDevice);
2997 		goto error;
2998 	}
2999 	//stream->out.latencySeconds = nano100ToSeconds(stream->out.deviceLatency);
3000 
3001     // Number of frames that are required at each period
3002 	stream->out.framesPerHostCallback = maxBufferSize;
3003 
3004 	// Calculate frames per single buffer, if buffers > 1 then always framesPerBuffer
3005 	stream->out.framesPerBuffer =
3006 		(stream->out.userBufferAndHostMatch ? stream->out.framesPerHostCallback : framesPerBuffer);
3007 
3008 	// Calculate buffer latency
3009 	buffer_latency = (PaTime)maxBufferSize / stream->out.wavex.Format.nSamplesPerSec;
3010 
3011 	// Append buffer latency to interface latency in shared mode (see GetStreamLatency notes)
3012 	stream->out.latencySeconds = buffer_latency;
3013 
3014 	PRINT(("WASAPI::OpenStream(output): framesPerUser[ %d ] framesPerHost[ %d ] latency[ %.02fms ] exclusive[ %s ] wow64_fix[ %s ] mode[ %s ]\n", (UINT32)framesPerBuffer, (UINT32)stream->out.framesPerHostCallback, (float)(stream->out.latencySeconds*1000.0f), (stream->out.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE ? "YES" : "NO"), (stream->out.params.wow64_workaround ? "YES" : "NO"), (stream->out.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK ? "EVENT" : "POLL")));
3015 
3016 	return paNoError;
3017 
3018 error:
3019 
3020 	return result;
3021 }
3022 
3023 // ------------------------------------------------------------------------------------------
ActivateAudioClientInput(PaWasapiStream * stream)3024 static PaError ActivateAudioClientInput(PaWasapiStream *stream)
3025 {
3026 	HRESULT hr;
3027 	PaError result;
3028 
3029 	UINT32 maxBufferSize   = 0;
3030 	PaTime buffer_latency  = 0;
3031 	UINT32 framesPerBuffer = stream->in.params.frames_per_buffer;
3032 
3033 	// Create Audio client
3034 	hr = CreateAudioClient(stream, &stream->in, FALSE, &result);
3035     if (hr != S_OK)
3036 	{
3037 		LogPaError(result);
3038 		goto error;
3039     }
3040 	LogWAVEFORMATEXTENSIBLE(&stream->in.wavex);
3041 
3042 	// Create volume mgr
3043 	stream->inVol = NULL;
3044     /*hr = info->device->Activate(
3045         __uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL,
3046         (void**)&stream->inVol);
3047     if (hr != S_OK)
3048         return paInvalidDevice;*/
3049 
3050     // Get max possible buffer size to check if it is not less than that we request
3051     hr = IAudioClient_GetBufferSize(stream->in.clientParent, &maxBufferSize);
3052     if (hr != S_OK)
3053 	{
3054 		LogHostError(hr);
3055 		LogPaError(result = paInvalidDevice);
3056 		goto error;
3057 	}
3058 
3059     // Correct buffer to max size if it maxed out result of GetBufferSize
3060 	stream->in.bufferSize = maxBufferSize;
3061 
3062 	// Get interface latency (actually uneeded as we calculate latency from the size
3063 	// of maxBufferSize).
3064     hr = IAudioClient_GetStreamLatency(stream->in.clientParent, &stream->in.deviceLatency);
3065     if (hr != S_OK)
3066 	{
3067 		LogHostError(hr);
3068 		LogPaError(result = paInvalidDevice);
3069 		goto error;
3070 	}
3071 	//stream->in.latencySeconds = nano100ToSeconds(stream->in.deviceLatency);
3072 
3073     // Number of frames that are required at each period
3074 	stream->in.framesPerHostCallback = maxBufferSize;
3075 
3076 	// Calculate frames per single buffer, if buffers > 1 then always framesPerBuffer
3077 	stream->in.framesPerBuffer =
3078 		(stream->in.userBufferAndHostMatch ? stream->in.framesPerHostCallback : framesPerBuffer);
3079 
3080 	// Calculate buffer latency
3081 	buffer_latency = (PaTime)maxBufferSize / stream->in.wavex.Format.nSamplesPerSec;
3082 
3083 	// Append buffer latency to interface latency in shared mode (see GetStreamLatency notes)
3084 	stream->in.latencySeconds = buffer_latency;
3085 
3086 	PRINT(("WASAPI::OpenStream(input): framesPerUser[ %d ] framesPerHost[ %d ] latency[ %.02fms ] exclusive[ %s ] wow64_fix[ %s ] mode[ %s ]\n", (UINT32)framesPerBuffer, (UINT32)stream->in.framesPerHostCallback, (float)(stream->in.latencySeconds*1000.0f), (stream->in.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE ? "YES" : "NO"), (stream->in.params.wow64_workaround ? "YES" : "NO"), (stream->in.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK ? "EVENT" : "POLL")));
3087 
3088 	return paNoError;
3089 
3090 error:
3091 
3092 	return result;
3093 }
3094 
3095 // ------------------------------------------------------------------------------------------
OpenStream(struct PaUtilHostApiRepresentation * hostApi,PaStream ** s,const PaStreamParameters * inputParameters,const PaStreamParameters * outputParameters,double sampleRate,unsigned long framesPerBuffer,PaStreamFlags streamFlags,PaStreamCallback * streamCallback,void * userData)3096 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
3097                            PaStream** s,
3098                            const PaStreamParameters *inputParameters,
3099                            const PaStreamParameters *outputParameters,
3100                            double sampleRate,
3101                            unsigned long framesPerBuffer,
3102                            PaStreamFlags streamFlags,
3103                            PaStreamCallback *streamCallback,
3104                            void *userData )
3105 {
3106     PaError result = paNoError;
3107 	HRESULT hr;
3108     PaWasapiHostApiRepresentation *paWasapi = (PaWasapiHostApiRepresentation*)hostApi;
3109     PaWasapiStream *stream = NULL;
3110     int inputChannelCount, outputChannelCount;
3111     PaSampleFormat inputSampleFormat, outputSampleFormat;
3112     PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
3113 	PaWasapiStreamInfo *inputStreamInfo = NULL, *outputStreamInfo = NULL;
3114 	PaWasapiDeviceInfo *info = NULL;
3115 	ULONG framesPerHostCallback;
3116 	PaUtilHostBufferSizeMode bufferMode;
3117 	const BOOL fullDuplex = ((inputParameters != NULL) && (outputParameters != NULL));
3118 
3119 	// validate PaStreamParameters
3120 	if ((result = IsStreamParamsValid(hostApi, inputParameters, outputParameters, sampleRate)) != paNoError)
3121 		return LogPaError(result);
3122 
3123     // Validate platform specific flags
3124     if ((streamFlags & paPlatformSpecificFlags) != 0)
3125 	{
3126 		LogPaError(result = paInvalidFlag); /* unexpected platform specific flag */
3127 		goto error;
3128 	}
3129 
3130 	// Allocate memory for PaWasapiStream
3131     if ((stream = (PaWasapiStream *)PaUtil_AllocateMemory(sizeof(PaWasapiStream))) == NULL)
3132 	{
3133         LogPaError(result = paInsufficientMemory);
3134         goto error;
3135     }
3136 
3137 	// Default thread priority is Audio: for exclusive mode we will use Pro Audio.
3138 	stream->nThreadPriority = eThreadPriorityAudio;
3139 
3140 	// Set default number of frames: paFramesPerBufferUnspecified
3141 	if (framesPerBuffer == paFramesPerBufferUnspecified)
3142 	{
3143 		UINT32 framesPerBufferIn  = 0, framesPerBufferOut = 0;
3144 		if (inputParameters != NULL)
3145 		{
3146 			info = &paWasapi->devInfo[inputParameters->device];
3147 			framesPerBufferIn = MakeFramesFromHns(info->DefaultDevicePeriod, (UINT32)sampleRate);
3148 		}
3149 		if (outputParameters != NULL)
3150 		{
3151 			info = &paWasapi->devInfo[outputParameters->device];
3152 			framesPerBufferOut = MakeFramesFromHns(info->DefaultDevicePeriod, (UINT32)sampleRate);
3153 		}
3154 		// choosing maximum default size
3155 		framesPerBuffer = max(framesPerBufferIn, framesPerBufferOut);
3156 	}
3157 	if (framesPerBuffer == 0)
3158 		framesPerBuffer = ((UINT32)sampleRate / 100) * 2;
3159 
3160 	// Try create device: Input
3161 	if (inputParameters != NULL)
3162     {
3163         inputChannelCount = inputParameters->channelCount;
3164         inputSampleFormat = inputParameters->sampleFormat;
3165         info              = &paWasapi->devInfo[inputParameters->device];
3166 
3167 		// default Shared Mode
3168 		stream->in.shareMode = AUDCLNT_SHAREMODE_SHARED;
3169 
3170 		// PaWasapiStreamInfo
3171 		if (inputParameters->hostApiSpecificStreamInfo != NULL)
3172 		{
3173 			memcpy(&stream->in.params.wasapi_params, inputParameters->hostApiSpecificStreamInfo, min(sizeof(stream->in.params.wasapi_params), ((PaWasapiStreamInfo *)inputParameters->hostApiSpecificStreamInfo)->size));
3174 			stream->in.params.wasapi_params.size = sizeof(stream->in.params.wasapi_params);
3175 
3176 			stream->in.params.stream_params.hostApiSpecificStreamInfo = &stream->in.params.wasapi_params;
3177 			inputStreamInfo = &stream->in.params.wasapi_params;
3178 
3179 			stream->in.flags = inputStreamInfo->flags;
3180 
3181 			// Exclusive Mode
3182 			if (inputStreamInfo->flags & paWinWasapiExclusive)
3183 			{
3184 				// Boost thread priority
3185 				stream->nThreadPriority = eThreadPriorityProAudio;
3186 				// Make Exclusive
3187 				stream->in.shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;
3188 			}
3189 
3190 			// explicit thread priority level
3191 			if (inputStreamInfo->flags & paWinWasapiThreadPriority)
3192 			{
3193 				if ((inputStreamInfo->threadPriority > eThreadPriorityNone) &&
3194 					(inputStreamInfo->threadPriority <= eThreadPriorityWindowManager))
3195 					stream->nThreadPriority = inputStreamInfo->threadPriority;
3196 			}
3197 		}
3198 
3199 		// Choose processing mode
3200 		stream->in.streamFlags = (stream->in.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE ? AUDCLNT_STREAMFLAGS_EVENTCALLBACK : 0);
3201 		if (paWasapi->useWOW64Workaround)
3202 			stream->in.streamFlags = 0; // polling interface
3203 		else
3204 		if (streamCallback == NULL)
3205 			stream->in.streamFlags = 0; // polling interface
3206 		else
3207 		if ((inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiPolling))
3208 			stream->in.streamFlags = 0; // polling interface
3209 		else
3210 		if (fullDuplex)
3211 			stream->in.streamFlags = 0; // polling interface is implemented for full-duplex mode also
3212 
3213 		// Fill parameters for Audio Client creation
3214 		stream->in.params.device_info       = info;
3215 		stream->in.params.stream_params     = (*inputParameters);
3216 		stream->in.params.frames_per_buffer = framesPerBuffer;
3217 		stream->in.params.sample_rate       = sampleRate;
3218 		stream->in.params.blocking          = (streamCallback == NULL);
3219 		stream->in.params.full_duplex       = fullDuplex;
3220 		stream->in.params.wow64_workaround  = paWasapi->useWOW64Workaround;
3221 
3222 		// Create and activate audio client
3223 		hr = ActivateAudioClientInput(stream);
3224         if (hr != S_OK)
3225 		{
3226 			LogPaError(result = paInvalidDevice);
3227 			goto error;
3228         }
3229 
3230 		// Get closest format
3231         hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( WaveToPaFormat(&stream->in.wavex), inputSampleFormat );
3232 
3233         // Set user-side custom host processor
3234         if ((inputStreamInfo != NULL) &&
3235             (inputStreamInfo->flags & paWinWasapiRedirectHostProcessor))
3236         {
3237             stream->hostProcessOverrideInput.processor = inputStreamInfo->hostProcessorInput;
3238             stream->hostProcessOverrideInput.userData = userData;
3239         }
3240 
3241 		// Only get IAudioCaptureClient input once here instead of getting it at multiple places based on the use
3242 		hr = IAudioClient_GetService(stream->in.clientParent, &pa_IID_IAudioCaptureClient, (void **)&stream->captureClientParent);
3243 		if (hr != S_OK)
3244 		{
3245 			LogHostError(hr);
3246 			LogPaError(result = paUnanticipatedHostError);
3247 			goto error;
3248 		}
3249 
3250 		// Create ring buffer for blocking mode (It is needed because we fetch Input packets, not frames,
3251 		// and thus we have to save partial packet if such remains unread)
3252 		if (stream->in.params.blocking == TRUE)
3253 		{
3254 			UINT32 bufferFrames = ALIGN_NEXT_POW2((stream->in.framesPerHostCallback / WASAPI_PACKETS_PER_INPUT_BUFFER) * 2);
3255 			UINT32 frameSize    = stream->in.wavex.Format.nBlockAlign;
3256 
3257 			// buffer
3258 			if ((stream->in.tailBuffer = PaUtil_AllocateMemory(sizeof(PaUtilRingBuffer))) == NULL)
3259 			{
3260 				LogPaError(result = paInsufficientMemory);
3261 				goto error;
3262 			}
3263 			memset(stream->in.tailBuffer, 0, sizeof(PaUtilRingBuffer));
3264 
3265 			// buffer memory region
3266 			stream->in.tailBufferMemory = PaUtil_AllocateMemory(frameSize * bufferFrames);
3267 			if (stream->in.tailBufferMemory == NULL)
3268 			{
3269 				LogPaError(result = paInsufficientMemory);
3270 				goto error;
3271 			}
3272 
3273 			// initialize
3274 			if (PaUtil_InitializeRingBuffer(stream->in.tailBuffer, frameSize, bufferFrames,	stream->in.tailBufferMemory) != 0)
3275 			{
3276 				LogPaError(result = paInternalError);
3277 				goto error;
3278 			}
3279 		}
3280 	}
3281     else
3282     {
3283         inputChannelCount = 0;
3284         inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */
3285     }
3286 
3287 	// Try create device: Output
3288     if (outputParameters != NULL)
3289     {
3290         outputChannelCount = outputParameters->channelCount;
3291         outputSampleFormat = outputParameters->sampleFormat;
3292 		info               = &paWasapi->devInfo[outputParameters->device];
3293 
3294 		// default Shared Mode
3295 		stream->out.shareMode = AUDCLNT_SHAREMODE_SHARED;
3296 
3297 		// set PaWasapiStreamInfo
3298 		if (outputParameters->hostApiSpecificStreamInfo != NULL)
3299 		{
3300 			memcpy(&stream->out.params.wasapi_params, outputParameters->hostApiSpecificStreamInfo, min(sizeof(stream->out.params.wasapi_params), ((PaWasapiStreamInfo *)outputParameters->hostApiSpecificStreamInfo)->size));
3301 			stream->out.params.wasapi_params.size = sizeof(stream->out.params.wasapi_params);
3302 
3303 			stream->out.params.stream_params.hostApiSpecificStreamInfo = &stream->out.params.wasapi_params;
3304 			outputStreamInfo = &stream->out.params.wasapi_params;
3305 
3306 			stream->out.flags = outputStreamInfo->flags;
3307 
3308 			// Exclusive Mode
3309 			if (outputStreamInfo->flags & paWinWasapiExclusive)
3310 			{
3311 				// Boost thread priority
3312 				stream->nThreadPriority = eThreadPriorityProAudio;
3313 				// Make Exclusive
3314 				stream->out.shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;
3315 			}
3316 
3317 			// explicit thread priority level
3318 			if (outputStreamInfo->flags & paWinWasapiThreadPriority)
3319 			{
3320 				if ((outputStreamInfo->threadPriority > eThreadPriorityNone) &&
3321 					(outputStreamInfo->threadPriority <= eThreadPriorityWindowManager))
3322 					stream->nThreadPriority = outputStreamInfo->threadPriority;
3323 			}
3324 		}
3325 
3326 		// Choose processing mode
3327 		stream->out.streamFlags = (stream->out.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE ? AUDCLNT_STREAMFLAGS_EVENTCALLBACK : 0);
3328 		if (paWasapi->useWOW64Workaround)
3329 			stream->out.streamFlags = 0; // polling interface
3330 		else
3331 		if (streamCallback == NULL)
3332 			stream->out.streamFlags = 0; // polling interface
3333 		else
3334 		if ((outputStreamInfo != NULL) && (outputStreamInfo->flags & paWinWasapiPolling))
3335 			stream->out.streamFlags = 0; // polling interface
3336 		else
3337 		if (fullDuplex)
3338 			stream->out.streamFlags = 0; // polling interface is implemented for full-duplex mode also
3339 
3340 		// Fill parameters for Audio Client creation
3341 		stream->out.params.device_info       = info;
3342 		stream->out.params.stream_params     = (*outputParameters);
3343 		stream->out.params.frames_per_buffer = framesPerBuffer;
3344 		stream->out.params.sample_rate       = sampleRate;
3345 		stream->out.params.blocking          = (streamCallback == NULL);
3346 		stream->out.params.full_duplex       = fullDuplex;
3347 		stream->out.params.wow64_workaround  = paWasapi->useWOW64Workaround;
3348 
3349 		// Create and activate audio client
3350 		hr = ActivateAudioClientOutput(stream);
3351         if (hr != S_OK)
3352 		{
3353 			LogPaError(result = paInvalidDevice);
3354 			goto error;
3355         }
3356 
3357 		// Get closest format
3358         hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( WaveToPaFormat(&stream->out.wavex), outputSampleFormat );
3359 
3360         // Set user-side custom host processor
3361         if ((outputStreamInfo != NULL) &&
3362             (outputStreamInfo->flags & paWinWasapiRedirectHostProcessor))
3363         {
3364             stream->hostProcessOverrideOutput.processor = outputStreamInfo->hostProcessorOutput;
3365             stream->hostProcessOverrideOutput.userData = userData;
3366         }
3367 
3368 		// Only get IAudioCaptureClient output once here instead of getting it at multiple places based on the use
3369 		hr = IAudioClient_GetService(stream->out.clientParent, &pa_IID_IAudioRenderClient, (void **)&stream->renderClientParent);
3370 		if (hr != S_OK)
3371 		{
3372 			LogHostError(hr);
3373 			LogPaError(result = paUnanticipatedHostError);
3374 			goto error;
3375 		}
3376 	}
3377     else
3378     {
3379         outputChannelCount = 0;
3380         outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */
3381     }
3382 
3383 	// log full-duplex
3384 	if (fullDuplex)
3385 		PRINT(("WASAPI::OpenStream: full-duplex mode\n"));
3386 
3387 	// paWinWasapiPolling must be on/or not on both streams
3388 	if ((inputParameters != NULL) && (outputParameters != NULL))
3389 	{
3390 		if ((inputStreamInfo != NULL) && (outputStreamInfo != NULL))
3391 		{
3392 			if (((inputStreamInfo->flags & paWinWasapiPolling) &&
3393 				!(outputStreamInfo->flags & paWinWasapiPolling))
3394 				||
3395 				(!(inputStreamInfo->flags & paWinWasapiPolling) &&
3396 				 (outputStreamInfo->flags & paWinWasapiPolling)))
3397 			{
3398 				LogPaError(result = paInvalidFlag);
3399 				goto error;
3400 			}
3401 		}
3402 	}
3403 
3404 	// Initialize stream representation
3405     if (streamCallback)
3406     {
3407 		stream->bBlocking = FALSE;
3408         PaUtil_InitializeStreamRepresentation(&stream->streamRepresentation,
3409                                               &paWasapi->callbackStreamInterface,
3410 											  streamCallback, userData);
3411     }
3412     else
3413     {
3414 		stream->bBlocking = TRUE;
3415         PaUtil_InitializeStreamRepresentation(&stream->streamRepresentation,
3416                                               &paWasapi->blockingStreamInterface,
3417 											  streamCallback, userData);
3418     }
3419 
3420 	// Initialize CPU measurer
3421     PaUtil_InitializeCpuLoadMeasurer(&stream->cpuLoadMeasurer, sampleRate);
3422 
3423 	if (outputParameters && inputParameters)
3424 	{
3425 		// serious problem #1 - No, Not a problem, especially concerning Exclusive mode.
3426 		// Input device in exclusive mode somehow is getting large buffer always, thus we
3427 		// adjust Output latency to reflect it, thus period will differ but playback will be
3428 		// normal.
3429 		/*if (stream->in.period != stream->out.period)
3430 		{
3431 			PRINT(("WASAPI: OpenStream: period discrepancy\n"));
3432 			LogPaError(result = paBadIODeviceCombination);
3433 			goto error;
3434 		}*/
3435 
3436 		// serious problem #2 - No, Not a problem, as framesPerHostCallback take into account
3437 		// sample size while it is not a problem for PA full-duplex, we must care of
3438 		// preriod only!
3439 		/*if (stream->out.framesPerHostCallback != stream->in.framesPerHostCallback)
3440 		{
3441 			PRINT(("WASAPI: OpenStream: framesPerHostCallback discrepancy\n"));
3442 			goto error;
3443 		}*/
3444 	}
3445 
3446 	// Calculate frames per host for processor
3447 	framesPerHostCallback = (outputParameters ? stream->out.framesPerBuffer : stream->in.framesPerBuffer);
3448 
3449 	// Choose correct mode of buffer processing:
3450 	// Exclusive/Shared non paWinWasapiPolling mode: paUtilFixedHostBufferSize - always fixed
3451 	// Exclusive/Shared paWinWasapiPolling mode: paUtilBoundedHostBufferSize - may vary for Exclusive or Full-duplex
3452 	bufferMode = paUtilFixedHostBufferSize;
3453 	if (inputParameters) // !!! WASAPI IAudioCaptureClient::GetBuffer extracts not number of frames but 1 packet, thus we always must adapt
3454 		bufferMode = paUtilBoundedHostBufferSize;
3455 	else
3456 	if (outputParameters)
3457 	{
3458 		if ((stream->out.buffers == 1) &&
3459 			(!stream->out.streamFlags || ((stream->out.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) == 0)))
3460 			bufferMode = paUtilBoundedHostBufferSize;
3461 	}
3462 	stream->bufferMode = bufferMode;
3463 
3464     // Initialize buffer processor
3465     result =  PaUtil_InitializeBufferProcessor(
3466 		&stream->bufferProcessor,
3467         inputChannelCount,
3468 		inputSampleFormat,
3469 		hostInputSampleFormat,
3470         outputChannelCount,
3471 		outputSampleFormat,
3472 		hostOutputSampleFormat,
3473         sampleRate,
3474 		streamFlags,
3475 		framesPerBuffer,
3476         framesPerHostCallback,
3477 		bufferMode,
3478         streamCallback,
3479 		userData);
3480     if (result != paNoError)
3481 	{
3482 		LogPaError(result);
3483         goto error;
3484 	}
3485 
3486 	// Set Input latency
3487     stream->streamRepresentation.streamInfo.inputLatency =
3488             ((double)PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor) / sampleRate)
3489 			+ ((inputParameters)?stream->in.latencySeconds : 0);
3490 
3491 	// Set Output latency
3492     stream->streamRepresentation.streamInfo.outputLatency =
3493             ((double)PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor) / sampleRate)
3494 			+ ((outputParameters)?stream->out.latencySeconds : 0);
3495 
3496 	// Set SR
3497     stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
3498 
3499     (*s) = (PaStream *)stream;
3500     return result;
3501 
3502 error:
3503 
3504     if (stream != NULL)
3505 		CloseStream(stream);
3506 
3507     return result;
3508 }
3509 
3510 // ------------------------------------------------------------------------------------------
CloseStream(PaStream * s)3511 static PaError CloseStream( PaStream* s )
3512 {
3513     PaError result = paNoError;
3514     PaWasapiStream *stream = (PaWasapiStream*)s;
3515 
3516 	// abort active stream
3517 	if (IsStreamActive(s))
3518 	{
3519 		result = AbortStream(s);
3520 	}
3521 
3522     SAFE_RELEASE(stream->captureClientParent);
3523     SAFE_RELEASE(stream->renderClientParent);
3524     SAFE_RELEASE(stream->out.clientParent);
3525     SAFE_RELEASE(stream->in.clientParent);
3526 	SAFE_RELEASE(stream->inVol);
3527 	SAFE_RELEASE(stream->outVol);
3528 
3529 	CloseHandle(stream->event[S_INPUT]);
3530 	CloseHandle(stream->event[S_OUTPUT]);
3531 
3532 	_StreamCleanup(stream);
3533 
3534 	PaWasapi_FreeMemory(stream->in.monoBuffer);
3535 	PaWasapi_FreeMemory(stream->out.monoBuffer);
3536 
3537 	PaUtil_FreeMemory(stream->in.tailBuffer);
3538 	PaUtil_FreeMemory(stream->in.tailBufferMemory);
3539 
3540 	PaUtil_FreeMemory(stream->out.tailBuffer);
3541 	PaUtil_FreeMemory(stream->out.tailBufferMemory);
3542 
3543     PaUtil_TerminateBufferProcessor(&stream->bufferProcessor);
3544     PaUtil_TerminateStreamRepresentation(&stream->streamRepresentation);
3545     PaUtil_FreeMemory(stream);
3546 
3547     return result;
3548 }
3549 
3550 // ------------------------------------------------------------------------------------------
UnmarshalSubStreamComPointers(PaWasapiSubStream * substream)3551 HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream)
3552 {
3553 #ifndef PA_WINRT
3554 	HRESULT hResult = S_OK;
3555 	HRESULT hFirstBadResult = S_OK;
3556 	substream->clientProc = NULL;
3557 
3558 	// IAudioClient
3559 	hResult = CoGetInterfaceAndReleaseStream(substream->clientStream, GetAudioClientIID(), (LPVOID*)&substream->clientProc);
3560 	substream->clientStream = NULL;
3561 	if (hResult != S_OK)
3562 	{
3563 		hFirstBadResult = (hFirstBadResult == S_OK) ? hResult : hFirstBadResult;
3564 	}
3565 
3566 	return hFirstBadResult;
3567 
3568 #else
3569 	(void)substream;
3570 	return S_OK;
3571 #endif
3572 }
3573 
3574 // ------------------------------------------------------------------------------------------
UnmarshalStreamComPointers(PaWasapiStream * stream)3575 HRESULT UnmarshalStreamComPointers(PaWasapiStream *stream)
3576 {
3577 #ifndef PA_WINRT
3578 	HRESULT hResult = S_OK;
3579 	HRESULT hFirstBadResult = S_OK;
3580 	stream->captureClient = NULL;
3581 	stream->renderClient = NULL;
3582 	stream->in.clientProc = NULL;
3583 	stream->out.clientProc = NULL;
3584 
3585 	if (NULL != stream->in.clientParent)
3586 	{
3587 		// SubStream pointers
3588 		hResult = UnmarshalSubStreamComPointers(&stream->in);
3589 		if (hResult != S_OK)
3590 		{
3591 			hFirstBadResult = (hFirstBadResult == S_OK) ? hResult : hFirstBadResult;
3592 		}
3593 
3594 		// IAudioCaptureClient
3595 		hResult = CoGetInterfaceAndReleaseStream(stream->captureClientStream, &pa_IID_IAudioCaptureClient, (LPVOID*)&stream->captureClient);
3596 		stream->captureClientStream = NULL;
3597 		if (hResult != S_OK)
3598 		{
3599 			hFirstBadResult = (hFirstBadResult == S_OK) ? hResult : hFirstBadResult;
3600 		}
3601 	}
3602 
3603 	if (NULL != stream->out.clientParent)
3604 	{
3605 		// SubStream pointers
3606 		hResult = UnmarshalSubStreamComPointers(&stream->out);
3607 		if (hResult != S_OK)
3608 		{
3609 			hFirstBadResult = (hFirstBadResult == S_OK) ? hResult : hFirstBadResult;
3610 		}
3611 
3612 		// IAudioRenderClient
3613 		hResult = CoGetInterfaceAndReleaseStream(stream->renderClientStream, &pa_IID_IAudioRenderClient, (LPVOID*)&stream->renderClient);
3614 		stream->renderClientStream = NULL;
3615 		if (hResult != S_OK)
3616 		{
3617 			hFirstBadResult = (hFirstBadResult == S_OK) ? hResult : hFirstBadResult;
3618 		}
3619 	}
3620 
3621 	return hFirstBadResult;
3622 #else
3623 	if (stream->in.clientParent != NULL)
3624 	{
3625 		stream->in.clientProc = stream->in.clientParent;
3626 		IAudioClient_AddRef(stream->in.clientParent);
3627 	}
3628 
3629 	if (stream->out.clientParent != NULL)
3630 	{
3631 		stream->out.clientProc = stream->out.clientParent;
3632 		IAudioClient_AddRef(stream->out.clientParent);
3633 	}
3634 
3635 	if (stream->renderClientParent != NULL)
3636 	{
3637 		stream->renderClient = stream->renderClientParent;
3638 		IAudioRenderClient_AddRef(stream->renderClientParent);
3639 	}
3640 
3641 	if (stream->captureClientParent != NULL)
3642 	{
3643 		stream->captureClient = stream->captureClientParent;
3644 		IAudioCaptureClient_AddRef(stream->captureClientParent);
3645 	}
3646 
3647 	return S_OK;
3648 #endif
3649 }
3650 
3651 // -----------------------------------------------------------------------------------------
ReleaseUnmarshaledSubComPointers(PaWasapiSubStream * substream)3652 void ReleaseUnmarshaledSubComPointers(PaWasapiSubStream *substream)
3653 {
3654 	SAFE_RELEASE(substream->clientProc);
3655 }
3656 
3657 // -----------------------------------------------------------------------------------------
ReleaseUnmarshaledComPointers(PaWasapiStream * stream)3658 void ReleaseUnmarshaledComPointers(PaWasapiStream *stream)
3659 {
3660 	// Release AudioClient services first
3661 	SAFE_RELEASE(stream->captureClient);
3662 	SAFE_RELEASE(stream->renderClient);
3663 
3664 	// Release AudioClients
3665 	ReleaseUnmarshaledSubComPointers(&stream->in);
3666 	ReleaseUnmarshaledSubComPointers(&stream->out);
3667 }
3668 
3669 // ------------------------------------------------------------------------------------------
MarshalSubStreamComPointers(PaWasapiSubStream * substream)3670 HRESULT MarshalSubStreamComPointers(PaWasapiSubStream *substream)
3671 {
3672 #ifndef PA_WINRT
3673 	HRESULT hResult;
3674 	substream->clientStream = NULL;
3675 
3676 	// IAudioClient
3677 	hResult = CoMarshalInterThreadInterfaceInStream(GetAudioClientIID(), (LPUNKNOWN)substream->clientParent, &substream->clientStream);
3678 	if (hResult != S_OK)
3679 		goto marshal_sub_error;
3680 
3681 	return hResult;
3682 
3683 	// If marshaling error occurred, make sure to release everything.
3684 marshal_sub_error:
3685 
3686 	UnmarshalSubStreamComPointers(substream);
3687 	ReleaseUnmarshaledSubComPointers(substream);
3688 	return hResult;
3689 #else
3690 	(void)substream;
3691 	return S_OK;
3692 #endif
3693 }
3694 
3695 // ------------------------------------------------------------------------------------------
MarshalStreamComPointers(PaWasapiStream * stream)3696 HRESULT MarshalStreamComPointers(PaWasapiStream *stream)
3697 {
3698 #ifndef PA_WINRT
3699 	HRESULT hResult = S_OK;
3700 	stream->captureClientStream = NULL;
3701 	stream->in.clientStream = NULL;
3702 	stream->renderClientStream = NULL;
3703 	stream->out.clientStream = NULL;
3704 
3705 	if (NULL != stream->in.clientParent)
3706 	{
3707 		// SubStream pointers
3708 		hResult = MarshalSubStreamComPointers(&stream->in);
3709 		if (hResult != S_OK)
3710 			goto marshal_error;
3711 
3712 		// IAudioCaptureClient
3713 		hResult = CoMarshalInterThreadInterfaceInStream(&pa_IID_IAudioCaptureClient, (LPUNKNOWN)stream->captureClientParent, &stream->captureClientStream);
3714 		if (hResult != S_OK)
3715 			goto marshal_error;
3716 	}
3717 
3718 	if (NULL != stream->out.clientParent)
3719 	{
3720 		// SubStream pointers
3721 		hResult = MarshalSubStreamComPointers(&stream->out);
3722 		if (hResult != S_OK)
3723 			goto marshal_error;
3724 
3725 		// IAudioRenderClient
3726 		hResult = CoMarshalInterThreadInterfaceInStream(&pa_IID_IAudioRenderClient, (LPUNKNOWN)stream->renderClientParent, &stream->renderClientStream);
3727 		if (hResult != S_OK)
3728 			goto marshal_error;
3729 	}
3730 
3731 	return hResult;
3732 
3733 	// If marshaling error occurred, make sure to release everything.
3734 marshal_error:
3735 
3736 	UnmarshalStreamComPointers(stream);
3737 	ReleaseUnmarshaledComPointers(stream);
3738 	return hResult;
3739 #else
3740 	(void)stream;
3741 	return S_OK;
3742 #endif
3743 }
3744 
3745 // ------------------------------------------------------------------------------------------
StartStream(PaStream * s)3746 static PaError StartStream( PaStream *s )
3747 {
3748 	HRESULT hr;
3749     PaWasapiStream *stream = (PaWasapiStream*)s;
3750 	PaError result = paNoError;
3751 
3752 	// check if stream is active already
3753 	if (IsStreamActive(s))
3754 		return paStreamIsNotStopped;
3755 
3756     PaUtil_ResetBufferProcessor(&stream->bufferProcessor);
3757 
3758 	// Cleanup handles (may be necessary if stream was stopped by itself due to error)
3759 	_StreamCleanup(stream);
3760 
3761 	// Create close event
3762 	if ((stream->hCloseRequest = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
3763 	{
3764 		result = paInsufficientMemory;
3765 		goto start_error;
3766 	}
3767 
3768 	// Create thread
3769 	if (!stream->bBlocking)
3770 	{
3771 		// Create thread events
3772 		stream->hThreadStart = CreateEvent(NULL, TRUE, FALSE, NULL);
3773 		stream->hThreadExit  = CreateEvent(NULL, TRUE, FALSE, NULL);
3774 		if ((stream->hThreadStart == NULL) || (stream->hThreadExit == NULL))
3775 		{
3776 			result = paInsufficientMemory;
3777 			goto start_error;
3778 		}
3779 
3780 		// Marshal WASAPI interface pointers for safe use in thread created below.
3781 		if ((hr = MarshalStreamComPointers(stream)) != S_OK)
3782 		{
3783 			PRINT(("Failed marshaling stream COM pointers."));
3784 			result = paUnanticipatedHostError;
3785 			goto nonblocking_start_error;
3786 		}
3787 
3788 		if ((stream->in.clientParent  && (stream->in.streamFlags  & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)) ||
3789 			(stream->out.clientParent && (stream->out.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)))
3790 		{
3791 			if ((stream->hThread = CREATE_THREAD(ProcThreadEvent)) == NULL)
3792 			{
3793 				PRINT(("Failed creating thread: ProcThreadEvent."));
3794 				result = paUnanticipatedHostError;
3795 				goto nonblocking_start_error;
3796 			}
3797 		}
3798 		else
3799 		{
3800 			if ((stream->hThread = CREATE_THREAD(ProcThreadPoll)) == NULL)
3801 			{
3802 				PRINT(("Failed creating thread: ProcThreadPoll."));
3803 				result = paUnanticipatedHostError;
3804 				goto nonblocking_start_error;
3805 			}
3806 		}
3807 
3808 		// Wait for thread to start
3809 		if (WaitForSingleObject(stream->hThreadStart, 60*1000) == WAIT_TIMEOUT)
3810 		{
3811 			PRINT(("Failed starting thread: timeout."));
3812 			result = paUnanticipatedHostError;
3813 			goto nonblocking_start_error;
3814 		}
3815 	}
3816 	else
3817 	{
3818 		// Create blocking operation events (non-signaled event means - blocking operation is pending)
3819 		if (stream->out.clientParent != NULL)
3820 		{
3821 			if ((stream->hBlockingOpStreamWR = CreateEvent(NULL, TRUE, TRUE, NULL)) == NULL)
3822 			{
3823 				result = paInsufficientMemory;
3824 				goto start_error;
3825 			}
3826 		}
3827 		if (stream->in.clientParent != NULL)
3828 		{
3829 			if ((stream->hBlockingOpStreamRD = CreateEvent(NULL, TRUE, TRUE, NULL)) == NULL)
3830 			{
3831 				result = paInsufficientMemory;
3832 				goto start_error;
3833 			}
3834 		}
3835 
3836 		// Initialize event & start INPUT stream
3837 		if (stream->in.clientParent != NULL)
3838 		{
3839 			if ((hr = IAudioClient_Start(stream->in.clientParent)) != S_OK)
3840 			{
3841 				LogHostError(hr);
3842 				result = paUnanticipatedHostError;
3843 				goto start_error;
3844 			}
3845 		}
3846 
3847 		// Initialize event & start OUTPUT stream
3848 		if (stream->out.clientParent != NULL)
3849 		{
3850 			// Start
3851 			if ((hr = IAudioClient_Start(stream->out.clientParent)) != S_OK)
3852 			{
3853 				LogHostError(hr);
3854 				result = paUnanticipatedHostError;
3855 				goto start_error;
3856 			}
3857 		}
3858 
3859 		// Set parent to working pointers to use shared functions.
3860 		stream->captureClient  = stream->captureClientParent;
3861 		stream->renderClient   = stream->renderClientParent;
3862 		stream->in.clientProc  = stream->in.clientParent;
3863 		stream->out.clientProc = stream->out.clientParent;
3864 
3865 		// Signal: stream running.
3866 		stream->running = TRUE;
3867 	}
3868 
3869     return result;
3870 
3871 nonblocking_start_error:
3872 
3873 	// Set hThreadExit event to prevent blocking during cleanup
3874 	SetEvent(stream->hThreadExit);
3875 	UnmarshalStreamComPointers(stream);
3876 	ReleaseUnmarshaledComPointers(stream);
3877 
3878 start_error:
3879 
3880 	StopStream(s);
3881 	return result;
3882 }
3883 
3884 // ------------------------------------------------------------------------------------------
_StreamFinish(PaWasapiStream * stream)3885 void _StreamFinish(PaWasapiStream *stream)
3886 {
3887 	// Issue command to thread to stop processing and wait for thread exit
3888 	if (!stream->bBlocking)
3889 	{
3890 		SignalObjectAndWait(stream->hCloseRequest, stream->hThreadExit, INFINITE, FALSE);
3891 	}
3892 	else
3893 	// Blocking mode does not own thread
3894 	{
3895 		// Signal close event and wait for each of 2 blocking operations to complete
3896 		if (stream->out.clientParent)
3897 			SignalObjectAndWait(stream->hCloseRequest, stream->hBlockingOpStreamWR, INFINITE, TRUE);
3898 		if (stream->out.clientParent)
3899 			SignalObjectAndWait(stream->hCloseRequest, stream->hBlockingOpStreamRD, INFINITE, TRUE);
3900 
3901 		// Process stop
3902 		_StreamOnStop(stream);
3903 	}
3904 
3905 	// Cleanup handles
3906 	_StreamCleanup(stream);
3907 
3908     stream->running = FALSE;
3909 }
3910 
3911 // ------------------------------------------------------------------------------------------
_StreamCleanup(PaWasapiStream * stream)3912 void _StreamCleanup(PaWasapiStream *stream)
3913 {
3914 	// Close thread handles to allow restart
3915 	SAFE_CLOSE(stream->hThread);
3916 	SAFE_CLOSE(stream->hThreadStart);
3917 	SAFE_CLOSE(stream->hThreadExit);
3918 	SAFE_CLOSE(stream->hCloseRequest);
3919 	SAFE_CLOSE(stream->hBlockingOpStreamRD);
3920 	SAFE_CLOSE(stream->hBlockingOpStreamWR);
3921 }
3922 
3923 // ------------------------------------------------------------------------------------------
StopStream(PaStream * s)3924 static PaError StopStream( PaStream *s )
3925 {
3926 	// Finish stream
3927 	_StreamFinish((PaWasapiStream *)s);
3928     return paNoError;
3929 }
3930 
3931 // ------------------------------------------------------------------------------------------
AbortStream(PaStream * s)3932 static PaError AbortStream( PaStream *s )
3933 {
3934 	// Finish stream
3935 	_StreamFinish((PaWasapiStream *)s);
3936     return paNoError;
3937 }
3938 
3939 // ------------------------------------------------------------------------------------------
IsStreamStopped(PaStream * s)3940 static PaError IsStreamStopped( PaStream *s )
3941 {
3942 	return !((PaWasapiStream *)s)->running;
3943 }
3944 
3945 // ------------------------------------------------------------------------------------------
IsStreamActive(PaStream * s)3946 static PaError IsStreamActive( PaStream *s )
3947 {
3948     return ((PaWasapiStream *)s)->running;
3949 }
3950 
3951 // ------------------------------------------------------------------------------------------
GetStreamTime(PaStream * s)3952 static PaTime GetStreamTime( PaStream *s )
3953 {
3954     PaWasapiStream *stream = (PaWasapiStream*)s;
3955 
3956     /* suppress unused variable warnings */
3957     (void) stream;
3958 
3959     return PaUtil_GetTime();
3960 }
3961 
3962 // ------------------------------------------------------------------------------------------
GetStreamCpuLoad(PaStream * s)3963 static double GetStreamCpuLoad( PaStream* s )
3964 {
3965 	return PaUtil_GetCpuLoad(&((PaWasapiStream *)s)->cpuLoadMeasurer);
3966 }
3967 
3968 // ------------------------------------------------------------------------------------------
ReadStream(PaStream * s,void * _buffer,unsigned long frames)3969 static PaError ReadStream( PaStream* s, void *_buffer, unsigned long frames )
3970 {
3971     PaWasapiStream *stream = (PaWasapiStream*)s;
3972 
3973 	HRESULT hr = S_OK;
3974 	BYTE *user_buffer = (BYTE *)_buffer;
3975 	BYTE *wasapi_buffer = NULL;
3976 	DWORD flags = 0;
3977 	UINT32 i, available, sleep = 0;
3978 	unsigned long processed;
3979 	ThreadIdleScheduler sched;
3980 
3981 	// validate
3982 	if (!stream->running)
3983 		return paStreamIsStopped;
3984 	if (stream->captureClient == NULL)
3985 		return paBadStreamPtr;
3986 
3987 	// Notify blocking op has begun
3988 	ResetEvent(stream->hBlockingOpStreamRD);
3989 
3990 	// Use thread scheduling for 500 microseconds (emulated) when wait time for frames is less than
3991 	// 1 milliseconds, emulation helps to normalize CPU consumption and avoids too busy waiting
3992 	ThreadIdleScheduler_Setup(&sched, 1, 250/* microseconds */);
3993 
3994     // Make a local copy of the user buffer pointer(s), this is necessary
3995 	// because PaUtil_CopyOutput() advances these pointers every time it is called
3996     if (!stream->bufferProcessor.userInputIsInterleaved)
3997     {
3998 		user_buffer = (BYTE *)alloca(sizeof(BYTE *) * stream->bufferProcessor.inputChannelCount);
3999         if (user_buffer == NULL)
4000             return paInsufficientMemory;
4001 
4002         for (i = 0; i < stream->bufferProcessor.inputChannelCount; ++i)
4003             ((BYTE **)user_buffer)[i] = ((BYTE **)_buffer)[i];
4004     }
4005 
4006 	// Findout if there are tail frames, flush them all before reading hardware
4007 	if ((available = PaUtil_GetRingBufferReadAvailable(stream->in.tailBuffer)) != 0)
4008 	{
4009 		ring_buffer_size_t buf1_size = 0, buf2_size = 0, read, desired;
4010 		void *buf1 = NULL, *buf2 = NULL;
4011 
4012 		// Limit desired to amount of requested frames
4013 		desired = available;
4014 		if ((UINT32)desired > frames)
4015 			desired = frames;
4016 
4017 		// Get pointers to read regions
4018 		read = PaUtil_GetRingBufferReadRegions(stream->in.tailBuffer, desired, &buf1, &buf1_size, &buf2, &buf2_size);
4019 
4020 		if (buf1 != NULL)
4021 		{
4022 			// Register available frames to processor
4023 			PaUtil_SetInputFrameCount(&stream->bufferProcessor, buf1_size);
4024 
4025 			// Register host buffer pointer to processor
4026 			PaUtil_SetInterleavedInputChannels(&stream->bufferProcessor, 0, buf1, stream->bufferProcessor.inputChannelCount);
4027 
4028 			// Copy user data to host buffer (with conversion if applicable)
4029 			processed = PaUtil_CopyInput(&stream->bufferProcessor, (void **)&user_buffer, buf1_size);
4030 			frames -= processed;
4031 		}
4032 
4033 		if (buf2 != NULL)
4034 		{
4035 			// Register available frames to processor
4036 			PaUtil_SetInputFrameCount(&stream->bufferProcessor, buf2_size);
4037 
4038 			// Register host buffer pointer to processor
4039 			PaUtil_SetInterleavedInputChannels(&stream->bufferProcessor, 0, buf2, stream->bufferProcessor.inputChannelCount);
4040 
4041 			// Copy user data to host buffer (with conversion if applicable)
4042 			processed = PaUtil_CopyInput(&stream->bufferProcessor, (void **)&user_buffer, buf2_size);
4043 			frames -= processed;
4044 		}
4045 
4046 		// Advance
4047 		PaUtil_AdvanceRingBufferReadIndex(stream->in.tailBuffer, read);
4048 	}
4049 
4050 	// Read hardware
4051 	while (frames != 0)
4052 	{
4053 		// Check if blocking call must be interrupted
4054 		if (WaitForSingleObject(stream->hCloseRequest, sleep) != WAIT_TIMEOUT)
4055 			break;
4056 
4057 		// Get available frames (must be finding out available frames before call to IAudioCaptureClient_GetBuffer
4058 		// othervise audio glitches will occur inExclusive mode as it seems that WASAPI has some scheduling/
4059 		// processing problems when such busy polling with IAudioCaptureClient_GetBuffer occurs)
4060 		if ((hr = _PollGetInputFramesAvailable(stream, &available)) != S_OK)
4061 		{
4062 			LogHostError(hr);
4063 			return paUnanticipatedHostError;
4064 		}
4065 
4066 		// Wait for more frames to become available
4067 		if (available == 0)
4068 		{
4069 			// Exclusive mode may require latency of 1 millisecond, thus we shall sleep
4070 			// around 500 microseconds (emulated) to collect packets in time
4071 			if (stream->in.shareMode != AUDCLNT_SHAREMODE_EXCLUSIVE)
4072 			{
4073 				UINT32 sleep_frames = (frames < stream->in.framesPerHostCallback ? frames : stream->in.framesPerHostCallback);
4074 
4075 				sleep  = GetFramesSleepTime(sleep_frames, stream->in.wavex.Format.nSamplesPerSec);
4076 				sleep /= 4; // wait only for 1/4 of the buffer
4077 
4078 				// WASAPI input provides packets, thus expiring packet will result in bad audio
4079 				// limit waiting time to 2 seconds (will always work for smallest buffer in Shared)
4080 				if (sleep > 2)
4081 					sleep = 2;
4082 
4083 				// Avoid busy waiting, schedule next 1 millesecond wait
4084 				if (sleep == 0)
4085 					sleep = ThreadIdleScheduler_NextSleep(&sched);
4086 			}
4087 			else
4088 			{
4089 				if ((sleep = ThreadIdleScheduler_NextSleep(&sched)) != 0)
4090 				{
4091 					Sleep(sleep);
4092 					sleep = 0;
4093 				}
4094 			}
4095 
4096 			continue;
4097 		}
4098 
4099 		// Get the available data in the shared buffer.
4100 		if ((hr = IAudioCaptureClient_GetBuffer(stream->captureClient, &wasapi_buffer, &available, &flags, NULL, NULL)) != S_OK)
4101 		{
4102 			// Buffer size is too small, waiting
4103 			if (hr != AUDCLNT_S_BUFFER_EMPTY)
4104 			{
4105 				LogHostError(hr);
4106 				goto end;
4107 			}
4108 
4109 			continue;
4110 		}
4111 
4112 		// Register available frames to processor
4113         PaUtil_SetInputFrameCount(&stream->bufferProcessor, available);
4114 
4115 		// Register host buffer pointer to processor
4116         PaUtil_SetInterleavedInputChannels(&stream->bufferProcessor, 0, wasapi_buffer, stream->bufferProcessor.inputChannelCount);
4117 
4118 		// Copy user data to host buffer (with conversion if applicable)
4119 		processed = PaUtil_CopyInput(&stream->bufferProcessor, (void **)&user_buffer, frames);
4120 		frames -= processed;
4121 
4122 		// Save tail into buffer
4123 		if ((frames == 0) && (available > processed))
4124 		{
4125 			UINT32 bytes_processed = processed * stream->in.wavex.Format.nBlockAlign;
4126 			UINT32 frames_to_save  = available - processed;
4127 
4128 			PaUtil_WriteRingBuffer(stream->in.tailBuffer, wasapi_buffer + bytes_processed, frames_to_save);
4129 		}
4130 
4131 		// Release host buffer
4132 		if ((hr = IAudioCaptureClient_ReleaseBuffer(stream->captureClient, available)) != S_OK)
4133 		{
4134 			LogHostError(hr);
4135 			goto end;
4136 		}
4137 	}
4138 
4139 end:
4140 
4141 	// Notify blocking op has ended
4142 	SetEvent(stream->hBlockingOpStreamRD);
4143 
4144 	return (hr != S_OK ? paUnanticipatedHostError : paNoError);
4145 }
4146 
4147 // ------------------------------------------------------------------------------------------
WriteStream(PaStream * s,const void * _buffer,unsigned long frames)4148 static PaError WriteStream( PaStream* s, const void *_buffer, unsigned long frames )
4149 {
4150     PaWasapiStream *stream = (PaWasapiStream*)s;
4151 
4152 	//UINT32 frames;
4153 	const BYTE *user_buffer = (const BYTE *)_buffer;
4154 	BYTE *wasapi_buffer;
4155 	HRESULT hr = S_OK;
4156 	UINT32 i, available, sleep = 0;
4157 	unsigned long processed;
4158 	ThreadIdleScheduler sched;
4159 
4160 	// validate
4161 	if (!stream->running)
4162 		return paStreamIsStopped;
4163 	if (stream->renderClient == NULL)
4164 		return paBadStreamPtr;
4165 
4166 	// Notify blocking op has begun
4167 	ResetEvent(stream->hBlockingOpStreamWR);
4168 
4169 	// Use thread scheduling for 500 microseconds (emulated) when wait time for frames is less than
4170 	// 1 milliseconds, emulation helps to normalize CPU consumption and avoids too busy waiting
4171 	ThreadIdleScheduler_Setup(&sched, 1, 500/* microseconds */);
4172 
4173     // Make a local copy of the user buffer pointer(s), this is necessary
4174 	// because PaUtil_CopyOutput() advances these pointers every time it is called
4175     if (!stream->bufferProcessor.userOutputIsInterleaved)
4176     {
4177         user_buffer = (const BYTE *)alloca(sizeof(const BYTE *) * stream->bufferProcessor.outputChannelCount);
4178         if (user_buffer == NULL)
4179             return paInsufficientMemory;
4180 
4181         for (i = 0; i < stream->bufferProcessor.outputChannelCount; ++i)
4182             ((const BYTE **)user_buffer)[i] = ((const BYTE **)_buffer)[i];
4183     }
4184 
4185 	// Blocking (potentially, untill 'frames' are consumed) loop
4186 	while (frames != 0)
4187 	{
4188 		// Check if blocking call must be interrupted
4189 		if (WaitForSingleObject(stream->hCloseRequest, sleep) != WAIT_TIMEOUT)
4190 			break;
4191 
4192 		// Get frames available
4193 		if ((hr = _PollGetOutputFramesAvailable(stream, &available)) != S_OK)
4194 		{
4195 			LogHostError(hr);
4196 			goto end;
4197 		}
4198 
4199 		// Wait for more frames to become available
4200 		if (available == 0)
4201 		{
4202 			UINT32 sleep_frames = (frames < stream->out.framesPerHostCallback ? frames : stream->out.framesPerHostCallback);
4203 
4204 			sleep  = GetFramesSleepTime(sleep_frames, stream->out.wavex.Format.nSamplesPerSec);
4205 			sleep /= 2; // wait only for half of the buffer
4206 
4207 			// Avoid busy waiting, schedule next 1 millesecond wait
4208 			if (sleep == 0)
4209 				sleep = ThreadIdleScheduler_NextSleep(&sched);
4210 
4211 			continue;
4212 		}
4213 
4214 		// Keep in 'frmaes' range
4215 		if (available > frames)
4216 			available = frames;
4217 
4218 		// Get pointer to host buffer
4219 		if ((hr = IAudioRenderClient_GetBuffer(stream->renderClient, available, &wasapi_buffer)) != S_OK)
4220 		{
4221 			// Buffer size is too big, waiting
4222 			if (hr == AUDCLNT_E_BUFFER_TOO_LARGE)
4223 				continue;
4224 
4225 			LogHostError(hr);
4226 			goto end;
4227 		}
4228 
4229 		// Keep waiting again (on Vista it was noticed that WASAPI could SOMETIMES return NULL pointer
4230 		// to buffer without returning AUDCLNT_E_BUFFER_TOO_LARGE instead)
4231 		if (wasapi_buffer == NULL)
4232 			continue;
4233 
4234 		// Register available frames to processor
4235         PaUtil_SetOutputFrameCount(&stream->bufferProcessor, available);
4236 
4237 		// Register host buffer pointer to processor
4238         PaUtil_SetInterleavedOutputChannels(&stream->bufferProcessor, 0, wasapi_buffer,	stream->bufferProcessor.outputChannelCount);
4239 
4240 		// Copy user data to host buffer (with conversion if applicable), this call will advance
4241 		// pointer 'user_buffer' to consumed portion of data
4242 		processed = PaUtil_CopyOutput(&stream->bufferProcessor, (const void **)&user_buffer, frames);
4243 		frames -= processed;
4244 
4245 		// Release host buffer
4246 		if ((hr = IAudioRenderClient_ReleaseBuffer(stream->renderClient, available, 0)) != S_OK)
4247 		{
4248 			LogHostError(hr);
4249 			goto end;
4250 		}
4251 	}
4252 
4253 end:
4254 
4255 	// Notify blocking op has ended
4256 	SetEvent(stream->hBlockingOpStreamWR);
4257 
4258 	return (hr != S_OK ? paUnanticipatedHostError : paNoError);
4259 }
4260 
PaUtil_GetOutputFrameCount(PaUtilBufferProcessor * bp)4261 unsigned long PaUtil_GetOutputFrameCount( PaUtilBufferProcessor* bp )
4262 {
4263 	return bp->hostOutputFrameCount[0];
4264 }
4265 
4266 // ------------------------------------------------------------------------------------------
GetStreamReadAvailable(PaStream * s)4267 static signed long GetStreamReadAvailable( PaStream* s )
4268 {
4269     PaWasapiStream *stream = (PaWasapiStream*)s;
4270 
4271 	HRESULT hr;
4272 	UINT32  available = 0;
4273 
4274 	// validate
4275 	if (!stream->running)
4276 		return paStreamIsStopped;
4277 	if (stream->captureClient == NULL)
4278 		return paBadStreamPtr;
4279 
4280 	// available in hardware buffer
4281 	if ((hr = _PollGetInputFramesAvailable(stream, &available)) != S_OK)
4282 	{
4283 		LogHostError(hr);
4284 		return paUnanticipatedHostError;
4285 	}
4286 
4287 	// available in software tail buffer
4288 	available += PaUtil_GetRingBufferReadAvailable(stream->in.tailBuffer);
4289 
4290     return available;
4291 }
4292 
4293 // ------------------------------------------------------------------------------------------
GetStreamWriteAvailable(PaStream * s)4294 static signed long GetStreamWriteAvailable( PaStream* s )
4295 {
4296     PaWasapiStream *stream = (PaWasapiStream*)s;
4297 	HRESULT hr;
4298 	UINT32  available = 0;
4299 
4300 	// validate
4301 	if (!stream->running)
4302 		return paStreamIsStopped;
4303 	if (stream->renderClient == NULL)
4304 		return paBadStreamPtr;
4305 
4306 	if ((hr = _PollGetOutputFramesAvailable(stream, &available)) != S_OK)
4307 	{
4308 		LogHostError(hr);
4309 		return paUnanticipatedHostError;
4310 	}
4311 
4312 	return (signed long)available;
4313 }
4314 
4315 
4316 // ------------------------------------------------------------------------------------------
WaspiHostProcessingLoop(void * inputBuffer,long inputFrames,void * outputBuffer,long outputFrames,void * userData)4317 static void WaspiHostProcessingLoop( void *inputBuffer,  long inputFrames,
4318                                      void *outputBuffer, long outputFrames,
4319                                      void *userData )
4320 {
4321     PaWasapiStream *stream = (PaWasapiStream*)userData;
4322     PaStreamCallbackTimeInfo timeInfo = {0,0,0};
4323 	PaStreamCallbackFlags flags = 0;
4324     int callbackResult;
4325     unsigned long framesProcessed;
4326 	HRESULT hr;
4327 	UINT32 pending;
4328 
4329     PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
4330 
4331     /*
4332 		Pa_GetStreamTime:
4333             - generate timing information
4334             - handle buffer slips
4335     */
4336 	timeInfo.currentTime = PaUtil_GetTime();
4337 	// Query input latency
4338 	if (stream->in.clientProc != NULL)
4339 	{
4340 		PaTime pending_time;
4341 		if ((hr = IAudioClient_GetCurrentPadding(stream->in.clientProc, &pending)) == S_OK)
4342 			pending_time = (PaTime)pending / (PaTime)stream->in.wavex.Format.nSamplesPerSec;
4343 		else
4344 			pending_time = (PaTime)stream->in.latencySeconds;
4345 
4346 		timeInfo.inputBufferAdcTime = timeInfo.currentTime + pending_time;
4347 	}
4348 	// Query output current latency
4349 	if (stream->out.clientProc != NULL)
4350 	{
4351 		PaTime pending_time;
4352 		if ((hr = IAudioClient_GetCurrentPadding(stream->out.clientProc, &pending)) == S_OK)
4353 			pending_time = (PaTime)pending / (PaTime)stream->out.wavex.Format.nSamplesPerSec;
4354 		else
4355 			pending_time = (PaTime)stream->out.latencySeconds;
4356 
4357 		timeInfo.outputBufferDacTime = timeInfo.currentTime + pending_time;
4358 	}
4359 
4360     /*
4361         If you need to byte swap or shift inputBuffer to convert it into a
4362         portaudio format, do it here.
4363     */
4364 
4365     PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, flags );
4366 
4367     /*
4368         depending on whether the host buffers are interleaved, non-interleaved
4369         or a mixture, you will want to call PaUtil_SetInterleaved*Channels(),
4370         PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here.
4371     */
4372 
4373     if (stream->bufferProcessor.inputChannelCount > 0)
4374     {
4375         PaUtil_SetInputFrameCount( &stream->bufferProcessor, inputFrames );
4376         PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor,
4377             0, /* first channel of inputBuffer is channel 0 */
4378             inputBuffer,
4379             0 ); /* 0 - use inputChannelCount passed to init buffer processor */
4380     }
4381 
4382     if (stream->bufferProcessor.outputChannelCount > 0)
4383     {
4384         PaUtil_SetOutputFrameCount( &stream->bufferProcessor, outputFrames);
4385         PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor,
4386             0, /* first channel of outputBuffer is channel 0 */
4387             outputBuffer,
4388             0 ); /* 0 - use outputChannelCount passed to init buffer processor */
4389     }
4390 
4391     /* you must pass a valid value of callback result to PaUtil_EndBufferProcessing()
4392         in general you would pass paContinue for normal operation, and
4393         paComplete to drain the buffer processor's internal output buffer.
4394         You can check whether the buffer processor's output buffer is empty
4395         using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor )
4396     */
4397     callbackResult = paContinue;
4398     framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
4399 
4400     /*
4401         If you need to byte swap or shift outputBuffer to convert it to
4402         host format, do it here.
4403     */
4404 
4405 	PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
4406 
4407     if (callbackResult == paContinue)
4408     {
4409         /* nothing special to do */
4410     }
4411     else
4412 	if (callbackResult == paAbort)
4413     {
4414 		// stop stream
4415         SetEvent(stream->hCloseRequest);
4416     }
4417     else
4418     {
4419 		// stop stream
4420         SetEvent(stream->hCloseRequest);
4421     }
4422 }
4423 
4424 // ------------------------------------------------------------------------------------------
MMCSS_activate(const char * name)4425 HANDLE MMCSS_activate(const char *name)
4426 {
4427 #ifndef PA_WINRT
4428     DWORD task_idx = 0;
4429     HANDLE hTask = pAvSetMmThreadCharacteristics(name, &task_idx);
4430     if (hTask == NULL)
4431 	{
4432         PRINT(("WASAPI: AvSetMmThreadCharacteristics failed!\n"));
4433     }
4434 
4435     /*BOOL priority_ok = pAvSetMmThreadPriority(hTask, AVRT_PRIORITY_NORMAL);
4436     if (priority_ok == FALSE)
4437 	{
4438         PRINT(("WASAPI: AvSetMmThreadPriority failed!\n"));
4439     }*/
4440 
4441 	// debug
4442     {
4443         int    cur_priority		  = GetThreadPriority(GetCurrentThread());
4444         DWORD  cur_priority_class = GetPriorityClass(GetCurrentProcess());
4445 		PRINT(("WASAPI: thread[ priority-0x%X class-0x%X ]\n", cur_priority, cur_priority_class));
4446     }
4447 
4448 	return hTask;
4449 #else
4450 	(void)name;
4451 	return NULL;
4452 #endif
4453 }
4454 
4455 // ------------------------------------------------------------------------------------------
MMCSS_deactivate(HANDLE hTask)4456 void MMCSS_deactivate(HANDLE hTask)
4457 {
4458 	if (!hTask)
4459 		return;
4460 
4461 #ifndef PA_WINRT
4462 	if (pAvRevertMmThreadCharacteristics(hTask) == FALSE)
4463 	{
4464         PRINT(("WASAPI: AvRevertMmThreadCharacteristics failed!\n"));
4465     }
4466 #endif
4467 }
4468 
4469 // ------------------------------------------------------------------------------------------
PaWasapi_ThreadPriorityBoost(void ** hTask,PaWasapiThreadPriority nPriorityClass)4470 PaError PaWasapi_ThreadPriorityBoost(void **hTask, PaWasapiThreadPriority nPriorityClass)
4471 {
4472 	static const char *mmcs_name[] =
4473 	{
4474 		NULL,
4475 		"Audio",
4476 		"Capture",
4477 		"Distribution",
4478 		"Games",
4479 		"Playback",
4480 		"Pro Audio",
4481 		"Window Manager"
4482 	};
4483 	HANDLE task;
4484 
4485 	if (hTask == NULL)
4486 		return paUnanticipatedHostError;
4487 
4488 	if ((UINT32)nPriorityClass >= STATIC_ARRAY_SIZE(mmcs_name))
4489 		return paUnanticipatedHostError;
4490 
4491 	task = MMCSS_activate(mmcs_name[nPriorityClass]);
4492 	if (task == NULL)
4493 		return paUnanticipatedHostError;
4494 
4495 	(*hTask) = task;
4496 	return paNoError;
4497 }
4498 
4499 // ------------------------------------------------------------------------------------------
PaWasapi_ThreadPriorityRevert(void * hTask)4500 PaError PaWasapi_ThreadPriorityRevert(void *hTask)
4501 {
4502 	if (hTask == NULL)
4503 		return paUnanticipatedHostError;
4504 
4505 	MMCSS_deactivate((HANDLE)hTask);
4506 
4507 	return paNoError;
4508 }
4509 
4510 // ------------------------------------------------------------------------------------------
4511 // Described at:
4512 // http://msdn.microsoft.com/en-us/library/dd371387(v=VS.85).aspx
4513 
PaWasapi_GetJackCount(PaDeviceIndex nDevice,int * jcount)4514 PaError PaWasapi_GetJackCount(PaDeviceIndex nDevice, int *jcount)
4515 {
4516 #ifndef PA_WINRT
4517 	PaError ret;
4518 	HRESULT hr = S_OK;
4519 	PaDeviceIndex index;
4520     IDeviceTopology *pDeviceTopology = NULL;
4521     IConnector *pConnFrom = NULL;
4522     IConnector *pConnTo = NULL;
4523     IPart *pPart = NULL;
4524     IKsJackDescription *pJackDesc = NULL;
4525 	UINT jackCount = 0;
4526 
4527 	PaWasapiHostApiRepresentation *paWasapi = _GetHostApi(&ret);
4528 	if (paWasapi == NULL)
4529 		return paNotInitialized;
4530 
4531 	// Get device index.
4532 	ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, nDevice, &paWasapi->inheritedHostApiRep);
4533     if (ret != paNoError)
4534         return ret;
4535 
4536 	// Validate index.
4537 	if ((UINT32)index >= paWasapi->deviceCount)
4538 		return paInvalidDevice;
4539 
4540 	// Get the endpoint device's IDeviceTopology interface.
4541 	hr = IMMDevice_Activate(paWasapi->devInfo[index].device, &pa_IID_IDeviceTopology,
4542 		CLSCTX_INPROC_SERVER, NULL, (void**)&pDeviceTopology);
4543 	IF_FAILED_JUMP(hr, error);
4544 
4545     // The device topology for an endpoint device always contains just one connector (connector number 0).
4546 	hr = IDeviceTopology_GetConnector(pDeviceTopology, 0, &pConnFrom);
4547 	IF_FAILED_JUMP(hr, error);
4548 
4549     // Step across the connection to the jack on the adapter.
4550 	hr = IConnector_GetConnectedTo(pConnFrom, &pConnTo);
4551     if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
4552     {
4553         // The adapter device is not currently active.
4554         hr = E_NOINTERFACE;
4555     }
4556 	IF_FAILED_JUMP(hr, error);
4557 
4558 	// Get the connector's IPart interface.
4559 	hr = IConnector_QueryInterface(pConnTo, &pa_IID_IPart, (void**)&pPart);
4560 	IF_FAILED_JUMP(hr, error);
4561 
4562 	// Activate the connector's IKsJackDescription interface.
4563 	hr = IPart_Activate(pPart, CLSCTX_INPROC_SERVER, &pa_IID_IKsJackDescription, (void**)&pJackDesc);
4564 	IF_FAILED_JUMP(hr, error);
4565 
4566 	// Return jack count for this device.
4567 	hr = IKsJackDescription_GetJackCount(pJackDesc, &jackCount);
4568 	IF_FAILED_JUMP(hr, error);
4569 
4570 	// Set.
4571 	(*jcount) = jackCount;
4572 
4573 	// Ok.
4574 	ret = paNoError;
4575 
4576 error:
4577 
4578 	SAFE_RELEASE(pDeviceTopology);
4579 	SAFE_RELEASE(pConnFrom);
4580 	SAFE_RELEASE(pConnTo);
4581 	SAFE_RELEASE(pPart);
4582 	SAFE_RELEASE(pJackDesc);
4583 
4584 	LogHostError(hr);
4585 	return paNoError;
4586 #else
4587 	(void)nDevice;
4588 	(void)jcount;
4589 	return paUnanticipatedHostError;
4590 #endif
4591 }
4592 
4593 // ------------------------------------------------------------------------------------------
4594 #ifndef PA_WINRT
ConvertJackConnectionTypeWASAPIToPA(int connType)4595 static PaWasapiJackConnectionType ConvertJackConnectionTypeWASAPIToPA(int connType)
4596 {
4597 	switch (connType)
4598 	{
4599 		case eConnTypeUnknown:			return eJackConnTypeUnknown;
4600 #ifdef _KS_
4601 		case eConnType3Point5mm:		return eJackConnType3Point5mm;
4602 #else
4603 		case eConnTypeEighth:		    return eJackConnType3Point5mm;
4604 #endif
4605 		case eConnTypeQuarter:			return eJackConnTypeQuarter;
4606 		case eConnTypeAtapiInternal:	return eJackConnTypeAtapiInternal;
4607 		case eConnTypeRCA:				return eJackConnTypeRCA;
4608 		case eConnTypeOptical:			return eJackConnTypeOptical;
4609 		case eConnTypeOtherDigital:		return eJackConnTypeOtherDigital;
4610 		case eConnTypeOtherAnalog:		return eJackConnTypeOtherAnalog;
4611 		case eConnTypeMultichannelAnalogDIN: return eJackConnTypeMultichannelAnalogDIN;
4612 		case eConnTypeXlrProfessional:	return eJackConnTypeXlrProfessional;
4613 		case eConnTypeRJ11Modem:		return eJackConnTypeRJ11Modem;
4614 		case eConnTypeCombination:		return eJackConnTypeCombination;
4615 	}
4616 	return eJackConnTypeUnknown;
4617 }
4618 #endif
4619 
4620 // ------------------------------------------------------------------------------------------
4621 #ifndef PA_WINRT
ConvertJackGeoLocationWASAPIToPA(int geoLoc)4622 static PaWasapiJackGeoLocation ConvertJackGeoLocationWASAPIToPA(int geoLoc)
4623 {
4624 	switch (geoLoc)
4625 	{
4626 	case eGeoLocRear:				return eJackGeoLocRear;
4627 	case eGeoLocFront:				return eJackGeoLocFront;
4628 	case eGeoLocLeft:				return eJackGeoLocLeft;
4629 	case eGeoLocRight:				return eJackGeoLocRight;
4630 	case eGeoLocTop:				return eJackGeoLocTop;
4631 	case eGeoLocBottom:				return eJackGeoLocBottom;
4632 #ifdef _KS_
4633 	case eGeoLocRearPanel:			return eJackGeoLocRearPanel;
4634 #else
4635 	case eGeoLocRearOPanel:         return eJackGeoLocRearPanel;
4636 #endif
4637 	case eGeoLocRiser:				return eJackGeoLocRiser;
4638 	case eGeoLocInsideMobileLid:	return eJackGeoLocInsideMobileLid;
4639 	case eGeoLocDrivebay:			return eJackGeoLocDrivebay;
4640 	case eGeoLocHDMI:				return eJackGeoLocHDMI;
4641 	case eGeoLocOutsideMobileLid:	return eJackGeoLocOutsideMobileLid;
4642 	case eGeoLocATAPI:				return eJackGeoLocATAPI;
4643 	}
4644 	return eJackGeoLocUnk;
4645 }
4646 #endif
4647 
4648 // ------------------------------------------------------------------------------------------
4649 #ifndef PA_WINRT
ConvertJackGenLocationWASAPIToPA(int genLoc)4650 static PaWasapiJackGenLocation ConvertJackGenLocationWASAPIToPA(int genLoc)
4651 {
4652 	switch (genLoc)
4653 	{
4654 	case eGenLocPrimaryBox:	return eJackGenLocPrimaryBox;
4655 	case eGenLocInternal:	return eJackGenLocInternal;
4656 #ifdef _KS_
4657 	case eGenLocSeparate:	return eJackGenLocSeparate;
4658 #else
4659 	case eGenLocSeperate:	return eJackGenLocSeparate;
4660 #endif
4661 	case eGenLocOther:		return eJackGenLocOther;
4662 	}
4663 	return eJackGenLocPrimaryBox;
4664 }
4665 #endif
4666 
4667 // ------------------------------------------------------------------------------------------
4668 #ifndef PA_WINRT
ConvertJackPortConnectionWASAPIToPA(int portConn)4669 static PaWasapiJackPortConnection ConvertJackPortConnectionWASAPIToPA(int portConn)
4670 {
4671 	switch (portConn)
4672 	{
4673 	case ePortConnJack:					return eJackPortConnJack;
4674 	case ePortConnIntegratedDevice:		return eJackPortConnIntegratedDevice;
4675 	case ePortConnBothIntegratedAndJack:return eJackPortConnBothIntegratedAndJack;
4676 	case ePortConnUnknown:				return eJackPortConnUnknown;
4677 	}
4678 	return eJackPortConnJack;
4679 }
4680 #endif
4681 
4682 // ------------------------------------------------------------------------------------------
4683 // Described at:
4684 // http://msdn.microsoft.com/en-us/library/dd371387(v=VS.85).aspx
4685 
PaWasapi_GetJackDescription(PaDeviceIndex nDevice,int jindex,PaWasapiJackDescription * pJackDescription)4686 PaError PaWasapi_GetJackDescription(PaDeviceIndex nDevice, int jindex, PaWasapiJackDescription *pJackDescription)
4687 {
4688 #ifndef PA_WINRT
4689 	PaError ret;
4690 	HRESULT hr = S_OK;
4691 	PaDeviceIndex index;
4692     IDeviceTopology *pDeviceTopology = NULL;
4693     IConnector *pConnFrom = NULL;
4694     IConnector *pConnTo = NULL;
4695     IPart *pPart = NULL;
4696     IKsJackDescription *pJackDesc = NULL;
4697 	KSJACK_DESCRIPTION jack = { 0 };
4698 
4699 	PaWasapiHostApiRepresentation *paWasapi = _GetHostApi(&ret);
4700 	if (paWasapi == NULL)
4701 		return paNotInitialized;
4702 
4703 	// Get device index.
4704 	ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, nDevice, &paWasapi->inheritedHostApiRep);
4705     if (ret != paNoError)
4706         return ret;
4707 
4708 	// Validate index.
4709 	if ((UINT32)index >= paWasapi->deviceCount)
4710 		return paInvalidDevice;
4711 
4712 	// Get the endpoint device's IDeviceTopology interface.
4713 	hr = IMMDevice_Activate(paWasapi->devInfo[index].device, &pa_IID_IDeviceTopology,
4714 		CLSCTX_INPROC_SERVER, NULL, (void**)&pDeviceTopology);
4715 	IF_FAILED_JUMP(hr, error);
4716 
4717     // The device topology for an endpoint device always contains just one connector (connector number 0).
4718 	hr = IDeviceTopology_GetConnector(pDeviceTopology, 0, &pConnFrom);
4719 	IF_FAILED_JUMP(hr, error);
4720 
4721     // Step across the connection to the jack on the adapter.
4722 	hr = IConnector_GetConnectedTo(pConnFrom, &pConnTo);
4723     if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
4724     {
4725         // The adapter device is not currently active.
4726         hr = E_NOINTERFACE;
4727     }
4728 	IF_FAILED_JUMP(hr, error);
4729 
4730 	// Get the connector's IPart interface.
4731 	hr = IConnector_QueryInterface(pConnTo, &pa_IID_IPart, (void**)&pPart);
4732 	IF_FAILED_JUMP(hr, error);
4733 
4734 	// Activate the connector's IKsJackDescription interface.
4735 	hr = IPart_Activate(pPart, CLSCTX_INPROC_SERVER, &pa_IID_IKsJackDescription, (void**)&pJackDesc);
4736 	IF_FAILED_JUMP(hr, error);
4737 
4738 	// Test to return jack description struct for index 0.
4739 	hr = IKsJackDescription_GetJackDescription(pJackDesc, jindex, &jack);
4740 	IF_FAILED_JUMP(hr, error);
4741 
4742 	// Convert WASAPI values to PA format.
4743 	pJackDescription->channelMapping = jack.ChannelMapping;
4744 	pJackDescription->color          = jack.Color;
4745 	pJackDescription->connectionType = ConvertJackConnectionTypeWASAPIToPA(jack.ConnectionType);
4746 	pJackDescription->genLocation    = ConvertJackGenLocationWASAPIToPA(jack.GenLocation);
4747 	pJackDescription->geoLocation    = ConvertJackGeoLocationWASAPIToPA(jack.GeoLocation);
4748 	pJackDescription->isConnected    = jack.IsConnected;
4749 	pJackDescription->portConnection = ConvertJackPortConnectionWASAPIToPA(jack.PortConnection);
4750 
4751 	// Ok.
4752 	ret = paNoError;
4753 
4754 error:
4755 
4756 	SAFE_RELEASE(pDeviceTopology);
4757 	SAFE_RELEASE(pConnFrom);
4758 	SAFE_RELEASE(pConnTo);
4759 	SAFE_RELEASE(pPart);
4760 	SAFE_RELEASE(pJackDesc);
4761 
4762 	LogHostError(hr);
4763 	return ret;
4764 
4765 #else
4766 	(void)nDevice;
4767 	(void)jindex;
4768 	(void)pJackDescription;
4769 	return paUnanticipatedHostError;
4770 #endif
4771 }
4772 
4773 // ------------------------------------------------------------------------------------------
_PollGetOutputFramesAvailable(PaWasapiStream * stream,UINT32 * available)4774 HRESULT _PollGetOutputFramesAvailable(PaWasapiStream *stream, UINT32 *available)
4775 {
4776 	HRESULT hr;
4777 	UINT32 frames  = stream->out.framesPerHostCallback,
4778 		   padding = 0;
4779 
4780 	(*available) = 0;
4781 
4782 	// get read position
4783 	if ((hr = IAudioClient_GetCurrentPadding(stream->out.clientProc, &padding)) != S_OK)
4784 		return LogHostError(hr);
4785 
4786 	// get available
4787 	frames -= padding;
4788 
4789 	// set
4790 	(*available) = frames;
4791 	return hr;
4792 }
4793 
4794 // ------------------------------------------------------------------------------------------
_PollGetInputFramesAvailable(PaWasapiStream * stream,UINT32 * available)4795 HRESULT _PollGetInputFramesAvailable(PaWasapiStream *stream, UINT32 *available)
4796 {
4797 	HRESULT hr;
4798 
4799 	(*available) = 0;
4800 
4801 	// GetCurrentPadding() has opposite meaning to Output stream
4802 	if ((hr = IAudioClient_GetCurrentPadding(stream->in.clientProc, available)) != S_OK)
4803 		return LogHostError(hr);
4804 
4805 	return hr;
4806 }
4807 
4808 // ------------------------------------------------------------------------------------------
ProcessOutputBuffer(PaWasapiStream * stream,PaWasapiHostProcessor * processor,UINT32 frames)4809 HRESULT ProcessOutputBuffer(PaWasapiStream *stream, PaWasapiHostProcessor *processor, UINT32 frames)
4810 {
4811 	HRESULT hr;
4812 	BYTE *data = NULL;
4813 
4814 	// Get buffer
4815 	if ((hr = IAudioRenderClient_GetBuffer(stream->renderClient, frames, &data)) != S_OK)
4816 	{
4817 		if (stream->out.shareMode == AUDCLNT_SHAREMODE_SHARED)
4818 		{
4819 			// Using GetCurrentPadding to overcome AUDCLNT_E_BUFFER_TOO_LARGE in
4820 			// shared mode results in no sound in Event-driven mode (MSDN does not
4821 			// document this, or is it WASAPI bug?), thus we better
4822 			// try to acquire buffer next time when GetBuffer allows to do so.
4823 #if 0
4824 			// Get Read position
4825 			UINT32 padding = 0;
4826 			hr = IAudioClient_GetCurrentPadding(stream->out.clientProc, &padding);
4827 			if (hr != S_OK)
4828 				return LogHostError(hr);
4829 
4830 			// Get frames to write
4831 			frames -= padding;
4832 			if (frames == 0)
4833 				return S_OK;
4834 
4835 			if ((hr = IAudioRenderClient_GetBuffer(stream->renderClient, frames, &data)) != S_OK)
4836 				return LogHostError(hr);
4837 #else
4838 			if (hr == AUDCLNT_E_BUFFER_TOO_LARGE)
4839 				return S_OK; // be silent in shared mode, try again next time
4840 #endif
4841 		}
4842 		else
4843 			return LogHostError(hr);
4844 	}
4845 
4846 	// Process data
4847 	if (stream->out.monoMixer != NULL)
4848 	{
4849 		// expand buffer
4850 		UINT32 mono_frames_size = frames * (stream->out.wavex.Format.wBitsPerSample / 8);
4851 		if (mono_frames_size > stream->out.monoBufferSize)
4852 			stream->out.monoBuffer = PaWasapi_ReallocateMemory(stream->out.monoBuffer, (stream->out.monoBufferSize = mono_frames_size));
4853 
4854 		// process
4855 		processor[S_OUTPUT].processor(NULL, 0, (BYTE *)stream->out.monoBuffer, frames, processor[S_OUTPUT].userData);
4856 
4857 		// mix 1 to 2 channels
4858 		stream->out.monoMixer(data, stream->out.monoBuffer, frames);
4859 	}
4860 	else
4861 	{
4862 		processor[S_OUTPUT].processor(NULL, 0, data, frames, processor[S_OUTPUT].userData);
4863 	}
4864 
4865 	// Release buffer
4866 	if ((hr = IAudioRenderClient_ReleaseBuffer(stream->renderClient, frames, 0)) != S_OK)
4867 		LogHostError(hr);
4868 
4869 	return hr;
4870 }
4871 
4872 // ------------------------------------------------------------------------------------------
ProcessInputBuffer(PaWasapiStream * stream,PaWasapiHostProcessor * processor)4873 HRESULT ProcessInputBuffer(PaWasapiStream *stream, PaWasapiHostProcessor *processor)
4874 {
4875 	HRESULT hr = S_OK;
4876 	UINT32 frames;
4877 	BYTE *data = NULL;
4878 	DWORD flags = 0;
4879 
4880 	for (;;)
4881 	{
4882 		// Check if blocking call must be interrupted
4883 		if (WaitForSingleObject(stream->hCloseRequest, 0) != WAIT_TIMEOUT)
4884 			break;
4885 
4886 		// Findout if any frames available
4887 		frames = 0;
4888 		if ((hr = _PollGetInputFramesAvailable(stream, &frames)) != S_OK)
4889 			return hr;
4890 
4891 		// Empty/consumed buffer
4892 		if (frames == 0)
4893 			break;
4894 
4895 		// Get the available data in the shared buffer.
4896 		if ((hr = IAudioCaptureClient_GetBuffer(stream->captureClient, &data, &frames, &flags, NULL, NULL)) != S_OK)
4897 		{
4898 			if (hr == AUDCLNT_S_BUFFER_EMPTY)
4899 			{
4900 				hr = S_OK;
4901 				break; // Empty/consumed buffer
4902 			}
4903 
4904 			return LogHostError(hr);
4905 			break;
4906 		}
4907 
4908 		// Detect silence
4909 		// if (flags & AUDCLNT_BUFFERFLAGS_SILENT)
4910 		//	data = NULL;
4911 
4912 		// Process data
4913 		if (stream->in.monoMixer != NULL)
4914 		{
4915 			// expand buffer
4916 			UINT32 mono_frames_size = frames * (stream->in.wavex.Format.wBitsPerSample / 8);
4917 			if (mono_frames_size > stream->in.monoBufferSize)
4918 				stream->in.monoBuffer = PaWasapi_ReallocateMemory(stream->in.monoBuffer, (stream->in.monoBufferSize = mono_frames_size));
4919 
4920 			// mix 1 to 2 channels
4921 			stream->in.monoMixer(stream->in.monoBuffer, data, frames);
4922 
4923 			// process
4924 			processor[S_INPUT].processor((BYTE *)stream->in.monoBuffer, frames, NULL, 0, processor[S_INPUT].userData);
4925 		}
4926 		else
4927 		{
4928 			processor[S_INPUT].processor(data, frames, NULL, 0, processor[S_INPUT].userData);
4929 		}
4930 
4931 		// Release buffer
4932 		if ((hr = IAudioCaptureClient_ReleaseBuffer(stream->captureClient, frames)) != S_OK)
4933 			return LogHostError(hr);
4934 
4935 		//break;
4936 	}
4937 
4938 	return hr;
4939 }
4940 
4941 // ------------------------------------------------------------------------------------------
_StreamOnStop(PaWasapiStream * stream)4942 void _StreamOnStop(PaWasapiStream *stream)
4943 {
4944 	// Stop INPUT/OUTPUT clients
4945 	if (!stream->bBlocking)
4946 	{
4947 		if (stream->in.clientProc != NULL)
4948 			IAudioClient_Stop(stream->in.clientProc);
4949 		if (stream->out.clientProc != NULL)
4950 			IAudioClient_Stop(stream->out.clientProc);
4951 	}
4952 	else
4953 	{
4954 		if (stream->in.clientParent != NULL)
4955 			IAudioClient_Stop(stream->in.clientParent);
4956 		if (stream->out.clientParent != NULL)
4957 			IAudioClient_Stop(stream->out.clientParent);
4958 	}
4959 
4960 	// Restore thread priority
4961 	if (stream->hAvTask != NULL)
4962 	{
4963 		PaWasapi_ThreadPriorityRevert(stream->hAvTask);
4964 		stream->hAvTask = NULL;
4965 	}
4966 
4967     // Notify
4968     if (stream->streamRepresentation.streamFinishedCallback != NULL)
4969         stream->streamRepresentation.streamFinishedCallback(stream->streamRepresentation.userData);
4970 }
4971 
4972 // ------------------------------------------------------------------------------------------
ProcThreadEvent(void * param)4973 PA_THREAD_FUNC ProcThreadEvent(void *param)
4974 {
4975     PaWasapiHostProcessor processor[S_COUNT];
4976 	HRESULT hr;
4977 	DWORD dwResult;
4978     PaWasapiStream *stream = (PaWasapiStream *)param;
4979 	PaWasapiHostProcessor defaultProcessor;
4980 	BOOL set_event[S_COUNT] = { FALSE, FALSE };
4981 	BOOL bWaitAllEvents = FALSE;
4982 	BOOL bThreadComInitialized = FALSE;
4983 
4984 	/*
4985 	If COM is already initialized CoInitialize will either return
4986 	FALSE, or RPC_E_CHANGED_MODE if it was initialized in a different
4987 	threading mode. In either case we shouldn't consider it an error
4988 	but we need to be careful to not call CoUninitialize() if
4989 	RPC_E_CHANGED_MODE was returned.
4990 	*/
4991 	hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
4992 	if (FAILED(hr) && (hr != RPC_E_CHANGED_MODE))
4993 	{
4994 		PRINT(("WASAPI: failed ProcThreadEvent CoInitialize"));
4995 		return (UINT32)paUnanticipatedHostError;
4996 	}
4997 	if (hr != RPC_E_CHANGED_MODE)
4998 		bThreadComInitialized = TRUE;
4999 
5000 	// Unmarshal stream pointers for safe COM operation
5001 	hr = UnmarshalStreamComPointers(stream);
5002 	if (hr != S_OK) {
5003 		PRINT(("Error unmarshaling stream COM pointers. HRESULT: %i\n", hr));
5004 		goto thread_end;
5005 	}
5006 
5007 	// Waiting on all events in case of Full-Duplex/Exclusive mode.
5008 	if ((stream->in.clientProc != NULL) && (stream->out.clientProc != NULL))
5009 	{
5010 		bWaitAllEvents = (stream->in.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) &&
5011 			(stream->out.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE);
5012 	}
5013 
5014     // Setup data processors
5015     defaultProcessor.processor = WaspiHostProcessingLoop;
5016     defaultProcessor.userData  = stream;
5017     processor[S_INPUT] = (stream->hostProcessOverrideInput.processor != NULL ? stream->hostProcessOverrideInput : defaultProcessor);
5018     processor[S_OUTPUT] = (stream->hostProcessOverrideOutput.processor != NULL ? stream->hostProcessOverrideOutput : defaultProcessor);
5019 
5020 	// Boost thread priority
5021 	PaWasapi_ThreadPriorityBoost((void **)&stream->hAvTask, stream->nThreadPriority);
5022 
5023 	// Create events
5024 	if (stream->event[S_OUTPUT] == NULL)
5025 	{
5026 		stream->event[S_OUTPUT] = CreateEvent(NULL, FALSE, FALSE, NULL);
5027 		set_event[S_OUTPUT] = TRUE;
5028 	}
5029 	if (stream->event[S_INPUT] == NULL)
5030 	{
5031 		stream->event[S_INPUT]  = CreateEvent(NULL, FALSE, FALSE, NULL);
5032 		set_event[S_INPUT] = TRUE;
5033 	}
5034 	if ((stream->event[S_OUTPUT] == NULL) || (stream->event[S_INPUT] == NULL))
5035 	{
5036 		PRINT(("WASAPI Thread: failed creating Input/Output event handle\n"));
5037 		goto thread_error;
5038 	}
5039 
5040 	// Initialize event & start INPUT stream
5041 	if (stream->in.clientProc)
5042 	{
5043 		// Create & set handle
5044 		if (set_event[S_INPUT])
5045 		{
5046 			if ((hr = IAudioClient_SetEventHandle(stream->in.clientProc, stream->event[S_INPUT])) != S_OK)
5047 			{
5048 				LogHostError(hr);
5049 				goto thread_error;
5050 			}
5051 		}
5052 
5053 		// Start
5054 		if ((hr = IAudioClient_Start(stream->in.clientProc)) != S_OK)
5055 		{
5056 			LogHostError(hr);
5057 			goto thread_error;
5058 		}
5059 	}
5060 
5061 	// Initialize event & start OUTPUT stream
5062 	if (stream->out.clientProc)
5063 	{
5064 		// Create & set handle
5065 		if (set_event[S_OUTPUT])
5066 		{
5067 			if ((hr = IAudioClient_SetEventHandle(stream->out.clientProc, stream->event[S_OUTPUT])) != S_OK)
5068 			{
5069 				LogHostError(hr);
5070 				goto thread_error;
5071 			}
5072 		}
5073 
5074 		// Preload buffer before start
5075 		if ((hr = ProcessOutputBuffer(stream, processor, stream->out.framesPerBuffer)) != S_OK)
5076 		{
5077 			LogHostError(hr);
5078 			goto thread_error;
5079 		}
5080 
5081 		// Start
5082 		if ((hr = IAudioClient_Start(stream->out.clientProc)) != S_OK)
5083 		{
5084 			LogHostError(hr);
5085 			goto thread_error;
5086 		}
5087 
5088 	}
5089 
5090 	// Signal: stream running
5091 	stream->running = TRUE;
5092 
5093 	// Notify: thread started
5094 	SetEvent(stream->hThreadStart);
5095 
5096 	// Processing Loop
5097 	for (;;)
5098     {
5099 	    // 10 sec timeout (on timeout stream will auto-stop when processed by WAIT_TIMEOUT case)
5100         dwResult = WaitForMultipleObjects(S_COUNT, stream->event, bWaitAllEvents, 10*1000);
5101 
5102 		// Check for close event (after wait for buffers to avoid any calls to user
5103 		// callback when hCloseRequest was set)
5104 		if (WaitForSingleObject(stream->hCloseRequest, 0) != WAIT_TIMEOUT)
5105 			break;
5106 
5107 		// Process S_INPUT/S_OUTPUT
5108 		switch (dwResult)
5109 		{
5110 		case WAIT_TIMEOUT: {
5111 			PRINT(("WASAPI Thread: WAIT_TIMEOUT - probably bad audio driver or Vista x64 bug: use paWinWasapiPolling instead\n"));
5112 			goto thread_end;
5113 			break; }
5114 
5115 		// Input stream
5116 		case WAIT_OBJECT_0 + S_INPUT: {
5117 
5118             if (stream->captureClient == NULL)
5119                 break;
5120 
5121 			if ((hr = ProcessInputBuffer(stream, processor)) != S_OK)
5122 			{
5123 				LogHostError(hr);
5124 				goto thread_error;
5125 			}
5126 
5127 			break; }
5128 
5129 		// Output stream
5130 		case WAIT_OBJECT_0 + S_OUTPUT: {
5131 
5132             if (stream->renderClient == NULL)
5133                 break;
5134 
5135 			if ((hr = ProcessOutputBuffer(stream, processor, stream->out.framesPerBuffer)) != S_OK)
5136 			{
5137 				LogHostError(hr);
5138 				goto thread_error;
5139 			}
5140 
5141 			break; }
5142 		}
5143 	}
5144 
5145 thread_end:
5146 
5147 	// Process stop
5148 	_StreamOnStop(stream);
5149 
5150 	// Release unmarshaled COM pointers
5151 	ReleaseUnmarshaledComPointers(stream);
5152 
5153 	// Cleanup COM for this thread
5154 	if (bThreadComInitialized == TRUE)
5155 		CoUninitialize();
5156 
5157 	// Notify: not running
5158 	stream->running = FALSE;
5159 
5160 	// Notify: thread exited
5161 	SetEvent(stream->hThreadExit);
5162 
5163 	return 0;
5164 
5165 thread_error:
5166 
5167 	// Prevent deadlocking in Pa_StreamStart
5168 	SetEvent(stream->hThreadStart);
5169 
5170 	// Exit
5171 	goto thread_end;
5172 }
5173 
5174 // ------------------------------------------------------------------------------------------
ProcThreadPoll(void * param)5175 PA_THREAD_FUNC ProcThreadPoll(void *param)
5176 {
5177     PaWasapiHostProcessor processor[S_COUNT];
5178 	HRESULT hr;
5179     PaWasapiStream *stream = (PaWasapiStream *)param;
5180 	PaWasapiHostProcessor defaultProcessor;
5181 	INT32 i;
5182 	ThreadIdleScheduler scheduler;
5183 
5184 	// Calculate the actual duration of the allocated buffer.
5185 	DWORD sleep_ms     = 0;
5186 	DWORD sleep_ms_in;
5187 	DWORD sleep_ms_out;
5188 
5189 	BOOL bThreadComInitialized = FALSE;
5190 
5191 	/*
5192 	If COM is already initialized CoInitialize will either return
5193 	FALSE, or RPC_E_CHANGED_MODE if it was initialized in a different
5194 	threading mode. In either case we shouldn't consider it an error
5195 	but we need to be careful to not call CoUninitialize() if
5196 	RPC_E_CHANGED_MODE was returned.
5197 	*/
5198 	hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
5199 	if (FAILED(hr) && (hr != RPC_E_CHANGED_MODE))
5200 	{
5201 		PRINT(("WASAPI: failed ProcThreadPoll CoInitialize"));
5202 		return (UINT32)paUnanticipatedHostError;
5203 	}
5204 	if (hr != RPC_E_CHANGED_MODE)
5205 		bThreadComInitialized = TRUE;
5206 
5207 	// Unmarshal stream pointers for safe COM operation
5208 	hr = UnmarshalStreamComPointers(stream);
5209 	if (hr != S_OK)
5210 	{
5211 		PRINT(("Error unmarshaling stream COM pointers. HRESULT: %i\n", hr));
5212 		return 0;
5213 	}
5214 
5215 	// Calculate timeout for next polling attempt.
5216 	sleep_ms_in  = GetFramesSleepTime(stream->in.framesPerHostCallback/WASAPI_PACKETS_PER_INPUT_BUFFER, stream->in.wavex.Format.nSamplesPerSec);
5217 	sleep_ms_out = GetFramesSleepTime(stream->out.framesPerBuffer, stream->out.wavex.Format.nSamplesPerSec);
5218 
5219 	// WASAPI Input packets tend to expire very easily, let's limit sleep time to 2 milliseconds
5220 	// for all cases. Please propose better solution if any.
5221 	if (sleep_ms_in > 2)
5222 		sleep_ms_in = 2;
5223 
5224 	// Adjust polling time for non-paUtilFixedHostBufferSize. Input stream is not adjustable as it is being
5225 	// polled according its packet length.
5226 	if (stream->bufferMode != paUtilFixedHostBufferSize)
5227 	{
5228 		//sleep_ms_in = GetFramesSleepTime(stream->bufferProcessor.framesPerUserBuffer, stream->in.wavex.Format.nSamplesPerSec);
5229 		sleep_ms_out = GetFramesSleepTime(stream->bufferProcessor.framesPerUserBuffer, stream->out.wavex.Format.nSamplesPerSec);
5230 	}
5231 
5232 	// Choose smallest
5233 	if ((sleep_ms_in != 0) && (sleep_ms_out != 0))
5234 		sleep_ms = min(sleep_ms_in, sleep_ms_out);
5235 	else
5236 	{
5237 		sleep_ms = (sleep_ms_in ? sleep_ms_in : sleep_ms_out);
5238 	}
5239 	// Make sure not 0, othervise use ThreadIdleScheduler
5240 	if (sleep_ms == 0)
5241 	{
5242 		sleep_ms_in  = GetFramesSleepTimeMicroseconds(stream->in.framesPerHostCallback/WASAPI_PACKETS_PER_INPUT_BUFFER, stream->in.wavex.Format.nSamplesPerSec);
5243 		sleep_ms_out = GetFramesSleepTimeMicroseconds(stream->bufferProcessor.framesPerUserBuffer, stream->out.wavex.Format.nSamplesPerSec);
5244 
5245 		// Choose smallest
5246 		if ((sleep_ms_in != 0) && (sleep_ms_out != 0))
5247 			sleep_ms = min(sleep_ms_in, sleep_ms_out);
5248 		else
5249 		{
5250 			sleep_ms = (sleep_ms_in ? sleep_ms_in : sleep_ms_out);
5251 		}
5252 
5253 		// Setup thread sleep scheduler
5254 		ThreadIdleScheduler_Setup(&scheduler, 1, sleep_ms/* microseconds here */);
5255 		sleep_ms = 0;
5256 	}
5257 
5258     // Setup data processors
5259     defaultProcessor.processor = WaspiHostProcessingLoop;
5260     defaultProcessor.userData  = stream;
5261     processor[S_INPUT] = (stream->hostProcessOverrideInput.processor != NULL ? stream->hostProcessOverrideInput : defaultProcessor);
5262     processor[S_OUTPUT] = (stream->hostProcessOverrideOutput.processor != NULL ? stream->hostProcessOverrideOutput : defaultProcessor);
5263 
5264 	// Boost thread priority
5265 	PaWasapi_ThreadPriorityBoost((void **)&stream->hAvTask, stream->nThreadPriority);
5266 
5267 	// Initialize event & start INPUT stream
5268 	if (stream->in.clientProc)
5269 	{
5270 		if ((hr = IAudioClient_Start(stream->in.clientProc)) != S_OK)
5271 		{
5272 			LogHostError(hr);
5273 			goto thread_error;
5274 		}
5275 	}
5276 
5277 	// Initialize event & start OUTPUT stream
5278 	if (stream->out.clientProc)
5279 	{
5280 		// Preload buffer (obligatory, othervise ->Start() will fail), avoid processing
5281 		// when in full-duplex mode as it requires input processing as well
5282 		if (!PA_WASAPI__IS_FULLDUPLEX(stream))
5283 		{
5284 			UINT32 frames = 0;
5285 			if ((hr = _PollGetOutputFramesAvailable(stream, &frames)) == S_OK)
5286             {
5287 				if (stream->bufferMode == paUtilFixedHostBufferSize)
5288 				{
5289 					if (frames >= stream->out.framesPerBuffer)
5290 					{
5291 						frames = stream->out.framesPerBuffer;
5292 
5293 						if ((hr = ProcessOutputBuffer(stream, processor, frames)) != S_OK)
5294 						{
5295 							LogHostError(hr); // not fatal, just log
5296 						}
5297 					}
5298 				}
5299 				else
5300 				{
5301 					if (frames != 0)
5302 					{
5303 						if ((hr = ProcessOutputBuffer(stream, processor, frames)) != S_OK)
5304 						{
5305 							LogHostError(hr); // not fatal, just log
5306 						}
5307 					}
5308 				}
5309             }
5310             else
5311 			{
5312 				LogHostError(hr); // not fatal, just log
5313 			}
5314 		}
5315 
5316 		// Start
5317 		if ((hr = IAudioClient_Start(stream->out.clientProc)) != S_OK)
5318 		{
5319 			LogHostError(hr);
5320 			goto thread_error;
5321 		}
5322 	}
5323 
5324 	// Signal: stream running
5325 	stream->running = TRUE;
5326 
5327 	// Notify: thread started
5328 	SetEvent(stream->hThreadStart);
5329 
5330 	if (!PA_WASAPI__IS_FULLDUPLEX(stream))
5331 	{
5332 		// Processing Loop
5333 		UINT32 next_sleep = sleep_ms;
5334 		while (WaitForSingleObject(stream->hCloseRequest, next_sleep) == WAIT_TIMEOUT)
5335 		{
5336 			// Get next sleep time
5337 			if (sleep_ms == 0)
5338 			{
5339 				next_sleep = ThreadIdleScheduler_NextSleep(&scheduler);
5340 			}
5341 
5342 			for (i = 0; i < S_COUNT; ++i)
5343 			{
5344 				// Process S_INPUT/S_OUTPUT
5345 				switch (i)
5346 				{
5347 				// Input stream
5348 				case S_INPUT: {
5349 
5350 					if (stream->captureClient == NULL)
5351 						break;
5352 
5353 					if ((hr = ProcessInputBuffer(stream, processor)) != S_OK)
5354 					{
5355 						LogHostError(hr);
5356 						goto thread_error;
5357 					}
5358 
5359 					break; }
5360 
5361 				// Output stream
5362 				case S_OUTPUT: {
5363 
5364 					UINT32 frames;
5365 					if (stream->renderClient == NULL)
5366 						break;
5367 
5368 					// get available frames
5369 					if ((hr = _PollGetOutputFramesAvailable(stream, &frames)) != S_OK)
5370 					{
5371 						LogHostError(hr);
5372 						goto thread_error;
5373 					}
5374 
5375 					// output
5376 					if (stream->bufferMode == paUtilFixedHostBufferSize)
5377 					{
5378 						while (frames >= stream->out.framesPerBuffer)
5379 						{
5380 							if ((hr = ProcessOutputBuffer(stream, processor, stream->out.framesPerBuffer)) != S_OK)
5381 							{
5382 								LogHostError(hr);
5383 								goto thread_error;
5384 							}
5385 
5386 							frames -= stream->out.framesPerBuffer;
5387 						}
5388 					}
5389 					else
5390 					{
5391 						if (frames != 0)
5392 						{
5393 							if ((hr = ProcessOutputBuffer(stream, processor, frames)) != S_OK)
5394 							{
5395 								LogHostError(hr);
5396 								goto thread_error;
5397 							}
5398 						}
5399 					}
5400 
5401 					break; }
5402 				}
5403 			}
5404 		}
5405 	}
5406 	else
5407 	{
5408 #if 0
5409 		// Processing Loop
5410 		while (WaitForSingleObject(stream->hCloseRequest, 1) == WAIT_TIMEOUT)
5411 		{
5412 			UINT32 i_frames = 0, i_processed = 0;
5413 			BYTE *i_data = NULL, *o_data = NULL, *o_data_host = NULL;
5414 			DWORD i_flags = 0;
5415 			UINT32 o_frames = 0;
5416 
5417 			// get host input buffer
5418 			if ((hr = IAudioCaptureClient_GetBuffer(stream->captureClient, &i_data, &i_frames, &i_flags, NULL, NULL)) != S_OK)
5419 			{
5420 				if (hr == AUDCLNT_S_BUFFER_EMPTY)
5421 					continue; // no data in capture buffer
5422 
5423 				LogHostError(hr);
5424 				break;
5425 			}
5426 
5427 			// get available frames
5428 			if ((hr = _PollGetOutputFramesAvailable(stream, &o_frames)) != S_OK)
5429 			{
5430 				// release input buffer
5431 				IAudioCaptureClient_ReleaseBuffer(stream->captureClient, 0);
5432 
5433 				LogHostError(hr);
5434 				break;
5435 			}
5436 
5437 			// process equal ammount of frames
5438 			if (o_frames >= i_frames)
5439 			{
5440 				// process input ammount of frames
5441 				UINT32 o_processed = i_frames;
5442 
5443 				// get host output buffer
5444 				if ((hr = IAudioRenderClient_GetBuffer(stream->procRCClient, o_processed, &o_data)) == S_OK)
5445 				{
5446 					// processed amount of i_frames
5447 					i_processed = i_frames;
5448 					o_data_host = o_data;
5449 
5450 					// convert output mono
5451 					if (stream->out.monoMixer)
5452 					{
5453 						UINT32 mono_frames_size = o_processed * (stream->out.wavex.Format.wBitsPerSample / 8);
5454 						// expand buffer
5455 						if (mono_frames_size > stream->out.monoBufferSize)
5456 						{
5457 							stream->out.monoBuffer = PaWasapi_ReallocateMemory(stream->out.monoBuffer, (stream->out.monoBufferSize = mono_frames_size));
5458 							if (stream->out.monoBuffer == NULL)
5459 							{
5460 								// release input buffer
5461 								IAudioCaptureClient_ReleaseBuffer(stream->captureClient, 0);
5462 								// release output buffer
5463 								IAudioRenderClient_ReleaseBuffer(stream->renderClient, 0, 0);
5464 
5465 								LogPaError(paInsufficientMemory);
5466 								break;
5467 							}
5468 						}
5469 
5470 						// replace buffer pointer
5471 						o_data = (BYTE *)stream->out.monoBuffer;
5472 					}
5473 
5474 					// convert input mono
5475 					if (stream->in.monoMixer)
5476 					{
5477 						UINT32 mono_frames_size = i_processed * (stream->in.wavex.Format.wBitsPerSample / 8);
5478 						// expand buffer
5479 						if (mono_frames_size > stream->in.monoBufferSize)
5480 						{
5481 							stream->in.monoBuffer = PaWasapi_ReallocateMemory(stream->in.monoBuffer, (stream->in.monoBufferSize = mono_frames_size));
5482 							if (stream->in.monoBuffer == NULL)
5483 							{
5484 								// release input buffer
5485 								IAudioCaptureClient_ReleaseBuffer(stream->captureClient, 0);
5486 								// release output buffer
5487 								IAudioRenderClient_ReleaseBuffer(stream->renderClient, 0, 0);
5488 
5489 								LogPaError(paInsufficientMemory);
5490 								break;
5491 							}
5492 						}
5493 
5494 						// mix 2 to 1 input channels
5495 						stream->in.monoMixer(stream->in.monoBuffer, i_data, i_processed);
5496 
5497 						// replace buffer pointer
5498 						i_data = (BYTE *)stream->in.monoBuffer;
5499 					}
5500 
5501 					// process
5502 					processor[S_FULLDUPLEX].processor(i_data, i_processed, o_data, o_processed, processor[S_FULLDUPLEX].userData);
5503 
5504 					// mix 1 to 2 output channels
5505 					if (stream->out.monoBuffer)
5506 						stream->out.monoMixer(o_data_host, stream->out.monoBuffer, o_processed);
5507 
5508 					// release host output buffer
5509 					if ((hr = IAudioRenderClient_ReleaseBuffer(stream->renderClient, o_processed, 0)) != S_OK)
5510 						LogHostError(hr);
5511 				}
5512 				else
5513 				{
5514 					if (stream->out.shareMode != AUDCLNT_SHAREMODE_SHARED)
5515 						LogHostError(hr); // be silent in shared mode, try again next time
5516 				}
5517 			}
5518 
5519 			// release host input buffer
5520 			if ((hr = IAudioCaptureClient_ReleaseBuffer(stream->captureClient, i_processed)) != S_OK)
5521 			{
5522 				LogHostError(hr);
5523 				break;
5524 			}
5525 		}
5526 #else
5527 		// Processing Loop
5528 		UINT32 next_sleep = sleep_ms;
5529 		while (WaitForSingleObject(stream->hCloseRequest, next_sleep) == WAIT_TIMEOUT)
5530 		{
5531 			UINT32 i_frames = 0, i_processed = 0;
5532 			BYTE *i_data = NULL, *o_data = NULL, *o_data_host = NULL;
5533 			DWORD i_flags = 0;
5534 			UINT32 o_frames = 0;
5535 
5536 			// Get next sleep time
5537 			if (sleep_ms == 0)
5538 			{
5539 				next_sleep = ThreadIdleScheduler_NextSleep(&scheduler);
5540 			}
5541 
5542 			// get available frames
5543 			if ((hr = _PollGetOutputFramesAvailable(stream, &o_frames)) != S_OK)
5544 			{
5545 				LogHostError(hr);
5546 				break;
5547 			}
5548 
5549 			while (o_frames != 0)
5550 			{
5551 				// get host input buffer
5552 				if ((hr = IAudioCaptureClient_GetBuffer(stream->captureClient, &i_data, &i_frames, &i_flags, NULL, NULL)) != S_OK)
5553 				{
5554 					if (hr == AUDCLNT_S_BUFFER_EMPTY)
5555 						break; // no data in capture buffer
5556 
5557 					LogHostError(hr);
5558 					break;
5559 				}
5560 
5561 				// process equal ammount of frames
5562 				if (o_frames >= i_frames)
5563 				{
5564 					// process input ammount of frames
5565 					UINT32 o_processed = i_frames;
5566 
5567 					// get host output buffer
5568 					if ((hr = IAudioRenderClient_GetBuffer(stream->renderClient, o_processed, &o_data)) == S_OK)
5569 					{
5570 						// processed amount of i_frames
5571 						i_processed = i_frames;
5572 						o_data_host = o_data;
5573 
5574 						// convert output mono
5575 						if (stream->out.monoMixer)
5576 						{
5577 							UINT32 mono_frames_size = o_processed * (stream->out.wavex.Format.wBitsPerSample / 8);
5578 							// expand buffer
5579 							if (mono_frames_size > stream->out.monoBufferSize)
5580 							{
5581 								stream->out.monoBuffer = PaWasapi_ReallocateMemory(stream->out.monoBuffer, (stream->out.monoBufferSize = mono_frames_size));
5582 								if (stream->out.monoBuffer == NULL)
5583 								{
5584 									// release input buffer
5585 									IAudioCaptureClient_ReleaseBuffer(stream->captureClient, 0);
5586 									// release output buffer
5587 									IAudioRenderClient_ReleaseBuffer(stream->renderClient, 0, 0);
5588 
5589 									LogPaError(paInsufficientMemory);
5590 									goto thread_error;
5591 								}
5592 							}
5593 
5594 							// replace buffer pointer
5595 							o_data = (BYTE *)stream->out.monoBuffer;
5596 						}
5597 
5598 						// convert input mono
5599 						if (stream->in.monoMixer)
5600 						{
5601 							UINT32 mono_frames_size = i_processed * (stream->in.wavex.Format.wBitsPerSample / 8);
5602 							// expand buffer
5603 							if (mono_frames_size > stream->in.monoBufferSize)
5604 							{
5605 								stream->in.monoBuffer = PaWasapi_ReallocateMemory(stream->in.monoBuffer, (stream->in.monoBufferSize = mono_frames_size));
5606 								if (stream->in.monoBuffer == NULL)
5607 								{
5608 									// release input buffer
5609 									IAudioCaptureClient_ReleaseBuffer(stream->captureClient, 0);
5610 									// release output buffer
5611 									IAudioRenderClient_ReleaseBuffer(stream->renderClient, 0, 0);
5612 
5613 									LogPaError(paInsufficientMemory);
5614 									goto thread_error;
5615 								}
5616 							}
5617 
5618 							// mix 2 to 1 input channels
5619 							stream->in.monoMixer(stream->in.monoBuffer, i_data, i_processed);
5620 
5621 							// replace buffer pointer
5622 							i_data = (BYTE *)stream->in.monoBuffer;
5623 						}
5624 
5625 						// process
5626 						processor[S_FULLDUPLEX].processor(i_data, i_processed, o_data, o_processed, processor[S_FULLDUPLEX].userData);
5627 
5628 						// mix 1 to 2 output channels
5629 						if (stream->out.monoBuffer)
5630 							stream->out.monoMixer(o_data_host, stream->out.monoBuffer, o_processed);
5631 
5632 						// release host output buffer
5633 						if ((hr = IAudioRenderClient_ReleaseBuffer(stream->renderClient, o_processed, 0)) != S_OK)
5634 							LogHostError(hr);
5635 
5636 						o_frames -= o_processed;
5637 					}
5638 					else
5639 					{
5640 						if (stream->out.shareMode != AUDCLNT_SHAREMODE_SHARED)
5641 							LogHostError(hr); // be silent in shared mode, try again next time
5642 					}
5643 				}
5644 				else
5645 				{
5646 					i_processed = 0;
5647 					goto fd_release_buffer_in;
5648 				}
5649 
5650 fd_release_buffer_in:
5651 
5652 				// release host input buffer
5653 				if ((hr = IAudioCaptureClient_ReleaseBuffer(stream->captureClient, i_processed)) != S_OK)
5654 				{
5655 					LogHostError(hr);
5656 					break;
5657 				}
5658 
5659 				// break processing, input hasn't been accumulated yet
5660 				if (i_processed == 0)
5661 					break;
5662 			}
5663 		}
5664 #endif
5665 	}
5666 
5667 thread_end:
5668 
5669 	// Process stop
5670 	_StreamOnStop(stream);
5671 
5672 	// Release unmarshaled COM pointers
5673 	ReleaseUnmarshaledComPointers(stream);
5674 
5675 	// Cleanup COM for this thread
5676 	if (bThreadComInitialized == TRUE)
5677 		CoUninitialize();
5678 
5679 	// Notify: not running
5680 	stream->running = FALSE;
5681 
5682 	// Notify: thread exited
5683 	SetEvent(stream->hThreadExit);
5684 
5685 	return 0;
5686 
5687 thread_error:
5688 
5689 	// Prevent deadlocking in Pa_StreamStart
5690 	SetEvent(stream->hThreadStart);
5691 
5692 	// Exit
5693 	goto thread_end;
5694 }
5695 
5696 // ------------------------------------------------------------------------------------------
PaWasapi_ReallocateMemory(void * ptr,size_t size)5697 void *PaWasapi_ReallocateMemory(void *ptr, size_t size)
5698 {
5699 	return realloc(ptr, size);
5700 }
5701 
5702 // ------------------------------------------------------------------------------------------
PaWasapi_FreeMemory(void * ptr)5703 void PaWasapi_FreeMemory(void *ptr)
5704 {
5705 	free(ptr);
5706 }
5707 
5708 //#endif //VC 2005
5709 
5710 
5711 
5712 
5713 #if 0
5714 			if(bFirst) {
5715 				float masteur;
5716 				hr = stream->outVol->GetMasterVolumeLevelScalar(&masteur);
5717 				if (hr != S_OK)
5718 					LogHostError(hr);
5719 				float chan1, chan2;
5720 				hr = stream->outVol->GetChannelVolumeLevelScalar(0, &chan1);
5721 				if (hr != S_OK)
5722 					LogHostError(hr);
5723 				hr = stream->outVol->GetChannelVolumeLevelScalar(1, &chan2);
5724 				if (hr != S_OK)
5725 					LogHostError(hr);
5726 
5727 				BOOL bMute;
5728 				hr = stream->outVol->GetMute(&bMute);
5729 				if (hr != S_OK)
5730 					LogHostError(hr);
5731 
5732 				stream->outVol->SetMasterVolumeLevelScalar(0.5, NULL);
5733 				stream->outVol->SetChannelVolumeLevelScalar(0, 0.5, NULL);
5734 				stream->outVol->SetChannelVolumeLevelScalar(1, 0.5, NULL);
5735 				stream->outVol->SetMute(FALSE, NULL);
5736 				bFirst = FALSE;
5737 			}
5738 #endif
5739