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. */
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
@ -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;
|
||||
|
||||
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)
|
||||
fnGetVersion = (LPFN_GETVERSION)GetProcAddress(GetModuleHandleA("kernel32"), "GetVersion");
|
||||
if (fnGetVersion != NULL)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
break; // skip lower
|
||||
case 6:
|
||||
switch (dwMinorVersion)
|
||||
PRINT(("WASAPI: getting Windows version with GetVersion()\n"));
|
||||
|
||||
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:
|
||||
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
**************
|
||||
* 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)
|
||||
Loading…
Reference in a new issue