]> Repos - portaudio/commitdiff
wasapi:
authordmitrykos <dmitrykos@0f58301d-fd10-0410-b4af-bbb618454e57>
Sun, 11 Apr 2010 16:04:21 +0000 (16:04 +0000)
committerdmitrykos <dmitrykos@0f58301d-fd10-0410-b4af-bbb618454e57>
Sun, 11 Apr 2010 16:04:21 +0000 (16:04 +0000)
 - fixed AUDCLNT_E_INVALID_DEVICE_PERIOD under Windows 7 if latency is set to lower than minimal device period
 - fixed AUDCLNT_E_INVALID_DEVICE_PERIOD under Windows 7 if latency for Exclusive mode is higher than 500ms, for Shared mode higher than 2000ms

src/hostapi/wasapi/pa_win_wasapi.c

index cb14cf5d9bef8432c786b64945e42b3590037dca..d7f58f851a158a90ecf9d6e15db8401a33d6d56c 100644 (file)
@@ -794,64 +794,72 @@ static BOOL IsWow64()
 // ------------------------------------------------------------------------------------------\r
 typedef enum EWindowsVersion\r
 {\r
-       WINDOWS_UNKNOWN,\r
-       WINDOWS_VISTA_SERVER2008,\r
-       WINDOWS_7_SERVER2008R2\r
+       WINDOWS_UNKNOWN                                 = 0,\r
+       WINDOWS_VISTA_SERVER2008                = (1 << 0),\r
+       WINDOWS_7_SERVER2008R2                  = (1 << 1),\r
+       WINDOWS_7_SERVER2008R2_AND_UP   = (1 << 2)\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
+static UINT32 GetWindowsVersion()\r
 {\r
-    DWORD dwVersion = 0;\r
-       DWORD dwMajorVersion = 0;\r
-       DWORD dwMinorVersion = 0;\r
-       DWORD dwBuild = 0;\r
+       static UINT32 version = WINDOWS_UNKNOWN;\r
 \r
-       typedef DWORD (WINAPI *LPFN_GETVERSION)(VOID);\r
-       LPFN_GETVERSION fnGetVersion;\r
+       if (version == WINDOWS_UNKNOWN)\r
+       {\r
+               DWORD dwVersion = 0;\r
+               DWORD dwMajorVersion = 0;\r
+               DWORD dwMinorVersion = 0;\r
+               DWORD dwBuild = 0;\r
 \r
-    fnGetVersion = (LPFN_GETVERSION) GetProcAddress(\r
-               GetModuleHandle(TEXT("kernel32")), TEXT("GetVersion"));\r
+               typedef DWORD (WINAPI *LPFN_GETVERSION)(VOID);\r
+               LPFN_GETVERSION fnGetVersion;\r
 \r
-       if (fnGetVersion == NULL)\r
-               return WINDOWS_UNKNOWN;\r
+               fnGetVersion = (LPFN_GETVERSION) GetProcAddress(GetModuleHandle(TEXT("kernel32")), TEXT("GetVersion"));\r
+               if (fnGetVersion == NULL)\r
+                       return WINDOWS_UNKNOWN;\r
 \r
-    dwVersion = fnGetVersion();\r
+               dwVersion = fnGetVersion();\r
 \r
-    // Get the Windows version\r
-    dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));\r
-    dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));\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
+               // 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
+               switch (dwMajorVersion)\r
                {\r
-               case 0:\r
-                       return WINDOWS_VISTA_SERVER2008;\r
-               case 1:\r
-                       return WINDOWS_7_SERVER2008R2;\r
+               case 6:\r
+                       switch (dwMinorVersion)\r
+                       {\r
+                       case 0:\r
+                               version |= WINDOWS_VISTA_SERVER2008;\r
+                               break;\r
+                       case 1:\r
+                               version |= WINDOWS_7_SERVER2008R2;\r
+                               break;\r
+                       default:\r
+                               version |= (WINDOWS_7_SERVER2008R2|WINDOWS_7_SERVER2008R2_AND_UP);\r
+                       }\r
                }\r
        }\r
 \r
-       return WINDOWS_UNKNOWN;\r
+       return version;\r
 }\r
 \r
 // ------------------------------------------------------------------------------------------\r
 static BOOL UseWOW64VistaWorkaround()\r
 {\r
-       return (IsWow64() && (GetWindowsVersion() == WINDOWS_VISTA_SERVER2008));\r
+       return (IsWow64() && (GetWindowsVersion() & WINDOWS_VISTA_SERVER2008));\r
 }\r
 \r
 // ------------------------------------------------------------------------------------------\r
 #define _WASAPI_MONO_TO_STEREO_MIXER(TYPE)\\r
-       TYPE * __restrict to   = (TYPE *)__to;\\r
-       TYPE * __restrict from = (TYPE *)__from;\\r
+       TYPE * __restrict to   = __to;\\r
+       TYPE * __restrict from = __from;\\r
        TYPE * __restrict end  = from + count;\\r
        while (from != end)\\r
        {\\r
@@ -1878,6 +1886,38 @@ static HRESULT CreateAudioClient(PaWasapiSubStream *pSubStream, PaWasapiDeviceIn
                        pSubStream->period = info->DefaultDevicePeriod;\r
        }\r
 \r
+       // Windows 7 does not allow to set latency lower than minimal device period and will\r
+       // return error: AUDCLNT_E_INVALID_DEVICE_PERIOD. Under Vista though this error is not implemented\r
+       // allowing to hack WASAPI device with lower period resulting in possibly lower latency.\r
+       if (GetWindowsVersion() & WINDOWS_7_SERVER2008R2_AND_UP)\r
+       {\r
+               if (pSubStream->period < info->MinimumDevicePeriod)\r
+                       pSubStream->period = info->MinimumDevicePeriod;\r
+\r
+               /*\r
+                       AUDCLNT_E_BUFFER_SIZE_ERROR: Applies to Windows 7 and later.\r
+                       Indicates that the buffer duration value requested by an exclusive-mode client is \r
+                       out of range. The requested duration value for pull mode must not be greater than \r
+                       500 milliseconds; for push mode the duration value must not be greater than 2 seconds.\r
+               */\r
+               if (pSubStream->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)\r
+               {\r
+static const REFERENCE_TIME MAX_BUFFER_EVENT_DURATION = 500  * 10000;\r
+static const REFERENCE_TIME MAX_BUFFER_POLL_DURATION  = 2000 * 10000;\r
+\r
+                       if (streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) // pull mode, max 500ms\r
+                       {\r
+                               if (pSubStream->period > MAX_BUFFER_EVENT_DURATION)\r
+                                       pSubStream->period = MAX_BUFFER_EVENT_DURATION;\r
+                       }\r
+                       else                                                                                             // push mode, max 2000ms\r
+                       {\r
+                               if (pSubStream->period > MAX_BUFFER_POLL_DURATION)\r
+                                       pSubStream->period = MAX_BUFFER_POLL_DURATION;\r
+                       }\r
+               }\r
+       }\r
+\r
        // Open the stream and associate it with an audio session\r
     hr = IAudioClient_Initialize(pAudioClient,\r
         pSubStream->shareMode,\r
@@ -1930,6 +1970,15 @@ static HRESULT CreateAudioClient(PaWasapiSubStream *pSubStream, PaWasapiDeviceIn
                // Calculate period\r
                pSubStream->period = MakeHnsPeriod(nFrames, pSubStream->wavex.Format.nSamplesPerSec);\r
 \r
+               // Windows 7 does not allow to set latency lower than minimal device period and will\r
+               // return error: AUDCLNT_E_INVALID_DEVICE_PERIOD. Under Vista though this error is not implemented\r
+               // allowing to hack WASAPI device with lower period resulting in possibly lower latency.\r
+               if (GetWindowsVersion() & WINDOWS_7_SERVER2008R2_AND_UP)\r
+               {\r
+                       if (pSubStream->period < info->MinimumDevicePeriod)\r
+                               pSubStream->period = info->MinimumDevicePeriod;\r
+               }\r
+\r
         // Open the stream and associate it with an audio session\r
         hr = IAudioClient_Initialize(pAudioClient,\r
             pSubStream->shareMode,\r