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:
dmitrykos 2015-10-19 11:03:31 +00:00
commit 4e194eaecf
3 changed files with 343 additions and 134 deletions

View file

@ -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

View file

@ -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;

View file

@ -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)