// ------------------------------------------------------------------------------------------\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
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
// 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