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,7 +128,7 @@ typedef enum PaWasapiJackConnectionType
PaWasapiJackConnectionType;
/* Jack geometric location */
/* Jack geometric location. */
typedef enum PaWasapiJackGeoLocation
{
eJackGeoLocUnk = 0,
@ -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;

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
@ -845,18 +871,48 @@ static BOOL IsWow64()
typedef enum EWindowsVersion
{
WINDOWS_UNKNOWN = 0,
WINDOWS_VISTA_SERVER2008 = (1 << 0),
WINDOWS_7_SERVER2008R2 = (1 << 1),
WINDOWS_FUTURE = (1 << 2)
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,9 +924,10 @@ static UINT32 GetWindowsVersion()
typedef DWORD (WINAPI *LPFN_GETVERSION)(VOID);
LPFN_GETVERSION fnGetVersion;
fnGetVersion = (LPFN_GETVERSION) GetProcAddress(GetModuleHandleA("kernel32"), "GetVersion");
if (fnGetVersion == NULL)
return WINDOWS_UNKNOWN;
fnGetVersion = (LPFN_GETVERSION)GetProcAddress(GetModuleHandleA("kernel32"), "GetVersion");
if (fnGetVersion != NULL)
{
PRINT(("WASAPI: getting Windows version with GetVersion()\n"));
dwVersion = fnGetVersion();
@ -894,20 +951,49 @@ static UINT32 GetWindowsVersion()
case 6:
switch (dwMinorVersion)
{
case 0:
version |= WINDOWS_VISTA_SERVER2008;
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 1:
version |= WINDOWS_7_SERVER2008R2;
break;
default:
version |= WINDOWS_FUTURE;
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;
}
}
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,13 +2848,24 @@ 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))
// PaWasapiStreamInfo
if (inputParameters->hostApiSpecificStreamInfo != NULL)
{
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;
@ -2706,13 +2873,14 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
stream->in.shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;
}
// If user provided explicit thread priority level, use it
if ((inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiThreadPriority))
// explicit thread priority level
if (inputStreamInfo->flags & paWinWasapiThreadPriority)
{
if ((inputStreamInfo->threadPriority > eThreadPriorityNone) &&
(inputStreamInfo->threadPriority <= eThreadPriorityWindowManager))
stream->nThreadPriority = inputStreamInfo->threadPriority;
}
}
// Choose processing mode
stream->in.streamFlags = (stream->in.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE ? AUDCLNT_STREAMFLAGS_EVENTCALLBACK : 0);
@ -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,13 +2975,24 @@ 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))
// set PaWasapiStreamInfo
if (outputParameters->hostApiSpecificStreamInfo != NULL)
{
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;
@ -2826,13 +3000,14 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
stream->out.shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;
}
// If user provided explicit thread priority level, use it
if ((outputStreamInfo != NULL) && (outputStreamInfo->flags & paWinWasapiThreadPriority))
// explicit thread priority level
if (outputStreamInfo->flags & paWinWasapiThreadPriority)
{
if ((outputStreamInfo->threadPriority > eThreadPriorityNone) &&
(outputStreamInfo->threadPriority <= eThreadPriorityWindowManager))
stream->nThreadPriority = outputStreamInfo->threadPriority;
}
}
// Choose processing mode
stream->out.streamFlags = (stream->out.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE ? AUDCLNT_STREAMFLAGS_EVENTCALLBACK : 0);
@ -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

@ -2,24 +2,21 @@
* WASAPI API *
**************
----------------------------------------
Microsoft Visual Studio 2005SP1/2008/10
----------------------------------------
No specific actions are needed to compile WASAPI API under Visual Studio.
-------------------------------------------
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
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
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
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)