Merge branch 'master' into hotplug

This commit is contained in:
Ross Bencina 2016-09-03 14:19:23 +10:00
commit 46f97c7c20
5 changed files with 504 additions and 121 deletions

View file

@ -27,26 +27,26 @@
*/
/*
* The text above constitutes the entire PortAudio license; however,
* The text above constitutes the entire PortAudio license; however,
* the PortAudio community also makes the following non-binding requests:
*
* Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. It is also
* requested that these non-binding requests be included along with the
* they can be incorporated into the canonical version. It is also
* requested that these non-binding requests be included along with the
* license above.
*/
/** @file
@ingroup common_src
@brief Implements PortAudio API functions defined in portaudio.h, checks
@brief Implements PortAudio API functions defined in portaudio.h, checks
some errors, delegates platform-specific behavior to host API implementations.
Implements the functions defined in the PortAudio API (portaudio.h),
validates some parameters and checks for state inconsistencies before
forwarding API requests to specific Host API implementations (via the
interface declared in pa_hostapi.h), and Streams (via the interface
Implements the functions defined in the PortAudio API (portaudio.h),
validates some parameters and checks for state inconsistencies before
forwarding API requests to specific Host API implementations (via the
interface declared in pa_hostapi.h), and Streams (via the interface
declared in pa_stream.h).
This file manages initialization and termination of Host API
@ -103,7 +103,7 @@
/**
* This is a combination of paVersionMajor, paVersionMinor and paVersionSubMinor.
* It will always increase so that version numbers can be compared as integers to
* It will always increase so that version numbers can be compared as integers to
* see which is later.
*/
#define paVersion paMakeVersionNumber(paVersionMajor, paVersionMinor, paVersionSubMinor)
@ -125,11 +125,11 @@ const char* Pa_GetVersionText( void )
}
static PaVersionInfo versionInfo_ = {
.versionMajor = paVersionMajor,
.versionMinor = paVersionMinor,
.versionSubMinor = paVersionSubMinor,
.versionControlRevision = TOSTRING(PA_SVN_REVISION),
.versionText = PA_VERSION_TEXT_
/*.versionMajor =*/ paVersionMajor,
/*.versionMinor =*/ paVersionMinor,
/*.versionSubMinor =*/ paVersionSubMinor,
/*.versionControlRevision =*/ TOSTRING(PA_SVN_REVISION),
/*.versionText =*/ PA_VERSION_TEXT_
};
const PaVersionInfo* Pa_GetVersionInfo()
@ -213,7 +213,7 @@ static PaError InitializeHostApis( void )
if( !hostApis_ )
{
result = paInsufficientMemory;
goto error;
goto error;
}
hostApisCount_ = 0;
@ -239,11 +239,11 @@ static PaError InitializeHostApis( void )
assert( hostApi->info.defaultInputDevice < hostApi->info.deviceCount );
assert( hostApi->info.defaultOutputDevice < hostApi->info.deviceCount );
/* the first successfully initialized host API with a default input *or*
/* the first successfully initialized host API with a default input *or*
output device is used as the default host API.
*/
if( (defaultHostApiIndex_ == -1) &&
( hostApi->info.defaultInputDevice != paNoDevice
( hostApi->info.defaultInputDevice != paNoDevice
|| hostApi->info.defaultOutputDevice != paNoDevice ) )
{
defaultHostApiIndex_ = hostApisCount_;
@ -281,7 +281,7 @@ error:
<device> belongs and returns it. if <hostSpecificDeviceIndex> is
non-null, the host specific device index is returned in it.
returns -1 if <device> is out of range.
*/
static int FindHostApi( PaDeviceIndex device, int *hostSpecificDeviceIndex )
{
@ -371,7 +371,7 @@ PaError Pa_Initialize( void )
{
PA_VALIDATE_TYPE_SIZES;
PA_VALIDATE_ENDIANNESS;
PaUtil_InitializeClock();
PaUtil_ResetTraceMessages();
@ -463,11 +463,11 @@ const char *Pa_GetErrorText( PaError errorCode )
case paCanNotWriteToAnInputOnlyStream: result = "Can't write to an input only stream"; break;
case paIncompatibleStreamHostApi: result = "Incompatible stream host API"; break;
case paBadBufferPtr: result = "Bad buffer pointer"; break;
default:
default:
if( errorCode > 0 )
result = "Invalid error code (value greater than zero)";
result = "Invalid error code (value greater than zero)";
else
result = "Invalid error code";
result = "Invalid error code";
break;
}
return result;
@ -478,7 +478,7 @@ PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type )
{
PaHostApiIndex result;
int i;
PA_LOGAPI_ENTER_PARAMS( "Pa_HostApiTypeIdToHostApiIndex" );
PA_LOGAPI(("\tPaHostApiTypeId type: %d\n", type ));
@ -489,14 +489,14 @@ PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type )
else
{
result = paHostApiNotFound;
for( i=0; i < hostApisCount_; ++i )
{
if( hostApis_[i]->info.type == type )
{
result = i;
break;
}
}
}
}
@ -511,7 +511,7 @@ PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **ho
{
PaError result;
int i;
if( !PA_IS_INITIALISED_ )
{
result = paNotInitialized;
@ -519,7 +519,7 @@ PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **ho
else
{
result = paHostApiNotFound;
for( i=0; i < hostApisCount_; ++i )
{
if( hostApis_[i]->info.type == type )
@ -540,7 +540,7 @@ PaError PaUtil_DeviceIndexToHostApiDeviceIndex(
{
PaError result;
PaDeviceIndex x;
x = device - hostApi->privatePaFrontInfo.baseDeviceIndex;
if( x < 0 || x >= hostApi->info.deviceCount )
@ -625,7 +625,7 @@ const PaHostApiInfo* Pa_GetHostApiInfo( PaHostApiIndex hostApi )
else if( hostApi < 0 || hostApi >= hostApisCount_ )
{
info = NULL;
PA_LOGAPI(("Pa_GetHostApiInfo returned:\n" ));
PA_LOGAPI(("\tPaHostApiInfo*: NULL [ hostApi out of range ]\n" ));
@ -734,7 +734,7 @@ PaDeviceIndex Pa_GetDefaultOutputDevice( void )
{
PaHostApiIndex hostApi;
PaDeviceIndex result;
PA_LOGAPI_ENTER( "Pa_GetDefaultOutputDevice" );
hostApi = Pa_GetDefaultHostApi();
@ -964,7 +964,7 @@ static int SampleFormatIsValid( PaSampleFormat format )
ValidateOpenStreamParameters() checks that parameters to Pa_OpenStream()
conform to the expected values as described below. This function is
also designed to be used with the proposed Pa_IsFormatSupported() function.
There are basically two types of validation that could be performed:
Generic conformance validation, and device capability mismatch
validation. This function performs only generic conformance validation.
@ -973,21 +973,21 @@ static int SampleFormatIsValid( PaSampleFormat format )
combinations of parameters - for example, even if the sampleRate
seems ok, it might not be for a duplex stream - we have no way of
checking this in an API-neutral way, so we don't try.
On success the function returns PaNoError and fills in hostApi,
hostApiInputDeviceID, and hostApiOutputDeviceID fields. On failure
the function returns an error code indicating the first encountered
parameter error.
If ValidateOpenStreamParameters() returns paNoError, the following
assertions are guaranteed to be true.
- at least one of inputParameters & outputParmeters is valid (not NULL)
- if inputParameters & outputParameters are both valid, that
inputParameters->device & outputParameters->device both use the same host api
PaDeviceIndex inputParameters->device
- is within range (0 to Pa_GetDeviceCount-1) Or:
- is paUseHostApiSpecificDeviceSpecification and
@ -997,30 +997,30 @@ static int SampleFormatIsValid( PaSampleFormat format )
int inputParameters->channelCount
- if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, channelCount is > 0
- upper bound is NOT validated against device capabilities
PaSampleFormat inputParameters->sampleFormat
- is one of the sample formats defined in portaudio.h
void *inputParameters->hostApiSpecificStreamInfo
- if supplied its hostApi field matches the input device's host Api
PaDeviceIndex outputParmeters->device
- is within range (0 to Pa_GetDeviceCount-1)
int outputParmeters->channelCount
- if inputDevice is valid, channelCount is > 0
- upper bound is NOT validated against device capabilities
PaSampleFormat outputParmeters->sampleFormat
- is one of the sample formats defined in portaudio.h
void *outputParmeters->hostApiSpecificStreamInfo
- if supplied its hostApi field matches the output device's host Api
double sampleRate
- is not an 'absurd' rate (less than 1000. or greater than 384000.)
- sampleRate is NOT validated against device capabilities
PaStreamFlags streamFlags
- unused platform neutral flags are zero
- paNeverDropInput is only used for full-duplex callback streams with
@ -1147,7 +1147,7 @@ static PaError ValidateOpenStreamParameters(
!= (*hostApi)->info.type )
return paIncompatibleHostApiSpecificStreamInfo;
}
}
}
if( (inputParameters != NULL) && (outputParameters != NULL) )
{
@ -1156,8 +1156,8 @@ static PaError ValidateOpenStreamParameters(
return paBadIODeviceCombination;
}
}
/* Check for absurd sample rates. */
if( (sampleRate < 1000.0) || (sampleRate > 384000.0) )
return paInvalidSampleRate;
@ -1179,7 +1179,7 @@ static PaError ValidateOpenStreamParameters(
if( framesPerBuffer != paFramesPerBufferUnspecified )
return paInvalidFlag;
}
return paNoError;
}
@ -1219,7 +1219,7 @@ PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters,
PA_LOGAPI(("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency ));
PA_LOGAPI(("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo ));
}
PA_LOGAPI(("\tdouble sampleRate: %g\n", sampleRate ));
#endif
@ -1242,7 +1242,7 @@ PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters,
PA_LOGAPI_EXIT_PAERROR( "Pa_IsFormatSupported", result );
return result;
}
if( inputParameters )
{
@ -1329,7 +1329,7 @@ PaError Pa_OpenStream( PaStream** stream,
PA_LOGAPI(("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency ));
PA_LOGAPI(("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo ));
}
PA_LOGAPI(("\tdouble sampleRate: %g\n", sampleRate ));
PA_LOGAPI(("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer ));
PA_LOGAPI(("\tPaStreamFlags streamFlags: 0x%x\n", streamFlags ));
@ -1376,7 +1376,7 @@ PaError Pa_OpenStream( PaStream** stream,
PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ));
return result;
}
if( inputParameters )
{
@ -1450,8 +1450,8 @@ PaError Pa_OpenDefaultStream( PaStream** stream,
{
hostApiInputParameters.device = Pa_GetDefaultInputDevice();
if( hostApiInputParameters.device == paNoDevice )
return paDeviceUnavailable;
return paDeviceUnavailable;
hostApiInputParameters.channelCount = inputChannelCount;
hostApiInputParameters.sampleFormat = sampleFormat;
/* defaultHighInputLatency is used below instead of
@ -1459,7 +1459,7 @@ PaError Pa_OpenDefaultStream( PaStream** stream,
stream to work reliably than it is for it to work with the lowest
latency.
*/
hostApiInputParameters.suggestedLatency =
hostApiInputParameters.suggestedLatency =
Pa_GetDeviceInfo( hostApiInputParameters.device )->defaultHighInputLatency;
hostApiInputParameters.hostApiSpecificStreamInfo = NULL;
hostApiInputParametersPtr = &hostApiInputParameters;
@ -1473,7 +1473,7 @@ PaError Pa_OpenDefaultStream( PaStream** stream,
{
hostApiOutputParameters.device = Pa_GetDefaultOutputDevice();
if( hostApiOutputParameters.device == paNoDevice )
return paDeviceUnavailable;
return paDeviceUnavailable;
hostApiOutputParameters.channelCount = outputChannelCount;
hostApiOutputParameters.sampleFormat = sampleFormat;
@ -1857,7 +1857,7 @@ PaError Pa_WriteStream( PaStream* stream,
else if( result == 1 )
{
result = paStreamIsStopped;
}
}
}
}

View file

@ -42,12 +42,18 @@
@note pa_wasapi currently requires minimum VC 2005, and the latest Vista SDK
*/
#define WIN32_LEAN_AND_MEAN // exclude rare headers
#include <windows.h>
#include <stdio.h>
#include <process.h>
#include <assert.h>
#include <mmsystem.h>
// WinRT
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
#define PA_WINRT
#define INITGUID
#endif
// WASAPI
#include <mmreg.h> // must be before other Wasapi headers
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
#include <Avrt.h>
@ -61,9 +67,9 @@
#undef INITGUID
#endif
#ifndef __MWERKS__
#include <malloc.h>
#include <memory.h>
#endif /* __MWERKS__ */
#include <malloc.h>
#include <memory.h>
#endif
#include "pa_util.h"
#include "pa_allocation.h"
@ -74,10 +80,9 @@
#include "pa_win_wasapi.h"
#include "pa_debugprint.h"
#include "pa_ringbuffer.h"
#include "pa_win_coinitialize.h"
#ifndef NTDDI_VERSION
#if !defined(NTDDI_VERSION)
#undef WINVER
#undef _WIN32_WINNT
@ -160,6 +165,38 @@
#endif // NTDDI_VERSION
// Missing declarations for WinRT
#ifdef PA_WINRT
#define DEVICE_STATE_ACTIVE 0x00000001
typedef enum _EDataFlow
{
eRender = 0,
eCapture = ( eRender + 1 ) ,
eAll = ( eCapture + 1 ) ,
EDataFlow_enum_count = ( eAll + 1 )
}
EDataFlow;
typedef enum _EndpointFormFactor
{
RemoteNetworkDevice = 0,
Speakers = ( RemoteNetworkDevice + 1 ) ,
LineLevel = ( Speakers + 1 ) ,
Headphones = ( LineLevel + 1 ) ,
Microphone = ( Headphones + 1 ) ,
Headset = ( Microphone + 1 ) ,
Handset = ( Headset + 1 ) ,
UnknownDigitalPassthrough = ( Handset + 1 ) ,
SPDIF = ( UnknownDigitalPassthrough + 1 ) ,
HDMI = ( SPDIF + 1 ) ,
UnknownFormFactor = ( HDMI + 1 )
}
EndpointFormFactor;
#endif
#ifndef GUID_SECT
#define GUID_SECT
#endif
@ -192,6 +229,7 @@ PA_DEFINE_IID(IDeviceTopology, 2A07407E, 6497, 4A18, 97, 87, 32, f7, 9b, d0
PA_DEFINE_IID(IPart, AE2DE0E4, 5BCA, 4F2D, aa, 46, 5d, 13, f8, fd, b3, a9);
// *4509F757-2D46-4637-8E62-CE7DB944F57B*
PA_DEFINE_IID(IKsJackDescription, 4509F757, 2D46, 4637, 8e, 62, ce, 7d, b9, 44, f5, 7b);
// Media formats:
__DEFINE_GUID(pa_KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 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 );
@ -272,13 +310,13 @@ enum { WASAPI_PACKETS_PER_INPUT_BUFFER = 6 };
typedef void (*MixMonoToStereoF) (void *__to, void *__from, UINT32 count);
// AVRT is the new "multimedia schedulling stuff"
#ifndef PA_WINRT
typedef BOOL (WINAPI *FAvRtCreateThreadOrderingGroup) (PHANDLE,PLARGE_INTEGER,GUID*,PLARGE_INTEGER);
typedef BOOL (WINAPI *FAvRtDeleteThreadOrderingGroup) (HANDLE);
typedef BOOL (WINAPI *FAvRtWaitOnThreadOrderingGroup) (HANDLE);
typedef HANDLE (WINAPI *FAvSetMmThreadCharacteristics) (LPCSTR,LPDWORD);
typedef BOOL (WINAPI *FAvRevertMmThreadCharacteristics)(HANDLE);
typedef BOOL (WINAPI *FAvSetMmThreadPriority) (HANDLE,AVRT_PRIORITY);
static HMODULE hDInputDLL = 0;
FAvRtCreateThreadOrderingGroup pAvRtCreateThreadOrderingGroup = NULL;
FAvRtDeleteThreadOrderingGroup pAvRtDeleteThreadOrderingGroup = NULL;
@ -286,6 +324,7 @@ FAvRtWaitOnThreadOrderingGroup pAvRtWaitOnThreadOrderingGroup = NULL;
FAvSetMmThreadCharacteristics pAvSetMmThreadCharacteristics = NULL;
FAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL;
FAvSetMmThreadPriority pAvSetMmThreadPriority = NULL;
#endif
#define _GetProc(fun, type, name) { \
fun = (type) GetProcAddress(hDInputDLL,name); \
@ -351,7 +390,9 @@ static signed long GetStreamWriteAvailable( PaStream* stream );
typedef struct PaWasapiDeviceInfo
{
// Device
#ifndef PA_WINRT
IMMDevice *device;
#endif
// from GetId
WCHAR szDeviceID[MAX_STR_LEN];
@ -359,20 +400,17 @@ typedef struct PaWasapiDeviceInfo
// from GetState
DWORD state;
// Fields filled from IMMEndpoint'sGetDataFlow
EDataFlow flow;
// Fields filled from IAudioDevice (_prior_ to Initialize)
// from GetDevicePeriod(
REFERENCE_TIME DefaultDevicePeriod;
REFERENCE_TIME MinimumDevicePeriod;
// from GetMixFormat
// WAVEFORMATEX *MixFormat;//needs to be CoTaskMemFree'd after use!
// Default format (setup through Control Panel by user)
WAVEFORMATEXTENSIBLE DefaultFormat;
// Fields filled from IMMEndpoint'sGetDataFlow
EDataFlow flow;
// Formfactor
EndpointFormFactor formFactor;
}
@ -393,7 +431,9 @@ typedef struct
PaWinUtilComInitializationResult comInitializationResult;
//in case we later need the synch
#ifndef PA_WINRT
IMMDeviceEnumerator *enumerator;
#endif
//this is the REAL number of devices, whether they are usefull to PA or not!
UINT32 deviceCount;
@ -428,7 +468,9 @@ PaWasapiAudioClientParams;
typedef struct PaWasapiSubStream
{
IAudioClient *clientParent;
#ifndef PA_WINRT
IStream *clientStream;
#endif
IAudioClient *clientProc;
WAVEFORMATEXTENSIBLE wavex;
@ -478,14 +520,18 @@ typedef struct PaWasapiStream
// input
PaWasapiSubStream in;
IAudioCaptureClient *captureClientParent;
#ifndef PA_WINRT
IStream *captureClientStream;
#endif
IAudioCaptureClient *captureClient;
IAudioEndpointVolume *inVol;
// output
PaWasapiSubStream out;
IAudioRenderClient *renderClientParent;
#ifndef PA_WINRT
IStream *renderClientStream;
#endif
IAudioRenderClient *renderClient;
IAudioEndpointVolume *outVol;
@ -766,6 +812,7 @@ static UINT32 AlignFramesPerBuffer(UINT32 nFrames, UINT32 nSamplesPerSec, UINT32
long frame_bytes = nFrames * nBlockAlign;
long packets;
(void)nSamplesPerSec;
// align to packet size
frame_bytes = pAlignFunc(frame_bytes, HDA_PACKET_SIZE); // use ALIGN_FWD if bigger but safer period is more desired
@ -812,6 +859,7 @@ static UINT32 GetFramesSleepTimeMicroseconds(UINT32 nFrames, UINT32 nSamplesPerS
}
// ------------------------------------------------------------------------------------------
#ifndef PA_WINRT
static BOOL SetupAVRT()
{
hDInputDLL = LoadLibraryA("avrt.dll");
@ -832,18 +880,23 @@ static BOOL SetupAVRT()
pAvRevertMmThreadCharacteristics &&
pAvSetMmThreadPriority;
}
#endif
// ------------------------------------------------------------------------------------------
static void CloseAVRT()
{
#ifndef PA_WINRT
if (hDInputDLL != NULL)
FreeLibrary(hDInputDLL);
hDInputDLL = NULL;
#endif
}
// ------------------------------------------------------------------------------------------
static BOOL IsWow64()
{
#ifndef PA_WINRT
// http://msdn.microsoft.com/en-us/library/ms684139(VS.85).aspx
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
@ -865,6 +918,12 @@ static BOOL IsWow64()
return FALSE;
return bIsWow64;
#else
return FALSE;
#endif
}
// ------------------------------------------------------------------------------------------
@ -880,6 +939,7 @@ typedef enum EWindowsVersion
}
EWindowsVersion;
// Alternative way for checking Windows version (allows to check version on Windows 8.1 and up)
#ifndef PA_WINRT
static BOOL IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
{
typedef ULONGLONG (NTAPI *LPFN_VERSETCONDITIONMASK)(ULONGLONG ConditionMask, DWORD TypeMask, BYTE Condition);
@ -909,9 +969,11 @@ static BOOL IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WO
return (fnVerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE);
}
#endif
// Get Windows version
static EWindowsVersion GetWindowsVersion()
{
#ifndef PA_WINRT
static EWindowsVersion version = WINDOWS_UNKNOWN;
if (version == WINDOWS_UNKNOWN)
@ -996,6 +1058,9 @@ static EWindowsVersion GetWindowsVersion()
}
return version;
#else
return WINDOWS_8_SERVER2012;
#endif
}
// ------------------------------------------------------------------------------------------
@ -1167,6 +1232,180 @@ static MixMonoToStereoF _GetMonoToStereoMixer(PaSampleFormat format, EMixerDir d
return NULL;
}
// ------------------------------------------------------------------------------------------
#ifdef PA_WINRT
typedef struct PaActivateAudioInterfaceCompletionHandler
{
IActivateAudioInterfaceCompletionHandler parent;
volatile LONG refs;
volatile LONG done;
struct
{
HRESULT hr;
IAudioClient *client;
}
out;
}
PaActivateAudioInterfaceCompletionHandler;
static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_QueryInterface)(
IActivateAudioInterfaceCompletionHandler *This, REFIID riid, void **ppvObject)
{
PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This;
// From MSDN:
// "The IAgileObject interface is a marker interface that indicates that an object
// is free threaded and can be called from any apartment."
if (IsEqualIID(riid, &IID_IUnknown) ||
IsEqualIID(riid, &IID_IAgileObject))
{
handler->parent.lpVtbl->AddRef((IActivateAudioInterfaceCompletionHandler *)handler);
(*ppvObject) = handler;
return S_OK;
}
return S_FALSE;
}
static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_AddRef)(
IActivateAudioInterfaceCompletionHandler *This)
{
PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This;
return InterlockedIncrement(&handler->refs);
}
static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Release)(
IActivateAudioInterfaceCompletionHandler *This)
{
PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This;
ULONG refs;
if ((refs = InterlockedDecrement(&handler->refs)) == 0)
{
PaUtil_FreeMemory(handler->parent.lpVtbl);
PaUtil_FreeMemory(handler);
}
return refs;
}
static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_ActivateCompleted)(
IActivateAudioInterfaceCompletionHandler *This, IActivateAudioInterfaceAsyncOperation *activateOperation)
{
PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This;
HRESULT hr = S_OK;
HRESULT hrActivateResult = S_OK;
IUnknown *punkAudioInterface = NULL;
// Check for a successful activation result
hr = activateOperation->lpVtbl->GetActivateResult(activateOperation, &hrActivateResult, &punkAudioInterface);
if (SUCCEEDED(hr) && SUCCEEDED(hrActivateResult))
{
// Get the pointer for the Audio Client
punkAudioInterface->lpVtbl->QueryInterface(punkAudioInterface, GetAudioClientIID(), &handler->out.client);
if (handler->out.client == NULL)
hrActivateResult = E_FAIL;
}
SAFE_RELEASE(punkAudioInterface);
if (SUCCEEDED(hr))
handler->out.hr = hrActivateResult;
else
handler->out.hr = hr;
// Got client object, stop busy waiting in ActivateAudioInterface_WINRT
InterlockedExchange(&handler->done, TRUE);
return hr;
}
static IActivateAudioInterfaceCompletionHandler *CreateActivateAudioInterfaceCompletionHandler()
{
PaActivateAudioInterfaceCompletionHandler *handler = PaUtil_AllocateMemory(sizeof(PaActivateAudioInterfaceCompletionHandler));
ZeroMemory(handler, sizeof(*handler));
handler->parent.lpVtbl = PaUtil_AllocateMemory(sizeof(*handler->parent.lpVtbl));
handler->parent.lpVtbl->QueryInterface = &PaActivateAudioInterfaceCompletionHandler_QueryInterface;
handler->parent.lpVtbl->AddRef = &PaActivateAudioInterfaceCompletionHandler_AddRef;
handler->parent.lpVtbl->Release = &PaActivateAudioInterfaceCompletionHandler_Release;
handler->parent.lpVtbl->ActivateCompleted = &PaActivateAudioInterfaceCompletionHandler_ActivateCompleted;
handler->refs = 1;
return (IActivateAudioInterfaceCompletionHandler *)handler;
}
#endif
// ------------------------------------------------------------------------------------------
#ifdef PA_WINRT
static HRESULT ActivateAudioInterface_WINRT(const PaWasapiDeviceInfo *deviceInfo, IAudioClient **client)
{
#define PA_WASAPI_DEVICE_PATH_LEN 64
PaError result = paNoError;
HRESULT hr = S_OK;
IActivateAudioInterfaceAsyncOperation *asyncOp = NULL;
IActivateAudioInterfaceCompletionHandler *handler = CreateActivateAudioInterfaceCompletionHandler();
PaActivateAudioInterfaceCompletionHandler *handlerImpl = (PaActivateAudioInterfaceCompletionHandler *)handler;
OLECHAR devicePath[PA_WASAPI_DEVICE_PATH_LEN] = { 0 };
// Get device path in form L"{DEVICE_GUID}"
switch (deviceInfo->flow)
{
case eRender:
StringFromGUID2(&DEVINTERFACE_AUDIO_RENDER, devicePath, PA_WASAPI_DEVICE_PATH_LEN - 1);
break;
case eCapture:
StringFromGUID2(&DEVINTERFACE_AUDIO_CAPTURE, devicePath, PA_WASAPI_DEVICE_PATH_LEN - 1);
break;
default:
return S_FALSE;
}
// Async operation will call back to IActivateAudioInterfaceCompletionHandler::ActivateCompleted
// which must be an agile interface implementation
hr = ActivateAudioInterfaceAsync(devicePath, GetAudioClientIID(), NULL, handler, &asyncOp);
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
// Wait in busy loop for async operation to complete
// Use Interlocked API here to ensure that ->done variable is read every time through the loop
while (SUCCEEDED(hr) && !InterlockedOr(&handlerImpl->done, 0))
{
Sleep(1);
}
(*client) = handlerImpl->out.client;
hr = handlerImpl->out.hr;
error:
SAFE_RELEASE(asyncOp);
SAFE_RELEASE(handler);
return hr;
#undef PA_WASAPI_DEVICE_PATH_LEN
}
#endif
// ------------------------------------------------------------------------------------------
static HRESULT ActivateAudioInterface(const PaWasapiDeviceInfo *deviceInfo, IAudioClient **client)
{
#ifndef PA_WINRT
return IMMDevice_Activate(deviceInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void **)client);
#else
return ActivateAudioInterface_WINRT(deviceInfo, client);
#endif
}
// ------------------------------------------------------------------------------------------
#ifdef PA_WINRT
static DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable)
{
SetEvent(hObjectToSignal);
return WaitForSingleObjectEx(hObjectToWaitOn, dwMilliseconds, bAlertable);
}
#endif
// ------------------------------------------------------------------------------------------
PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
{
@ -1174,14 +1413,20 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
PaWasapiHostApiRepresentation *paWasapi;
PaDeviceInfo *deviceInfoArray;
HRESULT hr = S_OK;
IMMDeviceCollection* pEndPoints = NULL;
UINT i;
#ifndef PA_WINRT
IMMDeviceCollection* pEndPoints = NULL;
#else
WAVEFORMATEX *mixFormat;
#endif
#ifndef PA_WINRT
if (!SetupAVRT())
{
PRINT(("WASAPI: No AVRT! (not VISTA?)"));
return paNoError;
}
#endif
paWasapi = (PaWasapiHostApiRepresentation *)PaUtil_AllocateMemory( sizeof(PaWasapiHostApiRepresentation) );
if (paWasapi == NULL)
@ -1213,6 +1458,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
(*hostApi)->info.defaultInputDevice = paNoDevice;
(*hostApi)->info.defaultOutputDevice = paNoDevice;
#ifndef PA_WINRT
paWasapi->enumerator = NULL;
hr = CoCreateInstance(&pa_CLSID_IMMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER,
&pa_IID_IMMDeviceEnumerator, (void **)&paWasapi->enumerator);
@ -1282,6 +1528,10 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
// [IF_FAILED_JUMP(hResult, error);]
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
#else
paWasapi->deviceCount = 2;
#endif
paWasapi->devInfo = (PaWasapiDeviceInfo *)PaUtil_AllocateMemory(sizeof(PaWasapiDeviceInfo) * paWasapi->deviceCount);
if (paWasapi->devInfo == NULL)
{
@ -1312,7 +1562,6 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
for (i = 0; i < paWasapi->deviceCount; ++i)
{
DWORD state = 0;
PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
deviceInfo->structVersion = 3;
deviceInfo->hostApi = hostApiIndex;
@ -1320,6 +1569,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
PA_DEBUG(("WASAPI: device idx: %02d\n", i));
PA_DEBUG(("WASAPI: ---------------\n"));
#ifndef PA_WINRT
hr = IMMDeviceCollection_Item(pEndPoints, i, &paWasapi->devInfo[i].device);
// We need to set the result to a value otherwise we will return paNoError
// [IF_FAILED_JUMP(hResult, error);]
@ -1352,7 +1602,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
if (paWasapi->devInfo[i].state != DEVICE_STATE_ACTIVE)
{
PRINT(("WASAPI device: %d is not currently available (state:%d)\n",i,state));
PRINT(("WASAPI device: %d is not currently available (state:%d)\n", i, paWasapi->devInfo[i].state));
}
{
@ -1379,9 +1629,9 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
goto error;
}
if (value.pwszVal)
WideCharToMultiByte(CP_UTF8, 0, value.pwszVal, (int)wcslen(value.pwszVal), deviceName, MAX_STR_LEN-1, 0, 0);
WideCharToMultiByte(CP_UTF8, 0, value.pwszVal, (int)wcslen(value.pwszVal), deviceName, MAX_STR_LEN - 1, 0, 0);
else
_snprintf(deviceName, MAX_STR_LEN-1, "baddev%d", i);
_snprintf(deviceName, MAX_STR_LEN - 1, "baddev%d", i);
deviceInfo->name = deviceName;
PropVariantClear(&value);
PA_DEBUG(("WASAPI:%d| name[%s]\n", i, deviceInfo->name));
@ -1424,8 +1674,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
SAFE_RELEASE(pProperty);
}
// Endpoint data
{
IMMEndpoint *endpoint = NULL;
@ -1436,18 +1685,25 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
SAFE_RELEASE(endpoint);
}
}
#endif
// Getting a temporary IAudioClient for more fields
// we make sure NOT to call Initialize yet!
{
IAudioClient *tmpClient = NULL;
#ifdef PA_WINRT
// Set flow as ActivateAudioInterface depends on it and selects corresponding
// direction for the Audio Client
paWasapi->devInfo[i].flow = (i == 0 ? eRender : eCapture);
#endif
hr = IMMDevice_Activate(paWasapi->devInfo[i].device, GetAudioClientIID(),
CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient);
// Create temp Audio Client instance to query additional details
IAudioClient *tmpClient = NULL;
hr = ActivateAudioInterface(&paWasapi->devInfo[i], &tmpClient);
// We need to set the result to a value otherwise we will return paNoError
// [IF_FAILED_JUMP(hResult, error);]
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
// Get latency
hr = IAudioClient_GetDevicePeriod(tmpClient,
&paWasapi->devInfo[i].DefaultDevicePeriod,
&paWasapi->devInfo[i].MinimumDevicePeriod);
@ -1462,10 +1718,42 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
// ignore error, let continue further without failing with paInternalError
hr = S_OK;
}
#ifdef PA_WINRT
// Get mix format which will treat as default device format
hr = IAudioClient_GetMixFormat(tmpClient, &mixFormat);
if (SUCCEEDED(hr))
{
// Default device
if (i == 0)
(*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
else
(*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;
//hr = tmpClient->GetMixFormat(&paWasapi->devInfo[i].MixFormat);
// State
paWasapi->devInfo[i].state = DEVICE_STATE_ACTIVE;
// Release client
// Default format
memcpy(&paWasapi->devInfo[i].DefaultFormat, mixFormat, min(sizeof(paWasapi->devInfo[i].DefaultFormat), sizeof(*mixFormat)));
CoTaskMemFree(mixFormat);
// Form-factor
paWasapi->devInfo[i].formFactor = UnknownFormFactor;
// Name
deviceInfo->name = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, MAX_STR_LEN + 1);
if (deviceInfo->name == NULL)
{
SAFE_RELEASE(tmpClient);
result = paInsufficientMemory;
goto error;
}
_snprintf((char *)deviceInfo->name, MAX_STR_LEN - 1, "WASAPI_%s:%d", (i == 0 ? "Output" : "Input"), i);
PA_DEBUG(("WASAPI:%d| name[%s]\n", i, deviceInfo->name));
}
#endif
// Release tmp client
SAFE_RELEASE(tmpClient);
if (hr != S_OK)
@ -1479,7 +1767,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
goto error;
}
}
// we can now fill in portaudio device data
deviceInfo->maxInputChannels = 0;
deviceInfo->maxOutputChannels = 0;
@ -1537,7 +1825,9 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
// findout if platform workaround is required
paWasapi->useWOW64Workaround = UseWOW64Workaround();
#ifndef PA_WINRT
SAFE_RELEASE(pEndPoints);
#endif
PRINT(("WASAPI: initialized ok\n"));
@ -1547,7 +1837,9 @@ error:
PRINT(("WASAPI: failed %s error[%d|%s]\n", __FUNCTION__, result, Pa_GetErrorText(result)));
#ifndef PA_WINRT
SAFE_RELEASE(pEndPoints);
#endif
Terminate((PaUtilHostApiRepresentation *)paWasapi);
@ -1568,15 +1860,19 @@ static void Terminate( PaUtilHostApiRepresentation *hostApi )
return;
// Release IMMDeviceEnumerator
#ifndef PA_WINRT
SAFE_RELEASE(paWasapi->enumerator);
#endif
// Release device info bound objects and device info itself
for (i = 0; i < paWasapi->deviceCount; ++i)
{
PaWasapiDeviceInfo *info = &paWasapi->devInfo[i];
#ifndef PA_WINRT
SAFE_RELEASE(info->device);
//if (info->MixFormat)
// CoTaskMemFree(info->MixFormat);
#else
(void)info;
#endif
}
PaUtil_FreeMemory(paWasapi->devInfo);
@ -1835,25 +2131,25 @@ static PaError MakeWaveFormatFromParams(WAVEFORMATEXTENSIBLE *wavex, const PaStr
{
switch (params->channelCount)
{
case 1: wavex->dwChannelMask = KSAUDIO_SPEAKER_MONO; break;
case 2: wavex->dwChannelMask = KSAUDIO_SPEAKER_STEREO; break;
case 3: wavex->dwChannelMask = KSAUDIO_SPEAKER_STEREO|SPEAKER_LOW_FREQUENCY; break;
case 4: wavex->dwChannelMask = KSAUDIO_SPEAKER_QUAD; break;
case 5: wavex->dwChannelMask = KSAUDIO_SPEAKER_QUAD|SPEAKER_LOW_FREQUENCY; break;
#ifdef KSAUDIO_SPEAKER_5POINT1_SURROUND
case 6: wavex->dwChannelMask = KSAUDIO_SPEAKER_5POINT1_SURROUND; break;
case 1: wavex->dwChannelMask = PAWIN_SPEAKER_MONO; break;
case 2: wavex->dwChannelMask = PAWIN_SPEAKER_STEREO; break;
case 3: wavex->dwChannelMask = PAWIN_SPEAKER_STEREO|SPEAKER_LOW_FREQUENCY; break;
case 4: wavex->dwChannelMask = PAWIN_SPEAKER_QUAD; break;
case 5: wavex->dwChannelMask = PAWIN_SPEAKER_QUAD|SPEAKER_LOW_FREQUENCY; break;
#ifdef PAWIN_SPEAKER_5POINT1_SURROUND
case 6: wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1_SURROUND; break;
#else
case 6: wavex->dwChannelMask = KSAUDIO_SPEAKER_5POINT1; break;
case 6: wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1; break;
#endif
#ifdef KSAUDIO_SPEAKER_5POINT1_SURROUND
case 7: wavex->dwChannelMask = KSAUDIO_SPEAKER_5POINT1_SURROUND|SPEAKER_BACK_CENTER; break;
#ifdef PAWIN_SPEAKER_5POINT1_SURROUND
case 7: wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1_SURROUND|SPEAKER_BACK_CENTER; break;
#else
case 7: wavex->dwChannelMask = KSAUDIO_SPEAKER_5POINT1|SPEAKER_BACK_CENTER; break;
case 7: wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1|SPEAKER_BACK_CENTER; break;
#endif
#ifdef KSAUDIO_SPEAKER_7POINT1_SURROUND
case 8: wavex->dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND; break;
#ifdef PAWIN_SPEAKER_7POINT1_SURROUND
case 8: wavex->dwChannelMask = PAWIN_SPEAKER_7POINT1_SURROUND; break;
#else
case 8: wavex->dwChannelMask = KSAUDIO_SPEAKER_7POINT1; break;
case 8: wavex->dwChannelMask = PAWIN_SPEAKER_7POINT1; break;
#endif
default: wavex->dwChannelMask = 0;
@ -1874,9 +2170,9 @@ static PaError MakeWaveFormatFromParams(WAVEFORMATEXTENSIBLE *wavex, const PaStr
pwfext->Format.nChannels = (WORD)channelCount;
pwfext->Format.nSamplesPerSec = (DWORD)sampleRate;
if(channelCount == 1)
pwfext->dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT;
pwfext->dwChannelMask = PAWIN_SPEAKER_DIRECTOUT;
else
pwfext->dwChannelMask = KSAUDIO_SPEAKER_STEREO;
pwfext->dwChannelMask = PAWIN_SPEAKER_STEREO;
if(sampleFormat == paFloat32)
{
pwfext->Format.nBlockAlign = (WORD)(channelCount * 4);
@ -1921,6 +2217,7 @@ static PaError GetClosestFormat(IAudioClient *myClient, double sampleRate,
WAVEFORMATEX *sharedClosestMatch = NULL;
HRESULT hr = !S_OK;
PaStreamParameters params = (*_params);
(void)output;
/* It was not noticed that 24-bit Input producing no output while device accepts this format.
To fix this issue let's ask for 32-bits and let PA converters convert host 32-bit data
@ -2159,8 +2456,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
if (inputStreamInfo && (inputStreamInfo->flags & paWinWasapiExclusive))
shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;
hr = IMMDevice_Activate(paWasapi->devInfo[inputParameters->device].device,
GetAudioClientIID(), CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient);
hr = ActivateAudioInterface(&paWasapi->devInfo[inputParameters->device], &tmpClient);
if (hr != S_OK)
{
LogHostError(hr);
@ -2185,8 +2481,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
if (outputStreamInfo && (outputStreamInfo->flags & paWinWasapiExclusive))
shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;
hr = IMMDevice_Activate(paWasapi->devInfo[outputParameters->device].device,
GetAudioClientIID(), CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient);
hr = ActivateAudioInterface(&paWasapi->devInfo[outputParameters->device], &tmpClient);
if (hr != S_OK)
{
LogHostError(hr);
@ -2264,7 +2559,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
const PaStreamParameters *params = &pSub->params.stream_params;
UINT32 framesPerLatency = pSub->params.frames_per_buffer;
double sampleRate = pSub->params.sample_rate;
BOOL blocking = pSub->params.blocking;
//BOOL blocking = pSub->params.blocking;
BOOL fullDuplex = pSub->params.full_duplex;
const UINT32 userFramesPerBuffer = framesPerLatency;
@ -2286,7 +2581,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
}
// Get the audio client
hr = IMMDevice_Activate(pInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void **)&audioClient);
hr = ActivateAudioInterface(pInfo, &audioClient);
if (hr != S_OK)
{
(*pa_error) = paInsufficientMemory;
@ -2500,7 +2795,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
SAFE_RELEASE(audioClient);
// Create a new audio client
hr = IMMDevice_Activate(pInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void**)&audioClient);
hr = ActivateAudioInterface(pInfo, &audioClient);
if (hr != S_OK)
{
(*pa_error) = paInsufficientMemory;
@ -2531,7 +2826,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
SAFE_RELEASE(audioClient);
// Create a new audio client
hr = IMMDevice_Activate(pInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void**)&audioClient);
hr = ActivateAudioInterface(pInfo, &audioClient);
if (hr != S_OK)
{
(*pa_error) = paInsufficientMemory;
@ -2571,7 +2866,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
SAFE_RELEASE(audioClient);
// Create a new audio client
hr = IMMDevice_Activate(pInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void**)&audioClient);
hr = ActivateAudioInterface(pInfo, &audioClient);
if (hr != S_OK)
{
(*pa_error) = paInsufficientMemory;
@ -3254,6 +3549,7 @@ static PaError CloseStream( PaStream* s )
// ------------------------------------------------------------------------------------------
HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream)
{
#ifndef PA_WINRT
HRESULT hResult = S_OK;
HRESULT hFirstBadResult = S_OK;
substream->clientProc = NULL;
@ -3267,11 +3563,17 @@ HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream)
}
return hFirstBadResult;
#else
(void)substream;
return S_OK;
#endif
}
// ------------------------------------------------------------------------------------------
HRESULT UnmarshalStreamComPointers(PaWasapiStream *stream)
{
#ifndef PA_WINRT
HRESULT hResult = S_OK;
HRESULT hFirstBadResult = S_OK;
stream->captureClient = NULL;
@ -3316,6 +3618,33 @@ HRESULT UnmarshalStreamComPointers(PaWasapiStream *stream)
}
return hFirstBadResult;
#else
if (stream->in.clientParent != NULL)
{
stream->in.clientProc = stream->in.clientParent;
IAudioClient_AddRef(stream->in.clientParent);
}
if (stream->out.clientParent != NULL)
{
stream->out.clientProc = stream->out.clientParent;
IAudioClient_AddRef(stream->out.clientParent);
}
if (stream->renderClientParent != NULL)
{
stream->renderClient = stream->renderClientParent;
IAudioRenderClient_AddRef(stream->renderClientParent);
}
if (stream->captureClientParent != NULL)
{
stream->captureClient = stream->captureClientParent;
IAudioCaptureClient_AddRef(stream->captureClientParent);
}
return S_OK;
#endif
}
// -----------------------------------------------------------------------------------------
@ -3339,6 +3668,7 @@ void ReleaseUnmarshaledComPointers(PaWasapiStream *stream)
// ------------------------------------------------------------------------------------------
HRESULT MarshalSubStreamComPointers(PaWasapiSubStream *substream)
{
#ifndef PA_WINRT
HRESULT hResult;
substream->clientStream = NULL;
@ -3355,11 +3685,16 @@ marshal_sub_error:
UnmarshalSubStreamComPointers(substream);
ReleaseUnmarshaledSubComPointers(substream);
return hResult;
#else
(void)substream;
return S_OK;
#endif
}
// ------------------------------------------------------------------------------------------
HRESULT MarshalStreamComPointers(PaWasapiStream *stream)
{
#ifndef PA_WINRT
HRESULT hResult = S_OK;
stream->captureClientStream = NULL;
stream->in.clientStream = NULL;
@ -3400,6 +3735,10 @@ marshal_error:
UnmarshalStreamComPointers(stream);
ReleaseUnmarshaledComPointers(stream);
return hResult;
#else
(void)stream;
return S_OK;
#endif
}
// ------------------------------------------------------------------------------------------
@ -4084,6 +4423,7 @@ static void WaspiHostProcessingLoop( void *inputBuffer, long inputFrames,
// ------------------------------------------------------------------------------------------
HANDLE MMCSS_activate(const char *name)
{
#ifndef PA_WINRT
DWORD task_idx = 0;
HANDLE hTask = pAvSetMmThreadCharacteristics(name, &task_idx);
if (hTask == NULL)
@ -4105,6 +4445,10 @@ HANDLE MMCSS_activate(const char *name)
}
return hTask;
#else
(void)name;
return NULL;
#endif
}
// ------------------------------------------------------------------------------------------
@ -4113,10 +4457,12 @@ void MMCSS_deactivate(HANDLE hTask)
if (!hTask)
return;
#ifndef PA_WINRT
if (pAvRevertMmThreadCharacteristics(hTask) == FALSE)
{
PRINT(("WASAPI: AvRevertMmThreadCharacteristics failed!\n"));
}
#endif
}
// ------------------------------------------------------------------------------------------
@ -4166,6 +4512,7 @@ PaError PaWasapi_ThreadPriorityRevert(void *hTask)
PaError PaWasapi_GetJackCount(PaDeviceIndex nDevice, int *jcount)
{
#ifndef PA_WINRT
PaError ret;
HRESULT hr = S_OK;
PaDeviceIndex index;
@ -4235,9 +4582,15 @@ error:
LogHostError(hr);
return paNoError;
#else
(void)nDevice;
(void)jcount;
return paUnanticipatedHostError;
#endif
}
// ------------------------------------------------------------------------------------------
#ifndef PA_WINRT
static PaWasapiJackConnectionType ConvertJackConnectionTypeWASAPIToPA(int connType)
{
switch (connType)
@ -4261,8 +4614,10 @@ static PaWasapiJackConnectionType ConvertJackConnectionTypeWASAPIToPA(int connTy
}
return eJackConnTypeUnknown;
}
#endif
// ------------------------------------------------------------------------------------------
#ifndef PA_WINRT
static PaWasapiJackGeoLocation ConvertJackGeoLocationWASAPIToPA(int geoLoc)
{
switch (geoLoc)
@ -4287,8 +4642,10 @@ static PaWasapiJackGeoLocation ConvertJackGeoLocationWASAPIToPA(int geoLoc)
}
return eJackGeoLocUnk;
}
#endif
// ------------------------------------------------------------------------------------------
#ifndef PA_WINRT
static PaWasapiJackGenLocation ConvertJackGenLocationWASAPIToPA(int genLoc)
{
switch (genLoc)
@ -4304,8 +4661,10 @@ static PaWasapiJackGenLocation ConvertJackGenLocationWASAPIToPA(int genLoc)
}
return eJackGenLocPrimaryBox;
}
#endif
// ------------------------------------------------------------------------------------------
#ifndef PA_WINRT
static PaWasapiJackPortConnection ConvertJackPortConnectionWASAPIToPA(int portConn)
{
switch (portConn)
@ -4317,6 +4676,7 @@ static PaWasapiJackPortConnection ConvertJackPortConnectionWASAPIToPA(int portCo
}
return eJackPortConnJack;
}
#endif
// ------------------------------------------------------------------------------------------
// Described at:
@ -4324,6 +4684,7 @@ static PaWasapiJackPortConnection ConvertJackPortConnectionWASAPIToPA(int portCo
PaError PaWasapi_GetJackDescription(PaDeviceIndex nDevice, int jindex, PaWasapiJackDescription *pJackDescription)
{
#ifndef PA_WINRT
PaError ret;
HRESULT hr = S_OK;
PaDeviceIndex index;
@ -4399,6 +4760,13 @@ error:
LogHostError(hr);
return ret;
#else
(void)nDevice;
(void)jindex;
(void)pJackDescription;
return paUnanticipatedHostError;
#endif
}
// ------------------------------------------------------------------------------------------
@ -4623,7 +4991,7 @@ PA_THREAD_FUNC ProcThreadEvent(void *param)
if (FAILED(hr) && (hr != RPC_E_CHANGED_MODE))
{
PRINT(("WASAPI: failed ProcThreadEvent CoInitialize"));
return paUnanticipatedHostError;
return (UINT32)paUnanticipatedHostError;
}
if (hr != RPC_E_CHANGED_MODE)
bThreadComInitialized = TRUE;
@ -4830,7 +5198,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
if (FAILED(hr) && (hr != RPC_E_CHANGED_MODE))
{
PRINT(("WASAPI: failed ProcThreadPoll CoInitialize"));
return paUnanticipatedHostError;
return (UINT32)paUnanticipatedHostError;
}
if (hr != RPC_E_CHANGED_MODE)
bThreadComInitialized = TRUE;

View file

@ -52,7 +52,7 @@
#include "pa_win_coinitialize.h"
#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && !defined(_WIN32_WCE) /* MSC version 6 and above */
#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && !defined(_WIN32_WCE) && !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)) /* MSC version 6 and above */
#pragma comment( lib, "ole32.lib" )
#endif
@ -76,7 +76,11 @@ PaError PaWinUtil_CoInitialize( PaHostApiTypeId hostApiType, PaWinUtilComInitial
RPC_E_CHANGED_MODE was returned.
*/
#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP)
hr = CoInitialize(0); /* use legacy-safe equivalent to CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) */
#else
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
#endif
if( FAILED(hr) && hr != RPC_E_CHANGED_MODE )
{
PA_DEBUG(("CoInitialize(0) failed. hr=%d\n", hr));

View file

@ -44,14 +44,17 @@
*/
#include <windows.h>
#include <mmsystem.h> /* for timeGetTime() */
#include "pa_util.h"
#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && !defined(_WIN32_WCE) /* MSC version 6 and above */
#pragma comment( lib, "winmm.lib" )
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
#include <sys/timeb.h> /* for _ftime_s() */
#else
#include <mmsystem.h> /* for timeGetTime() */
#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && !defined(_WIN32_WCE) /* MSC version 6 and above */
#pragma comment( lib, "winmm.lib" )
#endif
#endif
#include "pa_util.h"
/*
Track memory allocations to avoid leaks.
@ -144,8 +147,12 @@ double PaUtil_GetTime( void )
}
else
{
#ifndef UNDER_CE
#ifndef UNDER_CE
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
return GetTickCount64() * .001;
#else
return timeGetTime() * .001;
#endif
#else
return GetTickCount() * .001;
#endif

View file

@ -38,6 +38,9 @@
#include <windows.h>
#include <mmsystem.h>
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
#include <mmreg.h> /* for WAVEFORMATEX */
#endif
#include "portaudio.h"
#include "pa_win_waveformat.h"
@ -47,6 +50,7 @@
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
#endif
static GUID pawin_ksDataFormatSubtypeGuidBase =
{ (USHORT)(WAVE_FORMAT_PCM), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 };