]> Repos - portaudio/commitdiff
wasapi: support for setting the WASAPI's AudioClientProperties options via PaWasapiSt...
authordmitrykos <dmitrykos@0f58301d-fd10-0410-b4af-bbb618454e57>
Mon, 19 Oct 2015 11:03:31 +0000 (11:03 +0000)
committerdmitrykos <dmitrykos@0f58301d-fd10-0410-b4af-bbb618454e57>
Mon, 19 Oct 2015 11:03:31 +0000 (11:03 +0000)
include/pa_win_wasapi.h
src/hostapi/wasapi/pa_win_wasapi.c
src/hostapi/wasapi/readme.txt

index 64eb49b02941ce3639562604c801f083a7d69879..40d3a099e03aad4729c85499741d8da22886cb47 100644 (file)
@@ -69,8 +69,8 @@ typedef enum PaWasapiFlags
              method can only provide 15-20ms latency. */\r
     paWinWasapiPolling                  = (1 << 3),\r
 \r
-    /* forces custom thread priority setting. must be used if PaWasapiStreamInfo::threadPriority \r
-       is set to custom value. */\r
+    /* forces custom thread priority setting, must be used if PaWasapiStreamInfo::threadPriority \r
+       is set to a custom value */\r
     paWinWasapiThreadPriority           = (1 << 4)\r
 }\r
 PaWasapiFlags;\r
@@ -91,7 +91,7 @@ typedef void (*PaWasapiHostProcessorCallback) (void *inputBuffer,  long inputFra
                                                void *outputBuffer, long outputFrames,\r
                                                void *userData);\r
 \r
-/* Device role */\r
+/* Device role. */\r
 typedef enum PaWasapiDeviceRole\r
 {\r
     eRoleRemoteNetworkDevice = 0,\r
@@ -109,7 +109,7 @@ typedef enum PaWasapiDeviceRole
 PaWasapiDeviceRole;\r
 \r
 \r
-/* Jack connection type */\r
+/* Jack connection type. */\r
 typedef enum PaWasapiJackConnectionType\r
 {\r
     eJackConnTypeUnknown,\r
@@ -128,10 +128,10 @@ typedef enum PaWasapiJackConnectionType
 PaWasapiJackConnectionType;\r
 \r
 \r
-/* Jack geometric location */\r
+/* Jack geometric location. */\r
 typedef enum PaWasapiJackGeoLocation\r
 {\r
-       eJackGeoLocUnk = 0,\r
+    eJackGeoLocUnk = 0,\r
     eJackGeoLocRear = 0x1, /* matches EPcxGeoLocation::eGeoLocRear */\r
     eJackGeoLocFront,\r
     eJackGeoLocLeft,\r
@@ -151,7 +151,7 @@ typedef enum PaWasapiJackGeoLocation
 PaWasapiJackGeoLocation;\r
 \r
 \r
-/* Jack general location */\r
+/* Jack general location. */\r
 typedef enum PaWasapiJackGenLocation\r
 {\r
     eJackGenLocPrimaryBox = 0,\r
@@ -162,7 +162,7 @@ typedef enum PaWasapiJackGenLocation
 PaWasapiJackGenLocation;\r
 \r
 \r
-/* Jack's type of port */\r
+/* Jack's type of port. */\r
 typedef enum PaWasapiJackPortConnection\r
 {\r
     eJackPortConnJack = 0,\r
@@ -173,7 +173,7 @@ typedef enum PaWasapiJackPortConnection
 PaWasapiJackPortConnection;\r
 \r
 \r
-/* Thread priority */\r
+/* Thread priority. */\r
 typedef enum PaWasapiThreadPriority\r
 {\r
     eThreadPriorityNone = 0,\r
@@ -202,6 +202,42 @@ typedef struct PaWasapiJackDescription
 PaWasapiJackDescription;\r
 \r
 \r
+/* Stream category.\r
+   Note:\r
+    - values are equal to WASAPI AUDIO_STREAM_CATEGORY enum\r
+    - supported since Windows 8.0, noop on earler versions\r
+    - values 1,2 are deprecated on Windows 10 and not included into enumeration\r
+*/\r
+typedef enum PaWasapiStreamCategory\r
+{\r
+    eAudioCategoryOther           = 0,\r
+    eAudioCategoryCommunications  = 3,\r
+    eAudioCategoryAlerts          = 4,\r
+    eAudioCategorySoundEffects    = 5,\r
+    eAudioCategoryGameEffects     = 6,\r
+    eAudioCategoryGameMedia       = 7,\r
+    eAudioCategoryGameChat        = 8,\r
+    eAudioCategorySpeech          = 9,\r
+    eAudioCategoryMovie           = 10,\r
+    eAudioCategoryMedia           = 11\r
+}\r
+PaWasapiStreamCategory;\r
+\r
+\r
+/* Stream option.\r
+   Note:\r
+    - values are equal to WASAPI AUDCLNT_STREAMOPTIONS enum\r
+    - supported since Windows 8.1, noop on earler versions\r
+*/\r
+typedef enum PaWasapiStreamOption\r
+{\r
+    eStreamOptionNone        = 0, //!< default\r
+    eStreamOptionRaw         = 1, //!< bypass WASAPI Audio Engine DSP effects, supported since Windows 8.1\r
+    eStreamOptionMatchFormat = 2  //!< force WASAPI Audio Engine into a stream format, supported since Windows 10\r
+}\r
+PaWasapiStreamOption;\r
+\r
+\r
 /* Stream descriptor. */\r
 typedef struct PaWasapiStreamInfo \r
 {\r
@@ -235,6 +271,12 @@ typedef struct PaWasapiStreamInfo
        to setup thread priority.\r
     */\r
     PaWasapiThreadPriority threadPriority;\r
+\r
+    /* Stream category. */\r
+    PaWasapiStreamCategory streamCategory;\r
+\r
+    /* Stream option. */\r
+    PaWasapiStreamOption streamOption;\r
 } \r
 PaWasapiStreamInfo;\r
 \r
@@ -303,7 +345,7 @@ PaError PaWasapi_GetFramesPerHostBuffer( PaStream *pStream, unsigned int *nInput
 \r
 /** Get number of jacks associated with a WASAPI device.  Use this method to determine if\r
     there are any jacks associated with the provided WASAPI device.  Not all audio devices\r
-       will support this capability.  This is valid for both input and output devices.\r
+    will support this capability.  This is valid for both input and output devices.\r
  @param  nDevice  device index.\r
  @param  jcount   Number of jacks is returned in this variable\r
  @return Error code indicating success or failure\r
@@ -314,9 +356,9 @@ PaError PaWasapi_GetJackCount(PaDeviceIndex nDevice, int *jcount);
 \r
 /** Get the jack description associated with a WASAPI device and jack number\r
     Before this function is called, use PaWasapi_GetJackCount to determine the\r
-       number of jacks associated with device.  If jcount is greater than zero, then\r
-       each jack from 0 to jcount can be queried with this function to get the jack\r
-       description.\r
+    number of jacks associated with device.  If jcount is greater than zero, then\r
+    each jack from 0 to jcount can be queried with this function to get the jack\r
+    description.\r
  @param  nDevice  device index.\r
  @param  jindex   Which jack to return information\r
  @param  KSJACK_DESCRIPTION This structure filled in on success.\r
@@ -347,7 +389,7 @@ PaError PaWasapi_GetJackDescription(PaDeviceIndex nDevice, int jindex, PaWasapiJ
         This is the most powerful WASAPI implementation which provides glitch-free\r
         audio at around 3ms latency in Exclusive mode. Lowest possible latency for this mode is \r
         3 ms for HD Audio class audio chips. For the Shared mode latency can not be \r
-               lower than 20 ms.\r
+        lower than 20 ms.\r
 \r
         2) Poll-Driven:\r
         Polling is another 2-nd method to operate with WASAPI. It is less efficient than Event-Driven\r
index aecdd63eea7a3e73b4e347dec9750b3c00dbbe63..da40e886e8121ea543dff520f007aff570f2f828 100644 (file)
 \r
 // "1CB9AD4C-DBFA-4c32-B178-C2F568A703B2"\r
 PA_DEFINE_IID(IAudioClient,         1cb9ad4c, dbfa, 4c32, b1, 78, c2, f5, 68, a7, 03, b2);\r
+// "726778CD-F60A-4EDA-82DE-E47610CD78AA"\r
+PA_DEFINE_IID(IAudioClient2,        726778cd, f60a, 4eda, 82, de, e4, 76, 10, cd, 78, aa);\r
 // "1BE09788-6894-4089-8586-9A2A6C265AC5"\r
 PA_DEFINE_IID(IMMEndpoint,          1be09788, 6894, 4089, 85, 86, 9a, 2a, 6c, 26, 5a, c5);\r
 // "A95664D2-9614-4F35-A746-DE8DB63617E6"\r
@@ -195,6 +197,22 @@ __DEFINE_GUID(pa_KSDATAFORMAT_SUBTYPE_PCM,        0x00000001, 0x0000, 0x0010, 0x
 __DEFINE_GUID(pa_KSDATAFORMAT_SUBTYPE_ADPCM,      0x00000002, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );\r
 __DEFINE_GUID(pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );\r
 \r
+#ifdef __IAudioClient2_INTERFACE_DEFINED__\r
+typedef enum _pa_AUDCLNT_STREAMOPTIONS { \r
+       pa_AUDCLNT_STREAMOPTIONS_NONE          = 0x00,\r
+       pa_AUDCLNT_STREAMOPTIONS_RAW           = 0x01,\r
+       pa_AUDCLNT_STREAMOPTIONS_MATCH_FORMAT  = 0x02\r
+} pa_AUDCLNT_STREAMOPTIONS;\r
+typedef struct _pa_AudioClientProperties {\r
+       UINT32                   cbSize;\r
+       BOOL                     bIsOffload;\r
+       AUDIO_STREAM_CATEGORY    eCategory;\r
+       pa_AUDCLNT_STREAMOPTIONS Options;\r
+} pa_AudioClientProperties;\r
+#define PA_AUDIOCLIENTPROPERTIES_SIZE_CATEGORY (sizeof(pa_AudioClientProperties) - sizeof(pa_AUDCLNT_STREAMOPTIONS))\r
+#define PA_AUDIOCLIENTPROPERTIES_SIZE_OPTIONS   sizeof(pa_AudioClientProperties)\r
+#endif // __IAudioClient2_INTERFACE_DEFINED__\r
+\r
 /* use CreateThread for CYGWIN/Windows Mobile, _beginthreadex for all others */\r
 #if !defined(__CYGWIN__) && !defined(_WIN32_WCE)\r
        #define CREATE_THREAD(PROC) (HANDLE)_beginthreadex( NULL, 0, (PROC), stream, 0, &stream->dwThreadId )\r
@@ -506,14 +524,22 @@ typedef struct PaWasapiStream
 }\r
 PaWasapiStream;\r
 \r
+// COM marshaling\r
+static HRESULT MarshalSubStreamComPointers(PaWasapiSubStream *substream);\r
+static HRESULT MarshalStreamComPointers(PaWasapiStream *stream);\r
+static HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream);\r
+static HRESULT UnmarshalStreamComPointers(PaWasapiStream *stream);\r
+static void ReleaseUnmarshaledSubComPointers(PaWasapiSubStream *substream);\r
+static void ReleaseUnmarshaledComPointers(PaWasapiStream *stream);\r
+\r
 // Local stream methods\r
-void _StreamOnStop(PaWasapiStream *stream);\r
-void _StreamFinish(PaWasapiStream *stream);\r
-void _StreamCleanup(PaWasapiStream *stream);\r
-HRESULT _PollGetOutputFramesAvailable(PaWasapiStream *stream, UINT32 *available);\r
-HRESULT _PollGetInputFramesAvailable(PaWasapiStream *stream, UINT32 *available);\r
-void *PaWasapi_ReallocateMemory(void *ptr, size_t size);\r
-void PaWasapi_FreeMemory(void *ptr);\r
+static void _StreamOnStop(PaWasapiStream *stream);\r
+static void _StreamFinish(PaWasapiStream *stream);\r
+static void _StreamCleanup(PaWasapiStream *stream);\r
+static HRESULT _PollGetOutputFramesAvailable(PaWasapiStream *stream, UINT32 *available);\r
+static HRESULT _PollGetInputFramesAvailable(PaWasapiStream *stream, UINT32 *available);\r
+static void *PaWasapi_ReallocateMemory(void *ptr, size_t size);\r
+static void PaWasapi_FreeMemory(void *ptr);\r
 \r
 // Local statics\r
 \r
@@ -844,19 +870,49 @@ static BOOL IsWow64()
 // ------------------------------------------------------------------------------------------\r
 typedef enum EWindowsVersion\r
 {\r
-       WINDOWS_UNKNOWN                  = 0,\r
-       WINDOWS_VISTA_SERVER2008 = (1 << 0),\r
-       WINDOWS_7_SERVER2008R2   = (1 << 1),\r
-       WINDOWS_FUTURE           = (1 << 2)\r
+       WINDOWS_UNKNOWN = 0,\r
+       WINDOWS_VISTA_SERVER2008,\r
+       WINDOWS_7_SERVER2008R2,\r
+       WINDOWS_8_SERVER2012,\r
+       WINDOWS_8_1_SERVER2012R2,\r
+       WINDOWS_10_SERVER2016,\r
+       WINDOWS_FUTURE\r
 }\r
 EWindowsVersion;\r
-// Defines Windows 7/Windows Server 2008 R2 and up (future versions)\r
-#define WINDOWS_7_SERVER2008R2_AND_UP (WINDOWS_7_SERVER2008R2|WINDOWS_FUTURE)\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 UINT32 GetWindowsVersion()\r
+// Alternative way for checking Windows version (allows to check version on Windows 8.1 and up)\r
+static BOOL IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)\r
+{\r
+       typedef ULONGLONG (NTAPI *LPFN_VERSETCONDITIONMASK)(ULONGLONG ConditionMask, DWORD TypeMask, BYTE Condition);\r
+       typedef BOOL (WINAPI *LPFN_VERIFYVERSIONINFO)(LPOSVERSIONINFOEXA lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask);\r
+\r
+       LPFN_VERSETCONDITIONMASK fnVerSetConditionMask;\r
+       LPFN_VERIFYVERSIONINFO fnVerifyVersionInfo;\r
+       OSVERSIONINFOEXA osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 };\r
+       DWORDLONG dwlConditionMask;\r
+\r
+       fnVerSetConditionMask = (LPFN_VERSETCONDITIONMASK)GetProcAddress(GetModuleHandleA("kernel32"), "VerSetConditionMask");\r
+       fnVerifyVersionInfo = (LPFN_VERIFYVERSIONINFO)GetProcAddress(GetModuleHandleA("kernel32"), "VerifyVersionInfoA");\r
+\r
+       if ((fnVerSetConditionMask == NULL) || (fnVerifyVersionInfo == NULL))\r
+               return FALSE;\r
+\r
+       dwlConditionMask = fnVerSetConditionMask(\r
+               fnVerSetConditionMask(\r
+                       fnVerSetConditionMask(\r
+                               0, VER_MAJORVERSION,     VER_GREATER_EQUAL),\r
+                                  VER_MINORVERSION,     VER_GREATER_EQUAL),\r
+                                  VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);\r
+\r
+       osvi.dwMajorVersion    = wMajorVersion;\r
+       osvi.dwMinorVersion    = wMinorVersion;\r
+       osvi.wServicePackMajor = wServicePackMajor;\r
+\r
+       return (fnVerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE);\r
+}\r
+// Get Windows version\r
+static EWindowsVersion GetWindowsVersion()\r
 {\r
-       static UINT32 version = WINDOWS_UNKNOWN;\r
+       static EWindowsVersion version = WINDOWS_UNKNOWN;\r
 \r
        if (version == WINDOWS_UNKNOWN)\r
        {\r
@@ -868,45 +924,75 @@ static UINT32 GetWindowsVersion()
                typedef DWORD (WINAPI *LPFN_GETVERSION)(VOID);\r
                LPFN_GETVERSION fnGetVersion;\r
 \r
-               fnGetVersion = (LPFN_GETVERSION) GetProcAddress(GetModuleHandleA("kernel32"), "GetVersion");\r
-               if (fnGetVersion == NULL)\r
-                       return WINDOWS_UNKNOWN;\r
+               fnGetVersion = (LPFN_GETVERSION)GetProcAddress(GetModuleHandleA("kernel32"), "GetVersion");\r
+               if (fnGetVersion != NULL)\r
+               {\r
+                       PRINT(("WASAPI: getting Windows version with GetVersion()\n"));\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 0:\r
-               case 1:\r
-               case 2:\r
-               case 3:\r
-               case 4:\r
-               case 5:\r
-                       break; // skip lower\r
-               case 6:\r
-                       switch (dwMinorVersion)\r
+                       switch (dwMajorVersion)\r
                        {\r
                        case 0:\r
-                               version |= WINDOWS_VISTA_SERVER2008;\r
-                               break;\r
                        case 1:\r
-                               version |= WINDOWS_7_SERVER2008R2;\r
+                       case 2:\r
+                       case 3:\r
+                       case 4:\r
+                       case 5:\r
+                               break; // skip lower\r
+                       case 6:\r
+                               switch (dwMinorVersion)\r
+                               {\r
+                               case 0:  version = WINDOWS_VISTA_SERVER2008;    break;\r
+                               case 1:  version = WINDOWS_7_SERVER2008R2;              break;\r
+                               case 2:  version = WINDOWS_8_SERVER2012;                break;\r
+                               case 3:  version = WINDOWS_8_1_SERVER2012R2;    break;\r
+                               default: version = WINDOWS_FUTURE;                              break;\r
+                               }\r
+                               break;\r
+                       case 10:\r
+                               switch (dwMinorVersion)\r
+                               {\r
+                               case 0:  version = WINDOWS_10_SERVER2016;               break;\r
+                               default: version = WINDOWS_FUTURE;                              break;\r
+                               }\r
                                break;\r
                        default:\r
-                               version |= WINDOWS_FUTURE;\r
+                               version = WINDOWS_FUTURE;\r
+                               break;\r
                        }\r
-                       break;\r
-               default:\r
-                       version |= WINDOWS_FUTURE;\r
                }\r
+               else\r
+               {\r
+                       PRINT(("WASAPI: getting Windows version with VerifyVersionInfo()\n"));\r
+\r
+                       if (IsWindowsVersionOrGreater(10, 0, 0))\r
+                               version = WINDOWS_10_SERVER2016;\r
+                       else\r
+                       if (IsWindowsVersionOrGreater(6, 3, 0))\r
+                               version = WINDOWS_8_1_SERVER2012R2;\r
+                       else\r
+                       if (IsWindowsVersionOrGreater(6, 2, 0))\r
+                               version = WINDOWS_8_SERVER2012;\r
+                       else\r
+                       if (IsWindowsVersionOrGreater(6, 1, 0))\r
+                               version = WINDOWS_7_SERVER2008R2;\r
+                       else\r
+                       if (IsWindowsVersionOrGreater(6, 0, 0))\r
+                               version = WINDOWS_VISTA_SERVER2008;\r
+                       else\r
+                               version = WINDOWS_FUTURE;\r
+               }\r
+\r
+               PRINT(("WASAPI: Windows version = %d\n", version));\r
        }\r
 \r
        return version;\r
@@ -918,7 +1004,45 @@ static BOOL UseWOW64Workaround()
        // note: WOW64 bug is common to Windows Vista x64, thus we fall back to safe Poll-driven\r
        //       method. Windows 7 x64 seems has WOW64 bug fixed.\r
 \r
-       return (IsWow64() && (GetWindowsVersion() & WINDOWS_VISTA_SERVER2008));\r
+       return (IsWow64() && (GetWindowsVersion() == WINDOWS_VISTA_SERVER2008));\r
+}\r
+\r
+// ------------------------------------------------------------------------------------------\r
+static UINT32 GetAudioClientVersion()\r
+{\r
+       if (GetWindowsVersion() >= WINDOWS_10_SERVER2016)\r
+               return 3;\r
+       else\r
+       if (GetWindowsVersion() >= WINDOWS_8_SERVER2012)\r
+               return 2;\r
+\r
+       return 1;\r
+}\r
+\r
+// ------------------------------------------------------------------------------------------\r
+static const IID *GetAudioClientIID()\r
+{\r
+       static const IID *cli_iid = NULL;\r
+       if (cli_iid == NULL)\r
+       {\r
+               UINT32 cli_version = GetAudioClientVersion();\r
+               if (cli_version <= 1)\r
+               {\r
+                       cli_iid = &pa_IID_IAudioClient;\r
+               }\r
+               else\r
+               {\r
+                       switch (cli_version)\r
+                       {\r
+                       case 3:  cli_iid = &pa_IID_IAudioClient2; cli_version = 2; break; // use IAudioClient2 for Windows 10+ until IAudioClient3 functions are required\r
+                       default: cli_iid = &pa_IID_IAudioClient2; cli_version = 2; break;\r
+                       }\r
+               }\r
+\r
+               PRINT(("WASAPI: IAudioClient version = %d\n", cli_version));\r
+       }\r
+\r
+       return cli_iid;\r
 }\r
 \r
 // ------------------------------------------------------------------------------------------\r
@@ -1313,7 +1437,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
             {\r
                 IAudioClient *tmpClient = NULL;\r
 \r
-                hr = IMMDevice_Activate(paWasapi->devInfo[i].device, &pa_IID_IAudioClient,\r
+                hr = IMMDevice_Activate(paWasapi->devInfo[i].device, GetAudioClientIID(),\r
                                        CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient);\r
                                // We need to set the result to a value otherwise we will return paNoError\r
                                // [IF_FAILED_JUMP(hResult, error);]\r
@@ -2018,7 +2142,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
                        shareMode  = AUDCLNT_SHAREMODE_EXCLUSIVE;\r
 \r
                hr = IMMDevice_Activate(paWasapi->devInfo[inputParameters->device].device,\r
-                       &pa_IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient);\r
+                       GetAudioClientIID(), CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient);\r
                if (hr != S_OK)\r
                {\r
                        LogHostError(hr);\r
@@ -2044,7 +2168,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
                        shareMode  = AUDCLNT_SHAREMODE_EXCLUSIVE;\r
 \r
                hr = IMMDevice_Activate(paWasapi->devInfo[outputParameters->device].device,\r
-                       &pa_IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient);\r
+                       GetAudioClientIID(), CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient);\r
                if (hr != S_OK)\r
                {\r
                        LogHostError(hr);\r
@@ -2144,7 +2268,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
        }\r
 \r
     // Get the audio client\r
-    hr = IMMDevice_Activate(pInfo->device, &pa_IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&audioClient);\r
+    hr = IMMDevice_Activate(pInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void **)&audioClient);\r
        if (hr != S_OK)\r
        {\r
                (*pa_error) = paInsufficientMemory;\r
@@ -2298,6 +2422,38 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
                }\r
        }\r
 \r
+       // Set Raw mode (applicable only to IAudioClient2)\r
+#ifdef __IAudioClient2_INTERFACE_DEFINED__\r
+       if (GetAudioClientVersion() >= 2)\r
+       {\r
+               pa_AudioClientProperties audioProps = { 0 };\r
+               audioProps.cbSize     = sizeof(pa_AudioClientProperties);\r
+               audioProps.bIsOffload = FALSE;\r
+               audioProps.eCategory  = (AUDIO_STREAM_CATEGORY)pSub->params.wasapi_params.streamCategory;\r
+               switch (pSub->params.wasapi_params.streamOption)\r
+               {\r
+               case eStreamOptionRaw:\r
+                       if (GetWindowsVersion() >= WINDOWS_8_1_SERVER2012R2)\r
+                               audioProps.Options = pa_AUDCLNT_STREAMOPTIONS_RAW;\r
+                       break;\r
+               case eStreamOptionMatchFormat:\r
+                       if (GetWindowsVersion() >= WINDOWS_10_SERVER2016)\r
+                               audioProps.Options = pa_AUDCLNT_STREAMOPTIONS_MATCH_FORMAT;\r
+                       break;\r
+               }\r
+\r
+               hr = IAudioClient2_SetClientProperties((IAudioClient2 *)audioClient, (AudioClientProperties *)&audioProps);\r
+               if (hr != S_OK)\r
+               {\r
+                       PRINT(("WASAPI: IAudioClient2_SetClientProperties(Category = %d, Options = %d) failed with error = %08X\n", audioProps.eCategory, audioProps.Options, (UINT32)hr));\r
+               }\r
+               else\r
+               {\r
+                       PRINT(("WASAPI: IAudioClient2 set properties: IsOffload = %d, Category = %d, Options = %d\n", audioProps.bIsOffload, audioProps.eCategory, audioProps.Options));\r
+               }\r
+       }\r
+#endif\r
+\r
        // Open the stream and associate it with an audio session\r
     hr = IAudioClient_Initialize(audioClient,\r
         pSub->shareMode,\r
@@ -2326,7 +2482,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
         SAFE_RELEASE(audioClient);\r
 \r
         // Create a new audio client\r
-        hr = IMMDevice_Activate(pInfo->device, &pa_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&audioClient);\r
+        hr = IMMDevice_Activate(pInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void**)&audioClient);\r
        if (hr != S_OK)\r
                {\r
                        (*pa_error) = paInsufficientMemory;\r
@@ -2357,7 +2513,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
         SAFE_RELEASE(audioClient);\r
 \r
         // Create a new audio client\r
-        hr = IMMDevice_Activate(pInfo->device, &pa_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&audioClient);\r
+        hr = IMMDevice_Activate(pInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void**)&audioClient);\r
        if (hr != S_OK)\r
                {\r
                        (*pa_error) = paInsufficientMemory;\r
@@ -2397,7 +2553,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
         SAFE_RELEASE(audioClient);\r
 \r
         // Create a new audio client\r
-        hr = IMMDevice_Activate(pInfo->device, &pa_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&audioClient);\r
+        hr = IMMDevice_Activate(pInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void**)&audioClient);\r
        if (hr != S_OK)\r
                {\r
                        (*pa_error) = paInsufficientMemory;\r
@@ -2692,26 +2848,38 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
     {\r
         inputChannelCount = inputParameters->channelCount;\r
         inputSampleFormat = inputParameters->sampleFormat;\r
-               inputStreamInfo   = (PaWasapiStreamInfo *)inputParameters->hostApiSpecificStreamInfo;\r
         info              = &paWasapi->devInfo[inputParameters->device];\r
-               stream->in.flags  = (inputStreamInfo ? inputStreamInfo->flags : 0);\r
 \r
-               // Select Exclusive/Shared mode\r
+               // default Shared Mode\r
                stream->in.shareMode = AUDCLNT_SHAREMODE_SHARED;\r
-        if ((inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiExclusive))\r
-               {\r
-                       // Boost thread priority\r
-                       stream->nThreadPriority = eThreadPriorityProAudio;\r
-                       // Make Exclusive\r
-                       stream->in.shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;\r
-               }\r
 \r
-               // If user provided explicit thread priority level, use it\r
-        if ((inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiThreadPriority))\r
+               // PaWasapiStreamInfo\r
+               if (inputParameters->hostApiSpecificStreamInfo != NULL)\r
                {\r
-                       if ((inputStreamInfo->threadPriority > eThreadPriorityNone) &&\r
-                               (inputStreamInfo->threadPriority <= eThreadPriorityWindowManager))\r
-                               stream->nThreadPriority = inputStreamInfo->threadPriority;\r
+                       memcpy(&stream->in.params.wasapi_params, inputParameters->hostApiSpecificStreamInfo, min(sizeof(stream->in.params.wasapi_params), ((PaWasapiStreamInfo *)inputParameters->hostApiSpecificStreamInfo)->size));\r
+                       stream->in.params.wasapi_params.size = sizeof(stream->in.params.wasapi_params);\r
+\r
+                       stream->in.params.stream_params.hostApiSpecificStreamInfo = &stream->in.params.wasapi_params;\r
+                       inputStreamInfo = &stream->in.params.wasapi_params;\r
+\r
+                       stream->in.flags = inputStreamInfo->flags;\r
+\r
+                       // Exclusive Mode\r
+                       if (inputStreamInfo->flags & paWinWasapiExclusive)\r
+                       {\r
+                               // Boost thread priority\r
+                               stream->nThreadPriority = eThreadPriorityProAudio;\r
+                               // Make Exclusive\r
+                               stream->in.shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;\r
+                       }\r
+\r
+                       // explicit thread priority level\r
+                       if (inputStreamInfo->flags & paWinWasapiThreadPriority)\r
+                       {\r
+                               if ((inputStreamInfo->threadPriority > eThreadPriorityNone) &&\r
+                                       (inputStreamInfo->threadPriority <= eThreadPriorityWindowManager))\r
+                                       stream->nThreadPriority = inputStreamInfo->threadPriority;\r
+                       }\r
                }\r
 \r
                // Choose processing mode\r
@@ -2731,11 +2899,6 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
                // Fill parameters for Audio Client creation\r
                stream->in.params.device_info       = info;\r
                stream->in.params.stream_params     = (*inputParameters);\r
-               if (inputStreamInfo != NULL)\r
-               {\r
-                       stream->in.params.wasapi_params = (*inputStreamInfo);\r
-                       stream->in.params.stream_params.hostApiSpecificStreamInfo = &stream->in.params.wasapi_params;\r
-               }\r
                stream->in.params.frames_per_buffer = framesPerBuffer;\r
                stream->in.params.sample_rate       = sampleRate;\r
                stream->in.params.blocking          = (streamCallback == NULL);\r
@@ -2812,26 +2975,38 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
     {\r
         outputChannelCount = outputParameters->channelCount;\r
         outputSampleFormat = outputParameters->sampleFormat;\r
-               outputStreamInfo   = (PaWasapiStreamInfo *)outputParameters->hostApiSpecificStreamInfo;\r
                info               = &paWasapi->devInfo[outputParameters->device];\r
-               stream->out.flags  = (outputStreamInfo ? outputStreamInfo->flags : 0);\r
 \r
-               // Select Exclusive/Shared mode\r
+               // default Shared Mode\r
                stream->out.shareMode = AUDCLNT_SHAREMODE_SHARED;\r
-        if ((outputStreamInfo != NULL) && (outputStreamInfo->flags & paWinWasapiExclusive))\r
-               {\r
-                       // Boost thread priority\r
-                       stream->nThreadPriority = eThreadPriorityProAudio;\r
-                       // Make Exclusive\r
-                       stream->out.shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;\r
-               }\r
 \r
-               // If user provided explicit thread priority level, use it\r
-        if ((outputStreamInfo != NULL) && (outputStreamInfo->flags & paWinWasapiThreadPriority))\r
+               // set PaWasapiStreamInfo\r
+               if (outputParameters->hostApiSpecificStreamInfo != NULL)\r
                {\r
-                       if ((outputStreamInfo->threadPriority > eThreadPriorityNone) &&\r
-                               (outputStreamInfo->threadPriority <= eThreadPriorityWindowManager))\r
-                               stream->nThreadPriority = outputStreamInfo->threadPriority;\r
+                       memcpy(&stream->out.params.wasapi_params, outputParameters->hostApiSpecificStreamInfo, min(sizeof(stream->out.params.wasapi_params), ((PaWasapiStreamInfo *)outputParameters->hostApiSpecificStreamInfo)->size));\r
+                       stream->out.params.wasapi_params.size = sizeof(stream->out.params.wasapi_params);\r
+\r
+                       stream->out.params.stream_params.hostApiSpecificStreamInfo = &stream->out.params.wasapi_params;\r
+                       outputStreamInfo = &stream->out.params.wasapi_params;\r
+\r
+                       stream->out.flags = outputStreamInfo->flags;\r
+\r
+                       // Exclusive Mode\r
+                       if (outputStreamInfo->flags & paWinWasapiExclusive)\r
+                       {\r
+                               // Boost thread priority\r
+                               stream->nThreadPriority = eThreadPriorityProAudio;\r
+                               // Make Exclusive\r
+                               stream->out.shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;\r
+                       }\r
+\r
+                       // explicit thread priority level\r
+                       if (outputStreamInfo->flags & paWinWasapiThreadPriority)\r
+                       {\r
+                               if ((outputStreamInfo->threadPriority > eThreadPriorityNone) &&\r
+                                       (outputStreamInfo->threadPriority <= eThreadPriorityWindowManager))\r
+                                       stream->nThreadPriority = outputStreamInfo->threadPriority;\r
+                       }\r
                }\r
 \r
                // Choose processing mode\r
@@ -2851,11 +3026,6 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
                // Fill parameters for Audio Client creation\r
                stream->out.params.device_info       = info;\r
                stream->out.params.stream_params     = (*outputParameters);\r
-               if (inputStreamInfo != NULL)\r
-               {\r
-                       stream->out.params.wasapi_params = (*outputStreamInfo);\r
-                       stream->out.params.stream_params.hostApiSpecificStreamInfo = &stream->out.params.wasapi_params;\r
-               }\r
                stream->out.params.frames_per_buffer = framesPerBuffer;\r
                stream->out.params.sample_rate       = sampleRate;\r
                stream->out.params.blocking          = (streamCallback == NULL);\r
@@ -3071,7 +3241,7 @@ HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream)
        substream->clientProc = NULL;\r
 \r
        // IAudioClient\r
-       hResult = CoGetInterfaceAndReleaseStream(substream->clientStream, &pa_IID_IAudioClient, (LPVOID*)&substream->clientProc);\r
+       hResult = CoGetInterfaceAndReleaseStream(substream->clientStream, GetAudioClientIID(), (LPVOID*)&substream->clientProc);\r
        substream->clientStream = NULL;\r
        if (hResult != S_OK) \r
        {\r
@@ -3155,7 +3325,7 @@ HRESULT MarshalSubStreamComPointers(PaWasapiSubStream *substream)
        substream->clientStream = NULL;\r
 \r
        // IAudioClient\r
-       hResult = CoMarshalInterThreadInterfaceInStream(&pa_IID_IAudioClient, (LPUNKNOWN)substream->clientParent, &substream->clientStream);\r
+       hResult = CoMarshalInterThreadInterfaceInStream(GetAudioClientIID(), (LPUNKNOWN)substream->clientParent, &substream->clientStream);\r
        if (hResult != S_OK)\r
                goto marshal_sub_error;\r
 \r
index 7d4082b6e0d598612ecf63d4c85779a215e3aafa..0cfa0fa49d0f25a75c8f062a1b0b9b02e453d942 100644 (file)
@@ -1,25 +1,22 @@
-**************\r
-* WASAPI API *\r
-**************\r
-\r
-----------------------------------------\r
-Microsoft Visual Studio 2005SP1/2008/10\r
-----------------------------------------\r
-No specific actions are needed to compile WASAPI API under Visual Studio.\r
-You are only required to install min. Windows Vista SDK (v6.0A) prior\r
-compilation.\r
-\r
-----------------------------------------\r
-MinGW (GCC 32-bit)/ MinGW64 (GCC 64-bit)\r
-----------------------------------------\r
-To compile under MinGW you are required to include 'mingw-include' directory\r
-which contains necessary files with WASAPI API. These files are modified\r
-in order to be compiled by MinGW compiler. These files are taken from \r
-Windows Vista SDK (v6.0A). MinGW compilation is tested and proved to be\r
-fully working under 32-bit and 64-bit modes.\r
-MinGW   (32-bit) tested: gcc version 4.4.0 (GCC)\r
-MinGW64 (64-bit) tested: gcc version 4.4.4 20100226 (prerelease) (GCC)\r
-\r
-PortAudio\r
-/Dmitry Kostjuchenko/\r
-04.03.2010
\ No newline at end of file
+**************
+* WASAPI API *
+**************
+
+-------------------------------------------
+Microsoft Visual Studio 2005 SP1 and higher
+-------------------------------------------
+No specific action is required to compile WASAPI API under Visual Studio.
+You are only required to install min. Windows Vista SDK (v6.0A) prior
+the compilation. To compile with WASAPI specific functionality for Windows 8
+and higher the min. Windows 8 SDK is required.
+
+----------------------------------------
+MinGW (GCC 32/64-bit)
+----------------------------------------
+To compile with MinGW you are required to include 'mingw-include' directory
+which contains necessary files with WASAPI API. These files are modified
+for the compatibility with MinGW compiler. These files are taken from 
+the Windows Vista SDK (v6.0A). MinGW compilation is tested and proved to be
+fully working.
+MinGW   (32-bit) tested min. version: gcc version 4.4.0 (GCC)
+MinGW64 (64-bit) tested min. version: gcc version 4.4.4 20100226 (prerelease) (GCC)
\ No newline at end of file