gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

pa_win_wasapi.c (192578B)


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