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