]> Repos - portaudio/commitdiff
windows WASAPI fixes/improvements:
authordmitrykos <dmitrykos@0f58301d-fd10-0410-b4af-bbb618454e57>
Fri, 19 Feb 2010 11:16:01 +0000 (11:16 +0000)
committerdmitrykos <dmitrykos@0f58301d-fd10-0410-b4af-bbb618454e57>
Fri, 19 Feb 2010 11:16:01 +0000 (11:16 +0000)
- fixed dependency of framesPerBuffer parameter in Pa_OpenStream and latency (now only latency setting affects device latency which is correct behavior);
- paFramesPerBufferUnspecified is now supported for Pa_OpenStream;
- sound distortion fixed for Shared mode if framesPerBuffer is lower than device limit and when latency was set to 0;
- fixed timeout for Exclusive mode due to buffer misalignment;
- improved precision of DAC/ADC time for running stream;
- avoided memory leaks on failure of Pa_OpenStream;
- NULL checks on stream pointer for all external methods;
- correct host buffer mode for paWinWasapiPolling mode to deliver fixed number of frames to user space;
- implemented workaround for Vista x64 WOW64 bug if Event-mode is used for Shared mode (due to incorrect Event signaling audio dropouts were happening): will fall back to safe Polling method automatically.

src/hostapi/wasapi/pa_win_wasapi.cpp

index 86b0267f764f703a4444a25a3de95a3304c91800..9540398c4f634982fa2993f6bb164de562002b3e 100644 (file)
@@ -102,7 +102,7 @@ enum { S_INPUT = 0, S_OUTPUT, S_COUNT };
 #define PRINT(x) PA_DEBUG(x);\r
 \r
 #define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \\r
-    PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )\r
+    PaUtil_SetLastHostErrorInfo( paWASAPI, errorCode, errorText )\r
 \r
 #ifndef IF_FAILED_JUMP\r
 #define IF_FAILED_JUMP(hr, label) if(FAILED(hr)) goto label;\r
@@ -243,7 +243,10 @@ typedef struct
     WCHAR defaultRenderer [MAX_STR_LEN];\r
     WCHAR defaultCapturer [MAX_STR_LEN];\r
 \r
-    PaWasapiDeviceInfo   *devInfo;\r
+    PaWasapiDeviceInfo *devInfo;\r
+\r
+       // Is true when WOW64 Vista Workaround is needed\r
+       bool useVistaWOW64Workaround;\r
 }\r
 PaWasapiHostApiRepresentation;\r
 \r
@@ -254,7 +257,7 @@ typedef struct PaWasapiSubStream
     IAudioClient        *client;\r
     WAVEFORMATEXTENSIBLE wavex;\r
     UINT32               bufferSize;\r
-    REFERENCE_TIME       latency;\r
+    REFERENCE_TIME       device_latency;\r
     REFERENCE_TIME       period;\r
        double                           latency_seconds;\r
     UINT32                              framesPerHostCallback;\r
@@ -478,7 +481,7 @@ static UINT32 AlignFramesPerBuffer(UINT32 nFrames, UINT32 nSamplesPerSec, UINT32
 {\r
 #define HDA_PACKET_SIZE 128\r
 \r
-       long packets_total = nSamplesPerSec * nBlockAlign / HDA_PACKET_SIZE;\r
+       long packets_total = 10000 * (nSamplesPerSec * nBlockAlign / HDA_PACKET_SIZE);\r
        long frame_bytes   = nFrames * nBlockAlign;\r
        \r
        // align to packet size\r
@@ -538,6 +541,89 @@ static void CloseAVRT()
        hDInputDLL = NULL;\r
 }\r
 \r
+// ------------------------------------------------------------------------------------------\r
+static BOOL IsWow64()\r
+{\r
+       // http://msdn.microsoft.com/en-us/library/ms684139(VS.85).aspx\r
+\r
+       typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);\r
+       LPFN_ISWOW64PROCESS fnIsWow64Process;\r
+\r
+    BOOL bIsWow64 = FALSE;\r
+\r
+    // IsWow64Process is not available on all supported versions of Windows.\r
+    // Use GetModuleHandle to get a handle to the DLL that contains the function\r
+    // and GetProcAddress to get a pointer to the function if available.\r
+\r
+    fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(\r
+        GetModuleHandle(TEXT("kernel32")), TEXT("IsWow64Process"));\r
+\r
+    if (fnIsWow64Process == NULL)\r
+               return FALSE;\r
+\r
+    if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64))\r
+               return FALSE;\r
+\r
+    return bIsWow64;\r
+}\r
+\r
+// ------------------------------------------------------------------------------------------\r
+typedef enum EWindowsVersion\r
+{\r
+       WINDOWS_UNKNOWN,\r
+       WINDOWS_VISTA_SERVER2008,\r
+       WINDOWS_7_SERVER2008R2\r
+}\r
+EWindowsVersion;\r
+// The function is limited to Vista/7 mostly as we need just to find out Vista/WOW64 combination\r
+// in order to use WASAPI WOW64 workarounds.\r
+static EWindowsVersion GetWindowsVersion()\r
+{\r
+    DWORD dwVersion = 0; \r
+       DWORD dwMajorVersion = 0;\r
+       DWORD dwMinorVersion = 0; \r
+       DWORD dwBuild = 0;\r
+\r
+       typedef DWORD (WINAPI *LPFN_GETVERSION)(VOID);\r
+       LPFN_GETVERSION fnGetVersion;\r
+\r
+    fnGetVersion = (LPFN_GETVERSION) GetProcAddress(\r
+               GetModuleHandle(TEXT("kernel32")), TEXT("GetVersion"));\r
+       \r
+       if (fnGetVersion == NULL)\r
+               return WINDOWS_UNKNOWN;\r
+\r
+    dwVersion = fnGetVersion();\r
\r
+    // Get the Windows version\r
+    dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));\r
+    dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));\r
+\r
+    // Get the build number\r
+    if (dwVersion < 0x80000000)              \r
+        dwBuild = (DWORD)(HIWORD(dwVersion));\r
+\r
+       switch (dwMajorVersion)\r
+       {\r
+       case 6: \r
+               switch (dwMinorVersion)\r
+               {\r
+               case 0:\r
+                       return WINDOWS_VISTA_SERVER2008;\r
+               case 1:\r
+                       return WINDOWS_7_SERVER2008R2;\r
+               }\r
+       }\r
+\r
+       return WINDOWS_UNKNOWN;\r
+}\r
+\r
+// ------------------------------------------------------------------------------------------\r
+static bool UseWOW64VistaWorkaround()\r
+{\r
+       return (::IsWow64() && (::GetWindowsVersion() == WINDOWS_VISTA_SERVER2008));\r
+}\r
+\r
 // ------------------------------------------------------------------------------------------\r
 PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )\r
 {\r
@@ -834,6 +920,10 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
                                       GetStreamTime, PaUtil_DummyGetCpuLoad,\r
                                       ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );\r
 \r
+\r
+       // findout if platform workaround is required\r
+       paWasapi->useVistaWOW64Workaround = ::UseWOW64VistaWorkaround();\r
+\r
     SAFE_RELEASE(pEndPoints);\r
 \r
     return result;\r
@@ -1274,7 +1364,10 @@ static PaError IsStreamParamsValid(struct PaUtilHostApiRepresentation *hostApi,
                                    const  PaStreamParameters *outputParameters,\r
                                    double sampleRate)\r
 {\r
-    if (inputParameters != NULL)\r
+       if (hostApi == NULL)\r
+               return paHostApiNotFound;\r
+       \r
+       if (inputParameters != NULL)\r
     {\r
         /* all standard sample formats are supported by the buffer adapter,\r
             this implementation doesn't support any custom sample formats */\r
@@ -1407,12 +1500,12 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
 \r
 // ------------------------------------------------------------------------------------------\r
 static HRESULT CreateAudioClient(PaWasapiSubStream *pSubStream, PaWasapiDeviceInfo *info,\r
-       const PaStreamParameters *params, UINT32 framesPerBuffer, double sampleRate, UINT32 streamFlags, \r
+       const PaStreamParameters *params, UINT32 framesPerLatency, double sampleRate, UINT32 streamFlags, \r
        PaError *pa_error)\r
 {\r
     if (!pSubStream || !info || !params)\r
         return E_POINTER;\r
-    if ((sampleRate == 0) || (framesPerBuffer == 0))\r
+       if ((UINT32)sampleRate == 0)\r
         return E_INVALIDARG;\r
 \r
        PaError error;\r
@@ -1436,19 +1529,32 @@ static HRESULT CreateAudioClient(PaWasapiSubStream *pSubStream, PaWasapiDeviceIn
                return AUDCLNT_E_UNSUPPORTED_FORMAT;\r
        }\r
 \r
-       // Align frames\r
-       framesPerBuffer = AlignFramesPerBuffer(framesPerBuffer, \r
-               pSubStream->wavex.Format.nSamplesPerSec, pSubStream->wavex.Format.nBlockAlign);\r
+       // Add latency frames\r
+       framesPerLatency += MakeFramesFromHns(SecondsTonano100(params->suggestedLatency), pSubStream->wavex.Format.nSamplesPerSec);\r
+\r
+       // Align frames to HD Audio packet size of 128 bytes for Exclusive mode only.\r
+       // Not aligning on Windows Vista will cause Event timeout, although Windows 7 will\r
+       // return AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED error to realign buffer. Aligning is necessary\r
+       // for Exclusive mode only! when audio data is feeded directly to hardware.\r
+       if (pSubStream->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)\r
+       {\r
+               framesPerLatency = AlignFramesPerBuffer(framesPerLatency, \r
+                       pSubStream->wavex.Format.nSamplesPerSec, pSubStream->wavex.Format.nBlockAlign);\r
+       }\r
 \r
     // Calculate period\r
-       pSubStream->period  = MakeHnsPeriod(framesPerBuffer, pSubStream->wavex.Format.nSamplesPerSec);\r
-       pSubStream->period += ::SecondsTonano100(params->suggestedLatency);\r
+       pSubStream->period = MakeHnsPeriod(framesPerLatency, pSubStream->wavex.Format.nSamplesPerSec);\r
        \r
-       // Let's do not enforce min, it is even a bug as MinimumDevicePeriod will make buffer not aligned\r
-       // on Vista\r
-       //pSubStream->period  = (pSubStream->period < info->MinimumDevicePeriod ? info->MinimumDevicePeriod : pSubStream->period);\r
+       // Enforce min/max period for device in Shared mode to avoid distorted sound.\r
+       // Avoid doing so for Exclusive mode as alignment will suffer. Exclusive mode processes\r
+       // big buffers without problem. Push Exclusive beyond limits if possible.\r
+       if (pSubStream->shareMode == AUDCLNT_SHAREMODE_SHARED)\r
+       {\r
+               if (pSubStream->period < info->DefaultDevicePeriod)\r
+                       pSubStream->period = info->DefaultDevicePeriod;\r
+       }\r
 \r
-    // Open the stream and associate it with an audio session\r
+       // Open the stream and associate it with an audio session\r
     hr = pAudioClient->Initialize( \r
         pSubStream->shareMode,\r
         streamFlags/*AUDCLNT_STREAMFLAGS_EVENTCALLBACK*/, \r
@@ -1509,14 +1615,6 @@ static HRESULT CreateAudioClient(PaWasapiSubStream *pSubStream, PaWasapiDeviceIn
                goto done;\r
     }\r
 \r
-    // Get the next aligned frame\r
-    hr = pAudioClient->GetBufferSize(&nFrames);\r
-       if (hr != S_OK)\r
-       {\r
-               LogHostError(hr);\r
-               goto done;\r
-       }\r
-    \r
     // Set result\r
        pSubStream->client = pAudioClient;\r
     pSubStream->client->AddRef();\r
@@ -1546,6 +1644,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
     PaSampleFormat inputSampleFormat, outputSampleFormat;\r
     PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;\r
        PaWasapiStreamInfo *inputStreamInfo = NULL, *outputStreamInfo = NULL;\r
+       PaWasapiDeviceInfo *info = NULL;\r
 \r
        // validate PaStreamParameters\r
        if ((result = IsStreamParamsValid(hostApi, inputParameters, outputParameters, sampleRate)) != paNoError)\r
@@ -1568,13 +1667,31 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
        // Default thread priority is Audio: for exclusive mode we will use Pro Audio.\r
        stream->nThreadPriority = eThreadPriorityAudio;\r
 \r
+       // Set default number of frames: paFramesPerBufferUnspecified\r
+       if (framesPerBuffer == paFramesPerBufferUnspecified)\r
+       {       \r
+               UINT32 framesPerBufferIn  = 0, framesPerBufferOut = 0;\r
+               if (inputParameters != NULL)\r
+               {\r
+                       info = &paWasapi->devInfo[inputParameters->device];\r
+                       framesPerBufferIn = MakeFramesFromHns(info->DefaultDevicePeriod, (UINT32)sampleRate);\r
+               }\r
+               if (outputParameters != NULL)\r
+               {\r
+                       info = &paWasapi->devInfo[outputParameters->device];\r
+                       framesPerBufferOut = MakeFramesFromHns(info->DefaultDevicePeriod, (UINT32)sampleRate);\r
+               }\r
+               // choosing maximum default size\r
+               framesPerBuffer = max(framesPerBufferIn, framesPerBufferOut);\r
+       }\r
+\r
        // Try create device: Input\r
        if (inputParameters != NULL)\r
     {\r
         inputChannelCount = inputParameters->channelCount;\r
         inputSampleFormat = inputParameters->sampleFormat;\r
                inputStreamInfo   = (PaWasapiStreamInfo *)inputParameters->hostApiSpecificStreamInfo;\r
-        PaWasapiDeviceInfo *info = &paWasapi->devInfo[inputParameters->device];\r
+        info              = &paWasapi->devInfo[inputParameters->device];\r
                stream->in.flags  = (inputStreamInfo ? inputStreamInfo->flags : 0);\r
 \r
                // Select Exclusive/Shared mode\r
@@ -1597,13 +1714,15 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
 \r
                // Choose processing mode\r
                stream->in.streamFlags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;\r
+               if (paWasapi->useVistaWOW64Workaround)\r
+                       stream->in.streamFlags = 0; // polling interface\r
                if (streamCallback == NULL)\r
                        stream->in.streamFlags = 0; // polling interface\r
                if ((inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiPolling))\r
                        stream->in.streamFlags = 0; // polling interface\r
 \r
                // Create Audio client\r
-               HRESULT hr = CreateAudioClient(&stream->in, info, inputParameters, framesPerBuffer\r
+               HRESULT hr = CreateAudioClient(&stream->in, info, inputParameters, 0/*framesPerLatency*/\r
                        sampleRate, stream->in.streamFlags, &result);\r
         if (hr != S_OK)\r
                {\r
@@ -1616,6 +1735,9 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
         }\r
                LogWAVEFORMATEXTENSIBLE(&stream->in.wavex);\r
 \r
+               // Get closest format\r
+        hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->in.wavex), inputSampleFormat );\r
+\r
                // Create volume mgr\r
                stream->inVol = NULL;\r
         /*hResult = info->device->Activate(\r
@@ -1638,31 +1760,34 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
         if (hr != S_OK)\r
                {\r
                        LogHostError(hr);\r
-            return paInvalidDevice;\r
+                       LogPaError(result = paInvalidDevice);\r
+                       goto error;\r
                }\r
 \r
         // Correct buffer to max size if it maxed out result of GetBufferSize\r
-               stream->in.bufferSize = (framesPerBuffer > maxBufferSize ? maxBufferSize : framesPerBuffer);\r
+               stream->in.bufferSize = maxBufferSize;\r
 \r
-               // Get stream latency\r
-        hr = stream->in.client->GetStreamLatency(&stream->in.latency);\r
+               // Get interface latency (actually uneeded as we calculate latency from the size\r
+               // of maxBufferSize).\r
+        hr = stream->in.client->GetStreamLatency(&stream->in.device_latency);\r
         if (hr != S_OK)\r
                {\r
                        LogHostError(hr);\r
-            return paInvalidDevice;\r
+                       LogPaError(result = paInvalidDevice);\r
+                       goto error;\r
                }\r
-               stream->in.latency_seconds = nano100ToSeconds(stream->in.latency);\r
+               //stream->in.latency_seconds = nano100ToSeconds(stream->in.device_latency);\r
 \r
-        // Number of samples that are required at each period\r
-               stream->in.framesPerHostCallback = \r
-                       (stream->in.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE ? maxBufferSize : stream->in.bufferSize);\r
+        // Number of frames that are required at each period\r
+               stream->in.framesPerHostCallback = maxBufferSize;\r
 \r
-               // Get closest format\r
-        hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->in.wavex), inputSampleFormat );\r
+               // Calculate buffer latency\r
+               PaTime buffer_latency = (PaTime)maxBufferSize / stream->in.wavex.Format.nSamplesPerSec;\r
+\r
+               // Append buffer latency to interface latency in shared mode (see GetStreamLatency notes)\r
+               stream->in.latency_seconds += buffer_latency;\r
 \r
-               UINT32 latency = (1000 * maxBufferSize) / stream->in.wavex.Format.nSamplesPerSec + (UINT32)nano100ToMillis(stream->in.latency);\r
-               PRINT(("PaWASAPIOpenStream: (input) framesPerHostCallback: %d\n", (UINT32)stream->in.framesPerHostCallback));\r
-               PRINT(("PaWASAPIOpenStream: (input) latency: %d\n", stream->in.latency));\r
+               PRINT(("PaWASAPIOpenStream(input): framesPerHostCallback[ %d ] latency[ %.02fms ]\n", (UINT32)stream->in.framesPerHostCallback, (float)(stream->in.latency_seconds*1000.0f)));\r
        }\r
     else\r
     {\r
@@ -1676,7 +1801,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
         outputChannelCount = outputParameters->channelCount;\r
         outputSampleFormat = outputParameters->sampleFormat;\r
                outputStreamInfo   = (PaWasapiStreamInfo *)outputParameters->hostApiSpecificStreamInfo;\r
-               PaWasapiDeviceInfo *info = &paWasapi->devInfo[outputParameters->device];\r
+               info               = &paWasapi->devInfo[outputParameters->device];\r
                stream->out.flags  = (outputStreamInfo ? outputStreamInfo->flags : 0);\r
 \r
                // Select Exclusive/Shared mode\r
@@ -1699,13 +1824,15 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
 \r
                // Choose processing mode\r
                stream->out.streamFlags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;\r
+               if (paWasapi->useVistaWOW64Workaround)\r
+                       stream->out.streamFlags = 0; // polling interface\r
                if (streamCallback == NULL)\r
                        stream->out.streamFlags = 0; // polling interface\r
                if ((outputStreamInfo != NULL) && (outputStreamInfo->flags & paWinWasapiPolling))\r
                        stream->out.streamFlags = 0; // polling interface\r
 \r
                // Create Audio client\r
-               HRESULT hr = CreateAudioClient(&stream->out, info, outputParameters, framesPerBuffer\r
+               HRESULT hr = CreateAudioClient(&stream->out, info, outputParameters, 0/*framesPerLatency*/\r
                        sampleRate, stream->out.streamFlags, &result);\r
         if (hr != S_OK)\r
                {\r
@@ -1718,6 +1845,9 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
         }\r
                LogWAVEFORMATEXTENSIBLE(&stream->out.wavex);\r
 \r
+        // Get closest format\r
+        hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->out.wavex), outputSampleFormat );\r
+\r
                // Activate volume\r
                stream->outVol = NULL;\r
         /*hResult = info->device->Activate(\r
@@ -1745,29 +1875,30 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
                }\r
 \r
         // Correct buffer to max size if it maxed out result of GetBufferSize\r
-               stream->out.bufferSize = (framesPerBuffer > maxBufferSize ? maxBufferSize : framesPerBuffer);\r
+               stream->out.bufferSize = maxBufferSize;\r
 \r
-               // Get stream latency\r
-        hr = stream->out.client->GetStreamLatency(&stream->out.latency);\r
+               // Get interface latency (actually uneeded as we calculate latency from the size\r
+               // of maxBufferSize).\r
+        hr = stream->out.client->GetStreamLatency(&stream->out.device_latency);\r
         if (hr != S_OK)\r
                {\r
                        LogHostError(hr);\r
                        LogPaError(result = paInvalidDevice);\r
                        goto error;\r
                }\r
-               stream->out.latency_seconds = nano100ToSeconds(stream->out.latency);\r
+               //stream->out.latency_seconds = nano100ToSeconds(stream->out.device_latency);\r
 \r
-        // Number of samples that are required at each period\r
-               stream->out.framesPerHostCallback = \r
-                       (stream->out.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE ? maxBufferSize : stream->out.bufferSize);\r
+        // Number of frames that are required at each period\r
+               stream->out.framesPerHostCallback = maxBufferSize;\r
 \r
-        // Get closest format\r
-        hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->out.wavex), outputSampleFormat );\r
+               // Calculate buffer latency\r
+               PaTime buffer_latency = (PaTime)maxBufferSize / stream->out.wavex.Format.nSamplesPerSec;\r
 \r
-               UINT32 latency = (1000 * maxBufferSize) / stream->out.wavex.Format.nSamplesPerSec + (UINT32)nano100ToMillis(stream->out.latency);\r
-               PRINT(("PaWASAPIOpenStream: (output) framesPerHostCallback: %d\n", (UINT32)stream->out.framesPerHostCallback));\r
-               PRINT(("PaWASAPIOpenStream: (output) latency: %d\n", latency));\r
-    }\r
+               // Append buffer latency to interface latency in shared mode (see GetStreamLatency notes)\r
+               stream->out.latency_seconds += buffer_latency;\r
+\r
+               PRINT(("PaWASAPIOpenStream(output): framesPerHostCallback[ %d ] latency[ %.02fms ]\n", (UINT32)stream->out.framesPerHostCallback, (float)(stream->out.latency_seconds*1000.0f)));\r
+       }\r
     else\r
     {\r
         outputChannelCount = 0;\r
@@ -1791,19 +1922,23 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
                }\r
        }\r
 \r
+       // Initialize stream representation\r
     if (streamCallback)\r
     {\r
                stream->bBlocking = false;\r
         PaUtil_InitializeStreamRepresentation(&stream->streamRepresentation,\r
-                                              &paWasapi->callbackStreamInterface, streamCallback, userData);\r
+                                              &paWasapi->callbackStreamInterface, \r
+                                                                                         streamCallback, userData);\r
     }\r
     else\r
     {\r
                stream->bBlocking = true;\r
         PaUtil_InitializeStreamRepresentation(&stream->streamRepresentation,\r
-                                              &paWasapi->blockingStreamInterface, streamCallback, userData);\r
+                                              &paWasapi->blockingStreamInterface, \r
+                                                                                         streamCallback, userData);\r
     }\r
 \r
+       // Initialize CPU measurer\r
     PaUtil_InitializeCpuLoadMeasurer(&stream->cpuLoadMeasurer, sampleRate);\r
 \r
        if (outputParameters && inputParameters)\r
@@ -1826,17 +1961,34 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
        ULONG framesPerHostCallback = (outputParameters) ? stream->out.framesPerHostCallback:\r
                stream->in.framesPerHostCallback;\r
 \r
-    /* we assume a fixed host buffer size in this example, but the buffer processor\r
-        can also support bounded and unknown host buffer sizes by passing\r
-        paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of\r
-        paUtilFixedHostBufferSize below.\r
-       */\r
-    result =  PaUtil_InitializeBufferProcessor(&stream->bufferProcessor,\r
-              inputChannelCount, inputSampleFormat, hostInputSampleFormat,\r
-              outputChannelCount, outputSampleFormat, hostOutputSampleFormat,\r
-              sampleRate, streamFlags, framesPerBuffer,\r
-              framesPerHostCallback, paUtilFixedHostBufferSize,\r
-              streamCallback, userData);\r
+       // Choose correct mode of buffer processing:\r
+       // Exclusive/Shared non paWinWasapiPolling mode: paUtilFixedHostBufferSize - always fixed\r
+       // Exclusive/Shared paWinWasapiPolling mode: paUtilBoundedHostBufferSize - may vary\r
+       PaUtilHostBufferSizeMode bufferMode = paUtilFixedHostBufferSize;\r
+       if (inputParameters && \r
+               (!stream->in.streamFlags || ((stream->in.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) == 0)))\r
+               bufferMode = paUtilBoundedHostBufferSize;\r
+       else\r
+       if (outputParameters && \r
+               (!stream->out.streamFlags || ((stream->out.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) == 0)))\r
+               bufferMode = paUtilBoundedHostBufferSize;\r
+\r
+    // Initialize buffer processor\r
+    result =  PaUtil_InitializeBufferProcessor(\r
+               &stream->bufferProcessor,\r
+        inputChannelCount, \r
+               inputSampleFormat, \r
+               hostInputSampleFormat,\r
+        outputChannelCount, \r
+               outputSampleFormat, \r
+               hostOutputSampleFormat,\r
+        sampleRate, \r
+               streamFlags, \r
+               framesPerBuffer,\r
+        framesPerHostCallback, \r
+               bufferMode,\r
+        streamCallback, \r
+               userData);\r
     if (result != paNoError)\r
        {\r
                LogPaError(result);\r
@@ -1853,16 +2005,19 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
             PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)\r
                        + ((outputParameters)?stream->out.latency_seconds :0);\r
 \r
+       // Set SR\r
     stream->streamRepresentation.streamInfo.sampleRate = sampleRate;\r
 \r
     (*s) = (PaStream *)stream;\r
-\r
     return result;\r
 \r
 error:\r
 \r
     if (stream)\r
+       {\r
+               CloseStream(stream);\r
         PaUtil_FreeMemory(stream);\r
+       }\r
 \r
     return result;\r
 }\r
@@ -1873,6 +2028,10 @@ static PaError CloseStream( PaStream* s )
     PaError result = paNoError;\r
     PaWasapiStream *stream = (PaWasapiStream*)s;\r
 \r
+       // validate\r
+       if (s == NULL)\r
+               return paBadStreamPtr;\r
+\r
        // abort active stream\r
        if (IsStreamActive(s))\r
        {\r
@@ -1907,6 +2066,10 @@ static PaError StartStream( PaStream *s )
        HRESULT hr;\r
     PaWasapiStream *stream = (PaWasapiStream*)s;\r
 \r
+       // validate\r
+       if (s == NULL)\r
+               return paBadStreamPtr;\r
+\r
        // check if stream is active already\r
        if (IsStreamActive(s))\r
                return paStreamIsNotStopped;\r
@@ -2023,6 +2186,10 @@ static PaError StopStream( PaStream *s )
 {\r
     PaError result = paNoError;\r
 \r
+       // validate\r
+       if (s == NULL)\r
+               return paBadStreamPtr;\r
+\r
        // Finish stream\r
        _FinishStream((PaWasapiStream *)s);\r
 \r
@@ -2034,6 +2201,10 @@ static PaError AbortStream( PaStream *s )
 {\r
     PaError result = paNoError;\r
 \r
+       // validate\r
+       if (s == NULL)\r
+               return paBadStreamPtr;\r
+\r
        // Finish stream\r
        _FinishStream((PaWasapiStream *)s);\r
 \r
@@ -2058,7 +2229,9 @@ static PaError IsStreamActive( PaStream *s )
 static PaTime GetStreamTime( PaStream *s )\r
 {\r
     PaWasapiStream *stream = (PaWasapiStream*)s;\r
-       if (stream == NULL)\r
+       \r
+       // validate\r
+       if (s == NULL)\r
                return paBadStreamPtr;\r
 \r
     /* suppress unused variable warnings */\r
@@ -2084,8 +2257,14 @@ static double GetStreamCpuLoad( PaStream* s )
 static PaError ReadStream( PaStream* s, void *_buffer, unsigned long _frames )\r
 {\r
     PaWasapiStream *stream = (PaWasapiStream*)s;\r
-       if (stream == NULL)\r
+       \r
+       // validate\r
+       if (s == NULL)\r
                return paBadStreamPtr;\r
+       if (_buffer == NULL)\r
+               return paBadBufferPtr;\r
+       if (_frames == 0)\r
+               return paBufferTooSmall;\r
 \r
        HRESULT hr = S_OK;\r
        UINT32 frames;\r
@@ -2148,8 +2327,13 @@ static PaError WriteStream( PaStream* s, const void *_buffer, unsigned long _fra
 {\r
     PaWasapiStream *stream = (PaWasapiStream*)s;\r
 \r
-       if (stream == NULL)\r
+       // validate\r
+       if (s == NULL)\r
                return paBadStreamPtr;\r
+       if (_buffer == NULL)\r
+               return paBadBufferPtr;\r
+       if (_frames == 0)\r
+               return paBufferTooSmall;\r
 \r
        if (!stream->running)\r
                return paStreamIsStopped;\r
@@ -2274,7 +2458,8 @@ static signed long GetStreamReadAvailable( PaStream* s )
 {\r
     PaWasapiStream *stream = (PaWasapiStream*)s;\r
 \r
-       if (stream == NULL)\r
+       // validate\r
+       if (s == NULL)\r
                return paBadStreamPtr;\r
 \r
        if (!stream->running)\r
@@ -2301,7 +2486,8 @@ static signed long GetStreamWriteAvailable( PaStream* s )
 {\r
     PaWasapiStream *stream = (PaWasapiStream*)s;\r
 \r
-       if (stream == NULL)\r
+       // validate\r
+       if (s == NULL)\r
                return paBadStreamPtr;\r
 \r
        if (!stream->running)\r
@@ -2353,9 +2539,9 @@ static void WaspiHostProcessingLoop( void *inputBuffer,  long inputFrames,
        {\r
                PaTime pending_time;\r
                if ((hResult = stream->in.client->GetCurrentPadding(&pending)) == S_OK)\r
-                       pending_time = ((PaTime)pending / (PaTime)stream->in.wavex.Format.nSamplesPerSec) + stream->in.latency_seconds;\r
+                       pending_time = (PaTime)pending / (PaTime)stream->in.wavex.Format.nSamplesPerSec;\r
                else\r
-                       pending_time = (PaTime)stream->in.framesPerHostCallback / (PaTime)stream->in.wavex.Format.nSamplesPerSec;\r
+                       pending_time = (PaTime)stream->in.latency_seconds;\r
 \r
                timeInfo.inputBufferAdcTime = timeInfo.currentTime + pending_time;\r
        }\r
@@ -2364,9 +2550,9 @@ static void WaspiHostProcessingLoop( void *inputBuffer,  long inputFrames,
        {\r
                PaTime pending_time;\r
                if ((hResult = stream->out.client->GetCurrentPadding(&pending)) == S_OK)\r
-                       pending_time = ((PaTime)pending / (PaTime)stream->out.wavex.Format.nSamplesPerSec) + stream->out.latency_seconds;\r
+                       pending_time = (PaTime)pending / (PaTime)stream->out.wavex.Format.nSamplesPerSec;\r
                else\r
-                       pending_time = (PaTime)stream->out.framesPerHostCallback / (PaTime)stream->out.wavex.Format.nSamplesPerSec;\r
+                       pending_time = (PaTime)stream->out.latency_seconds;\r
 \r
                timeInfo.outputBufferDacTime = timeInfo.currentTime + pending_time;\r
        }\r
@@ -2521,7 +2707,35 @@ static __forceinline HRESULT FillOutputBuffer(PaWasapiStream *stream, PaWasapiHo
 \r
        // Get buffer\r
        if ((hr = stream->rclient->GetBuffer(frames, &data)) != S_OK)\r
-               return LogHostError(hr);\r
+       {\r
+               if (stream->out.shareMode == AUDCLNT_SHAREMODE_SHARED)\r
+               {\r
+                       // Using GetCurrentPadding to overcome AUDCLNT_E_BUFFER_TOO_LARGE in\r
+                       // shared mode results in no sound in Event-driven mode (MSDN does not\r
+                       // document this, or is it WASAPI bug?), thus we better\r
+                       // try to acquire buffer next time when GetBuffer allows to do so.\r
+#if 0\r
+                       // Get Read position\r
+                       UINT32 padding = 0;\r
+                       hr = stream->out.client->GetCurrentPadding(&padding);\r
+                       if (hr != S_OK)\r
+                               return LogHostError(hr);\r
+\r
+                       // Get frames to write\r
+                       frames -= padding;\r
+                       if (frames == 0)\r
+                               return S_OK;\r
+\r
+                       if ((hr = stream->rclient->GetBuffer(frames, &data)) != S_OK)\r
+                               return LogHostError(hr);\r
+#else\r
+                       if (hr == AUDCLNT_E_BUFFER_TOO_LARGE)\r
+                               return S_OK; // be silent in shared mode, try again next time\r
+#endif\r
+               }\r
+               else\r
+                       return LogHostError(hr);\r
+       }\r
 \r
        // Process data\r
        processor[S_OUTPUT].processor(NULL, 0, data, frames, processor[S_OUTPUT].userData);\r
@@ -2660,7 +2874,7 @@ PA_THREAD_FUNC ProcThreadEvent(void *param)
        for (;;)\r
     {\r
            // 2 sec timeout\r
-        dwResult = WaitForMultipleObjects(S_COUNT, event, FALSE, 2000);\r
+        dwResult = WaitForMultipleObjects(S_COUNT, event, FALSE, 10000);\r
 \r
                // Check for close event (after wait for buffers to avoid any calls to user\r
                // callback when hCloseRequest was set)\r
@@ -2673,7 +2887,6 @@ PA_THREAD_FUNC ProcThreadEvent(void *param)
                case WAIT_TIMEOUT: {\r
                        PRINT(("WASAPI Thread: WAIT_TIMEOUT - probably bad audio driver or Vista x64 bug: use paWinWasapiPolling instead\n"));\r
                        goto processing_stop;\r
-                       //SetEvent(stream->hCloseRequest);\r
                        break; }\r
 \r
                // Input stream\r
@@ -2781,14 +2994,15 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
                 break;\r
 \r
                        UINT32 frames = stream->out.framesPerHostCallback;\r
-                       BYTE *data    = NULL;\r
-                       DWORD flags   = 0;\r
 \r
                        // Get Read position\r
                        UINT32 padding = 0;\r
                        hr = stream->out.client->GetCurrentPadding(&padding);\r
-                       if (hr != S_OK || padding == 0)\r
+                       if (hr != S_OK)\r
+                       {\r
+                               LogHostError(hr);\r
                                break;\r
+                       }\r
 \r
                        // Fill buffer\r
                        frames -= padding;\r