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)
This commit is contained in:
parent
fb929ad5fb
commit
4e194eaecf
3 changed files with 343 additions and 134 deletions
|
|
@ -69,8 +69,8 @@ typedef enum PaWasapiFlags
|
||||||
method can only provide 15-20ms latency. */
|
method can only provide 15-20ms latency. */
|
||||||
paWinWasapiPolling = (1 << 3),
|
paWinWasapiPolling = (1 << 3),
|
||||||
|
|
||||||
/* forces custom thread priority setting. must be used if PaWasapiStreamInfo::threadPriority
|
/* forces custom thread priority setting, must be used if PaWasapiStreamInfo::threadPriority
|
||||||
is set to custom value. */
|
is set to a custom value */
|
||||||
paWinWasapiThreadPriority = (1 << 4)
|
paWinWasapiThreadPriority = (1 << 4)
|
||||||
}
|
}
|
||||||
PaWasapiFlags;
|
PaWasapiFlags;
|
||||||
|
|
@ -91,7 +91,7 @@ typedef void (*PaWasapiHostProcessorCallback) (void *inputBuffer, long inputFra
|
||||||
void *outputBuffer, long outputFrames,
|
void *outputBuffer, long outputFrames,
|
||||||
void *userData);
|
void *userData);
|
||||||
|
|
||||||
/* Device role */
|
/* Device role. */
|
||||||
typedef enum PaWasapiDeviceRole
|
typedef enum PaWasapiDeviceRole
|
||||||
{
|
{
|
||||||
eRoleRemoteNetworkDevice = 0,
|
eRoleRemoteNetworkDevice = 0,
|
||||||
|
|
@ -109,7 +109,7 @@ typedef enum PaWasapiDeviceRole
|
||||||
PaWasapiDeviceRole;
|
PaWasapiDeviceRole;
|
||||||
|
|
||||||
|
|
||||||
/* Jack connection type */
|
/* Jack connection type. */
|
||||||
typedef enum PaWasapiJackConnectionType
|
typedef enum PaWasapiJackConnectionType
|
||||||
{
|
{
|
||||||
eJackConnTypeUnknown,
|
eJackConnTypeUnknown,
|
||||||
|
|
@ -128,10 +128,10 @@ typedef enum PaWasapiJackConnectionType
|
||||||
PaWasapiJackConnectionType;
|
PaWasapiJackConnectionType;
|
||||||
|
|
||||||
|
|
||||||
/* Jack geometric location */
|
/* Jack geometric location. */
|
||||||
typedef enum PaWasapiJackGeoLocation
|
typedef enum PaWasapiJackGeoLocation
|
||||||
{
|
{
|
||||||
eJackGeoLocUnk = 0,
|
eJackGeoLocUnk = 0,
|
||||||
eJackGeoLocRear = 0x1, /* matches EPcxGeoLocation::eGeoLocRear */
|
eJackGeoLocRear = 0x1, /* matches EPcxGeoLocation::eGeoLocRear */
|
||||||
eJackGeoLocFront,
|
eJackGeoLocFront,
|
||||||
eJackGeoLocLeft,
|
eJackGeoLocLeft,
|
||||||
|
|
@ -151,7 +151,7 @@ typedef enum PaWasapiJackGeoLocation
|
||||||
PaWasapiJackGeoLocation;
|
PaWasapiJackGeoLocation;
|
||||||
|
|
||||||
|
|
||||||
/* Jack general location */
|
/* Jack general location. */
|
||||||
typedef enum PaWasapiJackGenLocation
|
typedef enum PaWasapiJackGenLocation
|
||||||
{
|
{
|
||||||
eJackGenLocPrimaryBox = 0,
|
eJackGenLocPrimaryBox = 0,
|
||||||
|
|
@ -162,7 +162,7 @@ typedef enum PaWasapiJackGenLocation
|
||||||
PaWasapiJackGenLocation;
|
PaWasapiJackGenLocation;
|
||||||
|
|
||||||
|
|
||||||
/* Jack's type of port */
|
/* Jack's type of port. */
|
||||||
typedef enum PaWasapiJackPortConnection
|
typedef enum PaWasapiJackPortConnection
|
||||||
{
|
{
|
||||||
eJackPortConnJack = 0,
|
eJackPortConnJack = 0,
|
||||||
|
|
@ -173,7 +173,7 @@ typedef enum PaWasapiJackPortConnection
|
||||||
PaWasapiJackPortConnection;
|
PaWasapiJackPortConnection;
|
||||||
|
|
||||||
|
|
||||||
/* Thread priority */
|
/* Thread priority. */
|
||||||
typedef enum PaWasapiThreadPriority
|
typedef enum PaWasapiThreadPriority
|
||||||
{
|
{
|
||||||
eThreadPriorityNone = 0,
|
eThreadPriorityNone = 0,
|
||||||
|
|
@ -202,6 +202,42 @@ typedef struct PaWasapiJackDescription
|
||||||
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. */
|
/* Stream descriptor. */
|
||||||
typedef struct PaWasapiStreamInfo
|
typedef struct PaWasapiStreamInfo
|
||||||
{
|
{
|
||||||
|
|
@ -235,6 +271,12 @@ typedef struct PaWasapiStreamInfo
|
||||||
to setup thread priority.
|
to setup thread priority.
|
||||||
*/
|
*/
|
||||||
PaWasapiThreadPriority threadPriority;
|
PaWasapiThreadPriority threadPriority;
|
||||||
|
|
||||||
|
/* Stream category. */
|
||||||
|
PaWasapiStreamCategory streamCategory;
|
||||||
|
|
||||||
|
/* Stream option. */
|
||||||
|
PaWasapiStreamOption streamOption;
|
||||||
}
|
}
|
||||||
PaWasapiStreamInfo;
|
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
|
/** 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
|
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 nDevice device index.
|
||||||
@param jcount Number of jacks is returned in this variable
|
@param jcount Number of jacks is returned in this variable
|
||||||
@return Error code indicating success or failure
|
@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
|
/** Get the jack description associated with a WASAPI device and jack number
|
||||||
Before this function is called, use PaWasapi_GetJackCount to determine the
|
Before this function is called, use PaWasapi_GetJackCount to determine the
|
||||||
number of jacks associated with device. If jcount is greater than zero, then
|
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
|
each jack from 0 to jcount can be queried with this function to get the jack
|
||||||
description.
|
description.
|
||||||
@param nDevice device index.
|
@param nDevice device index.
|
||||||
@param jindex Which jack to return information
|
@param jindex Which jack to return information
|
||||||
@param KSJACK_DESCRIPTION This structure filled in on success.
|
@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
|
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
|
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
|
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:
|
2) Poll-Driven:
|
||||||
Polling is another 2-nd method to operate with WASAPI. It is less efficient than Event-Driven
|
Polling is another 2-nd method to operate with WASAPI. It is less efficient than Event-Driven
|
||||||
|
|
|
||||||
|
|
@ -174,6 +174,8 @@
|
||||||
|
|
||||||
// "1CB9AD4C-DBFA-4c32-B178-C2F568A703B2"
|
// "1CB9AD4C-DBFA-4c32-B178-C2F568A703B2"
|
||||||
PA_DEFINE_IID(IAudioClient, 1cb9ad4c, dbfa, 4c32, b1, 78, c2, f5, 68, a7, 03, b2);
|
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"
|
// "1BE09788-6894-4089-8586-9A2A6C265AC5"
|
||||||
PA_DEFINE_IID(IMMEndpoint, 1be09788, 6894, 4089, 85, 86, 9a, 2a, 6c, 26, 5a, c5);
|
PA_DEFINE_IID(IMMEndpoint, 1be09788, 6894, 4089, 85, 86, 9a, 2a, 6c, 26, 5a, c5);
|
||||||
// "A95664D2-9614-4F35-A746-DE8DB63617E6"
|
// "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_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 );
|
__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 */
|
/* use CreateThread for CYGWIN/Windows Mobile, _beginthreadex for all others */
|
||||||
#if !defined(__CYGWIN__) && !defined(_WIN32_WCE)
|
#if !defined(__CYGWIN__) && !defined(_WIN32_WCE)
|
||||||
#define CREATE_THREAD(PROC) (HANDLE)_beginthreadex( NULL, 0, (PROC), stream, 0, &stream->dwThreadId )
|
#define CREATE_THREAD(PROC) (HANDLE)_beginthreadex( NULL, 0, (PROC), stream, 0, &stream->dwThreadId )
|
||||||
|
|
@ -506,14 +524,22 @@ typedef struct PaWasapiStream
|
||||||
}
|
}
|
||||||
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
|
// Local stream methods
|
||||||
void _StreamOnStop(PaWasapiStream *stream);
|
static void _StreamOnStop(PaWasapiStream *stream);
|
||||||
void _StreamFinish(PaWasapiStream *stream);
|
static void _StreamFinish(PaWasapiStream *stream);
|
||||||
void _StreamCleanup(PaWasapiStream *stream);
|
static void _StreamCleanup(PaWasapiStream *stream);
|
||||||
HRESULT _PollGetOutputFramesAvailable(PaWasapiStream *stream, UINT32 *available);
|
static HRESULT _PollGetOutputFramesAvailable(PaWasapiStream *stream, UINT32 *available);
|
||||||
HRESULT _PollGetInputFramesAvailable(PaWasapiStream *stream, UINT32 *available);
|
static HRESULT _PollGetInputFramesAvailable(PaWasapiStream *stream, UINT32 *available);
|
||||||
void *PaWasapi_ReallocateMemory(void *ptr, size_t size);
|
static void *PaWasapi_ReallocateMemory(void *ptr, size_t size);
|
||||||
void PaWasapi_FreeMemory(void *ptr);
|
static void PaWasapi_FreeMemory(void *ptr);
|
||||||
|
|
||||||
// Local statics
|
// Local statics
|
||||||
|
|
||||||
|
|
@ -844,19 +870,49 @@ static BOOL IsWow64()
|
||||||
// ------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------
|
||||||
typedef enum EWindowsVersion
|
typedef enum EWindowsVersion
|
||||||
{
|
{
|
||||||
WINDOWS_UNKNOWN = 0,
|
WINDOWS_UNKNOWN = 0,
|
||||||
WINDOWS_VISTA_SERVER2008 = (1 << 0),
|
WINDOWS_VISTA_SERVER2008,
|
||||||
WINDOWS_7_SERVER2008R2 = (1 << 1),
|
WINDOWS_7_SERVER2008R2,
|
||||||
WINDOWS_FUTURE = (1 << 2)
|
WINDOWS_8_SERVER2012,
|
||||||
|
WINDOWS_8_1_SERVER2012R2,
|
||||||
|
WINDOWS_10_SERVER2016,
|
||||||
|
WINDOWS_FUTURE
|
||||||
}
|
}
|
||||||
EWindowsVersion;
|
EWindowsVersion;
|
||||||
// Defines Windows 7/Windows Server 2008 R2 and up (future versions)
|
// Alternative way for checking Windows version (allows to check version on Windows 8.1 and up)
|
||||||
#define WINDOWS_7_SERVER2008R2_AND_UP (WINDOWS_7_SERVER2008R2|WINDOWS_FUTURE)
|
static BOOL IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
|
||||||
// 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()
|
|
||||||
{
|
{
|
||||||
static UINT32 version = WINDOWS_UNKNOWN;
|
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 EWindowsVersion version = WINDOWS_UNKNOWN;
|
||||||
|
|
||||||
if (version == WINDOWS_UNKNOWN)
|
if (version == WINDOWS_UNKNOWN)
|
||||||
{
|
{
|
||||||
|
|
@ -868,45 +924,75 @@ static UINT32 GetWindowsVersion()
|
||||||
typedef DWORD (WINAPI *LPFN_GETVERSION)(VOID);
|
typedef DWORD (WINAPI *LPFN_GETVERSION)(VOID);
|
||||||
LPFN_GETVERSION fnGetVersion;
|
LPFN_GETVERSION fnGetVersion;
|
||||||
|
|
||||||
fnGetVersion = (LPFN_GETVERSION) GetProcAddress(GetModuleHandleA("kernel32"), "GetVersion");
|
fnGetVersion = (LPFN_GETVERSION)GetProcAddress(GetModuleHandleA("kernel32"), "GetVersion");
|
||||||
if (fnGetVersion == NULL)
|
if (fnGetVersion != NULL)
|
||||||
return WINDOWS_UNKNOWN;
|
|
||||||
|
|
||||||
dwVersion = fnGetVersion();
|
|
||||||
|
|
||||||
// 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));
|
|
||||||
|
|
||||||
switch (dwMajorVersion)
|
|
||||||
{
|
{
|
||||||
case 0:
|
PRINT(("WASAPI: getting Windows version with GetVersion()\n"));
|
||||||
case 1:
|
|
||||||
case 2:
|
dwVersion = fnGetVersion();
|
||||||
case 3:
|
|
||||||
case 4:
|
// Get the Windows version
|
||||||
case 5:
|
dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
|
||||||
break; // skip lower
|
dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
|
||||||
case 6:
|
|
||||||
switch (dwMinorVersion)
|
// Get the build number
|
||||||
|
if (dwVersion < 0x80000000)
|
||||||
|
dwBuild = (DWORD)(HIWORD(dwVersion));
|
||||||
|
|
||||||
|
switch (dwMajorVersion)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
version |= WINDOWS_VISTA_SERVER2008;
|
|
||||||
break;
|
|
||||||
case 1:
|
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;
|
break;
|
||||||
default:
|
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;
|
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
|
// 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.
|
// 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;
|
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);
|
CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient);
|
||||||
// We need to set the result to a value otherwise we will return paNoError
|
// We need to set the result to a value otherwise we will return paNoError
|
||||||
// [IF_FAILED_JUMP(hResult, error);]
|
// [IF_FAILED_JUMP(hResult, error);]
|
||||||
|
|
@ -2018,7 +2142,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;
|
shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;
|
||||||
|
|
||||||
hr = IMMDevice_Activate(paWasapi->devInfo[inputParameters->device].device,
|
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)
|
if (hr != S_OK)
|
||||||
{
|
{
|
||||||
LogHostError(hr);
|
LogHostError(hr);
|
||||||
|
|
@ -2044,7 +2168,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;
|
shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;
|
||||||
|
|
||||||
hr = IMMDevice_Activate(paWasapi->devInfo[outputParameters->device].device,
|
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)
|
if (hr != S_OK)
|
||||||
{
|
{
|
||||||
LogHostError(hr);
|
LogHostError(hr);
|
||||||
|
|
@ -2144,7 +2268,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the audio client
|
// 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)
|
if (hr != S_OK)
|
||||||
{
|
{
|
||||||
(*pa_error) = paInsufficientMemory;
|
(*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
|
// Open the stream and associate it with an audio session
|
||||||
hr = IAudioClient_Initialize(audioClient,
|
hr = IAudioClient_Initialize(audioClient,
|
||||||
pSub->shareMode,
|
pSub->shareMode,
|
||||||
|
|
@ -2326,7 +2482,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
|
||||||
SAFE_RELEASE(audioClient);
|
SAFE_RELEASE(audioClient);
|
||||||
|
|
||||||
// Create a new audio client
|
// 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)
|
if (hr != S_OK)
|
||||||
{
|
{
|
||||||
(*pa_error) = paInsufficientMemory;
|
(*pa_error) = paInsufficientMemory;
|
||||||
|
|
@ -2357,7 +2513,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
|
||||||
SAFE_RELEASE(audioClient);
|
SAFE_RELEASE(audioClient);
|
||||||
|
|
||||||
// Create a new audio client
|
// 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)
|
if (hr != S_OK)
|
||||||
{
|
{
|
||||||
(*pa_error) = paInsufficientMemory;
|
(*pa_error) = paInsufficientMemory;
|
||||||
|
|
@ -2397,7 +2553,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
|
||||||
SAFE_RELEASE(audioClient);
|
SAFE_RELEASE(audioClient);
|
||||||
|
|
||||||
// Create a new audio client
|
// 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)
|
if (hr != S_OK)
|
||||||
{
|
{
|
||||||
(*pa_error) = paInsufficientMemory;
|
(*pa_error) = paInsufficientMemory;
|
||||||
|
|
@ -2692,26 +2848,38 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
{
|
{
|
||||||
inputChannelCount = inputParameters->channelCount;
|
inputChannelCount = inputParameters->channelCount;
|
||||||
inputSampleFormat = inputParameters->sampleFormat;
|
inputSampleFormat = inputParameters->sampleFormat;
|
||||||
inputStreamInfo = (PaWasapiStreamInfo *)inputParameters->hostApiSpecificStreamInfo;
|
|
||||||
info = &paWasapi->devInfo[inputParameters->device];
|
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;
|
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
|
// PaWasapiStreamInfo
|
||||||
if ((inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiThreadPriority))
|
if (inputParameters->hostApiSpecificStreamInfo != NULL)
|
||||||
{
|
{
|
||||||
if ((inputStreamInfo->threadPriority > eThreadPriorityNone) &&
|
memcpy(&stream->in.params.wasapi_params, inputParameters->hostApiSpecificStreamInfo, min(sizeof(stream->in.params.wasapi_params), ((PaWasapiStreamInfo *)inputParameters->hostApiSpecificStreamInfo)->size));
|
||||||
(inputStreamInfo->threadPriority <= eThreadPriorityWindowManager))
|
stream->in.params.wasapi_params.size = sizeof(stream->in.params.wasapi_params);
|
||||||
stream->nThreadPriority = inputStreamInfo->threadPriority;
|
|
||||||
|
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
|
// Choose processing mode
|
||||||
|
|
@ -2731,11 +2899,6 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
// Fill parameters for Audio Client creation
|
// Fill parameters for Audio Client creation
|
||||||
stream->in.params.device_info = info;
|
stream->in.params.device_info = info;
|
||||||
stream->in.params.stream_params = (*inputParameters);
|
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.frames_per_buffer = framesPerBuffer;
|
||||||
stream->in.params.sample_rate = sampleRate;
|
stream->in.params.sample_rate = sampleRate;
|
||||||
stream->in.params.blocking = (streamCallback == NULL);
|
stream->in.params.blocking = (streamCallback == NULL);
|
||||||
|
|
@ -2812,26 +2975,38 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
{
|
{
|
||||||
outputChannelCount = outputParameters->channelCount;
|
outputChannelCount = outputParameters->channelCount;
|
||||||
outputSampleFormat = outputParameters->sampleFormat;
|
outputSampleFormat = outputParameters->sampleFormat;
|
||||||
outputStreamInfo = (PaWasapiStreamInfo *)outputParameters->hostApiSpecificStreamInfo;
|
|
||||||
info = &paWasapi->devInfo[outputParameters->device];
|
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;
|
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
|
// set PaWasapiStreamInfo
|
||||||
if ((outputStreamInfo != NULL) && (outputStreamInfo->flags & paWinWasapiThreadPriority))
|
if (outputParameters->hostApiSpecificStreamInfo != NULL)
|
||||||
{
|
{
|
||||||
if ((outputStreamInfo->threadPriority > eThreadPriorityNone) &&
|
memcpy(&stream->out.params.wasapi_params, outputParameters->hostApiSpecificStreamInfo, min(sizeof(stream->out.params.wasapi_params), ((PaWasapiStreamInfo *)outputParameters->hostApiSpecificStreamInfo)->size));
|
||||||
(outputStreamInfo->threadPriority <= eThreadPriorityWindowManager))
|
stream->out.params.wasapi_params.size = sizeof(stream->out.params.wasapi_params);
|
||||||
stream->nThreadPriority = outputStreamInfo->threadPriority;
|
|
||||||
|
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
|
// Choose processing mode
|
||||||
|
|
@ -2851,11 +3026,6 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
// Fill parameters for Audio Client creation
|
// Fill parameters for Audio Client creation
|
||||||
stream->out.params.device_info = info;
|
stream->out.params.device_info = info;
|
||||||
stream->out.params.stream_params = (*outputParameters);
|
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.frames_per_buffer = framesPerBuffer;
|
||||||
stream->out.params.sample_rate = sampleRate;
|
stream->out.params.sample_rate = sampleRate;
|
||||||
stream->out.params.blocking = (streamCallback == NULL);
|
stream->out.params.blocking = (streamCallback == NULL);
|
||||||
|
|
@ -3071,7 +3241,7 @@ HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream)
|
||||||
substream->clientProc = NULL;
|
substream->clientProc = NULL;
|
||||||
|
|
||||||
// IAudioClient
|
// IAudioClient
|
||||||
hResult = CoGetInterfaceAndReleaseStream(substream->clientStream, &pa_IID_IAudioClient, (LPVOID*)&substream->clientProc);
|
hResult = CoGetInterfaceAndReleaseStream(substream->clientStream, GetAudioClientIID(), (LPVOID*)&substream->clientProc);
|
||||||
substream->clientStream = NULL;
|
substream->clientStream = NULL;
|
||||||
if (hResult != S_OK)
|
if (hResult != S_OK)
|
||||||
{
|
{
|
||||||
|
|
@ -3155,7 +3325,7 @@ HRESULT MarshalSubStreamComPointers(PaWasapiSubStream *substream)
|
||||||
substream->clientStream = NULL;
|
substream->clientStream = NULL;
|
||||||
|
|
||||||
// IAudioClient
|
// IAudioClient
|
||||||
hResult = CoMarshalInterThreadInterfaceInStream(&pa_IID_IAudioClient, (LPUNKNOWN)substream->clientParent, &substream->clientStream);
|
hResult = CoMarshalInterThreadInterfaceInStream(GetAudioClientIID(), (LPUNKNOWN)substream->clientParent, &substream->clientStream);
|
||||||
if (hResult != S_OK)
|
if (hResult != S_OK)
|
||||||
goto marshal_sub_error;
|
goto marshal_sub_error;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,21 @@
|
||||||
* WASAPI API *
|
* WASAPI API *
|
||||||
**************
|
**************
|
||||||
|
|
||||||
----------------------------------------
|
-------------------------------------------
|
||||||
Microsoft Visual Studio 2005SP1/2008/10
|
Microsoft Visual Studio 2005 SP1 and higher
|
||||||
----------------------------------------
|
-------------------------------------------
|
||||||
No specific actions are needed to compile WASAPI API under Visual Studio.
|
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
|
You are only required to install min. Windows Vista SDK (v6.0A) prior
|
||||||
compilation.
|
the compilation. To compile with WASAPI specific functionality for Windows 8
|
||||||
|
and higher the min. Windows 8 SDK is required.
|
||||||
|
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
MinGW (GCC 32-bit)/ MinGW64 (GCC 64-bit)
|
MinGW (GCC 32/64-bit)
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
To compile under MinGW you are required to include 'mingw-include' directory
|
To compile with MinGW you are required to include 'mingw-include' directory
|
||||||
which contains necessary files with WASAPI API. These files are modified
|
which contains necessary files with WASAPI API. These files are modified
|
||||||
in order to be compiled by MinGW compiler. These files are taken from
|
for the compatibility with MinGW compiler. These files are taken from
|
||||||
Windows Vista SDK (v6.0A). MinGW compilation is tested and proved to be
|
the Windows Vista SDK (v6.0A). MinGW compilation is tested and proved to be
|
||||||
fully working under 32-bit and 64-bit modes.
|
fully working.
|
||||||
MinGW (32-bit) tested: gcc version 4.4.0 (GCC)
|
MinGW (32-bit) tested min. version: gcc version 4.4.0 (GCC)
|
||||||
MinGW64 (64-bit) tested: gcc version 4.4.4 20100226 (prerelease) (GCC)
|
MinGW64 (64-bit) tested min. version: gcc version 4.4.4 20100226 (prerelease) (GCC)
|
||||||
|
|
||||||
PortAudio
|
|
||||||
/Dmitry Kostjuchenko/
|
|
||||||
04.03.2010
|
|
||||||
Loading…
Reference in a new issue