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